1: /* Keyboard driver for PC's and AT's. 2: * 3: * Changed by Marcus Hampel (04/02/1994) 4: * - Loadable keymaps 5: */ 6: 7: #include "kernel.h" 8: #include <termios.h> 9: #include <signal.h> 10: #include <unistd.h> 11: #include <minix/callnr.h> 12: #include <minix/com.h> 13: #include <minix/keymap.h> 14: #include "tty.h" 15: #include "keymaps/us-std.src" 16: 17: /* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */ 18: #define KEYBD 0x60 /* I/O port for keyboard data */ 19: 20: /* AT keyboard. */ 21: #define KB_COMMAND 0x64 /* I/O port for commands on AT */ 22: #define KB_STATUS 0x64 /* I/O port for status on AT */ 23: #define KB_ACK 0xFA /* keyboard ack response */ 24: #define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */ 25: #define KB_IN_FULL 0x02 /* status bit set when not ready to receive */ 26: #define LED_CODE 0xED /* command to keyboard to set LEDs */ 27: #define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */ 28: #define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */ 29: #define KBIT 0x80 /* bit used to ack characters to keyboard */ 30: 31: /* Miscellaneous. */ 32: #define ESC_SCAN 0x01 /* Reboot key when panicking */ 33: #define SLASH_SCAN 0x35 /* to recognize numeric slash */ 34: #define RSHIFT_SCAN 0x36 /* to distinguish left and right shift */ 35: #define HOME_SCAN 0x47 /* first key on the numeric keypad */ 36: #define INS_SCAN 0x52 /* INS for use in CTRL-ALT-INS reboot */ 37: #define DEL_SCAN 0x53 /* DEL for use in CTRL-ALT-DEL reboot */ 38: #define CONSOLE 0 /* line number for console */ 39: #define MEMCHECK_ADR 0x472 /* address to stop memory check after reboot */ 40: #define MEMCHECK_MAG 0x1234 /* magic number to stop memory check */ 41: 42: #define KB_IN_BYTES 32 /* size of keyboard input buffer */ 43: 44: PRIVATE char ibuf[KB_IN_BYTES]; /* input buffer */ 45: PRIVATE char *ihead = ibuf; /* next free spot in input buffer */ 46: PRIVATE char *itail = ibuf; /* scan code to return to TTY */ 47: PRIVATE int icount; /* # codes in buffer */ 48: 49: PRIVATE int esc; /* escape scan code detected? */ 50: PRIVATE int alt_l; /* left alt key state */ 51: PRIVATE int alt_r; /* right alt key state */ 52: PRIVATE int alt; /* either alt key */ 53: PRIVATE int ctrl_l; /* left control key state */ 54: PRIVATE int ctrl_r; /* right control key state */ 55: PRIVATE int ctrl; /* either control key */ 56: PRIVATE int shift_l; /* left shift key state */ 57: PRIVATE int shift_r; /* right shift key state */ 58: PRIVATE int shift; /* either shift key */ 59: PRIVATE int num_down; /* num lock key depressed */ 60: PRIVATE int caps_down; /* caps lock key depressed */ 61: PRIVATE int scroll_down; /* scroll lock key depressed */ 62: PRIVATE int locks[NR_CONS]; /* per console lock keys state */ 63: 64: /* Lock key active bits. Chosen to be equal to the keyboard LED bits. */ 65: #define SCROLL_LOCK 0x01 66: #define NUM_LOCK 0x02 67: #define CAPS_LOCK 0x04 68: 69: PRIVATE char numpad_map[] = 70: {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'}; 71: 72: FORWARD _PROTOTYPE( int kb_ack, (void) ); 73: FORWARD _PROTOTYPE( int kb_wait, (void) ); 74: FORWARD _PROTOTYPE( int func_key, (int scode) ); 75: FORWARD _PROTOTYPE( int scan_keyboard, (void) ); 76: FORWARD _PROTOTYPE( unsigned make_break, (int scode) ); 77: FORWARD _PROTOTYPE( void set_leds, (void) ); 78: FORWARD _PROTOTYPE( int kbd_hw_int, (irq_hook_t *hook) ); 79: FORWARD _PROTOTYPE( void kb_read, (struct tty *tp) ); 80: FORWARD _PROTOTYPE( unsigned map_key, (int scode) ); 81: 82: 83: /*===========================================================================* 84: * map_key0 * 85: *===========================================================================*/ 86: /* Map a scan code to an ASCII code ignoring modifiers. */ 87: #define map_key0(scode) \ 88: ((unsigned) keymap[(scode) * MAP_COLS]) 89: 90: 91: /*===========================================================================* 92: * map_key * 93: *===========================================================================*/ 94: PRIVATE unsigned map_key(scode) 95: int scode; 96: { 97: /* Map a scan code to an ASCII code. */ 98: 99: int caps, column, lk; 100: u16_t *keyrow; 101: 102: if (scode == SLASH_SCAN && esc) return '/'; /* don't map numeric slash */ 103: 104: keyrow = &keymap[scode * MAP_COLS]; 105: 106: caps = shift; 107: lk = locks[current]; 108: if ((lk & NUM_LOCK) && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps; 109: if ((lk & CAPS_LOCK) && (keyrow[0] & HASCAPS)) caps = !caps; 110: 111: if (alt) { 112: column = 2; 113: if (ctrl || alt_r) column = 3; /* Ctrl + Alt == AltGr */ 114: if (caps) column = 4; 115: } else { 116: column = 0; 117: if (caps) column = 1; 118: if (ctrl) column = 5; 119: } 120: return keyrow[column] & ~HASCAPS; 121: } 122: 123: 124: /*===========================================================================* 125: * kbd_hw_int * 126: *===========================================================================*/ 127: PRIVATE int kbd_hw_int(hook) 128: irq_hook_t *hook; 129: { 130: /* A keyboard interrupt has occurred. Process it. */ 131: 132: int scode; 133: 134: /* Fetch the character from the keyboard hardware and acknowledge it. */ 135: scode = scan_keyboard(); 136: 137: /* Store the scancode in memory so the task can get at it later. */ 138: if (icount < KB_IN_BYTES) { 139: *ihead++ = scode; 140: if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf; 141: icount++; 142: tty_table[current].tty_events = 1; 143: force_timeout(); 144: } 145: return 1; /* Reenable keyboard interrupt */ 146: } 147: 148: 149: /*==========================================================================* 150: * kb_read * 151: *==========================================================================*/ 152: PRIVATE void kb_read(tp) 153: tty_t *tp; 154: { 155: /* Process characters from the circular keyboard buffer. */ 156: 157: char buf[3]; 158: int scode; 159: unsigned ch; 160: 161: tp = &tty_table[current]; /* always use the current console */ 162: 163: while (icount > 0) { 164: scode = *itail++; /* take one key scan code */ 165: if (itail == ibuf + KB_IN_BYTES) itail = ibuf; 166: lock(); 167: icount--; 168: unlock(); 169: 170: /* Function keys are being used for debug dumps. */ 171: if (func_key(scode)) continue; 172: 173: /* Perform make/break processing. */ 174: ch = make_break(scode); 175: 176: if (ch <= 0xFF) { 177: /* A normal character. */ 178: buf[0] = ch; 179: (void) in_process(tp, buf, 1); 180: } else 181: if (HOME <= ch && ch <= INSRT) { 182: /* An ASCII escape sequence generated by the numeric pad. */ 183: buf[0] = ESC; 184: buf[1] = '['; 185: buf[2] = numpad_map[ch - HOME]; 186: (void) in_process(tp, buf, 3); 187: } else 188: if (ch == ALEFT) { 189: /* Choose lower numbered console as current console. */ 190: select_console(current - 1); 191: set_leds(); 192: } else 193: if (ch == ARIGHT) { 194: /* Choose higher numbered console as current console. */ 195: select_console(current + 1); 196: set_leds(); 197: } else 198: if (AF1 <= ch && ch <= AF12) { 199: /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */ 200: select_console(ch - AF1); 201: set_leds(); 202: } 203: } 204: } 205: 206: 207: /*===========================================================================* 208: * make_break * 209: *===========================================================================*/ 210: PRIVATE unsigned make_break(scode) 211: int scode; /* scan code of key just struck or released */ 212: { 213: /* This routine can handle keyboards that interrupt only on key depression, 214: * as well as keyboards that interrupt on key depression and key release. 215: * For efficiency, the interrupt routine filters out most key releases. 216: */ 217: int ch, make, escape; 218: static int CAD_count = 0; 219: 220: /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would 221: * be better done in keyboard() in case TTY is hung, except control and 222: * alt are set in the high level code. 223: */ 224: if (ctrl && alt && (scode == DEL_SCAN || scode == INS_SCAN)) 225: { 226: if (++CAD_count == 3) wreboot(RBT_HALT); 227: cause_sig(INIT_PROC_NR, SIGABRT); 228: return -1; 229: } 230: 231: /* High-order bit set on key release. */ 232: make = (scode & 0200) == 0; /* true if pressed */ 233: 234: ch = map_key(scode &= 0177); /* map to ASCII */ 235: 236: escape = esc; /* Key is escaped? (true if added since the XT) */ 237: esc = 0; 238: 239: switch (ch) { 240: case CTRL: /* Left or right control key */ 241: *(escape ? &ctrl_r : &ctrl_l) = make; 242: ctrl = ctrl_l | ctrl_r; 243: break; 244: case SHIFT: /* Left or right shift key */ 245: *(scode == RSHIFT_SCAN ? &shift_r : &shift_l) = make; 246: shift = shift_l | shift_r; 247: break; 248: case ALT: /* Left or right alt key */ 249: *(escape ? &alt_r : &alt_l) = make; 250: alt = alt_l | alt_r; 251: break; 252: case CALOCK: /* Caps lock - toggle on 0 -> 1 transition */ 253: if (caps_down < make) { 254: locks[current] ^= CAPS_LOCK; 255: set_leds(); 256: } 257: caps_down = make; 258: break; 259: case NLOCK: /* Num lock */ 260: if (num_down < make) { 261: locks[current] ^= NUM_LOCK; 262: set_leds(); 263: } 264: num_down = make; 265: break; 266: case SLOCK: /* Scroll lock */ 267: if (scroll_down < make) { 268: locks[current] ^= SCROLL_LOCK; 269: set_leds(); 270: } 271: scroll_down = make; 272: break; 273: case EXTKEY: /* Escape keycode */ 274: esc = 1; /* Next key is escaped */ 275: return(-1); 276: default: /* A normal key */ 277: if (make) return(ch); 278: } 279: 280: /* Key release, or a shift type key. */ 281: return(-1); 282: } 283: 284: 285: /*===========================================================================* 286: * set_leds * 287: *===========================================================================*/ 288: PRIVATE void set_leds() 289: { 290: /* Set the LEDs on the caps, num, and scroll lock keys */ 291: 292: if (!pc_at) return; /* PC/XT doesn't have LEDs */ 293: 294: kb_wait(); /* wait for buffer empty */ 295: outb(KEYBD, LED_CODE); /* prepare keyboard to accept LED values */ 296: kb_ack(); /* wait for ack response */ 297: 298: kb_wait(); /* wait for buffer empty */ 299: outb(KEYBD, locks[current]); /* give keyboard LED values */ 300: kb_ack(); /* wait for ack response */ 301: } 302: 303: 304: /*==========================================================================* 305: * kb_wait * 306: *==========================================================================*/ 307: PRIVATE int kb_wait() 308: { 309: /* Wait until the controller is ready; return zero if this times out. */ 310: 311: int retries, status; 312: 313: retries = MAX_KB_BUSY_RETRIES + 1; /* wait until not busy */ 314: while (--retries != 0 315: && (status = inb(KB_STATUS)) & (KB_IN_FULL|KB_OUT_FULL)) { 316: if (status & KB_OUT_FULL) (void) inb(KEYBD); /* discard */ 317: } 318: return(retries); /* nonzero if ready */ 319: } 320: 321: 322: /*==========================================================================* 323: * kb_ack * 324: *==========================================================================*/ 325: PRIVATE int kb_ack() 326: { 327: /* Wait until kbd acknowledges last command; return zero if this times out. */ 328: 329: int retries; 330: 331: retries = MAX_KB_ACK_RETRIES + 1; 332: while (--retries != 0 && inb(KEYBD) != KB_ACK) 333: ; /* wait for ack */ 334: return(retries); /* nonzero if ack received */ 335: } 336: 337: /*===========================================================================* 338: * kb_init * 339: *===========================================================================*/ 340: PUBLIC void kb_init(tp) 341: tty_t *tp; 342: { 343: /* Initialize the keyboard driver. */ 344: static irq_hook_t kbd_hook; 345: 346: tp->tty_devread = kb_read; /* Input function */ 347: 348: set_leds(); /* Turn off numlock led */ 349: 350: scan_keyboard(); /* Discard leftover keystroke */ 351: 352: /* Set interrupt handler and enable keyboard IRQ. */ 353: put_irq_handler(&kbd_hook, KEYBOARD_IRQ, kbd_hw_int); 354: enable_irq(&kbd_hook); 355: } 356: 357: 358: /*===========================================================================* 359: * kbd_loadmap * 360: *===========================================================================*/ 361: PUBLIC int kbd_loadmap(user_phys) 362: phys_bytes user_phys; 363: { 364: /* Load a new keymap. */ 365: 366: phys_copy(user_phys, vir2phys(keymap), (phys_bytes) sizeof(keymap)); 367: return(OK); 368: } 369: 370: 371: /*===========================================================================* 372: * func_key * 373: *===========================================================================*/ 374: PRIVATE int func_key(scode) 375: int scode; /* scan code for a function key */ 376: { 377: /* This procedure traps function keys for debugging and control purposes. */ 378: 379: unsigned code; 380: 381: if (scode & 0200) return(FALSE); /* key release */ 382: code = map_key0(scode); /* first ignore modifiers */ 383: if (code < F1 || code > F12) return(FALSE); /* not our job */ 384: 385: switch (map_key(scode)) { /* include modifiers */ 386: 387: case F1: p_dmp(); break; /* print process table */ 388: case F2: map_dmp(); break; /* print memory map */ 389: case F3: toggle_scroll(); break; /* hardware vs. software scrolling */ 390: 391: case F5: /* network statistics */ 392: #if ENABLE_DP8390 393: dp8390_dump(); 394: #endif 395: #if ENABLE_RTL8139 396: rtl8139_dump(); 397: #endif 398: break; 399: case CF7: sigchar(&tty_table[CONSOLE], SIGQUIT); break; 400: case CF8: sigchar(&tty_table[CONSOLE], SIGINT); break; 401: case CF9: sigchar(&tty_table[CONSOLE], SIGKILL); break; 402: default: return(FALSE); 403: } 404: return(TRUE); 405: } 406: 407: 408: /*==========================================================================* 409: * scan_keyboard * 410: *==========================================================================*/ 411: PRIVATE int scan_keyboard() 412: { 413: /* Fetch the character from the keyboard hardware and acknowledge it. */ 414: 415: int code; 416: int val; 417: 418: code = inb(KEYBD); /* get the scan code for the key struck */ 419: val = inb(PORT_B); /* strobe the keyboard to ack the char */ 420: outb(PORT_B, val | KBIT); /* strobe the bit high */ 421: outb(PORT_B, val); /* now strobe it low */ 422: return code; 423: } 424: 425: 426: /*==========================================================================* 427: * wreboot * 428: *==========================================================================*/ 429: PUBLIC void wreboot(how) 430: int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */ 431: { 432: /* Wait for keystrokes for printing debugging info and reboot. */ 433: 434: int quiet, code; 435: static u16_t magic = MEMCHECK_MAG; 436: struct tasktab *ttp; 437: 438: /* Mask all interrupts. */ 439: outb(INT_CTLMASK, ~0); 440: 441: /* Tell several tasks to stop. */ 442: cons_stop(); 443: #if ENABLE_DP8390 444: dp8390_stop(); 445: #endif 446: #if ENABLE_RTL8139 447: rtl8139_stop(); 448: #endif 449: floppy_stop(); 450: clock_stop(); 451: #if ENABLE_DOSFILE 452: dosfile_stop(); 453: #endif 454: 455: if (how == RBT_HALT) { 456: printf("System Halted\n"); 457: if (!mon_return) how = RBT_PANIC; 458: } 459: 460: if (how == RBT_PANIC) { 461: /* A panic! */ 462: printf("Hit ESC to reboot, F-keys for debug dumps\n"); 463: 464: (void) scan_keyboard(); /* ack any old input */ 465: quiet = scan_keyboard();/* quiescent value (0 on PC, last code on AT)*/ 466: for (;;) { 467: milli_delay(100); /* pause for a decisecond */ 468: code = scan_keyboard(); 469: if (code != quiet) { 470: /* A key has been pressed. */ 471: if (code == ESC_SCAN) break; /* reboot if ESC typed */ 472: (void) func_key(code); /* process function key */ 473: quiet = scan_keyboard(); 474: } 475: } 476: how = RBT_REBOOT; 477: } 478: 479: if (how == RBT_REBOOT) printf("Rebooting\n"); 480: 481: if (mon_return && how != RBT_RESET) { 482: /* Reinitialize the interrupt controllers to the BIOS defaults. */ 483: intr_init(0); 484: outb(INT_CTLMASK, 0); 485: outb(INT2_CTLMASK, 0); 486: 487: /* Return to the boot monitor. */ 488: if (how == RBT_HALT) { 489: phys_copy(vir2phys(""), mon_params, 2); 490: } else 491: if (how == RBT_REBOOT) { 492: phys_copy(vir2phys("delay;boot"), mon_params, 11); 493: } 494: level0(monitor); 495: } 496: 497: /* Stop BIOS memory test. */ 498: phys_copy(vir2phys(&magic), (phys_bytes) MEMCHECK_ADR, 499: (phys_bytes) sizeof(magic)); 500: 501: /* Reset the system by jumping to the reset address (real mode), or by 502: * forcing a processor shutdown (protected mode). 503: */ 504: level0(reset); 505: }