xref: /plan9-contrib/sys/src/9k/386/kbd.c (revision 277b6efdcc262cd4d08d05822b6e10d78be9f0bc)
1 /*
2  * keyboard input
3  */
4 #include	"u.h"
5 #include	"../port/lib.h"
6 #include	"mem.h"
7 #include	"dat.h"
8 #include	"fns.h"
9 #include	"../port/error.h"
10 
11 #include	"io.h"
12 
13 enum {
14 	Data=		0x60,		/* data port */
15 
16 	Status=		0x64,		/* status port */
17 	 Inready=	0x01,		/*  input character ready */
18 	 Outbusy=	0x02,		/*  output busy */
19 	 Sysflag=	0x04,		/*  system flag */
20 	 Cmddata=	0x08,		/*  cmd==0, data==1 */
21 	 Inhibit=	0x10,		/*  keyboard/mouse inhibited */
22 	 Minready=	0x20,		/*  mouse character ready */
23 	 Rtimeout=	0x40,		/*  general timeout */
24 	 Parity=	0x80,
25 
26 	Cmd=		0x64,		/* command port (write only) */
27 
28 	Spec=		0xF800,		/* Unicode private space */
29 	PF=		Spec|0x20,	/* num pad function key */
30 	View=		Spec|0x00,	/* view (shift window up) */
31 	KF=		0xF000,		/* function key (begin Unicode private space) */
32 	Shift=		Spec|0x60,
33 	Break=		Spec|0x61,
34 	Ctrl=		Spec|0x62,
35 	Latin=		Spec|0x63,
36 	Caps=		Spec|0x64,
37 	Num=		Spec|0x65,
38 	Middle=		Spec|0x66,
39 	Altgr=		Spec|0x67,
40 	Kmouse=		Spec|0x100,
41 	No=		0x00,		/* peter */
42 
43 	Home=		KF|13,
44 	Up=		KF|14,
45 	Pgup=		KF|15,
46 	Print=		KF|16,
47 	Left=		KF|17,
48 	Right=		KF|18,
49 	End=		KF|24,
50 	Down=		View,
51 	Pgdown=		KF|19,
52 	Ins=		KF|20,
53 	Del=		0x7F,
54 	Scroll=		KF|21,
55 
56 	Nscan=	128,
57 
58 	Int=	0,			/* kbscans indices */
59 	Ext,
60 	Nscans,
61 };
62 
63 /*
64  * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
65  * A 'standard' keyboard doesn't produce anything above 0x58.
66  */
67 Rune kbtab[Nscan] =
68 {
69 [0x00]	No,	0x1b,	'1',	'2',	'3',	'4',	'5',	'6',
70 [0x08]	'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
71 [0x10]	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
72 [0x18]	'o',	'p',	'[',	']',	'\n',	Ctrl,	'a',	's',
73 [0x20]	'd',	'f',	'g',	'h',	'j',	'k',	'l',	';',
74 [0x28]	'\'',	'`',	Shift,	'\\',	'z',	'x',	'c',	'v',
75 [0x30]	'b',	'n',	'm',	',',	'.',	'/',	Shift,	'*',
76 [0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
77 [0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
78 [0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
79 [0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
80 [0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
81 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
82 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
83 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
84 [0x78]	No,	View,	No,	Up,	No,	No,	No,	No,
85 };
86 
87 Rune kbtabshift[Nscan] =
88 {
89 [0x00]	No,	0x1b,	'!',	'@',	'#',	'$',	'%',	'^',
90 [0x08]	'&',	'*',	'(',	')',	'_',	'+',	'\b',	'\t',
91 [0x10]	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I',
92 [0x18]	'O',	'P',	'{',	'}',	'\n',	Ctrl,	'A',	'S',
93 [0x20]	'D',	'F',	'G',	'H',	'J',	'K',	'L',	':',
94 [0x28]	'"',	'~',	Shift,	'|',	'Z',	'X',	'C',	'V',
95 [0x30]	'B',	'N',	'M',	'<',	'>',	'?',	Shift,	'*',
96 [0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
97 [0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
98 [0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
99 [0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
100 [0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
101 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
102 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
103 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
104 [0x78]	No,	Up,	No,	Up,	No,	No,	No,	No,
105 };
106 
107 Rune kbtabesc1[Nscan] =
108 {
109 [0x00]	No,	No,	No,	No,	No,	No,	No,	No,
110 [0x08]	No,	No,	No,	No,	No,	No,	No,	No,
111 [0x10]	No,	No,	No,	No,	No,	No,	No,	No,
112 [0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
113 [0x20]	No,	No,	No,	No,	No,	No,	No,	No,
114 [0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
115 [0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
116 [0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
117 [0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
118 [0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
119 [0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
120 [0x58]	No,	No,	No,	No,	No,	No,	No,	No,
121 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
122 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
123 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
124 [0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
125 };
126 
127 Rune kbtabaltgr[Nscan] =
128 {
129 [0x00]	No,	No,	No,	No,	No,	No,	No,	No,
130 [0x08]	No,	No,	No,	No,	No,	No,	No,	No,
131 [0x10]	No,	No,	No,	No,	No,	No,	No,	No,
132 [0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
133 [0x20]	No,	No,	No,	No,	No,	No,	No,	No,
134 [0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
135 [0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
136 [0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
137 [0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
138 [0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
139 [0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
140 [0x58]	No,	No,	No,	No,	No,	No,	No,	No,
141 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
142 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
143 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
144 [0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
145 };
146 
147 Rune kbtabctrl[Nscan] =
148 {
149 [0x00]	No,	'', 	'', 	'', 	'', 	'', 	'', 	'',
150 [0x08]	'', 	'', 	'', 	'', 	'
151 ', 	'', 	'\b',	'\t',
152 [0x10]	'', 	'', 	'', 	'', 	'', 	'', 	'', 	'\t',
153 [0x18]	'', 	'', 	'', 	'', 	'\n',	Ctrl,	'', 	'',
154 [0x20]	'', 	'', 	'', 	'\b',	'\n',	'', 	'', 	'',
155 [0x28]	'', 	No, 	Shift,	'', 	'', 	'', 	'', 	'',
156 [0x30]	'', 	'', 	'
157 ', 	'', 	'', 	'', 	Shift,	'\n',
158 [0x38]	Latin,	No, 	Ctrl,	'', 	'', 	'', 	'', 	'',
159 [0x40]	'', 	'', 	'', 	'
160 ', 	'', 	'', 	'', 	'',
161 [0x48]	'', 	'', 	'
162 ', 	'', 	'', 	'', 	'', 	'',
163 [0x50]	'', 	'', 	'', 	'', 	No,	No,	No,	'',
164 [0x58]	'', 	No,	No,	No,	No,	No,	No,	No,
165 [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
166 [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
167 [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
168 [0x78]	No,	'', 	No,	'\b',	No,	No,	No,	No,
169 };
170 
171 enum
172 {
173 	/* controller command byte */
174 	Cscs1=		(1<<6),		/* scan code set 1 */
175 	Cauxdis=	(1<<5),		/* mouse disable */
176 	Ckbddis=	(1<<4),		/* kbd disable */
177 	Csf=		(1<<2),		/* system flag */
178 	Cauxint=	(1<<1),		/* mouse interrupt enable */
179 	Ckbdint=	(1<<0),		/* kbd interrupt enable */
180 };
181 
182 static Queue *kbdq;
183 
184 int mouseshifted;
185 void (*kbdmouse)(int);
186 
187 static Lock i8042lock;
188 static uchar ccc;
189 static void (*auxputc)(int, int);
190 static int nokbd = 1;			/* flag: no PS/2 keyboard */
191 
outready(void)192 /*
193  *  wait for output no longer busy
194  */
195 static int
196 outready(void)
197 {
198 	int tries;
199 
200 	for(tries = 0; (inb(Status) & Outbusy); tries++){
201 		if(tries > 500)
202 			return -1;
203 		delay(2);
204 	}
205 	return 0;
206 }
207 
inready(void)208 /*
209  *  wait for input
210  */
211 static int
212 inready(void)
213 {
214 	int tries;
215 
216 	for(tries = 0; !(inb(Status) & Inready); tries++){
217 		if(tries > 500)
218 			return -1;
219 		delay(2);
220 	}
221 	return 0;
222 }
223 
i8042a20(void)224 /*
225  *  ask 8042 to enable the use of address bit 20
226  */
227 void
228 i8042a20(void)
229 {
230 	outready();
231 	outb(Cmd, 0xD1);
232 	outready();
233 	outb(Data, 0xDF);
234 	outready();
235 }
236 
i8042reset(void)237 /*
238  *  ask 8042 to reset the machine
239  */
240 void
241 i8042reset(void)
242 {
243 	int i, x;
244 
245 	if(nokbd)
246 		return;
247 
248 	*((ushort*)KADDR(0x472)) = 0x1234;	/* BIOS warm-boot flag */
249 
250 	/*
251 	 *  newer reset the machine command
252 	 */
253 	outready();
254 	outb(Cmd, 0xFE);
255 	outready();
256 
257 	/*
258 	 *  Pulse it by hand (old somewhat reliable)
259 	 */
260 	x = 0xDF;
261 	for(i = 0; i < 5; i++){
262 		x ^= 1;
263 		outready();
264 		outb(Cmd, 0xD1);
265 		outready();
266 		outb(Data, x);	/* toggle reset */
267 		delay(100);
268 	}
269 }
270 
271 int
272 i8042auxcmd(int cmd)
273 {
274 	unsigned int c;
275 	int tries;
276 	static int badkbd;
277 
278 	if(badkbd)
279 		return -1;
280 	c = 0;
281 	tries = 0;
282 
283 	ilock(&i8042lock);
284 	do{
285 		if(tries++ > 2)
286 			break;
287 		if(outready() < 0)
288 			break;
289 		outb(Cmd, 0xD4);
290 		if(outready() < 0)
291 			break;
292 		outb(Data, cmd);
293 		if(outready() < 0)
294 			break;
295 		if(inready() < 0)
296 			break;
297 		c = inb(Data);
298 	} while(c == 0xFE || c == 0);
299 	iunlock(&i8042lock);
300 
301 	if(c != 0xFA){
302 		print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
303 		badkbd = 1;	/* don't keep trying; there might not be one */
304 		return -1;
305 	}
i8042auxcmds(uchar * cmd,int ncmd)306 	return 0;
307 }
308 
309 int
310 i8042auxcmds(uchar *cmd, int ncmd)
311 {
312 	int i;
313 
314 	ilock(&i8042lock);
315 	for(i=0; i<ncmd; i++){
316 		if(outready() < 0)
317 			break;
318 		outb(Cmd, 0xD4);
319 		if(outready() < 0)
320 			break;
321 		outb(Data, cmd[i]);
322 	}
323 	iunlock(&i8042lock);
324 	return i;
325 }
326 
327 typedef struct Kbscan Kbscan;
328 struct Kbscan {
329 	int	esc1;
330 	int	esc2;
331 	int	alt;
332 	int	altgr;
333 	int	caps;
334 	int	ctl;
335 	int	num;
336 	int	shift;
337 	int	collecting;
338 	int	nk;
339 	Rune	kc[5];
340 	int	buttons;
341 };
342 
343 Kbscan kbscans[Nscans];	/* kernel and external scan code state */
344 
345 static int kdebug;
346 
347 /*
348  * set keyboard's leds for lock states (scroll, numeric, caps).
349  *
350  * at least one keyboard (from Qtronics) also sets its numeric-lock
351  * behaviour to match the led state, though it has no numeric keypad,
352  * and some BIOSes bring the system up with numeric-lock set and no
353  * setting to change that.  this combination steals the keys for these
setleds(Kbscan * kbscan)354  * characters and makes it impossible to generate them: uiolkjm&*().
355  * thus we'd like to be able to force the numeric-lock led (and behaviour) off.
356  */
357 static void
358 setleds(Kbscan *kbscan)
359 {
360 	int leds;
361 
362 	if(nokbd || kbscan != &kbscans[Int])
363 		return;
364 	leds = 0;
365 	if(kbscan->num)
366 		leds |= 1<<1;
367 	if(0 && kbscan->caps)		/* we don't implement caps lock */
368 		leds |= 1<<2;
369 
370 	ilock(&i8042lock);
371 	outready();
372 	outb(Data, 0xed);		/* `reset keyboard lock states' */
373 	if(inready() == 0)
374 		inb(Data);
375 
376 	outready();
377 	outb(Data, leds);
378 	if(inready() == 0)
379 		inb(Data);
380 
381 	outready();
382 	iunlock(&i8042lock);
383 }
384 
kbdputsc(int c,int external)385 /*
386  * Scan code processing
387  */
388 void
389 kbdputsc(int c, int external)
390 {
391 	int i, keyup;
392 	Kbscan *kbscan;
393 
394 	if(external)
395 		kbscan = &kbscans[Ext];
396 	else
397 		kbscan = &kbscans[Int];
398 
399 	if(kdebug)
400 		print("sc %x ms %d\n", c, mouseshifted);
401 	/*
402 	 *  e0's is the first of a 2 character sequence, e1 the first
403 	 *  of a 3 character sequence (on the safari)
404 	 */
405 	if(c == 0xe0){
406 		kbscan->esc1 = 1;
407 		return;
408 	} else if(c == 0xe1){
409 		kbscan->esc2 = 2;
410 		return;
411 	}
412 
413 	keyup = c & 0x80;
414 	c &= 0x7f;
415 	if(c > sizeof kbtab){
416 		c |= keyup;
417 		if(c != 0xFF)	/* these come fairly often: CAPSLOCK U Y */
418 			print("unknown key %ux\n", c);
419 		return;
420 	}
421 
422 	if(kbscan->esc1){
423 		c = kbtabesc1[c];
424 		kbscan->esc1 = 0;
425 	} else if(kbscan->esc2){
426 		kbscan->esc2--;
427 		return;
428 	} else if(kbscan->shift)
429 		c = kbtabshift[c];
430 	else if(kbscan->altgr)
431 		c = kbtabaltgr[c];
432 	else if(kbscan->ctl)
433 		c = kbtabctrl[c];
434 	else
435 		c = kbtab[c];
436 
437 	if(kbscan->caps && c<='z' && c>='a')
438 		c += 'A' - 'a';
439 
440 	/*
441 	 *  keyup only important for shifts
442 	 */
443 	if(keyup){
444 		switch(c){
445 		case Latin:
446 			kbscan->alt = 0;
447 			break;
448 		case Shift:
449 			kbscan->shift = 0;
450 			mouseshifted = 0;
451 			if(kdebug)
452 				print("shiftclr\n");
453 			break;
454 		case Ctrl:
455 			kbscan->ctl = 0;
456 			break;
457 		case Altgr:
458 			kbscan->altgr = 0;
459 			break;
460 		case Kmouse|1:
461 		case Kmouse|2:
462 		case Kmouse|3:
463 		case Kmouse|4:
464 		case Kmouse|5:
465 			kbscan->buttons &= ~(1<<(c-Kmouse-1));
466 			if(kbdmouse)
467 				kbdmouse(kbscan->buttons);
468 			break;
469 		}
470 		return;
471 	}
472 
473 	/*
474 	 *  normal character
475 	 */
476 	if(!(c & (Spec|KF))){
477 		if(kbscan->ctl)
478 			if(kbscan->alt && c == Del)
479 				exit(0);
480 		if(!kbscan->collecting){
481 			kbdputc(kbdq, c);
482 			return;
483 		}
484 		kbscan->kc[kbscan->nk++] = c;
485 		c = latin1(kbscan->kc, kbscan->nk);
486 		if(c < -1)	/* need more keystrokes */
487 			return;
488 		if(c != -1)	/* valid sequence */
489 			kbdputc(kbdq, c);
490 		else	/* dump characters */
491 			for(i=0; i<kbscan->nk; i++)
492 				kbdputc(kbdq, kbscan->kc[i]);
493 		kbscan->nk = 0;
494 		kbscan->collecting = 0;
495 		return;
496 	} else {
497 		switch(c){
498 		case Caps:
499 			kbscan->caps ^= 1;
500 			return;
501 		case Num:
502 			kbscan->num ^= 1;
503 			if(!external)
504 				setleds(kbscan);
505 			return;
506 		case Shift:
507 			kbscan->shift = 1;
508 			if(kdebug)
509 				print("shift\n");
510 			mouseshifted = 1;
511 			return;
512 		case Latin:
513 			kbscan->alt = 1;
514 			/*
515 			 * VMware and Qemu use Ctl-Alt as the key combination
516 			 * to make the VM give up keyboard and mouse focus.
517 			 * This has the unfortunate side effect that when you
518 			 * come back into focus, Plan 9 thinks you want to type
519 			 * a compose sequence (you just typed alt).
520 			 *
521 			 * As a clumsy hack around this, we look for ctl-alt
522 			 * and don't treat it as the start of a compose sequence.
523 			 */
524 			if(!kbscan->ctl){
525 				kbscan->collecting = 1;
526 				kbscan->nk = 0;
527 			}
528 			return;
529 		case Ctrl:
530 			kbscan->ctl = 1;
531 			return;
532 		case Altgr:
533 			kbscan->altgr = 1;
534 			return;
535 		case Kmouse|1:
536 		case Kmouse|2:
537 		case Kmouse|3:
538 		case Kmouse|4:
539 		case Kmouse|5:
540 			kbscan->buttons |= 1<<(c-Kmouse-1);
541 			if(kbdmouse)
542 				kbdmouse(kbscan->buttons);
543 			return;
544 		case KF|11:
545 			print("kbd debug on, F12 turns it off\n");
546 			kdebug = 1;
547 			break;
548 		case KF|12:
549 			kdebug = 0;
550 			break;
551 		}
552 	}
553 	kbdputc(kbdq, c);
554 }
555 
i8042intr(Ureg *,void *)556 /*
557  *  keyboard interrupt
558  */
559 static void
560 i8042intr(Ureg*, void*)
561 {
562 	int s, c;
563 
564 	/*
565 	 *  get status
566 	 */
567 	ilock(&i8042lock);
568 	s = inb(Status);
569 	if(!(s&Inready)){
570 		iunlock(&i8042lock);
571 		return;
572 	}
573 
574 	/*
575 	 *  get the character
576 	 */
577 	c = inb(Data);
578 	iunlock(&i8042lock);
579 
580 	/*
581 	 *  if it's the aux port...
582 	 */
583 	if(s & Minready){
584 		if(auxputc != nil)
585 			auxputc(c, kbscans[Int].shift);
586 		return;
587 	}
588 
589 	kbdputsc(c, Int);
590 }
591 
592 void
593 i8042auxenable(void (*putc)(int, int))
594 {
595 	char *err = "i8042: aux init failed\n";
596 
597 	/* enable kbd/aux xfers and interrupts */
598 	ccc &= ~Cauxdis;
599 	ccc |= Cauxint;
600 
601 	ilock(&i8042lock);
602 	if(outready() < 0)
603 		print(err);
604 	outb(Cmd, 0x60);			/* write control register */
605 	if(outready() < 0)
606 		print(err);
607 	outb(Data, ccc);
608 	if(outready() < 0)
609 		print(err);
610 	outb(Cmd, 0xA8);			/* auxiliary device enable */
611 	if(outready() < 0){
612 		iunlock(&i8042lock);
613 		return;
614 	}
615 	auxputc = putc;
616 	intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
617 	iunlock(&i8042lock);
618 }
outbyte(int port,int c)619 
620 static char *initfailed = "i8042: kbdinit failed\n";
621 
622 static int
623 outbyte(int port, int c)
624 {
625 	outb(port, c);
626 	if(outready() < 0) {
627 		print(initfailed);
628 		return -1;
629 	}
kbdinit(void)630 	return 0;
631 }
632 
633 void
634 kbdinit(void)
635 {
636 	int c, try;
637 
638 	/* wait for a quiescent controller */
639 	try = 500;
640 	while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
641 		if(c & Inready)
642 			inb(Data);
643 		delay(1);
644 	}
645 	if (try <= 0) {
646 		print(initfailed);
647 		return;
648 	}
649 
650 	/* get current controller command byte */
651 	outb(Cmd, 0x20);
652 	if(inready() < 0){
653 		print("i8042: kbdinit can't read ccc\n");
654 		ccc = 0;
655 	} else
656 		ccc = inb(Data);
657 
658 	/* enable kbd xfers and interrupts */
659 	ccc &= ~Ckbddis;
660 	ccc |= Csf | Ckbdint | Cscs1;
661 	if(outready() < 0) {
662 		print(initfailed);
663 		return;
664 	}
665 
666 	nokbd = 0;
667 
668 	/* disable mouse */
669 	if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0)
670 		print("i8042: kbdinit mouse disable failed\n");
671 
672 	/* see http://www.computer-engineering.org/ps2keyboard for codes */
673 	if(getconf("*typematic") != nil)
674 		/* set typematic rate/delay (0 -> delay=250ms & rate=30cps) */
675 		if(outbyte(Data, 0xf3) < 0 || outbyte(Data, 0) < 0)
kbdenable(void)676 			print("i8042: kbdinit set typematic rate failed\n");
677 }
678 
679 void
680 kbdenable(void)
681 {
682 	kbdq = qopen(4*1024, 0, 0, 0);
683 	if(kbdq == nil)
684 		panic("kbdinit");
685 	qnoblock(kbdq, 1);
686 	addkbdq(kbdq, -1);
687 
688 	ioalloc(Data, 1, 0, "kbd");
689 	ioalloc(Cmd, 1, 0, "kbd");
690 
691 	intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
692 
693 	kbscans[Int].num = 0;
kbdputmap(ushort m,ushort scanc,Rune r)694 	setleds(&kbscans[Int]);
695 }
696 
697 void
698 kbdputmap(ushort m, ushort scanc, Rune r)
699 {
700 	if(scanc >= Nscan)
701 		error(Ebadarg);
702 	switch(m) {
703 	default:
704 		error(Ebadarg);
705 	case 0:
706 		kbtab[scanc] = r;
707 		break;
708 	case 1:
709 		kbtabshift[scanc] = r;
710 		break;
711 	case 2:
712 		kbtabesc1[scanc] = r;
713 		break;
714 	case 3:
715 		kbtabaltgr[scanc] = r;
716 		break;
717 	case 4:
718 		kbtabctrl[scanc] = r;
719 		break;
kbdgetmap(uint offset,int * t,int * sc,Rune * r)720 	}
721 }
722 
723 int
724 kbdgetmap(uint offset, int *t, int *sc, Rune *r)
725 {
726 	if ((int)offset < 0)
727 		error(Ebadarg);
728 	*t = offset/Nscan;
729 	*sc = offset%Nscan;
730 	switch(*t) {
731 	default:
732 		return 0;
733 	case 0:
734 		*r = kbtab[*sc];
735 		return 1;
736 	case 1:
737 		*r = kbtabshift[*sc];
738 		return 1;
739 	case 2:
740 		*r = kbtabesc1[*sc];
741 		return 1;
742 	case 3:
743 		*r = kbtabaltgr[*sc];
744 		return 1;
745 	case 4:
746 		*r = kbtabctrl[*sc];
747 		return 1;
748 	}
749 }
750