183030dd5SDavid du Colombier /* 283030dd5SDavid du Colombier * USB Human Interaction Device: keyboard and mouse. 383030dd5SDavid du Colombier * 483030dd5SDavid du Colombier * If there's no usb keyboard, it tries to setup the mouse, if any. 583030dd5SDavid du Colombier * It should be started at boot time. 683030dd5SDavid du Colombier * 783030dd5SDavid du Colombier * Mouse events are converted to the format of mouse(3)'s 883030dd5SDavid du Colombier * mousein file. 983030dd5SDavid du Colombier * Keyboard keycodes are translated to scan codes and sent to kbin(3). 1083030dd5SDavid du Colombier * 1183030dd5SDavid du Colombier */ 1283030dd5SDavid du Colombier 1383030dd5SDavid du Colombier #include <u.h> 1483030dd5SDavid du Colombier #include <libc.h> 1583030dd5SDavid du Colombier #include <thread.h> 1683030dd5SDavid du Colombier #include "usb.h" 1783030dd5SDavid du Colombier #include "hid.h" 1883030dd5SDavid du Colombier 19906943f9SDavid du Colombier enum 20906943f9SDavid du Colombier { 21906943f9SDavid du Colombier Awakemsg=0xdeaddead, 22906943f9SDavid du Colombier Diemsg = 0xbeefbeef, 23906943f9SDavid du Colombier }; 24906943f9SDavid du Colombier 25906943f9SDavid du Colombier typedef struct KDev KDev; 26906943f9SDavid du Colombier typedef struct Kin Kin; 27906943f9SDavid du Colombier 28906943f9SDavid du Colombier struct KDev 29906943f9SDavid du Colombier { 30906943f9SDavid du Colombier Dev* dev; /* usb device*/ 31906943f9SDavid du Colombier Dev* ep; /* endpoint to get events */ 32906943f9SDavid du Colombier Kin* in; /* used to send events to kernel */ 33906943f9SDavid du Colombier Channel*repeatc; /* only for keyboard */ 34906943f9SDavid du Colombier int accel; /* only for mouse */ 35906943f9SDavid du Colombier }; 36906943f9SDavid du Colombier 37906943f9SDavid du Colombier /* 38906943f9SDavid du Colombier * Kbdin and mousein files must be shared among all instances. 39906943f9SDavid du Colombier */ 40906943f9SDavid du Colombier struct Kin 41906943f9SDavid du Colombier { 42906943f9SDavid du Colombier int ref; 43906943f9SDavid du Colombier int fd; 44906943f9SDavid du Colombier char* name; 45906943f9SDavid du Colombier }; 46906943f9SDavid du Colombier 4783030dd5SDavid du Colombier /* 4883030dd5SDavid du Colombier * Map for the logitech bluetooth mouse with 8 buttons and wheels. 4983030dd5SDavid du Colombier * { ptr ->mouse} 5083030dd5SDavid du Colombier * { 0x01, 0x01 }, // left 5183030dd5SDavid du Colombier * { 0x04, 0x02 }, // middle 5283030dd5SDavid du Colombier * { 0x02, 0x04 }, // right 5383030dd5SDavid du Colombier * { 0x40, 0x08 }, // up 5483030dd5SDavid du Colombier * { 0x80, 0x10 }, // down 5583030dd5SDavid du Colombier * { 0x10, 0x08 }, // side up 5683030dd5SDavid du Colombier * { 0x08, 0x10 }, // side down 5783030dd5SDavid du Colombier * { 0x20, 0x02 }, // page 5883030dd5SDavid du Colombier * besides wheel and regular up/down report the 4th byte as 1/-1 5983030dd5SDavid du Colombier */ 6083030dd5SDavid du Colombier 6183030dd5SDavid du Colombier /* 6283030dd5SDavid du Colombier * key code to scan code; for the page table used by 6383030dd5SDavid du Colombier * the logitech bluetooth keyboard. 6483030dd5SDavid du Colombier */ 65906943f9SDavid du Colombier static char sctab[256] = 6683030dd5SDavid du Colombier { 6783030dd5SDavid du Colombier [0x00] 0x0, 0x0, 0x0, 0x0, 0x1e, 0x30, 0x2e, 0x20, 6883030dd5SDavid du Colombier [0x08] 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 6983030dd5SDavid du Colombier [0x10] 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 7083030dd5SDavid du Colombier [0x18] 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x2, 0x3, 7183030dd5SDavid du Colombier [0x20] 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 7283030dd5SDavid du Colombier [0x28] 0x1c, 0x1, 0xe, 0xf, 0x39, 0xc, 0xd, 0x1a, 7383030dd5SDavid du Colombier [0x30] 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, 7483030dd5SDavid du Colombier [0x38] 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 7583030dd5SDavid du Colombier [0x40] 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0x63, 0x46, 7683030dd5SDavid du Colombier [0x48] 0x77, 0x52, 0x47, 0x49, 0x53, 0x4f, 0x51, 0x4d, 7783030dd5SDavid du Colombier [0x50] 0x4b, 0x50, 0x48, 0x45, 0x35, 0x37, 0x4a, 0x4e, 7883030dd5SDavid du Colombier [0x58] 0x1c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, 7983030dd5SDavid du Colombier [0x60] 0x48, 0x49, 0x52, 0x53, 0x56, 0x7f, 0x74, 0x75, 8083030dd5SDavid du Colombier [0x68] 0x55, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 8183030dd5SDavid du Colombier [0x70] 0x78, 0x79, 0x7a, 0x7b, 0x0, 0x0, 0x0, 0x0, 8283030dd5SDavid du Colombier [0x78] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 8383030dd5SDavid du Colombier [0x80] 0x73, 0x72, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 8483030dd5SDavid du Colombier [0x88] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 8583030dd5SDavid du Colombier [0x90] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 8683030dd5SDavid du Colombier [0x98] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 8783030dd5SDavid du Colombier [0xa0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 8883030dd5SDavid du Colombier [0xa8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 8983030dd5SDavid du Colombier [0xb0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9083030dd5SDavid du Colombier [0xb8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9183030dd5SDavid du Colombier [0xc0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9283030dd5SDavid du Colombier [0xc8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9383030dd5SDavid du Colombier [0xd0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9483030dd5SDavid du Colombier [0xd8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9583030dd5SDavid du Colombier [0xe0] 0x1d, 0x2a, 0x38, 0x7d, 0x61, 0x36, 0x64, 0x7e, 9683030dd5SDavid du Colombier [0xe8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x73, 0x72, 0x71, 9783030dd5SDavid du Colombier [0xf0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9883030dd5SDavid du Colombier [0xf8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9983030dd5SDavid du Colombier }; 10083030dd5SDavid du Colombier 101906943f9SDavid du Colombier static QLock inlck; 102906943f9SDavid du Colombier static Kin kbdin = 103906943f9SDavid du Colombier { 104906943f9SDavid du Colombier .ref = 0, 105906943f9SDavid du Colombier .name = "#Ι/kbin", 106906943f9SDavid du Colombier .fd = -1, 107906943f9SDavid du Colombier }; 108906943f9SDavid du Colombier static Kin ptrin = 109906943f9SDavid du Colombier { 110906943f9SDavid du Colombier .ref = 0, 111906943f9SDavid du Colombier .name = "#m/mousein", 112906943f9SDavid du Colombier .fd = -1, 11383030dd5SDavid du Colombier }; 11483030dd5SDavid du Colombier 115906943f9SDavid du Colombier static int kbdebug; 11683030dd5SDavid du Colombier 117906943f9SDavid du Colombier static void 118906943f9SDavid du Colombier kbfatal(KDev *kd, char *sts) 11983030dd5SDavid du Colombier { 120906943f9SDavid du Colombier Dev *dev; 12183030dd5SDavid du Colombier 122906943f9SDavid du Colombier if(sts != nil) 123*39dc1420SDavid du Colombier fprint(2, "kb: fatal: %s\n", sts); 124*39dc1420SDavid du Colombier else 125*39dc1420SDavid du Colombier fprint(2, "kb: exiting\n"); 126906943f9SDavid du Colombier if(kd->repeatc != nil) 127*39dc1420SDavid du Colombier nbsendul(kd->repeatc, Diemsg); 128*39dc1420SDavid du Colombier dev = kd->dev; 129*39dc1420SDavid du Colombier kd->dev = nil; 130*39dc1420SDavid du Colombier if(kd->ep != nil) 131906943f9SDavid du Colombier closedev(kd->ep); 132906943f9SDavid du Colombier kd->ep = nil; 133*39dc1420SDavid du Colombier devctl(dev, "detach"); 134906943f9SDavid du Colombier closedev(dev); 135906943f9SDavid du Colombier /* 136906943f9SDavid du Colombier * free(kd); done by closedev. 137906943f9SDavid du Colombier */ 138906943f9SDavid du Colombier threadexits(sts); 13983030dd5SDavid du Colombier } 14083030dd5SDavid du Colombier 14183030dd5SDavid du Colombier static int 142906943f9SDavid du Colombier scale(KDev *f, int x) 14383030dd5SDavid du Colombier { 14483030dd5SDavid du Colombier int sign = 1; 14583030dd5SDavid du Colombier 14683030dd5SDavid du Colombier if(x < 0){ 14783030dd5SDavid du Colombier sign = -1; 14883030dd5SDavid du Colombier x = -x; 14983030dd5SDavid du Colombier } 15083030dd5SDavid du Colombier switch(x){ 15183030dd5SDavid du Colombier case 0: 15283030dd5SDavid du Colombier case 1: 15383030dd5SDavid du Colombier case 2: 15483030dd5SDavid du Colombier case 3: 15583030dd5SDavid du Colombier break; 15683030dd5SDavid du Colombier case 4: 157906943f9SDavid du Colombier x = 6 + (f->accel>>2); 15883030dd5SDavid du Colombier break; 15983030dd5SDavid du Colombier case 5: 160906943f9SDavid du Colombier x = 9 + (f->accel>>1); 16183030dd5SDavid du Colombier break; 16283030dd5SDavid du Colombier default: 16383030dd5SDavid du Colombier x *= MaxAcc; 16483030dd5SDavid du Colombier break; 16583030dd5SDavid du Colombier } 16683030dd5SDavid du Colombier return sign*x; 16783030dd5SDavid du Colombier } 16883030dd5SDavid du Colombier 169906943f9SDavid du Colombier /* 170906943f9SDavid du Colombier * ps2 mouse is processed mostly at interrupt time. 171906943f9SDavid du Colombier * for usb we do what we can. 172906943f9SDavid du Colombier */ 173906943f9SDavid du Colombier static void 174906943f9SDavid du Colombier sethipri(void) 175906943f9SDavid du Colombier { 176906943f9SDavid du Colombier char fn[30]; 177906943f9SDavid du Colombier int fd; 178906943f9SDavid du Colombier 179906943f9SDavid du Colombier snprint(fn, sizeof(fn), "/proc/%d/ctl", getpid()); 180906943f9SDavid du Colombier fd = open(fn, OWRITE); 181906943f9SDavid du Colombier if(fd < 0) 182906943f9SDavid du Colombier return; 183906943f9SDavid du Colombier fprint(fd, "pri 13"); 184906943f9SDavid du Colombier close(fd); 185906943f9SDavid du Colombier } 186906943f9SDavid du Colombier 187906943f9SDavid du Colombier static void 18883030dd5SDavid du Colombier ptrwork(void* a) 18983030dd5SDavid du Colombier { 19083030dd5SDavid du Colombier static char maptab[] = {0x0, 0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7}; 191906943f9SDavid du Colombier int x, y, b, c, ptrfd; 192906943f9SDavid du Colombier int mfd; 193906943f9SDavid du Colombier char buf[32]; 194906943f9SDavid du Colombier char mbuf[80]; 195906943f9SDavid du Colombier KDev* f = a; 196906943f9SDavid du Colombier int hipri; 19783030dd5SDavid du Colombier 198906943f9SDavid du Colombier hipri = 0; 199906943f9SDavid du Colombier ptrfd = f->ep->dfd; 200906943f9SDavid du Colombier mfd = f->in->fd; 201906943f9SDavid du Colombier 202906943f9SDavid du Colombier if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) 203*39dc1420SDavid du Colombier kbfatal(f, "weird mouse maxpkt"); 20483030dd5SDavid du Colombier for(;;){ 20583030dd5SDavid du Colombier memset(buf, 0, sizeof buf); 206*39dc1420SDavid du Colombier if(f->ep == nil) 207*39dc1420SDavid du Colombier kbfatal(f, nil); 208906943f9SDavid du Colombier c = read(ptrfd, buf, f->ep->maxpkt); 209*39dc1420SDavid du Colombier assert(f->dev != nil); 210*39dc1420SDavid du Colombier assert(f->ep != nil); 21183030dd5SDavid du Colombier if(c < 0) 212*39dc1420SDavid du Colombier dprint(2, "kb: mouse: %s: read: %r\n", f->ep->dir); 213906943f9SDavid du Colombier if(c <= 0) 214906943f9SDavid du Colombier kbfatal(f, nil); 21583030dd5SDavid du Colombier if(c < 3) 21683030dd5SDavid du Colombier continue; 217906943f9SDavid du Colombier if(f->accel){ 218906943f9SDavid du Colombier x = scale(f, buf[1]); 219906943f9SDavid du Colombier y = scale(f, buf[2]); 22083030dd5SDavid du Colombier }else{ 22183030dd5SDavid du Colombier x = buf[1]; 22283030dd5SDavid du Colombier y = buf[2]; 22383030dd5SDavid du Colombier } 22483030dd5SDavid du Colombier b = maptab[buf[0] & 0x7]; 22583030dd5SDavid du Colombier if(c > 3 && buf[3] == 1) /* up */ 22683030dd5SDavid du Colombier b |= 0x08; 22783030dd5SDavid du Colombier if(c > 3 && buf[3] == -1) /* down */ 22883030dd5SDavid du Colombier b |= 0x10; 229906943f9SDavid du Colombier if(kbdebug) 230*39dc1420SDavid du Colombier fprint(2, "kb: m%11d %11d %11d\n", x, y, b); 231906943f9SDavid du Colombier seprint(mbuf, mbuf+sizeof(mbuf), "m%11d %11d %11d", x, y,b); 232*39dc1420SDavid du Colombier if(write(mfd, mbuf, strlen(mbuf)) < 0) 233*39dc1420SDavid du Colombier kbfatal(f, "mousein i/o"); 234906943f9SDavid du Colombier if(hipri == 0){ 235906943f9SDavid du Colombier sethipri(); 236906943f9SDavid du Colombier hipri = 1; 23783030dd5SDavid du Colombier } 23883030dd5SDavid du Colombier } 23983030dd5SDavid du Colombier } 24083030dd5SDavid du Colombier 24183030dd5SDavid du Colombier static void 242906943f9SDavid du Colombier stoprepeat(KDev *f) 24383030dd5SDavid du Colombier { 244906943f9SDavid du Colombier sendul(f->repeatc, Awakemsg); 24583030dd5SDavid du Colombier } 24683030dd5SDavid du Colombier 24783030dd5SDavid du Colombier static void 248906943f9SDavid du Colombier startrepeat(KDev *f, uchar esc1, uchar sc) 24983030dd5SDavid du Colombier { 25083030dd5SDavid du Colombier ulong c; 25183030dd5SDavid du Colombier 25283030dd5SDavid du Colombier if(esc1) 25383030dd5SDavid du Colombier c = SCesc1 << 8 | (sc & 0xff); 25483030dd5SDavid du Colombier else 25583030dd5SDavid du Colombier c = sc; 256906943f9SDavid du Colombier sendul(f->repeatc, c); 25783030dd5SDavid du Colombier } 25883030dd5SDavid du Colombier 25983030dd5SDavid du Colombier static void 260906943f9SDavid du Colombier putscan(int kbinfd, uchar esc, uchar sc) 26183030dd5SDavid du Colombier { 262906943f9SDavid du Colombier uchar s[2] = {SCesc1, 0}; 26383030dd5SDavid du Colombier 26483030dd5SDavid du Colombier if(sc == 0x41){ 265906943f9SDavid du Colombier kbdebug++; 26683030dd5SDavid du Colombier return; 26783030dd5SDavid du Colombier } 26883030dd5SDavid du Colombier if(sc == 0x42){ 269906943f9SDavid du Colombier kbdebug = 0; 27083030dd5SDavid du Colombier return; 27183030dd5SDavid du Colombier } 272906943f9SDavid du Colombier if(kbdebug) 27383030dd5SDavid du Colombier fprint(2, "sc: %x %x\n", (esc? SCesc1: 0), sc); 27483030dd5SDavid du Colombier s[1] = sc; 27583030dd5SDavid du Colombier if(esc && sc != 0) 27683030dd5SDavid du Colombier write(kbinfd, s, 2); 27783030dd5SDavid du Colombier else if(sc != 0) 27883030dd5SDavid du Colombier write(kbinfd, s+1, 1); 27983030dd5SDavid du Colombier } 28083030dd5SDavid du Colombier 28183030dd5SDavid du Colombier static void 282906943f9SDavid du Colombier repeatproc(void* a) 28383030dd5SDavid du Colombier { 284906943f9SDavid du Colombier KDev *f; 285906943f9SDavid du Colombier Channel *repeatc; 286906943f9SDavid du Colombier int kbdinfd; 287906943f9SDavid du Colombier ulong l, t, i; 28883030dd5SDavid du Colombier uchar esc1, sc; 28983030dd5SDavid du Colombier 290906943f9SDavid du Colombier /* 291906943f9SDavid du Colombier * too many jumps here. 292906943f9SDavid du Colombier * Rewrite instead of debug, if needed. 293906943f9SDavid du Colombier */ 294906943f9SDavid du Colombier f = a; 295906943f9SDavid du Colombier repeatc = f->repeatc; 296906943f9SDavid du Colombier kbdinfd = f->in->fd; 297906943f9SDavid du Colombier l = Awakemsg; 298906943f9SDavid du Colombier Repeat: 299906943f9SDavid du Colombier if(l == Diemsg) 300906943f9SDavid du Colombier goto Abort; 301906943f9SDavid du Colombier while(l == Awakemsg) 302906943f9SDavid du Colombier l = recvul(repeatc); 303906943f9SDavid du Colombier if(l == Diemsg) 304906943f9SDavid du Colombier goto Abort; 30583030dd5SDavid du Colombier esc1 = l >> 8; 30683030dd5SDavid du Colombier sc = l; 307906943f9SDavid du Colombier t = 160; 30883030dd5SDavid du Colombier for(;;){ 309906943f9SDavid du Colombier for(i = 0; i < t; i += 5){ 310906943f9SDavid du Colombier if(l = nbrecvul(repeatc)) 311906943f9SDavid du Colombier goto Repeat; 312906943f9SDavid du Colombier sleep(5); 31383030dd5SDavid du Colombier } 314906943f9SDavid du Colombier putscan(kbdinfd, esc1, sc); 315906943f9SDavid du Colombier t = 30; 31683030dd5SDavid du Colombier } 317906943f9SDavid du Colombier Abort: 318906943f9SDavid du Colombier chanfree(repeatc); 319906943f9SDavid du Colombier threadexits("aborted"); 320906943f9SDavid du Colombier 32183030dd5SDavid du Colombier } 32283030dd5SDavid du Colombier 32383030dd5SDavid du Colombier 32483030dd5SDavid du Colombier #define hasesc1(sc) (((sc) > 0x47) || ((sc) == 0x38)) 32583030dd5SDavid du Colombier 32683030dd5SDavid du Colombier static void 327906943f9SDavid du Colombier putmod(int fd, uchar mods, uchar omods, uchar mask, uchar esc, uchar sc) 32883030dd5SDavid du Colombier { 329906943f9SDavid du Colombier /* BUG: Should be a single write */ 33083030dd5SDavid du Colombier if((mods&mask) && !(omods&mask)) 331906943f9SDavid du Colombier putscan(fd, esc, sc); 33283030dd5SDavid du Colombier if(!(mods&mask) && (omods&mask)) 333906943f9SDavid du Colombier putscan(fd, esc, Keyup|sc); 33483030dd5SDavid du Colombier } 33583030dd5SDavid du Colombier 33683030dd5SDavid du Colombier /* 33783030dd5SDavid du Colombier * This routine diffs the state with the last known state 33883030dd5SDavid du Colombier * and invents the scan codes that would have been sent 33983030dd5SDavid du Colombier * by a non-usb keyboard in that case. This also requires supplying 34083030dd5SDavid du Colombier * the extra esc1 byte as well as keyup flags. 34183030dd5SDavid du Colombier * The aim is to allow future addition of other keycode pages 34283030dd5SDavid du Colombier * for other keyboards. 34383030dd5SDavid du Colombier */ 344906943f9SDavid du Colombier static uchar 345906943f9SDavid du Colombier putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk) 34683030dd5SDavid du Colombier { 34783030dd5SDavid du Colombier int i, j; 348906943f9SDavid du Colombier uchar uk; 349906943f9SDavid du Colombier int fd; 35083030dd5SDavid du Colombier 351906943f9SDavid du Colombier fd = f->in->fd; 352906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Mctrl, 0, SCctrl); 353906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], (1<<Mlshift), 0, SClshift); 354906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], (1<<Mrshift), 0, SCrshift); 355906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Mcompose, 0, SCcompose); 356906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Maltgr, 1, SCcompose); 35783030dd5SDavid du Colombier 35883030dd5SDavid du Colombier /* Report key downs */ 35983030dd5SDavid du Colombier for(i = 2; i < n; i++){ 36083030dd5SDavid du Colombier for(j = 2; j < n; j++) 36183030dd5SDavid du Colombier if(buf[i] == obuf[j]) 36283030dd5SDavid du Colombier break; 36383030dd5SDavid du Colombier if(j == n && buf[i] != 0){ 364906943f9SDavid du Colombier dk = sctab[buf[i]]; 365906943f9SDavid du Colombier putscan(fd, hasesc1(dk), dk); 366906943f9SDavid du Colombier startrepeat(f, hasesc1(dk), dk); 36783030dd5SDavid du Colombier } 36883030dd5SDavid du Colombier } 36983030dd5SDavid du Colombier 37083030dd5SDavid du Colombier /* Report key ups */ 371906943f9SDavid du Colombier uk = 0; 37283030dd5SDavid du Colombier for(i = 2; i < n; i++){ 37383030dd5SDavid du Colombier for(j = 2; j < n; j++) 37483030dd5SDavid du Colombier if(obuf[i] == buf[j]) 37583030dd5SDavid du Colombier break; 37683030dd5SDavid du Colombier if(j == n && obuf[i] != 0){ 377906943f9SDavid du Colombier uk = sctab[obuf[i]]; 378906943f9SDavid du Colombier putscan(fd, hasesc1(uk), uk|Keyup); 37983030dd5SDavid du Colombier } 38083030dd5SDavid du Colombier } 381906943f9SDavid du Colombier if(uk && (dk == 0 || dk == uk)){ 382906943f9SDavid du Colombier stoprepeat(f); 383906943f9SDavid du Colombier dk = 0; 384906943f9SDavid du Colombier } 385906943f9SDavid du Colombier return dk; 38683030dd5SDavid du Colombier } 38783030dd5SDavid du Colombier 38883030dd5SDavid du Colombier static int 38983030dd5SDavid du Colombier kbdbusy(uchar* buf, int n) 39083030dd5SDavid du Colombier { 39183030dd5SDavid du Colombier int i; 39283030dd5SDavid du Colombier 39383030dd5SDavid du Colombier for(i = 1; i < n; i++) 39483030dd5SDavid du Colombier if(buf[i] == 0 || buf[i] != buf[0]) 39583030dd5SDavid du Colombier return 0; 39683030dd5SDavid du Colombier return 1; 39783030dd5SDavid du Colombier } 39883030dd5SDavid du Colombier 399906943f9SDavid du Colombier static void 40083030dd5SDavid du Colombier kbdwork(void *a) 40183030dd5SDavid du Colombier { 40283030dd5SDavid du Colombier int c, i, kbdfd; 40383030dd5SDavid du Colombier uchar buf[64], lbuf[64]; 404906943f9SDavid du Colombier KDev *f = a; 405906943f9SDavid du Colombier uchar dk; 40683030dd5SDavid du Colombier 407906943f9SDavid du Colombier kbdfd = f->ep->dfd; 408906943f9SDavid du Colombier 409906943f9SDavid du Colombier if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) 410906943f9SDavid du Colombier kbfatal(f, "weird maxpkt"); 411906943f9SDavid du Colombier 412906943f9SDavid du Colombier f->repeatc = chancreate(sizeof(ulong), 0); 413906943f9SDavid du Colombier if(f->repeatc == nil) 414906943f9SDavid du Colombier kbfatal(f, "chancreate failed"); 415906943f9SDavid du Colombier 416906943f9SDavid du Colombier proccreate(repeatproc, f, Stack); 41783030dd5SDavid du Colombier memset(lbuf, 0, sizeof lbuf); 418906943f9SDavid du Colombier dk = 0; 41983030dd5SDavid du Colombier for(;;){ 42083030dd5SDavid du Colombier memset(buf, 0, sizeof buf); 421906943f9SDavid du Colombier c = read(kbdfd, buf, f->ep->maxpkt); 422*39dc1420SDavid du Colombier assert(f->dev != nil); 423*39dc1420SDavid du Colombier assert(f->ep != nil); 424906943f9SDavid du Colombier if(c < 0) 425*39dc1420SDavid du Colombier dprint(2, "kb: %s: read: %r\n", f->ep->dir); 426906943f9SDavid du Colombier if(c <= 0) 427*39dc1420SDavid du Colombier kbfatal(f, nil); 42883030dd5SDavid du Colombier if(c < 3) 42983030dd5SDavid du Colombier continue; 43083030dd5SDavid du Colombier if(kbdbusy(buf + 2, c - 2)) 43183030dd5SDavid du Colombier continue; 432906943f9SDavid du Colombier if(usbdebug > 1 || kbdebug > 1){ 43383030dd5SDavid du Colombier fprint(2, "kbd mod %x: ", buf[0]); 43483030dd5SDavid du Colombier for(i = 2; i < c; i++) 43583030dd5SDavid du Colombier fprint(2, "kc %x ", buf[i]); 43683030dd5SDavid du Colombier fprint(2, "\n"); 43783030dd5SDavid du Colombier } 438906943f9SDavid du Colombier dk = putkeys(f, buf, lbuf, f->ep->maxpkt, dk); 43983030dd5SDavid du Colombier memmove(lbuf, buf, c); 44083030dd5SDavid du Colombier } 44183030dd5SDavid du Colombier } 44283030dd5SDavid du Colombier 44383030dd5SDavid du Colombier static int 444906943f9SDavid du Colombier setbootproto(KDev* f, int eid) 44583030dd5SDavid du Colombier { 44683030dd5SDavid du Colombier int r, id; 44783030dd5SDavid du Colombier 448906943f9SDavid du Colombier r = Rh2d|Rclass|Riface; 449906943f9SDavid du Colombier id = f->dev->usb->ep[eid]->iface->id; 450906943f9SDavid du Colombier return usbcmd(f->dev, r, Setproto, Bootproto, id, nil, 0); 45183030dd5SDavid du Colombier } 45283030dd5SDavid du Colombier 45383030dd5SDavid du Colombier static void 454906943f9SDavid du Colombier freekdev(void *a) 45583030dd5SDavid du Colombier { 456906943f9SDavid du Colombier KDev *kd; 45783030dd5SDavid du Colombier 458906943f9SDavid du Colombier kd = a; 459906943f9SDavid du Colombier if(kd->in != nil){ 460906943f9SDavid du Colombier qlock(&inlck); 461906943f9SDavid du Colombier if(--kd->in->ref == 0){ 462906943f9SDavid du Colombier close(kd->in->fd); 463906943f9SDavid du Colombier kd->in->fd = -1; 46483030dd5SDavid du Colombier } 465906943f9SDavid du Colombier qunlock(&inlck); 46683030dd5SDavid du Colombier } 467*39dc1420SDavid du Colombier dprint(2, "freekdev\n"); 468906943f9SDavid du Colombier free(kd); 46983030dd5SDavid du Colombier } 47083030dd5SDavid du Colombier 47183030dd5SDavid du Colombier static void 472906943f9SDavid du Colombier kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), int accel) 473906943f9SDavid du Colombier { 474906943f9SDavid du Colombier KDev *kd; 475906943f9SDavid du Colombier 476906943f9SDavid du Colombier qlock(&inlck); 477906943f9SDavid du Colombier if(in->fd < 0){ 478906943f9SDavid du Colombier in->fd = open(in->name, OWRITE); 479906943f9SDavid du Colombier if(in->fd < 0){ 480906943f9SDavid du Colombier fprint(2, "kb: %s: %r\n", in->name); 481906943f9SDavid du Colombier qunlock(&inlck); 482906943f9SDavid du Colombier return; 483906943f9SDavid du Colombier } 484906943f9SDavid du Colombier } 485*39dc1420SDavid du Colombier in->ref++; /* for kd->in = in */ 486906943f9SDavid du Colombier qunlock(&inlck); 487906943f9SDavid du Colombier kd = d->aux = emallocz(sizeof(KDev), 1); 488906943f9SDavid du Colombier d->free = freekdev; 489906943f9SDavid du Colombier kd->in = in; 490906943f9SDavid du Colombier kd->dev = d; 491906943f9SDavid du Colombier if(setbootproto(kd, ep->id) < 0){ 492906943f9SDavid du Colombier fprint(2, "kb: %s: bootproto: %r\n", d->dir); 493906943f9SDavid du Colombier return; 494906943f9SDavid du Colombier } 495906943f9SDavid du Colombier kd->accel = accel; 496906943f9SDavid du Colombier kd->ep = openep(d, ep->id); 497906943f9SDavid du Colombier if(kd->ep == nil){ 498906943f9SDavid du Colombier fprint(2, "kb: %s: openep %d: %r\n", d->dir, ep->id); 499906943f9SDavid du Colombier return; 500906943f9SDavid du Colombier } 501906943f9SDavid du Colombier if(opendevdata(kd->ep, OREAD) < 0){ 502906943f9SDavid du Colombier fprint(2, "kb: %s: opendevdata: %r\n", kd->ep->dir); 503906943f9SDavid du Colombier closedev(kd->ep); 504906943f9SDavid du Colombier kd->ep = nil; 505906943f9SDavid du Colombier return; 506906943f9SDavid du Colombier } 507906943f9SDavid du Colombier 508906943f9SDavid du Colombier incref(d); 509906943f9SDavid du Colombier proccreate(f, kd, Stack); 510906943f9SDavid du Colombier } 511906943f9SDavid du Colombier 512906943f9SDavid du Colombier static int 51383030dd5SDavid du Colombier usage(void) 51483030dd5SDavid du Colombier { 515906943f9SDavid du Colombier werrstr("usage: usb/kb [-dkmn] [-a n]"); 516906943f9SDavid du Colombier return -1; 51783030dd5SDavid du Colombier } 51883030dd5SDavid du Colombier 519906943f9SDavid du Colombier int 520906943f9SDavid du Colombier kbmain(Dev *d, int argc, char* argv[]) 52183030dd5SDavid du Colombier { 522906943f9SDavid du Colombier int i; 523906943f9SDavid du Colombier int kena; 524906943f9SDavid du Colombier int pena; 525906943f9SDavid du Colombier int accel; 526906943f9SDavid du Colombier char *as; 527906943f9SDavid du Colombier Usbdev *ud; 528906943f9SDavid du Colombier Ep *ep; 52983030dd5SDavid du Colombier 530906943f9SDavid du Colombier kena = pena = 1; 531906943f9SDavid du Colombier accel = 0; 53283030dd5SDavid du Colombier ARGBEGIN{ 53383030dd5SDavid du Colombier case 'a': 534906943f9SDavid du Colombier as = ARGF(); 535906943f9SDavid du Colombier if(as == nil) 536906943f9SDavid du Colombier return usage(); 537906943f9SDavid du Colombier accel = strtol(as, nil, 0); 53883030dd5SDavid du Colombier break; 53983030dd5SDavid du Colombier case 'd': 540906943f9SDavid du Colombier kbdebug++; 54183030dd5SDavid du Colombier break; 54283030dd5SDavid du Colombier case 'k': 543906943f9SDavid du Colombier kena = 1; 544906943f9SDavid du Colombier pena = 0; 54583030dd5SDavid du Colombier break; 54683030dd5SDavid du Colombier case 'm': 547906943f9SDavid du Colombier kena = 0; 548906943f9SDavid du Colombier pena = 1; 54983030dd5SDavid du Colombier break; 55083030dd5SDavid du Colombier default: 551906943f9SDavid du Colombier return usage(); 55283030dd5SDavid du Colombier }ARGEND; 553906943f9SDavid du Colombier if(argc != 0){ 554906943f9SDavid du Colombier return usage(); 55583030dd5SDavid du Colombier } 556906943f9SDavid du Colombier ud = d->usb; 557906943f9SDavid du Colombier d->aux = nil; 558906943f9SDavid du Colombier dprint(2, "kb: main: dev %s ref %ld\n", d->dir, d->ref); 559906943f9SDavid du Colombier for(i = 0; i < nelem(ud->ep); i++){ 560906943f9SDavid du Colombier if((ep = ud->ep[i]) == nil) 561906943f9SDavid du Colombier break; 562906943f9SDavid du Colombier if(kena && ep->type == Eintr && ep->dir == Ein) 563906943f9SDavid du Colombier if(ep->iface->csp == KbdCSP) 564906943f9SDavid du Colombier kbstart(d, ep, &kbdin, kbdwork, accel); 565906943f9SDavid du Colombier if(pena && ep->type == Eintr && ep->dir == Ein) 566906943f9SDavid du Colombier if(ep->iface->csp == PtrCSP) 567906943f9SDavid du Colombier kbstart(d, ep, &ptrin, ptrwork, accel); 568906943f9SDavid du Colombier } 569906943f9SDavid du Colombier closedev(d); 570906943f9SDavid du Colombier return 0; 57183030dd5SDavid du Colombier } 572