xref: /plan9-contrib/sys/src/cmd/usb/kb/kb.c (revision 0cc6832d7c845a6250c7353daab06d4af2dfe5cb)
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