1 /* 2 * USB Human Interaction Device: keyboard and mouse. 3 * 4 * If there's no usb keyboard, it tries to setup the mouse, if any. 5 * It should be started at boot time. 6 * 7 * Mouse events are converted to the format of mouse(3)'s mousein file. 8 * Keyboard keycodes are translated to scan codes and sent to kbin(3). 9 * 10 * If there is no keyboard, it tries to setup the mouse properly, else it falls 11 * back to boot protocol. 12 */ 13 14 #include <u.h> 15 #include <libc.h> 16 #include <thread.h> 17 #include "usb.h" 18 #include "hid.h" 19 20 enum 21 { 22 Awakemsg= 0xdeaddead, 23 Diemsg = 0xbeefbeef, 24 Dwcidle = 8, 25 }; 26 27 typedef struct KDev KDev; 28 typedef struct Kin Kin; 29 30 struct KDev 31 { 32 Dev* dev; /* usb device*/ 33 Dev* ep; /* endpoint to get events */ 34 Kin* in; /* used to send events to kernel */ 35 int idle; /* min time between reports (× 4ms) */ 36 Channel*repeatc; /* only for keyboard */ 37 int accel; /* only for mouse */ 38 int bootp; /* has associated keyboard */ 39 HidRepTempl templ; 40 int (*ptrvals)(KDev *kd, Chain *ch, int *px, int *py, int *pb); 41 }; 42 43 /* 44 * Kbdin and mousein files must be shared among all instances. 45 */ 46 struct Kin 47 { 48 int ref; 49 int fd; 50 char* name; 51 }; 52 53 /* 54 * Map for the logitech bluetooth mouse with 8 buttons and wheels. 55 * { ptr ->mouse} 56 * { 0x01, 0x01 }, // left 57 * { 0x04, 0x02 }, // middle 58 * { 0x02, 0x04 }, // right 59 * { 0x40, 0x08 }, // up 60 * { 0x80, 0x10 }, // down 61 * { 0x10, 0x08 }, // side up 62 * { 0x08, 0x10 }, // side down 63 * { 0x20, 0x02 }, // page 64 * besides wheel and regular up/down report the 4th byte as 1/-1 65 */ 66 67 /* 68 * key code to scan code; for the page table used by 69 * the logitech bluetooth keyboard. 70 */ 71 static char sctab[256] = 72 { 73 [0x00] 0x0, 0x0, 0x0, 0x0, 0x1e, 0x30, 0x2e, 0x20, 74 [0x08] 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 75 [0x10] 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 76 [0x18] 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x2, 0x3, 77 [0x20] 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 78 [0x28] 0x1c, 0x1, 0xe, 0xf, 0x39, 0xc, 0xd, 0x1a, 79 [0x30] 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, 80 [0x38] 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 81 [0x40] 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0x63, 0x46, 82 [0x48] 0x77, 0x52, 0x47, 0x49, 0x53, 0x4f, 0x51, 0x4d, 83 [0x50] 0x4b, 0x50, 0x48, 0x45, 0x35, 0x37, 0x4a, 0x4e, 84 [0x58] 0x1c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, 85 [0x60] 0x48, 0x49, 0x52, 0x53, 0x56, 0x7f, 0x74, 0x75, 86 [0x68] 0x55, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 87 [0x70] 0x78, 0x79, 0x7a, 0x7b, 0x0, 0x0, 0x0, 0x0, 88 [0x78] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 89 [0x80] 0x73, 0x72, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, 90 [0x88] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 91 [0x90] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 92 [0x98] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 93 [0xa0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 94 [0xa8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 95 [0xb0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 96 [0xb8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 97 [0xc0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 98 [0xc8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 99 [0xd0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 100 [0xd8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 101 [0xe0] 0x1d, 0x2a, 0x38, 0x7d, 0x61, 0x36, 0x64, 0x7e, 102 [0xe8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x73, 0x72, 0x71, 103 [0xf0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 104 [0xf8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 105 }; 106 107 static QLock inlck; 108 static Kin kbdin = 109 { 110 .ref = 0, 111 .name = "#Ι/kbin", 112 .fd = -1, 113 }; 114 static Kin ptrin = 115 { 116 .ref = 0, 117 .name = "#m/mousein", 118 .fd = -1, 119 }; 120 121 static int kbdebug; 122 123 static int ptrbootpvals(KDev *kd, Chain *ch, int *px, int *py, int *pb); 124 static int ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb); 125 126 static int 127 setbootproto(KDev* f, int eid, uchar *, int) 128 { 129 int nr, r, id; 130 131 f->ptrvals = ptrbootpvals; 132 r = Rh2d|Rclass|Riface; 133 dprint(2, "setting boot protocol\n"); 134 id = f->dev->usb->ep[eid]->iface->id; 135 nr = usbcmd(f->dev, r, Setproto, Bootproto, id, nil, 0); 136 if(nr < 0) 137 return -1; 138 usbcmd(f->dev, r, Setidle, f->idle<<8, id, nil, 0); 139 return nr; 140 } 141 142 static uchar ignoredesc[128]; 143 144 static int 145 setfirstconfig(KDev* f, int eid, uchar *desc, int descsz) 146 { 147 int nr, r, id, i; 148 149 dprint(2, "setting first config\n"); 150 if(desc == nil){ 151 descsz = sizeof ignoredesc; 152 desc = ignoredesc; 153 } 154 id = f->dev->usb->ep[eid]->iface->id; 155 r = Rh2d | Rstd | Rdev; 156 nr =usbcmd(f->dev, r, Rsetconf, 1, id, nil, 0); 157 if(nr < 0) 158 return -1; 159 r = Rh2d | Rclass | Riface; 160 nr = usbcmd(f->dev, r, Setidle, f->idle<<8, id, nil, 0); 161 if(nr < 0) 162 return -1; 163 r = Rd2h | Rstd | Riface; 164 nr=usbcmd(f->dev, r, Rgetdesc, Dreport<<8, id, desc, descsz); 165 if(nr < 0) 166 return -1; 167 if(kbdebug && nr > 0){ 168 fprint(2, "report descriptor:"); 169 for(i = 0; i < nr; i++){ 170 if(i%8 == 0) 171 fprint(2, "\n\t"); 172 fprint(2, "%#2.2ux ", desc[i]); 173 } 174 fprint(2, "\n"); 175 } 176 f->ptrvals = ptrrepvals; 177 return nr; 178 } 179 180 /* 181 * Try to recover from a babble error. A port reset is the only way out. 182 * BUG: we should be careful not to reset a bundle with several devices. 183 */ 184 static void 185 recoverkb(KDev *f) 186 { 187 int i; 188 189 close(f->dev->dfd); /* it's for usbd now */ 190 devctl(f->dev, "reset"); 191 for(i = 0; i < 10; i++){ 192 if(i == 5) 193 f->bootp++; 194 sleep(500); 195 if(opendevdata(f->dev, ORDWR) >= 0){ 196 if(f->bootp) 197 /* TODO func pointer */ 198 setbootproto(f, f->ep->id, nil, 0); 199 else 200 setfirstconfig(f, f->ep->id, nil, 0); 201 break; 202 } 203 /* else usbd still working... */ 204 } 205 } 206 207 static void 208 kbfatal(KDev *kd, char *sts) 209 { 210 Dev *dev; 211 212 if(sts != nil) 213 fprint(2, "kb: fatal: %s\n", sts); 214 else 215 fprint(2, "kb: exiting\n"); 216 if(kd->repeatc != nil) 217 nbsendul(kd->repeatc, Diemsg); 218 dev = kd->dev; 219 kd->dev = nil; 220 if(kd->ep != nil) 221 closedev(kd->ep); 222 kd->ep = nil; 223 devctl(dev, "detach"); 224 closedev(dev); 225 /* 226 * free(kd); done by closedev. 227 */ 228 threadexits(sts); 229 } 230 231 static int 232 scale(KDev *f, int x) 233 { 234 int sign = 1; 235 236 if(x < 0){ 237 sign = -1; 238 x = -x; 239 } 240 switch(x){ 241 case 0: 242 case 1: 243 case 2: 244 case 3: 245 break; 246 case 4: 247 x = 6 + (f->accel>>2); 248 break; 249 case 5: 250 x = 9 + (f->accel>>1); 251 break; 252 default: 253 x *= MaxAcc; 254 break; 255 } 256 return sign*x; 257 } 258 259 /* 260 * ps2 mouse is processed mostly at interrupt time. 261 * for usb we do what we can. 262 */ 263 static void 264 sethipri(void) 265 { 266 char fn[30]; 267 int fd; 268 269 snprint(fn, sizeof fn, "/proc/%d/ctl", getpid()); 270 fd = open(fn, OWRITE); 271 if(fd >= 0) { 272 fprint(fd, "pri 13"); 273 close(fd); 274 } 275 } 276 277 static int 278 ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb) 279 { 280 int i, x, y, b, c; 281 static char buts[] = {0x0, 0x2, 0x1}; 282 283 c = ch->e / 8; 284 285 /* sometimes there is a report id, sometimes not */ 286 if(c == kd->templ.sz + 1) 287 if(ch->buf[0] == kd->templ.id) 288 ch->b += 8; 289 else 290 return -1; 291 parsereport(&kd->templ, ch); 292 293 if(kbdebug) 294 dumpreport(&kd->templ); 295 if(c < 3) 296 return -1; 297 x = hidifcval(&kd->templ, KindX, 0); 298 y = hidifcval(&kd->templ, KindY, 0); 299 b = 0; 300 for(i = 0; i<sizeof buts; i++) 301 b |= (hidifcval(&kd->templ, KindButtons, i) & 1) << buts[i]; 302 if(c > 3 && hidifcval(&kd->templ, KindWheel, 0) > 0) /* up */ 303 b |= 0x10; 304 if(c > 3 && hidifcval(&kd->templ, KindWheel, 0) < 0) /* down */ 305 b |= 0x08; 306 307 *px = x; 308 *py = y; 309 *pb = b; 310 return 0; 311 } 312 313 static int 314 ptrbootpvals(KDev *kd, Chain *ch, int *px, int *py, int *pb) 315 { 316 int b, c; 317 char x, y; 318 static char maptab[] = {0x0, 0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7}; 319 320 c = ch->e / 8; 321 if(c < 3) 322 return -1; 323 x = hidifcval(&kd->templ, KindX, 0); 324 y = hidifcval(&kd->templ, KindY, 0); 325 326 b = maptab[ch->buf[0] & 0x7]; 327 if(c > 3 && ch->buf[3] == 1) /* up */ 328 b |= 0x08; 329 if(c > 3 && ch->buf[3] == 0xff) /* down */ 330 b |= 0x10; 331 *px = x; 332 *py = y; 333 *pb = b; 334 return 0; 335 } 336 337 static void 338 ptrwork(void* a) 339 { 340 int hipri, mfd, nerrs, x, y, b, c, ptrfd; 341 char mbuf[80]; 342 Chain ch; 343 KDev* f = a; 344 345 threadsetname("ptr %s", f->in->name); 346 hipri = nerrs = 0; 347 ptrfd = f->ep->dfd; 348 mfd = f->in->fd; 349 if(f->ep->maxpkt < 3 || f->ep->maxpkt > MaxChLen) 350 kbfatal(f, "weird mouse maxpkt"); 351 for(;;){ 352 memset(ch.buf, 0, MaxChLen); 353 if(f->ep == nil) 354 kbfatal(f, nil); 355 c = read(ptrfd, ch.buf, f->ep->maxpkt); 356 assert(f->dev != nil); 357 assert(f->ep != nil); 358 if(c < 0){ 359 dprint(2, "kb: mouse: %s: read: %r\n", f->ep->dir); 360 if(++nerrs < 3){ 361 recoverkb(f); 362 continue; 363 } 364 } 365 if(c <= 0) 366 kbfatal(f, nil); 367 ch.b = 0; 368 ch.e = 8 * c; 369 if(f->ptrvals(f, &ch, &x, &y, &b) < 0) 370 continue; 371 if(f->accel){ 372 x = scale(f, x); 373 y = scale(f, y); 374 } 375 if(kbdebug > 1) 376 fprint(2, "kb: m%11d %11d %11d\n", x, y, b); 377 seprint(mbuf, mbuf+sizeof(mbuf), "m%11d %11d %11d", x, y,b); 378 if(write(mfd, mbuf, strlen(mbuf)) < 0) 379 kbfatal(f, "mousein i/o"); 380 if(hipri == 0){ 381 sethipri(); 382 hipri = 1; 383 } 384 } 385 } 386 387 static void 388 stoprepeat(KDev *f) 389 { 390 sendul(f->repeatc, Awakemsg); 391 } 392 393 static void 394 startrepeat(KDev *f, uchar esc1, uchar sc) 395 { 396 ulong c; 397 398 if(esc1) 399 c = SCesc1 << 8 | (sc & 0xff); 400 else 401 c = sc; 402 sendul(f->repeatc, c); 403 } 404 405 static void 406 putscan(int kbinfd, uchar esc, uchar sc) 407 { 408 uchar s[2] = {SCesc1, 0}; 409 410 if(sc == 0x41){ 411 kbdebug += 2; 412 return; 413 } 414 if(sc == 0x42){ 415 kbdebug = 0; 416 return; 417 } 418 if(kbdebug) 419 fprint(2, "sc: %x %x\n", (esc? SCesc1: 0), sc); 420 s[1] = sc; 421 if(esc && sc != 0) 422 write(kbinfd, s, 2); 423 else if(sc != 0) 424 write(kbinfd, s+1, 1); 425 } 426 427 static void 428 repeatproc(void* a) 429 { 430 KDev *f; 431 Channel *repeatc; 432 int kbdinfd; 433 ulong l, t, i; 434 uchar esc1, sc; 435 436 threadsetname("kbd repeat"); 437 /* 438 * too many jumps here. 439 * Rewrite instead of debug, if needed. 440 */ 441 f = a; 442 repeatc = f->repeatc; 443 kbdinfd = f->in->fd; 444 l = Awakemsg; 445 Repeat: 446 if(l == Diemsg) 447 goto Abort; 448 while(l == Awakemsg) 449 l = recvul(repeatc); 450 if(l == Diemsg) 451 goto Abort; 452 esc1 = l >> 8; 453 sc = l; 454 t = 160; 455 for(;;){ 456 for(i = 0; i < t; i += 5){ 457 if(l = nbrecvul(repeatc)) 458 goto Repeat; 459 sleep(5); 460 } 461 putscan(kbdinfd, esc1, sc); 462 t = 30; 463 } 464 Abort: 465 chanfree(repeatc); 466 threadexits("aborted"); 467 468 } 469 470 471 #define hasesc1(sc) (((sc) > 0x47) || ((sc) == 0x38)) 472 473 static void 474 putmod(int fd, uchar mods, uchar omods, uchar mask, uchar esc, uchar sc) 475 { 476 /* BUG: Should be a single write */ 477 if((mods&mask) && !(omods&mask)) 478 putscan(fd, esc, sc); 479 if(!(mods&mask) && (omods&mask)) 480 putscan(fd, esc, Keyup|sc); 481 } 482 483 /* 484 * This routine diffs the state with the last known state 485 * and invents the scan codes that would have been sent 486 * by a non-usb keyboard in that case. This also requires supplying 487 * the extra esc1 byte as well as keyup flags. 488 * The aim is to allow future addition of other keycode pages 489 * for other keyboards. 490 */ 491 static uchar 492 putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk) 493 { 494 int i, j; 495 uchar uk; 496 int fd; 497 498 fd = f->in->fd; 499 putmod(fd, buf[0], obuf[0], Mctrl, 0, SCctrl); 500 putmod(fd, buf[0], obuf[0], (1<<Mlshift), 0, SClshift); 501 putmod(fd, buf[0], obuf[0], (1<<Mrshift), 0, SCrshift); 502 putmod(fd, buf[0], obuf[0], Mcompose, 0, SCcompose); 503 putmod(fd, buf[0], obuf[0], Maltgr, 1, SCcompose); 504 505 /* Report key downs */ 506 for(i = 2; i < n; i++){ 507 for(j = 2; j < n; j++) 508 if(buf[i] == obuf[j]) 509 break; 510 if(j == n && buf[i] != 0){ 511 dk = sctab[buf[i]]; 512 putscan(fd, hasesc1(dk), dk); 513 startrepeat(f, hasesc1(dk), dk); 514 } 515 } 516 517 /* Report key ups */ 518 uk = 0; 519 for(i = 2; i < n; i++){ 520 for(j = 2; j < n; j++) 521 if(obuf[i] == buf[j]) 522 break; 523 if(j == n && obuf[i] != 0){ 524 uk = sctab[obuf[i]]; 525 putscan(fd, hasesc1(uk), uk|Keyup); 526 } 527 } 528 if(uk && (dk == 0 || dk == uk)){ 529 stoprepeat(f); 530 dk = 0; 531 } 532 return dk; 533 } 534 535 static int 536 kbdbusy(uchar* buf, int n) 537 { 538 int i; 539 540 for(i = 1; i < n; i++) 541 if(buf[i] == 0 || buf[i] != buf[0]) 542 return 0; 543 return 1; 544 } 545 546 static void 547 kbdwork(void *a) 548 { 549 int c, i, kbdfd, nerrs; 550 uchar dk, buf[64], lbuf[64]; 551 char err[128]; 552 KDev *f = a; 553 554 threadsetname("kbd %s", f->in->name); 555 kbdfd = f->ep->dfd; 556 557 if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) 558 kbfatal(f, "weird maxpkt"); 559 560 f->repeatc = chancreate(sizeof(ulong), 0); 561 if(f->repeatc == nil) 562 kbfatal(f, "chancreate failed"); 563 564 proccreate(repeatproc, f, Stack); 565 memset(lbuf, 0, sizeof lbuf); 566 dk = nerrs = 0; 567 for(;;){ 568 memset(buf, 0, sizeof buf); 569 c = read(kbdfd, buf, f->ep->maxpkt); 570 assert(f->dev != nil); 571 assert(f->ep != nil); 572 if(c < 0){ 573 rerrstr(err, sizeof(err)); 574 fprint(2, "kb: %s: read: %s\n", f->ep->dir, err); 575 if(strstr(err, "babble") != 0 && ++nerrs < 3){ 576 recoverkb(f); 577 continue; 578 } 579 } 580 if(c <= 0) 581 kbfatal(f, nil); 582 if(c < 3) 583 continue; 584 if(kbdbusy(buf + 2, c - 2)) 585 continue; 586 if(usbdebug > 2 || kbdebug > 1){ 587 fprint(2, "kbd mod %x: ", buf[0]); 588 for(i = 2; i < c; i++) 589 fprint(2, "kc %x ", buf[i]); 590 fprint(2, "\n"); 591 } 592 dk = putkeys(f, buf, lbuf, f->ep->maxpkt, dk); 593 memmove(lbuf, buf, c); 594 nerrs = 0; 595 } 596 } 597 598 static void 599 freekdev(void *a) 600 { 601 KDev *kd; 602 603 kd = a; 604 if(kd->in != nil){ 605 qlock(&inlck); 606 if(--kd->in->ref == 0){ 607 close(kd->in->fd); 608 kd->in->fd = -1; 609 } 610 qunlock(&inlck); 611 } 612 dprint(2, "freekdev\n"); 613 free(kd); 614 } 615 616 static void 617 kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), KDev *kd) 618 { 619 uchar desc[128]; 620 int n, res; 621 622 qlock(&inlck); 623 if(in->fd < 0){ 624 in->fd = open(in->name, OWRITE); 625 if(in->fd < 0){ 626 fprint(2, "kb: %s: %r\n", in->name); 627 qunlock(&inlck); 628 return; 629 } 630 } 631 in->ref++; /* for kd->in = in */ 632 qunlock(&inlck); 633 d->free = freekdev; 634 kd->in = in; 635 kd->dev = d; 636 res = -1; 637 kd->ep = openep(d, ep->id); 638 if(kd->ep == nil){ 639 fprint(2, "kb: %s: openep %d: %r\n", d->dir, ep->id); 640 return; 641 } 642 if(in == &kbdin){ 643 /* 644 * DWC OTG controller misses some split transaction inputs. 645 * Set nonzero idle time to return more frequent reports 646 * of keyboard state, to avoid losing key up/down events. 647 */ 648 n = read(d->cfd, desc, sizeof desc - 1); 649 if(n > 0){ 650 desc[n] = 0; 651 if(strstr((char*)desc, "dwcotg") != nil) 652 kd->idle = Dwcidle; 653 } 654 } 655 if(!kd->bootp) 656 res= setfirstconfig(kd, ep->id, desc, sizeof desc); 657 if(res > 0) 658 res = parsereportdesc(&kd->templ, desc, sizeof desc); 659 /* if we could not set the first config, we give up */ 660 if(kd->bootp || res < 0){ 661 kd->bootp = 1; 662 if(setbootproto(kd, ep->id, nil, 0) < 0){ 663 fprint(2, "kb: %s: bootproto: %r\n", d->dir); 664 return; 665 } 666 }else if(kbdebug) 667 dumpreport(&kd->templ); 668 if(opendevdata(kd->ep, OREAD) < 0){ 669 fprint(2, "kb: %s: opendevdata: %r\n", kd->ep->dir); 670 closedev(kd->ep); 671 kd->ep = nil; 672 return; 673 } 674 675 incref(d); 676 proccreate(f, kd, Stack); 677 } 678 679 static int 680 usage(void) 681 { 682 werrstr("usage: usb/kb [-bdkm] [-a n] [-N nb]"); 683 return -1; 684 } 685 686 int 687 kbmain(Dev *d, int argc, char* argv[]) 688 { 689 int bootp, i, kena, pena, accel, devid; 690 Ep *ep; 691 KDev *kd; 692 Usbdev *ud; 693 694 kena = pena = 1; 695 bootp = 0; 696 accel = 0; 697 devid = d->id; 698 ARGBEGIN{ 699 case 'a': 700 accel = strtol(EARGF(usage()), nil, 0); 701 break; 702 case 'd': 703 kbdebug++; 704 break; 705 case 'k': 706 kena = 1; 707 pena = 0; 708 break; 709 case 'm': 710 kena = 0; 711 pena = 1; 712 break; 713 case 'N': 714 devid = atoi(EARGF(usage())); /* ignore dev number */ 715 break; 716 case 'b': 717 bootp++; 718 break; 719 default: 720 return usage(); 721 }ARGEND; 722 if(argc != 0) 723 return usage(); 724 USED(devid); 725 ud = d->usb; 726 d->aux = nil; 727 dprint(2, "kb: main: dev %s ref %ld\n", d->dir, d->ref); 728 729 if(kena) 730 for(i = 0; i < nelem(ud->ep); i++) 731 if((ep = ud->ep[i]) == nil) 732 break; 733 else if(ep->iface->csp == KbdCSP) 734 bootp = 1; 735 736 for(i = 0; i < nelem(ud->ep); i++){ 737 if((ep = ud->ep[i]) == nil) 738 break; 739 if(kena && ep->type == Eintr && ep->dir == Ein && 740 ep->iface->csp == KbdCSP){ 741 kd = d->aux = emallocz(sizeof(KDev), 1); 742 kd->accel = 0; 743 kd->bootp = 1; 744 kbstart(d, ep, &kbdin, kbdwork, kd); 745 } 746 if(pena && ep->type == Eintr && ep->dir == Ein && 747 ep->iface->csp == PtrCSP){ 748 kd = d->aux = emallocz(sizeof(KDev), 1); 749 kd->accel = accel; 750 kd->bootp = bootp; 751 kbstart(d, ep, &ptrin, ptrwork, kd); 752 } 753 } 754 return 0; 755 } 756