| #include <linux/keyboard.h> | 
 |  | 
 | #include "defkeymap.c"	/* yeah I know it's bad -- Cort */ | 
 |  | 
 |  | 
 | unsigned char shfts, ctls, alts, caps; | 
 |  | 
 | #define	KBDATAP		0x60	/* kbd data port */ | 
 | #define	KBSTATUSPORT	0x61	/* kbd status */ | 
 | #define	KBSTATP		0x64	/* kbd status port */ | 
 | #define	KBINRDY		0x01 | 
 | #define	KBOUTRDY	0x02 | 
 |  | 
 | extern unsigned char inb(int port); | 
 | extern void outb(int port, char val); | 
 | extern void puts(const char *); | 
 | extern void puthex(unsigned long val); | 
 | extern void udelay(long x); | 
 |  | 
 | static int kbd(int noblock) | 
 | { | 
 | 	unsigned char dt, brk, val; | 
 | 	unsigned code; | 
 | loop: | 
 | 	if (noblock) { | 
 | 	    if ((inb(KBSTATP) & KBINRDY) == 0) | 
 | 		return (-1); | 
 | 	} else while((inb(KBSTATP) & KBINRDY) == 0) ; | 
 |  | 
 | 	dt = inb(KBDATAP); | 
 |  | 
 | 	brk = dt & 0x80;	/* brk == 1 on key release */ | 
 | 	dt = dt & 0x7f;		/* keycode */ | 
 |  | 
 | 	if (shfts) | 
 | 	    code = shift_map[dt]; | 
 | 	else if (ctls) | 
 | 	    code = ctrl_map[dt]; | 
 | 	else | 
 | 	    code = plain_map[dt]; | 
 |  | 
 | 	val = KVAL(code); | 
 | 	switch (KTYP(code) & 0x0f) { | 
 | 	    case KT_LATIN: | 
 | 		if (brk) | 
 | 		    break; | 
 | 		if (alts) | 
 | 		    val |= 0x80; | 
 | 		if (val == 0x7f)	/* map delete to backspace */ | 
 | 		    val = '\b'; | 
 | 		return val; | 
 |  | 
 | 	    case KT_LETTER: | 
 | 		if (brk) | 
 | 		    break; | 
 | 		if (caps) | 
 | 		    val -= 'a'-'A'; | 
 | 		return val; | 
 |  | 
 | 	    case KT_SPEC: | 
 | 		if (brk) | 
 | 		    break; | 
 | 		if (val == KVAL(K_CAPS)) | 
 | 		    caps = !caps; | 
 | 		else if (val == KVAL(K_ENTER)) { | 
 | enter:		    /* Wait for key up */ | 
 | 		    while (1) { | 
 | 			while((inb(KBSTATP) & KBINRDY) == 0) ; | 
 | 			dt = inb(KBDATAP); | 
 | 			if (dt & 0x80) /* key up */ break; | 
 | 		    } | 
 | 		    return 10; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	    case KT_PAD: | 
 | 		if (brk) | 
 | 		    break; | 
 | 		if (val < 10) | 
 | 		    return val; | 
 | 		if (val == KVAL(K_PENTER)) | 
 | 		    goto enter; | 
 | 		break; | 
 |  | 
 | 	    case KT_SHIFT: | 
 | 		switch (val) { | 
 | 		    case KG_SHIFT: | 
 | 		    case KG_SHIFTL: | 
 | 		    case KG_SHIFTR: | 
 | 			shfts = brk ? 0 : 1; | 
 | 			break; | 
 | 		    case KG_ALT: | 
 | 		    case KG_ALTGR: | 
 | 			alts = brk ? 0 : 1; | 
 | 			break; | 
 | 		    case KG_CTRL: | 
 | 		    case KG_CTRLL: | 
 | 		    case KG_CTRLR: | 
 | 			ctls = brk ? 0 : 1; | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	    case KT_LOCK: | 
 | 		switch (val) { | 
 | 		    case KG_SHIFT: | 
 | 		    case KG_SHIFTL: | 
 | 		    case KG_SHIFTR: | 
 | 			if (brk) | 
 | 			    shfts = !shfts; | 
 | 			break; | 
 | 		    case KG_ALT: | 
 | 		    case KG_ALTGR: | 
 | 			if (brk) | 
 | 			    alts = !alts; | 
 | 			break; | 
 | 		    case KG_CTRL: | 
 | 		    case KG_CTRLL: | 
 | 		    case KG_CTRLR: | 
 | 			if (brk) | 
 | 			    ctls = !ctls; | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 | 	} | 
 | 	if (brk) return (-1);  /* Ignore initial 'key up' codes */ | 
 | 	goto loop; | 
 | } | 
 |  | 
 | static int __kbdreset(void) | 
 | { | 
 | 	unsigned char c; | 
 | 	int i, t; | 
 |  | 
 | 	/* flush input queue */ | 
 | 	t = 2000; | 
 | 	while ((inb(KBSTATP) & KBINRDY)) | 
 | 	{ | 
 | 		(void)inb(KBDATAP); | 
 | 		if (--t == 0) | 
 | 			return 1; | 
 | 	} | 
 | 	/* Send self-test */ | 
 | 	t = 20000; | 
 | 	while (inb(KBSTATP) & KBOUTRDY) | 
 | 		if (--t == 0) | 
 | 			return 2; | 
 | 	outb(KBSTATP,0xAA); | 
 | 	t = 200000; | 
 | 	while ((inb(KBSTATP) & KBINRDY) == 0)	/* wait input ready */ | 
 | 		if (--t == 0) | 
 | 			return 3; | 
 | 	if ((c = inb(KBDATAP)) != 0x55) | 
 | 	{ | 
 | 		puts("Keyboard self test failed - result:"); | 
 | 		puthex(c); | 
 | 		puts("\n"); | 
 | 	} | 
 | 	/* Enable interrupts and keyboard controller */ | 
 | 	t = 20000; | 
 | 	while (inb(KBSTATP) & KBOUTRDY) | 
 | 		if (--t == 0) return 4; | 
 | 	outb(KBSTATP,0x60); | 
 | 	t = 20000; | 
 | 	while (inb(KBSTATP) & KBOUTRDY) | 
 | 		if (--t == 0) return 5; | 
 | 	outb(KBDATAP,0x45); | 
 | 	for (i = 0;  i < 10000;  i++) udelay(1); | 
 |  | 
 | 	t = 20000; | 
 | 	while (inb(KBSTATP) & KBOUTRDY) | 
 | 		if (--t == 0) return 6; | 
 | 	outb(KBSTATP,0x20); | 
 | 	t = 200000; | 
 | 	while ((inb(KBSTATP) & KBINRDY) == 0)	/* wait input ready */ | 
 | 		if (--t == 0) return 7; | 
 | 	if (! (inb(KBDATAP) & 0x40)) { | 
 | 		/* | 
 | 		 * Quote from PS/2 System Reference Manual: | 
 | 		 * | 
 | 		 * "Address hex 0060 and address hex 0064 should be | 
 | 		 * written only when the input-buffer-full bit and | 
 | 		 * output-buffer-full bit in the Controller Status | 
 | 		 * register are set 0." (KBINRDY and KBOUTRDY) | 
 | 		 */ | 
 | 		t = 200000; | 
 | 		while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) | 
 | 			if (--t == 0) return 8; | 
 | 		outb(KBDATAP,0xF0); | 
 | 		t = 200000; | 
 | 		while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) | 
 | 			if (--t == 0) return 9; | 
 | 		outb(KBDATAP,0x01); | 
 | 	} | 
 | 	t = 20000; | 
 | 	while (inb(KBSTATP) & KBOUTRDY) | 
 | 		if (--t == 0) return 10; | 
 | 	outb(KBSTATP,0xAE); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void kbdreset(void) | 
 | { | 
 | 	int ret = __kbdreset(); | 
 |  | 
 | 	if (ret) { | 
 | 		puts("__kbdreset failed: "); | 
 | 		puthex(ret); | 
 | 		puts("\n"); | 
 | 	} | 
 | } | 
 |  | 
 | /* We have to actually read the keyboard when CRT_tstc is called, | 
 |  * since the pending data might be a key release code, and therefore | 
 |  * not valid data.  In this case, kbd() will return -1, even though there's | 
 |  * data to be read.  Of course, we might actually read a valid key press, | 
 |  * in which case it gets queued into key_pending for use by CRT_getc. | 
 |  */ | 
 |  | 
 | static int kbd_reset = 0; | 
 |  | 
 | static int key_pending = -1; | 
 |  | 
 | int CRT_getc(void) | 
 | { | 
 | 	int c; | 
 | 	if (!kbd_reset) {kbdreset(); kbd_reset++; } | 
 |  | 
 |         if (key_pending != -1) { | 
 |                 c = key_pending; | 
 |                 key_pending = -1; | 
 |                 return c; | 
 |         } else { | 
 | 	while ((c = kbd(0)) == 0) ; | 
 |                 return c; | 
 |         } | 
 | } | 
 |  | 
 | int CRT_tstc(void) | 
 | { | 
 | 	if (!kbd_reset) {kbdreset(); kbd_reset++; } | 
 |  | 
 |         while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) { | 
 |                 key_pending = kbd(1); | 
 |         } | 
 |  | 
 |         return (key_pending != -1); | 
 | } |