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 * 7d40255d8SDavid du Colombier * Mouse events are converted to the format of mouse(3)'s mousein file. 883030dd5SDavid du Colombier * Keyboard keycodes are translated to scan codes and sent to kbin(3). 983030dd5SDavid du Colombier * 10d40255d8SDavid du Colombier * If there is no keyboard, it tries to setup the mouse properly, else it falls 11d40255d8SDavid du Colombier * back to boot protocol. 1283030dd5SDavid du Colombier */ 1383030dd5SDavid du Colombier 1483030dd5SDavid du Colombier #include <u.h> 1583030dd5SDavid du Colombier #include <libc.h> 1683030dd5SDavid du Colombier #include <thread.h> 1783030dd5SDavid du Colombier #include "usb.h" 1883030dd5SDavid du Colombier #include "hid.h" 1983030dd5SDavid du Colombier 20906943f9SDavid du Colombier enum 21906943f9SDavid du Colombier { 22906943f9SDavid du Colombier Awakemsg= 0xdeaddead, 23906943f9SDavid du Colombier Diemsg = 0xbeefbeef, 24906943f9SDavid du Colombier }; 25906943f9SDavid du Colombier 26906943f9SDavid du Colombier typedef struct KDev KDev; 27906943f9SDavid du Colombier typedef struct Kin Kin; 28906943f9SDavid du Colombier 29906943f9SDavid du Colombier struct KDev 30906943f9SDavid du Colombier { 31906943f9SDavid du Colombier Dev* dev; /* usb device*/ 32906943f9SDavid du Colombier Dev* ep; /* endpoint to get events */ 33906943f9SDavid du Colombier Kin* in; /* used to send events to kernel */ 34906943f9SDavid du Colombier Channel*repeatc; /* only for keyboard */ 35906943f9SDavid du Colombier int accel; /* only for mouse */ 36d40255d8SDavid du Colombier int bootp; /* has associated keyboard */ 37d40255d8SDavid du Colombier HidRepTempl templ; 38d40255d8SDavid du Colombier int (*ptrvals)(KDev *kd, Chain *ch, int *px, int *py, int *pb); 39906943f9SDavid du Colombier }; 40906943f9SDavid du Colombier 41906943f9SDavid du Colombier /* 42906943f9SDavid du Colombier * Kbdin and mousein files must be shared among all instances. 43906943f9SDavid du Colombier */ 44906943f9SDavid du Colombier struct Kin 45906943f9SDavid du Colombier { 46906943f9SDavid du Colombier int ref; 47906943f9SDavid du Colombier int fd; 48906943f9SDavid du Colombier char* name; 49906943f9SDavid du Colombier }; 50906943f9SDavid du Colombier 5183030dd5SDavid du Colombier /* 5283030dd5SDavid du Colombier * Map for the logitech bluetooth mouse with 8 buttons and wheels. 5383030dd5SDavid du Colombier * { ptr ->mouse} 5483030dd5SDavid du Colombier * { 0x01, 0x01 }, // left 5583030dd5SDavid du Colombier * { 0x04, 0x02 }, // middle 5683030dd5SDavid du Colombier * { 0x02, 0x04 }, // right 5783030dd5SDavid du Colombier * { 0x40, 0x08 }, // up 5883030dd5SDavid du Colombier * { 0x80, 0x10 }, // down 5983030dd5SDavid du Colombier * { 0x10, 0x08 }, // side up 6083030dd5SDavid du Colombier * { 0x08, 0x10 }, // side down 6183030dd5SDavid du Colombier * { 0x20, 0x02 }, // page 6283030dd5SDavid du Colombier * besides wheel and regular up/down report the 4th byte as 1/-1 6383030dd5SDavid du Colombier */ 6483030dd5SDavid du Colombier 6583030dd5SDavid du Colombier /* 6683030dd5SDavid du Colombier * key code to scan code; for the page table used by 6783030dd5SDavid du Colombier * the logitech bluetooth keyboard. 6883030dd5SDavid du Colombier */ 69906943f9SDavid du Colombier static char sctab[256] = 7083030dd5SDavid du Colombier { 7183030dd5SDavid du Colombier [0x00] 0x0, 0x0, 0x0, 0x0, 0x1e, 0x30, 0x2e, 0x20, 7283030dd5SDavid du Colombier [0x08] 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 7383030dd5SDavid du Colombier [0x10] 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 7483030dd5SDavid du Colombier [0x18] 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x2, 0x3, 7583030dd5SDavid du Colombier [0x20] 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 7683030dd5SDavid du Colombier [0x28] 0x1c, 0x1, 0xe, 0xf, 0x39, 0xc, 0xd, 0x1a, 7783030dd5SDavid du Colombier [0x30] 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, 7883030dd5SDavid du Colombier [0x38] 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 7983030dd5SDavid du Colombier [0x40] 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0x63, 0x46, 8083030dd5SDavid du Colombier [0x48] 0x77, 0x52, 0x47, 0x49, 0x53, 0x4f, 0x51, 0x4d, 8183030dd5SDavid du Colombier [0x50] 0x4b, 0x50, 0x48, 0x45, 0x35, 0x37, 0x4a, 0x4e, 8283030dd5SDavid du Colombier [0x58] 0x1c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, 8383030dd5SDavid du Colombier [0x60] 0x48, 0x49, 0x52, 0x53, 0x56, 0x7f, 0x74, 0x75, 8483030dd5SDavid du Colombier [0x68] 0x55, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 8583030dd5SDavid du Colombier [0x70] 0x78, 0x79, 0x7a, 0x7b, 0x0, 0x0, 0x0, 0x0, 8683030dd5SDavid du Colombier [0x78] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 8783030dd5SDavid du Colombier [0x80] 0x73, 0x72, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 8883030dd5SDavid du Colombier [0x88] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 8983030dd5SDavid du Colombier [0x90] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9083030dd5SDavid du Colombier [0x98] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9183030dd5SDavid du Colombier [0xa0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9283030dd5SDavid du Colombier [0xa8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9383030dd5SDavid du Colombier [0xb0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9483030dd5SDavid du Colombier [0xb8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9583030dd5SDavid du Colombier [0xc0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9683030dd5SDavid du Colombier [0xc8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9783030dd5SDavid du Colombier [0xd0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9883030dd5SDavid du Colombier [0xd8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 9983030dd5SDavid du Colombier [0xe0] 0x1d, 0x2a, 0x38, 0x7d, 0x61, 0x36, 0x64, 0x7e, 10083030dd5SDavid du Colombier [0xe8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x73, 0x72, 0x71, 10183030dd5SDavid du Colombier [0xf0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 10283030dd5SDavid du Colombier [0xf8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 10383030dd5SDavid du Colombier }; 10483030dd5SDavid du Colombier 105906943f9SDavid du Colombier static QLock inlck; 106906943f9SDavid du Colombier static Kin kbdin = 107906943f9SDavid du Colombier { 108906943f9SDavid du Colombier .ref = 0, 109906943f9SDavid du Colombier .name = "#Ι/kbin", 110906943f9SDavid du Colombier .fd = -1, 111906943f9SDavid du Colombier }; 112906943f9SDavid du Colombier static Kin ptrin = 113906943f9SDavid du Colombier { 114906943f9SDavid du Colombier .ref = 0, 115906943f9SDavid du Colombier .name = "#m/mousein", 116906943f9SDavid du Colombier .fd = -1, 11783030dd5SDavid du Colombier }; 11883030dd5SDavid du Colombier 119906943f9SDavid du Colombier static int kbdebug; 12083030dd5SDavid du Colombier 121d40255d8SDavid du Colombier static int ptrbootpvals(KDev *kd, Chain *ch, int *px, int *py, int *pb); 122d40255d8SDavid du Colombier static int ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb); 123d40255d8SDavid du Colombier 124d5789509SDavid du Colombier static int 125d40255d8SDavid du Colombier setbootproto(KDev* f, int eid, uchar *, int) 126d5789509SDavid du Colombier { 127d5789509SDavid du Colombier int r, id; 128d5789509SDavid du Colombier 129d40255d8SDavid du Colombier f->ptrvals = ptrbootpvals; 130d5789509SDavid du Colombier r = Rh2d|Rclass|Riface; 131d40255d8SDavid du Colombier dprint(2, "setting boot protocol\n"); 132d5789509SDavid du Colombier id = f->dev->usb->ep[eid]->iface->id; 133d5789509SDavid du Colombier return usbcmd(f->dev, r, Setproto, Bootproto, id, nil, 0); 134d5789509SDavid du Colombier } 135d5789509SDavid du Colombier 136d40255d8SDavid du Colombier static uchar ignoredesc[128]; 137d40255d8SDavid du Colombier 138d40255d8SDavid du Colombier static int 139d40255d8SDavid du Colombier setfirstconfig(KDev* f, int eid, uchar *desc, int descsz) 140d40255d8SDavid du Colombier { 141d40255d8SDavid du Colombier int nr, r, id, i; 142d40255d8SDavid du Colombier 143d40255d8SDavid du Colombier dprint(2, "setting first config\n"); 144d40255d8SDavid du Colombier if(desc == nil){ 145d40255d8SDavid du Colombier descsz = sizeof ignoredesc; 146d40255d8SDavid du Colombier desc = ignoredesc; 147d40255d8SDavid du Colombier } 148d40255d8SDavid du Colombier id = f->dev->usb->ep[eid]->iface->id; 149d40255d8SDavid du Colombier r = Rh2d | Rstd | Rdev; 150d40255d8SDavid du Colombier nr =usbcmd(f->dev, r, Rsetconf, 1, id, nil, 0); 151d40255d8SDavid du Colombier if(nr < 0) 152d40255d8SDavid du Colombier return -1; 153d40255d8SDavid du Colombier r = Rh2d | Rclass | Riface; 154d40255d8SDavid du Colombier nr=usbcmd(f->dev, r, Setidle, 0, id, nil, 0); 155d40255d8SDavid du Colombier if(nr < 0) 156d40255d8SDavid du Colombier return -1; 157d40255d8SDavid du Colombier r = Rd2h | Rstd | Riface; 158d40255d8SDavid du Colombier nr=usbcmd(f->dev, r, Rgetdesc, Dreport<<8, id, desc, descsz); 159d40255d8SDavid du Colombier if(nr < 0) 160d40255d8SDavid du Colombier return -1; 161d40255d8SDavid du Colombier if(kbdebug && nr > 0){ 162d40255d8SDavid du Colombier fprint(2, "report descriptor:"); 163d40255d8SDavid du Colombier for(i = 0; i < nr; i++){ 164eb2d6162SDavid du Colombier if(i%8 == 0) 165eb2d6162SDavid du Colombier fprint(2, "\n\t"); 166d40255d8SDavid du Colombier fprint(2, "%#2.2ux ", desc[i]); 167d40255d8SDavid du Colombier } 168d40255d8SDavid du Colombier fprint(2, "\n"); 169d40255d8SDavid du Colombier } 170d40255d8SDavid du Colombier f->ptrvals = ptrrepvals; 171d40255d8SDavid du Colombier return nr; 172d40255d8SDavid du Colombier } 173d40255d8SDavid du Colombier 174d5789509SDavid du Colombier /* 175d5789509SDavid du Colombier * Try to recover from a babble error. A port reset is the only way out. 176d5789509SDavid du Colombier * BUG: we should be careful not to reset a bundle with several devices. 177d5789509SDavid du Colombier */ 178d5789509SDavid du Colombier static void 179d5789509SDavid du Colombier recoverkb(KDev *f) 180d5789509SDavid du Colombier { 181d5789509SDavid du Colombier int i; 182d5789509SDavid du Colombier 183d5789509SDavid du Colombier close(f->dev->dfd); /* it's for usbd now */ 184d5789509SDavid du Colombier devctl(f->dev, "reset"); 185d5789509SDavid du Colombier for(i = 0; i < 10; i++){ 186d40255d8SDavid du Colombier if(i == 5) 187d40255d8SDavid du Colombier f->bootp++; 188d5789509SDavid du Colombier sleep(500); 189d5789509SDavid du Colombier if(opendevdata(f->dev, ORDWR) >= 0){ 190d40255d8SDavid du Colombier if(f->bootp) 191d40255d8SDavid du Colombier /* TODO func pointer */ 192d40255d8SDavid du Colombier setbootproto(f, f->ep->id, nil, 0); 193d40255d8SDavid du Colombier else 194d40255d8SDavid du Colombier setfirstconfig(f, f->ep->id, nil, 0); 195d5789509SDavid du Colombier break; 196d5789509SDavid du Colombier } 197d5789509SDavid du Colombier /* else usbd still working... */ 198d5789509SDavid du Colombier } 199d5789509SDavid du Colombier } 200d5789509SDavid du Colombier 201906943f9SDavid du Colombier static void 202906943f9SDavid du Colombier kbfatal(KDev *kd, char *sts) 20383030dd5SDavid du Colombier { 204906943f9SDavid du Colombier Dev *dev; 20583030dd5SDavid du Colombier 206906943f9SDavid du Colombier if(sts != nil) 20739dc1420SDavid du Colombier fprint(2, "kb: fatal: %s\n", sts); 20839dc1420SDavid du Colombier else 20939dc1420SDavid du Colombier fprint(2, "kb: exiting\n"); 210906943f9SDavid du Colombier if(kd->repeatc != nil) 21139dc1420SDavid du Colombier nbsendul(kd->repeatc, Diemsg); 21239dc1420SDavid du Colombier dev = kd->dev; 21339dc1420SDavid du Colombier kd->dev = nil; 21439dc1420SDavid du Colombier if(kd->ep != nil) 215906943f9SDavid du Colombier closedev(kd->ep); 216906943f9SDavid du Colombier kd->ep = nil; 21739dc1420SDavid du Colombier devctl(dev, "detach"); 218906943f9SDavid du Colombier closedev(dev); 219906943f9SDavid du Colombier /* 220906943f9SDavid du Colombier * free(kd); done by closedev. 221906943f9SDavid du Colombier */ 222906943f9SDavid du Colombier threadexits(sts); 22383030dd5SDavid du Colombier } 22483030dd5SDavid du Colombier 22583030dd5SDavid du Colombier static int 226906943f9SDavid du Colombier scale(KDev *f, int x) 22783030dd5SDavid du Colombier { 22883030dd5SDavid du Colombier int sign = 1; 22983030dd5SDavid du Colombier 23083030dd5SDavid du Colombier if(x < 0){ 23183030dd5SDavid du Colombier sign = -1; 23283030dd5SDavid du Colombier x = -x; 23383030dd5SDavid du Colombier } 23483030dd5SDavid du Colombier switch(x){ 23583030dd5SDavid du Colombier case 0: 23683030dd5SDavid du Colombier case 1: 23783030dd5SDavid du Colombier case 2: 23883030dd5SDavid du Colombier case 3: 23983030dd5SDavid du Colombier break; 24083030dd5SDavid du Colombier case 4: 241906943f9SDavid du Colombier x = 6 + (f->accel>>2); 24283030dd5SDavid du Colombier break; 24383030dd5SDavid du Colombier case 5: 244906943f9SDavid du Colombier x = 9 + (f->accel>>1); 24583030dd5SDavid du Colombier break; 24683030dd5SDavid du Colombier default: 24783030dd5SDavid du Colombier x *= MaxAcc; 24883030dd5SDavid du Colombier break; 24983030dd5SDavid du Colombier } 25083030dd5SDavid du Colombier return sign*x; 25183030dd5SDavid du Colombier } 25283030dd5SDavid du Colombier 253906943f9SDavid du Colombier /* 254906943f9SDavid du Colombier * ps2 mouse is processed mostly at interrupt time. 255906943f9SDavid du Colombier * for usb we do what we can. 256906943f9SDavid du Colombier */ 257906943f9SDavid du Colombier static void 258906943f9SDavid du Colombier sethipri(void) 259906943f9SDavid du Colombier { 260906943f9SDavid du Colombier char fn[30]; 261906943f9SDavid du Colombier int fd; 262906943f9SDavid du Colombier 263d40255d8SDavid du Colombier snprint(fn, sizeof fn, "/proc/%d/ctl", getpid()); 264906943f9SDavid du Colombier fd = open(fn, OWRITE); 265d40255d8SDavid du Colombier if(fd >= 0) { 266906943f9SDavid du Colombier fprint(fd, "pri 13"); 267906943f9SDavid du Colombier close(fd); 268906943f9SDavid du Colombier } 269d40255d8SDavid du Colombier } 270d40255d8SDavid du Colombier 271d40255d8SDavid du Colombier static int 272d40255d8SDavid du Colombier ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb) 273d40255d8SDavid du Colombier { 274d40255d8SDavid du Colombier int i, x, y, b, c; 275d40255d8SDavid du Colombier static char buts[] = {0x0, 0x2, 0x1}; 276d40255d8SDavid du Colombier 277d40255d8SDavid du Colombier c = ch->e / 8; 278*f7db6155SDavid du Colombier 279*f7db6155SDavid du Colombier /* sometimes there is a report id, sometimes not */ 280*f7db6155SDavid du Colombier if(c == kd->templ.sz + 1) 281*f7db6155SDavid du Colombier if(ch->buf[0] == kd->templ.id) 282*f7db6155SDavid du Colombier ch->b += 8; 283*f7db6155SDavid du Colombier else 284*f7db6155SDavid du Colombier return -1; 285d40255d8SDavid du Colombier parsereport(&kd->templ, ch); 286d40255d8SDavid du Colombier 287d40255d8SDavid du Colombier if(kbdebug) 288d40255d8SDavid du Colombier dumpreport(&kd->templ); 289d40255d8SDavid du Colombier if(c < 3) 290d40255d8SDavid du Colombier return -1; 291d40255d8SDavid du Colombier x = hidifcval(&kd->templ, KindX, 0); 292d40255d8SDavid du Colombier y = hidifcval(&kd->templ, KindY, 0); 293d40255d8SDavid du Colombier b = 0; 294d40255d8SDavid du Colombier for(i = 0; i<sizeof buts; i++) 295d40255d8SDavid du Colombier b |= (hidifcval(&kd->templ, KindButtons, i) & 1) << buts[i]; 296d40255d8SDavid du Colombier if(c > 3 && hidifcval(&kd->templ, KindWheel, 0) > 0) /* up */ 297d40255d8SDavid du Colombier b |= 0x10; 298d40255d8SDavid du Colombier if(c > 3 && hidifcval(&kd->templ, KindWheel, 0) < 0) /* down */ 299d40255d8SDavid du Colombier b |= 0x08; 300d40255d8SDavid du Colombier 301d40255d8SDavid du Colombier *px = x; 302d40255d8SDavid du Colombier *py = y; 303d40255d8SDavid du Colombier *pb = b; 304d40255d8SDavid du Colombier return 0; 305d40255d8SDavid du Colombier } 306d40255d8SDavid du Colombier 307d40255d8SDavid du Colombier static int 308d40255d8SDavid du Colombier ptrbootpvals(KDev *kd, Chain *ch, int *px, int *py, int *pb) 309d40255d8SDavid du Colombier { 310d40255d8SDavid du Colombier int b, c; 311d40255d8SDavid du Colombier char x, y; 312d40255d8SDavid du Colombier static char maptab[] = {0x0, 0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7}; 313d40255d8SDavid du Colombier 314d40255d8SDavid du Colombier c = ch->e / 8; 315d40255d8SDavid du Colombier if(c < 3) 316d40255d8SDavid du Colombier return -1; 317d40255d8SDavid du Colombier x = hidifcval(&kd->templ, KindX, 0); 318d40255d8SDavid du Colombier y = hidifcval(&kd->templ, KindY, 0); 319d40255d8SDavid du Colombier 320d40255d8SDavid du Colombier b = maptab[ch->buf[0] & 0x7]; 321d40255d8SDavid du Colombier if(c > 3 && ch->buf[3] == 1) /* up */ 322d40255d8SDavid du Colombier b |= 0x08; 323d40255d8SDavid du Colombier if(c > 3 && ch->buf[3] == 0xff) /* down */ 324d40255d8SDavid du Colombier b |= 0x10; 325d40255d8SDavid du Colombier *px = x; 326d40255d8SDavid du Colombier *py = y; 327d40255d8SDavid du Colombier *pb = b; 328d40255d8SDavid du Colombier return 0; 329d40255d8SDavid du Colombier } 330906943f9SDavid du Colombier 331906943f9SDavid du Colombier static void 33283030dd5SDavid du Colombier ptrwork(void* a) 33383030dd5SDavid du Colombier { 334d40255d8SDavid du Colombier int hipri, mfd, nerrs, x, y, b, c, ptrfd; 335906943f9SDavid du Colombier char mbuf[80]; 336d40255d8SDavid du Colombier Chain ch; 337906943f9SDavid du Colombier KDev* f = a; 33883030dd5SDavid du Colombier 339d5789509SDavid du Colombier hipri = nerrs = 0; 340906943f9SDavid du Colombier ptrfd = f->ep->dfd; 341906943f9SDavid du Colombier mfd = f->in->fd; 342d40255d8SDavid du Colombier if(f->ep->maxpkt < 3 || f->ep->maxpkt > MaxChLen) 34339dc1420SDavid du Colombier kbfatal(f, "weird mouse maxpkt"); 34483030dd5SDavid du Colombier for(;;){ 345d40255d8SDavid du Colombier memset(ch.buf, 0, MaxChLen); 34639dc1420SDavid du Colombier if(f->ep == nil) 34739dc1420SDavid du Colombier kbfatal(f, nil); 348d40255d8SDavid du Colombier c = read(ptrfd, ch.buf, f->ep->maxpkt); 34939dc1420SDavid du Colombier assert(f->dev != nil); 35039dc1420SDavid du Colombier assert(f->ep != nil); 351d5789509SDavid du Colombier if(c < 0){ 35239dc1420SDavid du Colombier dprint(2, "kb: mouse: %s: read: %r\n", f->ep->dir); 353d5789509SDavid du Colombier if(++nerrs < 3){ 354d5789509SDavid du Colombier recoverkb(f); 355d5789509SDavid du Colombier continue; 356d5789509SDavid du Colombier } 357d5789509SDavid du Colombier } 358906943f9SDavid du Colombier if(c <= 0) 359906943f9SDavid du Colombier kbfatal(f, nil); 360d40255d8SDavid du Colombier ch.b = 0; 361d40255d8SDavid du Colombier ch.e = 8 * c; 362d40255d8SDavid du Colombier if(f->ptrvals(f, &ch, &x, &y, &b) < 0) 36383030dd5SDavid du Colombier continue; 364906943f9SDavid du Colombier if(f->accel){ 365d40255d8SDavid du Colombier x = scale(f, x); 366d40255d8SDavid du Colombier y = scale(f, y); 36783030dd5SDavid du Colombier } 368d5789509SDavid du Colombier if(kbdebug > 1) 36939dc1420SDavid du Colombier fprint(2, "kb: m%11d %11d %11d\n", x, y, b); 370906943f9SDavid du Colombier seprint(mbuf, mbuf+sizeof(mbuf), "m%11d %11d %11d", x, y,b); 37139dc1420SDavid du Colombier if(write(mfd, mbuf, strlen(mbuf)) < 0) 37239dc1420SDavid du Colombier kbfatal(f, "mousein i/o"); 373906943f9SDavid du Colombier if(hipri == 0){ 374906943f9SDavid du Colombier sethipri(); 375906943f9SDavid du Colombier hipri = 1; 37683030dd5SDavid du Colombier } 37783030dd5SDavid du Colombier } 37883030dd5SDavid du Colombier } 37983030dd5SDavid du Colombier 38083030dd5SDavid du Colombier static void 381906943f9SDavid du Colombier stoprepeat(KDev *f) 38283030dd5SDavid du Colombier { 383906943f9SDavid du Colombier sendul(f->repeatc, Awakemsg); 38483030dd5SDavid du Colombier } 38583030dd5SDavid du Colombier 38683030dd5SDavid du Colombier static void 387906943f9SDavid du Colombier startrepeat(KDev *f, uchar esc1, uchar sc) 38883030dd5SDavid du Colombier { 38983030dd5SDavid du Colombier ulong c; 39083030dd5SDavid du Colombier 39183030dd5SDavid du Colombier if(esc1) 39283030dd5SDavid du Colombier c = SCesc1 << 8 | (sc & 0xff); 39383030dd5SDavid du Colombier else 39483030dd5SDavid du Colombier c = sc; 395906943f9SDavid du Colombier sendul(f->repeatc, c); 39683030dd5SDavid du Colombier } 39783030dd5SDavid du Colombier 39883030dd5SDavid du Colombier static void 399906943f9SDavid du Colombier putscan(int kbinfd, uchar esc, uchar sc) 40083030dd5SDavid du Colombier { 401906943f9SDavid du Colombier uchar s[2] = {SCesc1, 0}; 40283030dd5SDavid du Colombier 40383030dd5SDavid du Colombier if(sc == 0x41){ 404d5789509SDavid du Colombier kbdebug += 2; 40583030dd5SDavid du Colombier return; 40683030dd5SDavid du Colombier } 40783030dd5SDavid du Colombier if(sc == 0x42){ 408906943f9SDavid du Colombier kbdebug = 0; 40983030dd5SDavid du Colombier return; 41083030dd5SDavid du Colombier } 411906943f9SDavid du Colombier if(kbdebug) 41283030dd5SDavid du Colombier fprint(2, "sc: %x %x\n", (esc? SCesc1: 0), sc); 41383030dd5SDavid du Colombier s[1] = sc; 41483030dd5SDavid du Colombier if(esc && sc != 0) 41583030dd5SDavid du Colombier write(kbinfd, s, 2); 41683030dd5SDavid du Colombier else if(sc != 0) 41783030dd5SDavid du Colombier write(kbinfd, s+1, 1); 41883030dd5SDavid du Colombier } 41983030dd5SDavid du Colombier 42083030dd5SDavid du Colombier static void 421906943f9SDavid du Colombier repeatproc(void* a) 42283030dd5SDavid du Colombier { 423906943f9SDavid du Colombier KDev *f; 424906943f9SDavid du Colombier Channel *repeatc; 425906943f9SDavid du Colombier int kbdinfd; 426906943f9SDavid du Colombier ulong l, t, i; 42783030dd5SDavid du Colombier uchar esc1, sc; 42883030dd5SDavid du Colombier 429906943f9SDavid du Colombier /* 430906943f9SDavid du Colombier * too many jumps here. 431906943f9SDavid du Colombier * Rewrite instead of debug, if needed. 432906943f9SDavid du Colombier */ 433906943f9SDavid du Colombier f = a; 434906943f9SDavid du Colombier repeatc = f->repeatc; 435906943f9SDavid du Colombier kbdinfd = f->in->fd; 436906943f9SDavid du Colombier l = Awakemsg; 437906943f9SDavid du Colombier Repeat: 438906943f9SDavid du Colombier if(l == Diemsg) 439906943f9SDavid du Colombier goto Abort; 440906943f9SDavid du Colombier while(l == Awakemsg) 441906943f9SDavid du Colombier l = recvul(repeatc); 442906943f9SDavid du Colombier if(l == Diemsg) 443906943f9SDavid du Colombier goto Abort; 44483030dd5SDavid du Colombier esc1 = l >> 8; 44583030dd5SDavid du Colombier sc = l; 446906943f9SDavid du Colombier t = 160; 44783030dd5SDavid du Colombier for(;;){ 448906943f9SDavid du Colombier for(i = 0; i < t; i += 5){ 449906943f9SDavid du Colombier if(l = nbrecvul(repeatc)) 450906943f9SDavid du Colombier goto Repeat; 451906943f9SDavid du Colombier sleep(5); 45283030dd5SDavid du Colombier } 453906943f9SDavid du Colombier putscan(kbdinfd, esc1, sc); 454906943f9SDavid du Colombier t = 30; 45583030dd5SDavid du Colombier } 456906943f9SDavid du Colombier Abort: 457906943f9SDavid du Colombier chanfree(repeatc); 458906943f9SDavid du Colombier threadexits("aborted"); 459906943f9SDavid du Colombier 46083030dd5SDavid du Colombier } 46183030dd5SDavid du Colombier 46283030dd5SDavid du Colombier 46383030dd5SDavid du Colombier #define hasesc1(sc) (((sc) > 0x47) || ((sc) == 0x38)) 46483030dd5SDavid du Colombier 46583030dd5SDavid du Colombier static void 466906943f9SDavid du Colombier putmod(int fd, uchar mods, uchar omods, uchar mask, uchar esc, uchar sc) 46783030dd5SDavid du Colombier { 468906943f9SDavid du Colombier /* BUG: Should be a single write */ 46983030dd5SDavid du Colombier if((mods&mask) && !(omods&mask)) 470906943f9SDavid du Colombier putscan(fd, esc, sc); 47183030dd5SDavid du Colombier if(!(mods&mask) && (omods&mask)) 472906943f9SDavid du Colombier putscan(fd, esc, Keyup|sc); 47383030dd5SDavid du Colombier } 47483030dd5SDavid du Colombier 47583030dd5SDavid du Colombier /* 47683030dd5SDavid du Colombier * This routine diffs the state with the last known state 47783030dd5SDavid du Colombier * and invents the scan codes that would have been sent 47883030dd5SDavid du Colombier * by a non-usb keyboard in that case. This also requires supplying 47983030dd5SDavid du Colombier * the extra esc1 byte as well as keyup flags. 48083030dd5SDavid du Colombier * The aim is to allow future addition of other keycode pages 48183030dd5SDavid du Colombier * for other keyboards. 48283030dd5SDavid du Colombier */ 483906943f9SDavid du Colombier static uchar 484906943f9SDavid du Colombier putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk) 48583030dd5SDavid du Colombier { 48683030dd5SDavid du Colombier int i, j; 487906943f9SDavid du Colombier uchar uk; 488906943f9SDavid du Colombier int fd; 48983030dd5SDavid du Colombier 490906943f9SDavid du Colombier fd = f->in->fd; 491906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Mctrl, 0, SCctrl); 492906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], (1<<Mlshift), 0, SClshift); 493906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], (1<<Mrshift), 0, SCrshift); 494906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Mcompose, 0, SCcompose); 495906943f9SDavid du Colombier putmod(fd, buf[0], obuf[0], Maltgr, 1, SCcompose); 49683030dd5SDavid du Colombier 49783030dd5SDavid du Colombier /* Report key downs */ 49883030dd5SDavid du Colombier for(i = 2; i < n; i++){ 49983030dd5SDavid du Colombier for(j = 2; j < n; j++) 50083030dd5SDavid du Colombier if(buf[i] == obuf[j]) 50183030dd5SDavid du Colombier break; 50283030dd5SDavid du Colombier if(j == n && buf[i] != 0){ 503906943f9SDavid du Colombier dk = sctab[buf[i]]; 504906943f9SDavid du Colombier putscan(fd, hasesc1(dk), dk); 505906943f9SDavid du Colombier startrepeat(f, hasesc1(dk), dk); 50683030dd5SDavid du Colombier } 50783030dd5SDavid du Colombier } 50883030dd5SDavid du Colombier 50983030dd5SDavid du Colombier /* Report key ups */ 510906943f9SDavid du Colombier uk = 0; 51183030dd5SDavid du Colombier for(i = 2; i < n; i++){ 51283030dd5SDavid du Colombier for(j = 2; j < n; j++) 51383030dd5SDavid du Colombier if(obuf[i] == buf[j]) 51483030dd5SDavid du Colombier break; 51583030dd5SDavid du Colombier if(j == n && obuf[i] != 0){ 516906943f9SDavid du Colombier uk = sctab[obuf[i]]; 517906943f9SDavid du Colombier putscan(fd, hasesc1(uk), uk|Keyup); 51883030dd5SDavid du Colombier } 51983030dd5SDavid du Colombier } 520906943f9SDavid du Colombier if(uk && (dk == 0 || dk == uk)){ 521906943f9SDavid du Colombier stoprepeat(f); 522906943f9SDavid du Colombier dk = 0; 523906943f9SDavid du Colombier } 524906943f9SDavid du Colombier return dk; 52583030dd5SDavid du Colombier } 52683030dd5SDavid du Colombier 52783030dd5SDavid du Colombier static int 52883030dd5SDavid du Colombier kbdbusy(uchar* buf, int n) 52983030dd5SDavid du Colombier { 53083030dd5SDavid du Colombier int i; 53183030dd5SDavid du Colombier 53283030dd5SDavid du Colombier for(i = 1; i < n; i++) 53383030dd5SDavid du Colombier if(buf[i] == 0 || buf[i] != buf[0]) 53483030dd5SDavid du Colombier return 0; 53583030dd5SDavid du Colombier return 1; 53683030dd5SDavid du Colombier } 53783030dd5SDavid du Colombier 538906943f9SDavid du Colombier static void 53983030dd5SDavid du Colombier kbdwork(void *a) 54083030dd5SDavid du Colombier { 541a23bc242SDavid du Colombier int c, i, kbdfd, nerrs; 542a23bc242SDavid du Colombier uchar dk, buf[64], lbuf[64]; 543a23bc242SDavid du Colombier char err[128]; 544906943f9SDavid du Colombier KDev *f = a; 54583030dd5SDavid du Colombier 546906943f9SDavid du Colombier kbdfd = f->ep->dfd; 547906943f9SDavid du Colombier 548906943f9SDavid du Colombier if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) 549906943f9SDavid du Colombier kbfatal(f, "weird maxpkt"); 550906943f9SDavid du Colombier 551906943f9SDavid du Colombier f->repeatc = chancreate(sizeof(ulong), 0); 552906943f9SDavid du Colombier if(f->repeatc == nil) 553906943f9SDavid du Colombier kbfatal(f, "chancreate failed"); 554906943f9SDavid du Colombier 555906943f9SDavid du Colombier proccreate(repeatproc, f, Stack); 55683030dd5SDavid du Colombier memset(lbuf, 0, sizeof lbuf); 557a23bc242SDavid du Colombier dk = nerrs = 0; 55883030dd5SDavid du Colombier for(;;){ 55983030dd5SDavid du Colombier memset(buf, 0, sizeof buf); 560906943f9SDavid du Colombier c = read(kbdfd, buf, f->ep->maxpkt); 56139dc1420SDavid du Colombier assert(f->dev != nil); 56239dc1420SDavid du Colombier assert(f->ep != nil); 563a23bc242SDavid du Colombier if(c < 0){ 564a23bc242SDavid du Colombier rerrstr(err, sizeof(err)); 565d5789509SDavid du Colombier fprint(2, "kb: %s: read: %s\n", f->ep->dir, err); 566a23bc242SDavid du Colombier if(strstr(err, "babble") != 0 && ++nerrs < 3){ 567a23bc242SDavid du Colombier recoverkb(f); 568a23bc242SDavid du Colombier continue; 569a23bc242SDavid du Colombier } 570a23bc242SDavid du Colombier } 571906943f9SDavid du Colombier if(c <= 0) 57239dc1420SDavid du Colombier kbfatal(f, nil); 57383030dd5SDavid du Colombier if(c < 3) 57483030dd5SDavid du Colombier continue; 57583030dd5SDavid du Colombier if(kbdbusy(buf + 2, c - 2)) 57683030dd5SDavid du Colombier continue; 577d5789509SDavid du Colombier if(usbdebug > 2 || kbdebug > 1){ 57883030dd5SDavid du Colombier fprint(2, "kbd mod %x: ", buf[0]); 57983030dd5SDavid du Colombier for(i = 2; i < c; i++) 58083030dd5SDavid du Colombier fprint(2, "kc %x ", buf[i]); 58183030dd5SDavid du Colombier fprint(2, "\n"); 58283030dd5SDavid du Colombier } 583906943f9SDavid du Colombier dk = putkeys(f, buf, lbuf, f->ep->maxpkt, dk); 58483030dd5SDavid du Colombier memmove(lbuf, buf, c); 585a23bc242SDavid du Colombier nerrs = 0; 58683030dd5SDavid du Colombier } 58783030dd5SDavid du Colombier } 58883030dd5SDavid du Colombier 58983030dd5SDavid du Colombier static void 590906943f9SDavid du Colombier freekdev(void *a) 59183030dd5SDavid du Colombier { 592906943f9SDavid du Colombier KDev *kd; 59383030dd5SDavid du Colombier 594906943f9SDavid du Colombier kd = a; 595906943f9SDavid du Colombier if(kd->in != nil){ 596906943f9SDavid du Colombier qlock(&inlck); 597906943f9SDavid du Colombier if(--kd->in->ref == 0){ 598906943f9SDavid du Colombier close(kd->in->fd); 599906943f9SDavid du Colombier kd->in->fd = -1; 60083030dd5SDavid du Colombier } 601906943f9SDavid du Colombier qunlock(&inlck); 60283030dd5SDavid du Colombier } 60339dc1420SDavid du Colombier dprint(2, "freekdev\n"); 604906943f9SDavid du Colombier free(kd); 60583030dd5SDavid du Colombier } 60683030dd5SDavid du Colombier 60783030dd5SDavid du Colombier static void 608d40255d8SDavid du Colombier kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), KDev *kd) 609906943f9SDavid du Colombier { 610d40255d8SDavid du Colombier uchar desc[128]; 611d40255d8SDavid du Colombier int res; 612906943f9SDavid du Colombier 613906943f9SDavid du Colombier qlock(&inlck); 614906943f9SDavid du Colombier if(in->fd < 0){ 615906943f9SDavid du Colombier in->fd = open(in->name, OWRITE); 616906943f9SDavid du Colombier if(in->fd < 0){ 617906943f9SDavid du Colombier fprint(2, "kb: %s: %r\n", in->name); 618906943f9SDavid du Colombier qunlock(&inlck); 619906943f9SDavid du Colombier return; 620906943f9SDavid du Colombier } 621906943f9SDavid du Colombier } 62239dc1420SDavid du Colombier in->ref++; /* for kd->in = in */ 623906943f9SDavid du Colombier qunlock(&inlck); 624906943f9SDavid du Colombier d->free = freekdev; 625906943f9SDavid du Colombier kd->in = in; 626906943f9SDavid du Colombier kd->dev = d; 627d40255d8SDavid du Colombier res = -1; 628*f7db6155SDavid du Colombier kd->ep = openep(d, ep->id); 629*f7db6155SDavid du Colombier if(kd->ep == nil){ 630*f7db6155SDavid du Colombier fprint(2, "kb: %s: openep %d: %r\n", d->dir, ep->id); 631*f7db6155SDavid du Colombier return; 632*f7db6155SDavid du Colombier } 633d40255d8SDavid du Colombier if(!kd->bootp) 634d40255d8SDavid du Colombier res= setfirstconfig(kd, ep->id, desc, sizeof desc); 635d40255d8SDavid du Colombier if(res > 0) 636d40255d8SDavid du Colombier res = parsereportdesc(&kd->templ, desc, sizeof desc); 637d40255d8SDavid du Colombier /* if we could not set the first config, we give up */ 638d40255d8SDavid du Colombier if(kd->bootp || res < 0){ 639d40255d8SDavid du Colombier kd->bootp = 1; 640d40255d8SDavid du Colombier if(setbootproto(kd, ep->id, nil, 0) < 0){ 641906943f9SDavid du Colombier fprint(2, "kb: %s: bootproto: %r\n", d->dir); 642906943f9SDavid du Colombier return; 643906943f9SDavid du Colombier } 644d40255d8SDavid du Colombier }else if(kbdebug) 645d40255d8SDavid du Colombier dumpreport(&kd->templ); 646906943f9SDavid du Colombier if(opendevdata(kd->ep, OREAD) < 0){ 647906943f9SDavid du Colombier fprint(2, "kb: %s: opendevdata: %r\n", kd->ep->dir); 648906943f9SDavid du Colombier closedev(kd->ep); 649906943f9SDavid du Colombier kd->ep = nil; 650906943f9SDavid du Colombier return; 651906943f9SDavid du Colombier } 652906943f9SDavid du Colombier 653906943f9SDavid du Colombier incref(d); 654906943f9SDavid du Colombier proccreate(f, kd, Stack); 655906943f9SDavid du Colombier } 656906943f9SDavid du Colombier 657906943f9SDavid du Colombier static int 65883030dd5SDavid du Colombier usage(void) 65983030dd5SDavid du Colombier { 660d40255d8SDavid du Colombier werrstr("usage: usb/kb [-bdkm] [-a n] [-N nb]"); 661906943f9SDavid du Colombier return -1; 66283030dd5SDavid du Colombier } 66383030dd5SDavid du Colombier 664906943f9SDavid du Colombier int 665906943f9SDavid du Colombier kbmain(Dev *d, int argc, char* argv[]) 66683030dd5SDavid du Colombier { 667d40255d8SDavid du Colombier int bootp, i, kena, pena, accel, devid; 668906943f9SDavid du Colombier Ep *ep; 669d40255d8SDavid du Colombier KDev *kd; 670d40255d8SDavid du Colombier Usbdev *ud; 67183030dd5SDavid du Colombier 672906943f9SDavid du Colombier kena = pena = 1; 673d40255d8SDavid du Colombier bootp = 0; 674906943f9SDavid du Colombier accel = 0; 675ed868a7cSDavid du Colombier devid = d->id; 67683030dd5SDavid du Colombier ARGBEGIN{ 67783030dd5SDavid du Colombier case 'a': 678ed868a7cSDavid du Colombier accel = strtol(EARGF(usage()), nil, 0); 67983030dd5SDavid du Colombier break; 68083030dd5SDavid du Colombier case 'd': 681906943f9SDavid du Colombier kbdebug++; 68283030dd5SDavid du Colombier break; 68383030dd5SDavid du Colombier case 'k': 684906943f9SDavid du Colombier kena = 1; 685906943f9SDavid du Colombier pena = 0; 68683030dd5SDavid du Colombier break; 68783030dd5SDavid du Colombier case 'm': 688906943f9SDavid du Colombier kena = 0; 689906943f9SDavid du Colombier pena = 1; 69083030dd5SDavid du Colombier break; 691ed868a7cSDavid du Colombier case 'N': 692ed868a7cSDavid du Colombier devid = atoi(EARGF(usage())); /* ignore dev number */ 693ed868a7cSDavid du Colombier break; 694d40255d8SDavid du Colombier case 'b': 695d40255d8SDavid du Colombier bootp++; 696d40255d8SDavid du Colombier break; 69783030dd5SDavid du Colombier default: 698906943f9SDavid du Colombier return usage(); 69983030dd5SDavid du Colombier }ARGEND; 700d40255d8SDavid du Colombier if(argc != 0) 701906943f9SDavid du Colombier return usage(); 702ed868a7cSDavid du Colombier USED(devid); 703906943f9SDavid du Colombier ud = d->usb; 704906943f9SDavid du Colombier d->aux = nil; 705906943f9SDavid du Colombier dprint(2, "kb: main: dev %s ref %ld\n", d->dir, d->ref); 706d40255d8SDavid du Colombier 707d40255d8SDavid du Colombier if(kena) 708d40255d8SDavid du Colombier for(i = 0; i < nelem(ud->ep); i++) 709d40255d8SDavid du Colombier if((ep = ud->ep[i]) == nil) 710d40255d8SDavid du Colombier break; 711d40255d8SDavid du Colombier else if(ep->iface->csp == KbdCSP) 712d40255d8SDavid du Colombier bootp = 1; 713d40255d8SDavid du Colombier 714906943f9SDavid du Colombier for(i = 0; i < nelem(ud->ep); i++){ 715906943f9SDavid du Colombier if((ep = ud->ep[i]) == nil) 716906943f9SDavid du Colombier break; 717d40255d8SDavid du Colombier if(kena && ep->type == Eintr && ep->dir == Ein && 718d40255d8SDavid du Colombier ep->iface->csp == KbdCSP){ 719d40255d8SDavid du Colombier kd = d->aux = emallocz(sizeof(KDev), 1); 720d40255d8SDavid du Colombier kd->accel = 0; 721d40255d8SDavid du Colombier kd->bootp = 1; 722d40255d8SDavid du Colombier kbstart(d, ep, &kbdin, kbdwork, kd); 723d40255d8SDavid du Colombier } 724d40255d8SDavid du Colombier if(pena && ep->type == Eintr && ep->dir == Ein && 725d40255d8SDavid du Colombier ep->iface->csp == PtrCSP){ 726d40255d8SDavid du Colombier kd = d->aux = emallocz(sizeof(KDev), 1); 727d40255d8SDavid du Colombier kd->accel = accel; 728d40255d8SDavid du Colombier kd->bootp = bootp; 729d40255d8SDavid du Colombier kbstart(d, ep, &ptrin, ptrwork, kd); 730d40255d8SDavid du Colombier } 731906943f9SDavid du Colombier } 732906943f9SDavid du Colombier return 0; 73383030dd5SDavid du Colombier } 734