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 /* 27 * Miniature keyboard driver for bootstrap. This allows keyboard 28 * support to continue after we take over interrupts and disable 29 * BIOS keyboard support. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/archsystm.h> 34 #include <sys/boot_console.h> 35 #include "boot_keyboard_table.h" 36 37 #if defined(_BOOT) 38 #include "dboot/dboot_asm.h" 39 #include "dboot/dboot_xboot.h" 40 #endif /* _BOOT */ 41 42 /* 43 * Definitions for BIOS keyboard state. We use BIOS's variable to store 44 * state, ensuring that we stay in sync with it. 45 */ 46 #define BIOS_KB_FLAG 0x417 47 #define BIOS_RIGHT_SHIFT 0x01 48 #define BIOS_LEFT_SHIFT 0x02 49 #define BIOS_EITHER_SHIFT (BIOS_LEFT_SHIFT | BIOS_RIGHT_SHIFT) 50 #define BIOS_CTL_SHIFT 0x04 51 #define BIOS_ALT_SHIFT 0x08 52 #define BIOS_SCROLL_STATE 0x10 53 #define BIOS_NUM_STATE 0x20 54 #define BIOS_CAPS_STATE 0x40 55 #define BIOS_INS_STATE 0x80 56 57 #define BIOS_KB_FLAG_1 0x418 58 #define BIOS_SYS_SHIFT 0x04 59 #define BIOS_HOLD_STATE 0x08 60 #define BIOS_SCROLL_SHIFT 0x10 61 #define BIOS_NUM_SHIFT 0x20 62 #define BIOS_CAPS_SHIFT 0x40 63 #define BIOS_INS_SHIFT 0x80 64 65 #if defined(__xpv) && defined(_BOOT) 66 67 /* 68 * Device memory addresses 69 * 70 * In dboot under the hypervisor we don't have any memory mappings 71 * for the first meg of low memory so we can't access devices there. 72 * Intead we've mapped the device memory that we need to access into 73 * a local variable within dboot so we can access the device memory 74 * there. 75 */ 76 extern unsigned short *kb_status; 77 #define kb_flag ((unsigned char *)&kb_status[BIOS_KB_FLAG]) 78 #define kb_flag_1 ((unsigned char *)&kb_status[BIOS_KB_FLAG_1]) 79 80 #else /* __xpv && _BOOT */ 81 82 /* Device memory addresses */ 83 #define kb_flag ((unsigned char *)BIOS_KB_FLAG) 84 #define kb_flag_1 ((unsigned char *)BIOS_KB_FLAG_1) 85 86 #endif /* __xpv && _BOOT */ 87 88 /* 89 * Keyboard controller registers 90 */ 91 #define I8042_DATA 0x60 92 #define I8042_STAT 0x64 93 #define I8042_CMD 0x64 94 95 /* 96 * Keyboard controller status register bits 97 */ 98 #define I8042_STAT_OUTBF 0x01 99 #define I8042_STAT_INBF 0x02 100 #define I8042_STAT_AUXBF 0x20 101 102 /* 103 * Keyboard controller commands 104 */ 105 #define I8042_RCB 0x20 106 #define I8042_WCB 0x60 107 108 /* 109 * Keyboard commands 110 */ 111 #define KB_SET_LED 0xED /* LED byte follows... */ 112 #define KB_LED_SCROLL_LOCK 0x01 /* Bits for LED byte */ 113 #define KB_LED_NUM_LOCK 0x02 114 #define KB_LED_CAPS_LOCK 0x04 115 116 #ifndef ASSERT 117 #define ASSERT(x) 118 #endif 119 120 #define peek8(p) (*(p)) 121 #define poke8(p, val) (*(p) = (val)) 122 123 static struct { 124 boolean_t initialized; 125 enum { KB_LED_IDLE, KB_LED_COMMAND_SENT, KB_LED_VALUE_SENT } 126 led_state; 127 int led_commanded; 128 /* 129 * Possible values: 130 * 131 * -1 Nothing pending 132 * 0x000-0x0ff Pending byte 133 * 0x100-0x1ff Needs leading zero, then low byte next. 134 * 135 * Others undefined. 136 */ 137 int pending; 138 } kb = { 139 B_FALSE, /* initialized? */ 140 KB_LED_IDLE, /* LED command state */ 141 -1, /* commanded LEDs - force refresh */ 142 -1, /* pending */ 143 }; 144 145 #define KTAB_STRLEN 3 146 static char keystringtab[KTAB_STRLEN] = {'\033', '[', ' '}; 147 static int keystring = -1; 148 149 static int kb_translate(unsigned char code); 150 static void kb_send(unsigned char cmd); 151 static void kb_update_leds(void); 152 static uchar_t kb_calculate_leds(void); 153 154 int 155 kb_getchar(void) 156 { 157 int ret; 158 159 while (!kb_ischar()) 160 /* LOOP */; 161 162 if (keystring >= 0) { 163 ret = keystringtab[keystring++]; 164 if (keystring == KTAB_STRLEN) { 165 keystring = -1; 166 kb.pending = -1; 167 } 168 return (ret); 169 } 170 171 /* 172 * kb_ischar() doesn't succeed without leaving kb.pending 173 * set. 174 */ 175 ASSERT(kb.pending >= 0); 176 177 if (kb.pending & 0x100) { 178 kb.pending &= 0xff; 179 switch (kb.pending) { 180 case 'H': /* Up */ 181 keystringtab[2] = 'A'; 182 keystring = 0; 183 return (kb_getchar()); 184 case 'P': /* Down */ 185 keystringtab[2] = 'B'; 186 keystring = 0; 187 return (kb_getchar()); 188 case 'M': /* Right */ 189 keystringtab[2] = 'C'; 190 keystring = 0; 191 return (kb_getchar()); 192 case 'K': /* Left */ 193 keystringtab[2] = 'D'; 194 keystring = 0; 195 return (kb_getchar()); 196 default: 197 ret = 0; 198 } 199 } else { 200 ret = kb.pending; 201 kb.pending = -1; 202 } 203 204 return (ret); 205 } 206 207 int 208 kb_ischar(void) 209 { 210 unsigned char buffer_stat; 211 unsigned char code; 212 unsigned char leds; 213 214 if (!kb.initialized) { 215 kb_init(); 216 kb.initialized = B_TRUE; 217 } 218 219 if (kb.pending >= 0) 220 return (1); 221 222 for (;;) { 223 buffer_stat = inb(I8042_STAT); 224 if (buffer_stat == 0xff) 225 return (0); 226 buffer_stat &= (I8042_STAT_OUTBF | I8042_STAT_AUXBF); 227 228 switch (buffer_stat) { 229 case 0: 230 case I8042_STAT_AUXBF: 231 return (0); 232 case (I8042_STAT_OUTBF | I8042_STAT_AUXBF): 233 /* 234 * Discard unwanted mouse data. 235 */ 236 (void) inb(I8042_DATA); 237 continue; 238 } 239 240 code = inb(I8042_DATA); 241 242 switch (code) { 243 /* 244 * case 0xAA: 245 * 246 * You might think that we should ignore 0xAA on the 247 * grounds that it is the BAT Complete response and will 248 * occur on keyboard detach/reattach. Unfortunately, 249 * it is ambiguous - this is also the code for a break 250 * of the left shift key. Since it will be harmless for 251 * us to "spuriously" process a break of Left Shift, 252 * we just let the normal code handle it. Perhaps we 253 * should take a hint and refresh the LEDs, but I 254 * refuse to get very worried about hot-plug issues 255 * in this mini-driver. 256 */ 257 case 0xFA: 258 259 switch (kb.led_state) { 260 case KB_LED_IDLE: 261 /* 262 * Spurious. Oh well, ignore it. 263 */ 264 break; 265 case KB_LED_COMMAND_SENT: 266 leds = kb_calculate_leds(); 267 kb_send(leds); 268 kb.led_commanded = leds; 269 kb.led_state = KB_LED_VALUE_SENT; 270 break; 271 case KB_LED_VALUE_SENT: 272 kb.led_state = KB_LED_IDLE; 273 /* 274 * Check for changes made while we were 275 * working on the last change. 276 */ 277 kb_update_leds(); 278 break; 279 } 280 continue; 281 282 case 0xE0: 283 case 0xE1: 284 /* 285 * These are used to distinguish the keys added on 286 * the AT-101 keyboard from the original 84 keys. 287 * We don't care, and the codes are carefully arranged 288 * so that we don't have to. 289 */ 290 continue; 291 292 default: 293 if (code & 0x80) { 294 /* Release */ 295 code &= 0x7f; 296 switch (keyboard_translate[code].normal) { 297 case KBTYPE_SPEC_LSHIFT: 298 poke8(kb_flag, peek8(kb_flag) & 299 ~BIOS_LEFT_SHIFT); 300 break; 301 case KBTYPE_SPEC_RSHIFT: 302 poke8(kb_flag, peek8(kb_flag) & 303 ~BIOS_RIGHT_SHIFT); 304 break; 305 case KBTYPE_SPEC_CTRL: 306 poke8(kb_flag, peek8(kb_flag) & 307 ~BIOS_CTL_SHIFT); 308 break; 309 case KBTYPE_SPEC_ALT: 310 poke8(kb_flag, peek8(kb_flag) & 311 ~BIOS_ALT_SHIFT); 312 break; 313 case KBTYPE_SPEC_CAPS_LOCK: 314 poke8(kb_flag_1, peek8(kb_flag_1) & 315 ~BIOS_CAPS_SHIFT); 316 break; 317 case KBTYPE_SPEC_NUM_LOCK: 318 poke8(kb_flag_1, peek8(kb_flag_1) & 319 ~BIOS_NUM_SHIFT); 320 break; 321 case KBTYPE_SPEC_SCROLL_LOCK: 322 poke8(kb_flag_1, peek8(kb_flag_1) & 323 ~BIOS_SCROLL_SHIFT); 324 break; 325 default: 326 /* 327 * Ignore all other releases. 328 */ 329 break; 330 } 331 } else { 332 /* Press */ 333 334 kb.pending = kb_translate(code); 335 if (kb.pending >= 0) { 336 return (1); 337 } 338 } 339 } 340 } 341 } 342 343 int 344 kb_translate(unsigned char code) 345 { 346 struct keyboard_translate *k; 347 unsigned short action; 348 boolean_t shifted; 349 350 k = keyboard_translate + code; 351 352 shifted = (peek8(kb_flag) & BIOS_EITHER_SHIFT) != 0; 353 354 switch (k->normal & 0xFF00) { 355 case KBTYPE_NUMPAD: 356 if (peek8(kb_flag) & BIOS_NUM_STATE) 357 shifted = !shifted; 358 break; 359 case KBTYPE_ALPHA: 360 if (peek8(kb_flag) & BIOS_CAPS_STATE) 361 shifted = !shifted; 362 break; 363 } 364 365 if (peek8(kb_flag) & BIOS_ALT_SHIFT) 366 action = k->alted; 367 else if (peek8(kb_flag) & BIOS_CTL_SHIFT) 368 action = k->ctrled; 369 else if (shifted) 370 action = k->shifted; 371 else 372 action = k->normal; 373 374 switch (action & 0xFF00) { 375 case KBTYPE_NORMAL: 376 case KBTYPE_ALPHA: 377 return (action & 0xFF); 378 379 case KBTYPE_NUMPAD: 380 case KBTYPE_FUNC: 381 return ((action & 0xFF) | 0x100); 382 383 case KBTYPE_SPEC: 384 break; 385 386 default: 387 /* 388 * Bad entry. 389 */ 390 ASSERT(0); 391 return (-1); 392 } 393 394 /* 395 * Handle special keys, mostly shifts. 396 */ 397 switch (action) { 398 case KBTYPE_SPEC_NOP: 399 case KBTYPE_SPEC_UNDEF: 400 break; 401 402 case KBTYPE_SPEC_LSHIFT: 403 poke8(kb_flag, peek8(kb_flag) | BIOS_LEFT_SHIFT); 404 break; 405 406 case KBTYPE_SPEC_RSHIFT: 407 poke8(kb_flag, peek8(kb_flag) | BIOS_RIGHT_SHIFT); 408 break; 409 410 case KBTYPE_SPEC_CTRL: 411 poke8(kb_flag, peek8(kb_flag) | BIOS_CTL_SHIFT); 412 break; 413 414 case KBTYPE_SPEC_ALT: 415 poke8(kb_flag, peek8(kb_flag) | BIOS_ALT_SHIFT); 416 break; 417 418 case KBTYPE_SPEC_CAPS_LOCK: 419 if (!(peek8(kb_flag_1) & BIOS_CAPS_SHIFT)) { 420 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_CAPS_SHIFT); 421 poke8(kb_flag, peek8(kb_flag) ^ BIOS_CAPS_STATE); 422 } 423 break; 424 425 case KBTYPE_SPEC_NUM_LOCK: 426 if (!(peek8(kb_flag_1) & BIOS_NUM_SHIFT)) { 427 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_NUM_SHIFT); 428 poke8(kb_flag, peek8(kb_flag) ^ BIOS_NUM_STATE); 429 } 430 break; 431 432 case KBTYPE_SPEC_SCROLL_LOCK: 433 if (!(peek8(kb_flag_1) & BIOS_SCROLL_SHIFT)) { 434 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_SCROLL_SHIFT); 435 poke8(kb_flag, peek8(kb_flag) ^ BIOS_SCROLL_STATE); 436 } 437 break; 438 439 case KBTYPE_SPEC_MAYBE_REBOOT: 440 #if 0 /* Solaris doesn't reboot via ctrl-alt-del */ 441 if ((peek8(kb_flag) & (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) == 442 (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) { 443 reset(); 444 /* NOTREACHED */ 445 } 446 #endif 447 break; 448 449 default: 450 /* 451 * Bad entry 452 */ 453 ASSERT(0); 454 break; 455 } 456 457 /* 458 * Consider updating the LEDs. This does nothing if nothing 459 * needs to be done. 460 */ 461 kb_update_leds(); 462 463 return (-1); 464 } 465 466 void 467 kb_send(unsigned char cmd) 468 { 469 int retries; 470 471 for (retries = 0; 472 (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000; 473 retries++) 474 /* LOOP */; 475 outb(I8042_DATA, cmd); 476 } 477 478 void 479 kb_update_leds(void) 480 { 481 if (kb.led_state != KB_LED_IDLE) { 482 /* 483 * The state machine will take care of any additional 484 * changes that are necessary. 485 */ 486 return; 487 } 488 489 if (kb_calculate_leds() == kb.led_commanded) { 490 kb.led_state = KB_LED_IDLE; 491 } else { 492 kb_send(KB_SET_LED); 493 kb.led_state = KB_LED_COMMAND_SENT; 494 } 495 } 496 497 #define MIMR_PORT 0x21 /* Mask register for master PIC */ 498 #define MIMR_KB 2 /* Keyboard mask bit in master PIC */ 499 500 void 501 kb_init(void) 502 { 503 /* 504 * Resist the urge to muck with the keyboard/mouse. Just assume 505 * that the bios, grub, and any optional hypervisor have left 506 * the keyboard in a sane and usable state. Messing with it now 507 * could result it making it unusuable, which would break early 508 * kmdb debugging support. Note that we don't actually need to 509 * disable interrupts for the keyboard/mouse since we're already 510 * in protected mode and we're not compeating with the bios for 511 * keyboard access. Also, we don't need to disable the mouse 512 * port since our polled input routine will just drop any mouse 513 * data that it recieves. 514 */ 515 kb_update_leds(); 516 } 517 518 unsigned char 519 kb_calculate_leds(void) 520 { 521 int res; 522 523 res = 0; 524 525 if (peek8(kb_flag) & BIOS_CAPS_STATE) 526 res |= KB_LED_CAPS_LOCK; 527 528 if (peek8(kb_flag) & BIOS_NUM_STATE) 529 res |= KB_LED_NUM_LOCK; 530 531 if (peek8(kb_flag) & BIOS_SCROLL_STATE) 532 res |= KB_LED_SCROLL_LOCK; 533 534 return ((char)res); 535 } 536