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
setbootproto(KDev * f,int eid,uchar *,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
setfirstconfig(KDev * f,int eid,uchar * desc,int descsz)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
recoverkb(KDev * f)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
kbfatal(KDev * kd,char * sts)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
scale(KDev * f,int x)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
sethipri(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
ptrrepvals(KDev * kd,Chain * ch,int * px,int * py,int * pb)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 |= 0x08;
303 if(c > 3 && hidifcval(&kd->templ, KindWheel, 0) < 0) /* down */
304 b |= 0x10;
305
306 *px = x;
307 *py = y;
308 *pb = b;
309 return 0;
310 }
311
312 static int
ptrbootpvals(KDev * kd,Chain * ch,int * px,int * py,int * pb)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
ptrwork(void * a)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
stoprepeat(KDev * f)393 stoprepeat(KDev *f)
394 {
395 sendul(f->repeatc, Awakemsg);
396 }
397
398 static void
startrepeat(KDev * f,uchar esc1,uchar sc)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
putscan(KDev * f,uchar esc,uchar sc)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
repeatproc(void * a)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
putmod(KDev * f,uchar mods,uchar omods,uchar mask,uchar esc,uchar sc)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
putkeys(KDev * f,uchar buf[],uchar obuf[],int n,uchar dk)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
kbdbusy(uchar * buf,int n)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
kbdwork(void * a)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
freekdev(void * a)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
kbstart(Dev * d,Ep * ep,Kin * in,void (* f)(void *),KDev * kd)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
usage(void)683 usage(void)
684 {
685 werrstr("usage: usb/kb [-bdkm] [-a n] [-N nb]");
686 return -1;
687 }
688
689 int
kbmain(Dev * d,int argc,char * argv[])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