xref: /plan9/sys/src/9/pc/kbd.c (revision 9a3e01025d6e8ffdbc1c812cb07a5cbab081e107)
19c1d3970SDavid du Colombier /*
29c1d3970SDavid du Colombier  * keyboard input
39c1d3970SDavid du Colombier  */
43e12c5d1SDavid du Colombier #include	"u.h"
53e12c5d1SDavid du Colombier #include	"../port/lib.h"
63e12c5d1SDavid du Colombier #include	"mem.h"
73e12c5d1SDavid du Colombier #include	"dat.h"
83e12c5d1SDavid du Colombier #include	"fns.h"
93e12c5d1SDavid du Colombier #include	"io.h"
10bd389b36SDavid du Colombier #include	"../port/error.h"
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier enum {
133e12c5d1SDavid du Colombier 	Data=		0x60,		/* data port */
143e12c5d1SDavid du Colombier 
153e12c5d1SDavid du Colombier 	Status=		0x64,		/* status port */
163e12c5d1SDavid du Colombier 	 Inready=	0x01,		/*  input character ready */
173e12c5d1SDavid du Colombier 	 Outbusy=	0x02,		/*  output busy */
183e12c5d1SDavid du Colombier 	 Sysflag=	0x04,		/*  system flag */
193e12c5d1SDavid du Colombier 	 Cmddata=	0x08,		/*  cmd==0, data==1 */
203e12c5d1SDavid du Colombier 	 Inhibit=	0x10,		/*  keyboard/mouse inhibited */
213e12c5d1SDavid du Colombier 	 Minready=	0x20,		/*  mouse character ready */
223e12c5d1SDavid du Colombier 	 Rtimeout=	0x40,		/*  general timeout */
233e12c5d1SDavid du Colombier 	 Parity=	0x80,
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier 	Cmd=		0x64,		/* command port (write only) */
263e12c5d1SDavid du Colombier 
27c49c9d4eSDavid du Colombier 	Spec=		0xF800,		/* Unicode private space */
283e12c5d1SDavid du Colombier 	PF=		Spec|0x20,	/* num pad function key */
293e12c5d1SDavid du Colombier 	View=		Spec|0x00,	/* view (shift window up) */
307dd7cddfSDavid du Colombier 	KF=		0xF000,		/* function key (begin Unicode private space) */
313e12c5d1SDavid du Colombier 	Shift=		Spec|0x60,
323e12c5d1SDavid du Colombier 	Break=		Spec|0x61,
333e12c5d1SDavid du Colombier 	Ctrl=		Spec|0x62,
343e12c5d1SDavid du Colombier 	Latin=		Spec|0x63,
353e12c5d1SDavid du Colombier 	Caps=		Spec|0x64,
363e12c5d1SDavid du Colombier 	Num=		Spec|0x65,
373e12c5d1SDavid du Colombier 	Middle=		Spec|0x66,
383901e6d0SDavid du Colombier 	Altgr=		Spec|0x67,
39e29df7b0SDavid du Colombier 	Kmouse=		Spec|0x100,
403e12c5d1SDavid du Colombier 	No=		0x00,		/* peter */
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier 	Home=		KF|13,
433e12c5d1SDavid du Colombier 	Up=		KF|14,
443e12c5d1SDavid du Colombier 	Pgup=		KF|15,
453e12c5d1SDavid du Colombier 	Print=		KF|16,
467dd7cddfSDavid du Colombier 	Left=		KF|17,
477dd7cddfSDavid du Colombier 	Right=		KF|18,
48651dbb72SDavid du Colombier 	End=		KF|24,
493e12c5d1SDavid du Colombier 	Down=		View,
507dd7cddfSDavid du Colombier 	Pgdown=		KF|19,
513e12c5d1SDavid du Colombier 	Ins=		KF|20,
523e12c5d1SDavid du Colombier 	Del=		0x7F,
537dd7cddfSDavid du Colombier 	Scroll=		KF|21,
543901e6d0SDavid du Colombier 
553901e6d0SDavid du Colombier 	Nscan=	128,
56d5b6fab5SDavid du Colombier 
57d5b6fab5SDavid du Colombier 	Int=	0,			/* kbscans indices */
58d5b6fab5SDavid du Colombier 	Ext,
59d5b6fab5SDavid du Colombier 	Nscans,
603e12c5d1SDavid du Colombier };
613e12c5d1SDavid du Colombier 
627dd7cddfSDavid du Colombier /*
6326d1d1dfSDavid du Colombier  * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
647dd7cddfSDavid du Colombier  * A 'standard' keyboard doesn't produce anything above 0x58.
657dd7cddfSDavid du Colombier  */
663901e6d0SDavid du Colombier Rune kbtab[Nscan] =
673e12c5d1SDavid du Colombier {
683e12c5d1SDavid du Colombier [0x00]	No,	0x1b,	'1',	'2',	'3',	'4',	'5',	'6',
693e12c5d1SDavid du Colombier [0x08]	'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
703e12c5d1SDavid du Colombier [0x10]	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
713e12c5d1SDavid du Colombier [0x18]	'o',	'p',	'[',	']',	'\n',	Ctrl,	'a',	's',
723e12c5d1SDavid du Colombier [0x20]	'd',	'f',	'g',	'h',	'j',	'k',	'l',	';',
733e12c5d1SDavid du Colombier [0x28]	'\'',	'`',	Shift,	'\\',	'z',	'x',	'c',	'v',
743e12c5d1SDavid du Colombier [0x30]	'b',	'n',	'm',	',',	'.',	'/',	Shift,	'*',
753e12c5d1SDavid du Colombier [0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
767dd7cddfSDavid du Colombier [0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
773e12c5d1SDavid du Colombier [0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
787dd7cddfSDavid du Colombier [0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
793e12c5d1SDavid du Colombier [0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
807dd7cddfSDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
817dd7cddfSDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
827dd7cddfSDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
837dd7cddfSDavid du Colombier [0x78]	No,	View,	No,	Up,	No,	No,	No,	No,
843e12c5d1SDavid du Colombier };
853e12c5d1SDavid du Colombier 
863901e6d0SDavid du Colombier Rune kbtabshift[Nscan] =
873e12c5d1SDavid du Colombier {
883e12c5d1SDavid du Colombier [0x00]	No,	0x1b,	'!',	'@',	'#',	'$',	'%',	'^',
893e12c5d1SDavid du Colombier [0x08]	'&',	'*',	'(',	')',	'_',	'+',	'\b',	'\t',
903e12c5d1SDavid du Colombier [0x10]	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I',
913e12c5d1SDavid du Colombier [0x18]	'O',	'P',	'{',	'}',	'\n',	Ctrl,	'A',	'S',
923e12c5d1SDavid du Colombier [0x20]	'D',	'F',	'G',	'H',	'J',	'K',	'L',	':',
933e12c5d1SDavid du Colombier [0x28]	'"',	'~',	Shift,	'|',	'Z',	'X',	'C',	'V',
943e12c5d1SDavid du Colombier [0x30]	'B',	'N',	'M',	'<',	'>',	'?',	Shift,	'*',
953e12c5d1SDavid du Colombier [0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
967dd7cddfSDavid du Colombier [0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
973e12c5d1SDavid du Colombier [0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
983e12c5d1SDavid du Colombier [0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
993e12c5d1SDavid du Colombier [0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
1007dd7cddfSDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
1017dd7cddfSDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
1027dd7cddfSDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
1037dd7cddfSDavid du Colombier [0x78]	No,	Up,	No,	Up,	No,	No,	No,	No,
1043e12c5d1SDavid du Colombier };
1053e12c5d1SDavid du Colombier 
1063901e6d0SDavid du Colombier Rune kbtabesc1[Nscan] =
1073e12c5d1SDavid du Colombier {
1083e12c5d1SDavid du Colombier [0x00]	No,	No,	No,	No,	No,	No,	No,	No,
1093e12c5d1SDavid du Colombier [0x08]	No,	No,	No,	No,	No,	No,	No,	No,
1103e12c5d1SDavid du Colombier [0x10]	No,	No,	No,	No,	No,	No,	No,	No,
1113e12c5d1SDavid du Colombier [0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
1123e12c5d1SDavid du Colombier [0x20]	No,	No,	No,	No,	No,	No,	No,	No,
1133e12c5d1SDavid du Colombier [0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
1143e12c5d1SDavid du Colombier [0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
1153901e6d0SDavid du Colombier [0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
1163e12c5d1SDavid du Colombier [0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
1173e12c5d1SDavid du Colombier [0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
1183e12c5d1SDavid du Colombier [0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
1193e12c5d1SDavid du Colombier [0x58]	No,	No,	No,	No,	No,	No,	No,	No,
1207dd7cddfSDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
1217dd7cddfSDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
1227dd7cddfSDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
1237dd7cddfSDavid du Colombier [0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
1243e12c5d1SDavid du Colombier };
1253e12c5d1SDavid du Colombier 
1263901e6d0SDavid du Colombier Rune kbtabaltgr[Nscan] =
1273901e6d0SDavid du Colombier {
1283901e6d0SDavid du Colombier [0x00]	No,	No,	No,	No,	No,	No,	No,	No,
1293901e6d0SDavid du Colombier [0x08]	No,	No,	No,	No,	No,	No,	No,	No,
1303901e6d0SDavid du Colombier [0x10]	No,	No,	No,	No,	No,	No,	No,	No,
131c49c9d4eSDavid du Colombier [0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
1323901e6d0SDavid du Colombier [0x20]	No,	No,	No,	No,	No,	No,	No,	No,
133c49c9d4eSDavid du Colombier [0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
134c49c9d4eSDavid du Colombier [0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
135c49c9d4eSDavid du Colombier [0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
136c49c9d4eSDavid du Colombier [0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
137c49c9d4eSDavid du Colombier [0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
138c49c9d4eSDavid du Colombier [0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
1393901e6d0SDavid du Colombier [0x58]	No,	No,	No,	No,	No,	No,	No,	No,
1403901e6d0SDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
1413901e6d0SDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
1423901e6d0SDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
1433901e6d0SDavid du Colombier [0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
1443901e6d0SDavid du Colombier };
1453901e6d0SDavid du Colombier 
14683030dd5SDavid du Colombier Rune kbtabctrl[Nscan] =
1473901e6d0SDavid du Colombier {
1483901e6d0SDavid du Colombier [0x00]	No,	'', 	'', 	'', 	'', 	'', 	'', 	'',
1493901e6d0SDavid du Colombier [0x08]	'', 	'', 	'', 	'', 	'
1503901e6d0SDavid du Colombier ', 	'', 	'\b',	'\t',
1513901e6d0SDavid du Colombier [0x10]	'', 	'', 	'', 	'', 	'', 	'', 	'', 	'\t',
1523901e6d0SDavid du Colombier [0x18]	'', 	'', 	'', 	'', 	'\n',	Ctrl,	'', 	'',
1533901e6d0SDavid du Colombier [0x20]	'', 	'', 	'', 	'\b',	'\n',	'', 	'', 	'',
1543901e6d0SDavid du Colombier [0x28]	'', 	No, 	Shift,	'', 	'', 	'', 	'', 	'',
1553901e6d0SDavid du Colombier [0x30]	'', 	'', 	'
1563901e6d0SDavid du Colombier ', 	'', 	'', 	'', 	Shift,	'\n',
1573901e6d0SDavid du Colombier [0x38]	Latin,	No, 	Ctrl,	'', 	'', 	'', 	'', 	'',
1583901e6d0SDavid du Colombier [0x40]	'', 	'', 	'', 	'
1593901e6d0SDavid du Colombier ', 	'', 	'', 	'', 	'',
1603901e6d0SDavid du Colombier [0x48]	'', 	'', 	'
1613901e6d0SDavid du Colombier ', 	'', 	'', 	'', 	'', 	'',
1623901e6d0SDavid du Colombier [0x50]	'', 	'', 	'', 	'', 	No,	No,	No,	'',
1633901e6d0SDavid du Colombier [0x58]	'', 	No,	No,	No,	No,	No,	No,	No,
1643901e6d0SDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
1653901e6d0SDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
1663e12c5d1SDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
1673e12c5d1SDavid du Colombier [0x78]	No,	'', 	No,	'\b',	No,	No,	No,	No,
168bd389b36SDavid du Colombier };
169bd389b36SDavid du Colombier 
1707dd7cddfSDavid du Colombier enum
171bd389b36SDavid du Colombier {
172bd389b36SDavid du Colombier 	/* controller command byte */
1737dd7cddfSDavid du Colombier 	Cscs1=		(1<<6),		/* scan code set 1 */
174bd389b36SDavid du Colombier 	Cauxdis=	(1<<5),		/* mouse disable */
1753e12c5d1SDavid du Colombier 	Ckbddis=	(1<<4),		/* kbd disable */
176bd389b36SDavid du Colombier 	Csf=		(1<<2),		/* system flag */
1773ff48bf5SDavid du Colombier 	Cauxint=	(1<<1),		/* mouse interrupt enable */
1783039af76SDavid du Colombier 	Ckbdint=	(1<<0),		/* kbd interrupt enable */
1793ff48bf5SDavid du Colombier };
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier int mouseshifted;
1827dd7cddfSDavid du Colombier void (*kbdmouse)(int);
183d5b6fab5SDavid du Colombier 
1843e12c5d1SDavid du Colombier static Lock i8042lock;
1853e12c5d1SDavid du Colombier static uchar ccc;
1863e12c5d1SDavid du Colombier static void (*auxputc)(int, int);
1873e12c5d1SDavid du Colombier static int nokbd = 1;			/* flag: no PS/2 keyboard */
1883e12c5d1SDavid du Colombier 
outready(void)1893e12c5d1SDavid du Colombier /*
1903e12c5d1SDavid du Colombier  *  wait for output no longer busy
1913e12c5d1SDavid du Colombier  */
1923e12c5d1SDavid du Colombier static int
193bd389b36SDavid du Colombier outready(void)
194bd389b36SDavid du Colombier {
1953e12c5d1SDavid du Colombier 	int tries;
196bd389b36SDavid du Colombier 
197bd389b36SDavid du Colombier 	for(tries = 0; (inb(Status) & Outbusy); tries++){
1983e12c5d1SDavid du Colombier 		if(tries > 500)
1993e12c5d1SDavid du Colombier 			return -1;
2003e12c5d1SDavid du Colombier 		delay(2);
2013e12c5d1SDavid du Colombier 	}
2023e12c5d1SDavid du Colombier 	return 0;
2033e12c5d1SDavid du Colombier }
2043e12c5d1SDavid du Colombier 
inready(void)2053e12c5d1SDavid du Colombier /*
2063e12c5d1SDavid du Colombier  *  wait for input
2073e12c5d1SDavid du Colombier  */
2083e12c5d1SDavid du Colombier static int
209bd389b36SDavid du Colombier inready(void)
210bd389b36SDavid du Colombier {
2113e12c5d1SDavid du Colombier 	int tries;
212bd389b36SDavid du Colombier 
213bd389b36SDavid du Colombier 	for(tries = 0; !(inb(Status) & Inready); tries++){
2143e12c5d1SDavid du Colombier 		if(tries > 500)
2153e12c5d1SDavid du Colombier 			return -1;
2163e12c5d1SDavid du Colombier 		delay(2);
2173e12c5d1SDavid du Colombier 	}
2181045bea1SDavid du Colombier 	return 0;
2191045bea1SDavid du Colombier }
2201045bea1SDavid du Colombier 
i8042a20(void)2211045bea1SDavid du Colombier /*
2221045bea1SDavid du Colombier  *  ask 8042 to enable the use of address bit 20
2231045bea1SDavid du Colombier  */
2241045bea1SDavid du Colombier void
2251045bea1SDavid du Colombier i8042a20(void)
2261045bea1SDavid du Colombier {
2271045bea1SDavid du Colombier 	outready();
2281045bea1SDavid du Colombier 	outb(Cmd, 0xD1);
2291045bea1SDavid du Colombier 	outready();
2301045bea1SDavid du Colombier 	outb(Data, 0xDF);
2313e12c5d1SDavid du Colombier 	outready();
2323e12c5d1SDavid du Colombier }
2333e12c5d1SDavid du Colombier 
i8042reset(void)2343e12c5d1SDavid du Colombier /*
2353e12c5d1SDavid du Colombier  *  ask 8042 to reset the machine
236219b2ee8SDavid du Colombier  */
237219b2ee8SDavid du Colombier void
238c3ca4b29SDavid du Colombier i8042reset(void)
239c3ca4b29SDavid du Colombier {
240c3ca4b29SDavid du Colombier 	int i, x;
241c3ca4b29SDavid du Colombier 
242219b2ee8SDavid du Colombier 	if(nokbd)
243bd389b36SDavid du Colombier 		return;
2447dd7cddfSDavid du Colombier 
245bd389b36SDavid du Colombier 	*((ushort*)KADDR(0x472)) = 0x1234;	/* BIOS warm-boot flag */
246bd389b36SDavid du Colombier 
2477dd7cddfSDavid du Colombier 	/*
248bd389b36SDavid du Colombier 	 *  newer reset the machine command
249219b2ee8SDavid du Colombier 	 */
250bd389b36SDavid du Colombier 	outready();
251219b2ee8SDavid du Colombier 	outb(Cmd, 0xFE);
252bd389b36SDavid du Colombier 	outready();
253219b2ee8SDavid du Colombier 
254219b2ee8SDavid du Colombier 	/*
255219b2ee8SDavid du Colombier 	 *  Pulse it by hand (old somewhat reliable)
2563e12c5d1SDavid du Colombier 	 */
2573e12c5d1SDavid du Colombier 	x = 0xDF;
2583e12c5d1SDavid du Colombier 	for(i = 0; i < 5; i++){
259219b2ee8SDavid du Colombier 		x ^= 1;
260219b2ee8SDavid du Colombier 		outready();
2613e12c5d1SDavid du Colombier 		outb(Cmd, 0xD1);
262219b2ee8SDavid du Colombier 		outready();
263219b2ee8SDavid du Colombier 		outb(Data, x);	/* toggle reset */
2647dd7cddfSDavid du Colombier 		delay(100);
2657dd7cddfSDavid du Colombier 	}
2663e12c5d1SDavid du Colombier }
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier int
2695acbe002SDavid du Colombier i8042auxcmd(int cmd)
2703e12c5d1SDavid du Colombier {
2715acbe002SDavid du Colombier 	unsigned int c;
2725acbe002SDavid du Colombier 	int tries;
2737dd7cddfSDavid du Colombier 	static int badkbd;
2747dd7cddfSDavid du Colombier 
2753e12c5d1SDavid du Colombier 	if(badkbd)
2767dd7cddfSDavid du Colombier 		return -1;
2777dd7cddfSDavid du Colombier 	c = 0;
2787dd7cddfSDavid du Colombier 	tries = 0;
2797dd7cddfSDavid du Colombier 
280bd389b36SDavid du Colombier 	ilock(&i8042lock);
2817dd7cddfSDavid du Colombier 	do{
2827dd7cddfSDavid du Colombier 		if(tries++ > 2)
2833e12c5d1SDavid du Colombier 			break;
2847dd7cddfSDavid du Colombier 		if(outready() < 0)
2857dd7cddfSDavid du Colombier 			break;
2867dd7cddfSDavid du Colombier 		outb(Cmd, 0xD4);
2877dd7cddfSDavid du Colombier 		if(outready() < 0)
2887dd7cddfSDavid du Colombier 			break;
2897dd7cddfSDavid du Colombier 		outb(Data, cmd);
2907dd7cddfSDavid du Colombier 		if(outready() < 0)
2917dd7cddfSDavid du Colombier 			break;
2927dd7cddfSDavid du Colombier 		if(inready() < 0)
2933e12c5d1SDavid du Colombier 			break;
2947dd7cddfSDavid du Colombier 		c = inb(Data);
2957dd7cddfSDavid du Colombier 	} while(c == 0xFE || c == 0);
2965acbe002SDavid du Colombier 	iunlock(&i8042lock);
297219b2ee8SDavid du Colombier 
2983e12c5d1SDavid du Colombier 	if(c != 0xFA){
299bd389b36SDavid du Colombier 		print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
300bd389b36SDavid du Colombier 		badkbd = 1;	/* don't keep trying; there might not be one */
301bd389b36SDavid du Colombier 		return -1;
3023ff48bf5SDavid du Colombier 	}
i8042auxcmds(uchar * cmd,int ncmd)3033ff48bf5SDavid du Colombier 	return 0;
3043ff48bf5SDavid du Colombier }
3053ff48bf5SDavid du Colombier 
3063ff48bf5SDavid du Colombier int
3073ff48bf5SDavid du Colombier i8042auxcmds(uchar *cmd, int ncmd)
3083ff48bf5SDavid du Colombier {
3093ff48bf5SDavid du Colombier 	int i;
3103ff48bf5SDavid du Colombier 
3113ff48bf5SDavid du Colombier 	ilock(&i8042lock);
3123ff48bf5SDavid du Colombier 	for(i=0; i<ncmd; i++){
3133ff48bf5SDavid du Colombier 		if(outready() < 0)
3143ff48bf5SDavid du Colombier 			break;
3153ff48bf5SDavid du Colombier 		outb(Cmd, 0xD4);
3163ff48bf5SDavid du Colombier 		if(outready() < 0)
3173ff48bf5SDavid du Colombier 			break;
3183ff48bf5SDavid du Colombier 		outb(Data, cmd[i]);
3193ff48bf5SDavid du Colombier 	}
3209c1d3970SDavid du Colombier 	iunlock(&i8042lock);
3219c1d3970SDavid du Colombier 	return i;
322e29df7b0SDavid du Colombier }
323e29df7b0SDavid du Colombier 
324e29df7b0SDavid du Colombier typedef struct Kbscan Kbscan;
325e29df7b0SDavid du Colombier struct Kbscan {
326e29df7b0SDavid du Colombier 	int	esc1;
327e29df7b0SDavid du Colombier 	int	esc2;
328e29df7b0SDavid du Colombier 	int	alt;
329e29df7b0SDavid du Colombier 	int	altgr;
330e29df7b0SDavid du Colombier 	int	caps;
331e29df7b0SDavid du Colombier 	int	ctl;
332e29df7b0SDavid du Colombier 	int	num;
3333039af76SDavid du Colombier 	int	shift;
3349c1d3970SDavid du Colombier 	int	collecting;
3359c1d3970SDavid du Colombier 	int	nk;
336d5b6fab5SDavid du Colombier 	Rune	kc[5];
337d5b6fab5SDavid du Colombier 	int	buttons;
33883030dd5SDavid du Colombier };
339d5b6fab5SDavid du Colombier 
340d5b6fab5SDavid du Colombier Kbscan kbscans[Nscans];	/* kernel and external scan code state */
341d5b6fab5SDavid du Colombier 
342d5b6fab5SDavid du Colombier static int kdebug;
343d5b6fab5SDavid du Colombier 
344d5b6fab5SDavid du Colombier /*
345d5b6fab5SDavid du Colombier  * set keyboard's leds for lock states (scroll, numeric, caps).
346d5b6fab5SDavid du Colombier  *
347d5b6fab5SDavid du Colombier  * at least one keyboard (from Qtronics) also sets its numeric-lock
348d5b6fab5SDavid du Colombier  * behaviour to match the led state, though it has no numeric keypad,
349d5b6fab5SDavid du Colombier  * and some BIOSes bring the system up with numeric-lock set and no
350d5b6fab5SDavid du Colombier  * setting to change that.  this combination steals the keys for these
setleds(Kbscan * kbscan)351d5b6fab5SDavid du Colombier  * characters and makes it impossible to generate them: uiolkjm&*().
352d5b6fab5SDavid du Colombier  * thus we'd like to be able to force the numeric-lock led (and behaviour) off.
353d5b6fab5SDavid du Colombier  */
354d5b6fab5SDavid du Colombier static void
355d5b6fab5SDavid du Colombier setleds(Kbscan *kbscan)
356d5b6fab5SDavid du Colombier {
357d5b6fab5SDavid du Colombier 	int leds;
358d5b6fab5SDavid du Colombier 
359d5b6fab5SDavid du Colombier 	if(nokbd || kbscan != &kbscans[Int])
360d5b6fab5SDavid du Colombier 		return;
361d5b6fab5SDavid du Colombier 	leds = 0;
36255a30970SDavid du Colombier 	if(kbscan->num)
363d5b6fab5SDavid du Colombier 		leds |= 1<<1;
364d5b6fab5SDavid du Colombier 	if(0 && kbscan->caps)		/* we don't implement caps lock */
365d5b6fab5SDavid du Colombier 		leds |= 1<<2;
36655a30970SDavid du Colombier 
36755a30970SDavid du Colombier 	ilock(&i8042lock);
36855a30970SDavid du Colombier 	outready();
369d5b6fab5SDavid du Colombier 	outb(Data, 0xed);		/* `reset keyboard lock states' */
370d5b6fab5SDavid du Colombier 	if(inready() == 0)
37155a30970SDavid du Colombier 		inb(Data);
37255a30970SDavid du Colombier 
37355a30970SDavid du Colombier 	outready();
374d5b6fab5SDavid du Colombier 	outb(Data, leds);
375d5b6fab5SDavid du Colombier 	if(inready() == 0)
376d5b6fab5SDavid du Colombier 		inb(Data);
377d5b6fab5SDavid du Colombier 
3789c1d3970SDavid du Colombier 	outready();
3799c1d3970SDavid du Colombier 	iunlock(&i8042lock);
3809c1d3970SDavid du Colombier }
3819c1d3970SDavid du Colombier 
kbdputsc(int c,int external)3829c1d3970SDavid du Colombier /*
3839c1d3970SDavid du Colombier  * Scan code processing
3849c1d3970SDavid du Colombier  */
3859c1d3970SDavid du Colombier void
3869c1d3970SDavid du Colombier kbdputsc(int c, int external)
3879c1d3970SDavid du Colombier {
388d5b6fab5SDavid du Colombier 	int i, keyup;
3899c1d3970SDavid du Colombier 	Kbscan *kbscan;
390d5b6fab5SDavid du Colombier 
3919c1d3970SDavid du Colombier 	if(external)
39283030dd5SDavid du Colombier 		kbscan = &kbscans[Ext];
39383030dd5SDavid du Colombier 	else
3949c1d3970SDavid du Colombier 		kbscan = &kbscans[Int];
3959c1d3970SDavid du Colombier 
3969c1d3970SDavid du Colombier 	if(kdebug)
3979c1d3970SDavid du Colombier 		print("sc %x ms %d\n", c, mouseshifted);
3989c1d3970SDavid du Colombier 	/*
3999c1d3970SDavid du Colombier 	 *  e0's is the first of a 2 character sequence, e1 the first
4009c1d3970SDavid du Colombier 	 *  of a 3 character sequence (on the safari)
4019c1d3970SDavid du Colombier 	 */
4029c1d3970SDavid du Colombier 	if(c == 0xe0){
4039c1d3970SDavid du Colombier 		kbscan->esc1 = 1;
4049c1d3970SDavid du Colombier 		return;
4059c1d3970SDavid du Colombier 	} else if(c == 0xe1){
4069c1d3970SDavid du Colombier 		kbscan->esc2 = 2;
4079c1d3970SDavid du Colombier 		return;
4089c1d3970SDavid du Colombier 	}
4099c1d3970SDavid du Colombier 
4109c1d3970SDavid du Colombier 	keyup = c & 0x80;
4119c1d3970SDavid du Colombier 	c &= 0x7f;
4129c1d3970SDavid du Colombier 	if(c > sizeof kbtab){
4139c1d3970SDavid du Colombier 		c |= keyup;
4149c1d3970SDavid du Colombier 		if(c != 0xFF)	/* these come fairly often: CAPSLOCK U Y */
4159c1d3970SDavid du Colombier 			print("unknown key %ux\n", c);
4169c1d3970SDavid du Colombier 		return;
4179c1d3970SDavid du Colombier 	}
4189c1d3970SDavid du Colombier 
4199c1d3970SDavid du Colombier 	if(kbscan->esc1){
4209c1d3970SDavid du Colombier 		c = kbtabesc1[c];
4219c1d3970SDavid du Colombier 		kbscan->esc1 = 0;
4229c1d3970SDavid du Colombier 	} else if(kbscan->esc2){
4239c1d3970SDavid du Colombier 		kbscan->esc2--;
4249c1d3970SDavid du Colombier 		return;
4259c1d3970SDavid du Colombier 	} else if(kbscan->shift)
4269c1d3970SDavid du Colombier 		c = kbtabshift[c];
4279c1d3970SDavid du Colombier 	else if(kbscan->altgr)
4289c1d3970SDavid du Colombier 		c = kbtabaltgr[c];
4299c1d3970SDavid du Colombier 	else if(kbscan->ctl)
4309c1d3970SDavid du Colombier 		c = kbtabctrl[c];
4319c1d3970SDavid du Colombier 	else
4329c1d3970SDavid du Colombier 		c = kbtab[c];
4339c1d3970SDavid du Colombier 
4349c1d3970SDavid du Colombier 	if(kbscan->caps && c<='z' && c>='a')
4359c1d3970SDavid du Colombier 		c += 'A' - 'a';
4369c1d3970SDavid du Colombier 
4379c1d3970SDavid du Colombier 	/*
4389c1d3970SDavid du Colombier 	 *  keyup only important for shifts
4399c1d3970SDavid du Colombier 	 */
4409c1d3970SDavid du Colombier 	if(keyup){
4419c1d3970SDavid du Colombier 		switch(c){
4429c1d3970SDavid du Colombier 		case Latin:
4439c1d3970SDavid du Colombier 			kbscan->alt = 0;
44483030dd5SDavid du Colombier 			break;
44583030dd5SDavid du Colombier 		case Shift:
4469c1d3970SDavid du Colombier 			kbscan->shift = 0;
4479c1d3970SDavid du Colombier 			mouseshifted = 0;
4489c1d3970SDavid du Colombier 			if(kdebug)
4499c1d3970SDavid du Colombier 				print("shiftclr\n");
4509c1d3970SDavid du Colombier 			break;
4519c1d3970SDavid du Colombier 		case Ctrl:
4529c1d3970SDavid du Colombier 			kbscan->ctl = 0;
4539c1d3970SDavid du Colombier 			break;
4549c1d3970SDavid du Colombier 		case Altgr:
4559c1d3970SDavid du Colombier 			kbscan->altgr = 0;
4569c1d3970SDavid du Colombier 			break;
4579c1d3970SDavid du Colombier 		case Kmouse|1:
4589c1d3970SDavid du Colombier 		case Kmouse|2:
4599c1d3970SDavid du Colombier 		case Kmouse|3:
4609c1d3970SDavid du Colombier 		case Kmouse|4:
4619c1d3970SDavid du Colombier 		case Kmouse|5:
4629c1d3970SDavid du Colombier 			kbscan->buttons &= ~(1<<(c-Kmouse-1));
4639c1d3970SDavid du Colombier 			if(kbdmouse)
4649c1d3970SDavid du Colombier 				kbdmouse(kbscan->buttons);
4659c1d3970SDavid du Colombier 			break;
4669c1d3970SDavid du Colombier 		}
4679c1d3970SDavid du Colombier 		return;
4689c1d3970SDavid du Colombier 	}
4699c1d3970SDavid du Colombier 
4709c1d3970SDavid du Colombier 	/*
4719c1d3970SDavid du Colombier 	 *  normal character
4729c1d3970SDavid du Colombier 	 */
4739c1d3970SDavid du Colombier 	if(!(c & (Spec|KF))){
4749c1d3970SDavid du Colombier 		if(kbscan->ctl)
4759c1d3970SDavid du Colombier 			if(kbscan->alt && c == Del)
4769c1d3970SDavid du Colombier 				exit(0);
4779c1d3970SDavid du Colombier 		if(!kbscan->collecting){
4789c1d3970SDavid du Colombier 			kbdputc(kbdq, c);
4799c1d3970SDavid du Colombier 			return;
4809c1d3970SDavid du Colombier 		}
4819c1d3970SDavid du Colombier 		kbscan->kc[kbscan->nk++] = c;
4829c1d3970SDavid du Colombier 		c = latin1(kbscan->kc, kbscan->nk);
4839c1d3970SDavid du Colombier 		if(c < -1)	/* need more keystrokes */
4849c1d3970SDavid du Colombier 			return;
4859c1d3970SDavid du Colombier 		if(c != -1)	/* valid sequence */
4869c1d3970SDavid du Colombier 			kbdputc(kbdq, c);
4879c1d3970SDavid du Colombier 		else	/* dump characters */
4889c1d3970SDavid du Colombier 			for(i=0; i<kbscan->nk; i++)
4899c1d3970SDavid du Colombier 				kbdputc(kbdq, kbscan->kc[i]);
4909c1d3970SDavid du Colombier 		kbscan->nk = 0;
4919c1d3970SDavid du Colombier 		kbscan->collecting = 0;
4929c1d3970SDavid du Colombier 		return;
4939c1d3970SDavid du Colombier 	} else {
4949c1d3970SDavid du Colombier 		switch(c){
4959c1d3970SDavid du Colombier 		case Caps:
496d5b6fab5SDavid du Colombier 			kbscan->caps ^= 1;
497d5b6fab5SDavid du Colombier 			return;
4989c1d3970SDavid du Colombier 		case Num:
4999c1d3970SDavid du Colombier 			kbscan->num ^= 1;
5009c1d3970SDavid du Colombier 			if(!external)
50183030dd5SDavid du Colombier 				setleds(kbscan);
50283030dd5SDavid du Colombier 			return;
5039c1d3970SDavid du Colombier 		case Shift:
5049c1d3970SDavid du Colombier 			kbscan->shift = 1;
5059c1d3970SDavid du Colombier 			if(kdebug)
5069c1d3970SDavid du Colombier 				print("shift\n");
5079c1d3970SDavid du Colombier 			mouseshifted = 1;
5089c1d3970SDavid du Colombier 			return;
5099c1d3970SDavid du Colombier 		case Latin:
5109c1d3970SDavid du Colombier 			kbscan->alt = 1;
5119c1d3970SDavid du Colombier 			/*
5129c1d3970SDavid du Colombier 			 * VMware and Qemu use Ctl-Alt as the key combination
5139c1d3970SDavid du Colombier 			 * to make the VM give up keyboard and mouse focus.
5149c1d3970SDavid du Colombier 			 * This has the unfortunate side effect that when you
5159c1d3970SDavid du Colombier 			 * come back into focus, Plan 9 thinks you want to type
5169c1d3970SDavid du Colombier 			 * a compose sequence (you just typed alt).
5179c1d3970SDavid du Colombier 			 *
5189c1d3970SDavid du Colombier 			 * As a clumsy hack around this, we look for ctl-alt
5199c1d3970SDavid du Colombier 			 * and don't treat it as the start of a compose sequence.
5209c1d3970SDavid du Colombier 			 */
5219c1d3970SDavid du Colombier 			if(!kbscan->ctl){
5229c1d3970SDavid du Colombier 				kbscan->collecting = 1;
5239c1d3970SDavid du Colombier 				kbscan->nk = 0;
5249c1d3970SDavid du Colombier 			}
5259c1d3970SDavid du Colombier 			return;
5269c1d3970SDavid du Colombier 		case Ctrl:
5279c1d3970SDavid du Colombier 			kbscan->ctl = 1;
5289c1d3970SDavid du Colombier 			return;
5299c1d3970SDavid du Colombier 		case Altgr:
5309c1d3970SDavid du Colombier 			kbscan->altgr = 1;
5319c1d3970SDavid du Colombier 			return;
5329c1d3970SDavid du Colombier 		case Kmouse|1:
5339c1d3970SDavid du Colombier 		case Kmouse|2:
5349c1d3970SDavid du Colombier 		case Kmouse|3:
5359c1d3970SDavid du Colombier 		case Kmouse|4:
5369c1d3970SDavid du Colombier 		case Kmouse|5:
53783030dd5SDavid du Colombier 			kbscan->buttons |= 1<<(c-Kmouse-1);
538d5b6fab5SDavid du Colombier 			if(kbdmouse)
53983030dd5SDavid du Colombier 				kbdmouse(kbscan->buttons);
54083030dd5SDavid du Colombier 			return;
54183030dd5SDavid du Colombier 		case KF|11:
54283030dd5SDavid du Colombier 			print("kbd debug on, F12 turns it off\n");
54383030dd5SDavid du Colombier 			kdebug = 1;
5449c1d3970SDavid du Colombier 			break;
5459c1d3970SDavid du Colombier 		case KF|12:
5469c1d3970SDavid du Colombier 			kdebug = 0;
5479c1d3970SDavid du Colombier 			break;
548e29df7b0SDavid du Colombier 		}
549bd389b36SDavid du Colombier 	}
5503e12c5d1SDavid du Colombier 	kbdputc(kbdq, c);
5513e12c5d1SDavid du Colombier }
5527dd7cddfSDavid du Colombier 
i8042intr(Ureg *,void *)5537dd7cddfSDavid du Colombier /*
5543e12c5d1SDavid du Colombier  *  keyboard interrupt
5559c1d3970SDavid du Colombier  */
5563e12c5d1SDavid du Colombier static void
5573e12c5d1SDavid du Colombier i8042intr(Ureg*, void*)
5583e12c5d1SDavid du Colombier {
5593e12c5d1SDavid du Colombier 	int s, c;
560b8d70f5aSDavid du Colombier 
5613e12c5d1SDavid du Colombier 	/*
5627dd7cddfSDavid du Colombier 	 *  get status
563b8d70f5aSDavid du Colombier 	 */
564219b2ee8SDavid du Colombier 	ilock(&i8042lock);
5657dd7cddfSDavid du Colombier 	s = inb(Status);
5663e12c5d1SDavid du Colombier 	if(!(s&Inready)){
5673e12c5d1SDavid du Colombier 		iunlock(&i8042lock);
5683e12c5d1SDavid du Colombier 		return;
5693e12c5d1SDavid du Colombier 	}
5703e12c5d1SDavid du Colombier 
571b8d70f5aSDavid du Colombier 	/*
5723e12c5d1SDavid du Colombier 	 *  get the character
5733e12c5d1SDavid du Colombier 	 */
5747dd7cddfSDavid du Colombier 	c = inb(Data);
5753e12c5d1SDavid du Colombier 	iunlock(&i8042lock);
5763e12c5d1SDavid du Colombier 
5777dd7cddfSDavid du Colombier 	/*
578d5b6fab5SDavid du Colombier 	 *  if it's the aux port...
579219b2ee8SDavid du Colombier 	 */
5803e12c5d1SDavid du Colombier 	if(s & Minready){
5813e12c5d1SDavid du Colombier 		if(auxputc != nil)
582d5b6fab5SDavid du Colombier 			auxputc(c, kbscans[Int].shift);
5833e12c5d1SDavid du Colombier 		return;
5843e12c5d1SDavid du Colombier 	}
5853e12c5d1SDavid du Colombier 
5867dd7cddfSDavid du Colombier 	kbdputsc(c, Int);
5873e12c5d1SDavid du Colombier }
5887dd7cddfSDavid du Colombier 
589219b2ee8SDavid du Colombier void
5907dd7cddfSDavid du Colombier i8042auxenable(void (*putc)(int, int))
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier 	char *err = "i8042: aux init failed\n";
5937dd7cddfSDavid du Colombier 
5947dd7cddfSDavid du Colombier 	/* enable kbd/aux xfers and interrupts */
5957dd7cddfSDavid du Colombier 	ccc &= ~Cauxdis;
5967dd7cddfSDavid du Colombier 	ccc |= Cauxint;
5977dd7cddfSDavid du Colombier 
5987dd7cddfSDavid du Colombier 	ilock(&i8042lock);
5997dd7cddfSDavid du Colombier 	if(outready() < 0)
6007dd7cddfSDavid du Colombier 		print(err);
6017dd7cddfSDavid du Colombier 	outb(Cmd, 0x60);			/* write control register */
6027dd7cddfSDavid du Colombier 	if(outready() < 0)
60326d1d1dfSDavid du Colombier 		print(err);
6047dd7cddfSDavid du Colombier 	outb(Data, ccc);
6057dd7cddfSDavid du Colombier 	if(outready() < 0)
606219b2ee8SDavid du Colombier 		print(err);
6077dd7cddfSDavid du Colombier 	outb(Cmd, 0xA8);			/* auxiliary device enable */
6087dd7cddfSDavid du Colombier 	if(outready() < 0){
6097dd7cddfSDavid du Colombier 		iunlock(&i8042lock);
6107dd7cddfSDavid du Colombier 		return;
6117dd7cddfSDavid du Colombier 	}
6127dd7cddfSDavid du Colombier 	auxputc = putc;
613c3ca4b29SDavid du Colombier 	intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
614c3ca4b29SDavid du Colombier 	iunlock(&i8042lock);
615c3ca4b29SDavid du Colombier }
outbyte(int port,int c)616c3ca4b29SDavid du Colombier 
617c3ca4b29SDavid du Colombier static char *initfailed = "i8042: kbdinit failed\n";
618c3ca4b29SDavid du Colombier 
619c3ca4b29SDavid du Colombier static int
620c3ca4b29SDavid du Colombier outbyte(int port, int c)
621c3ca4b29SDavid du Colombier {
622c3ca4b29SDavid du Colombier 	outb(port, c);
623c3ca4b29SDavid du Colombier 	if(outready() < 0) {
624c3ca4b29SDavid du Colombier 		print(initfailed);
625c3ca4b29SDavid du Colombier 		return -1;
6267dd7cddfSDavid du Colombier 	}
kbdinit(void)6277dd7cddfSDavid du Colombier 	return 0;
6287dd7cddfSDavid du Colombier }
629c3ca4b29SDavid du Colombier 
6307dd7cddfSDavid du Colombier void
6317dd7cddfSDavid du Colombier kbdinit(void)
6327d80c4cdSDavid du Colombier {
633c3ca4b29SDavid du Colombier 	int c, try;
6347dd7cddfSDavid du Colombier 
6357dd7cddfSDavid du Colombier 	/* wait for a quiescent controller */
636c3ca4b29SDavid du Colombier 	try = 500;
637c3ca4b29SDavid du Colombier 	while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
638c3ca4b29SDavid du Colombier 		if(c & Inready)
639c3ca4b29SDavid du Colombier 			inb(Data);
640c3ca4b29SDavid du Colombier 		delay(1);
641c3ca4b29SDavid du Colombier 	}
6427dd7cddfSDavid du Colombier 	if (try <= 0) {
6437dd7cddfSDavid du Colombier 		print(initfailed);
6447dd7cddfSDavid du Colombier 		return;
6457dd7cddfSDavid du Colombier 	}
646c3ca4b29SDavid du Colombier 
6477dd7cddfSDavid du Colombier 	/* get current controller command byte */
6487dd7cddfSDavid du Colombier 	outb(Cmd, 0x20);
6497dd7cddfSDavid du Colombier 	if(inready() < 0){
6507dd7cddfSDavid du Colombier 		print("i8042: kbdinit can't read ccc\n");
6517dd7cddfSDavid du Colombier 		ccc = 0;
6527dd7cddfSDavid du Colombier 	} else
6537dd7cddfSDavid du Colombier 		ccc = inb(Data);
654c3ca4b29SDavid du Colombier 
655c3ca4b29SDavid du Colombier 	/* enable kbd xfers and interrupts */
656c3ca4b29SDavid du Colombier 	ccc &= ~Ckbddis;
657c3ca4b29SDavid du Colombier 	ccc |= Csf | Ckbdint | Cscs1;
658c3ca4b29SDavid du Colombier 	if(outready() < 0) {
659c3ca4b29SDavid du Colombier 		print(initfailed);
660c3ca4b29SDavid du Colombier 		return;
661c3ca4b29SDavid du Colombier 	}
662c3ca4b29SDavid du Colombier 
663c3ca4b29SDavid du Colombier 	nokbd = 0;
664f7db6155SDavid du Colombier 
665*9a3e0102SDavid du Colombier 	/* disable mouse */
666*9a3e0102SDavid du Colombier 	if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0)
667f7db6155SDavid du Colombier 		print("i8042: kbdinit mouse disable failed\n");
668f7db6155SDavid du Colombier 
669f7db6155SDavid du Colombier 	/* see http://www.computer-engineering.org/ps2keyboard for codes */
6703e12c5d1SDavid du Colombier 	if(getconf("*typematic") != nil)
6719a747e4fSDavid du Colombier 		/* set typematic rate/delay (0 -> delay=250ms & rate=30cps) */
6729a747e4fSDavid du Colombier 		if(outbyte(Data, 0xf3) < 0 || outbyte(Data, 0) < 0)
kbdenable(void)6739a747e4fSDavid du Colombier 			print("i8042: kbdinit set typematic rate failed\n");
6749a747e4fSDavid du Colombier }
6759a747e4fSDavid du Colombier 
6769a747e4fSDavid du Colombier void
6779a747e4fSDavid du Colombier kbdenable(void)
6789a747e4fSDavid du Colombier {
6799a747e4fSDavid du Colombier 	kbdq = qopen(4*1024, 0, 0, 0);
6809a747e4fSDavid du Colombier 	if(kbdq == nil)
6819a747e4fSDavid du Colombier 		panic("kbdinit");
6829a747e4fSDavid du Colombier 	qnoblock(kbdq, 1);
6839a747e4fSDavid du Colombier 
684d5b6fab5SDavid du Colombier 	ioalloc(Data, 1, 0, "kbd");
685d5b6fab5SDavid du Colombier 	ioalloc(Cmd, 1, 0, "kbd");
686d5b6fab5SDavid du Colombier 
6879a747e4fSDavid du Colombier 	intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
6883901e6d0SDavid du Colombier 
6893901e6d0SDavid du Colombier 	kbscans[Int].num = 0;
kbdputmap(ushort m,ushort scanc,Rune r)6903901e6d0SDavid du Colombier 	setleds(&kbscans[Int]);
6913901e6d0SDavid du Colombier }
6923901e6d0SDavid du Colombier 
6933901e6d0SDavid du Colombier void
6943901e6d0SDavid du Colombier kbdputmap(ushort m, ushort scanc, Rune r)
6953901e6d0SDavid du Colombier {
6963901e6d0SDavid du Colombier 	if(scanc >= Nscan)
6973901e6d0SDavid du Colombier 		error(Ebadarg);
6983901e6d0SDavid du Colombier 	switch(m) {
6993901e6d0SDavid du Colombier 	default:
7003901e6d0SDavid du Colombier 		error(Ebadarg);
7013901e6d0SDavid du Colombier 	case 0:
7023901e6d0SDavid du Colombier 		kbtab[scanc] = r;
7033901e6d0SDavid du Colombier 		break;
7043901e6d0SDavid du Colombier 	case 1:
7053901e6d0SDavid du Colombier 		kbtabshift[scanc] = r;
7063901e6d0SDavid du Colombier 		break;
7073901e6d0SDavid du Colombier 	case 2:
7083901e6d0SDavid du Colombier 		kbtabesc1[scanc] = r;
7093901e6d0SDavid du Colombier 		break;
7103901e6d0SDavid du Colombier 	case 3:
7113901e6d0SDavid du Colombier 		kbtabaltgr[scanc] = r;
7123901e6d0SDavid du Colombier 		break;
7133901e6d0SDavid du Colombier 	case 4:
7143901e6d0SDavid du Colombier 		kbtabctrl[scanc] = r;
7153901e6d0SDavid du Colombier 		break;
kbdgetmap(uint offset,int * t,int * sc,Rune * r)7169c1d3970SDavid du Colombier 	}
7173901e6d0SDavid du Colombier }
7189c1d3970SDavid du Colombier 
7199c1d3970SDavid du Colombier int
7203901e6d0SDavid du Colombier kbdgetmap(uint offset, int *t, int *sc, Rune *r)
7213901e6d0SDavid du Colombier {
7223901e6d0SDavid du Colombier 	if ((int)offset < 0)
7233901e6d0SDavid du Colombier 		error(Ebadarg);
7243901e6d0SDavid du Colombier 	*t = offset/Nscan;
7253901e6d0SDavid du Colombier 	*sc = offset%Nscan;
7263901e6d0SDavid du Colombier 	switch(*t) {
7273901e6d0SDavid du Colombier 	default:
7283901e6d0SDavid du Colombier 		return 0;
7293901e6d0SDavid du Colombier 	case 0:
7303901e6d0SDavid du Colombier 		*r = kbtab[*sc];
7313901e6d0SDavid du Colombier 		return 1;
7323901e6d0SDavid du Colombier 	case 1:
7333901e6d0SDavid du Colombier 		*r = kbtabshift[*sc];
7343901e6d0SDavid du Colombier 		return 1;
7353901e6d0SDavid du Colombier 	case 2:
7363901e6d0SDavid du Colombier 		*r = kbtabesc1[*sc];
7373901e6d0SDavid du Colombier 		return 1;
7383901e6d0SDavid du Colombier 	case 3:
7393901e6d0SDavid du Colombier 		*r = kbtabaltgr[*sc];
7403901e6d0SDavid du Colombier 		return 1;
7413901e6d0SDavid du Colombier 	case 4:
742 		*r = kbtabctrl[*sc];
743 		return 1;
744 	}
745 }
746