1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Miniature keyboard driver for bootstrap. This allows keyboard 30 * support to continue after we take over interrupts and disable 31 * BIOS keyboard support. 32 */ 33 34 #include <sys/types.h> 35 #include <sys/archsystm.h> 36 #include <sys/boot_console.h> 37 #include "boot_keyboard_table.h" 38 39 #if defined(_BOOT) 40 #include "dboot/dboot_xboot.h" 41 #endif 42 43 /* 44 * Definitions for BIOS keyboard state. We use BIOS's variable to store 45 * state, ensuring that we stay in sync with it. 46 */ 47 #define BIOS_KB_FLAG 0x417 48 #define BIOS_RIGHT_SHIFT 0x01 49 #define BIOS_LEFT_SHIFT 0x02 50 #define BIOS_EITHER_SHIFT (BIOS_LEFT_SHIFT | BIOS_RIGHT_SHIFT) 51 #define BIOS_CTL_SHIFT 0x04 52 #define BIOS_ALT_SHIFT 0x08 53 #define BIOS_SCROLL_STATE 0x10 54 #define BIOS_NUM_STATE 0x20 55 #define BIOS_CAPS_STATE 0x40 56 #define BIOS_INS_STATE 0x80 57 58 #define BIOS_KB_FLAG_1 0x418 59 #define BIOS_SYS_SHIFT 0x04 60 #define BIOS_HOLD_STATE 0x08 61 #define BIOS_SCROLL_SHIFT 0x10 62 #define BIOS_NUM_SHIFT 0x20 63 #define BIOS_CAPS_SHIFT 0x40 64 #define BIOS_INS_SHIFT 0x80 65 66 #define kb_flag ((unsigned char *)BIOS_KB_FLAG) 67 #define kb_flag_1 ((unsigned char *)BIOS_KB_FLAG_1) 68 69 /* 70 * Keyboard controller registers 71 */ 72 #define I8042_DATA 0x60 73 #define I8042_STAT 0x64 74 #define I8042_CMD 0x64 75 76 /* 77 * Keyboard controller status register bits 78 */ 79 #define I8042_STAT_OUTBF 0x01 80 #define I8042_STAT_INBF 0x02 81 #define I8042_STAT_AUXBF 0x20 82 83 /* 84 * Keyboard controller commands 85 */ 86 #define I8042_RCB 0x20 87 #define I8042_WCB 0x60 88 89 /* 90 * Keyboard commands 91 */ 92 #define KB_SET_LED 0xED /* LED byte follows... */ 93 #define KB_LED_SCROLL_LOCK 0x01 /* Bits for LED byte */ 94 #define KB_LED_NUM_LOCK 0x02 95 #define KB_LED_CAPS_LOCK 0x04 96 97 #ifndef ASSERT 98 #define ASSERT(x) 99 #endif 100 101 #define peek8(p) (*(p)) 102 #define poke8(p, val) (*(p) = (val)) 103 104 static struct { 105 boolean_t initialized; 106 enum { KB_LED_IDLE, KB_LED_COMMAND_SENT, KB_LED_VALUE_SENT } 107 led_state; 108 int led_commanded; 109 /* 110 * Possible values: 111 * 112 * -1 Nothing pending 113 * 0x000-0x0ff Pending byte 114 * 0x100-0x1ff Needs leading zero, then low byte next. 115 * 116 * Others undefined. 117 */ 118 int pending; 119 } kb = { 120 B_FALSE, /* initialized? */ 121 KB_LED_IDLE, /* LED command state */ 122 -1, /* commanded LEDs - force refresh */ 123 -1, /* pending */ 124 }; 125 126 static int kb_translate(unsigned char code); 127 static void kb_send(unsigned char cmd); 128 static void kb_update_leds(void); 129 static uchar_t kb_calculate_leds(void); 130 131 int 132 kb_getchar(void) 133 { 134 int ret; 135 136 while (!kb_ischar()) 137 /* LOOP */; 138 139 /* 140 * kb_ischar() doesn't succeed without leaving kb.pending 141 * set. 142 */ 143 ASSERT(kb.pending >= 0); 144 145 if (kb.pending & 0x100) { 146 ret = 0; 147 kb.pending &= 0xff; 148 } else { 149 ret = kb.pending; 150 kb.pending = -1; 151 } 152 153 return (ret); 154 } 155 156 int 157 kb_ischar(void) 158 { 159 unsigned char buffer_stat; 160 unsigned char code; 161 unsigned char leds; 162 163 if (!kb.initialized) { 164 kb_init(); 165 kb.initialized = B_TRUE; 166 } 167 168 if (kb.pending >= 0) 169 return (1); 170 171 for (;;) { 172 buffer_stat = inb(I8042_STAT); 173 if (buffer_stat == 0xff) 174 return (0); 175 buffer_stat &= (I8042_STAT_OUTBF | I8042_STAT_AUXBF); 176 177 switch (buffer_stat) { 178 case 0: 179 case I8042_STAT_AUXBF: 180 return (0); 181 case (I8042_STAT_OUTBF | I8042_STAT_AUXBF): 182 /* 183 * Discard unwanted mouse data. 184 */ 185 (void) inb(I8042_DATA); 186 continue; 187 } 188 189 code = inb(I8042_DATA); 190 191 switch (code) { 192 /* 193 * case 0xAA: 194 * 195 * You might think that we should ignore 0xAA on the 196 * grounds that it is the BAT Complete response and will 197 * occur on keyboard detach/reattach. Unfortunately, 198 * it is ambiguous - this is also the code for a break 199 * of the left shift key. Since it will be harmless for 200 * us to "spuriously" process a break of Left Shift, 201 * we just let the normal code handle it. Perhaps we 202 * should take a hint and refresh the LEDs, but I 203 * refuse to get very worried about hot-plug issues 204 * in this mini-driver. 205 */ 206 case 0xFA: 207 208 switch (kb.led_state) { 209 case KB_LED_IDLE: 210 /* 211 * Spurious. Oh well, ignore it. 212 */ 213 break; 214 case KB_LED_COMMAND_SENT: 215 leds = kb_calculate_leds(); 216 kb_send(leds); 217 kb.led_commanded = leds; 218 kb.led_state = KB_LED_VALUE_SENT; 219 break; 220 case KB_LED_VALUE_SENT: 221 kb.led_state = KB_LED_IDLE; 222 /* 223 * Check for changes made while we were 224 * working on the last change. 225 */ 226 kb_update_leds(); 227 break; 228 } 229 continue; 230 231 case 0xE0: 232 case 0xE1: 233 /* 234 * These are used to distinguish the keys added on 235 * the AT-101 keyboard from the original 84 keys. 236 * We don't care, and the codes are carefully arranged 237 * so that we don't have to. 238 */ 239 continue; 240 241 default: 242 if (code & 0x80) { 243 /* Release */ 244 code &= 0x7f; 245 switch (keyboard_translate[code].normal) { 246 case KBTYPE_SPEC_LSHIFT: 247 poke8(kb_flag, peek8(kb_flag) & 248 ~BIOS_LEFT_SHIFT); 249 break; 250 case KBTYPE_SPEC_RSHIFT: 251 poke8(kb_flag, peek8(kb_flag) & 252 ~BIOS_RIGHT_SHIFT); 253 break; 254 case KBTYPE_SPEC_CTRL: 255 poke8(kb_flag, peek8(kb_flag) & 256 ~BIOS_CTL_SHIFT); 257 break; 258 case KBTYPE_SPEC_ALT: 259 poke8(kb_flag, peek8(kb_flag) & 260 ~BIOS_ALT_SHIFT); 261 break; 262 case KBTYPE_SPEC_CAPS_LOCK: 263 poke8(kb_flag_1, peek8(kb_flag_1) & 264 ~BIOS_CAPS_SHIFT); 265 break; 266 case KBTYPE_SPEC_NUM_LOCK: 267 poke8(kb_flag_1, peek8(kb_flag_1) & 268 ~BIOS_NUM_SHIFT); 269 break; 270 case KBTYPE_SPEC_SCROLL_LOCK: 271 poke8(kb_flag_1, peek8(kb_flag_1) & 272 ~BIOS_SCROLL_SHIFT); 273 break; 274 default: 275 /* 276 * Ignore all other releases. 277 */ 278 break; 279 } 280 } else { 281 /* Press */ 282 283 kb.pending = kb_translate(code); 284 if (kb.pending >= 0) { 285 return (1); 286 } 287 } 288 } 289 } 290 } 291 292 int 293 kb_translate(unsigned char code) 294 { 295 struct keyboard_translate *k; 296 unsigned short action; 297 boolean_t shifted; 298 299 k = keyboard_translate + code; 300 301 shifted = (peek8(kb_flag) & BIOS_EITHER_SHIFT) != 0; 302 303 switch (k->normal & 0xFF00) { 304 case KBTYPE_NUMPAD: 305 if (peek8(kb_flag) & BIOS_NUM_STATE) 306 shifted = !shifted; 307 break; 308 case KBTYPE_ALPHA: 309 if (peek8(kb_flag) & BIOS_CAPS_STATE) 310 shifted = !shifted; 311 break; 312 } 313 314 if (peek8(kb_flag) & BIOS_ALT_SHIFT) 315 action = k->alted; 316 else if (peek8(kb_flag) & BIOS_CTL_SHIFT) 317 action = k->ctrled; 318 else if (shifted) 319 action = k->shifted; 320 else 321 action = k->normal; 322 323 switch (action & 0xFF00) { 324 case KBTYPE_NORMAL: 325 case KBTYPE_ALPHA: 326 return (action & 0xFF); 327 328 case KBTYPE_NUMPAD: 329 case KBTYPE_FUNC: 330 return ((action & 0xFF) | 0x100); 331 332 case KBTYPE_SPEC: 333 break; 334 335 default: 336 /* 337 * Bad entry. 338 */ 339 ASSERT(0); 340 return (-1); 341 } 342 343 /* 344 * Handle special keys, mostly shifts. 345 */ 346 switch (action) { 347 case KBTYPE_SPEC_NOP: 348 case KBTYPE_SPEC_UNDEF: 349 break; 350 351 case KBTYPE_SPEC_LSHIFT: 352 poke8(kb_flag, peek8(kb_flag) | BIOS_LEFT_SHIFT); 353 break; 354 355 case KBTYPE_SPEC_RSHIFT: 356 poke8(kb_flag, peek8(kb_flag) | BIOS_RIGHT_SHIFT); 357 break; 358 359 case KBTYPE_SPEC_CTRL: 360 poke8(kb_flag, peek8(kb_flag) | BIOS_CTL_SHIFT); 361 break; 362 363 case KBTYPE_SPEC_ALT: 364 poke8(kb_flag, peek8(kb_flag) | BIOS_ALT_SHIFT); 365 break; 366 367 case KBTYPE_SPEC_CAPS_LOCK: 368 if (!(peek8(kb_flag_1) & BIOS_CAPS_SHIFT)) { 369 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_CAPS_SHIFT); 370 poke8(kb_flag, peek8(kb_flag) ^ BIOS_CAPS_STATE); 371 } 372 break; 373 374 case KBTYPE_SPEC_NUM_LOCK: 375 if (!(peek8(kb_flag_1) & BIOS_NUM_SHIFT)) { 376 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_NUM_SHIFT); 377 poke8(kb_flag, peek8(kb_flag) ^ BIOS_NUM_STATE); 378 } 379 break; 380 381 case KBTYPE_SPEC_SCROLL_LOCK: 382 if (!(peek8(kb_flag_1) & BIOS_SCROLL_SHIFT)) { 383 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_SCROLL_SHIFT); 384 poke8(kb_flag, peek8(kb_flag) ^ BIOS_SCROLL_STATE); 385 } 386 break; 387 388 case KBTYPE_SPEC_MAYBE_REBOOT: 389 #if 0 /* Solaris doesn't reboot via ctrl-alt-del */ 390 if ((peek8(kb_flag) & (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) == 391 (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) { 392 reset(); 393 /* NOTREACHED */ 394 } 395 #endif 396 break; 397 398 default: 399 /* 400 * Bad entry 401 */ 402 ASSERT(0); 403 break; 404 } 405 406 /* 407 * Consider updating the LEDs. This does nothing if nothing 408 * needs to be done. 409 */ 410 kb_update_leds(); 411 412 return (-1); 413 } 414 415 void 416 kb_send(unsigned char cmd) 417 { 418 int retries; 419 420 for (retries = 0; 421 (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000; 422 retries++) 423 /* LOOP */; 424 outb(I8042_DATA, cmd); 425 } 426 427 void 428 kb_update_leds(void) 429 { 430 if (kb.led_state != KB_LED_IDLE) { 431 /* 432 * The state machine will take care of any additional 433 * changes that are necessary. 434 */ 435 return; 436 } 437 438 if (kb_calculate_leds() == kb.led_commanded) { 439 kb.led_state = KB_LED_IDLE; 440 } else { 441 kb_send(KB_SET_LED); 442 kb.led_state = KB_LED_COMMAND_SENT; 443 } 444 } 445 446 #define MIMR_PORT 0x21 /* Mask register for master PIC */ 447 #define MIMR_KB 2 /* Keyboard mask bit in master PIC */ 448 449 void 450 kb_init(void) 451 { 452 unsigned char pic_mask; 453 int retries; 454 455 /* 456 * Write the command byte to turn off interrupts and 457 * disable the auxiliary port. 458 * 459 * 0x80: 0 = Reserved, must be zero. 460 * 0x40: 1 = Translate to XT codes. 461 * Solaris turns this off later, but we have a legacy 462 * of using XT codes. 463 * 0x20: 1 = Disable aux (mouse) port. 464 * 0x10: 0 = Enable main (keyboard) port. 465 * 0x08: 0 = Reserved, must be zero. 466 * 0x04: 1 = System flag, 1 means passed self-test. 467 * Caution: setting this bit to zero causes some 468 * systems (HP Kayak XA) to fail to reboot without 469 * a hard reset. 470 * 0x02: 0 = Disable aux interrupts. 471 * 0x01: 0 = Disable aux interrupts. 472 */ 473 474 for (retries = 0; 475 (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000; 476 retries++) 477 /* LOOP */; 478 outb(I8042_CMD, I8042_WCB); 479 480 for (retries = 0; 481 (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000; 482 retries++) 483 /* LOOP */; 484 outb(I8042_DATA, 0x64); 485 486 /* 487 * If we're running on a system with an emulated 8042 (with 488 * USB and SMI emulation), the above command *might* not 489 * have turned off keyboard interrupts. If it didn't, 490 * we will lose keystrokes to the BIOS int handler every 491 * time someone hits a key while BIOS and STI are active.. 492 * that is, every time we're in bootconf.exe, for example. 493 * Turn off ints at the PIC to prevent this from happening. 494 * 495 * Yes, this is yet another workaround for buggy BIOS 496 * emulation. 497 */ 498 499 pic_mask = inb(MIMR_PORT); 500 outb(MIMR_PORT, pic_mask | MIMR_KB); 501 502 kb_update_leds(); 503 } 504 505 unsigned char 506 kb_calculate_leds(void) 507 { 508 int res; 509 510 res = 0; 511 512 if (peek8(kb_flag) & BIOS_CAPS_STATE) 513 res |= KB_LED_CAPS_LOCK; 514 515 if (peek8(kb_flag) & BIOS_NUM_STATE) 516 res |= KB_LED_NUM_LOCK; 517 518 if (peek8(kb_flag) & BIOS_SCROLL_STATE) 519 res |= KB_LED_SCROLL_LOCK; 520 521 return ((char)res); 522 } 523