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 /*
22*ae115bc7Smrj  * 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Miniature keyboard driver for bootstrap.  This allows keyboard
307c478bd9Sstevel@tonic-gate  * support to continue after we take over interrupts and disable
317c478bd9Sstevel@tonic-gate  * BIOS keyboard support.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*ae115bc7Smrj #include <sys/archsystm.h>
36*ae115bc7Smrj #include <sys/boot_console.h>
37*ae115bc7Smrj #include "boot_keyboard_table.h"
38*ae115bc7Smrj 
39*ae115bc7Smrj #if defined(_BOOT)
40*ae115bc7Smrj #include "dboot/dboot_xboot.h"
41*ae115bc7Smrj #endif
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * Definitions for BIOS keyboard state.  We use BIOS's variable to store
457c478bd9Sstevel@tonic-gate  * state, ensuring that we stay in sync with it.
467c478bd9Sstevel@tonic-gate  */
477c478bd9Sstevel@tonic-gate #define	BIOS_KB_FLAG		0x417
487c478bd9Sstevel@tonic-gate #define	BIOS_RIGHT_SHIFT	0x01
497c478bd9Sstevel@tonic-gate #define	BIOS_LEFT_SHIFT		0x02
507c478bd9Sstevel@tonic-gate #define	BIOS_EITHER_SHIFT	(BIOS_LEFT_SHIFT | BIOS_RIGHT_SHIFT)
517c478bd9Sstevel@tonic-gate #define	BIOS_CTL_SHIFT		0x04
527c478bd9Sstevel@tonic-gate #define	BIOS_ALT_SHIFT		0x08
537c478bd9Sstevel@tonic-gate #define	BIOS_SCROLL_STATE	0x10
547c478bd9Sstevel@tonic-gate #define	BIOS_NUM_STATE		0x20
557c478bd9Sstevel@tonic-gate #define	BIOS_CAPS_STATE		0x40
567c478bd9Sstevel@tonic-gate #define	BIOS_INS_STATE		0x80
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #define	BIOS_KB_FLAG_1		0x418
597c478bd9Sstevel@tonic-gate #define	BIOS_SYS_SHIFT		0x04
607c478bd9Sstevel@tonic-gate #define	BIOS_HOLD_STATE		0x08
617c478bd9Sstevel@tonic-gate #define	BIOS_SCROLL_SHIFT	0x10
627c478bd9Sstevel@tonic-gate #define	BIOS_NUM_SHIFT		0x20
637c478bd9Sstevel@tonic-gate #define	BIOS_CAPS_SHIFT		0x40
647c478bd9Sstevel@tonic-gate #define	BIOS_INS_SHIFT		0x80
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	kb_flag		((unsigned char *)BIOS_KB_FLAG)
677c478bd9Sstevel@tonic-gate #define	kb_flag_1	((unsigned char *)BIOS_KB_FLAG_1)
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Keyboard controller registers
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate #define	I8042_DATA		0x60
737c478bd9Sstevel@tonic-gate #define	I8042_STAT		0x64
747c478bd9Sstevel@tonic-gate #define	I8042_CMD		0x64
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Keyboard controller status register bits
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate #define	I8042_STAT_OUTBF	0x01
807c478bd9Sstevel@tonic-gate #define	I8042_STAT_INBF		0x02
817c478bd9Sstevel@tonic-gate #define	I8042_STAT_AUXBF	0x20
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * Keyboard controller commands
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate #define	I8042_RCB		0x20
877c478bd9Sstevel@tonic-gate #define	I8042_WCB		0x60
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * Keyboard commands
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate #define	KB_SET_LED		0xED	/* LED byte follows... */
937c478bd9Sstevel@tonic-gate #define	KB_LED_SCROLL_LOCK	0x01	/* Bits for LED byte */
947c478bd9Sstevel@tonic-gate #define	KB_LED_NUM_LOCK		0x02
957c478bd9Sstevel@tonic-gate #define	KB_LED_CAPS_LOCK	0x04
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate #ifndef ASSERT
987c478bd9Sstevel@tonic-gate #define	ASSERT(x)
997c478bd9Sstevel@tonic-gate #endif
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	peek8(p)	(*(p))
1027c478bd9Sstevel@tonic-gate #define	poke8(p, val)	(*(p) = (val))
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static struct {
1057c478bd9Sstevel@tonic-gate 	boolean_t	initialized;
1067c478bd9Sstevel@tonic-gate 	enum { KB_LED_IDLE, KB_LED_COMMAND_SENT, KB_LED_VALUE_SENT }
1077c478bd9Sstevel@tonic-gate 			led_state;
1087c478bd9Sstevel@tonic-gate 	int		led_commanded;
1097c478bd9Sstevel@tonic-gate 	/*
1107c478bd9Sstevel@tonic-gate 	 * Possible values:
1117c478bd9Sstevel@tonic-gate 	 *
1127c478bd9Sstevel@tonic-gate 	 * -1		Nothing pending
1137c478bd9Sstevel@tonic-gate 	 * 0x000-0x0ff	Pending byte
1147c478bd9Sstevel@tonic-gate 	 * 0x100-0x1ff	Needs leading zero, then low byte next.
1157c478bd9Sstevel@tonic-gate 	 *
1167c478bd9Sstevel@tonic-gate 	 * Others undefined.
1177c478bd9Sstevel@tonic-gate 	 */
1187c478bd9Sstevel@tonic-gate 	int		pending;
1197c478bd9Sstevel@tonic-gate } kb = {
1207c478bd9Sstevel@tonic-gate 	B_FALSE,	/* initialized? */
1217c478bd9Sstevel@tonic-gate 	KB_LED_IDLE,	/* LED command state */
1227c478bd9Sstevel@tonic-gate 	-1,		/* commanded LEDs - force refresh */
1237c478bd9Sstevel@tonic-gate 	-1,		/* pending */
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate static int kb_translate(unsigned char code);
1277c478bd9Sstevel@tonic-gate static void kb_send(unsigned char cmd);
1287c478bd9Sstevel@tonic-gate static void kb_update_leds(void);
1297c478bd9Sstevel@tonic-gate static uchar_t kb_calculate_leds(void);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate int
1327c478bd9Sstevel@tonic-gate kb_getchar(void)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	int ret;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	while (!kb_ischar())
1377c478bd9Sstevel@tonic-gate 		/* LOOP */;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	/*
1407c478bd9Sstevel@tonic-gate 	 * kb_ischar() doesn't succeed without leaving kb.pending
1417c478bd9Sstevel@tonic-gate 	 * set.
1427c478bd9Sstevel@tonic-gate 	 */
1437c478bd9Sstevel@tonic-gate 	ASSERT(kb.pending >= 0);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if (kb.pending & 0x100) {
1467c478bd9Sstevel@tonic-gate 		ret = 0;
1477c478bd9Sstevel@tonic-gate 		kb.pending &= 0xff;
1487c478bd9Sstevel@tonic-gate 	} else {
1497c478bd9Sstevel@tonic-gate 		ret = kb.pending;
1507c478bd9Sstevel@tonic-gate 		kb.pending = -1;
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	return (ret);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate int
1577c478bd9Sstevel@tonic-gate kb_ischar(void)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	unsigned char buffer_stat;
1607c478bd9Sstevel@tonic-gate 	unsigned char code;
1617c478bd9Sstevel@tonic-gate 	unsigned char leds;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	if (!kb.initialized) {
1647c478bd9Sstevel@tonic-gate 		kb_init();
1657c478bd9Sstevel@tonic-gate 		kb.initialized = B_TRUE;
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	if (kb.pending >= 0)
1697c478bd9Sstevel@tonic-gate 		return (1);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	for (;;) {
1726ee4b8d7Ssetje 		buffer_stat = inb(I8042_STAT);
1736ee4b8d7Ssetje 		if (buffer_stat == 0xff)
1746ee4b8d7Ssetje 			return (0);
1756ee4b8d7Ssetje 		buffer_stat &= (I8042_STAT_OUTBF | I8042_STAT_AUXBF);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		switch (buffer_stat) {
1787c478bd9Sstevel@tonic-gate 		case 0:
1797c478bd9Sstevel@tonic-gate 		case I8042_STAT_AUXBF:
1807c478bd9Sstevel@tonic-gate 			return (0);
1817c478bd9Sstevel@tonic-gate 		case (I8042_STAT_OUTBF | I8042_STAT_AUXBF):
1827c478bd9Sstevel@tonic-gate 			/*
1837c478bd9Sstevel@tonic-gate 			 * Discard unwanted mouse data.
1847c478bd9Sstevel@tonic-gate 			 */
1857c478bd9Sstevel@tonic-gate 			(void) inb(I8042_DATA);
1867c478bd9Sstevel@tonic-gate 			continue;
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 		code = inb(I8042_DATA);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 		switch (code) {
1927c478bd9Sstevel@tonic-gate 		/*
1937c478bd9Sstevel@tonic-gate 		 * case 0xAA:
1947c478bd9Sstevel@tonic-gate 		 *
1957c478bd9Sstevel@tonic-gate 		 * You might think that we should ignore 0xAA on the
1967c478bd9Sstevel@tonic-gate 		 * grounds that it is the BAT Complete response and will
1977c478bd9Sstevel@tonic-gate 		 * occur on keyboard detach/reattach.  Unfortunately,
1987c478bd9Sstevel@tonic-gate 		 * it is ambiguous - this is also the code for a break
1997c478bd9Sstevel@tonic-gate 		 * of the left shift key.  Since it will be harmless for
2007c478bd9Sstevel@tonic-gate 		 * us to "spuriously" process a break of Left Shift,
2017c478bd9Sstevel@tonic-gate 		 * we just let the normal code handle it.  Perhaps we
2027c478bd9Sstevel@tonic-gate 		 * should take a hint and refresh the LEDs, but I
2037c478bd9Sstevel@tonic-gate 		 * refuse to get very worried about hot-plug issues
2047c478bd9Sstevel@tonic-gate 		 * in this mini-driver.
2057c478bd9Sstevel@tonic-gate 		 */
2067c478bd9Sstevel@tonic-gate 		case 0xFA:
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 			switch (kb.led_state) {
2097c478bd9Sstevel@tonic-gate 			case KB_LED_IDLE:
2107c478bd9Sstevel@tonic-gate 				/*
2117c478bd9Sstevel@tonic-gate 				 * Spurious.  Oh well, ignore it.
2127c478bd9Sstevel@tonic-gate 				 */
2137c478bd9Sstevel@tonic-gate 				break;
2147c478bd9Sstevel@tonic-gate 			case KB_LED_COMMAND_SENT:
2157c478bd9Sstevel@tonic-gate 				leds = kb_calculate_leds();
2167c478bd9Sstevel@tonic-gate 				kb_send(leds);
2177c478bd9Sstevel@tonic-gate 				kb.led_commanded = leds;
2187c478bd9Sstevel@tonic-gate 				kb.led_state = KB_LED_VALUE_SENT;
2197c478bd9Sstevel@tonic-gate 				break;
2207c478bd9Sstevel@tonic-gate 			case KB_LED_VALUE_SENT:
2217c478bd9Sstevel@tonic-gate 				kb.led_state = KB_LED_IDLE;
2227c478bd9Sstevel@tonic-gate 				/*
2237c478bd9Sstevel@tonic-gate 				 * Check for changes made while we were
2247c478bd9Sstevel@tonic-gate 				 * working on the last change.
2257c478bd9Sstevel@tonic-gate 				 */
2267c478bd9Sstevel@tonic-gate 				kb_update_leds();
2277c478bd9Sstevel@tonic-gate 				break;
2287c478bd9Sstevel@tonic-gate 			}
2297c478bd9Sstevel@tonic-gate 			continue;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		case 0xE0:
2327c478bd9Sstevel@tonic-gate 		case 0xE1:
2337c478bd9Sstevel@tonic-gate 			/*
2347c478bd9Sstevel@tonic-gate 			 * These are used to distinguish the keys added on
2357c478bd9Sstevel@tonic-gate 			 * the AT-101 keyboard from the original 84 keys.
2367c478bd9Sstevel@tonic-gate 			 * We don't care, and the codes are carefully arranged
2377c478bd9Sstevel@tonic-gate 			 * so that we don't have to.
2387c478bd9Sstevel@tonic-gate 			 */
2397c478bd9Sstevel@tonic-gate 			continue;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 		default:
2427c478bd9Sstevel@tonic-gate 			if (code & 0x80) {
2437c478bd9Sstevel@tonic-gate 				/* Release */
2447c478bd9Sstevel@tonic-gate 				code &= 0x7f;
2457c478bd9Sstevel@tonic-gate 				switch (keyboard_translate[code].normal) {
2467c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_LSHIFT:
2477c478bd9Sstevel@tonic-gate 					poke8(kb_flag, peek8(kb_flag) &
2487c478bd9Sstevel@tonic-gate 					    ~BIOS_LEFT_SHIFT);
2497c478bd9Sstevel@tonic-gate 					break;
2507c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_RSHIFT:
2517c478bd9Sstevel@tonic-gate 					poke8(kb_flag, peek8(kb_flag) &
2527c478bd9Sstevel@tonic-gate 					    ~BIOS_RIGHT_SHIFT);
2537c478bd9Sstevel@tonic-gate 					break;
2547c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_CTRL:
2557c478bd9Sstevel@tonic-gate 					poke8(kb_flag, peek8(kb_flag) &
2567c478bd9Sstevel@tonic-gate 					    ~BIOS_CTL_SHIFT);
2577c478bd9Sstevel@tonic-gate 					break;
2587c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_ALT:
2597c478bd9Sstevel@tonic-gate 					poke8(kb_flag, peek8(kb_flag) &
2607c478bd9Sstevel@tonic-gate 					    ~BIOS_ALT_SHIFT);
2617c478bd9Sstevel@tonic-gate 					break;
2627c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_CAPS_LOCK:
2637c478bd9Sstevel@tonic-gate 					poke8(kb_flag_1, peek8(kb_flag_1) &
2647c478bd9Sstevel@tonic-gate 					    ~BIOS_CAPS_SHIFT);
2657c478bd9Sstevel@tonic-gate 					break;
2667c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_NUM_LOCK:
2677c478bd9Sstevel@tonic-gate 					poke8(kb_flag_1, peek8(kb_flag_1) &
2687c478bd9Sstevel@tonic-gate 					    ~BIOS_NUM_SHIFT);
2697c478bd9Sstevel@tonic-gate 					break;
2707c478bd9Sstevel@tonic-gate 				case KBTYPE_SPEC_SCROLL_LOCK:
2717c478bd9Sstevel@tonic-gate 					poke8(kb_flag_1, peek8(kb_flag_1) &
2727c478bd9Sstevel@tonic-gate 					    ~BIOS_SCROLL_SHIFT);
2737c478bd9Sstevel@tonic-gate 					break;
2747c478bd9Sstevel@tonic-gate 				default:
2757c478bd9Sstevel@tonic-gate 					/*
2767c478bd9Sstevel@tonic-gate 					 * Ignore all other releases.
2777c478bd9Sstevel@tonic-gate 					 */
2787c478bd9Sstevel@tonic-gate 					break;
2797c478bd9Sstevel@tonic-gate 				}
2807c478bd9Sstevel@tonic-gate 			} else {
2817c478bd9Sstevel@tonic-gate 				/* Press */
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 				kb.pending = kb_translate(code);
2847c478bd9Sstevel@tonic-gate 				if (kb.pending >= 0) {
2857c478bd9Sstevel@tonic-gate 					return (1);
2867c478bd9Sstevel@tonic-gate 				}
2877c478bd9Sstevel@tonic-gate 			}
2887c478bd9Sstevel@tonic-gate 		}
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate int
2937c478bd9Sstevel@tonic-gate kb_translate(unsigned char code)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	struct keyboard_translate *k;
2967c478bd9Sstevel@tonic-gate 	unsigned short action;
2977c478bd9Sstevel@tonic-gate 	boolean_t shifted;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	k = keyboard_translate + code;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	shifted = (peek8(kb_flag) & BIOS_EITHER_SHIFT) != 0;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	switch (k->normal & 0xFF00) {
3047c478bd9Sstevel@tonic-gate 	case KBTYPE_NUMPAD:
3057c478bd9Sstevel@tonic-gate 		if (peek8(kb_flag) & BIOS_NUM_STATE)
3067c478bd9Sstevel@tonic-gate 			shifted = !shifted;
3077c478bd9Sstevel@tonic-gate 		break;
3087c478bd9Sstevel@tonic-gate 	case KBTYPE_ALPHA:
3097c478bd9Sstevel@tonic-gate 		if (peek8(kb_flag) & BIOS_CAPS_STATE)
3107c478bd9Sstevel@tonic-gate 			shifted = !shifted;
3117c478bd9Sstevel@tonic-gate 		break;
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	if (peek8(kb_flag) & BIOS_ALT_SHIFT)
3157c478bd9Sstevel@tonic-gate 		action = k->alted;
3167c478bd9Sstevel@tonic-gate 	else if (peek8(kb_flag) & BIOS_CTL_SHIFT)
3177c478bd9Sstevel@tonic-gate 		action = k->ctrled;
3187c478bd9Sstevel@tonic-gate 	else if (shifted)
3197c478bd9Sstevel@tonic-gate 		action = k->shifted;
3207c478bd9Sstevel@tonic-gate 	else
3217c478bd9Sstevel@tonic-gate 		action = k->normal;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	switch (action & 0xFF00) {
3247c478bd9Sstevel@tonic-gate 	case KBTYPE_NORMAL:
3257c478bd9Sstevel@tonic-gate 	case KBTYPE_ALPHA:
3267c478bd9Sstevel@tonic-gate 		return (action & 0xFF);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	case KBTYPE_NUMPAD:
3297c478bd9Sstevel@tonic-gate 	case KBTYPE_FUNC:
3307c478bd9Sstevel@tonic-gate 		return ((action & 0xFF) | 0x100);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC:
3337c478bd9Sstevel@tonic-gate 		break;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	default:
3367c478bd9Sstevel@tonic-gate 		/*
3377c478bd9Sstevel@tonic-gate 		 * Bad entry.
3387c478bd9Sstevel@tonic-gate 		 */
3397c478bd9Sstevel@tonic-gate 		ASSERT(0);
3407c478bd9Sstevel@tonic-gate 		return (-1);
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/*
3447c478bd9Sstevel@tonic-gate 	 * Handle special keys, mostly shifts.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 	switch (action) {
3477c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_NOP:
3487c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_UNDEF:
3497c478bd9Sstevel@tonic-gate 		break;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_LSHIFT:
3527c478bd9Sstevel@tonic-gate 		poke8(kb_flag, peek8(kb_flag) | BIOS_LEFT_SHIFT);
3537c478bd9Sstevel@tonic-gate 		break;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_RSHIFT:
3567c478bd9Sstevel@tonic-gate 		poke8(kb_flag, peek8(kb_flag) | BIOS_RIGHT_SHIFT);
3577c478bd9Sstevel@tonic-gate 		break;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_CTRL:
3607c478bd9Sstevel@tonic-gate 		poke8(kb_flag, peek8(kb_flag) | BIOS_CTL_SHIFT);
3617c478bd9Sstevel@tonic-gate 		break;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_ALT:
3647c478bd9Sstevel@tonic-gate 		poke8(kb_flag, peek8(kb_flag) | BIOS_ALT_SHIFT);
3657c478bd9Sstevel@tonic-gate 		break;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_CAPS_LOCK:
3687c478bd9Sstevel@tonic-gate 		if (!(peek8(kb_flag_1) & BIOS_CAPS_SHIFT)) {
3697c478bd9Sstevel@tonic-gate 			poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_CAPS_SHIFT);
3707c478bd9Sstevel@tonic-gate 			poke8(kb_flag, peek8(kb_flag) ^ BIOS_CAPS_STATE);
3717c478bd9Sstevel@tonic-gate 		}
3727c478bd9Sstevel@tonic-gate 		break;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_NUM_LOCK:
3757c478bd9Sstevel@tonic-gate 		if (!(peek8(kb_flag_1) & BIOS_NUM_SHIFT)) {
3767c478bd9Sstevel@tonic-gate 			poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_NUM_SHIFT);
3777c478bd9Sstevel@tonic-gate 			poke8(kb_flag, peek8(kb_flag) ^ BIOS_NUM_STATE);
3787c478bd9Sstevel@tonic-gate 		}
3797c478bd9Sstevel@tonic-gate 		break;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_SCROLL_LOCK:
3827c478bd9Sstevel@tonic-gate 		if (!(peek8(kb_flag_1) & BIOS_SCROLL_SHIFT)) {
3837c478bd9Sstevel@tonic-gate 			poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_SCROLL_SHIFT);
3847c478bd9Sstevel@tonic-gate 			poke8(kb_flag, peek8(kb_flag) ^ BIOS_SCROLL_STATE);
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 		break;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	case KBTYPE_SPEC_MAYBE_REBOOT:
389*ae115bc7Smrj #if 0	/* Solaris doesn't reboot via ctrl-alt-del */
3907c478bd9Sstevel@tonic-gate 		if ((peek8(kb_flag) & (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) ==
3917c478bd9Sstevel@tonic-gate 		    (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) {
3927c478bd9Sstevel@tonic-gate 			reset();
3937c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
3947c478bd9Sstevel@tonic-gate 		}
395*ae115bc7Smrj #endif
3967c478bd9Sstevel@tonic-gate 		break;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	default:
3997c478bd9Sstevel@tonic-gate 		/*
4007c478bd9Sstevel@tonic-gate 		 * Bad entry
4017c478bd9Sstevel@tonic-gate 		 */
4027c478bd9Sstevel@tonic-gate 		ASSERT(0);
4037c478bd9Sstevel@tonic-gate 		break;
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/*
4077c478bd9Sstevel@tonic-gate 	 * Consider updating the LEDs.  This does nothing if nothing
4087c478bd9Sstevel@tonic-gate 	 * needs to be done.
4097c478bd9Sstevel@tonic-gate 	 */
4107c478bd9Sstevel@tonic-gate 	kb_update_leds();
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	return (-1);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate void
4167c478bd9Sstevel@tonic-gate kb_send(unsigned char cmd)
4177c478bd9Sstevel@tonic-gate {
4186ee4b8d7Ssetje 	int retries;
4196ee4b8d7Ssetje 
4206ee4b8d7Ssetje 	for (retries = 0;
4216ee4b8d7Ssetje 	    (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000;
4226ee4b8d7Ssetje 	    retries++)
4237c478bd9Sstevel@tonic-gate 		/* LOOP */;
4247c478bd9Sstevel@tonic-gate 	outb(I8042_DATA, cmd);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate void
4287c478bd9Sstevel@tonic-gate kb_update_leds(void)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	if (kb.led_state != KB_LED_IDLE) {
4317c478bd9Sstevel@tonic-gate 		/*
4327c478bd9Sstevel@tonic-gate 		 * The state machine will take care of any additional
4337c478bd9Sstevel@tonic-gate 		 * changes that are necessary.
4347c478bd9Sstevel@tonic-gate 		 */
4357c478bd9Sstevel@tonic-gate 		return;
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	if (kb_calculate_leds() == kb.led_commanded) {
4397c478bd9Sstevel@tonic-gate 		kb.led_state = KB_LED_IDLE;
4407c478bd9Sstevel@tonic-gate 	} else {
4417c478bd9Sstevel@tonic-gate 		kb_send(KB_SET_LED);
4427c478bd9Sstevel@tonic-gate 		kb.led_state = KB_LED_COMMAND_SENT;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate #define	MIMR_PORT	0x21	/* Mask register for master PIC */
4477c478bd9Sstevel@tonic-gate #define	MIMR_KB		2	/* Keyboard mask bit in master PIC */
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate void
4507c478bd9Sstevel@tonic-gate kb_init(void)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	unsigned char pic_mask;
4536ee4b8d7Ssetje 	int retries;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	/*
4567c478bd9Sstevel@tonic-gate 	 * Write the command byte to turn off interrupts and
4577c478bd9Sstevel@tonic-gate 	 * disable the auxiliary port.
4587c478bd9Sstevel@tonic-gate 	 *
4597c478bd9Sstevel@tonic-gate 	 * 0x80:  0 = Reserved, must be zero.
4607c478bd9Sstevel@tonic-gate 	 * 0x40:  1 = Translate to XT codes.
4617c478bd9Sstevel@tonic-gate 	 *		Solaris turns this off later, but we have a legacy
4627c478bd9Sstevel@tonic-gate 	 *		of using XT codes.
4637c478bd9Sstevel@tonic-gate 	 * 0x20:  1 = Disable aux (mouse) port.
4647c478bd9Sstevel@tonic-gate 	 * 0x10:  0 = Enable main (keyboard) port.
4657c478bd9Sstevel@tonic-gate 	 * 0x08:  0 = Reserved, must be zero.
4667c478bd9Sstevel@tonic-gate 	 * 0x04:  1 = System flag, 1 means passed self-test.
4677c478bd9Sstevel@tonic-gate 	 *		Caution:  setting this bit to zero causes some
4687c478bd9Sstevel@tonic-gate 	 *		systems (HP Kayak XA) to fail to reboot without
4697c478bd9Sstevel@tonic-gate 	 *		a hard reset.
4707c478bd9Sstevel@tonic-gate 	 * 0x02:  0 = Disable aux interrupts.
4717c478bd9Sstevel@tonic-gate 	 * 0x01:  0 = Disable aux interrupts.
4727c478bd9Sstevel@tonic-gate 	 */
4737c478bd9Sstevel@tonic-gate 
4746ee4b8d7Ssetje 	for (retries = 0;
4756ee4b8d7Ssetje 	    (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000;
4766ee4b8d7Ssetje 	    retries++)
4777c478bd9Sstevel@tonic-gate 		/* LOOP */;
4787c478bd9Sstevel@tonic-gate 	outb(I8042_CMD, I8042_WCB);
4797c478bd9Sstevel@tonic-gate 
4806ee4b8d7Ssetje 	for (retries = 0;
4816ee4b8d7Ssetje 	    (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000;
4826ee4b8d7Ssetje 	    retries++)
4837c478bd9Sstevel@tonic-gate 		/* LOOP */;
4847c478bd9Sstevel@tonic-gate 	outb(I8042_DATA, 0x64);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/*
4877c478bd9Sstevel@tonic-gate 	 * If we're running on a system with an emulated 8042 (with
4887c478bd9Sstevel@tonic-gate 	 * USB and SMI emulation), the above command *might* not
4897c478bd9Sstevel@tonic-gate 	 * have turned off keyboard interrupts.  If it didn't,
4907c478bd9Sstevel@tonic-gate 	 * we will lose keystrokes to the BIOS int handler every
4917c478bd9Sstevel@tonic-gate 	 * time someone hits a key while BIOS and STI are active..
4927c478bd9Sstevel@tonic-gate 	 * that is, every time we're in bootconf.exe, for example.
4937c478bd9Sstevel@tonic-gate 	 * Turn off ints at the PIC to prevent this from happening.
4947c478bd9Sstevel@tonic-gate 	 *
4957c478bd9Sstevel@tonic-gate 	 * Yes, this is yet another workaround for buggy BIOS
4967c478bd9Sstevel@tonic-gate 	 * emulation.
4977c478bd9Sstevel@tonic-gate 	 */
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	pic_mask = inb(MIMR_PORT);
5007c478bd9Sstevel@tonic-gate 	outb(MIMR_PORT, pic_mask | MIMR_KB);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	kb_update_leds();
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate unsigned char
5067c478bd9Sstevel@tonic-gate kb_calculate_leds(void)
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate 	int res;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	res = 0;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	if (peek8(kb_flag) & BIOS_CAPS_STATE)
5137c478bd9Sstevel@tonic-gate 		res |= KB_LED_CAPS_LOCK;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	if (peek8(kb_flag) & BIOS_NUM_STATE)
5167c478bd9Sstevel@tonic-gate 		res |= KB_LED_NUM_LOCK;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if (peek8(kb_flag) & BIOS_SCROLL_STATE)
5197c478bd9Sstevel@tonic-gate 		res |= KB_LED_SCROLL_LOCK;
5207c478bd9Sstevel@tonic-gate 
521*ae115bc7Smrj 	return ((char)res);
5227c478bd9Sstevel@tonic-gate }
523