Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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 |= 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
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
}