xref: /plan9-contrib/sys/src/9k/386/kbd.c (revision 277b6efdcc262cd4d08d05822b6e10d78be9f0bc)
1*277b6efdSDavid du Colombier /*
2*277b6efdSDavid du Colombier  * keyboard input
3*277b6efdSDavid du Colombier  */
49ef1f84bSDavid du Colombier #include	"u.h"
59ef1f84bSDavid du Colombier #include	"../port/lib.h"
69ef1f84bSDavid du Colombier #include	"mem.h"
79ef1f84bSDavid du Colombier #include	"dat.h"
89ef1f84bSDavid du Colombier #include	"fns.h"
99ef1f84bSDavid du Colombier #include	"../port/error.h"
109ef1f84bSDavid du Colombier 
119ef1f84bSDavid du Colombier #include	"io.h"
129ef1f84bSDavid du Colombier 
139ef1f84bSDavid du Colombier enum {
149ef1f84bSDavid du Colombier 	Data=		0x60,		/* data port */
159ef1f84bSDavid du Colombier 
169ef1f84bSDavid du Colombier 	Status=		0x64,		/* status port */
179ef1f84bSDavid du Colombier 	 Inready=	0x01,		/*  input character ready */
189ef1f84bSDavid du Colombier 	 Outbusy=	0x02,		/*  output busy */
199ef1f84bSDavid du Colombier 	 Sysflag=	0x04,		/*  system flag */
209ef1f84bSDavid du Colombier 	 Cmddata=	0x08,		/*  cmd==0, data==1 */
219ef1f84bSDavid du Colombier 	 Inhibit=	0x10,		/*  keyboard/mouse inhibited */
229ef1f84bSDavid du Colombier 	 Minready=	0x20,		/*  mouse character ready */
239ef1f84bSDavid du Colombier 	 Rtimeout=	0x40,		/*  general timeout */
249ef1f84bSDavid du Colombier 	 Parity=	0x80,
259ef1f84bSDavid du Colombier 
269ef1f84bSDavid du Colombier 	Cmd=		0x64,		/* command port (write only) */
279ef1f84bSDavid du Colombier 
289ef1f84bSDavid du Colombier 	Spec=		0xF800,		/* Unicode private space */
299ef1f84bSDavid du Colombier 	PF=		Spec|0x20,	/* num pad function key */
309ef1f84bSDavid du Colombier 	View=		Spec|0x00,	/* view (shift window up) */
319ef1f84bSDavid du Colombier 	KF=		0xF000,		/* function key (begin Unicode private space) */
329ef1f84bSDavid du Colombier 	Shift=		Spec|0x60,
339ef1f84bSDavid du Colombier 	Break=		Spec|0x61,
349ef1f84bSDavid du Colombier 	Ctrl=		Spec|0x62,
359ef1f84bSDavid du Colombier 	Latin=		Spec|0x63,
369ef1f84bSDavid du Colombier 	Caps=		Spec|0x64,
379ef1f84bSDavid du Colombier 	Num=		Spec|0x65,
389ef1f84bSDavid du Colombier 	Middle=		Spec|0x66,
399ef1f84bSDavid du Colombier 	Altgr=		Spec|0x67,
409ef1f84bSDavid du Colombier 	Kmouse=		Spec|0x100,
419ef1f84bSDavid du Colombier 	No=		0x00,		/* peter */
429ef1f84bSDavid du Colombier 
439ef1f84bSDavid du Colombier 	Home=		KF|13,
449ef1f84bSDavid du Colombier 	Up=		KF|14,
459ef1f84bSDavid du Colombier 	Pgup=		KF|15,
469ef1f84bSDavid du Colombier 	Print=		KF|16,
479ef1f84bSDavid du Colombier 	Left=		KF|17,
489ef1f84bSDavid du Colombier 	Right=		KF|18,
499ef1f84bSDavid du Colombier 	End=		KF|24,
509ef1f84bSDavid du Colombier 	Down=		View,
519ef1f84bSDavid du Colombier 	Pgdown=		KF|19,
529ef1f84bSDavid du Colombier 	Ins=		KF|20,
539ef1f84bSDavid du Colombier 	Del=		0x7F,
549ef1f84bSDavid du Colombier 	Scroll=		KF|21,
559ef1f84bSDavid du Colombier 
569ef1f84bSDavid du Colombier 	Nscan=	128,
57*277b6efdSDavid du Colombier 
58*277b6efdSDavid du Colombier 	Int=	0,			/* kbscans indices */
59*277b6efdSDavid du Colombier 	Ext,
60*277b6efdSDavid du Colombier 	Nscans,
619ef1f84bSDavid du Colombier };
629ef1f84bSDavid du Colombier 
639ef1f84bSDavid du Colombier /*
64*277b6efdSDavid du Colombier  * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
659ef1f84bSDavid du Colombier  * A 'standard' keyboard doesn't produce anything above 0x58.
669ef1f84bSDavid du Colombier  */
679ef1f84bSDavid du Colombier Rune kbtab[Nscan] =
689ef1f84bSDavid du Colombier {
699ef1f84bSDavid du Colombier [0x00]	No,	0x1b,	'1',	'2',	'3',	'4',	'5',	'6',
709ef1f84bSDavid du Colombier [0x08]	'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
719ef1f84bSDavid du Colombier [0x10]	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
729ef1f84bSDavid du Colombier [0x18]	'o',	'p',	'[',	']',	'\n',	Ctrl,	'a',	's',
739ef1f84bSDavid du Colombier [0x20]	'd',	'f',	'g',	'h',	'j',	'k',	'l',	';',
749ef1f84bSDavid du Colombier [0x28]	'\'',	'`',	Shift,	'\\',	'z',	'x',	'c',	'v',
759ef1f84bSDavid du Colombier [0x30]	'b',	'n',	'm',	',',	'.',	'/',	Shift,	'*',
769ef1f84bSDavid du Colombier [0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
779ef1f84bSDavid du Colombier [0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
789ef1f84bSDavid du Colombier [0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
799ef1f84bSDavid du Colombier [0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
809ef1f84bSDavid du Colombier [0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
819ef1f84bSDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
829ef1f84bSDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
839ef1f84bSDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
849ef1f84bSDavid du Colombier [0x78]	No,	View,	No,	Up,	No,	No,	No,	No,
859ef1f84bSDavid du Colombier };
869ef1f84bSDavid du Colombier 
879ef1f84bSDavid du Colombier Rune kbtabshift[Nscan] =
889ef1f84bSDavid du Colombier {
899ef1f84bSDavid du Colombier [0x00]	No,	0x1b,	'!',	'@',	'#',	'$',	'%',	'^',
909ef1f84bSDavid du Colombier [0x08]	'&',	'*',	'(',	')',	'_',	'+',	'\b',	'\t',
919ef1f84bSDavid du Colombier [0x10]	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I',
929ef1f84bSDavid du Colombier [0x18]	'O',	'P',	'{',	'}',	'\n',	Ctrl,	'A',	'S',
939ef1f84bSDavid du Colombier [0x20]	'D',	'F',	'G',	'H',	'J',	'K',	'L',	':',
949ef1f84bSDavid du Colombier [0x28]	'"',	'~',	Shift,	'|',	'Z',	'X',	'C',	'V',
959ef1f84bSDavid du Colombier [0x30]	'B',	'N',	'M',	'<',	'>',	'?',	Shift,	'*',
969ef1f84bSDavid du Colombier [0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
979ef1f84bSDavid du Colombier [0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
989ef1f84bSDavid du Colombier [0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
999ef1f84bSDavid du Colombier [0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
1009ef1f84bSDavid du Colombier [0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
1019ef1f84bSDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
1029ef1f84bSDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
1039ef1f84bSDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
1049ef1f84bSDavid du Colombier [0x78]	No,	Up,	No,	Up,	No,	No,	No,	No,
1059ef1f84bSDavid du Colombier };
1069ef1f84bSDavid du Colombier 
1079ef1f84bSDavid du Colombier Rune kbtabesc1[Nscan] =
1089ef1f84bSDavid du Colombier {
1099ef1f84bSDavid du Colombier [0x00]	No,	No,	No,	No,	No,	No,	No,	No,
1109ef1f84bSDavid du Colombier [0x08]	No,	No,	No,	No,	No,	No,	No,	No,
1119ef1f84bSDavid du Colombier [0x10]	No,	No,	No,	No,	No,	No,	No,	No,
1129ef1f84bSDavid du Colombier [0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
1139ef1f84bSDavid du Colombier [0x20]	No,	No,	No,	No,	No,	No,	No,	No,
1149ef1f84bSDavid du Colombier [0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
1159ef1f84bSDavid du Colombier [0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
1169ef1f84bSDavid du Colombier [0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
1179ef1f84bSDavid du Colombier [0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
1189ef1f84bSDavid du Colombier [0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
1199ef1f84bSDavid du Colombier [0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
1209ef1f84bSDavid du Colombier [0x58]	No,	No,	No,	No,	No,	No,	No,	No,
1219ef1f84bSDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
1229ef1f84bSDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
1239ef1f84bSDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
1249ef1f84bSDavid du Colombier [0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
1259ef1f84bSDavid du Colombier };
1269ef1f84bSDavid du Colombier 
1279ef1f84bSDavid du Colombier Rune kbtabaltgr[Nscan] =
1289ef1f84bSDavid du Colombier {
1299ef1f84bSDavid du Colombier [0x00]	No,	No,	No,	No,	No,	No,	No,	No,
1309ef1f84bSDavid du Colombier [0x08]	No,	No,	No,	No,	No,	No,	No,	No,
1319ef1f84bSDavid du Colombier [0x10]	No,	No,	No,	No,	No,	No,	No,	No,
1329ef1f84bSDavid du Colombier [0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
1339ef1f84bSDavid du Colombier [0x20]	No,	No,	No,	No,	No,	No,	No,	No,
1349ef1f84bSDavid du Colombier [0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
1359ef1f84bSDavid du Colombier [0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
1369ef1f84bSDavid du Colombier [0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
1379ef1f84bSDavid du Colombier [0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
1389ef1f84bSDavid du Colombier [0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
1399ef1f84bSDavid du Colombier [0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
1409ef1f84bSDavid du Colombier [0x58]	No,	No,	No,	No,	No,	No,	No,	No,
1419ef1f84bSDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
1429ef1f84bSDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
1439ef1f84bSDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
1449ef1f84bSDavid du Colombier [0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
1459ef1f84bSDavid du Colombier };
1469ef1f84bSDavid du Colombier 
147*277b6efdSDavid du Colombier Rune kbtabctrl[Nscan] =
1489ef1f84bSDavid du Colombier {
1499ef1f84bSDavid du Colombier [0x00]	No,	'', 	'', 	'', 	'', 	'', 	'', 	'',
1509ef1f84bSDavid du Colombier [0x08]	'', 	'', 	'', 	'', 	'
1519ef1f84bSDavid du Colombier ', 	'', 	'\b',	'\t',
1529ef1f84bSDavid du Colombier [0x10]	'', 	'', 	'', 	'', 	'', 	'', 	'', 	'\t',
1539ef1f84bSDavid du Colombier [0x18]	'', 	'', 	'', 	'', 	'\n',	Ctrl,	'', 	'',
1549ef1f84bSDavid du Colombier [0x20]	'', 	'', 	'', 	'\b',	'\n',	'', 	'', 	'',
1559ef1f84bSDavid du Colombier [0x28]	'', 	No, 	Shift,	'', 	'', 	'', 	'', 	'',
1569ef1f84bSDavid du Colombier [0x30]	'', 	'', 	'
1579ef1f84bSDavid du Colombier ', 	'', 	'', 	'', 	Shift,	'\n',
1589ef1f84bSDavid du Colombier [0x38]	Latin,	No, 	Ctrl,	'', 	'', 	'', 	'', 	'',
1599ef1f84bSDavid du Colombier [0x40]	'', 	'', 	'', 	'
1609ef1f84bSDavid du Colombier ', 	'', 	'', 	'', 	'',
1619ef1f84bSDavid du Colombier [0x48]	'', 	'', 	'
1629ef1f84bSDavid du Colombier ', 	'', 	'', 	'', 	'', 	'',
1639ef1f84bSDavid du Colombier [0x50]	'', 	'', 	'', 	'', 	No,	No,	No,	'',
1649ef1f84bSDavid du Colombier [0x58]	'', 	No,	No,	No,	No,	No,	No,	No,
1659ef1f84bSDavid du Colombier [0x60]	No,	No,	No,	No,	No,	No,	No,	No,
1669ef1f84bSDavid du Colombier [0x68]	No,	No,	No,	No,	No,	No,	No,	No,
1679ef1f84bSDavid du Colombier [0x70]	No,	No,	No,	No,	No,	No,	No,	No,
1689ef1f84bSDavid du Colombier [0x78]	No,	'', 	No,	'\b',	No,	No,	No,	No,
1699ef1f84bSDavid du Colombier };
1709ef1f84bSDavid du Colombier 
1719ef1f84bSDavid du Colombier enum
1729ef1f84bSDavid du Colombier {
1739ef1f84bSDavid du Colombier 	/* controller command byte */
1749ef1f84bSDavid du Colombier 	Cscs1=		(1<<6),		/* scan code set 1 */
1759ef1f84bSDavid du Colombier 	Cauxdis=	(1<<5),		/* mouse disable */
1769ef1f84bSDavid du Colombier 	Ckbddis=	(1<<4),		/* kbd disable */
1779ef1f84bSDavid du Colombier 	Csf=		(1<<2),		/* system flag */
1789ef1f84bSDavid du Colombier 	Cauxint=	(1<<1),		/* mouse interrupt enable */
1799ef1f84bSDavid du Colombier 	Ckbdint=	(1<<0),		/* kbd interrupt enable */
1809ef1f84bSDavid du Colombier };
1819ef1f84bSDavid du Colombier 
1829ef1f84bSDavid du Colombier static Queue *kbdq;
1839ef1f84bSDavid du Colombier 
1849ef1f84bSDavid du Colombier int mouseshifted;
1859ef1f84bSDavid du Colombier void (*kbdmouse)(int);
186*277b6efdSDavid du Colombier 
1879ef1f84bSDavid du Colombier static Lock i8042lock;
1889ef1f84bSDavid du Colombier static uchar ccc;
1899ef1f84bSDavid du Colombier static void (*auxputc)(int, int);
1909ef1f84bSDavid du Colombier static int nokbd = 1;			/* flag: no PS/2 keyboard */
1919ef1f84bSDavid du Colombier 
outready(void)1929ef1f84bSDavid du Colombier /*
1939ef1f84bSDavid du Colombier  *  wait for output no longer busy
1949ef1f84bSDavid du Colombier  */
1959ef1f84bSDavid du Colombier static int
1969ef1f84bSDavid du Colombier outready(void)
1979ef1f84bSDavid du Colombier {
1989ef1f84bSDavid du Colombier 	int tries;
1999ef1f84bSDavid du Colombier 
2009ef1f84bSDavid du Colombier 	for(tries = 0; (inb(Status) & Outbusy); tries++){
2019ef1f84bSDavid du Colombier 		if(tries > 500)
2029ef1f84bSDavid du Colombier 			return -1;
2039ef1f84bSDavid du Colombier 		delay(2);
2049ef1f84bSDavid du Colombier 	}
2059ef1f84bSDavid du Colombier 	return 0;
2069ef1f84bSDavid du Colombier }
2079ef1f84bSDavid du Colombier 
inready(void)2089ef1f84bSDavid du Colombier /*
2099ef1f84bSDavid du Colombier  *  wait for input
2109ef1f84bSDavid du Colombier  */
2119ef1f84bSDavid du Colombier static int
2129ef1f84bSDavid du Colombier inready(void)
2139ef1f84bSDavid du Colombier {
2149ef1f84bSDavid du Colombier 	int tries;
2159ef1f84bSDavid du Colombier 
2169ef1f84bSDavid du Colombier 	for(tries = 0; !(inb(Status) & Inready); tries++){
2179ef1f84bSDavid du Colombier 		if(tries > 500)
2189ef1f84bSDavid du Colombier 			return -1;
2199ef1f84bSDavid du Colombier 		delay(2);
2209ef1f84bSDavid du Colombier 	}
221*277b6efdSDavid du Colombier 	return 0;
222*277b6efdSDavid du Colombier }
223*277b6efdSDavid du Colombier 
i8042a20(void)224*277b6efdSDavid du Colombier /*
225*277b6efdSDavid du Colombier  *  ask 8042 to enable the use of address bit 20
226*277b6efdSDavid du Colombier  */
227*277b6efdSDavid du Colombier void
228*277b6efdSDavid du Colombier i8042a20(void)
229*277b6efdSDavid du Colombier {
230*277b6efdSDavid du Colombier 	outready();
231*277b6efdSDavid du Colombier 	outb(Cmd, 0xD1);
232*277b6efdSDavid du Colombier 	outready();
233*277b6efdSDavid du Colombier 	outb(Data, 0xDF);
2349ef1f84bSDavid du Colombier 	outready();
2359ef1f84bSDavid du Colombier }
2369ef1f84bSDavid du Colombier 
i8042reset(void)2379ef1f84bSDavid du Colombier /*
2389ef1f84bSDavid du Colombier  *  ask 8042 to reset the machine
2399ef1f84bSDavid du Colombier  */
2409ef1f84bSDavid du Colombier void
2419ef1f84bSDavid du Colombier i8042reset(void)
2429ef1f84bSDavid du Colombier {
2439ef1f84bSDavid du Colombier 	int i, x;
244*277b6efdSDavid du Colombier 
2459ef1f84bSDavid du Colombier 	if(nokbd)
2469ef1f84bSDavid du Colombier 		return;
2479ef1f84bSDavid du Colombier 
2489ef1f84bSDavid du Colombier 	*((ushort*)KADDR(0x472)) = 0x1234;	/* BIOS warm-boot flag */
2499ef1f84bSDavid du Colombier 
2509ef1f84bSDavid du Colombier 	/*
2519ef1f84bSDavid du Colombier 	 *  newer reset the machine command
2529ef1f84bSDavid du Colombier 	 */
2539ef1f84bSDavid du Colombier 	outready();
2549ef1f84bSDavid du Colombier 	outb(Cmd, 0xFE);
2559ef1f84bSDavid du Colombier 	outready();
2569ef1f84bSDavid du Colombier 
2579ef1f84bSDavid du Colombier 	/*
2589ef1f84bSDavid du Colombier 	 *  Pulse it by hand (old somewhat reliable)
2599ef1f84bSDavid du Colombier 	 */
2609ef1f84bSDavid du Colombier 	x = 0xDF;
2619ef1f84bSDavid du Colombier 	for(i = 0; i < 5; i++){
2629ef1f84bSDavid du Colombier 		x ^= 1;
2639ef1f84bSDavid du Colombier 		outready();
2649ef1f84bSDavid du Colombier 		outb(Cmd, 0xD1);
2659ef1f84bSDavid du Colombier 		outready();
2669ef1f84bSDavid du Colombier 		outb(Data, x);	/* toggle reset */
2679ef1f84bSDavid du Colombier 		delay(100);
2689ef1f84bSDavid du Colombier 	}
2699ef1f84bSDavid du Colombier }
2709ef1f84bSDavid du Colombier 
2719ef1f84bSDavid du Colombier int
272*277b6efdSDavid du Colombier i8042auxcmd(int cmd)
2739ef1f84bSDavid du Colombier {
274*277b6efdSDavid du Colombier 	unsigned int c;
275*277b6efdSDavid du Colombier 	int tries;
2769ef1f84bSDavid du Colombier 	static int badkbd;
2779ef1f84bSDavid du Colombier 
2789ef1f84bSDavid du Colombier 	if(badkbd)
2799ef1f84bSDavid du Colombier 		return -1;
2809ef1f84bSDavid du Colombier 	c = 0;
2819ef1f84bSDavid du Colombier 	tries = 0;
2829ef1f84bSDavid du Colombier 
2839ef1f84bSDavid du Colombier 	ilock(&i8042lock);
2849ef1f84bSDavid du Colombier 	do{
2859ef1f84bSDavid du Colombier 		if(tries++ > 2)
2869ef1f84bSDavid du Colombier 			break;
2879ef1f84bSDavid du Colombier 		if(outready() < 0)
2889ef1f84bSDavid du Colombier 			break;
2899ef1f84bSDavid du Colombier 		outb(Cmd, 0xD4);
2909ef1f84bSDavid du Colombier 		if(outready() < 0)
2919ef1f84bSDavid du Colombier 			break;
2929ef1f84bSDavid du Colombier 		outb(Data, cmd);
2939ef1f84bSDavid du Colombier 		if(outready() < 0)
2949ef1f84bSDavid du Colombier 			break;
2959ef1f84bSDavid du Colombier 		if(inready() < 0)
2969ef1f84bSDavid du Colombier 			break;
2979ef1f84bSDavid du Colombier 		c = inb(Data);
2989ef1f84bSDavid du Colombier 	} while(c == 0xFE || c == 0);
299*277b6efdSDavid du Colombier 	iunlock(&i8042lock);
3009ef1f84bSDavid du Colombier 
3019ef1f84bSDavid du Colombier 	if(c != 0xFA){
3029ef1f84bSDavid du Colombier 		print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
3039ef1f84bSDavid du Colombier 		badkbd = 1;	/* don't keep trying; there might not be one */
3049ef1f84bSDavid du Colombier 		return -1;
3059ef1f84bSDavid du Colombier 	}
i8042auxcmds(uchar * cmd,int ncmd)3069ef1f84bSDavid du Colombier 	return 0;
3079ef1f84bSDavid du Colombier }
3089ef1f84bSDavid du Colombier 
3099ef1f84bSDavid du Colombier int
3109ef1f84bSDavid du Colombier i8042auxcmds(uchar *cmd, int ncmd)
3119ef1f84bSDavid du Colombier {
3129ef1f84bSDavid du Colombier 	int i;
3139ef1f84bSDavid du Colombier 
3149ef1f84bSDavid du Colombier 	ilock(&i8042lock);
3159ef1f84bSDavid du Colombier 	for(i=0; i<ncmd; i++){
3169ef1f84bSDavid du Colombier 		if(outready() < 0)
3179ef1f84bSDavid du Colombier 			break;
3189ef1f84bSDavid du Colombier 		outb(Cmd, 0xD4);
3199ef1f84bSDavid du Colombier 		if(outready() < 0)
3209ef1f84bSDavid du Colombier 			break;
3219ef1f84bSDavid du Colombier 		outb(Data, cmd[i]);
3229ef1f84bSDavid du Colombier 	}
323*277b6efdSDavid du Colombier 	iunlock(&i8042lock);
324*277b6efdSDavid du Colombier 	return i;
3259ef1f84bSDavid du Colombier }
3269ef1f84bSDavid du Colombier 
3279ef1f84bSDavid du Colombier typedef struct Kbscan Kbscan;
3289ef1f84bSDavid du Colombier struct Kbscan {
3299ef1f84bSDavid du Colombier 	int	esc1;
3309ef1f84bSDavid du Colombier 	int	esc2;
3319ef1f84bSDavid du Colombier 	int	alt;
3329ef1f84bSDavid du Colombier 	int	altgr;
3339ef1f84bSDavid du Colombier 	int	caps;
3349ef1f84bSDavid du Colombier 	int	ctl;
3359ef1f84bSDavid du Colombier 	int	num;
3369ef1f84bSDavid du Colombier 	int	shift;
337*277b6efdSDavid du Colombier 	int	collecting;
338*277b6efdSDavid du Colombier 	int	nk;
339*277b6efdSDavid du Colombier 	Rune	kc[5];
340*277b6efdSDavid du Colombier 	int	buttons;
341*277b6efdSDavid du Colombier };
342*277b6efdSDavid du Colombier 
343*277b6efdSDavid du Colombier Kbscan kbscans[Nscans];	/* kernel and external scan code state */
344*277b6efdSDavid du Colombier 
345*277b6efdSDavid du Colombier static int kdebug;
346*277b6efdSDavid du Colombier 
347*277b6efdSDavid du Colombier /*
348*277b6efdSDavid du Colombier  * set keyboard's leds for lock states (scroll, numeric, caps).
349*277b6efdSDavid du Colombier  *
350*277b6efdSDavid du Colombier  * at least one keyboard (from Qtronics) also sets its numeric-lock
351*277b6efdSDavid du Colombier  * behaviour to match the led state, though it has no numeric keypad,
352*277b6efdSDavid du Colombier  * and some BIOSes bring the system up with numeric-lock set and no
353*277b6efdSDavid du Colombier  * setting to change that.  this combination steals the keys for these
setleds(Kbscan * kbscan)354*277b6efdSDavid du Colombier  * characters and makes it impossible to generate them: uiolkjm&*().
355*277b6efdSDavid du Colombier  * thus we'd like to be able to force the numeric-lock led (and behaviour) off.
356*277b6efdSDavid du Colombier  */
357*277b6efdSDavid du Colombier static void
358*277b6efdSDavid du Colombier setleds(Kbscan *kbscan)
359*277b6efdSDavid du Colombier {
360*277b6efdSDavid du Colombier 	int leds;
361*277b6efdSDavid du Colombier 
362*277b6efdSDavid du Colombier 	if(nokbd || kbscan != &kbscans[Int])
363*277b6efdSDavid du Colombier 		return;
364*277b6efdSDavid du Colombier 	leds = 0;
365*277b6efdSDavid du Colombier 	if(kbscan->num)
366*277b6efdSDavid du Colombier 		leds |= 1<<1;
367*277b6efdSDavid du Colombier 	if(0 && kbscan->caps)		/* we don't implement caps lock */
368*277b6efdSDavid du Colombier 		leds |= 1<<2;
369*277b6efdSDavid du Colombier 
370*277b6efdSDavid du Colombier 	ilock(&i8042lock);
371*277b6efdSDavid du Colombier 	outready();
372*277b6efdSDavid du Colombier 	outb(Data, 0xed);		/* `reset keyboard lock states' */
373*277b6efdSDavid du Colombier 	if(inready() == 0)
374*277b6efdSDavid du Colombier 		inb(Data);
375*277b6efdSDavid du Colombier 
376*277b6efdSDavid du Colombier 	outready();
377*277b6efdSDavid du Colombier 	outb(Data, leds);
378*277b6efdSDavid du Colombier 	if(inready() == 0)
379*277b6efdSDavid du Colombier 		inb(Data);
380*277b6efdSDavid du Colombier 
381*277b6efdSDavid du Colombier 	outready();
382*277b6efdSDavid du Colombier 	iunlock(&i8042lock);
383*277b6efdSDavid du Colombier }
384*277b6efdSDavid du Colombier 
kbdputsc(int c,int external)385*277b6efdSDavid du Colombier /*
386*277b6efdSDavid du Colombier  * Scan code processing
387*277b6efdSDavid du Colombier  */
388*277b6efdSDavid du Colombier void
389*277b6efdSDavid du Colombier kbdputsc(int c, int external)
390*277b6efdSDavid du Colombier {
391*277b6efdSDavid du Colombier 	int i, keyup;
392*277b6efdSDavid du Colombier 	Kbscan *kbscan;
393*277b6efdSDavid du Colombier 
394*277b6efdSDavid du Colombier 	if(external)
395*277b6efdSDavid du Colombier 		kbscan = &kbscans[Ext];
396*277b6efdSDavid du Colombier 	else
397*277b6efdSDavid du Colombier 		kbscan = &kbscans[Int];
398*277b6efdSDavid du Colombier 
399*277b6efdSDavid du Colombier 	if(kdebug)
400*277b6efdSDavid du Colombier 		print("sc %x ms %d\n", c, mouseshifted);
401*277b6efdSDavid du Colombier 	/*
402*277b6efdSDavid du Colombier 	 *  e0's is the first of a 2 character sequence, e1 the first
403*277b6efdSDavid du Colombier 	 *  of a 3 character sequence (on the safari)
404*277b6efdSDavid du Colombier 	 */
405*277b6efdSDavid du Colombier 	if(c == 0xe0){
406*277b6efdSDavid du Colombier 		kbscan->esc1 = 1;
407*277b6efdSDavid du Colombier 		return;
408*277b6efdSDavid du Colombier 	} else if(c == 0xe1){
409*277b6efdSDavid du Colombier 		kbscan->esc2 = 2;
410*277b6efdSDavid du Colombier 		return;
411*277b6efdSDavid du Colombier 	}
412*277b6efdSDavid du Colombier 
413*277b6efdSDavid du Colombier 	keyup = c & 0x80;
414*277b6efdSDavid du Colombier 	c &= 0x7f;
415*277b6efdSDavid du Colombier 	if(c > sizeof kbtab){
416*277b6efdSDavid du Colombier 		c |= keyup;
417*277b6efdSDavid du Colombier 		if(c != 0xFF)	/* these come fairly often: CAPSLOCK U Y */
418*277b6efdSDavid du Colombier 			print("unknown key %ux\n", c);
419*277b6efdSDavid du Colombier 		return;
420*277b6efdSDavid du Colombier 	}
421*277b6efdSDavid du Colombier 
422*277b6efdSDavid du Colombier 	if(kbscan->esc1){
423*277b6efdSDavid du Colombier 		c = kbtabesc1[c];
424*277b6efdSDavid du Colombier 		kbscan->esc1 = 0;
425*277b6efdSDavid du Colombier 	} else if(kbscan->esc2){
426*277b6efdSDavid du Colombier 		kbscan->esc2--;
427*277b6efdSDavid du Colombier 		return;
428*277b6efdSDavid du Colombier 	} else if(kbscan->shift)
429*277b6efdSDavid du Colombier 		c = kbtabshift[c];
430*277b6efdSDavid du Colombier 	else if(kbscan->altgr)
431*277b6efdSDavid du Colombier 		c = kbtabaltgr[c];
432*277b6efdSDavid du Colombier 	else if(kbscan->ctl)
433*277b6efdSDavid du Colombier 		c = kbtabctrl[c];
434*277b6efdSDavid du Colombier 	else
435*277b6efdSDavid du Colombier 		c = kbtab[c];
436*277b6efdSDavid du Colombier 
437*277b6efdSDavid du Colombier 	if(kbscan->caps && c<='z' && c>='a')
438*277b6efdSDavid du Colombier 		c += 'A' - 'a';
439*277b6efdSDavid du Colombier 
440*277b6efdSDavid du Colombier 	/*
441*277b6efdSDavid du Colombier 	 *  keyup only important for shifts
442*277b6efdSDavid du Colombier 	 */
443*277b6efdSDavid du Colombier 	if(keyup){
444*277b6efdSDavid du Colombier 		switch(c){
445*277b6efdSDavid du Colombier 		case Latin:
446*277b6efdSDavid du Colombier 			kbscan->alt = 0;
447*277b6efdSDavid du Colombier 			break;
448*277b6efdSDavid du Colombier 		case Shift:
449*277b6efdSDavid du Colombier 			kbscan->shift = 0;
450*277b6efdSDavid du Colombier 			mouseshifted = 0;
451*277b6efdSDavid du Colombier 			if(kdebug)
452*277b6efdSDavid du Colombier 				print("shiftclr\n");
453*277b6efdSDavid du Colombier 			break;
454*277b6efdSDavid du Colombier 		case Ctrl:
455*277b6efdSDavid du Colombier 			kbscan->ctl = 0;
456*277b6efdSDavid du Colombier 			break;
457*277b6efdSDavid du Colombier 		case Altgr:
458*277b6efdSDavid du Colombier 			kbscan->altgr = 0;
459*277b6efdSDavid du Colombier 			break;
460*277b6efdSDavid du Colombier 		case Kmouse|1:
461*277b6efdSDavid du Colombier 		case Kmouse|2:
462*277b6efdSDavid du Colombier 		case Kmouse|3:
463*277b6efdSDavid du Colombier 		case Kmouse|4:
464*277b6efdSDavid du Colombier 		case Kmouse|5:
465*277b6efdSDavid du Colombier 			kbscan->buttons &= ~(1<<(c-Kmouse-1));
466*277b6efdSDavid du Colombier 			if(kbdmouse)
467*277b6efdSDavid du Colombier 				kbdmouse(kbscan->buttons);
468*277b6efdSDavid du Colombier 			break;
469*277b6efdSDavid du Colombier 		}
470*277b6efdSDavid du Colombier 		return;
471*277b6efdSDavid du Colombier 	}
472*277b6efdSDavid du Colombier 
473*277b6efdSDavid du Colombier 	/*
474*277b6efdSDavid du Colombier 	 *  normal character
475*277b6efdSDavid du Colombier 	 */
476*277b6efdSDavid du Colombier 	if(!(c & (Spec|KF))){
477*277b6efdSDavid du Colombier 		if(kbscan->ctl)
478*277b6efdSDavid du Colombier 			if(kbscan->alt && c == Del)
479*277b6efdSDavid du Colombier 				exit(0);
480*277b6efdSDavid du Colombier 		if(!kbscan->collecting){
481*277b6efdSDavid du Colombier 			kbdputc(kbdq, c);
482*277b6efdSDavid du Colombier 			return;
483*277b6efdSDavid du Colombier 		}
484*277b6efdSDavid du Colombier 		kbscan->kc[kbscan->nk++] = c;
485*277b6efdSDavid du Colombier 		c = latin1(kbscan->kc, kbscan->nk);
486*277b6efdSDavid du Colombier 		if(c < -1)	/* need more keystrokes */
487*277b6efdSDavid du Colombier 			return;
488*277b6efdSDavid du Colombier 		if(c != -1)	/* valid sequence */
489*277b6efdSDavid du Colombier 			kbdputc(kbdq, c);
490*277b6efdSDavid du Colombier 		else	/* dump characters */
491*277b6efdSDavid du Colombier 			for(i=0; i<kbscan->nk; i++)
492*277b6efdSDavid du Colombier 				kbdputc(kbdq, kbscan->kc[i]);
493*277b6efdSDavid du Colombier 		kbscan->nk = 0;
494*277b6efdSDavid du Colombier 		kbscan->collecting = 0;
495*277b6efdSDavid du Colombier 		return;
496*277b6efdSDavid du Colombier 	} else {
497*277b6efdSDavid du Colombier 		switch(c){
498*277b6efdSDavid du Colombier 		case Caps:
499*277b6efdSDavid du Colombier 			kbscan->caps ^= 1;
500*277b6efdSDavid du Colombier 			return;
501*277b6efdSDavid du Colombier 		case Num:
502*277b6efdSDavid du Colombier 			kbscan->num ^= 1;
503*277b6efdSDavid du Colombier 			if(!external)
504*277b6efdSDavid du Colombier 				setleds(kbscan);
505*277b6efdSDavid du Colombier 			return;
506*277b6efdSDavid du Colombier 		case Shift:
507*277b6efdSDavid du Colombier 			kbscan->shift = 1;
508*277b6efdSDavid du Colombier 			if(kdebug)
509*277b6efdSDavid du Colombier 				print("shift\n");
510*277b6efdSDavid du Colombier 			mouseshifted = 1;
511*277b6efdSDavid du Colombier 			return;
512*277b6efdSDavid du Colombier 		case Latin:
513*277b6efdSDavid du Colombier 			kbscan->alt = 1;
514*277b6efdSDavid du Colombier 			/*
515*277b6efdSDavid du Colombier 			 * VMware and Qemu use Ctl-Alt as the key combination
516*277b6efdSDavid du Colombier 			 * to make the VM give up keyboard and mouse focus.
517*277b6efdSDavid du Colombier 			 * This has the unfortunate side effect that when you
518*277b6efdSDavid du Colombier 			 * come back into focus, Plan 9 thinks you want to type
519*277b6efdSDavid du Colombier 			 * a compose sequence (you just typed alt).
520*277b6efdSDavid du Colombier 			 *
521*277b6efdSDavid du Colombier 			 * As a clumsy hack around this, we look for ctl-alt
522*277b6efdSDavid du Colombier 			 * and don't treat it as the start of a compose sequence.
523*277b6efdSDavid du Colombier 			 */
524*277b6efdSDavid du Colombier 			if(!kbscan->ctl){
525*277b6efdSDavid du Colombier 				kbscan->collecting = 1;
526*277b6efdSDavid du Colombier 				kbscan->nk = 0;
527*277b6efdSDavid du Colombier 			}
528*277b6efdSDavid du Colombier 			return;
529*277b6efdSDavid du Colombier 		case Ctrl:
530*277b6efdSDavid du Colombier 			kbscan->ctl = 1;
531*277b6efdSDavid du Colombier 			return;
532*277b6efdSDavid du Colombier 		case Altgr:
533*277b6efdSDavid du Colombier 			kbscan->altgr = 1;
534*277b6efdSDavid du Colombier 			return;
535*277b6efdSDavid du Colombier 		case Kmouse|1:
536*277b6efdSDavid du Colombier 		case Kmouse|2:
537*277b6efdSDavid du Colombier 		case Kmouse|3:
538*277b6efdSDavid du Colombier 		case Kmouse|4:
539*277b6efdSDavid du Colombier 		case Kmouse|5:
540*277b6efdSDavid du Colombier 			kbscan->buttons |= 1<<(c-Kmouse-1);
541*277b6efdSDavid du Colombier 			if(kbdmouse)
542*277b6efdSDavid du Colombier 				kbdmouse(kbscan->buttons);
543*277b6efdSDavid du Colombier 			return;
544*277b6efdSDavid du Colombier 		case KF|11:
545*277b6efdSDavid du Colombier 			print("kbd debug on, F12 turns it off\n");
546*277b6efdSDavid du Colombier 			kdebug = 1;
547*277b6efdSDavid du Colombier 			break;
548*277b6efdSDavid du Colombier 		case KF|12:
549*277b6efdSDavid du Colombier 			kdebug = 0;
550*277b6efdSDavid du Colombier 			break;
5519ef1f84bSDavid du Colombier 		}
5529ef1f84bSDavid du Colombier 	}
5539ef1f84bSDavid du Colombier 	kbdputc(kbdq, c);
5549ef1f84bSDavid du Colombier }
5559ef1f84bSDavid du Colombier 
i8042intr(Ureg *,void *)5569ef1f84bSDavid du Colombier /*
5579ef1f84bSDavid du Colombier  *  keyboard interrupt
558*277b6efdSDavid du Colombier  */
5599ef1f84bSDavid du Colombier static void
5609ef1f84bSDavid du Colombier i8042intr(Ureg*, void*)
5619ef1f84bSDavid du Colombier {
5629ef1f84bSDavid du Colombier 	int s, c;
5639ef1f84bSDavid du Colombier 
5649ef1f84bSDavid du Colombier 	/*
5659ef1f84bSDavid du Colombier 	 *  get status
5669ef1f84bSDavid du Colombier 	 */
5679ef1f84bSDavid du Colombier 	ilock(&i8042lock);
5689ef1f84bSDavid du Colombier 	s = inb(Status);
5699ef1f84bSDavid du Colombier 	if(!(s&Inready)){
5709ef1f84bSDavid du Colombier 		iunlock(&i8042lock);
5719ef1f84bSDavid du Colombier 		return;
5729ef1f84bSDavid du Colombier 	}
5739ef1f84bSDavid du Colombier 
5749ef1f84bSDavid du Colombier 	/*
5759ef1f84bSDavid du Colombier 	 *  get the character
5769ef1f84bSDavid du Colombier 	 */
5779ef1f84bSDavid du Colombier 	c = inb(Data);
5789ef1f84bSDavid du Colombier 	iunlock(&i8042lock);
5799ef1f84bSDavid du Colombier 
5809ef1f84bSDavid du Colombier 	/*
581*277b6efdSDavid du Colombier 	 *  if it's the aux port...
5829ef1f84bSDavid du Colombier 	 */
5839ef1f84bSDavid du Colombier 	if(s & Minready){
5849ef1f84bSDavid du Colombier 		if(auxputc != nil)
585*277b6efdSDavid du Colombier 			auxputc(c, kbscans[Int].shift);
5869ef1f84bSDavid du Colombier 		return;
5879ef1f84bSDavid du Colombier 	}
5889ef1f84bSDavid du Colombier 
5899ef1f84bSDavid du Colombier 	kbdputsc(c, Int);
5909ef1f84bSDavid du Colombier }
5919ef1f84bSDavid du Colombier 
5929ef1f84bSDavid du Colombier void
5939ef1f84bSDavid du Colombier i8042auxenable(void (*putc)(int, int))
5949ef1f84bSDavid du Colombier {
5959ef1f84bSDavid du Colombier 	char *err = "i8042: aux init failed\n";
5969ef1f84bSDavid du Colombier 
5979ef1f84bSDavid du Colombier 	/* enable kbd/aux xfers and interrupts */
5989ef1f84bSDavid du Colombier 	ccc &= ~Cauxdis;
5999ef1f84bSDavid du Colombier 	ccc |= Cauxint;
6009ef1f84bSDavid du Colombier 
6019ef1f84bSDavid du Colombier 	ilock(&i8042lock);
6029ef1f84bSDavid du Colombier 	if(outready() < 0)
6039ef1f84bSDavid du Colombier 		print(err);
6049ef1f84bSDavid du Colombier 	outb(Cmd, 0x60);			/* write control register */
6059ef1f84bSDavid du Colombier 	if(outready() < 0)
606*277b6efdSDavid du Colombier 		print(err);
6079ef1f84bSDavid du Colombier 	outb(Data, ccc);
6089ef1f84bSDavid du Colombier 	if(outready() < 0)
6099ef1f84bSDavid du Colombier 		print(err);
6109ef1f84bSDavid du Colombier 	outb(Cmd, 0xA8);			/* auxiliary device enable */
6119ef1f84bSDavid du Colombier 	if(outready() < 0){
6129ef1f84bSDavid du Colombier 		iunlock(&i8042lock);
6139ef1f84bSDavid du Colombier 		return;
6149ef1f84bSDavid du Colombier 	}
6159ef1f84bSDavid du Colombier 	auxputc = putc;
6169ef1f84bSDavid du Colombier 	intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
6179ef1f84bSDavid du Colombier 	iunlock(&i8042lock);
6189ef1f84bSDavid du Colombier }
outbyte(int port,int c)6199ef1f84bSDavid du Colombier 
6209ef1f84bSDavid du Colombier static char *initfailed = "i8042: kbdinit failed\n";
6219ef1f84bSDavid du Colombier 
6229ef1f84bSDavid du Colombier static int
6239ef1f84bSDavid du Colombier outbyte(int port, int c)
6249ef1f84bSDavid du Colombier {
6259ef1f84bSDavid du Colombier 	outb(port, c);
6269ef1f84bSDavid du Colombier 	if(outready() < 0) {
6279ef1f84bSDavid du Colombier 		print(initfailed);
6289ef1f84bSDavid du Colombier 		return -1;
6299ef1f84bSDavid du Colombier 	}
kbdinit(void)6309ef1f84bSDavid du Colombier 	return 0;
6319ef1f84bSDavid du Colombier }
6329ef1f84bSDavid du Colombier 
6339ef1f84bSDavid du Colombier void
6349ef1f84bSDavid du Colombier kbdinit(void)
635*277b6efdSDavid du Colombier {
6369ef1f84bSDavid du Colombier 	int c, try;
6379ef1f84bSDavid du Colombier 
6389ef1f84bSDavid du Colombier 	/* wait for a quiescent controller */
6399ef1f84bSDavid du Colombier 	try = 500;
6409ef1f84bSDavid du Colombier 	while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
6419ef1f84bSDavid du Colombier 		if(c & Inready)
6429ef1f84bSDavid du Colombier 			inb(Data);
6439ef1f84bSDavid du Colombier 		delay(1);
6449ef1f84bSDavid du Colombier 	}
6459ef1f84bSDavid du Colombier 	if (try <= 0) {
6469ef1f84bSDavid du Colombier 		print(initfailed);
6479ef1f84bSDavid du Colombier 		return;
6489ef1f84bSDavid du Colombier 	}
6499ef1f84bSDavid du Colombier 
6509ef1f84bSDavid du Colombier 	/* get current controller command byte */
6519ef1f84bSDavid du Colombier 	outb(Cmd, 0x20);
6529ef1f84bSDavid du Colombier 	if(inready() < 0){
6539ef1f84bSDavid du Colombier 		print("i8042: kbdinit can't read ccc\n");
6549ef1f84bSDavid du Colombier 		ccc = 0;
6559ef1f84bSDavid du Colombier 	} else
6569ef1f84bSDavid du Colombier 		ccc = inb(Data);
6579ef1f84bSDavid du Colombier 
6589ef1f84bSDavid du Colombier 	/* enable kbd xfers and interrupts */
6599ef1f84bSDavid du Colombier 	ccc &= ~Ckbddis;
6609ef1f84bSDavid du Colombier 	ccc |= Csf | Ckbdint | Cscs1;
6619ef1f84bSDavid du Colombier 	if(outready() < 0) {
6629ef1f84bSDavid du Colombier 		print(initfailed);
6639ef1f84bSDavid du Colombier 		return;
6649ef1f84bSDavid du Colombier 	}
6659ef1f84bSDavid du Colombier 
6669ef1f84bSDavid du Colombier 	nokbd = 0;
667*277b6efdSDavid du Colombier 
668*277b6efdSDavid du Colombier 	/* disable mouse */
669*277b6efdSDavid du Colombier 	if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0)
670*277b6efdSDavid du Colombier 		print("i8042: kbdinit mouse disable failed\n");
671*277b6efdSDavid du Colombier 
672*277b6efdSDavid du Colombier 	/* see http://www.computer-engineering.org/ps2keyboard for codes */
6739ef1f84bSDavid du Colombier 	if(getconf("*typematic") != nil)
6749ef1f84bSDavid du Colombier 		/* set typematic rate/delay (0 -> delay=250ms & rate=30cps) */
6759ef1f84bSDavid du Colombier 		if(outbyte(Data, 0xf3) < 0 || outbyte(Data, 0) < 0)
kbdenable(void)6769ef1f84bSDavid du Colombier 			print("i8042: kbdinit set typematic rate failed\n");
6779ef1f84bSDavid du Colombier }
6789ef1f84bSDavid du Colombier 
6799ef1f84bSDavid du Colombier void
6809ef1f84bSDavid du Colombier kbdenable(void)
6819ef1f84bSDavid du Colombier {
6829ef1f84bSDavid du Colombier 	kbdq = qopen(4*1024, 0, 0, 0);
6839ef1f84bSDavid du Colombier 	if(kbdq == nil)
6849ef1f84bSDavid du Colombier 		panic("kbdinit");
6859ef1f84bSDavid du Colombier 	qnoblock(kbdq, 1);
6869ef1f84bSDavid du Colombier 	addkbdq(kbdq, -1);
6879ef1f84bSDavid du Colombier 
688*277b6efdSDavid du Colombier 	ioalloc(Data, 1, 0, "kbd");
689*277b6efdSDavid du Colombier 	ioalloc(Cmd, 1, 0, "kbd");
690*277b6efdSDavid du Colombier 
6919ef1f84bSDavid du Colombier 	intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
6929ef1f84bSDavid du Colombier 
6939ef1f84bSDavid du Colombier 	kbscans[Int].num = 0;
kbdputmap(ushort m,ushort scanc,Rune r)6949ef1f84bSDavid du Colombier 	setleds(&kbscans[Int]);
6959ef1f84bSDavid du Colombier }
6969ef1f84bSDavid du Colombier 
6979ef1f84bSDavid du Colombier void
6989ef1f84bSDavid du Colombier kbdputmap(ushort m, ushort scanc, Rune r)
6999ef1f84bSDavid du Colombier {
7009ef1f84bSDavid du Colombier 	if(scanc >= Nscan)
7019ef1f84bSDavid du Colombier 		error(Ebadarg);
7029ef1f84bSDavid du Colombier 	switch(m) {
7039ef1f84bSDavid du Colombier 	default:
7049ef1f84bSDavid du Colombier 		error(Ebadarg);
7059ef1f84bSDavid du Colombier 	case 0:
7069ef1f84bSDavid du Colombier 		kbtab[scanc] = r;
7079ef1f84bSDavid du Colombier 		break;
7089ef1f84bSDavid du Colombier 	case 1:
7099ef1f84bSDavid du Colombier 		kbtabshift[scanc] = r;
7109ef1f84bSDavid du Colombier 		break;
7119ef1f84bSDavid du Colombier 	case 2:
7129ef1f84bSDavid du Colombier 		kbtabesc1[scanc] = r;
7139ef1f84bSDavid du Colombier 		break;
7149ef1f84bSDavid du Colombier 	case 3:
7159ef1f84bSDavid du Colombier 		kbtabaltgr[scanc] = r;
7169ef1f84bSDavid du Colombier 		break;
7179ef1f84bSDavid du Colombier 	case 4:
7189ef1f84bSDavid du Colombier 		kbtabctrl[scanc] = r;
7199ef1f84bSDavid du Colombier 		break;
kbdgetmap(uint offset,int * t,int * sc,Rune * r)720*277b6efdSDavid du Colombier 	}
7219ef1f84bSDavid du Colombier }
722*277b6efdSDavid du Colombier 
723*277b6efdSDavid du Colombier int
7249ef1f84bSDavid du Colombier kbdgetmap(uint offset, int *t, int *sc, Rune *r)
7259ef1f84bSDavid du Colombier {
7269ef1f84bSDavid du Colombier 	if ((int)offset < 0)
7279ef1f84bSDavid du Colombier 		error(Ebadarg);
7289ef1f84bSDavid du Colombier 	*t = offset/Nscan;
7299ef1f84bSDavid du Colombier 	*sc = offset%Nscan;
7309ef1f84bSDavid du Colombier 	switch(*t) {
7319ef1f84bSDavid du Colombier 	default:
7329ef1f84bSDavid du Colombier 		return 0;
7339ef1f84bSDavid du Colombier 	case 0:
7349ef1f84bSDavid du Colombier 		*r = kbtab[*sc];
7359ef1f84bSDavid du Colombier 		return 1;
7369ef1f84bSDavid du Colombier 	case 1:
7379ef1f84bSDavid du Colombier 		*r = kbtabshift[*sc];
7389ef1f84bSDavid du Colombier 		return 1;
7399ef1f84bSDavid du Colombier 	case 2:
7409ef1f84bSDavid du Colombier 		*r = kbtabesc1[*sc];
7419ef1f84bSDavid du Colombier 		return 1;
7429ef1f84bSDavid du Colombier 	case 3:
7439ef1f84bSDavid du Colombier 		*r = kbtabaltgr[*sc];
7449ef1f84bSDavid du Colombier 		return 1;
7459ef1f84bSDavid du Colombier 	case 4:
746 		*r = kbtabctrl[*sc];
747 		return 1;
748 	}
749 }
750