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 117d5789509SDavid du Colombier static int 118d5789509SDavid du Colombier setbootproto(KDev* f, int eid) 119d5789509SDavid du Colombier { 120d5789509SDavid du Colombier int r, id; 121d5789509SDavid du Colombier 122d5789509SDavid du Colombier r = Rh2d|Rclass|Riface; 123d5789509SDavid du Colombier id = f->dev->usb->ep[eid]->iface->id; 124d5789509SDavid du Colombier return usbcmd(f->dev, r, Setproto, Bootproto, id, nil, 0); 125d5789509SDavid du Colombier } 126d5789509SDavid du Colombier 127d5789509SDavid du Colombier /* 128d5789509SDavid du Colombier * Try to recover from a babble error. A port reset is the only way out. 129d5789509SDavid du Colombier * BUG: we should be careful not to reset a bundle with several devices. 130d5789509SDavid du Colombier */ 131d5789509SDavid du Colombier static void 132d5789509SDavid du Colombier recoverkb(KDev *f) 133d5789509SDavid du Colombier { 134d5789509SDavid du Colombier int i; 135d5789509SDavid du Colombier 136d5789509SDavid du Colombier close(f->dev->dfd); /* it's for usbd now */ 137d5789509SDavid du Colombier devctl(f->dev, "reset"); 138d5789509SDavid du Colombier for(i = 0; i < 10; i++){ 139d5789509SDavid du Colombier sleep(500); 140d5789509SDavid du Colombier if(opendevdata(f->dev, ORDWR) >= 0){ 141d5789509SDavid du Colombier setbootproto(f, f->ep->id); 142d5789509SDavid du Colombier break; 143d5789509SDavid du Colombier } 144d5789509SDavid du Colombier /* else usbd still working... */ 145d5789509SDavid du Colombier } 146d5789509SDavid du Colombier } 147d5789509SDavid du Colombier 148906943f9SDavid du Colombier static void 149906943f9SDavid du Colombier kbfatal(KDev *kd, char *sts) 15083030dd5SDavid du Colombier { 151906943f9SDavid du Colombier Dev *dev; 15283030dd5SDavid du Colombier 153906943f9SDavid du Colombier if(sts != nil) 15439dc1420SDavid du Colombier fprint(2, "kb: fatal: %s\n", sts); 15539dc1420SDavid du Colombier else 15639dc1420SDavid du Colombier fprint(2, "kb: exiting\n"); 157906943f9SDavid du Colombier if(kd->repeatc != nil) 15839dc1420SDavid du Colombier nbsendul(kd->repeatc, Diemsg); 15939dc1420SDavid du Colombier dev = kd->dev; 16039dc1420SDavid du Colombier kd->dev = nil; 16139dc1420SDavid du Colombier if(kd->ep != nil) 162906943f9SDavid du Colombier closedev(kd->ep); 163906943f9SDavid du Colombier kd->ep = nil; 16439dc1420SDavid du Colombier devctl(dev, "detach"); 165906943f9SDavid du Colombier closedev(dev); 166906943f9SDavid du Colombier /* 167906943f9SDavid du Colombier * free(kd); done by closedev. 168906943f9SDavid du Colombier */ 169906943f9SDavid du Colombier threadexits(sts); 17083030dd5SDavid du Colombier } 17183030dd5SDavid du Colombier 17283030dd5SDavid du Colombier static int 173906943f9SDavid du Colombier scale(KDev *f, int x) 17483030dd5SDavid du Colombier { 17583030dd5SDavid du Colombier int sign = 1; 17683030dd5SDavid du Colombier 17783030dd5SDavid du Colombier if(x < 0){ 17883030dd5SDavid du Colombier sign = -1; 17983030dd5SDavid du Colombier x = -x; 18083030dd5SDavid du Colombier } 18183030dd5SDavid du Colombier switch(x){ 18283030dd5SDavid du Colombier case 0: 18383030dd5SDavid du Colombier case 1: 18483030dd5SDavid du Colombier case 2: 18583030dd5SDavid du Colombier case 3: 18683030dd5SDavid du Colombier break; 18783030dd5SDavid du Colombier case 4: 188906943f9SDavid du Colombier x = 6 + (f->accel>>2); 18983030dd5SDavid du Colombier break; 19083030dd5SDavid du Colombier case 5: 191906943f9SDavid du Colombier x = 9 + (f->accel>>1); 19283030dd5SDavid du Colombier break; 19383030dd5SDavid du Colombier default: 19483030dd5SDavid du Colombier x *= MaxAcc; 19583030dd5SDavid du Colombier break; 19683030dd5SDavid du Colombier } 19783030dd5SDavid du Colombier return sign*x; 19883030dd5SDavid du Colombier } 19983030dd5SDavid du Colombier 200906943f9SDavid du Colombier /* 201906943f9SDavid du Colombier * ps2 mouse is processed mostly at interrupt time. 202906943f9SDavid du Colombier * for usb we do what we can. 203906943f9SDavid du Colombier */ 204906943f9SDavid du Colombier static void 205906943f9SDavid du Colombier sethipri(void) 206906943f9SDavid du Colombier { 207906943f9SDavid du Colombier char fn[30]; 208906943f9SDavid du Colombier int fd; 209906943f9SDavid du Colombier 210906943f9SDavid du Colombier snprint(fn, sizeof(fn), "/proc/%d/ctl", getpid()); 211906943f9SDavid du Colombier fd = open(fn, OWRITE); 212906943f9SDavid du Colombier if(fd < 0) 213906943f9SDavid du Colombier return; 214906943f9SDavid du Colombier fprint(fd, "pri 13"); 215906943f9SDavid du Colombier close(fd); 216906943f9SDavid du Colombier } 217906943f9SDavid du Colombier 218906943f9SDavid du Colombier static void 21983030dd5SDavid du Colombier ptrwork(void* a) 22083030dd5SDavid du Colombier { 22183030dd5SDavid du Colombier static char maptab[] = {0x0, 0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7}; 222906943f9SDavid du Colombier int x, y, b, c, ptrfd; 223d5789509SDavid du Colombier int mfd, nerrs; 224906943f9SDavid du Colombier char buf[32]; 225906943f9SDavid du Colombier char mbuf[80]; 226906943f9SDavid du Colombier KDev* f = a; 227906943f9SDavid du Colombier int hipri; 22883030dd5SDavid du Colombier 229d5789509SDavid du Colombier hipri = nerrs = 0; 230906943f9SDavid du Colombier ptrfd = f->ep->dfd; 231906943f9SDavid du Colombier mfd = f->in->fd; 232906943f9SDavid du Colombier 233906943f9SDavid du Colombier if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) 23439dc1420SDavid du Colombier kbfatal(f, "weird mouse maxpkt"); 23583030dd5SDavid du Colombier for(;;){ 23683030dd5SDavid du Colombier memset(buf, 0, sizeof buf); 23739dc1420SDavid du Colombier if(f->ep == nil) 23839dc1420SDavid du Colombier kbfatal(f, nil); 239906943f9SDavid du Colombier c = read(ptrfd, buf, f->ep->maxpkt); 24039dc1420SDavid du Colombier assert(f->dev != nil); 24139dc1420SDavid du Colombier assert(f->ep != nil); 242d5789509SDavid du Colombier if(c < 0){ 24339dc1420SDavid du Colombier dprint(2, "kb: mouse: %s: read: %r\n", f->ep->dir); 244d5789509SDavid du Colombier if(++nerrs < 3){ 245d5789509SDavid du Colombier recoverkb(f); 246d5789509SDavid du Colombier continue; 247d5789509SDavid du Colombier } 248d5789509SDavid du Colombier } 249906943f9SDavid du Colombier if(c <= 0) 250906943f9SDavid du Colombier kbfatal(f, nil); 25183030dd5SDavid du Colombier if(c < 3) 25283030dd5SDavid du Colombier continue; 253906943f9SDavid du Colombier if(f->accel){ 254906943f9SDavid du Colombier x = scale(f, buf[1]); 255906943f9SDavid du Colombier y = scale(f, buf[2]); 25683030dd5SDavid du Colombier }else{ 25783030dd5SDavid du Colombier x = buf[1]; 25883030dd5SDavid du Colombier y = buf[2]; 25983030dd5SDavid du Colombier } 26083030dd5SDavid du Colombier b = maptab[buf[0] & 0x7]; 26183030dd5SDavid du Colombier if(c > 3 && buf[3] == 1) /* up */ 26283030dd5SDavid du Colombier b |= 0x08; 26383030dd5SDavid du Colombier if(c > 3 && buf[3] == -1) /* down */ 26483030dd5SDavid du Colombier b |= 0x10; 265d5789509SDavid du Colombier if(kbdebug > 1) 26639dc1420SDavid du Colombier fprint(2, "kb: m%11d %11d %11d\n", x, y, b); 267906943f9SDavid du Colombier seprint(mbuf, mbuf+sizeof(mbuf), "m%11d %11d %11d", x, y,b); 26839dc1420SDavid du Colombier if(write(mfd, mbuf, strlen(mbuf)) < 0) 26939dc1420SDavid du Colombier kbfatal(f, "mousein i/o"); 270906943f9SDavid du Colombier if(hipri == 0){ 271906943f9SDavid du Colombier sethipri(); 272906943f9SDavid du Colombier hipri = 1; 27383030dd5SDavid du Colombier } 27483030dd5SDavid du Colombier } 27583030dd5SDavid du Colombier } 27683030dd5SDavid du Colombier 27783030dd5SDavid du Colombier static void 278906943f9SDavid du Colombier stoprepeat(KDev *f) 27983030dd5SDavid du Colombier { 280906943f9SDavid du Colombier sendul(f->repeatc, Awakemsg); 28183030dd5SDavid du Colombier } 28283030dd5SDavid du Colombier 28383030dd5SDavid du Colombier static void 284906943f9SDavid du Colombier startrepeat(KDev *f, uchar esc1, uchar sc) 28583030dd5SDavid du Colombier { 28683030dd5SDavid du Colombier ulong c; 28783030dd5SDavid du Colombier 28883030dd5SDavid du Colombier if(esc1) 28983030dd5SDavid du Colombier c = SCesc1 << 8 | (sc & 0xff); 29083030dd5SDavid du Colombier else 29183030dd5SDavid du Colombier c = sc; 292906943f9SDavid du Colombier sendul(f->repeatc, c); 29383030dd5SDavid du Colombier } 29483030dd5SDavid du Colombier 29583030dd5SDavid du Colombier static void 296906943f9SDavid du Colombier putscan(int kbinfd, uchar esc, uchar sc) 29783030dd5SDavid du Colombier { 298906943f9SDavid du Colombier uchar s[2] = {SCesc1, 0}; 29983030dd5SDavid du Colombier 30083030dd5SDavid du Colombier if(sc == 0x41){ 301d5789509SDavid du Colombier kbdebug += 2; 30283030dd5SDavid du Colombier return; 30383030dd5SDavid du Colombier } 30483030dd5SDavid du Colombier if(sc == 0x42){ 305906943f9SDavid du Colombier kbdebug = 0; 30683030dd5SDavid du Colombier return; 30783030dd5SDavid du Colombier } 308906943f9SDavid du Colombier if(kbdebug) 30983030dd5SDavid du Colombier fprint(2, "sc: %x %x\n", (esc? SCesc1: 0), sc); 31083030dd5SDavid du Colombier s[1] = sc; 31183030dd5SDavid du Colombier if(esc && sc != 0) 31283030dd5SDavid du Colombier write(kbinfd, s, 2); 31383030dd5SDavid du Colombier else if(sc != 0) 31483030dd5SDavid du Colombier write(kbinfd, s+1, 1); 31583030dd5SDavid du Colombier } 31683030dd5SDavid du Colombier 31783030dd5SDavid du Colombier static void 318906943f9SDavid du Colombier repeatproc(void* a) 31983030dd5SDavid du Colombier { 320906943f9SDavid du Colombier KDev *f; 321906943f9SDavid du Colombier Channel *repeatc; 322906943f9SDavid du Colombier int kbdinfd; 323906943f9SDavid du Colombier ulong l, t, i; 32483030dd5SDavid du Colombier uchar esc1, sc; 32583030dd5SDavid du Colombier 326906943f9SDavid du Colombier /* 327906943f9SDavid du Colombier * too many jumps here. 328906943f9SDavid du Colombier * Rewrite instead of debug, if needed. 329906943f9SDavid du Colombier */ 330906943f9SDavid du Colombier f = a; 331906943f9SDavid du Colombier repeatc = f->repeatc; 332906943f9SDavid du Colombier kbdinfd = f->in->fd; 333906943f9SDavid du Colombier l = Awakemsg; 334906943f9SDavid du Colombier Repeat: 335906943f9SDavid du Colombier if(l == Diemsg) 336906943f9SDavid du Colombier goto Abort; 337906943f9SDavid du Colombier while(l == Awakemsg) 338906943f9SDavid du Colombier l = recvul(repeatc); 339906943f9SDavid du Colombier if(l == Diemsg) 340906943f9SDavid du Colombier goto Abort; 34183030dd5SDavid du Colombier esc1 = l >> 8; 34283030dd5SDavid du Colombier sc = l; 343906943f9SDavid du Colombier t = 160; 34483030dd5SDavid du Colombier for(;;){ 345906943f9SDavid du Colombier for(i = 0; i < t; i += 5){ 346906943f9SDavid du Colombier if(l = nbrecvul(repeatc)) 347906943f9SDavid du Colombier goto Repeat; 348906943f9SDavid du Colombier sleep(5); 34983030dd5SDavid du Colombier } 350906943f9SDavid du Colombier putscan(kbdinfd, esc1, sc); 351906943f9SDavid du Colombier t = 30; 35283030dd5SDavid du Colombier } 353906943f9SDavid du Colombier Abort: 354906943f9SDavid du Colombier chanfree(repeatc); 355906943f9SDavid du Colombier threadexits("aborted"); 356906943f9SDavid du Colombier 35783030dd5SDavid du Colombier } 35883030dd5SDavid du Colombier 35983030dd5SDavid du Colombier 36083030dd5SDavid du Colombier #define hasesc1(sc) (((sc) > 0x47) || ((sc) == 0x38)) 36183030dd5SDavid du Colombier 36283030dd5SDavid du Colombier static void 363906943f9SDavid du Colombier putmod(int fd, uchar mods, uchar omods, uchar mask, uchar esc, uchar sc) 36483030dd5SDavid du Colombier { 365906943f9SDavid du Colombier /* BUG: Should be a single write */ 36683030dd5SDavid du Colombier if((mods&mask) && !(omods&mask)) 367906943f9SDavid du Colombier putscan(fd, esc, sc); 36883030dd5SDavid du Colombier if(!(mods&mask) && (omods&mask)) 369906943f9SDavid du Colombier putscan(fd, esc, Keyup|sc); 37083030dd5SDavid du Colombier } 37183030dd5SDavid du Colombier 37283030dd5SDavid du Colombier /* 37383030dd5SDavid du Colombier * This routine diffs the state with the last known state 37483030dd5SDavid du Colombier * and invents the scan codes that would have been sent 37583030dd5SDavid du Colombier * by a non-usb keyboard in that case. This also requires supplying 37683030dd5SDavid du Colombier * the extra esc1 byte as well as keyup flags. 37783030dd5SDavid du Colombier * The aim is to allow future addition of other keycode pages 37883030dd5SDavid du Colombier * for other keyboards. 37983030dd5SDavid du Colombier */ 380906943f9SDavid du Colombier static uchar 381906943f9SDavid du Colombier putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk) 38283030dd5SDavid du Colombier { 38383030dd5SDavid du Colombier int i, j; 384906943f9SDavid du Colombier uchar uk; 385906943f9SDavid du Colombier int fd; 38683030dd5SDavid du Colombier 387906943f9SDavid du Colombier fd = f->in->fd; 388906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Mctrl, 0, SCctrl); 389906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], (1<<Mlshift), 0, SClshift); 390906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], (1<<Mrshift), 0, SCrshift); 391906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Mcompose, 0, SCcompose); 392906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Maltgr, 1, SCcompose); 39383030dd5SDavid du Colombier 39483030dd5SDavid du Colombier /* Report key downs */ 39583030dd5SDavid du Colombier for(i = 2; i < n; i++){ 39683030dd5SDavid du Colombier for(j = 2; j < n; j++) 39783030dd5SDavid du Colombier if(buf[i] == obuf[j]) 39883030dd5SDavid du Colombier break; 39983030dd5SDavid du Colombier if(j == n && buf[i] != 0){ 400906943f9SDavid du Colombier dk = sctab[buf[i]]; 401906943f9SDavid du Colombier putscan(fd, hasesc1(dk), dk); 402906943f9SDavid du Colombier startrepeat(f, hasesc1(dk), dk); 40383030dd5SDavid du Colombier } 40483030dd5SDavid du Colombier } 40583030dd5SDavid du Colombier 40683030dd5SDavid du Colombier /* Report key ups */ 407906943f9SDavid du Colombier uk = 0; 40883030dd5SDavid du Colombier for(i = 2; i < n; i++){ 40983030dd5SDavid du Colombier for(j = 2; j < n; j++) 41083030dd5SDavid du Colombier if(obuf[i] == buf[j]) 41183030dd5SDavid du Colombier break; 41283030dd5SDavid du Colombier if(j == n && obuf[i] != 0){ 413906943f9SDavid du Colombier uk = sctab[obuf[i]]; 414906943f9SDavid du Colombier putscan(fd, hasesc1(uk), uk|Keyup); 41583030dd5SDavid du Colombier } 41683030dd5SDavid du Colombier } 417906943f9SDavid du Colombier if(uk && (dk == 0 || dk == uk)){ 418906943f9SDavid du Colombier stoprepeat(f); 419906943f9SDavid du Colombier dk = 0; 420906943f9SDavid du Colombier } 421906943f9SDavid du Colombier return dk; 42283030dd5SDavid du Colombier } 42383030dd5SDavid du Colombier 42483030dd5SDavid du Colombier static int 42583030dd5SDavid du Colombier kbdbusy(uchar* buf, int n) 42683030dd5SDavid du Colombier { 42783030dd5SDavid du Colombier int i; 42883030dd5SDavid du Colombier 42983030dd5SDavid du Colombier for(i = 1; i < n; i++) 43083030dd5SDavid du Colombier if(buf[i] == 0 || buf[i] != buf[0]) 43183030dd5SDavid du Colombier return 0; 43283030dd5SDavid du Colombier return 1; 43383030dd5SDavid du Colombier } 43483030dd5SDavid du Colombier 435906943f9SDavid du Colombier static void 43683030dd5SDavid du Colombier kbdwork(void *a) 43783030dd5SDavid du Colombier { 438a23bc242SDavid du Colombier int c, i, kbdfd, nerrs; 439a23bc242SDavid du Colombier uchar dk, buf[64], lbuf[64]; 440a23bc242SDavid du Colombier char err[128]; 441906943f9SDavid du Colombier KDev *f = a; 44283030dd5SDavid du Colombier 443906943f9SDavid du Colombier kbdfd = f->ep->dfd; 444906943f9SDavid du Colombier 445906943f9SDavid du Colombier if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) 446906943f9SDavid du Colombier kbfatal(f, "weird maxpkt"); 447906943f9SDavid du Colombier 448906943f9SDavid du Colombier f->repeatc = chancreate(sizeof(ulong), 0); 449906943f9SDavid du Colombier if(f->repeatc == nil) 450906943f9SDavid du Colombier kbfatal(f, "chancreate failed"); 451906943f9SDavid du Colombier 452906943f9SDavid du Colombier proccreate(repeatproc, f, Stack); 45383030dd5SDavid du Colombier memset(lbuf, 0, sizeof lbuf); 454a23bc242SDavid du Colombier dk = nerrs = 0; 45583030dd5SDavid du Colombier for(;;){ 45683030dd5SDavid du Colombier memset(buf, 0, sizeof buf); 457906943f9SDavid du Colombier c = read(kbdfd, buf, f->ep->maxpkt); 45839dc1420SDavid du Colombier assert(f->dev != nil); 45939dc1420SDavid du Colombier assert(f->ep != nil); 460a23bc242SDavid du Colombier if(c < 0){ 461a23bc242SDavid du Colombier rerrstr(err, sizeof(err)); 462d5789509SDavid du Colombier fprint(2, "kb: %s: read: %s\n", f->ep->dir, err); 463a23bc242SDavid du Colombier if(strstr(err, "babble") != 0 && ++nerrs < 3){ 464a23bc242SDavid du Colombier recoverkb(f); 465a23bc242SDavid du Colombier continue; 466a23bc242SDavid du Colombier } 467a23bc242SDavid du Colombier } 468906943f9SDavid du Colombier if(c <= 0) 46939dc1420SDavid du Colombier kbfatal(f, nil); 47083030dd5SDavid du Colombier if(c < 3) 47183030dd5SDavid du Colombier continue; 47283030dd5SDavid du Colombier if(kbdbusy(buf + 2, c - 2)) 47383030dd5SDavid du Colombier continue; 474d5789509SDavid du Colombier if(usbdebug > 2 || kbdebug > 1){ 47583030dd5SDavid du Colombier fprint(2, "kbd mod %x: ", buf[0]); 47683030dd5SDavid du Colombier for(i = 2; i < c; i++) 47783030dd5SDavid du Colombier fprint(2, "kc %x ", buf[i]); 47883030dd5SDavid du Colombier fprint(2, "\n"); 47983030dd5SDavid du Colombier } 480906943f9SDavid du Colombier dk = putkeys(f, buf, lbuf, f->ep->maxpkt, dk); 48183030dd5SDavid du Colombier memmove(lbuf, buf, c); 482a23bc242SDavid du Colombier nerrs = 0; 48383030dd5SDavid du Colombier } 48483030dd5SDavid du Colombier } 48583030dd5SDavid du Colombier 48683030dd5SDavid du Colombier static void 487906943f9SDavid du Colombier freekdev(void *a) 48883030dd5SDavid du Colombier { 489906943f9SDavid du Colombier KDev *kd; 49083030dd5SDavid du Colombier 491906943f9SDavid du Colombier kd = a; 492906943f9SDavid du Colombier if(kd->in != nil){ 493906943f9SDavid du Colombier qlock(&inlck); 494906943f9SDavid du Colombier if(--kd->in->ref == 0){ 495906943f9SDavid du Colombier close(kd->in->fd); 496906943f9SDavid du Colombier kd->in->fd = -1; 49783030dd5SDavid du Colombier } 498906943f9SDavid du Colombier qunlock(&inlck); 49983030dd5SDavid du Colombier } 50039dc1420SDavid du Colombier dprint(2, "freekdev\n"); 501906943f9SDavid du Colombier free(kd); 50283030dd5SDavid du Colombier } 50383030dd5SDavid du Colombier 50483030dd5SDavid du Colombier static void 505906943f9SDavid du Colombier kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), int accel) 506906943f9SDavid du Colombier { 507906943f9SDavid du Colombier KDev *kd; 508906943f9SDavid du Colombier 509906943f9SDavid du Colombier qlock(&inlck); 510906943f9SDavid du Colombier if(in->fd < 0){ 511906943f9SDavid du Colombier in->fd = open(in->name, OWRITE); 512906943f9SDavid du Colombier if(in->fd < 0){ 513906943f9SDavid du Colombier fprint(2, "kb: %s: %r\n", in->name); 514906943f9SDavid du Colombier qunlock(&inlck); 515906943f9SDavid du Colombier return; 516906943f9SDavid du Colombier } 517906943f9SDavid du Colombier } 51839dc1420SDavid du Colombier in->ref++; /* for kd->in = in */ 519906943f9SDavid du Colombier qunlock(&inlck); 520906943f9SDavid du Colombier kd = d->aux = emallocz(sizeof(KDev), 1); 521906943f9SDavid du Colombier d->free = freekdev; 522906943f9SDavid du Colombier kd->in = in; 523906943f9SDavid du Colombier kd->dev = d; 524906943f9SDavid du Colombier if(setbootproto(kd, ep->id) < 0){ 525906943f9SDavid du Colombier fprint(2, "kb: %s: bootproto: %r\n", d->dir); 526906943f9SDavid du Colombier return; 527906943f9SDavid du Colombier } 528906943f9SDavid du Colombier kd->accel = accel; 529906943f9SDavid du Colombier kd->ep = openep(d, ep->id); 530906943f9SDavid du Colombier if(kd->ep == nil){ 531906943f9SDavid du Colombier fprint(2, "kb: %s: openep %d: %r\n", d->dir, ep->id); 532906943f9SDavid du Colombier return; 533906943f9SDavid du Colombier } 534906943f9SDavid du Colombier if(opendevdata(kd->ep, OREAD) < 0){ 535906943f9SDavid du Colombier fprint(2, "kb: %s: opendevdata: %r\n", kd->ep->dir); 536906943f9SDavid du Colombier closedev(kd->ep); 537906943f9SDavid du Colombier kd->ep = nil; 538906943f9SDavid du Colombier return; 539906943f9SDavid du Colombier } 540906943f9SDavid du Colombier 541906943f9SDavid du Colombier incref(d); 542906943f9SDavid du Colombier proccreate(f, kd, Stack); 543906943f9SDavid du Colombier } 544906943f9SDavid du Colombier 545906943f9SDavid du Colombier static int 54683030dd5SDavid du Colombier usage(void) 54783030dd5SDavid du Colombier { 548*ed868a7cSDavid du Colombier werrstr("usage: usb/kb [-dkm] [-a n] [-N nb]"); 549906943f9SDavid du Colombier return -1; 55083030dd5SDavid du Colombier } 55183030dd5SDavid du Colombier 552906943f9SDavid du Colombier int 553906943f9SDavid du Colombier kbmain(Dev *d, int argc, char* argv[]) 55483030dd5SDavid du Colombier { 555*ed868a7cSDavid du Colombier int i, kena, pena, accel, devid; 556906943f9SDavid du Colombier Usbdev *ud; 557906943f9SDavid du Colombier Ep *ep; 55883030dd5SDavid du Colombier 559906943f9SDavid du Colombier kena = pena = 1; 560906943f9SDavid du Colombier accel = 0; 561*ed868a7cSDavid du Colombier devid = d->id; 56283030dd5SDavid du Colombier ARGBEGIN{ 56383030dd5SDavid du Colombier case 'a': 564*ed868a7cSDavid du Colombier accel = strtol(EARGF(usage()), nil, 0); 56583030dd5SDavid du Colombier break; 56683030dd5SDavid du Colombier case 'd': 567906943f9SDavid du Colombier kbdebug++; 56883030dd5SDavid du Colombier break; 56983030dd5SDavid du Colombier case 'k': 570906943f9SDavid du Colombier kena = 1; 571906943f9SDavid du Colombier pena = 0; 57283030dd5SDavid du Colombier break; 57383030dd5SDavid du Colombier case 'm': 574906943f9SDavid du Colombier kena = 0; 575906943f9SDavid du Colombier pena = 1; 57683030dd5SDavid du Colombier break; 577*ed868a7cSDavid du Colombier case 'N': 578*ed868a7cSDavid du Colombier devid = atoi(EARGF(usage())); /* ignore dev number */ 579*ed868a7cSDavid du Colombier break; 58083030dd5SDavid du Colombier default: 581906943f9SDavid du Colombier return usage(); 58283030dd5SDavid du Colombier }ARGEND; 583906943f9SDavid du Colombier if(argc != 0){ 584906943f9SDavid du Colombier return usage(); 58583030dd5SDavid du Colombier } 586*ed868a7cSDavid du Colombier USED(devid); 587906943f9SDavid du Colombier ud = d->usb; 588906943f9SDavid du Colombier d->aux = nil; 589906943f9SDavid du Colombier dprint(2, "kb: main: dev %s ref %ld\n", d->dir, d->ref); 590906943f9SDavid du Colombier for(i = 0; i < nelem(ud->ep); i++){ 591906943f9SDavid du Colombier if((ep = ud->ep[i]) == nil) 592906943f9SDavid du Colombier break; 593906943f9SDavid du Colombier if(kena && ep->type == Eintr && ep->dir == Ein) 594906943f9SDavid du Colombier if(ep->iface->csp == KbdCSP) 595906943f9SDavid du Colombier kbstart(d, ep, &kbdin, kbdwork, accel); 596906943f9SDavid du Colombier if(pena && ep->type == Eintr && ep->dir == Ein) 597906943f9SDavid du Colombier if(ep->iface->csp == PtrCSP) 598906943f9SDavid du Colombier kbstart(d, ep, &ptrin, ptrwork, accel); 599906943f9SDavid du Colombier } 600906943f9SDavid du Colombier return 0; 60183030dd5SDavid du Colombier } 602