keyboard.c

Go to the documentation of this file.
00001 /* Keyboard driver for PC's and AT's.
00002  *
00003  * Changes: 
00004  *   Jul 13, 2004   processes can observe function keys  (Jorrit N. Herder)
00005  *   Jun 15, 2004   removed wreboot(), except panic dumps (Jorrit N. Herder)
00006  *   Feb 04, 1994   loadable keymaps  (Marcus Hampel)
00007  */
00008 
00009 #include "../drivers.h"
00010 #include <sys/ioctl.h>
00011 #include <sys/kbdio.h>
00012 #include <sys/time.h>
00013 #include <sys/select.h>
00014 #include <termios.h>
00015 #include <signal.h>
00016 #include <unistd.h>
00017 #include <minix/callnr.h>
00018 #include <minix/com.h>
00019 #include <minix/keymap.h>
00020 #include "tty.h"
00021 #include "keymaps/us-std.src"
00022 #include "../../kernel/const.h"
00023 #include "../../kernel/config.h"
00024 #include "../../kernel/type.h"
00025 #include "../../kernel/proc.h"
00026 
00027 int irq_hook_id = -1;
00028 int aux_irq_hook_id = -1;
00029 
00030 /* Standard and AT keyboard.  (PS/2 MCA implies AT throughout.) */
00031 #define KEYBD           0x60    /* I/O port for keyboard data */
00032 
00033 /* AT keyboard. */
00034 #define KB_COMMAND      0x64    /* I/O port for commands on AT */
00035 #define KB_STATUS       0x64    /* I/O port for status on AT */
00036 #define KB_ACK          0xFA    /* keyboard ack response */
00037 #define KB_AUX_BYTE     0x20    /* Auxiliary Device Output Buffer Full */
00038 #define KB_OUT_FULL     0x01    /* status bit set when keypress char pending */
00039 #define KB_IN_FULL      0x02    /* status bit set when not ready to receive */
00040 #define KBC_RD_RAM_CCB  0x20    /* Read controller command byte */
00041 #define KBC_WR_RAM_CCB  0x60    /* Write controller command byte */
00042 #define KBC_DI_AUX      0xA7    /* Disable Auxiliary Device */
00043 #define KBC_EN_AUX      0xA8    /* Enable Auxiliary Device */
00044 #define KBC_DI_KBD      0xAD    /* Disable Keybard Interface */
00045 #define KBC_EN_KBD      0xAE    /* Enable Keybard Interface */
00046 #define KBC_WRITE_AUX   0xD4    /* Write to Auxiliary Device */
00047 #define LED_CODE        0xED    /* command to keyboard to set LEDs */
00048 #define MAX_KB_ACK_RETRIES 0x1000       /* max #times to wait for kb ack */
00049 #define MAX_KB_BUSY_RETRIES 0x1000      /* max #times to loop while kb busy */
00050 #define KBIT            0x80    /* bit used to ack characters to keyboard */
00051 
00052 #define KBC_IN_DELAY    7       /* wait 7 microseconds when polling */
00053 
00054 /* Miscellaneous. */
00055 #define ESC_SCAN        0x01    /* reboot key when panicking */
00056 #define SLASH_SCAN      0x35    /* to recognize numeric slash */
00057 #define RSHIFT_SCAN     0x36    /* to distinguish left and right shift */
00058 #define HOME_SCAN       0x47    /* first key on the numeric keypad */
00059 #define INS_SCAN        0x52    /* INS for use in CTRL-ALT-INS reboot */
00060 #define DEL_SCAN        0x53    /* DEL for use in CTRL-ALT-DEL reboot */
00061 
00062 #define KBD_BUFSZ       1024    /* Buffer size for raw scan codes */
00063 #define KBD_OUT_BUFSZ   16      /* Output buffer to sending data to the
00064                                  * keyboard.
00065                                  */
00066 
00067 #define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
00068 
00069 #define CONSOLE            0    /* line number for console */
00070 #define KB_IN_BYTES       32    /* size of keyboard input buffer */
00071 PRIVATE char ibuf[KB_IN_BYTES]; /* input buffer */
00072 PRIVATE char *ihead = ibuf;     /* next free spot in input buffer */
00073 PRIVATE char *itail = ibuf;     /* scan code to return to TTY */
00074 PRIVATE int icount;             /* # codes in buffer */
00075 
00076 PRIVATE int esc;                /* escape scan code detected? */
00077 PRIVATE int alt_l;              /* left alt key state */
00078 PRIVATE int alt_r;              /* right alt key state */
00079 PRIVATE int alt;                /* either alt key */
00080 PRIVATE int ctrl_l;             /* left control key state */
00081 PRIVATE int ctrl_r;             /* right control key state */
00082 PRIVATE int ctrl;               /* either control key */
00083 PRIVATE int shift_l;            /* left shift key state */
00084 PRIVATE int shift_r;            /* right shift key state */
00085 PRIVATE int shift;              /* either shift key */
00086 PRIVATE int num_down;           /* num lock key depressed */
00087 PRIVATE int caps_down;          /* caps lock key depressed */
00088 PRIVATE int scroll_down;        /* scroll lock key depressed */
00089 PRIVATE int locks[NR_CONS];     /* per console lock keys state */
00090 
00091 /* Lock key active bits.  Chosen to be equal to the keyboard LED bits. */
00092 #define SCROLL_LOCK     0x01
00093 #define NUM_LOCK        0x02
00094 #define CAPS_LOCK       0x04
00095 
00096 PRIVATE char numpad_map[] =
00097                 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
00098 
00099 /* Variables and definition for observed function keys. */
00100 typedef struct observer { int proc_nr; int events; } obs_t;
00101 PRIVATE obs_t  fkey_obs[12];    /* observers for F1-F12 */
00102 PRIVATE obs_t sfkey_obs[12];    /* observers for SHIFT F1-F12 */
00103 
00104 PRIVATE struct kbd
00105 {
00106         int minor;
00107         int nr_open;
00108         char buf[KBD_BUFSZ];
00109         int offset;
00110         int avail;
00111         int req_size;
00112         int req_proc;
00113         vir_bytes req_addr;
00114         int incaller;
00115         int select_ops;
00116         int select_proc;
00117 } kbd, kbdaux;
00118 
00119 /* Data that is to be sent to the keyboard. Each byte is ACKed by the
00120  * keyboard.
00121  */
00122 PRIVATE struct kbd_outack
00123 {
00124         unsigned char buf[KBD_OUT_BUFSZ];
00125         int offset;
00126         int avail;
00127         int expect_ack;
00128 } kbdout;
00129 
00130 PRIVATE int kbd_watchdog_set= 0;
00131 PRIVATE int kbd_alive= 1;
00132 PRIVATE timer_t tmr_kbd_wd;
00133 
00134 FORWARD _PROTOTYPE( void handle_req, (struct kbd *kbdp, message *m)     );
00135 FORWARD _PROTOTYPE( int handle_status, (struct kbd *kbdp, message *m)   );
00136 FORWARD _PROTOTYPE( void kbc_cmd0, (int cmd)                            );
00137 FORWARD _PROTOTYPE( void kbc_cmd1, (int cmd, int data)                  );
00138 FORWARD _PROTOTYPE( int kbc_read, (void)                                );
00139 FORWARD _PROTOTYPE( void kbd_send, (void)                               );
00140 FORWARD _PROTOTYPE( int kb_ack, (void)                                  );
00141 FORWARD _PROTOTYPE( int kb_wait, (void)                                 );
00142 FORWARD _PROTOTYPE( int func_key, (int scode)                           );
00143 FORWARD _PROTOTYPE( int scan_keyboard, (unsigned char *bp, int *isauxp) );
00144 FORWARD _PROTOTYPE( unsigned make_break, (int scode)                    );
00145 FORWARD _PROTOTYPE( void set_leds, (void)                               );
00146 FORWARD _PROTOTYPE( void show_key_mappings, (void)                      );
00147 FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try)              );
00148 FORWARD _PROTOTYPE( unsigned map_key, (int scode)                       );
00149 FORWARD _PROTOTYPE( void micro_delay, (unsigned long usecs)             );
00150 FORWARD _PROTOTYPE( void kbd_watchdog, (timer_t *tmrp)                  );
00151 
00152 /*===========================================================================*
00153  *                              do_kbd                                       *
00154  *===========================================================================*/
00155 PUBLIC void do_kbd(message *m)
00156 {
00157         handle_req(&kbd, m);
00158 }
00159 
00160 
00161 /*===========================================================================*
00162  *                              kbd_status                                   *
00163  *===========================================================================*/
00164 PUBLIC int kbd_status(message *m)
00165 {
00166         int r;
00167 
00168         r= handle_status(&kbd, m);
00169         if (r)
00170                 return r;
00171         return handle_status(&kbdaux, m);
00172 }
00173 
00174 
00175 /*===========================================================================*
00176  *                              do_kbdaux                                    *
00177  *===========================================================================*/
00178 PUBLIC void do_kbdaux(message *m)
00179 {
00180         handle_req(&kbdaux, m);
00181 }
00182 
00183 
00184 /*===========================================================================*
00185  *                              handle_req                                   *
00186  *===========================================================================*/
00187 PRIVATE void handle_req(kbdp, m)
00188 struct kbd *kbdp;
00189 message *m;
00190 {
00191         int i, n, r, ops, watch;
00192         unsigned char c;
00193 
00194         /* Execute the requested device driver function. */
00195         r= EINVAL;      /* just in case */
00196         switch (m->m_type) {
00197             case DEV_OPEN:
00198                 kbdp->nr_open++;
00199                 r= OK;
00200                 break;
00201             case DEV_CLOSE:
00202                 kbdp->nr_open--;
00203                 if (kbdp->nr_open < 0)
00204                 {
00205                         printf("TTY(kbd): open count is negative\n");
00206                         kbdp->nr_open= 0;
00207                 }
00208                 if (kbdp->nr_open == 0)
00209                         kbdp->avail= 0;
00210                 r= OK;
00211                 break;
00212             case DEV_READ:       
00213                 if (kbdp->req_size)
00214                 {
00215                         /* We handle only request at a time */
00216                         r= EIO;
00217                         break;
00218                 }
00219                 if (kbdp->avail == 0)
00220                 {
00221                         /* Should record proc */
00222                         kbdp->req_size= m->COUNT;
00223                         kbdp->req_proc= m->IO_ENDPT;
00224                         kbdp->req_addr= (vir_bytes)m->ADDRESS;
00225                         kbdp->incaller= m->m_source;
00226                         r= SUSPEND;
00227                         break;
00228                 }
00229 
00230                 /* Handle read request */
00231                 n= kbdp->avail;
00232                 if (n > m->COUNT)
00233                         n= m->COUNT;
00234                 if (kbdp->offset + n > KBD_BUFSZ)
00235                         n= KBD_BUFSZ-kbdp->offset;
00236                 if (n <= 0)
00237                         panic("TTY", "do_kbd(READ): bad n", n);
00238                 r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset], 
00239                         m->IO_ENDPT, D, (vir_bytes) m->ADDRESS, n);
00240                 if (r == OK)
00241                 {
00242                         kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
00243                         kbdp->avail -= n;
00244                         r= n;
00245                 }
00246 
00247                 break;
00248 
00249             case DEV_WRITE:
00250                 if (kbdp != &kbdaux)
00251                 {
00252                         printf("write to keyboard not implemented\n");
00253                         r= EINVAL;
00254                         break;
00255                 }
00256 
00257                 /* Assume that output to AUX only happens during
00258                  * initialization and we can afford to lose input. This should
00259                  * be fixed at a later time.
00260                  */
00261                 for (i= 0; i<m->COUNT; i++)
00262                 {
00263                         r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS+i,
00264                                 SELF, D, (vir_bytes)&c, 1);
00265                         if (r != OK)
00266                                 break;
00267                         kbc_cmd1(KBC_WRITE_AUX, c);
00268                 }
00269                 r= i;
00270                 break;
00271 
00272             case CANCEL:
00273                 kbdp->req_size= 0;
00274                 r= OK;
00275                 break;
00276             case DEV_SELECT:
00277                 ops = m->IO_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
00278                 watch = (m->IO_ENDPT & SEL_NOTIFY) ? 1 : 0;
00279                 
00280                 r= 0;
00281                 if (kbdp->avail && (ops & SEL_RD))
00282                 {
00283                         r |= SEL_RD;
00284                         break;
00285                 }
00286 
00287                 if (ops && watch)
00288                 {
00289                         kbdp->select_ops |= ops;
00290                         kbdp->select_proc= m->m_source;
00291                 }
00292                 break;
00293             case DEV_IOCTL:
00294                 if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS)
00295                 {
00296                         kio_leds_t leds;
00297                         unsigned char b;
00298 
00299                         r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
00300                                 SELF, D, (vir_bytes)&leds, sizeof(leds));
00301                         if (r != OK)
00302                                 break;
00303                         b= 0;
00304                         if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK;
00305                         if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK;
00306                         if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK;
00307                         if (kbdout.avail == 0)
00308                                 kbdout.offset= 0;
00309                         if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ)
00310                         {
00311                                 /* Output buffer is full. Ignore this command.
00312                                  * Reset ACK flag.
00313                                  */
00314                                 kbdout.expect_ack= 0;
00315                         }
00316                         else
00317                         {
00318                                 kbdout.buf[kbdout.offset+kbdout.avail]=
00319                                         LED_CODE;
00320                                 kbdout.buf[kbdout.offset+kbdout.avail+1]= b;
00321                                 kbdout.avail += 2;
00322                          }
00323                          if (!kbdout.expect_ack)
00324                                 kbd_send();
00325                          r= OK;
00326                          break;
00327                 }
00328                 if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL)
00329                 {
00330                         kio_bell_t bell;
00331                         clock_t ticks;
00332 
00333                         r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
00334                                 SELF, D, (vir_bytes)&bell, sizeof(bell));
00335                         if (r != OK)
00336                                 break;
00337 
00338                         ticks= bell.kb_duration.tv_usec * HZ / 1000000;
00339                         ticks += bell.kb_duration.tv_sec * HZ;
00340                         if (!ticks)
00341                                 ticks++;
00342                         beep_x(bell.kb_pitch, ticks);
00343 
00344                         r= OK;
00345                         break;
00346                 }
00347                 r= ENOTTY;
00348                 break;
00349 
00350             default:            
00351                 printf("Warning, TTY(kbd) got unexpected request %d from %d\n",
00352                         m->m_type, m->m_source);
00353                 r= EINVAL;
00354         }
00355         tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
00356 }
00357 
00358 
00359 /*===========================================================================*
00360  *                              handle_status                                *
00361  *===========================================================================*/
00362 PRIVATE int handle_status(kbdp, m)
00363 struct kbd *kbdp;
00364 message *m;
00365 {
00366         int n, r;
00367 
00368         if (kbdp->avail && kbdp->req_size && m->m_source == kbdp->incaller)
00369         {
00370                 /* Handle read request */
00371                 n= kbdp->avail;
00372                 if (n > kbdp->req_size)
00373                         n= kbdp->req_size;
00374                 if (kbdp->offset + n > KBD_BUFSZ)
00375                         n= KBD_BUFSZ-kbdp->offset;
00376                 if (n <= 0)
00377                         panic("TTY", "kbd_status: bad n", n);
00378                 kbdp->req_size= 0;
00379                 r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset], 
00380                         kbdp->req_proc, D, kbdp->req_addr, n);
00381                 if (r == OK)
00382                 {
00383                         kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
00384                         kbdp->avail -= n;
00385                         r= n;
00386                 }
00387 
00388                 m->m_type = DEV_REVIVE;
00389                 m->REP_ENDPT= kbdp->req_proc;
00390                 m->REP_STATUS= r;
00391                 return 1;
00392         }
00393         if (kbdp->avail && (kbdp->select_ops & SEL_RD) &&
00394                 m->m_source == kbdp->select_proc)
00395         {
00396                 m->m_type = DEV_IO_READY;
00397                 m->DEV_MINOR = kbdp->minor;
00398                 m->DEV_SEL_OPS = SEL_RD;
00399 
00400                 kbdp->select_ops &= ~SEL_RD;
00401                 return 1;
00402         }
00403 
00404         return 0;
00405 }
00406 
00407 
00408 /*===========================================================================*
00409  *                              map_key0                                     *
00410  *===========================================================================*/
00411 /* Map a scan code to an ASCII code ignoring modifiers. */
00412 #define map_key0(scode)  \
00413         ((unsigned) keymap[(scode) * MAP_COLS])
00414 
00415 /*===========================================================================*
00416  *                              map_key                                      *
00417  *===========================================================================*/
00418 PRIVATE unsigned map_key(scode)
00419 int scode;
00420 {
00421 /* Map a scan code to an ASCII code. */
00422 
00423   int caps, column, lk;
00424   u16_t *keyrow;
00425 
00426   if (scode == SLASH_SCAN && esc) return '/';   /* don't map numeric slash */
00427 
00428   keyrow = &keymap[scode * MAP_COLS];
00429 
00430   caps = shift;
00431   lk = locks[ccurrent];
00432   if ((lk & NUM_LOCK) && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps;
00433   if ((lk & CAPS_LOCK) && (keyrow[0] & HASCAPS)) caps = !caps;
00434 
00435   if (alt) {
00436         column = 2;
00437         if (ctrl || alt_r) column = 3;  /* Ctrl + Alt == AltGr */
00438         if (caps) column = 4;
00439   } else {
00440         column = 0;
00441         if (caps) column = 1;
00442         if (ctrl) column = 5;
00443   }
00444   return keyrow[column] & ~HASCAPS;
00445 }
00446 
00447 /*===========================================================================*
00448  *                              kbd_interrupt                                *
00449  *===========================================================================*/
00450 PUBLIC void kbd_interrupt(m_ptr)
00451 message *m_ptr;
00452 {
00453 /* A keyboard interrupt has occurred.  Process it. */
00454   int o, isaux;
00455   unsigned char scode;
00456   struct kbd *kbdp;
00457   static timer_t timer;         /* timer must be static! */
00458 
00459   /* Fetch the character from the keyboard hardware and acknowledge it. */
00460   if (!scan_keyboard(&scode, &isaux))
00461         return;
00462 
00463   if (isaux)
00464         kbdp= &kbdaux;
00465   else if (kbd.nr_open && !panicing)
00466         kbdp= &kbd;
00467   else
00468         kbdp= NULL;
00469 
00470   if (kbdp)
00471   {
00472         /* raw scan codes or aux data */
00473         if (kbdp->avail >= KBD_BUFSZ)
00474         {
00475                 printf("kbd_interrupt: %s buffer is full\n",
00476                         isaux ? "kbdaux" : "keyboard");
00477                 return; /* Buffer is full */
00478         }
00479          o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ;
00480          kbdp->buf[o]= scode;
00481          kbdp->avail++;
00482          if (kbdp->req_size)
00483                 notify(kbdp->incaller);
00484          if (kbdp->select_ops & SEL_RD)
00485                 notify(kbdp->select_proc);
00486          return;
00487   }
00488 
00489   /* Store the scancode in memory so the task can get at it later. */
00490   if (icount < KB_IN_BYTES) {
00491         *ihead++ = scode;
00492         if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf;
00493         icount++;
00494         tty_table[ccurrent].tty_events = 1;
00495         if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
00496                 select_retry(&tty_table[ccurrent]);
00497         }
00498   }
00499 }
00500 
00501 /*===========================================================================*
00502  *                              kb_read                                      *
00503  *===========================================================================*/
00504 PRIVATE int kb_read(tp, try)
00505 tty_t *tp;
00506 int try;
00507 {
00508 /* Process characters from the circular keyboard buffer. */
00509   char buf[3];
00510   int scode;
00511   unsigned ch;
00512 
00513   tp = &tty_table[ccurrent];            /* always use the current console */
00514 
00515   if (try) {
00516         if (icount > 0) return 1;
00517         return 0;
00518   }
00519 
00520   while (icount > 0) {
00521         scode = *itail++;                       /* take one key scan code */
00522         if (itail == ibuf + KB_IN_BYTES) itail = ibuf;
00523         icount--;
00524 
00525         /* Function keys are being used for debug dumps. */
00526         if (func_key(scode)) continue;
00527 
00528         /* Perform make/break processing. */
00529         ch = make_break(scode);
00530 
00531         if (ch <= 0xFF) {
00532                 /* A normal character. */
00533                 buf[0] = ch;
00534                 (void) in_process(tp, buf, 1);
00535         } else
00536         if (HOME <= ch && ch <= INSRT) {
00537                 /* An ASCII escape sequence generated by the numeric pad. */
00538                 buf[0] = ESC;
00539                 buf[1] = '[';
00540                 buf[2] = numpad_map[ch - HOME];
00541                 (void) in_process(tp, buf, 3);
00542         } else
00543         if (ch == ALEFT) {
00544                 /* Choose lower numbered console as current console. */
00545                 select_console(ccurrent - 1);
00546                 set_leds();
00547         } else
00548         if (ch == ARIGHT) {
00549                 /* Choose higher numbered console as current console. */
00550                 select_console(ccurrent + 1);
00551                 set_leds();
00552         } else
00553         if (AF1 <= ch && ch <= AF12) {
00554                 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
00555                 select_console(ch - AF1);
00556                 set_leds();
00557         } else
00558         if (CF1 <= ch && ch <= CF12) {
00559             switch(ch) {
00560                 case CF1: show_key_mappings(); break; 
00561                 case CF3: toggle_scroll(); break; /* hardware <-> software */   
00562                 case CF7: sigchar(&tty_table[CONSOLE], SIGQUIT); break;
00563                 case CF8: sigchar(&tty_table[CONSOLE], SIGINT); break;
00564                 case CF9: sigchar(&tty_table[CONSOLE], SIGKILL); break;
00565             }
00566         }
00567   }
00568 
00569   return 1;
00570 }
00571 
00572 /*===========================================================================*
00573  *                              kbd_send                                     *
00574  *===========================================================================*/
00575 PRIVATE void kbd_send()
00576 {
00577         unsigned long sb;
00578         int r;
00579         clock_t now;
00580 
00581         if (!kbdout.avail)
00582                 return;
00583         if (kbdout.expect_ack)
00584                 return;
00585 
00586         sys_inb(KB_STATUS, &sb);
00587         if (sb & (KB_OUT_FULL|KB_IN_FULL))
00588         {
00589                 printf("not sending 1: sb = 0x%x\n", sb);
00590                 return;
00591         }
00592         micro_delay(KBC_IN_DELAY);
00593         sys_inb(KB_STATUS, &sb);
00594         if (sb & (KB_OUT_FULL|KB_IN_FULL))
00595         {
00596                 printf("not sending 2: sb = 0x%x\n", sb);
00597                 return;
00598         }
00599 
00600         /* Okay, buffer is really empty */
00601 #if 0
00602         printf("sending byte 0x%x to keyboard\n", kbdout.buf[kbdout.offset]);
00603 #endif
00604         sys_outb(KEYBD, kbdout.buf[kbdout.offset]);
00605         kbdout.offset++;
00606         kbdout.avail--;
00607         kbdout.expect_ack= 1;
00608 
00609         kbd_alive= 1;
00610         if (kbd_watchdog_set)
00611         {
00612                 /* Add a timer to the timers list. Possibly reschedule the
00613                  * alarm.
00614                  */
00615                 if ((r= getuptime(&now)) != OK)
00616                         panic("TTY","Keyboard couldn't get clock's uptime.", r);
00617                 tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+HZ, kbd_watchdog,
00618                         NULL);
00619                 if (tty_timers->tmr_exp_time != tty_next_timeout) {
00620                         tty_next_timeout = tty_timers->tmr_exp_time;
00621                         if ((r= sys_setalarm(tty_next_timeout, 1)) != OK)
00622                                 panic("TTY","Keyboard couldn't set alarm.", r);
00623                 }
00624                 kbd_watchdog_set= 1;
00625          }
00626 }
00627 
00628 /*===========================================================================*
00629  *                              make_break                                   *
00630  *===========================================================================*/
00631 PRIVATE unsigned make_break(scode)
00632 int scode;                      /* scan code of key just struck or released */
00633 {
00634 /* This routine can handle keyboards that interrupt only on key depression,
00635  * as well as keyboards that interrupt on key depression and key release.
00636  * For efficiency, the interrupt routine filters out most key releases.
00637  */
00638   int ch, make, escape;
00639   static int CAD_count = 0;
00640 
00641   /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would
00642    * be better done in keyboard() in case TTY is hung, except control and
00643    * alt are set in the high level code.
00644    */
00645   if (ctrl && alt && (scode == DEL_SCAN || scode == INS_SCAN))
00646   {
00647         if (++CAD_count == 3) sys_abort(RBT_HALT);
00648         sys_kill(INIT_PROC_NR, SIGABRT);
00649         return -1;
00650   }
00651 
00652   /* High-order bit set on key release. */
00653   make = (scode & KEY_RELEASE) == 0;            /* true if pressed */
00654 
00655   ch = map_key(scode &= ASCII_MASK);            /* map to ASCII */
00656 
00657   escape = esc;         /* Key is escaped?  (true if added since the XT) */
00658   esc = 0;
00659 
00660   switch (ch) {
00661         case CTRL:              /* Left or right control key */
00662                 *(escape ? &ctrl_r : &ctrl_l) = make;
00663                 ctrl = ctrl_l | ctrl_r;
00664                 break;
00665         case SHIFT:             /* Left or right shift key */
00666                 *(scode == RSHIFT_SCAN ? &shift_r : &shift_l) = make;
00667                 shift = shift_l | shift_r;
00668                 break;
00669         case ALT:               /* Left or right alt key */
00670                 *(escape ? &alt_r : &alt_l) = make;
00671                 alt = alt_l | alt_r;
00672                 break;
00673         case CALOCK:            /* Caps lock - toggle on 0 -> 1 transition */
00674                 if (caps_down < make) {
00675                         locks[ccurrent] ^= CAPS_LOCK;
00676                         set_leds();
00677                 }
00678                 caps_down = make;
00679                 break;
00680         case NLOCK:             /* Num lock */
00681                 if (num_down < make) {
00682                         locks[ccurrent] ^= NUM_LOCK;
00683                         set_leds();
00684                 }
00685                 num_down = make;
00686                 break;
00687         case SLOCK:             /* Scroll lock */
00688                 if (scroll_down < make) {
00689                         locks[ccurrent] ^= SCROLL_LOCK;
00690                         set_leds();
00691                 }
00692                 scroll_down = make;
00693                 break;
00694         case EXTKEY:            /* Escape keycode */
00695                 esc = 1;                /* Next key is escaped */
00696                 return(-1);
00697         default:                /* A normal key */
00698                 if (make) return(ch);
00699   }
00700 
00701   /* Key release, or a shift type key. */
00702   return(-1);
00703 }
00704 
00705 /*===========================================================================*
00706  *                              set_leds                                     *
00707  *===========================================================================*/
00708 PRIVATE void set_leds()
00709 {
00710 /* Set the LEDs on the caps, num, and scroll lock keys */
00711   int s;
00712   if (! machine.pc_at) return;  /* PC/XT doesn't have LEDs */
00713 
00714   kb_wait();                    /* wait for buffer empty  */
00715   if ((s=sys_outb(KEYBD, LED_CODE)) != OK)
00716       printf("Warning, sys_outb couldn't prepare for LED values: %d\n", s);
00717                                 /* prepare keyboard to accept LED values */
00718   kb_ack();                     /* wait for ack response  */
00719 
00720   kb_wait();                    /* wait for buffer empty  */
00721   if ((s=sys_outb(KEYBD, locks[ccurrent])) != OK)
00722       printf("Warning, sys_outb couldn't give LED values: %d\n", s);
00723                                 /* give keyboard LED values */
00724   kb_ack();                     /* wait for ack response  */
00725 }
00726 
00727 /*===========================================================================*
00728  *                              kbc_cmd0                                     *
00729  *===========================================================================*/
00730 PRIVATE void kbc_cmd0(cmd)
00731 int cmd;
00732 {
00733         kb_wait();
00734         sys_outb(KB_COMMAND, cmd);
00735 }
00736 
00737 /*===========================================================================*
00738  *                              kbc_cmd1                                     *
00739  *===========================================================================*/
00740 PRIVATE void kbc_cmd1(cmd, data)
00741 int cmd;
00742 int data;
00743 {
00744         kb_wait();
00745         sys_outb(KB_COMMAND, cmd);
00746         kb_wait();
00747         sys_outb(KEYBD, data);
00748 }
00749 
00750 
00751 /*===========================================================================*
00752 *                              kbc_read                                     *
00753 *===========================================================================*/
00754 PRIVATE int kbc_read()
00755 {
00756         int i;
00757         unsigned long byte, st;
00758 #if 0
00759         struct micro_state ms;
00760 #endif
00761 
00762 #if DEBUG
00763         printf("in kbc_read\n");
00764 #endif
00765 
00766         /* Wait at most 1 second for a byte from the keyboard or
00767         * the kbd controller, return -1 on a timeout.
00768         */
00769         for (i= 0; i<1000; i++)
00770  #if 0
00771         micro_start(&ms);
00772         do
00773 #endif
00774         {
00775                 sys_inb(KB_STATUS, &st);
00776                 if (st & KB_OUT_FULL)
00777                 {
00778                         micro_delay(KBC_IN_DELAY);
00779                         sys_inb(KEYBD, &byte);
00780                         if (st & KB_AUX_BYTE)
00781                         {
00782 #if DEBUG
00783                                 printf(
00784                 "keyboard`kbc_read: ignoring byte (0x%x) from aux device.\n",
00785                                         byte);
00786 #endif
00787                                 continue;
00788                         }
00789 #if DEBUG
00790                         printf("keyboard`kbc_read: returning byte 0x%x\n",
00791                                 byte);
00792 #endif
00793                         return byte;
00794                 }
00795         }
00796 #if 0
00797         while (micro_elapsed(&ms) < 1000000);
00798 #endif
00799         panic("TTY", "kbc_read failed to complete", NO_NUM);
00800 }
00801 
00802 
00803 
00804 /*===========================================================================*
00805  *                              kb_wait                                      *
00806  *===========================================================================*/
00807 PRIVATE int kb_wait()
00808 {
00809 /* Wait until the controller is ready; return zero if this times out. */
00810 
00811   int retries;
00812   unsigned long status, temp;
00813   int s, isaux;
00814   unsigned char byte;
00815 
00816   retries = MAX_KB_BUSY_RETRIES + 1;    /* wait until not busy */
00817   do {
00818       s = sys_inb(KB_STATUS, &status);
00819       if (status & KB_OUT_FULL) {
00820           if (scan_keyboard(&byte, &isaux))
00821           {
00822 #if 0
00823                   printf("ignoring %sbyte in kb_wait\n", isaux ? "AUX " : "");
00824 #endif
00825           }
00826       }
00827       if (! (status & (KB_IN_FULL|KB_OUT_FULL)) )
00828           break;                        /* wait until ready */
00829   } while (--retries != 0);             /* continue unless timeout */ 
00830   return(retries);              /* zero on timeout, positive if ready */
00831 }
00832 
00833 /*===========================================================================*
00834  *                              kb_ack                                       *
00835  *===========================================================================*/
00836 PRIVATE int kb_ack()
00837 {
00838 /* Wait until kbd acknowledges last command; return zero if this times out. */
00839 
00840   int retries, s;
00841   unsigned long u8val;
00842 
00843 
00844   retries = MAX_KB_ACK_RETRIES + 1;
00845   do {
00846       s = sys_inb(KEYBD, &u8val);
00847       if (u8val == KB_ACK)      
00848           break;                /* wait for ack */
00849   } while(--retries != 0);      /* continue unless timeout */
00850 
00851   return(retries);              /* nonzero if ack received */
00852 }
00853 
00854 /*===========================================================================*
00855  *                              kb_init                                      *
00856  *===========================================================================*/
00857 PUBLIC void kb_init(tp)
00858 tty_t *tp;
00859 {
00860 /* Initialize the keyboard driver. */
00861 
00862   tp->tty_devread = kb_read;    /* input function */
00863 }
00864 
00865 /*===========================================================================*
00866  *                              kb_init_once                                 *
00867  *===========================================================================*/
00868 PUBLIC void kb_init_once(void)
00869 {
00870   int i;
00871   u8_t ccb;
00872 
00873   set_leds();                   /* turn off numlock led */
00874   scan_keyboard(NULL, NULL);    /* discard leftover keystroke */
00875 
00876       /* Clear the function key observers array. Also see func_key(). */
00877       for (i=0; i<12; i++) {
00878           fkey_obs[i].proc_nr = NONE;   /* F1-F12 observers */
00879           fkey_obs[i].events = 0;       /* F1-F12 observers */
00880           sfkey_obs[i].proc_nr = NONE;  /* Shift F1-F12 observers */
00881           sfkey_obs[i].events = 0;      /* Shift F1-F12 observers */
00882       }
00883 
00884       kbd.minor= KBD_MINOR;
00885       kbdaux.minor= KBDAUX_MINOR;
00886 
00887       /* Set interrupt handler and enable keyboard IRQ. */
00888       irq_hook_id = KEYBOARD_IRQ;       /* id to be returned on interrupt */
00889       if ((i=sys_irqsetpolicy(KEYBOARD_IRQ, IRQ_REENABLE, &irq_hook_id)) != OK)
00890           panic("TTY",  "Couldn't set keyboard IRQ policy", i);
00891       if ((i=sys_irqenable(&irq_hook_id)) != OK)
00892           panic("TTY", "Couldn't enable keyboard IRQs", i);
00893       kbd_irq_set |= (1 << KEYBOARD_IRQ);
00894 
00895       /* Set AUX interrupt handler and enable AUX IRQ. */
00896       aux_irq_hook_id = KBD_AUX_IRQ;    /* id to be returned on interrupt */
00897       if ((i=sys_irqsetpolicy(KBD_AUX_IRQ, IRQ_REENABLE,
00898                 &aux_irq_hook_id)) != OK)
00899           panic("TTY",  "Couldn't set AUX IRQ policy", i);
00900       if ((i=sys_irqenable(&aux_irq_hook_id)) != OK)
00901           panic("TTY", "Couldn't enable AUX IRQs", i);
00902       kbd_irq_set |= (1 << KBD_AUX_IRQ);
00903 
00904         /* Disable the keyboard and aux */
00905         kbc_cmd0(KBC_DI_KBD);
00906         kbc_cmd0(KBC_DI_AUX);
00907 
00908         /* Get the current configuration byte */
00909         kbc_cmd0(KBC_RD_RAM_CCB);
00910         ccb= kbc_read();
00911 
00912         /* Enable both interrupts. */
00913         kbc_cmd1(KBC_WR_RAM_CCB, ccb | 3);
00914 
00915         /* Re-enable the keyboard device. */
00916         kbc_cmd0(KBC_EN_KBD);
00917 
00918         /* Enable the aux device. */
00919         kbc_cmd0(KBC_EN_AUX);
00920 }
00921 
00922 /*===========================================================================*
00923  *                              kbd_loadmap                                  *
00924  *===========================================================================*/
00925 PUBLIC int kbd_loadmap(m)
00926 message *m;
00927 {
00928 /* Load a new keymap. */
00929   int result;
00930   result = sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
00931         SELF, D, (vir_bytes) keymap, 
00932         (vir_bytes) sizeof(keymap));
00933   return(result);
00934 }
00935 
00936 /*===========================================================================*
00937  *                              do_fkey_ctl                                  *
00938  *===========================================================================*/
00939 PUBLIC void do_fkey_ctl(m_ptr)
00940 message *m_ptr;                 /* pointer to the request message */
00941 {
00942 /* This procedure allows processes to register a function key to receive
00943  * notifications if it is pressed. At most one binding per key can exist.
00944  */
00945   int i; 
00946   int result;
00947 
00948   switch (m_ptr->FKEY_REQUEST) {        /* see what we must do */
00949   case FKEY_MAP:                        /* request for new mapping */
00950       result = OK;                      /* assume everything will be ok*/
00951       for (i=0; i < 12; i++) {          /* check F1-F12 keys */
00952           if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
00953 #if DEAD_CODE
00954         /* Currently, we don't check if the slot is in use, so that IS
00955          * can recover after a crash by overtaking its existing mappings.
00956          * In future, a better solution will be implemented.
00957          */
00958               if (fkey_obs[i].proc_nr == NONE) { 
00959 #endif
00960                   fkey_obs[i].proc_nr = m_ptr->m_source;
00961                   fkey_obs[i].events = 0;
00962                   bit_unset(m_ptr->FKEY_FKEYS, i+1);
00963 #if DEAD_CODE
00964               } else {
00965                   printf("WARNING, fkey_map failed F%d\n", i+1);
00966                   result = EBUSY;       /* report failure, but try rest */
00967               }
00968 #endif
00969           }
00970       }
00971       for (i=0; i < 12; i++) {          /* check Shift+F1-F12 keys */
00972           if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
00973 #if DEAD_CODE
00974               if (sfkey_obs[i].proc_nr == NONE) { 
00975 #endif
00976                   sfkey_obs[i].proc_nr = m_ptr->m_source;
00977                   sfkey_obs[i].events = 0;
00978                   bit_unset(m_ptr->FKEY_SFKEYS, i+1);
00979 #if DEAD_CODE
00980               } else {
00981                   printf("WARNING, fkey_map failed Shift F%d\n", i+1);
00982                   result = EBUSY;       /* report failure but try rest */
00983               }
00984 #endif
00985           }
00986       }
00987       break;
00988   case FKEY_UNMAP:
00989       result = OK;                      /* assume everything will be ok*/
00990       for (i=0; i < 12; i++) {          /* check F1-F12 keys */
00991           if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
00992               if (fkey_obs[i].proc_nr == m_ptr->m_source) { 
00993                   fkey_obs[i].proc_nr = NONE;
00994                   fkey_obs[i].events = 0;
00995                   bit_unset(m_ptr->FKEY_FKEYS, i+1);
00996               } else {
00997                   result = EPERM;       /* report failure, but try rest */
00998               }
00999           }
01000       }
01001       for (i=0; i < 12; i++) {          /* check Shift+F1-F12 keys */
01002           if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
01003               if (sfkey_obs[i].proc_nr == m_ptr->m_source) { 
01004                   sfkey_obs[i].proc_nr = NONE;
01005                   sfkey_obs[i].events = 0;
01006                   bit_unset(m_ptr->FKEY_SFKEYS, i+1);
01007               } else {
01008                   result = EPERM;       /* report failure, but try rest */
01009               }
01010           }
01011       }
01012       break;
01013   case FKEY_EVENTS:
01014       m_ptr->FKEY_FKEYS = m_ptr->FKEY_SFKEYS = 0;
01015       for (i=0; i < 12; i++) {          /* check (Shift+) F1-F12 keys */
01016           if (fkey_obs[i].proc_nr == m_ptr->m_source) {
01017               if (fkey_obs[i].events) { 
01018                   bit_set(m_ptr->FKEY_FKEYS, i+1);
01019                   fkey_obs[i].events = 0;
01020               }
01021           }
01022           if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
01023               if (sfkey_obs[i].events) { 
01024                   bit_set(m_ptr->FKEY_SFKEYS, i+1);
01025                   sfkey_obs[i].events = 0;
01026               }
01027           }
01028       }
01029       break;
01030   default:
01031           result =  EINVAL;             /* key cannot be observed */
01032   }
01033 
01034   /* Almost done, return result to caller. */
01035   m_ptr->m_type = result;
01036   send(m_ptr->m_source, m_ptr);
01037 }
01038 
01039 /*===========================================================================*
01040  *                              func_key                                     *
01041  *===========================================================================*/
01042 PRIVATE int func_key(scode)
01043 int scode;                      /* scan code for a function key */
01044 {
01045 /* This procedure traps function keys for debugging purposes. Observers of 
01046  * function keys are kept in a global array. If a subject (a key) is pressed
01047  * the observer is notified of the event. Initialization of the arrays is done
01048  * in kb_init, where NONE is set to indicate there is no interest in the key.
01049  * Returns FALSE on a key release or if the key is not observable.
01050  */
01051   message m;
01052   int key;
01053   int proc_nr;
01054   int i,s;
01055 
01056   /* Ignore key releases. If this is a key press, get full key code. */
01057   if (scode & KEY_RELEASE) return(FALSE);       /* key release */
01058   key = map_key(scode);                         /* include modifiers */
01059 
01060   /* Key pressed, now see if there is an observer for the pressed key.
01061    *           F1-F12   observers are in fkey_obs array. 
01062    *    SHIFT  F1-F12   observers are in sfkey_req array. 
01063    *    CTRL   F1-F12   reserved (see kb_read)
01064    *    ALT    F1-F12   reserved (see kb_read)
01065    * Other combinations are not in use. Note that Alt+Shift+F1-F12 is yet
01066    * defined in <minix/keymap.h>, and thus is easy for future extensions.
01067    */
01068   if (F1 <= key && key <= F12) {                /* F1-F12 */
01069       proc_nr = fkey_obs[key - F1].proc_nr;     
01070       fkey_obs[key - F1].events ++ ;    
01071   } else if (SF1 <= key && key <= SF12) {       /* Shift F2-F12 */
01072       proc_nr = sfkey_obs[key - SF1].proc_nr;   
01073       sfkey_obs[key - SF1].events ++;   
01074   }
01075   else {
01076       return(FALSE);                            /* not observable */
01077   }
01078 
01079   /* See if an observer is registered and send it a message. */
01080   if (proc_nr != NONE) { 
01081       m.NOTIFY_TYPE = FKEY_PRESSED;
01082       notify(proc_nr);
01083   }
01084   return(TRUE);
01085 }
01086 
01087 /*===========================================================================*
01088  *                              show_key_mappings                            *
01089  *===========================================================================*/
01090 PRIVATE void show_key_mappings()
01091 {
01092     int i,s;
01093     struct proc proc;
01094 
01095     printf("\n");
01096     printf("System information.   Known function key mappings to request debug dumps:\n");
01097     printf("-------------------------------------------------------------------------\n");
01098     for (i=0; i<12; i++) {
01099 
01100       printf(" %sF%d: ", i+1<10? " ":"", i+1);
01101       if (fkey_obs[i].proc_nr != NONE) {
01102           if ((s=sys_getproc(&proc, fkey_obs[i].proc_nr))!=OK)
01103               printf("sys_getproc: %d\n", s);
01104           printf("%-14.14s", proc.p_name);
01105       } else {
01106           printf("%-14.14s", "<none>");
01107       }
01108 
01109       printf("    %sShift-F%d: ", i+1<10? " ":"", i+1);
01110       if (sfkey_obs[i].proc_nr != NONE) {
01111           if ((s=sys_getproc(&proc, sfkey_obs[i].proc_nr))!=OK)
01112               printf("sys_getproc: %d\n", s);
01113           printf("%-14.14s", proc.p_name);
01114       } else {
01115           printf("%-14.14s", "<none>");
01116       }
01117       printf("\n");
01118     }
01119     printf("\n");
01120     printf("Press one of the registered function keys to trigger a debug dump.\n");
01121     printf("\n");
01122 }
01123 
01124 /*===========================================================================*
01125  *                              scan_keyboard                                *
01126  *===========================================================================*/
01127 PRIVATE int scan_keyboard(bp, isauxp)
01128 unsigned char *bp;
01129 int *isauxp;
01130 {
01131 #if 0   /* Is this old XT code? It doesn't match the PS/2 hardware */
01132 /* Fetch the character from the keyboard hardware and acknowledge it. */
01133   pvb_pair_t byte_in[2], byte_out[2];
01134   
01135   byte_in[0].port = KEYBD;      /* get the scan code for the key struck */
01136   byte_in[1].port = PORT_B;     /* strobe the keyboard to ack the char */
01137   sys_vinb(byte_in, 2);         /* request actual input */
01138 
01139   pv_set(byte_out[0], PORT_B, byte_in[1].value | KBIT); /* strobe bit high */
01140   pv_set(byte_out[1], PORT_B, byte_in[1].value);        /* then strobe low */
01141   sys_voutb(byte_out, 2);       /* request actual output */
01142 
01143   return(byte_in[0].value);             /* return scan code */
01144 #else
01145   unsigned long b, sb;
01146 
01147   sys_inb(KB_STATUS, &sb);
01148   if (!(sb & KB_OUT_FULL))
01149   {
01150         if (kbdout.avail && !kbdout.expect_ack)
01151                 kbd_send();
01152         return 0;
01153   }
01154   sys_inb(KEYBD, &b);
01155 #if 0
01156   printf("got byte 0x%x from %s\n", b, (sb & KB_AUX_BYTE) ? "AUX" : "keyboard");
01157 #endif
01158   if (!(sb & KB_AUX_BYTE) && b == KB_ACK && kbdout.expect_ack)
01159   {
01160 #if 1
01161         printf("got ACK from keyboard\n");
01162 #endif
01163         kbdout.expect_ack= 0;
01164         micro_delay(KBC_IN_DELAY);
01165         kbd_send();
01166         return 0;
01167   }
01168   if (bp)
01169         *bp= b;
01170   if (isauxp)
01171         *isauxp= !!(sb & KB_AUX_BYTE);
01172   if (kbdout.avail && !kbdout.expect_ack)
01173   {
01174         micro_delay(KBC_IN_DELAY);
01175         kbd_send();
01176   }
01177   return 1;
01178 #endif
01179 }
01180 
01181 static void micro_delay(unsigned long usecs)
01182 {
01183         tickdelay(MICROS_TO_TICKS(usecs));
01184 }
01185 
01186 /*===========================================================================*
01187  *                              kbd_watchdog                                 *
01188  *===========================================================================*/
01189 PRIVATE void kbd_watchdog(tmrp)
01190 timer_t *tmrp;
01191 {
01192         int r;
01193         clock_t now;
01194 
01195         kbd_watchdog_set= 0;
01196         if (!kbdout.avail)
01197                 return; /* Watchdog is no longer needed */
01198         if (!kbd_alive)
01199         {
01200                 printf("kbd_watchdog: should reset keyboard\n");
01201         }
01202         kbd_alive= 0;
01203 
01204         if ((r= getuptime(&now)) != OK)
01205                 panic("TTY","Keyboard couldn't get clock's uptime.", r);
01206         tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+HZ, kbd_watchdog,
01207                 NULL);
01208         if (tty_timers->tmr_exp_time != tty_next_timeout) {
01209                 tty_next_timeout = tty_timers->tmr_exp_time;
01210                 if ((r= sys_setalarm(tty_next_timeout, 1)) != OK)
01211                         panic("TTY","Keyboard couldn't set alarm.", r);
01212         }
01213         kbd_watchdog_set= 1;
01214 }

Generated on Fri Apr 14 22:57:19 2006 for minix by  doxygen 1.4.6