17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56ee4b8d7Ssetje  * Common Development and Distribution License (the "License").
66ee4b8d7Ssetje  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22ae115bc7Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Miniature keyboard driver for bootstrap.  This allows keyboard
287c478bd9Sstevel@tonic-gate  * support to continue after we take over interrupts and disable
297c478bd9Sstevel@tonic-gate  * BIOS keyboard support.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
33ae115bc7Smrj #include <sys/archsystm.h>
34ae115bc7Smrj #include <sys/boot_console.h>
35ae115bc7Smrj #include "boot_keyboard_table.h"
36ae115bc7Smrj 
37ae115bc7Smrj #if defined(_BOOT)
38843e1988Sjohnlev #include "dboot/dboot_asm.h"
39ae115bc7Smrj #include "dboot/dboot_xboot.h"
40843e1988Sjohnlev #endif /* _BOOT */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * Definitions for BIOS keyboard state.  We use BIOS's variable to store
447c478bd9Sstevel@tonic-gate  * state, ensuring that we stay in sync with it.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate #define	BIOS_KB_FLAG		0x417
477c478bd9Sstevel@tonic-gate #define	BIOS_RIGHT_SHIFT	0x01
487c478bd9Sstevel@tonic-gate #define	BIOS_LEFT_SHIFT		0x02
497c478bd9Sstevel@tonic-gate #define	BIOS_EITHER_SHIFT	(BIOS_LEFT_SHIFT | BIOS_RIGHT_SHIFT)
507c478bd9Sstevel@tonic-gate #define	BIOS_CTL_SHIFT		0x04
517c478bd9Sstevel@tonic-gate #define	BIOS_ALT_SHIFT		0x08
527c478bd9Sstevel@tonic-gate #define	BIOS_SCROLL_STATE	0x10
537c478bd9Sstevel@tonic-gate #define	BIOS_NUM_STATE		0x20
547c478bd9Sstevel@tonic-gate #define	BIOS_CAPS_STATE		0x40
557c478bd9Sstevel@tonic-gate #define	BIOS_INS_STATE		0x80
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #define	BIOS_KB_FLAG_1		0x418
587c478bd9Sstevel@tonic-gate #define	BIOS_SYS_SHIFT		0x04
597c478bd9Sstevel@tonic-gate #define	BIOS_HOLD_STATE		0x08
607c478bd9Sstevel@tonic-gate #define	BIOS_SCROLL_SHIFT	0x10
617c478bd9Sstevel@tonic-gate #define	BIOS_NUM_SHIFT		0x20
627c478bd9Sstevel@tonic-gate #define	BIOS_CAPS_SHIFT		0x40
637c478bd9Sstevel@tonic-gate #define	BIOS_INS_SHIFT		0x80
647c478bd9Sstevel@tonic-gate 
65843e1988Sjohnlev #if defined(__xpv) && defined(_BOOT)
66843e1988Sjohnlev 
67843e1988Sjohnlev /*
68843e1988Sjohnlev  * Device memory addresses
69843e1988Sjohnlev  *
70843e1988Sjohnlev  * In dboot under the hypervisor we don't have any memory mappings
71843e1988Sjohnlev  * for the first meg of low memory so we can't access devices there.
72843e1988Sjohnlev  * Intead we've mapped the device memory that we need to access into
73843e1988Sjohnlev  * a local variable within dboot so we can access the device memory
74843e1988Sjohnlev  * there.
75843e1988Sjohnlev  */
76843e1988Sjohnlev extern unsigned short *kb_status;
77843e1988Sjohnlev #define	kb_flag		((unsigned char *)&kb_status[BIOS_KB_FLAG])
78843e1988Sjohnlev #define	kb_flag_1	((unsigned char *)&kb_status[BIOS_KB_FLAG_1])
79843e1988Sjohnlev 
80843e1988Sjohnlev #else /* __xpv && _BOOT */
81843e1988Sjohnlev 
82843e1988Sjohnlev /* Device memory addresses */
83*a34c59afSToomas Soome static unsigned char *kb_status = ((unsigned char *)BIOS_KB_FLAG);
84*a34c59afSToomas Soome #define	kb_flag		(&kb_status[0])
85*a34c59afSToomas Soome #define	kb_flag_1	(&kb_status[1])
867c478bd9Sstevel@tonic-gate 
87843e1988Sjohnlev #endif /* __xpv && _BOOT */
88843e1988Sjohnlev 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * Keyboard controller registers
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate #define	I8042_DATA		0x60
937c478bd9Sstevel@tonic-gate #define	I8042_STAT		0x64
947c478bd9Sstevel@tonic-gate #define	I8042_CMD		0x64
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * Keyboard controller status register bits
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate #define	I8042_STAT_OUTBF	0x01
1007c478bd9Sstevel@tonic-gate #define	I8042_STAT_INBF		0x02
1017c478bd9Sstevel@tonic-gate #define	I8042_STAT_AUXBF	0x20
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * Keyboard controller commands
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate #define	I8042_RCB		0x20
1077c478bd9Sstevel@tonic-gate #define	I8042_WCB		0x60
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * Keyboard commands
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate #define	KB_SET_LED		0xED	/* LED byte follows... */
1137c478bd9Sstevel@tonic-gate #define	KB_LED_SCROLL_LOCK	0x01	/* Bits for LED byte */
1147c478bd9Sstevel@tonic-gate #define	KB_LED_NUM_LOCK		0x02
1157c478bd9Sstevel@tonic-gate #define	KB_LED_CAPS_LOCK	0x04
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate #ifndef ASSERT
1187c478bd9Sstevel@tonic-gate #define	ASSERT(x)
1197c478bd9Sstevel@tonic-gate #endif
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate #define	peek8(p)	(*(p))
1227c478bd9Sstevel@tonic-gate #define	poke8(p, val)	(*(p) = (val))
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static struct {
1257c478bd9Sstevel@tonic-gate 	boolean_t	initialized;
1267c478bd9Sstevel@tonic-gate 	enum { KB_LED_IDLE, KB_LED_COMMAND_SENT, KB_LED_VALUE_SENT }
1277c478bd9Sstevel@tonic-gate 			led_state;
1287c478bd9Sstevel@tonic-gate 	int		led_commanded;
1297c478bd9Sstevel@tonic-gate 	/*
1307c478bd9Sstevel@tonic-gate 	 * Possible values:
1317c478bd9Sstevel@tonic-gate 	 *
1327c478bd9Sstevel@tonic-gate 	 * -1		Nothing pending
1337c478bd9Sstevel@tonic-gate 	 * 0x000-0x0ff	Pending byte
1347c478bd9Sstevel@tonic-gate 	 * 0x100-0x1ff	Needs leading zero, then low byte next.
1357c478bd9Sstevel@tonic-gate 	 *
1367c478bd9Sstevel@tonic-gate 	 * Others undefined.
1377c478bd9Sstevel@tonic-gate 	 */
1387c478bd9Sstevel@tonic-gate 	int		pending;
1397c478bd9Sstevel@tonic-gate } kb = {
1407c478bd9Sstevel@tonic-gate 	B_FALSE,	/* initialized? */
1417c478bd9Sstevel@tonic-gate 	KB_LED_IDLE,	/* LED command state */
1427c478bd9Sstevel@tonic-gate 	-1,		/* commanded LEDs - force refresh */
1437c478bd9Sstevel@tonic-gate 	-1,		/* pending */
1447c478bd9Sstevel@tonic-gate };
1457c478bd9Sstevel@tonic-gate 
146ead1aeb9SToomas Soome #define	KTAB_STRLEN 3
147ead1aeb9SToomas Soome static char keystringtab[KTAB_STRLEN] = {'\033', '[', ' '};
148ead1aeb9SToomas Soome static int keystring = -1;
149ead1aeb9SToomas Soome 
1507c478bd9Sstevel@tonic-gate static int kb_translate(unsigned char code);
1517c478bd9Sstevel@tonic-gate static void kb_send(unsigned char cmd);
1527c478bd9Sstevel@tonic-gate static void kb_update_leds(void);
1537c478bd9Sstevel@tonic-gate static uchar_t kb_calculate_leds(void);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate int
kb_getchar(void)1567c478bd9Sstevel@tonic-gate kb_getchar(void)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	int ret;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	while (!kb_ischar())
1617c478bd9Sstevel@tonic-gate 		/* LOOP */;
1627c478bd9Sstevel@tonic-gate 
163ead1aeb9SToomas Soome 	if (keystring >= 0) {
164ead1aeb9SToomas Soome 		ret = keystringtab[keystring++];
165ead1aeb9SToomas Soome 		if (keystring == KTAB_STRLEN) {
166ead1aeb9SToomas Soome 			keystring = -1;
167ead1aeb9SToomas Soome 			kb.pending = -1;
168ead1aeb9SToomas Soome 		}
169ead1aeb9SToomas Soome 		return (ret);
170ead1aeb9SToomas Soome 	}
171ead1aeb9SToomas Soome 
1727c478bd9Sstevel@tonic-gate 	/*
1737c478bd9Sstevel@tonic-gate 	 * kb_ischar() doesn't succeed without leaving kb.pending
1747c478bd9Sstevel@tonic-gate 	 * set.
1757c478bd9Sstevel@tonic-gate 	 */
1767c478bd9Sstevel@tonic-gate 	ASSERT(kb.pending >= 0);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (kb.pending & 0x100) {
1797c478bd9Sstevel@tonic-gate 		kb.pending &= 0xff;
180ead1aeb9SToomas Soome 		switch (kb.pending) {
181ead1aeb9SToomas Soome 		case 'H':		/* Up */
182ead1aeb9SToomas Soome 			keystringtab[2] = 'A';
183ead1aeb9SToomas Soome 			keystring = 0;
184ead1aeb9SToomas Soome 			return (kb_getchar());
185ead1aeb9SToomas Soome 		case 'P':		/* Down */
186ead1aeb9SToomas Soome 			keystringtab[2] = 'B';
187ead1aeb9SToomas Soome 			keystring = 0;
188ead1aeb9SToomas Soome 			return (kb_getchar());
189ead1aeb9SToomas Soome 		case 'M':		/* Right */
190ead1aeb9SToomas Soome 			keystringtab[2] = 'C';
191ead1aeb9SToomas Soome 			keystring = 0;
192ead1aeb9SToomas Soome 			return (kb_getchar());
193ead1aeb9SToomas Soome 		case 'K':		/* Left */
194ead1aeb9SToomas Soome 			keystringtab[2] = 'D';
195ead1aeb9SToomas Soome 			keystring = 0;
196ead1aeb9SToomas Soome 			return (kb_getchar());
197ead1aeb9SToomas Soome 		default:
198ead1aeb9SToomas Soome 			ret = 0;
199ead1aeb9SToomas Soome 		}
2007c478bd9Sstevel@tonic-gate 	} else {
2017c478bd9Sstevel@tonic-gate 		ret = kb.pending;
2027c478bd9Sstevel@tonic-gate 		kb.pending = -1;
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	return (ret);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate int
kb_ischar(void)2097c478bd9Sstevel@tonic-gate kb_ischar(void)
2107c478bd9Sstevel@tonic-gate {
2117c478bd9Sstevel@tonic-gate 	unsigned char buffer_stat;
2127c478bd9Sstevel@tonic-gate 	unsigned char code;
2137c478bd9Sstevel@tonic-gate 	unsigned char leds;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	if (!kb.initialized) {
2167c478bd9Sstevel@tonic-gate 		kb_init();
2177c478bd9Sstevel@tonic-gate 		kb.initialized = B_TRUE;
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	if (kb.pending >= 0)
2217c478bd9Sstevel@tonic-gate 		return (1);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	for (;;) {
2246ee4b8d7Ssetje 		buffer_stat = inb(I8042_STAT);
2256ee4b8d7Ssetje 		if (buffer_stat == 0xff)
2266ee4b8d7Ssetje 			return (0);
2276ee4b8d7Ssetje 		buffer_stat &= (I8042_STAT_OUTBF | I8042_STAT_AUXBF);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		switch (buffer_stat) {
2307c478bd9Sstevel@tonic-gate 		case 0:
2317c478bd9Sstevel@tonic-gate 		case I8042_STAT_AUXBF:
2327c478bd9Sstevel@tonic-gate 			return (0);
2337c478bd9Sstevel@tonic-gate 		case (I8042_STAT_OUTBF | I8042_STAT_AUXBF):
2347c478bd9Sstevel@tonic-gate 			/*
2357c478bd9Sstevel@tonic-gate 			 * Discard unwanted mouse data.
2367c478bd9Sstevel@tonic-gate 			 */
2377c478bd9Sstevel@tonic-gate 			(void) inb(I8042_DATA);
2387c478bd9Sstevel@tonic-gate 			continue;
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 		code = inb(I8042_DATA);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 		switch (code) {
2447c478bd9Sstevel@tonic-gate 		/*
2457c478bd9Sstevel@tonic-gate 		 * case 0xAA:
2467c478bd9Sstevel@tonic-gate 		 *
2477c478bd9Sstevel@tonic-gate 		 * You might think that we should ignore 0xAA on the
2487c478bd9Sstevel@tonic-gate 		 * grounds that it is the BAT Complete response and will
2497c478bd9Sstevel@tonic-gate 		 * occur on keyboard detach/reattach.  Unfortunately,
2507c478bd9Sstevel@tonic-gate 		 * it is ambiguous - this is also the code for a break
2517c478bd9Sstevel@tonic-gate 		 * of the left shift key.  Since it will be harmless for
2527c478bd9Sstevel@tonic-gate 		 * us to "spuriously" process a break of Left Shift,
2537c478bd9Sstevel@tonic-gate 		 * we just let the normal code handle it.  Perhaps we
2547c478bd9Sstevel@tonic-gate 		 * should take a hint and refresh the LEDs, but I
2557c478bd9Sstevel@tonic-gate 		 * refuse to get very worried about hot-plug issues
2567c478bd9Sstevel@tonic-gate 		 * in this mini-driver.
2577c478bd9Sstevel@tonic-gate 		 */
2587c478bd9Sstevel@tonic-gate 		case 0xFA:
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 			switch (kb.led_state) {
2617c478bd9Sstevel@tonic-gate 			case KB_LED_IDLE:
2627c478bd9Sstevel@tonic-gate 				/*
2637c478bd9Sstevel@tonic-gate 				 * Spurious.  Oh well, ignore it.
2647c478bd9Sstevel@tonic-gate 				 */
2657c478bd9Sstevel@tonic-gate 				break;
2667c478bd9Sstevel@tonic-gate 			case KB_LED_COMMAND_SENT:
2677c478bd9Sstevel@tonic-gate 				leds = kb_calculate_leds();
2687c478bd9Sstevel@tonic-gate 				kb_send(leds);
2697c478bd9Sstevel@tonic-gate 				kb.led_commanded = leds;
2707c478bd9Sstevel@tonic-gate 				kb.led_state = KB_LED_VALUE_SENT;
2717c478bd9Sstevel@tonic-gate 				break;
2727c478bd9Sstevel@tonic-gate 			case KB_LED_VALUE_SENT:
2737c478bd9Sstevel@tonic-gate 				kb.led_state = KB_LED_IDLE;
2747c478bd9Sstevel@tonic-gate 				/*
2757c478bd9Sstevel@tonic-gate 				 * Check for changes made while we were
2767c478bd9Sstevel@tonic-gate 				 * working on the last change.
2777c478bd9Sstevel@tonic-gate 				 */
2787c478bd9Sstevel@tonic-gate 				kb_update_leds();
2797c478bd9Sstevel@tonic-gate 				break;
2807c478bd9Sstevel@tonic-gate 			}
2817c478bd9Sstevel@tonic-gate 			continue;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		case 0xE0:
2847c478bd9Sstevel@tonic-gate 		case 0xE1:
2857c478bd9Sstevel@tonic-gate 			/*
2867c478bd9Sstevel@tonic-gate 			 * These are used to distinguish the keys added on
2877c478bd9Sstevel@tonic-gate 			 * the AT-101 keyboard from the original 84 keys.
2887c478bd9Sstevel@tonic-gate 			 * We don't care, and the codes are carefully arranged
2897c478bd9Sstevel@tonic-gate 			 * so that we don't have to.
2907c478bd9Sstevel@tonic-gate 			 */
2917c478bd9Sstevel@tonic-gate 			continue;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 		default:
2947c478bd9Sstevel@tonic-gate 			if (code & 0x80) {
2957c478bd9Sstevel@tonic-gate 				/* Release */
2967c478bd9Sstevel@tonic-gate 				code &= 0x7f;
2977c478bd9Sstevel@tonic-gate 				switch (keyboard_translate[code].normal) {
2987c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_LSHIFT:
2997c478bd9Sstevel@tonic-gate 					poke8(kb_flag, peek8(kb_flag) &
3007c478bd9Sstevel@tonic-gate 					    ~BIOS_LEFT_SHIFT);
3017c478bd9Sstevel@tonic-gate 					break;
3027c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_RSHIFT:
3037c478bd9Sstevel@tonic-gate 					poke8(kb_flag, peek8(kb_flag) &
3047c478bd9Sstevel@tonic-gate 					    ~BIOS_RIGHT_SHIFT);
3057c478bd9Sstevel@tonic-gate 					break;
3067c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_CTRL:
3077c478bd9Sstevel@tonic-gate 					poke8(kb_flag, peek8(kb_flag) &
3087c478bd9Sstevel@tonic-gate 					    ~BIOS_CTL_SHIFT);
3097c478bd9Sstevel@tonic-gate 					break;
3107c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_ALT:
3117c478bd9Sstevel@tonic-gate 					poke8(kb_flag, peek8(kb_flag) &
3127c478bd9Sstevel@tonic-gate 					    ~BIOS_ALT_SHIFT);
3137c478bd9Sstevel@tonic-gate 					break;
3147c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_CAPS_LOCK:
3157c478bd9Sstevel@tonic-gate 					poke8(kb_flag_1, peek8(kb_flag_1) &
3167c478bd9Sstevel@tonic-gate 					    ~BIOS_CAPS_SHIFT);
3177c478bd9Sstevel@tonic-gate 					break;
3187c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_NUM_LOCK:
3197c478bd9Sstevel@tonic-gate 					poke8(kb_flag_1, peek8(kb_flag_1) &
3207c478bd9Sstevel@tonic-gate 					    ~BIOS_NUM_SHIFT);
3217c478bd9Sstevel@tonic-gate 					break;
3227c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_SCROLL_LOCK:
3237c478bd9Sstevel@tonic-gate 					poke8(kb_flag_1, peek8(kb_flag_1) &
3247c478bd9Sstevel@tonic-gate 					    ~BIOS_SCROLL_SHIFT);
3257c478bd9Sstevel@tonic-gate 					break;
3267c478bd9Sstevel@tonic-gate 				default:
3277c478bd9Sstevel@tonic-gate 					/*
3287c478bd9Sstevel@tonic-gate 					 * Ignore all other releases.
3297c478bd9Sstevel@tonic-gate 					 */
3307c478bd9Sstevel@tonic-gate 					break;
3317c478bd9Sstevel@tonic-gate 				}
3327c478bd9Sstevel@tonic-gate 			} else {
3337c478bd9Sstevel@tonic-gate 				/* Press */
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 				kb.pending = kb_translate(code);
3367c478bd9Sstevel@tonic-gate 				if (kb.pending >= 0) {
3377c478bd9Sstevel@tonic-gate 					return (1);
3387c478bd9Sstevel@tonic-gate 				}
3397c478bd9Sstevel@tonic-gate 			}
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate int
kb_translate(unsigned char code)3457c478bd9Sstevel@tonic-gate kb_translate(unsigned char code)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 	struct keyboard_translate *k;
3487c478bd9Sstevel@tonic-gate 	unsigned short action;
3497c478bd9Sstevel@tonic-gate 	boolean_t shifted;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	k = keyboard_translate + code;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	shifted = (peek8(kb_flag) & BIOS_EITHER_SHIFT) != 0;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	switch (k->normal & 0xFF00) {
3567c478bd9Sstevel@tonic-gate 	case KBTYPE_NUMPAD:
3577c478bd9Sstevel@tonic-gate 		if (peek8(kb_flag) & BIOS_NUM_STATE)
3587c478bd9Sstevel@tonic-gate 			shifted = !shifted;
3597c478bd9Sstevel@tonic-gate 		break;
3607c478bd9Sstevel@tonic-gate 	case KBTYPE_ALPHA:
3617c478bd9Sstevel@tonic-gate 		if (peek8(kb_flag) & BIOS_CAPS_STATE)
3627c478bd9Sstevel@tonic-gate 			shifted = !shifted;
3637c478bd9Sstevel@tonic-gate 		break;
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (peek8(kb_flag) & BIOS_ALT_SHIFT)
3677c478bd9Sstevel@tonic-gate 		action = k->alted;
3687c478bd9Sstevel@tonic-gate 	else if (peek8(kb_flag) & BIOS_CTL_SHIFT)
3697c478bd9Sstevel@tonic-gate 		action = k->ctrled;
3707c478bd9Sstevel@tonic-gate 	else if (shifted)
3717c478bd9Sstevel@tonic-gate 		action = k->shifted;
3727c478bd9Sstevel@tonic-gate 	else
3737c478bd9Sstevel@tonic-gate 		action = k->normal;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	switch (action & 0xFF00) {
3767c478bd9Sstevel@tonic-gate 	case KBTYPE_NORMAL:
3777c478bd9Sstevel@tonic-gate 	case KBTYPE_ALPHA:
3787c478bd9Sstevel@tonic-gate 		return (action & 0xFF);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	case KBTYPE_NUMPAD:
3817c478bd9Sstevel@tonic-gate 	case KBTYPE_FUNC:
3827c478bd9Sstevel@tonic-gate 		return ((action & 0xFF) | 0x100);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC:
3857c478bd9Sstevel@tonic-gate 		break;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	default:
3887c478bd9Sstevel@tonic-gate 		/*
3897c478bd9Sstevel@tonic-gate 		 * Bad entry.
3907c478bd9Sstevel@tonic-gate 		 */
3917c478bd9Sstevel@tonic-gate 		ASSERT(0);
3927c478bd9Sstevel@tonic-gate 		return (-1);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/*
3967c478bd9Sstevel@tonic-gate 	 * Handle special keys, mostly shifts.
3977c478bd9Sstevel@tonic-gate 	 */
3987c478bd9Sstevel@tonic-gate 	switch (action) {
3997c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_NOP:
4007c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_UNDEF:
4017c478bd9Sstevel@tonic-gate 		break;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_LSHIFT:
4047c478bd9Sstevel@tonic-gate 		poke8(kb_flag, peek8(kb_flag) | BIOS_LEFT_SHIFT);
4057c478bd9Sstevel@tonic-gate 		break;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_RSHIFT:
4087c478bd9Sstevel@tonic-gate 		poke8(kb_flag, peek8(kb_flag) | BIOS_RIGHT_SHIFT);
4097c478bd9Sstevel@tonic-gate 		break;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_CTRL:
4127c478bd9Sstevel@tonic-gate 		poke8(kb_flag, peek8(kb_flag) | BIOS_CTL_SHIFT);
4137c478bd9Sstevel@tonic-gate 		break;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_ALT:
4167c478bd9Sstevel@tonic-gate 		poke8(kb_flag, peek8(kb_flag) | BIOS_ALT_SHIFT);
4177c478bd9Sstevel@tonic-gate 		break;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_CAPS_LOCK:
4207c478bd9Sstevel@tonic-gate 		if (!(peek8(kb_flag_1) & BIOS_CAPS_SHIFT)) {
4217c478bd9Sstevel@tonic-gate 			poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_CAPS_SHIFT);
4227c478bd9Sstevel@tonic-gate 			poke8(kb_flag, peek8(kb_flag) ^ BIOS_CAPS_STATE);
4237c478bd9Sstevel@tonic-gate 		}
4247c478bd9Sstevel@tonic-gate 		break;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_NUM_LOCK:
4277c478bd9Sstevel@tonic-gate 		if (!(peek8(kb_flag_1) & BIOS_NUM_SHIFT)) {
4287c478bd9Sstevel@tonic-gate 			poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_NUM_SHIFT);
4297c478bd9Sstevel@tonic-gate 			poke8(kb_flag, peek8(kb_flag) ^ BIOS_NUM_STATE);
4307c478bd9Sstevel@tonic-gate 		}
4317c478bd9Sstevel@tonic-gate 		break;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_SCROLL_LOCK:
4347c478bd9Sstevel@tonic-gate 		if (!(peek8(kb_flag_1) & BIOS_SCROLL_SHIFT)) {
4357c478bd9Sstevel@tonic-gate 			poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_SCROLL_SHIFT);
4367c478bd9Sstevel@tonic-gate 			poke8(kb_flag, peek8(kb_flag) ^ BIOS_SCROLL_STATE);
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 		break;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_MAYBE_REBOOT:
441ae115bc7Smrj #if 0	/* Solaris doesn't reboot via ctrl-alt-del */
4427c478bd9Sstevel@tonic-gate 		if ((peek8(kb_flag) & (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) ==
4437c478bd9Sstevel@tonic-gate 		    (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) {
4447c478bd9Sstevel@tonic-gate 			reset();
4457c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
4467c478bd9Sstevel@tonic-gate 		}
447ae115bc7Smrj #endif
4487c478bd9Sstevel@tonic-gate 		break;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	default:
4517c478bd9Sstevel@tonic-gate 		/*
4527c478bd9Sstevel@tonic-gate 		 * Bad entry
4537c478bd9Sstevel@tonic-gate 		 */
4547c478bd9Sstevel@tonic-gate 		ASSERT(0);
4557c478bd9Sstevel@tonic-gate 		break;
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/*
4597c478bd9Sstevel@tonic-gate 	 * Consider updating the LEDs.  This does nothing if nothing
4607c478bd9Sstevel@tonic-gate 	 * needs to be done.
4617c478bd9Sstevel@tonic-gate 	 */
4627c478bd9Sstevel@tonic-gate 	kb_update_leds();
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	return (-1);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate void
kb_send(unsigned char cmd)4687c478bd9Sstevel@tonic-gate kb_send(unsigned char cmd)
4697c478bd9Sstevel@tonic-gate {
4706ee4b8d7Ssetje 	int retries;
4716ee4b8d7Ssetje 
4726ee4b8d7Ssetje 	for (retries = 0;
4736ee4b8d7Ssetje 	    (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000;
4746ee4b8d7Ssetje 	    retries++)
4757c478bd9Sstevel@tonic-gate 		/* LOOP */;
4767c478bd9Sstevel@tonic-gate 	outb(I8042_DATA, cmd);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate void
kb_update_leds(void)4807c478bd9Sstevel@tonic-gate kb_update_leds(void)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate 	if (kb.led_state != KB_LED_IDLE) {
4837c478bd9Sstevel@tonic-gate 		/*
4847c478bd9Sstevel@tonic-gate 		 * The state machine will take care of any additional
4857c478bd9Sstevel@tonic-gate 		 * changes that are necessary.
4867c478bd9Sstevel@tonic-gate 		 */
4877c478bd9Sstevel@tonic-gate 		return;
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (kb_calculate_leds() == kb.led_commanded) {
4917c478bd9Sstevel@tonic-gate 		kb.led_state = KB_LED_IDLE;
4927c478bd9Sstevel@tonic-gate 	} else {
4937c478bd9Sstevel@tonic-gate 		kb_send(KB_SET_LED);
4947c478bd9Sstevel@tonic-gate 		kb.led_state = KB_LED_COMMAND_SENT;
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate #define	MIMR_PORT	0x21	/* Mask register for master PIC */
4997c478bd9Sstevel@tonic-gate #define	MIMR_KB		2	/* Keyboard mask bit in master PIC */
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate void
kb_init(void)5027c478bd9Sstevel@tonic-gate kb_init(void)
5037c478bd9Sstevel@tonic-gate {
5047c478bd9Sstevel@tonic-gate 	/*
505843e1988Sjohnlev 	 * Resist the urge to muck with the keyboard/mouse.  Just assume
506843e1988Sjohnlev 	 * that the bios, grub, and any optional hypervisor have left
507843e1988Sjohnlev 	 * the keyboard in a sane and usable state.  Messing with it now
508843e1988Sjohnlev 	 * could result it making it unusuable, which would break early
509843e1988Sjohnlev 	 * kmdb debugging support.  Note that we don't actually need to
510843e1988Sjohnlev 	 * disable interrupts for the keyboard/mouse since we're already
511843e1988Sjohnlev 	 * in protected mode and we're not compeating with the bios for
512843e1988Sjohnlev 	 * keyboard access.  Also, we don't need to disable the mouse
513843e1988Sjohnlev 	 * port since our polled input routine will just drop any mouse
514843e1988Sjohnlev 	 * data that it recieves.
5157c478bd9Sstevel@tonic-gate 	 */
5167c478bd9Sstevel@tonic-gate 	kb_update_leds();
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate unsigned char
kb_calculate_leds(void)5207c478bd9Sstevel@tonic-gate kb_calculate_leds(void)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate 	int res;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	res = 0;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	if (peek8(kb_flag) & BIOS_CAPS_STATE)
5277c478bd9Sstevel@tonic-gate 		res |= KB_LED_CAPS_LOCK;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	if (peek8(kb_flag) & BIOS_NUM_STATE)
5307c478bd9Sstevel@tonic-gate 		res |= KB_LED_NUM_LOCK;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	if (peek8(kb_flag) & BIOS_SCROLL_STATE)
5337c478bd9Sstevel@tonic-gate 		res |= KB_LED_SCROLL_LOCK;
5347c478bd9Sstevel@tonic-gate 
535ae115bc7Smrj 	return ((char)res);
5367c478bd9Sstevel@tonic-gate }
537