3.1.7 branch.
[minix.git] / drivers / tty / keyboard.c
blobaece6f9f86ed25248beba386064c64901d465493
1 /* Keyboard driver for PC's and AT's.
3 * Changes:
4 * Jul 13, 2004 processes can observe function keys (Jorrit N. Herder)
5 * Jun 15, 2004 removed wreboot(), except panic dumps (Jorrit N. Herder)
6 * Feb 04, 1994 loadable keymaps (Marcus Hampel)
7 */
9 #include <minix/drivers.h>
10 #include <sys/ioctl.h>
11 #include <sys/kbdio.h>
12 #include <sys/time.h>
13 #include <sys/select.h>
14 #include <termios.h>
15 #include <signal.h>
16 #include <unistd.h>
17 #include <machine/archtypes.h>
18 #include <minix/callnr.h>
19 #include <minix/com.h>
20 #include <minix/keymap.h>
21 #include "tty.h"
22 #include "kernel/const.h"
23 #include "kernel/config.h"
24 #include "kernel/type.h"
25 #include "kernel/proc.h"
27 PRIVATE u16_t keymap[NR_SCAN_CODES * MAP_COLS] = {
28 #include "keymaps/us-std.src"
31 PRIVATE u16_t keymap_escaped[NR_SCAN_CODES * MAP_COLS] = {
32 #include "keymaps/us-std-esc.src"
35 PRIVATE int irq_hook_id = -1;
36 PRIVATE int aux_irq_hook_id = -1;
38 /* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
39 #define KEYBD 0x60 /* I/O port for keyboard data */
41 /* AT keyboard. */
42 #define KB_COMMAND 0x64 /* I/O port for commands on AT */
43 #define KB_STATUS 0x64 /* I/O port for status on AT */
44 #define KB_ACK 0xFA /* keyboard ack response */
45 #define KB_AUX_BYTE 0x20 /* Auxiliary Device Output Buffer Full */
46 #define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */
47 #define KB_IN_FULL 0x02 /* status bit set when not ready to receive */
48 #define KBC_RD_RAM_CCB 0x20 /* Read controller command byte */
49 #define KBC_WR_RAM_CCB 0x60 /* Write controller command byte */
50 #define KBC_DI_AUX 0xA7 /* Disable Auxiliary Device */
51 #define KBC_EN_AUX 0xA8 /* Enable Auxiliary Device */
52 #define KBC_DI_KBD 0xAD /* Disable Keybard Interface */
53 #define KBC_EN_KBD 0xAE /* Enable Keybard Interface */
54 #define KBC_WRITE_AUX 0xD4 /* Write to Auxiliary Device */
55 #define LED_CODE 0xED /* command to keyboard to set LEDs */
56 #define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */
57 #define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */
58 #define KBIT 0x80 /* bit used to ack characters to keyboard */
60 #define KBC_IN_DELAY 7 /* wait 7 microseconds when polling */
62 /* Miscellaneous. */
63 #define ESC_SCAN 0x01 /* reboot key when panicking */
64 #define SLASH_SCAN 0x35 /* to recognize numeric slash */
65 #define RSHIFT_SCAN 0x36 /* to distinguish left and right shift */
66 #define HOME_SCAN 0x47 /* first key on the numeric keypad */
67 #define INS_SCAN 0x52 /* INS for use in CTRL-ALT-INS reboot */
68 #define DEL_SCAN 0x53 /* DEL for use in CTRL-ALT-DEL reboot */
70 #define KBD_BUFSZ 1024 /* Buffer size for raw scan codes */
71 #define KBD_OUT_BUFSZ 16 /* Output buffer to sending data to the
72 * keyboard.
75 #define CONSOLE 0 /* line number for console */
76 #define KB_IN_BYTES 32 /* size of keyboard input buffer */
77 PRIVATE char ibuf[KB_IN_BYTES]; /* input buffer */
78 PRIVATE char *ihead = ibuf; /* next free spot in input buffer */
79 PRIVATE char *itail = ibuf; /* scan code to return to TTY */
80 PRIVATE int icount; /* # codes in buffer */
82 PRIVATE int esc; /* escape scan code detected? */
83 PRIVATE int alt_l; /* left alt key state */
84 PRIVATE int alt_r; /* right alt key state */
85 PRIVATE int alt; /* either alt key */
86 PRIVATE int ctrl_l; /* left control key state */
87 PRIVATE int ctrl_r; /* right control key state */
88 PRIVATE int ctrl; /* either control key */
89 PRIVATE int shift_l; /* left shift key state */
90 PRIVATE int shift_r; /* right shift key state */
91 PRIVATE int shift; /* either shift key */
92 PRIVATE int num_down; /* num lock key depressed */
93 PRIVATE int caps_down; /* caps lock key depressed */
94 PRIVATE int scroll_down; /* scroll lock key depressed */
95 PRIVATE int alt_down; /* alt key depressed */
96 PRIVATE int locks[NR_CONS]; /* per console lock keys state */
98 /* Lock key active bits. Chosen to be equal to the keyboard LED bits. */
99 #define SCROLL_LOCK 0x01
100 #define NUM_LOCK 0x02
101 #define CAPS_LOCK 0x04
102 #define ALT_LOCK 0x08
104 PRIVATE char numpad_map[] =
105 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
107 PRIVATE char *fkey_map[] =
108 {"11", "12", "13", "14", "15", "17", /* F1-F6 */
109 "18", "19", "20", "21", "23", "24"}; /* F7-F12 */
111 /* Variables and definition for observed function keys. */
112 typedef struct observer { int proc_nr; int events; } obs_t;
113 PRIVATE obs_t fkey_obs[12]; /* observers for F1-F12 */
114 PRIVATE obs_t sfkey_obs[12]; /* observers for SHIFT F1-F12 */
116 PRIVATE struct kbd
118 int minor;
119 int nr_open;
120 char buf[KBD_BUFSZ];
121 int offset;
122 int avail;
123 int req_size;
124 int req_proc;
125 int req_safe; /* nonzero: safe (req_addr_g is grant) */
126 vir_bytes req_addr_g; /* Virtual address or grant */
127 vir_bytes req_addr_offset;
128 int incaller;
129 int select_ops;
130 int select_proc;
131 } kbd, kbdaux;
133 /* Data that is to be sent to the keyboard. Each byte is ACKed by the
134 * keyboard.
136 PRIVATE struct kbd_outack
138 unsigned char buf[KBD_OUT_BUFSZ];
139 int offset;
140 int avail;
141 int expect_ack;
142 } kbdout;
144 PRIVATE int kbd_watchdog_set= 0;
145 PRIVATE int kbd_alive= 1;
146 PRIVATE long sticky_alt_mode = 0;
147 PRIVATE long debug_fkeys = 1;
148 PRIVATE timer_t tmr_kbd_wd;
150 FORWARD _PROTOTYPE( void handle_req, (struct kbd *kbdp, message *m) );
151 FORWARD _PROTOTYPE( int handle_status, (struct kbd *kbdp, message *m) );
152 FORWARD _PROTOTYPE( void kbc_cmd0, (int cmd) );
153 FORWARD _PROTOTYPE( void kbc_cmd1, (int cmd, int data) );
154 FORWARD _PROTOTYPE( int kbc_read, (void) );
155 FORWARD _PROTOTYPE( void kbd_send, (void) );
156 FORWARD _PROTOTYPE( int kb_ack, (void) );
157 FORWARD _PROTOTYPE( int kb_wait, (void) );
158 FORWARD _PROTOTYPE( int func_key, (int scode) );
159 FORWARD _PROTOTYPE( int scan_keyboard, (unsigned char *bp, int *isauxp) );
160 FORWARD _PROTOTYPE( unsigned make_break, (int scode) );
161 FORWARD _PROTOTYPE( void set_leds, (void) );
162 FORWARD _PROTOTYPE( void show_key_mappings, (void) );
163 FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try) );
164 FORWARD _PROTOTYPE( unsigned map_key, (int scode) );
165 FORWARD _PROTOTYPE( void kbd_watchdog, (timer_t *tmrp) );
167 int micro_delay(u32_t usecs)
169 /* TTY can't use the library micro_delay() as that calls PM. */
170 tickdelay(micros_to_ticks(usecs));
171 return OK;
174 /*===========================================================================*
175 * do_kbd *
176 *===========================================================================*/
177 PUBLIC void do_kbd(message *m)
179 handle_req(&kbd, m);
183 /*===========================================================================*
184 * kbd_status *
185 *===========================================================================*/
186 PUBLIC int kbd_status(message *m)
188 int r;
190 r= handle_status(&kbd, m);
191 if (r)
192 return r;
193 return handle_status(&kbdaux, m);
197 /*===========================================================================*
198 * do_kbdaux *
199 *===========================================================================*/
200 PUBLIC void do_kbdaux(message *m)
202 handle_req(&kbdaux, m);
206 /*===========================================================================*
207 * handle_req *
208 *===========================================================================*/
209 PRIVATE void handle_req(kbdp, m)
210 struct kbd *kbdp;
211 message *m;
213 int i, n, r, ops, watch, safecopy = 0;
214 unsigned char c;
216 /* Execute the requested device driver function. */
217 r= EINVAL; /* just in case */
218 switch (m->m_type) {
219 case DEV_OPEN:
220 kbdp->nr_open++;
221 r= OK;
222 break;
223 case DEV_CLOSE:
224 kbdp->nr_open--;
225 if (kbdp->nr_open < 0)
227 printf("TTY(kbd): open count is negative\n");
228 kbdp->nr_open= 0;
230 if (kbdp->nr_open == 0)
231 kbdp->avail= 0;
232 r= OK;
233 break;
234 case DEV_READ_S:
235 safecopy = 1;
236 if (kbdp->req_size)
238 /* We handle only request at a time */
239 r= EIO;
240 break;
242 if (kbdp->avail == 0)
244 /* Should record proc */
245 kbdp->req_size= m->COUNT;
246 kbdp->req_proc= m->IO_ENDPT;
247 kbdp->req_addr_g= (vir_bytes)m->ADDRESS;
248 kbdp->req_addr_offset= 0;
249 kbdp->req_safe= safecopy;
250 kbdp->incaller= m->m_source;
251 r= SUSPEND;
252 break;
255 /* Handle read request */
256 n= kbdp->avail;
257 if (n > m->COUNT)
258 n= m->COUNT;
259 if (kbdp->offset + n > KBD_BUFSZ)
260 n= KBD_BUFSZ-kbdp->offset;
261 if (n <= 0)
262 panic("do_kbd(READ): bad n: %d", n);
263 if(safecopy) {
264 r= sys_safecopyto(m->IO_ENDPT, (vir_bytes) m->ADDRESS, 0,
265 (vir_bytes) &kbdp->buf[kbdp->offset], n, D);
266 } else {
267 r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
268 m->IO_ENDPT, D, (vir_bytes) m->ADDRESS, n);
270 if (r == OK)
272 kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
273 kbdp->avail -= n;
274 r= n;
275 } else {
276 printf("copy in read kbd failed: %d\n", r);
279 break;
281 case DEV_WRITE_S:
282 safecopy = 1;
283 if (kbdp != &kbdaux)
285 printf("write to keyboard not implemented\n");
286 r= EINVAL;
287 break;
290 /* Assume that output to AUX only happens during
291 * initialization and we can afford to lose input. This should
292 * be fixed at a later time.
294 for (i= 0; i<m->COUNT; i++)
296 if(safecopy) {
297 r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
298 m->ADDRESS, i, (vir_bytes)&c, 1, D);
299 } else {
300 r= sys_vircopy(m->IO_ENDPT, D,
301 (vir_bytes) m->ADDRESS+i,
302 SELF, D, (vir_bytes)&c, 1);
304 if (r != OK)
305 break;
306 kbc_cmd1(KBC_WRITE_AUX, c);
308 r= i;
309 break;
311 case CANCEL:
312 kbdp->req_size= 0;
313 r= OK;
314 break;
315 case DEV_SELECT:
316 ops = m->IO_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
317 watch = (m->IO_ENDPT & SEL_NOTIFY) ? 1 : 0;
319 r= 0;
320 if (kbdp->avail && (ops & SEL_RD))
322 r |= SEL_RD;
323 break;
326 if (ops && watch)
328 kbdp->select_ops |= ops;
329 kbdp->select_proc= m->m_source;
331 break;
332 case DEV_IOCTL_S:
333 safecopy=1;
334 if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS)
336 kio_leds_t leds;
337 unsigned char b;
340 if(safecopy) {
341 r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
342 m->ADDRESS, 0, (vir_bytes)&leds,
343 sizeof(leds), D);
344 } else {
345 r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
346 SELF, D, (vir_bytes)&leds, sizeof(leds));
348 if (r != OK)
349 break;
350 b= 0;
351 if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK;
352 if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK;
353 if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK;
354 if (kbdout.avail == 0)
355 kbdout.offset= 0;
356 if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ)
358 /* Output buffer is full. Ignore this command.
359 * Reset ACK flag.
361 kbdout.expect_ack= 0;
363 else
365 kbdout.buf[kbdout.offset+kbdout.avail]=
366 LED_CODE;
367 kbdout.buf[kbdout.offset+kbdout.avail+1]= b;
368 kbdout.avail += 2;
370 if (!kbdout.expect_ack)
371 kbd_send();
372 r= OK;
373 break;
375 if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL)
377 kio_bell_t bell;
378 clock_t ticks;
380 if(safecopy) {
381 r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
382 m->ADDRESS, 0, (vir_bytes)&bell,
383 sizeof(bell), D);
384 } else {
385 r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
386 SELF, D, (vir_bytes)&bell, sizeof(bell));
388 if (r != OK)
389 break;
391 ticks= bell.kb_duration.tv_usec * system_hz / 1000000;
392 ticks += bell.kb_duration.tv_sec * system_hz;
393 if (!ticks)
394 ticks++;
395 beep_x(bell.kb_pitch, ticks);
397 r= OK;
398 break;
400 r= ENOTTY;
401 break;
403 default:
404 printf("Warning, TTY(kbd) got unexpected request %d from %d\n",
405 m->m_type, m->m_source);
406 r= EINVAL;
408 tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
412 /*===========================================================================*
413 * handle_status *
414 *===========================================================================*/
415 PRIVATE int handle_status(kbdp, m)
416 struct kbd *kbdp;
417 message *m;
419 int n, r;
421 if (kbdp->avail && kbdp->req_size && m->m_source == kbdp->incaller)
423 /* Handle read request */
424 n= kbdp->avail;
425 if (n > kbdp->req_size)
426 n= kbdp->req_size;
427 if (kbdp->offset + n > KBD_BUFSZ)
428 n= KBD_BUFSZ-kbdp->offset;
429 if (n <= 0)
430 panic("kbd_status: bad n: %d", n);
431 kbdp->req_size= 0;
432 if(kbdp->req_safe) {
433 r= sys_safecopyto(kbdp->req_proc, kbdp->req_addr_g, 0,
434 (vir_bytes)&kbdp->buf[kbdp->offset], n, D);
435 } else {
436 r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
437 kbdp->req_proc, D, kbdp->req_addr_g, n);
439 if (r == OK)
441 kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
442 kbdp->avail -= n;
443 r= n;
444 } else printf("copy in revive kbd failed: %d\n", r);
446 m->m_type = DEV_REVIVE;
447 m->REP_ENDPT= kbdp->req_proc;
448 m->REP_IO_GRANT= kbdp->req_addr_g;
449 m->REP_STATUS= r;
450 return 1;
452 if (kbdp->avail && (kbdp->select_ops & SEL_RD) &&
453 m->m_source == kbdp->select_proc)
455 m->m_type = DEV_IO_READY;
456 m->DEV_MINOR = kbdp->minor;
457 m->DEV_SEL_OPS = SEL_RD;
459 kbdp->select_ops &= ~SEL_RD;
460 return 1;
463 return 0;
467 /*===========================================================================*
468 * map_key *
469 *===========================================================================*/
470 PRIVATE unsigned map_key(scode)
471 int scode;
473 /* Map a scan code to an ASCII code. */
475 int caps, column, lk;
476 u16_t *keyrow;
478 if(esc)
479 keyrow = &keymap_escaped[scode * MAP_COLS];
480 else
481 keyrow = &keymap[scode * MAP_COLS];
483 caps = shift;
484 lk = locks[ccurrent];
485 if ((lk & NUM_LOCK) && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps;
486 if ((lk & CAPS_LOCK) && (keyrow[0] & HASCAPS)) caps = !caps;
488 if (alt) {
489 column = 2;
490 if (ctrl || alt_r) column = 3; /* Ctrl + Alt == AltGr */
491 if (caps) column = 4;
492 } else {
493 if (sticky_alt_mode && (lk & ALT_LOCK)) {
494 column = 2;
495 if (caps) column = 4;
496 } else {
497 column = 0;
498 if (caps) column = 1;
499 if (ctrl) column = 5;
502 return keyrow[column] & ~HASCAPS;
505 /*===========================================================================*
506 * kbd_interrupt *
507 *===========================================================================*/
508 PUBLIC void kbd_interrupt(m_ptr)
509 message *m_ptr;
511 /* A keyboard interrupt has occurred. Process it. */
512 int o, isaux;
513 unsigned char scode;
514 struct kbd *kbdp;
516 /* Fetch the character from the keyboard hardware and acknowledge it. */
517 if (!scan_keyboard(&scode, &isaux))
518 return;
520 if (isaux)
521 kbdp= &kbdaux;
522 else if (kbd.nr_open)
523 kbdp= &kbd;
524 else
525 kbdp= NULL;
527 if (kbdp)
529 /* raw scan codes or aux data */
530 if (kbdp->avail >= KBD_BUFSZ)
532 #if 0
533 printf("kbd_interrupt: %s buffer is full\n",
534 isaux ? "kbdaux" : "keyboard");
535 #endif
536 return; /* Buffer is full */
538 o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ;
539 kbdp->buf[o]= scode;
540 kbdp->avail++;
541 if (kbdp->req_size) {
542 notify(kbdp->incaller);
544 if (kbdp->select_ops & SEL_RD)
545 notify(kbdp->select_proc);
546 return;
549 /* Store the scancode in memory so the task can get at it later. */
550 if (icount < KB_IN_BYTES) {
551 *ihead++ = scode;
552 if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf;
553 icount++;
554 tty_table[ccurrent].tty_events = 1;
555 if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
556 select_retry(&tty_table[ccurrent]);
561 /*===========================================================================*
562 * kb_read *
563 *===========================================================================*/
564 PRIVATE int kb_read(tp, try)
565 tty_t *tp;
566 int try;
568 /* Process characters from the circular keyboard buffer. */
569 char buf[7], *p, suffix;
570 int scode;
571 unsigned ch;
573 tp = &tty_table[ccurrent]; /* always use the current console */
575 if (try) {
576 if (icount > 0) return 1;
577 return 0;
580 while (icount > 0) {
581 scode = *itail++; /* take one key scan code */
582 if (itail == ibuf + KB_IN_BYTES) itail = ibuf;
583 icount--;
585 /* Function keys are being used for debug dumps (if enabled). */
586 if (debug_fkeys && func_key(scode)) continue;
588 /* Perform make/break processing. */
589 ch = make_break(scode);
591 if (ch <= 0xFF) {
592 /* A normal character. */
593 buf[0] = ch;
594 (void) in_process(tp, buf, 1, scode);
595 } else
596 if (HOME <= ch && ch <= INSRT) {
597 /* An ASCII escape sequence generated by the numeric pad. */
598 buf[0] = ESC;
599 buf[1] = '[';
600 buf[2] = numpad_map[ch - HOME];
601 (void) in_process(tp, buf, 3, scode);
602 } else
603 if ((F1 <= ch && ch <= F12) || (SF1 <= ch && ch <= SF12) ||
604 (CF1 <= ch && ch <= CF12 && !debug_fkeys)) {
605 /* An escape sequence generated by function keys. */
606 if (F1 <= ch && ch <= F12) {
607 ch -= F1;
608 suffix = 0;
609 } else
610 if (SF1 <= ch && ch <= SF12) {
611 ch -= SF1;
612 suffix = '2';
613 } else
614 if (CF1 <= ch && ch <= CF12) {
615 ch -= CF1;
616 suffix = shift ? '6' : '5';
618 /* ^[[11~ for F1, ^[[24;5~ for CF12 etc */
619 buf[0] = ESC;
620 buf[1] = '[';
621 buf[2] = fkey_map[ch][0];
622 buf[3] = fkey_map[ch][1];
623 p = &buf[4];
624 if (suffix) {
625 *p++ = ';';
626 *p++ = suffix;
628 *p++ = '~';
629 (void) in_process(tp, buf, p - buf, scode);
630 } else
631 if (ch == ALEFT) {
632 /* Choose lower numbered console as current console. */
633 select_console(ccurrent - 1);
634 set_leds();
635 } else
636 if (ch == ARIGHT) {
637 /* Choose higher numbered console as current console. */
638 select_console(ccurrent + 1);
639 set_leds();
640 } else
641 if (AF1 <= ch && ch <= AF12) {
642 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
643 select_console(ch - AF1);
644 set_leds();
645 } else
646 if (CF1 <= ch && ch <= CF12) {
647 switch(ch) {
648 case CF1: show_key_mappings(); break;
649 case CF3: toggle_scroll(); break; /* hardware <-> software */
650 case CF7: sigchar(&tty_table[CONSOLE], SIGQUIT, 1); break;
651 case CF8: sigchar(&tty_table[CONSOLE], SIGINT, 1); break;
652 case CF9: sigchar(&tty_table[CONSOLE], SIGKILL, 1); break;
654 } else {
655 /* pass on scancode even though there is no character code */
656 (void) in_process(tp, NULL, 0, scode);
660 return 1;
663 /*===========================================================================*
664 * kbd_send *
665 *===========================================================================*/
666 PRIVATE void kbd_send()
668 unsigned long sb;
669 int r;
670 clock_t now;
672 if (!kbdout.avail)
673 return;
674 if (kbdout.expect_ack)
675 return;
677 if((r=sys_inb(KB_STATUS, &sb)) != OK) {
678 printf("kbd_send: 1 sys_inb() failed: %d\n", r);
680 if (sb & (KB_OUT_FULL|KB_IN_FULL))
682 printf("not sending 1: sb = 0x%lx\n", sb);
683 return;
685 micro_delay(KBC_IN_DELAY);
686 if((r=sys_inb(KB_STATUS, &sb)) != OK) {
687 printf("kbd_send: 2 sys_inb() failed: %d\n", r);
689 if (sb & (KB_OUT_FULL|KB_IN_FULL))
691 printf("not sending 2: sb = 0x%lx\n", sb);
692 return;
695 /* Okay, buffer is really empty */
696 #if 0
697 printf("sending byte 0x%x to keyboard\n", kbdout.buf[kbdout.offset]);
698 #endif
699 if((r=sys_outb(KEYBD, kbdout.buf[kbdout.offset])) != OK) {
700 printf("kbd_send: 3 sys_inb() failed: %d\n", r);
702 kbdout.offset++;
703 kbdout.avail--;
704 kbdout.expect_ack= 1;
706 kbd_alive= 1;
707 if (kbd_watchdog_set)
709 /* Add a timer to the timers list. Possibly reschedule the
710 * alarm.
712 if ((r= getuptime(&now)) != OK)
713 panic("Keyboard couldn't get clock's uptime: %d", r);
714 tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+system_hz, kbd_watchdog,
715 NULL);
716 if (tty_timers->tmr_exp_time != tty_next_timeout) {
717 tty_next_timeout = tty_timers->tmr_exp_time;
718 if ((r= sys_setalarm(tty_next_timeout, 1)) != OK)
719 panic("Keyboard couldn't set alarm: %d", r);
721 kbd_watchdog_set= 1;
725 /*===========================================================================*
726 * make_break *
727 *===========================================================================*/
728 PRIVATE unsigned make_break(scode)
729 int scode; /* scan code of key just struck or released */
731 /* This routine can handle keyboards that interrupt only on key depression,
732 * as well as keyboards that interrupt on key depression and key release.
733 * For efficiency, the interrupt routine filters out most key releases.
735 int ch, make, escape;
736 static int CAD_count = 0;
737 static int rebooting = 0;
739 /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would
740 * be better done in keyboard() in case TTY is hung, except control and
741 * alt are set in the high level code.
743 if (ctrl && alt && (scode == DEL_SCAN || scode == INS_SCAN))
745 if (++CAD_count == 3) {
746 cons_stop();
747 sys_abort(RBT_HALT);
749 sys_kill(INIT_PROC_NR, SIGABRT);
750 rebooting = 1;
753 if(rebooting)
754 return -1;
756 /* High-order bit set on key release. */
757 make = (scode & KEY_RELEASE) == 0; /* true if pressed */
759 ch = map_key(scode &= ASCII_MASK); /* map to ASCII */
761 escape = esc; /* Key is escaped? (true if added since the XT) */
762 esc = 0;
764 switch (ch) {
765 case CTRL: /* Left or right control key */
766 *(escape ? &ctrl_r : &ctrl_l) = make;
767 ctrl = ctrl_l | ctrl_r;
768 break;
769 case SHIFT: /* Left or right shift key */
770 *(scode == RSHIFT_SCAN ? &shift_r : &shift_l) = make;
771 shift = shift_l | shift_r;
772 break;
773 case ALT: /* Left or right alt key */
774 *(escape ? &alt_r : &alt_l) = make;
775 alt = alt_l | alt_r;
776 if (sticky_alt_mode && (alt_r && (alt_down < make))) {
777 locks[ccurrent] ^= ALT_LOCK;
779 alt_down = make;
780 break;
781 case CALOCK: /* Caps lock - toggle on 0 -> 1 transition */
782 if (caps_down < make) {
783 locks[ccurrent] ^= CAPS_LOCK;
784 set_leds();
786 caps_down = make;
787 break;
788 case NLOCK: /* Num lock */
789 if (num_down < make) {
790 locks[ccurrent] ^= NUM_LOCK;
791 set_leds();
793 num_down = make;
794 break;
795 case SLOCK: /* Scroll lock */
796 if (scroll_down < make) {
797 locks[ccurrent] ^= SCROLL_LOCK;
798 set_leds();
800 scroll_down = make;
801 break;
802 case EXTKEY: /* Escape keycode */
803 esc = 1; /* Next key is escaped */
804 return(-1);
805 default: /* A normal key */
806 if(!make)
807 return -1;
808 if(ch)
809 return ch;
811 static char seen[2][NR_SCAN_CODES];
812 int notseen = 0, ei;
813 ei = escape ? 1 : 0;
814 if(scode >= 0 && scode < NR_SCAN_CODES) {
815 notseen = !seen[ei][scode];
816 seen[ei][scode] = 1;
817 } else {
818 printf("tty: scode %d makes no sense\n", scode);
820 if(notseen) {
821 printf("tty: ignoring unrecognized %s "
822 "scancode 0x%x\n",
823 escape ? "escaped" : "straight", scode);
826 return -1;
829 /* Key release, or a shift type key. */
830 return(-1);
833 /*===========================================================================*
834 * set_leds *
835 *===========================================================================*/
836 PRIVATE void set_leds()
838 /* Set the LEDs on the caps, num, and scroll lock keys */
839 int s;
840 if (! machine.pc_at) return; /* PC/XT doesn't have LEDs */
842 kb_wait(); /* wait for buffer empty */
843 if ((s=sys_outb(KEYBD, LED_CODE)) != OK)
844 printf("Warning, sys_outb couldn't prepare for LED values: %d\n", s);
845 /* prepare keyboard to accept LED values */
846 kb_ack(); /* wait for ack response */
848 kb_wait(); /* wait for buffer empty */
849 if ((s=sys_outb(KEYBD, locks[ccurrent])) != OK)
850 printf("Warning, sys_outb couldn't give LED values: %d\n", s);
851 /* give keyboard LED values */
852 kb_ack(); /* wait for ack response */
855 /*===========================================================================*
856 * kbc_cmd0 *
857 *===========================================================================*/
858 PRIVATE void kbc_cmd0(cmd)
859 int cmd;
861 kb_wait();
862 if(sys_outb(KB_COMMAND, cmd) != OK)
863 printf("kbc_cmd0: sys_outb failed\n");
866 /*===========================================================================*
867 * kbc_cmd1 *
868 *===========================================================================*/
869 PRIVATE void kbc_cmd1(cmd, data)
870 int cmd;
871 int data;
873 kb_wait();
874 if(sys_outb(KB_COMMAND, cmd) != OK)
875 printf("kbc_cmd1: 1 sys_outb failed\n");
876 kb_wait();
877 if(sys_outb(KEYBD, data) != OK)
878 printf("kbc_cmd1: 2 sys_outb failed\n");
882 /*===========================================================================*
883 * kbc_read *
884 *===========================================================================*/
885 PRIVATE int kbc_read()
887 int i;
888 unsigned long byte, st;
889 #if 0
890 struct micro_state ms;
891 #endif
893 #if DEBUG
894 printf("in kbc_read\n");
895 #endif
897 /* Wait at most 1 second for a byte from the keyboard or
898 * the kbd controller, return -1 on a timeout.
900 for (i= 0; i<1000000; i++)
901 #if 0
902 micro_start(&ms);
904 #endif
906 if(sys_inb(KB_STATUS, &st) != OK)
907 printf("kbc_read: 1 sys_inb failed\n");
908 if (st & KB_OUT_FULL)
910 micro_delay(KBC_IN_DELAY);
911 if(sys_inb(KEYBD, &byte) != OK)
912 printf("kbc_read: 2 sys_inb failed\n");
913 if (st & KB_AUX_BYTE)
914 printf("kbc_read: aux byte 0x%x\n", byte);
915 #if DEBUG
916 printf("keyboard`kbc_read: returning byte 0x%x\n",
917 byte);
918 #endif
919 return byte;
922 #if 0
923 while (micro_elapsed(&ms) < 1000000);
924 #endif
925 panic("kbc_read failed to complete");
926 return EINVAL;
930 /*===========================================================================*
931 * kb_wait *
932 *===========================================================================*/
933 PRIVATE int kb_wait()
935 /* Wait until the controller is ready; return zero if this times out. */
937 int retries;
938 unsigned long status;
939 int s, isaux;
940 unsigned char byte;
942 retries = MAX_KB_BUSY_RETRIES + 1; /* wait until not busy */
943 do {
944 s = sys_inb(KB_STATUS, &status);
945 if(s != OK)
946 printf("kb_wait: sys_inb failed: %d\n", s);
947 if (status & KB_OUT_FULL) {
948 if (scan_keyboard(&byte, &isaux))
950 #if 0
951 printf("ignoring %sbyte in kb_wait\n", isaux ? "AUX " : "");
952 #endif
955 if (! (status & (KB_IN_FULL|KB_OUT_FULL)) )
956 break; /* wait until ready */
957 } while (--retries != 0); /* continue unless timeout */
958 return(retries); /* zero on timeout, positive if ready */
961 /*===========================================================================*
962 * kb_ack *
963 *===========================================================================*/
964 PRIVATE int kb_ack()
966 /* Wait until kbd acknowledges last command; return zero if this times out. */
968 int retries, s;
969 unsigned long u8val;
972 retries = MAX_KB_ACK_RETRIES + 1;
973 do {
974 s = sys_inb(KEYBD, &u8val);
975 if(s != OK)
976 printf("kb_ack: sys_inb failed: %d\n", s);
977 if (u8val == KB_ACK)
978 break; /* wait for ack */
979 } while(--retries != 0); /* continue unless timeout */
981 return(retries); /* nonzero if ack received */
984 /*===========================================================================*
985 * kb_init *
986 *===========================================================================*/
987 PUBLIC void kb_init(tp)
988 tty_t *tp;
990 /* Initialize the keyboard driver. */
992 tp->tty_devread = kb_read; /* input function */
995 /*===========================================================================*
996 * kb_init_once *
997 *===========================================================================*/
998 PUBLIC void kb_init_once(void)
1000 int i;
1001 u8_t ccb;
1003 env_parse("sticky_alt", "d", 0, &sticky_alt_mode, 0, 1);
1004 env_parse("debug_fkeys", "d", 0, &debug_fkeys, 0, 1);
1006 set_leds(); /* turn off numlock led */
1007 scan_keyboard(NULL, NULL); /* discard leftover keystroke */
1009 /* Clear the function key observers array. Also see func_key(). */
1010 for (i=0; i<12; i++) {
1011 fkey_obs[i].proc_nr = NONE; /* F1-F12 observers */
1012 fkey_obs[i].events = 0; /* F1-F12 observers */
1013 sfkey_obs[i].proc_nr = NONE; /* Shift F1-F12 observers */
1014 sfkey_obs[i].events = 0; /* Shift F1-F12 observers */
1017 kbd.minor= KBD_MINOR;
1018 kbdaux.minor= KBDAUX_MINOR;
1020 /* Set interrupt handler and enable keyboard IRQ. */
1021 irq_hook_id = KEYBOARD_IRQ; /* id to be returned on interrupt */
1022 if ((i=sys_irqsetpolicy(KEYBOARD_IRQ, IRQ_REENABLE, &irq_hook_id)) != OK)
1023 panic("Couldn't set keyboard IRQ policy: %d", i);
1024 if ((i=sys_irqenable(&irq_hook_id)) != OK)
1025 panic("Couldn't enable keyboard IRQs: %d", i);
1026 kbd_irq_set |= (1 << KEYBOARD_IRQ);
1028 /* Set AUX interrupt handler and enable AUX IRQ. */
1029 aux_irq_hook_id = KBD_AUX_IRQ; /* id to be returned on interrupt */
1030 if ((i=sys_irqsetpolicy(KBD_AUX_IRQ, IRQ_REENABLE,
1031 &aux_irq_hook_id)) != OK)
1032 panic("Couldn't set AUX IRQ policy: %d", i);
1033 if ((i=sys_irqenable(&aux_irq_hook_id)) != OK)
1034 panic("Couldn't enable AUX IRQs: %d", i);
1035 kbd_irq_set |= (1 << KBD_AUX_IRQ);
1037 /* Disable the keyboard and aux */
1038 kbc_cmd0(KBC_DI_KBD);
1039 kbc_cmd0(KBC_DI_AUX);
1041 /* Get the current configuration byte */
1042 kbc_cmd0(KBC_RD_RAM_CCB);
1043 ccb= kbc_read();
1045 /* Enable both interrupts. */
1046 kbc_cmd1(KBC_WR_RAM_CCB, ccb | 3);
1048 /* Re-enable the keyboard device. */
1049 kbc_cmd0(KBC_EN_KBD);
1051 /* Enable the aux device. */
1052 kbc_cmd0(KBC_EN_AUX);
1055 /*===========================================================================*
1056 * kbd_loadmap *
1057 *===========================================================================*/
1058 PUBLIC int kbd_loadmap(m, safe)
1059 message *m;
1060 int safe;
1062 /* Load a new keymap. */
1063 int result;
1064 if(safe) {
1065 result = sys_safecopyfrom(m->IO_ENDPT, (vir_bytes) m->ADDRESS,
1066 0, (vir_bytes) keymap, (vir_bytes) sizeof(keymap), D);
1067 } else {
1068 result = sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
1069 SELF, D, (vir_bytes) keymap,
1070 (vir_bytes) sizeof(keymap));
1072 return(result);
1075 /*===========================================================================*
1076 * do_fkey_ctl *
1077 *===========================================================================*/
1078 PUBLIC void do_fkey_ctl(m_ptr)
1079 message *m_ptr; /* pointer to the request message */
1081 /* This procedure allows processes to register a function key to receive
1082 * notifications if it is pressed. At most one binding per key can exist.
1084 int i;
1085 int result = EINVAL;
1087 switch (m_ptr->FKEY_REQUEST) { /* see what we must do */
1088 case FKEY_MAP: /* request for new mapping */
1089 result = OK; /* assume everything will be ok*/
1090 for (i=0; i < 12; i++) { /* check F1-F12 keys */
1091 if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
1092 #if DEAD_CODE
1093 /* Currently, we don't check if the slot is in use, so that IS
1094 * can recover after a crash by overtaking its existing mappings.
1095 * In future, a better solution will be implemented.
1097 if (fkey_obs[i].proc_nr == NONE) {
1098 #endif
1099 fkey_obs[i].proc_nr = m_ptr->m_source;
1100 fkey_obs[i].events = 0;
1101 bit_unset(m_ptr->FKEY_FKEYS, i+1);
1102 #if DEAD_CODE
1103 } else {
1104 printf("WARNING, fkey_map failed F%d\n", i+1);
1105 result = EBUSY; /* report failure, but try rest */
1107 #endif
1110 for (i=0; i < 12; i++) { /* check Shift+F1-F12 keys */
1111 if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
1112 #if DEAD_CODE
1113 if (sfkey_obs[i].proc_nr == NONE) {
1114 #endif
1115 sfkey_obs[i].proc_nr = m_ptr->m_source;
1116 sfkey_obs[i].events = 0;
1117 bit_unset(m_ptr->FKEY_SFKEYS, i+1);
1118 #if DEAD_CODE
1119 } else {
1120 printf("WARNING, fkey_map failed Shift F%d\n", i+1);
1121 result = EBUSY; /* report failure but try rest */
1123 #endif
1126 break;
1127 case FKEY_UNMAP:
1128 result = OK; /* assume everything will be ok*/
1129 for (i=0; i < 12; i++) { /* check F1-F12 keys */
1130 if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
1131 if (fkey_obs[i].proc_nr == m_ptr->m_source) {
1132 fkey_obs[i].proc_nr = NONE;
1133 fkey_obs[i].events = 0;
1134 bit_unset(m_ptr->FKEY_FKEYS, i+1);
1135 } else {
1136 result = EPERM; /* report failure, but try rest */
1140 for (i=0; i < 12; i++) { /* check Shift+F1-F12 keys */
1141 if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
1142 if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
1143 sfkey_obs[i].proc_nr = NONE;
1144 sfkey_obs[i].events = 0;
1145 bit_unset(m_ptr->FKEY_SFKEYS, i+1);
1146 } else {
1147 result = EPERM; /* report failure, but try rest */
1151 break;
1152 case FKEY_EVENTS:
1153 m_ptr->FKEY_FKEYS = m_ptr->FKEY_SFKEYS = 0;
1154 for (i=0; i < 12; i++) { /* check (Shift+) F1-F12 keys */
1155 if (fkey_obs[i].proc_nr == m_ptr->m_source) {
1156 if (fkey_obs[i].events) {
1157 bit_set(m_ptr->FKEY_FKEYS, i+1);
1158 fkey_obs[i].events = 0;
1161 if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
1162 if (sfkey_obs[i].events) {
1163 bit_set(m_ptr->FKEY_SFKEYS, i+1);
1164 sfkey_obs[i].events = 0;
1168 break;
1171 /* Almost done, return result to caller. */
1172 m_ptr->m_type = result;
1173 send(m_ptr->m_source, m_ptr);
1176 /*===========================================================================*
1177 * func_key *
1178 *===========================================================================*/
1179 PRIVATE int func_key(scode)
1180 int scode; /* scan code for a function key */
1182 /* This procedure traps function keys for debugging purposes. Observers of
1183 * function keys are kept in a global array. If a subject (a key) is pressed
1184 * the observer is notified of the event. Initialization of the arrays is done
1185 * in kb_init, where NONE is set to indicate there is no interest in the key.
1186 * Returns FALSE on a key release or if the key is not observable.
1188 int key;
1189 int proc_nr;
1191 /* Ignore key releases. If this is a key press, get full key code. */
1192 if (scode & KEY_RELEASE) return(FALSE); /* key release */
1193 key = map_key(scode); /* include modifiers */
1195 /* Key pressed, now see if there is an observer for the pressed key.
1196 * F1-F12 observers are in fkey_obs array.
1197 * SHIFT F1-F12 observers are in sfkey_req array.
1198 * CTRL F1-F12 reserved (see kb_read)
1199 * ALT F1-F12 reserved (see kb_read)
1200 * Other combinations are not in use. Note that Alt+Shift+F1-F12 is yet
1201 * defined in <minix/keymap.h>, and thus is easy for future extensions.
1203 if (F1 <= key && key <= F12) { /* F1-F12 */
1204 proc_nr = fkey_obs[key - F1].proc_nr;
1205 fkey_obs[key - F1].events ++ ;
1206 } else if (SF1 <= key && key <= SF12) { /* Shift F2-F12 */
1207 proc_nr = sfkey_obs[key - SF1].proc_nr;
1208 sfkey_obs[key - SF1].events ++;
1210 else {
1211 return(FALSE); /* not observable */
1214 /* See if an observer is registered and send it a message. */
1215 if (proc_nr != NONE) {
1216 notify(proc_nr);
1218 return(TRUE);
1221 /*===========================================================================*
1222 * show_key_mappings *
1223 *===========================================================================*/
1224 PRIVATE void show_key_mappings()
1226 int i,s;
1227 struct proc proc;
1229 printf("\n");
1230 printf("System information. Known function key mappings to request debug dumps:\n");
1231 printf("-------------------------------------------------------------------------\n");
1232 for (i=0; i<12; i++) {
1234 printf(" %sF%d: ", i+1<10? " ":"", i+1);
1235 if (fkey_obs[i].proc_nr != NONE) {
1236 if ((s = sys_getproc(&proc, fkey_obs[i].proc_nr))!=OK)
1237 printf("%-14.14s", "<unknown>");
1238 else
1239 printf("%-14.14s", proc.p_name);
1240 } else {
1241 printf("%-14.14s", "<none>");
1244 printf(" %sShift-F%d: ", i+1<10? " ":"", i+1);
1245 if (sfkey_obs[i].proc_nr != NONE) {
1246 if ((s = sys_getproc(&proc, sfkey_obs[i].proc_nr))!=OK)
1247 printf("%-14.14s", "<unknown>");
1248 else
1249 printf("%-14.14s", proc.p_name);
1250 } else {
1251 printf("%-14.14s", "<none>");
1253 printf("\n");
1255 printf("\n");
1256 printf("Press one of the registered function keys to trigger a debug dump.\n");
1257 printf("\n");
1260 /*===========================================================================*
1261 * scan_keyboard *
1262 *===========================================================================*/
1263 PRIVATE int scan_keyboard(bp, isauxp)
1264 unsigned char *bp;
1265 int *isauxp;
1267 unsigned long b, sb;
1269 if(sys_inb(KB_STATUS, &sb) != OK)
1270 printf("scan_keyboard: sys_inb failed\n");
1272 if (!(sb & KB_OUT_FULL))
1274 if (kbdout.avail && !kbdout.expect_ack)
1275 kbd_send();
1276 return 0;
1278 if(sys_inb(KEYBD, &b) != OK)
1279 printf("scan_keyboard: 2 sys_inb failed\n");
1280 #if 0
1281 printf("got byte 0x%x from %s\n", b, (sb & KB_AUX_BYTE) ? "AUX" : "keyboard");
1282 #endif
1283 if (!(sb & KB_AUX_BYTE) && b == KB_ACK && kbdout.expect_ack)
1285 #if 0
1286 printf("got ACK from keyboard\n");
1287 #endif
1288 kbdout.expect_ack= 0;
1289 micro_delay(KBC_IN_DELAY);
1290 kbd_send();
1291 return 0;
1293 if (bp)
1294 *bp= b;
1295 if (isauxp)
1296 *isauxp= !!(sb & KB_AUX_BYTE);
1297 if (kbdout.avail && !kbdout.expect_ack)
1299 micro_delay(KBC_IN_DELAY);
1300 kbd_send();
1302 return 1;
1305 /*===========================================================================*
1306 * kbd_watchdog *
1307 *===========================================================================*/
1308 PRIVATE void kbd_watchdog(tmrp)
1309 timer_t *tmrp;
1311 int r;
1312 clock_t now;
1314 kbd_watchdog_set= 0;
1315 if (!kbdout.avail)
1316 return; /* Watchdog is no longer needed */
1317 if (!kbd_alive)
1319 printf("kbd_watchdog: should reset keyboard\n");
1321 kbd_alive= 0;
1323 if ((r= getuptime(&now)) != OK)
1324 panic("Keyboard couldn't get clock's uptime: %d", r);
1325 tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+system_hz, kbd_watchdog,
1326 NULL);
1327 if (tty_timers->tmr_exp_time != tty_next_timeout) {
1328 tty_next_timeout = tty_timers->tmr_exp_time;
1329 if ((r= sys_setalarm(tty_next_timeout, 1)) != OK)
1330 panic("Keyboard couldn't set alarm: %d", r);
1332 kbd_watchdog_set= 1;