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: }