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