1*83030dd5SDavid du Colombier /* 2*83030dd5SDavid du Colombier * USB Human Interaction Device: keyboard and mouse. 3*83030dd5SDavid du Colombier * 4*83030dd5SDavid du Colombier * If there's no usb keyboard, it tries to setup the mouse, if any. 5*83030dd5SDavid du Colombier * It should be started at boot time. 6*83030dd5SDavid du Colombier * 7*83030dd5SDavid du Colombier * Mouse events are converted to the format of mouse(3)'s 8*83030dd5SDavid du Colombier * mousein file. 9*83030dd5SDavid du Colombier * Keyboard keycodes are translated to scan codes and sent to kbin(3). 10*83030dd5SDavid du Colombier * 11*83030dd5SDavid du Colombier */ 12*83030dd5SDavid du Colombier 13*83030dd5SDavid du Colombier #include <u.h> 14*83030dd5SDavid du Colombier #include <libc.h> 15*83030dd5SDavid du Colombier #include <thread.h> 16*83030dd5SDavid du Colombier #include "usb.h" 17*83030dd5SDavid du Colombier #include "hid.h" 18*83030dd5SDavid du Colombier 19*83030dd5SDavid du Colombier /* 20*83030dd5SDavid du Colombier * Map for the logitech bluetooth mouse with 8 buttons and wheels. 21*83030dd5SDavid du Colombier * { ptr ->mouse} 22*83030dd5SDavid du Colombier * { 0x01, 0x01 }, // left 23*83030dd5SDavid du Colombier * { 0x04, 0x02 }, // middle 24*83030dd5SDavid du Colombier * { 0x02, 0x04 }, // right 25*83030dd5SDavid du Colombier * { 0x40, 0x08 }, // up 26*83030dd5SDavid du Colombier * { 0x80, 0x10 }, // down 27*83030dd5SDavid du Colombier * { 0x10, 0x08 }, // side up 28*83030dd5SDavid du Colombier * { 0x08, 0x10 }, // side down 29*83030dd5SDavid du Colombier * { 0x20, 0x02 }, // page 30*83030dd5SDavid du Colombier * besides wheel and regular up/down report the 4th byte as 1/-1 31*83030dd5SDavid du Colombier */ 32*83030dd5SDavid du Colombier 33*83030dd5SDavid du Colombier /* 34*83030dd5SDavid du Colombier * key code to scan code; for the page table used by 35*83030dd5SDavid du Colombier * the logitech bluetooth keyboard. 36*83030dd5SDavid du Colombier */ 37*83030dd5SDavid du Colombier char sctab[256] = 38*83030dd5SDavid du Colombier { 39*83030dd5SDavid du Colombier [0x00] 0x0, 0x0, 0x0, 0x0, 0x1e, 0x30, 0x2e, 0x20, 40*83030dd5SDavid du Colombier [0x08] 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 41*83030dd5SDavid du Colombier [0x10] 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 42*83030dd5SDavid du Colombier [0x18] 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x2, 0x3, 43*83030dd5SDavid du Colombier [0x20] 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 44*83030dd5SDavid du Colombier [0x28] 0x1c, 0x1, 0xe, 0xf, 0x39, 0xc, 0xd, 0x1a, 45*83030dd5SDavid du Colombier [0x30] 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, 46*83030dd5SDavid du Colombier [0x38] 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 47*83030dd5SDavid du Colombier [0x40] 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0x63, 0x46, 48*83030dd5SDavid du Colombier [0x48] 0x77, 0x52, 0x47, 0x49, 0x53, 0x4f, 0x51, 0x4d, 49*83030dd5SDavid du Colombier [0x50] 0x4b, 0x50, 0x48, 0x45, 0x35, 0x37, 0x4a, 0x4e, 50*83030dd5SDavid du Colombier [0x58] 0x1c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, 51*83030dd5SDavid du Colombier [0x60] 0x48, 0x49, 0x52, 0x53, 0x56, 0x7f, 0x74, 0x75, 52*83030dd5SDavid du Colombier [0x68] 0x55, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 53*83030dd5SDavid du Colombier [0x70] 0x78, 0x79, 0x7a, 0x7b, 0x0, 0x0, 0x0, 0x0, 54*83030dd5SDavid du Colombier [0x78] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 55*83030dd5SDavid du Colombier [0x80] 0x73, 0x72, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 56*83030dd5SDavid du Colombier [0x88] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 57*83030dd5SDavid du Colombier [0x90] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 58*83030dd5SDavid du Colombier [0x98] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 59*83030dd5SDavid du Colombier [0xa0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 60*83030dd5SDavid du Colombier [0xa8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 61*83030dd5SDavid du Colombier [0xb0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 62*83030dd5SDavid du Colombier [0xb8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 63*83030dd5SDavid du Colombier [0xc0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 64*83030dd5SDavid du Colombier [0xc8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 65*83030dd5SDavid du Colombier [0xd0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 66*83030dd5SDavid du Colombier [0xd8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 67*83030dd5SDavid du Colombier [0xe0] 0x1d, 0x2a, 0x38, 0x7d, 0x61, 0x36, 0x64, 0x7e, 68*83030dd5SDavid du Colombier [0xe8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x73, 0x72, 0x71, 69*83030dd5SDavid du Colombier [0xf0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 70*83030dd5SDavid du Colombier [0xf8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 71*83030dd5SDavid du Colombier }; 72*83030dd5SDavid du Colombier 73*83030dd5SDavid du Colombier typedef struct Dev Dev; 74*83030dd5SDavid du Colombier struct Dev { 75*83030dd5SDavid du Colombier char* name; /* debug */ 76*83030dd5SDavid du Colombier void (*proc)(void*); /* handler process */ 77*83030dd5SDavid du Colombier int csp; /* the csp we want */ 78*83030dd5SDavid du Colombier int enabled; /* can we start it? */ 79*83030dd5SDavid du Colombier int ctlrno; /* controller number, for probing*/ 80*83030dd5SDavid du Colombier int id; /* device id, for probing*/ 81*83030dd5SDavid du Colombier int ep; /* endpoint used to get events */ 82*83030dd5SDavid du Colombier int msz; /* message size */ 83*83030dd5SDavid du Colombier int fd; /* to the endpoint data file */ 84*83030dd5SDavid du Colombier Device* dev; /* usb device*/ 85*83030dd5SDavid du Colombier }; 86*83030dd5SDavid du Colombier 87*83030dd5SDavid du Colombier 88*83030dd5SDavid du Colombier Dev kf, pf; /* kbd and pointer drivers*/ 89*83030dd5SDavid du Colombier Channel *repeatc; /* channel to request key repeating*/ 90*83030dd5SDavid du Colombier 91*83030dd5SDavid du Colombier void (*dprinter[])(Device *, int, ulong, void *b, int n) = { 92*83030dd5SDavid du Colombier [STRING] pstring, 93*83030dd5SDavid du Colombier [DEVICE] pdevice, 94*83030dd5SDavid du Colombier [HID] phid, 95*83030dd5SDavid du Colombier }; 96*83030dd5SDavid du Colombier 97*83030dd5SDavid du Colombier int accel; 98*83030dd5SDavid du Colombier int hdebug; 99*83030dd5SDavid du Colombier int dryrun; 100*83030dd5SDavid du Colombier int verbose; 101*83030dd5SDavid du Colombier 102*83030dd5SDavid du Colombier int mainstacksize = 32*1024; 103*83030dd5SDavid du Colombier 104*83030dd5SDavid du Colombier int 105*83030dd5SDavid du Colombier robusthandler(void*, char *s) 106*83030dd5SDavid du Colombier { 107*83030dd5SDavid du Colombier if(hdebug) 108*83030dd5SDavid du Colombier fprint(2, "inthandler: %s\n", s); 109*83030dd5SDavid du Colombier return (s && (strstr(s, "interrupted")|| strstr(s, "hangup"))); 110*83030dd5SDavid du Colombier } 111*83030dd5SDavid du Colombier 112*83030dd5SDavid du Colombier long 113*83030dd5SDavid du Colombier robustread(int fd, void *buf, long sz) 114*83030dd5SDavid du Colombier { 115*83030dd5SDavid du Colombier long r; 116*83030dd5SDavid du Colombier char err[ERRMAX]; 117*83030dd5SDavid du Colombier 118*83030dd5SDavid du Colombier do { 119*83030dd5SDavid du Colombier r = read(fd , buf, sz); 120*83030dd5SDavid du Colombier if(r < 0) 121*83030dd5SDavid du Colombier rerrstr(err, sizeof err); 122*83030dd5SDavid du Colombier } while(r < 0 && robusthandler(nil, err)); 123*83030dd5SDavid du Colombier return r; 124*83030dd5SDavid du Colombier } 125*83030dd5SDavid du Colombier 126*83030dd5SDavid du Colombier static int 127*83030dd5SDavid du Colombier scale(int x) 128*83030dd5SDavid du Colombier { 129*83030dd5SDavid du Colombier int sign = 1; 130*83030dd5SDavid du Colombier 131*83030dd5SDavid du Colombier if(x < 0){ 132*83030dd5SDavid du Colombier sign = -1; 133*83030dd5SDavid du Colombier x = -x; 134*83030dd5SDavid du Colombier } 135*83030dd5SDavid du Colombier switch(x){ 136*83030dd5SDavid du Colombier case 0: 137*83030dd5SDavid du Colombier case 1: 138*83030dd5SDavid du Colombier case 2: 139*83030dd5SDavid du Colombier case 3: 140*83030dd5SDavid du Colombier break; 141*83030dd5SDavid du Colombier case 4: 142*83030dd5SDavid du Colombier x = 6 + (accel>>2); 143*83030dd5SDavid du Colombier break; 144*83030dd5SDavid du Colombier case 5: 145*83030dd5SDavid du Colombier x = 9 + (accel>>1); 146*83030dd5SDavid du Colombier break; 147*83030dd5SDavid du Colombier default: 148*83030dd5SDavid du Colombier x *= MaxAcc; 149*83030dd5SDavid du Colombier break; 150*83030dd5SDavid du Colombier } 151*83030dd5SDavid du Colombier return sign*x; 152*83030dd5SDavid du Colombier } 153*83030dd5SDavid du Colombier 154*83030dd5SDavid du Colombier void 155*83030dd5SDavid du Colombier ptrwork(void* a) 156*83030dd5SDavid du Colombier { 157*83030dd5SDavid du Colombier int x, y, b, c, mfd, ptrfd; 158*83030dd5SDavid du Colombier char buf[32]; 159*83030dd5SDavid du Colombier Dev* f = a; 160*83030dd5SDavid du Colombier static char maptab[] = {0x0, 0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7}; 161*83030dd5SDavid du Colombier 162*83030dd5SDavid du Colombier ptrfd = f->fd; 163*83030dd5SDavid du Colombier if(ptrfd < 0) 164*83030dd5SDavid du Colombier return; 165*83030dd5SDavid du Colombier mfd = -1; 166*83030dd5SDavid du Colombier if(f->msz < 3 || f->msz > sizeof buf) 167*83030dd5SDavid du Colombier sysfatal("bug: ptrwork: bad mouse maxpkt"); 168*83030dd5SDavid du Colombier if(!dryrun){ 169*83030dd5SDavid du Colombier mfd = open("#m/mousein", OWRITE); 170*83030dd5SDavid du Colombier if(mfd < 0) 171*83030dd5SDavid du Colombier sysfatal("%s: mousein: %r", f->name); 172*83030dd5SDavid du Colombier } 173*83030dd5SDavid du Colombier for(;;){ 174*83030dd5SDavid du Colombier memset(buf, 0, sizeof buf); 175*83030dd5SDavid du Colombier c = robustread(ptrfd, buf, f->msz); 176*83030dd5SDavid du Colombier if(c == 0) 177*83030dd5SDavid du Colombier fprint(2, "%s: %s: eof\n", argv0, f->name); 178*83030dd5SDavid du Colombier if(c < 0) 179*83030dd5SDavid du Colombier fprint(2, "%s: %s: read: %r\n", argv0, f->name); 180*83030dd5SDavid du Colombier if(c <= 0){ 181*83030dd5SDavid du Colombier if(!dryrun) 182*83030dd5SDavid du Colombier close(mfd); 183*83030dd5SDavid du Colombier close(f->fd); 184*83030dd5SDavid du Colombier threadexits("read"); 185*83030dd5SDavid du Colombier } 186*83030dd5SDavid du Colombier if(c < 3) 187*83030dd5SDavid du Colombier continue; 188*83030dd5SDavid du Colombier if(accel) { 189*83030dd5SDavid du Colombier x = scale(buf[1]); 190*83030dd5SDavid du Colombier y = scale(buf[2]); 191*83030dd5SDavid du Colombier } else { 192*83030dd5SDavid du Colombier x = buf[1]; 193*83030dd5SDavid du Colombier y = buf[2]; 194*83030dd5SDavid du Colombier } 195*83030dd5SDavid du Colombier b = maptab[buf[0] & 0x7]; 196*83030dd5SDavid du Colombier if(c > 3 && buf[3] == 1) /* up */ 197*83030dd5SDavid du Colombier b |= 0x08; 198*83030dd5SDavid du Colombier if(c > 3 && buf[3] == -1) /* down */ 199*83030dd5SDavid du Colombier b |= 0x10; 200*83030dd5SDavid du Colombier if(hdebug) 201*83030dd5SDavid du Colombier fprint(2, "%s: %s: m%11d %11d %11d\n", 202*83030dd5SDavid du Colombier argv0, f->name, x, y, b); 203*83030dd5SDavid du Colombier if(!dryrun) 204*83030dd5SDavid du Colombier if(fprint(mfd, "m%11d %11d %11d", x, y, b) < 0){ 205*83030dd5SDavid du Colombier fprint(2, "%s: #m/mousein: write: %r", argv0); 206*83030dd5SDavid du Colombier close(mfd); 207*83030dd5SDavid du Colombier close(f->fd); 208*83030dd5SDavid du Colombier threadexits("write"); 209*83030dd5SDavid du Colombier } 210*83030dd5SDavid du Colombier } 211*83030dd5SDavid du Colombier } 212*83030dd5SDavid du Colombier 213*83030dd5SDavid du Colombier static void 214*83030dd5SDavid du Colombier stoprepeat(void) 215*83030dd5SDavid du Colombier { 216*83030dd5SDavid du Colombier sendul(repeatc, Awakemsg); 217*83030dd5SDavid du Colombier } 218*83030dd5SDavid du Colombier 219*83030dd5SDavid du Colombier static void 220*83030dd5SDavid du Colombier startrepeat(uchar esc1, uchar sc) 221*83030dd5SDavid du Colombier { 222*83030dd5SDavid du Colombier ulong c; 223*83030dd5SDavid du Colombier 224*83030dd5SDavid du Colombier if(esc1) 225*83030dd5SDavid du Colombier c = SCesc1 << 8 | (sc & 0xff); 226*83030dd5SDavid du Colombier else 227*83030dd5SDavid du Colombier c = sc; 228*83030dd5SDavid du Colombier sendul(repeatc, c); 229*83030dd5SDavid du Colombier } 230*83030dd5SDavid du Colombier 231*83030dd5SDavid du Colombier static int kbinfd = -1; 232*83030dd5SDavid du Colombier 233*83030dd5SDavid du Colombier static void 234*83030dd5SDavid du Colombier putscan(uchar esc, uchar sc) 235*83030dd5SDavid du Colombier { 236*83030dd5SDavid du Colombier static uchar s[2] = {SCesc1, 0}; 237*83030dd5SDavid du Colombier 238*83030dd5SDavid du Colombier if(sc == 0x41){ 239*83030dd5SDavid du Colombier hdebug = 1; 240*83030dd5SDavid du Colombier return; 241*83030dd5SDavid du Colombier } 242*83030dd5SDavid du Colombier if(sc == 0x42){ 243*83030dd5SDavid du Colombier hdebug = 0; 244*83030dd5SDavid du Colombier return; 245*83030dd5SDavid du Colombier } 246*83030dd5SDavid du Colombier if(kbinfd < 0 && !dryrun) 247*83030dd5SDavid du Colombier kbinfd = open("#Ι/kbin", OWRITE); 248*83030dd5SDavid du Colombier if(kbinfd < 0 && !dryrun) 249*83030dd5SDavid du Colombier sysfatal("/dev/kbin: %r"); 250*83030dd5SDavid du Colombier if(hdebug) 251*83030dd5SDavid du Colombier fprint(2, "sc: %x %x\n", (esc? SCesc1: 0), sc); 252*83030dd5SDavid du Colombier if(!dryrun){ 253*83030dd5SDavid du Colombier s[1] = sc; 254*83030dd5SDavid du Colombier if(esc && sc != 0) 255*83030dd5SDavid du Colombier write(kbinfd, s, 2); 256*83030dd5SDavid du Colombier else if(sc != 0) 257*83030dd5SDavid du Colombier write(kbinfd, s+1, 1); 258*83030dd5SDavid du Colombier } 259*83030dd5SDavid du Colombier } 260*83030dd5SDavid du Colombier 261*83030dd5SDavid du Colombier static void 262*83030dd5SDavid du Colombier repeatproc(void*) 263*83030dd5SDavid du Colombier { 264*83030dd5SDavid du Colombier ulong l; 265*83030dd5SDavid du Colombier uchar esc1, sc; 266*83030dd5SDavid du Colombier 267*83030dd5SDavid du Colombier assert(sizeof(int) <= sizeof(void*)); 268*83030dd5SDavid du Colombier 269*83030dd5SDavid du Colombier for(;;){ 270*83030dd5SDavid du Colombier l = recvul(repeatc); /* wait for work*/ 271*83030dd5SDavid du Colombier if(l == 0xdeaddead) 272*83030dd5SDavid du Colombier continue; 273*83030dd5SDavid du Colombier esc1 = l >> 8; 274*83030dd5SDavid du Colombier sc = l; 275*83030dd5SDavid du Colombier for(;;){ 276*83030dd5SDavid du Colombier putscan(esc1, sc); 277*83030dd5SDavid du Colombier sleep(80); 278*83030dd5SDavid du Colombier l = nbrecvul(repeatc); 279*83030dd5SDavid du Colombier if(l != 0){ /* stop repeating*/ 280*83030dd5SDavid du Colombier if(l != Awakemsg) 281*83030dd5SDavid du Colombier fprint(2, "kb: race: should be awake mesg\n"); 282*83030dd5SDavid du Colombier break; 283*83030dd5SDavid du Colombier } 284*83030dd5SDavid du Colombier } 285*83030dd5SDavid du Colombier } 286*83030dd5SDavid du Colombier } 287*83030dd5SDavid du Colombier 288*83030dd5SDavid du Colombier 289*83030dd5SDavid du Colombier #define hasesc1(sc) (((sc) > 0x47) || ((sc) == 0x38)) 290*83030dd5SDavid du Colombier 291*83030dd5SDavid du Colombier static void 292*83030dd5SDavid du Colombier putmod(uchar mods, uchar omods, uchar mask, uchar esc, uchar sc) 293*83030dd5SDavid du Colombier { 294*83030dd5SDavid du Colombier if((mods&mask) && !(omods&mask)) 295*83030dd5SDavid du Colombier putscan(esc, sc); 296*83030dd5SDavid du Colombier if(!(mods&mask) && (omods&mask)) 297*83030dd5SDavid du Colombier putscan(esc, Keyup|sc); 298*83030dd5SDavid du Colombier } 299*83030dd5SDavid du Colombier 300*83030dd5SDavid du Colombier /* 301*83030dd5SDavid du Colombier * This routine diffs the state with the last known state 302*83030dd5SDavid du Colombier * and invents the scan codes that would have been sent 303*83030dd5SDavid du Colombier * by a non-usb keyboard in that case. This also requires supplying 304*83030dd5SDavid du Colombier * the extra esc1 byte as well as keyup flags. 305*83030dd5SDavid du Colombier * The aim is to allow future addition of other keycode pages 306*83030dd5SDavid du Colombier * for other keyboards. 307*83030dd5SDavid du Colombier */ 308*83030dd5SDavid du Colombier static void 309*83030dd5SDavid du Colombier putkeys(uchar buf[], uchar obuf[], int n) 310*83030dd5SDavid du Colombier { 311*83030dd5SDavid du Colombier int i, j; 312*83030dd5SDavid du Colombier uchar sc; 313*83030dd5SDavid du Colombier static int repeating = 0, times = 0; 314*83030dd5SDavid du Colombier static uchar last = 0; 315*83030dd5SDavid du Colombier 316*83030dd5SDavid du Colombier putmod(buf[0], obuf[0], Mctrl, 0, SCctrl); 317*83030dd5SDavid du Colombier putmod(buf[0], obuf[0], (1<<Mlshift), 0, SClshift); 318*83030dd5SDavid du Colombier putmod(buf[0], obuf[0], (1<<Mrshift), 0, SCrshift); 319*83030dd5SDavid du Colombier putmod(buf[0], obuf[0], Mcompose, 0, SCcompose); 320*83030dd5SDavid du Colombier putmod(buf[0], obuf[0], Maltgr, 1, SCcompose); 321*83030dd5SDavid du Colombier 322*83030dd5SDavid du Colombier /* 323*83030dd5SDavid du Colombier * If we get three times the same (single) key, we start 324*83030dd5SDavid du Colombier * repeating. Otherwise, we stop repeating and 325*83030dd5SDavid du Colombier * perform normal processing. 326*83030dd5SDavid du Colombier */ 327*83030dd5SDavid du Colombier if(buf[2] != 0 && buf[3] == 0 && buf[2] == last){ 328*83030dd5SDavid du Colombier if(repeating) 329*83030dd5SDavid du Colombier return; /* already being done */ 330*83030dd5SDavid du Colombier times++; 331*83030dd5SDavid du Colombier if(times >= 2){ 332*83030dd5SDavid du Colombier repeating = 1; 333*83030dd5SDavid du Colombier sc = sctab[buf[2]]; 334*83030dd5SDavid du Colombier startrepeat(hasesc1(sc), sc); 335*83030dd5SDavid du Colombier return; 336*83030dd5SDavid du Colombier } 337*83030dd5SDavid du Colombier } else 338*83030dd5SDavid du Colombier times = 0; 339*83030dd5SDavid du Colombier last = buf[2]; 340*83030dd5SDavid du Colombier if(repeating){ 341*83030dd5SDavid du Colombier repeating = 0; 342*83030dd5SDavid du Colombier stoprepeat(); 343*83030dd5SDavid du Colombier } 344*83030dd5SDavid du Colombier 345*83030dd5SDavid du Colombier /* Report key downs */ 346*83030dd5SDavid du Colombier for(i = 2; i < n; i++){ 347*83030dd5SDavid du Colombier for(j = 2; j < n; j++) 348*83030dd5SDavid du Colombier if(buf[i] == obuf[j]) 349*83030dd5SDavid du Colombier break; 350*83030dd5SDavid du Colombier if(j == n && buf[i] != 0){ 351*83030dd5SDavid du Colombier sc = sctab[buf[i]]; 352*83030dd5SDavid du Colombier putscan(hasesc1(sc), sc); 353*83030dd5SDavid du Colombier } 354*83030dd5SDavid du Colombier } 355*83030dd5SDavid du Colombier 356*83030dd5SDavid du Colombier /* Report key ups */ 357*83030dd5SDavid du Colombier for(i = 2; i < n; i++){ 358*83030dd5SDavid du Colombier for(j = 2; j < n; j++) 359*83030dd5SDavid du Colombier if(obuf[i] == buf[j]) 360*83030dd5SDavid du Colombier break; 361*83030dd5SDavid du Colombier if(j == n && obuf[i] != 0){ 362*83030dd5SDavid du Colombier sc = sctab[obuf[i]]; 363*83030dd5SDavid du Colombier putscan(hasesc1(sc), sc|Keyup); 364*83030dd5SDavid du Colombier } 365*83030dd5SDavid du Colombier } 366*83030dd5SDavid du Colombier } 367*83030dd5SDavid du Colombier 368*83030dd5SDavid du Colombier static int 369*83030dd5SDavid du Colombier kbdbusy(uchar* buf, int n) 370*83030dd5SDavid du Colombier { 371*83030dd5SDavid du Colombier int i; 372*83030dd5SDavid du Colombier 373*83030dd5SDavid du Colombier for(i = 1; i < n; i++) 374*83030dd5SDavid du Colombier if(buf[i] == 0 || buf[i] != buf[0]) 375*83030dd5SDavid du Colombier return 0; 376*83030dd5SDavid du Colombier return 1; 377*83030dd5SDavid du Colombier } 378*83030dd5SDavid du Colombier 379*83030dd5SDavid du Colombier void 380*83030dd5SDavid du Colombier kbdwork(void *a) 381*83030dd5SDavid du Colombier { 382*83030dd5SDavid du Colombier int c, i, kbdfd; 383*83030dd5SDavid du Colombier uchar buf[64], lbuf[64]; 384*83030dd5SDavid du Colombier Dev *f = a; 385*83030dd5SDavid du Colombier 386*83030dd5SDavid du Colombier kbdfd = f->fd; 387*83030dd5SDavid du Colombier if(kbdfd < 0) 388*83030dd5SDavid du Colombier return; 389*83030dd5SDavid du Colombier if(f->msz < 3 || f->msz > sizeof buf) 390*83030dd5SDavid du Colombier sysfatal("bug: ptrwork: bad kbd maxpkt"); 391*83030dd5SDavid du Colombier repeatc = chancreate(sizeof(ulong), 0); 392*83030dd5SDavid du Colombier if(repeatc == nil) 393*83030dd5SDavid du Colombier sysfatal("repeat chan: %r"); 394*83030dd5SDavid du Colombier proccreate(repeatproc, nil, 32*1024); 395*83030dd5SDavid du Colombier memset(lbuf, 0, sizeof lbuf); 396*83030dd5SDavid du Colombier for(;;) { 397*83030dd5SDavid du Colombier memset(buf, 0, sizeof buf); 398*83030dd5SDavid du Colombier c = robustread(kbdfd, buf, f->msz); 399*83030dd5SDavid du Colombier if(c == 0) 400*83030dd5SDavid du Colombier fprint(2, "%s: %s: eof\n", argv0, f->name); 401*83030dd5SDavid du Colombier if(c < 0) 402*83030dd5SDavid du Colombier fprint(2, "%s: %s: read: %r\n", argv0, f->name); 403*83030dd5SDavid du Colombier if(c <= 0){ 404*83030dd5SDavid du Colombier if(!dryrun) 405*83030dd5SDavid du Colombier close(kbinfd); 406*83030dd5SDavid du Colombier close(f->fd); 407*83030dd5SDavid du Colombier threadexits("read"); 408*83030dd5SDavid du Colombier } 409*83030dd5SDavid du Colombier if(c < 3) 410*83030dd5SDavid du Colombier continue; 411*83030dd5SDavid du Colombier if(kbdbusy(buf + 2, c - 2)) 412*83030dd5SDavid du Colombier continue; 413*83030dd5SDavid du Colombier if(hdebug > 1){ 414*83030dd5SDavid du Colombier fprint(2, "kbd mod %x: ", buf[0]); 415*83030dd5SDavid du Colombier for(i = 2; i < c; i++) 416*83030dd5SDavid du Colombier fprint(2, "kc %x ", buf[i]); 417*83030dd5SDavid du Colombier fprint(2, "\n"); 418*83030dd5SDavid du Colombier } 419*83030dd5SDavid du Colombier putkeys(buf, lbuf, f->msz); 420*83030dd5SDavid du Colombier memmove(lbuf, buf, c); 421*83030dd5SDavid du Colombier } 422*83030dd5SDavid du Colombier } 423*83030dd5SDavid du Colombier 424*83030dd5SDavid du Colombier static int 425*83030dd5SDavid du Colombier probeif(Dev* f, int ctlrno, int i, int kcsp, int csp, int, int) 426*83030dd5SDavid du Colombier { 427*83030dd5SDavid du Colombier int found, n, sfd; 428*83030dd5SDavid du Colombier char buf[256], cspstr[50], kcspstr[50]; 429*83030dd5SDavid du Colombier 430*83030dd5SDavid du Colombier seprint(cspstr, cspstr + sizeof cspstr, "0x%0.06x", csp); 431*83030dd5SDavid du Colombier seprint(buf, buf + sizeof buf, "/dev/usb%d/%d/status", ctlrno, i); 432*83030dd5SDavid du Colombier sfd = open(buf, OREAD); 433*83030dd5SDavid du Colombier if(sfd < 0) 434*83030dd5SDavid du Colombier return -1; 435*83030dd5SDavid du Colombier n = read(sfd, buf, sizeof buf - 1); 436*83030dd5SDavid du Colombier if(n <= 0){ 437*83030dd5SDavid du Colombier close(sfd); 438*83030dd5SDavid du Colombier return -1; 439*83030dd5SDavid du Colombier } 440*83030dd5SDavid du Colombier buf[n] = 0; 441*83030dd5SDavid du Colombier close(sfd); 442*83030dd5SDavid du Colombier /* 443*83030dd5SDavid du Colombier * Mouse + keyboard combos may report the interface as Kbdcsp, 444*83030dd5SDavid du Colombier * because it's the endpoint the one with the right csp. 445*83030dd5SDavid du Colombier */ 446*83030dd5SDavid du Colombier sprint(cspstr, "Enabled 0x%0.06x", csp); 447*83030dd5SDavid du Colombier found = (strncmp(buf, cspstr, strlen(cspstr)) == 0); 448*83030dd5SDavid du Colombier if(!found){ 449*83030dd5SDavid du Colombier sprint(cspstr, " 0x%0.06x", csp); 450*83030dd5SDavid du Colombier sprint(kcspstr, "Enabled 0x%0.06x", kcsp); 451*83030dd5SDavid du Colombier if(strncmp(buf, kcspstr, strlen(kcspstr)) == 0 && 452*83030dd5SDavid du Colombier strstr(buf, cspstr) != nil) 453*83030dd5SDavid du Colombier found = 1; 454*83030dd5SDavid du Colombier } 455*83030dd5SDavid du Colombier if(found){ 456*83030dd5SDavid du Colombier f->ctlrno = ctlrno; 457*83030dd5SDavid du Colombier f->id = i; 458*83030dd5SDavid du Colombier f->enabled = 1; 459*83030dd5SDavid du Colombier if(hdebug) 460*83030dd5SDavid du Colombier fprint(2, "%s: csp 0x%x at /dev/usb%d/%d\n", 461*83030dd5SDavid du Colombier f->name, csp, f->ctlrno, f->id); 462*83030dd5SDavid du Colombier return 0; 463*83030dd5SDavid du Colombier } 464*83030dd5SDavid du Colombier if(hdebug) 465*83030dd5SDavid du Colombier fprint(2, "%s: not found %s\n", f->name, cspstr); 466*83030dd5SDavid du Colombier return -1; 467*83030dd5SDavid du Colombier 468*83030dd5SDavid du Colombier } 469*83030dd5SDavid du Colombier 470*83030dd5SDavid du Colombier static int 471*83030dd5SDavid du Colombier probedev(Dev* f, int kcsp, int csp, int vid, int did) 472*83030dd5SDavid du Colombier { 473*83030dd5SDavid du Colombier int c, i; 474*83030dd5SDavid du Colombier 475*83030dd5SDavid du Colombier for(c = 0; c < 16; c++) 476*83030dd5SDavid du Colombier if(f->ctlrno == 0 || c == f->ctlrno) 477*83030dd5SDavid du Colombier for(i = 1; i < 128; i++) 478*83030dd5SDavid du Colombier if(f->id == 0 || i == f->id) 479*83030dd5SDavid du Colombier if(probeif(f, c, i, kcsp, csp, vid, did) != -1){ 480*83030dd5SDavid du Colombier f->csp = csp; 481*83030dd5SDavid du Colombier return 0; 482*83030dd5SDavid du Colombier } 483*83030dd5SDavid du Colombier f->enabled = 0; 484*83030dd5SDavid du Colombier if(hdebug || verbose) 485*83030dd5SDavid du Colombier fprint(2, "%s: csp 0x%x: not found\n", f->name, csp); 486*83030dd5SDavid du Colombier return -1; 487*83030dd5SDavid du Colombier } 488*83030dd5SDavid du Colombier 489*83030dd5SDavid du Colombier static void 490*83030dd5SDavid du Colombier initdev(Dev* f) 491*83030dd5SDavid du Colombier { 492*83030dd5SDavid du Colombier int i; 493*83030dd5SDavid du Colombier 494*83030dd5SDavid du Colombier f->dev = opendev(f->ctlrno, f->id); 495*83030dd5SDavid du Colombier if(f->dev == nil || describedevice(f->dev) < 0) { 496*83030dd5SDavid du Colombier fprint(2, "init failed: %s: %r\n", f->name); 497*83030dd5SDavid du Colombier f->enabled = 0; 498*83030dd5SDavid du Colombier f->ctlrno = f->id = -1; 499*83030dd5SDavid du Colombier return; 500*83030dd5SDavid du Colombier } 501*83030dd5SDavid du Colombier memset(f->dev->config, 0, sizeof f->dev->config); 502*83030dd5SDavid du Colombier for(i = 0; i < f->dev->nconf; i++){ 503*83030dd5SDavid du Colombier f->dev->config[i] = mallocz(sizeof *f->dev->config[i], 1); 504*83030dd5SDavid du Colombier loadconfig(f->dev, i); 505*83030dd5SDavid du Colombier } 506*83030dd5SDavid du Colombier if(verbose || hdebug){ 507*83030dd5SDavid du Colombier fprint(2, "%s found: ctlrno=%d id=%d\n", 508*83030dd5SDavid du Colombier f->name, f->ctlrno, f->id); 509*83030dd5SDavid du Colombier // printdevice(f->dev); // TODO 510*83030dd5SDavid du Colombier } 511*83030dd5SDavid du Colombier } 512*83030dd5SDavid du Colombier 513*83030dd5SDavid du Colombier static int 514*83030dd5SDavid du Colombier setbootproto(Dev* f) 515*83030dd5SDavid du Colombier { 516*83030dd5SDavid du Colombier int r, id; 517*83030dd5SDavid du Colombier Endpt* ep; 518*83030dd5SDavid du Colombier 519*83030dd5SDavid du Colombier ep = f->dev->ep[0]; 520*83030dd5SDavid du Colombier r = RH2D | Rclass | Rinterface; 521*83030dd5SDavid du Colombier id = f->dev->ep[f->ep]->iface->interface; 522*83030dd5SDavid du Colombier return setupreq(ep, r, SET_PROTO, BOOT_PROTO, id, 0); 523*83030dd5SDavid du Colombier } 524*83030dd5SDavid du Colombier 525*83030dd5SDavid du Colombier static void 526*83030dd5SDavid du Colombier startdev(Dev* f) 527*83030dd5SDavid du Colombier { 528*83030dd5SDavid du Colombier int i; 529*83030dd5SDavid du Colombier char buf[128]; 530*83030dd5SDavid du Colombier Endpt* ep; 531*83030dd5SDavid du Colombier 532*83030dd5SDavid du Colombier f->ep = -1; 533*83030dd5SDavid du Colombier ep = nil; 534*83030dd5SDavid du Colombier for(i = 0; i < Nendpt; i++) 535*83030dd5SDavid du Colombier if((ep = f->dev->ep[i]) != nil && 536*83030dd5SDavid du Colombier ep->csp == f->csp && ep->type == Eintr && ep->dir == Ein){ 537*83030dd5SDavid du Colombier f->ep = i; 538*83030dd5SDavid du Colombier f->msz = ep->maxpkt; 539*83030dd5SDavid du Colombier break; 540*83030dd5SDavid du Colombier } 541*83030dd5SDavid du Colombier if(ep == nil){ 542*83030dd5SDavid du Colombier fprint(2, "%s: %s: bug: no endpoint\n", argv0, f->name); 543*83030dd5SDavid du Colombier return; 544*83030dd5SDavid du Colombier } 545*83030dd5SDavid du Colombier sprint(buf, "ep %d 10 r %d", f->ep, f->msz); 546*83030dd5SDavid du Colombier if(hdebug) 547*83030dd5SDavid du Colombier fprint(2, "%s: %s: ep %d: ctl %s\n", argv0, f->name, f->ep, buf); 548*83030dd5SDavid du Colombier if(write(f->dev->ctl, buf, strlen(buf)) != strlen(buf)){ 549*83030dd5SDavid du Colombier fprint(2, "%s: %s: startdev: %r\n", argv0, f->name); 550*83030dd5SDavid du Colombier return; 551*83030dd5SDavid du Colombier } 552*83030dd5SDavid du Colombier sprint(buf, "/dev/usb%d/%d/ep%ddata", f->ctlrno, f->id, f->ep); 553*83030dd5SDavid du Colombier f->fd = open(buf, OREAD); 554*83030dd5SDavid du Colombier if(f->fd < 0){ 555*83030dd5SDavid du Colombier fprint(2, "%s: opening %s: %s: %r", argv0, f->name, buf); 556*83030dd5SDavid du Colombier return; 557*83030dd5SDavid du Colombier } 558*83030dd5SDavid du Colombier if(setbootproto(f) < 0) 559*83030dd5SDavid du Colombier fprint(2, "%s: %s: setbootproto: %r\n", argv0, f->name); 560*83030dd5SDavid du Colombier if(hdebug) 561*83030dd5SDavid du Colombier fprint(2, "starting %s\n", f->name); 562*83030dd5SDavid du Colombier proccreate(f->proc, f, 32*1024); 563*83030dd5SDavid du Colombier } 564*83030dd5SDavid du Colombier 565*83030dd5SDavid du Colombier static void 566*83030dd5SDavid du Colombier usage(void) 567*83030dd5SDavid du Colombier { 568*83030dd5SDavid du Colombier fprint(2, "usage: %s [-dkmn] [-a n] [ctlrno usbport]\n", argv0); 569*83030dd5SDavid du Colombier threadexitsall("usage"); 570*83030dd5SDavid du Colombier } 571*83030dd5SDavid du Colombier 572*83030dd5SDavid du Colombier void 573*83030dd5SDavid du Colombier threadmain(int argc, char **argv) 574*83030dd5SDavid du Colombier { 575*83030dd5SDavid du Colombier 576*83030dd5SDavid du Colombier quotefmtinstall(); 577*83030dd5SDavid du Colombier usbfmtinit(); 578*83030dd5SDavid du Colombier 579*83030dd5SDavid du Colombier pf.enabled = kf.enabled = 1; 580*83030dd5SDavid du Colombier ARGBEGIN{ 581*83030dd5SDavid du Colombier case 'a': 582*83030dd5SDavid du Colombier accel = strtol(EARGF(usage()), nil, 0); 583*83030dd5SDavid du Colombier break; 584*83030dd5SDavid du Colombier case 'd': 585*83030dd5SDavid du Colombier hdebug++; 586*83030dd5SDavid du Colombier usbdebug++; 587*83030dd5SDavid du Colombier break; 588*83030dd5SDavid du Colombier case 'k': 589*83030dd5SDavid du Colombier kf.enabled = 1; 590*83030dd5SDavid du Colombier pf.enabled = 0; 591*83030dd5SDavid du Colombier break; 592*83030dd5SDavid du Colombier case 'm': 593*83030dd5SDavid du Colombier kf.enabled = 0; 594*83030dd5SDavid du Colombier pf.enabled = 1; 595*83030dd5SDavid du Colombier break; 596*83030dd5SDavid du Colombier case 'n': 597*83030dd5SDavid du Colombier dryrun = 1; 598*83030dd5SDavid du Colombier break; 599*83030dd5SDavid du Colombier default: 600*83030dd5SDavid du Colombier usage(); 601*83030dd5SDavid du Colombier }ARGEND; 602*83030dd5SDavid du Colombier 603*83030dd5SDavid du Colombier switch(argc){ 604*83030dd5SDavid du Colombier case 0: 605*83030dd5SDavid du Colombier break; 606*83030dd5SDavid du Colombier case 2: 607*83030dd5SDavid du Colombier pf.ctlrno = kf.ctlrno = atoi(argv[0]); 608*83030dd5SDavid du Colombier pf.id = kf.id = atoi(argv[1]); 609*83030dd5SDavid du Colombier break; 610*83030dd5SDavid du Colombier default: 611*83030dd5SDavid du Colombier usage(); 612*83030dd5SDavid du Colombier } 613*83030dd5SDavid du Colombier threadnotify(robusthandler, 1); 614*83030dd5SDavid du Colombier 615*83030dd5SDavid du Colombier kf.name = "kbd"; 616*83030dd5SDavid du Colombier kf.proc = kbdwork; 617*83030dd5SDavid du Colombier pf.name = "mouse"; 618*83030dd5SDavid du Colombier pf.proc = ptrwork; 619*83030dd5SDavid du Colombier 620*83030dd5SDavid du Colombier if(kf.enabled) 621*83030dd5SDavid du Colombier probedev(&kf, KbdCSP, KbdCSP, 0, 0); 622*83030dd5SDavid du Colombier if(kf.enabled) 623*83030dd5SDavid du Colombier initdev(&kf); 624*83030dd5SDavid du Colombier if(pf.enabled) 625*83030dd5SDavid du Colombier probedev(&pf, KbdCSP, PtrCSP, 0, 0); 626*83030dd5SDavid du Colombier if(pf.enabled) 627*83030dd5SDavid du Colombier if(kf.enabled && pf.ctlrno == kf.ctlrno && pf.id == kf.id) 628*83030dd5SDavid du Colombier pf.dev = kf.dev; 629*83030dd5SDavid du Colombier else 630*83030dd5SDavid du Colombier initdev(&pf); 631*83030dd5SDavid du Colombier rfork(RFNOTEG); 632*83030dd5SDavid du Colombier if(kf.enabled) 633*83030dd5SDavid du Colombier startdev(&kf); 634*83030dd5SDavid du Colombier if(pf.enabled) 635*83030dd5SDavid du Colombier startdev(&pf); 636*83030dd5SDavid du Colombier threadexits(nil); 637*83030dd5SDavid du Colombier } 638