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