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