memory: use sys_safememset() for /dev/zero
[minix.git] / drivers / tty / keyboard.c
blob181cd29f119c05076795959701071a79d47ede2e
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/input.h>
21 #include <minix/keymap.h>
22 #include "tty.h"
23 #include "kernel/const.h"
24 #include "kernel/config.h"
25 #include "kernel/type.h"
26 #include "kernel/proc.h"
28 static u16_t keymap[NR_SCAN_CODES * MAP_COLS] = {
29 #include "keymaps/us-std.src"
32 static u16_t keymap_escaped[NR_SCAN_CODES * MAP_COLS] = {
33 #include "keymaps/us-std-esc.src"
36 static int irq_hook_id = -1;
37 static int aux_irq_hook_id = -1;
39 /* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
40 #define KEYBD 0x60 /* I/O port for keyboard data */
42 /* AT keyboard. */
43 #define KB_COMMAND 0x64 /* I/O port for commands on AT */
44 #define KB_STATUS 0x64 /* I/O port for status on AT */
45 #define KB_ACK 0xFA /* keyboard ack response */
46 #define KB_AUX_BYTE 0x20 /* Auxiliary Device Output Buffer Full */
47 #define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */
48 #define KB_IN_FULL 0x02 /* status bit set when not ready to receive */
49 #define KBC_RD_RAM_CCB 0x20 /* Read controller command byte */
50 #define KBC_WR_RAM_CCB 0x60 /* Write controller command byte */
51 #define KBC_DI_AUX 0xA7 /* Disable Auxiliary Device */
52 #define KBC_EN_AUX 0xA8 /* Enable Auxiliary Device */
53 #define KBC_DI_KBD 0xAD /* Disable Keybard Interface */
54 #define KBC_EN_KBD 0xAE /* Enable Keybard Interface */
55 #define KBC_WRITE_AUX 0xD4 /* Write to Auxiliary Device */
56 #define LED_CODE 0xED /* command to keyboard to set LEDs */
57 #define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */
58 #define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */
59 #define KBIT 0x80 /* bit used to ack characters to keyboard */
61 #define KBC_IN_DELAY 7 /* wait 7 microseconds when polling */
63 /* Miscellaneous. */
64 #define ESC_SCAN 0x01 /* reboot key when panicking */
65 #define SLASH_SCAN 0x35 /* to recognize numeric slash */
66 #define RSHIFT_SCAN 0x36 /* to distinguish left and right shift */
67 #define HOME_SCAN 0x47 /* first key on the numeric keypad */
68 #define INS_SCAN 0x52 /* INS for use in CTRL-ALT-INS reboot */
69 #define DEL_SCAN 0x53 /* DEL for use in CTRL-ALT-DEL reboot */
71 #define KBD_BUFSZ 1024 /* Buffer size for raw scan codes */
72 #define KBD_OUT_BUFSZ 16 /* Output buffer to sending data to the
73 * keyboard.
76 #define CONSOLE 0 /* line number for console */
77 #define KB_IN_BYTES 32 /* size of keyboard input buffer */
79 static char injbuf[KB_IN_BYTES];
80 static char *injhead = injbuf;
81 static char *injtail = injbuf;
82 static int injcount;
84 static char ibuf[KB_IN_BYTES]; /* input buffer */
85 static char *ihead = ibuf; /* next free spot in input buffer */
86 static char *itail = ibuf; /* scan code to return to TTY */
87 static int icount; /* # codes in buffer */
89 static int esc; /* escape scan code detected? */
90 static int alt_l; /* left alt key state */
91 static int alt_r; /* right alt key state */
92 static int alt; /* either alt key */
93 static int ctrl_l; /* left control key state */
94 static int ctrl_r; /* right control key state */
95 static int ctrl; /* either control key */
96 static int shift_l; /* left shift key state */
97 static int shift_r; /* right shift key state */
98 static int shift; /* either shift key */
99 static int num_down; /* num lock key depressed */
100 static int caps_down; /* caps lock key depressed */
101 static int scroll_down; /* scroll lock key depressed */
102 static int alt_down; /* alt key depressed */
103 static int locks[NR_CONS]; /* per console lock keys state */
105 /* Lock key active bits. Chosen to be equal to the keyboard LED bits. */
106 #define SCROLL_LOCK 0x01
107 #define NUM_LOCK 0x02
108 #define CAPS_LOCK 0x04
109 #define ALT_LOCK 0x08
111 static char numpad_map[12] =
112 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
114 static char *fkey_map[12] =
115 {"11", "12", "13", "14", "15", "17", /* F1-F6 */
116 "18", "19", "20", "21", "23", "24"}; /* F7-F12 */
118 /* Variables and definition for observed function keys. */
119 typedef struct observer { int proc_nr; int events; } obs_t;
120 static obs_t fkey_obs[12]; /* observers for F1-F12 */
121 static obs_t sfkey_obs[12]; /* observers for SHIFT F1-F12 */
123 static struct kbd
125 int minor;
126 int nr_open;
127 char buf[KBD_BUFSZ];
128 int offset;
129 int avail;
130 int req_size;
131 int req_proc;
132 cp_grant_id_t req_grant;
133 vir_bytes req_addr_offset;
134 int incaller;
135 int select_ops;
136 int select_proc;
137 } kbd, kbdaux;
139 /* Data that is to be sent to the keyboard. Each byte is ACKed by the
140 * keyboard.
142 static struct kbd_outack
144 unsigned char buf[KBD_OUT_BUFSZ];
145 int offset;
146 int avail;
147 int expect_ack;
148 } kbdout;
150 static int kbd_watchdog_set= 0;
151 static int kbd_alive= 1;
152 static long sticky_alt_mode = 0;
153 static long debug_fkeys = 1;
154 static timer_t tmr_kbd_wd;
156 static void handle_req(struct kbd *kbdp, message *m);
157 static int handle_status(struct kbd *kbdp, message *m);
158 static void kbc_cmd0(int cmd);
159 static void kbc_cmd1(int cmd, int data);
160 static int kbc_read(void);
161 static void kbd_send(void);
162 static int kb_ack(void);
163 static int kb_wait(void);
164 static int func_key(int scode);
165 static int scan_keyboard(unsigned char *bp, int *isauxp);
166 static unsigned make_break(int scode);
167 static void set_leds(void);
168 static void show_key_mappings(void);
169 static int kb_read(struct tty *tp, int try);
170 static unsigned map_key(int scode);
171 static void kbd_watchdog(timer_t *tmrp);
173 int micro_delay(u32_t usecs)
175 /* TTY can't use the library micro_delay() as that calls PM. */
176 tickdelay(micros_to_ticks(usecs));
177 return OK;
180 /*===========================================================================*
181 * do_kbd *
182 *===========================================================================*/
183 void do_kbd(message *m)
185 handle_req(&kbd, m);
189 /*===========================================================================*
190 * kbd_status *
191 *===========================================================================*/
192 int kbd_status(message *m)
194 int r;
196 r= handle_status(&kbd, m);
197 if (r)
198 return r;
199 return handle_status(&kbdaux, m);
203 /*===========================================================================*
204 * do_kbdaux *
205 *===========================================================================*/
206 void do_kbdaux(message *m)
208 handle_req(&kbdaux, m);
212 /*===========================================================================*
213 * handle_req *
214 *===========================================================================*/
215 static void handle_req(kbdp, m)
216 struct kbd *kbdp;
217 message *m;
219 int i, n, r, ops, watch;
220 unsigned char c;
222 /* Execute the requested device driver function. */
223 r= EINVAL; /* just in case */
224 switch (m->m_type) {
225 case DEV_OPEN:
226 kbdp->nr_open++;
227 r= OK;
228 break;
229 case DEV_CLOSE:
230 kbdp->nr_open--;
231 if (kbdp->nr_open < 0)
233 printf("TTY(kbd): open count is negative\n");
234 kbdp->nr_open= 0;
236 if (kbdp->nr_open == 0)
237 kbdp->avail= 0;
238 r= OK;
239 break;
240 case DEV_READ_S:
241 if (kbdp->req_size)
243 /* We handle only request at a time */
244 r= EIO;
245 break;
247 if (kbdp->avail == 0)
249 /* Should record proc */
250 kbdp->req_size= m->COUNT;
251 kbdp->req_proc= m->USER_ENDPT;
252 kbdp->req_grant= (cp_grant_id_t) m->IO_GRANT;
253 kbdp->req_addr_offset= 0;
254 kbdp->incaller= m->m_source;
255 r= SUSPEND;
256 break;
259 /* Handle read request */
260 n= kbdp->avail;
261 if (n > m->COUNT)
262 n= m->COUNT;
263 if (kbdp->offset + n > KBD_BUFSZ)
264 n= KBD_BUFSZ-kbdp->offset;
265 if (n <= 0)
266 panic("do_kbd(READ): bad n: %d", n);
267 r= sys_safecopyto(m->m_source, (cp_grant_id_t) m->IO_GRANT, 0,
268 (vir_bytes) &kbdp->buf[kbdp->offset], n);
269 if (r == OK)
271 kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
272 kbdp->avail -= n;
273 r= n;
274 } else {
275 printf("copy in read kbd failed: %d\n", r);
278 break;
280 case DEV_WRITE_S:
281 if (kbdp != &kbdaux)
283 printf("write to keyboard not implemented\n");
284 r= EINVAL;
285 break;
288 /* Assume that output to AUX only happens during
289 * initialization and we can afford to lose input. This should
290 * be fixed at a later time.
292 for (i= 0; i<m->COUNT; i++)
294 r= sys_safecopyfrom(m->m_source, (cp_grant_id_t)
295 m->IO_GRANT, i, (vir_bytes) &c, 1);
296 if (r != OK)
297 break;
298 kbc_cmd1(KBC_WRITE_AUX, c);
300 r= i;
301 break;
303 case CANCEL:
304 kbdp->req_size= 0;
305 r= OK;
306 break;
307 case DEV_SELECT:
308 ops = m->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
309 watch = (m->USER_ENDPT & SEL_NOTIFY) ? 1 : 0;
311 r= 0;
312 if (kbdp->avail && (ops & SEL_RD))
314 r |= SEL_RD;
315 break;
318 if (ops && watch)
320 kbdp->select_ops |= ops;
321 kbdp->select_proc= m->m_source;
323 break;
324 case DEV_IOCTL_S:
325 if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS)
327 kio_leds_t leds;
328 unsigned char b;
331 r= sys_safecopyfrom(m->m_source, (cp_grant_id_t)
332 m->IO_GRANT, 0, (vir_bytes) &leds,
333 sizeof(leds));
334 if (r != OK)
335 break;
336 b= 0;
337 if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK;
338 if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK;
339 if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK;
340 if (kbdout.avail == 0)
341 kbdout.offset= 0;
342 if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ)
344 /* Output buffer is full. Ignore this command.
345 * Reset ACK flag.
347 kbdout.expect_ack= 0;
349 else
351 kbdout.buf[kbdout.offset+kbdout.avail]=
352 LED_CODE;
353 kbdout.buf[kbdout.offset+kbdout.avail+1]= b;
354 kbdout.avail += 2;
356 if (!kbdout.expect_ack)
357 kbd_send();
358 r= OK;
359 break;
361 if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL)
363 kio_bell_t bell;
364 clock_t ticks;
366 r = sys_safecopyfrom(m->m_source, (cp_grant_id_t)
367 m->IO_GRANT, 0, (vir_bytes) &bell,
368 sizeof(bell));
369 if (r != OK)
370 break;
372 ticks= bell.kb_duration.tv_usec * system_hz / 1000000;
373 ticks += bell.kb_duration.tv_sec * system_hz;
374 if (!ticks)
375 ticks++;
376 beep_x(bell.kb_pitch, ticks);
378 r= OK;
379 break;
381 r= ENOTTY;
382 break;
384 default:
385 printf("Warning, TTY(kbd) got unexpected request %d from %d\n",
386 m->m_type, m->m_source);
387 r= EINVAL;
389 tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r);
393 /*===========================================================================*
394 * handle_status *
395 *===========================================================================*/
396 static int handle_status(kbdp, m)
397 struct kbd *kbdp;
398 message *m;
400 int n, r;
402 if (kbdp->avail && kbdp->req_size && m->m_source == kbdp->incaller &&
403 kbdp->req_grant != GRANT_INVALID)
405 /* Handle read request */
406 n= kbdp->avail;
407 if (n > kbdp->req_size)
408 n= kbdp->req_size;
409 if (kbdp->offset + n > KBD_BUFSZ)
410 n= KBD_BUFSZ-kbdp->offset;
411 if (n <= 0)
412 panic("kbd_status: bad n: %d", n);
413 kbdp->req_size= 0;
414 r= sys_safecopyto(kbdp->incaller, kbdp->req_grant, 0,
415 (vir_bytes)&kbdp->buf[kbdp->offset], n);
416 if (r == OK)
418 kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
419 kbdp->avail -= n;
420 r= n;
421 } else printf("copy in revive kbd failed: %d\n", r);
423 m->m_type = DEV_REVIVE;
424 m->REP_ENDPT= kbdp->req_proc;
425 m->REP_IO_GRANT= kbdp->req_grant;
426 m->REP_STATUS= r;
427 kbdp->req_grant = GRANT_INVALID;
428 return 1;
430 if (kbdp->avail && (kbdp->select_ops & SEL_RD) &&
431 m->m_source == kbdp->select_proc)
433 m->m_type = DEV_IO_READY;
434 m->DEV_MINOR = kbdp->minor;
435 m->DEV_SEL_OPS = SEL_RD;
437 kbdp->select_ops &= ~SEL_RD;
438 return 1;
441 return 0;
445 /*===========================================================================*
446 * map_key *
447 *===========================================================================*/
448 static unsigned map_key(scode)
449 int scode;
451 /* Map a scan code to an ASCII code. */
453 int caps, column, lk;
454 u16_t *keyrow;
456 if(esc)
457 keyrow = &keymap_escaped[scode * MAP_COLS];
458 else
459 keyrow = &keymap[scode * MAP_COLS];
461 caps = shift;
462 lk = locks[ccurrent];
463 if ((lk & NUM_LOCK) && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps;
464 if ((lk & CAPS_LOCK) && (keyrow[0] & HASCAPS)) caps = !caps;
466 if (alt) {
467 column = 2;
468 if (ctrl || alt_r) column = 3; /* Ctrl + Alt == AltGr */
469 if (caps) column = 4;
470 } else {
471 if (sticky_alt_mode && (lk & ALT_LOCK)) {
472 column = 2;
473 if (caps) column = 4;
474 } else {
475 column = 0;
476 if (caps) column = 1;
477 if (ctrl) column = 5;
480 return keyrow[column] & ~HASCAPS;
483 /*===========================================================================*
484 * kbd_interrupt *
485 *===========================================================================*/
486 void kbd_interrupt(message *UNUSED(m_ptr))
488 /* A keyboard interrupt has occurred. Process it. */
489 int o, isaux;
490 unsigned char scode;
491 struct kbd *kbdp;
493 /* Fetch the character from the keyboard hardware and acknowledge it. */
494 if (!scan_keyboard(&scode, &isaux))
495 return;
497 if (isaux)
498 kbdp= &kbdaux;
499 else if (kbd.nr_open)
500 kbdp= &kbd;
501 else
502 kbdp= NULL;
504 if (kbdp)
506 /* raw scan codes or aux data */
507 if (kbdp->avail >= KBD_BUFSZ)
509 #if 0
510 printf("kbd_interrupt: %s buffer is full\n",
511 isaux ? "kbdaux" : "keyboard");
512 #endif
513 return; /* Buffer is full */
515 o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ;
516 kbdp->buf[o]= scode;
517 kbdp->avail++;
518 if (kbdp->req_size) {
519 notify(kbdp->incaller);
521 if (kbdp->select_ops & SEL_RD)
522 notify(kbdp->select_proc);
523 return;
526 /* Store the scancode in memory so the task can get at it later. */
527 if (icount < KB_IN_BYTES) {
528 *ihead++ = scode;
529 if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf;
530 icount++;
531 tty_table[ccurrent].tty_events = 1;
532 if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
533 select_retry(&tty_table[ccurrent]);
539 void do_kb_inject(message *msg)
541 unsigned char scode;
542 /* only handle keyboard events */
543 if (msg->INPUT_TYPE == INPUT_EV_KEY) {
544 scode = msg->INPUT_CODE;
546 /* is it a KEY RELEASE? */
547 if (msg->INPUT_VALUE == 0) {
548 scode |= KEY_RELEASE;
551 if (injcount < KB_IN_BYTES) {
552 *injhead++ = scode;
553 if (injhead == injbuf + KB_IN_BYTES) injhead = injbuf;
554 injcount++;
555 tty_table[ccurrent].tty_events = 1;
556 if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
557 select_retry(&tty_table[ccurrent]);
563 /*===========================================================================*
564 * kb_read *
565 *===========================================================================*/
566 static int kb_read(tp, try)
567 tty_t *tp;
568 int try;
570 /* Process characters from the circular keyboard buffer. */
571 char buf[7], *p, suffix;
572 int scode;
573 unsigned ch;
575 /* always use the current console */
576 tp = &tty_table[ccurrent];
578 if (try) {
579 if (icount > 0) return 1;
580 return 0;
583 while (icount > 0 || injcount > 0) {
584 if (injcount > 0) {
585 /* take one key scan code */
586 scode = *injtail++;
587 if (injtail == injbuf + KB_IN_BYTES) injtail = injbuf;
588 injcount--;
589 } else {
590 /* take one key scan code */
591 scode = *itail++;
592 if (itail == ibuf + KB_IN_BYTES) itail = ibuf;
593 icount--;
596 /* Function keys are being used for debug dumps (if enabled). */
597 if (debug_fkeys && func_key(scode)) continue;
599 /* Perform make/break processing. */
601 ch = make_break(scode);
603 if (ch <= 0xFF) {
604 /* A normal character. */
605 buf[0] = ch;
606 (void) in_process(tp, buf, 1, scode);
607 } else
608 if (HOME <= ch && ch <= INSRT) {
609 /* An ASCII escape sequence generated by the numeric pad. */
610 buf[0] = ESC;
611 buf[1] = '[';
612 buf[2] = numpad_map[ch - HOME];
613 (void) in_process(tp, buf, 3, scode);
614 } else
615 if ((F1 <= ch && ch <= F12) || (SF1 <= ch && ch <= SF12) ||
616 (CF1 <= ch && ch <= CF12 && !debug_fkeys)) {
617 /* An escape sequence generated by function keys. */
618 if (F1 <= ch && ch <= F12) {
619 ch -= F1;
620 suffix = 0;
621 } else
622 if (SF1 <= ch && ch <= SF12) {
623 ch -= SF1;
624 suffix = '2';
625 } else
626 /* (CF1 <= ch && ch <= CF12) */ {
627 ch -= CF1;
628 suffix = shift ? '6' : '5';
630 /* ^[[11~ for F1, ^[[24;5~ for CF12 etc */
631 buf[0] = ESC;
632 buf[1] = '[';
633 buf[2] = fkey_map[ch][0];
634 buf[3] = fkey_map[ch][1];
635 p = &buf[4];
636 if (suffix) {
637 *p++ = ';';
638 *p++ = suffix;
640 *p++ = '~';
641 (void) in_process(tp, buf, p - buf, scode);
642 } else
643 if (ch == ALEFT) {
644 /* Choose lower numbered console as current console. */
645 select_console(ccurrent - 1);
646 set_leds();
647 } else
648 if (ch == ARIGHT) {
649 /* Choose higher numbered console as current console. */
650 select_console(ccurrent + 1);
651 set_leds();
652 } else
653 if (AF1 <= ch && ch <= AF12) {
654 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
655 select_console(ch - AF1);
656 set_leds();
657 } else
658 if (CF1 <= ch && ch <= CF12) {
659 switch(ch) {
660 case CF1: show_key_mappings(); break;
661 case CF3: toggle_scroll(); break; /* hardware <-> software */
662 case CF7: sigchar(&tty_table[CONSOLE], SIGQUIT, 1); break;
663 case CF8: sigchar(&tty_table[CONSOLE], SIGINT, 1); break;
664 case CF9: sigchar(&tty_table[CONSOLE], SIGKILL, 1); break;
666 } else {
667 /* pass on scancode even though there is no character code */
668 (void) in_process(tp, NULL, 0, scode);
672 return 1;
675 /*===========================================================================*
676 * kbd_send *
677 *===========================================================================*/
678 static void kbd_send()
680 u32_t sb;
681 int r;
683 if (!kbdout.avail)
684 return;
685 if (kbdout.expect_ack)
686 return;
688 if((r=sys_inb(KB_STATUS, &sb)) != OK) {
689 printf("kbd_send: 1 sys_inb() failed: %d\n", r);
691 if (sb & (KB_OUT_FULL|KB_IN_FULL))
693 printf("not sending 1: sb = 0x%x\n", sb);
694 return;
696 micro_delay(KBC_IN_DELAY);
697 if((r=sys_inb(KB_STATUS, &sb)) != OK) {
698 printf("kbd_send: 2 sys_inb() failed: %d\n", r);
700 if (sb & (KB_OUT_FULL|KB_IN_FULL))
702 printf("not sending 2: sb = 0x%x\n", sb);
703 return;
706 /* Okay, buffer is really empty */
707 #if 0
708 printf("sending byte 0x%x to keyboard\n", kbdout.buf[kbdout.offset]);
709 #endif
710 if((r=sys_outb(KEYBD, kbdout.buf[kbdout.offset])) != OK) {
711 printf("kbd_send: 3 sys_outb() failed: %d\n", r);
713 kbdout.offset++;
714 kbdout.avail--;
715 kbdout.expect_ack= 1;
717 kbd_alive= 1;
718 if (kbd_watchdog_set)
720 /* Set a watchdog timer for one second. */
721 set_timer(&tmr_kbd_wd, system_hz, kbd_watchdog, 0);
723 kbd_watchdog_set= 1;
727 /*===========================================================================*
728 * make_break *
729 *===========================================================================*/
730 static unsigned make_break(scode)
731 int scode; /* scan code of key just struck or released */
733 /* This routine can handle keyboards that interrupt only on key depression,
734 * as well as keyboards that interrupt on key depression and key release.
735 * For efficiency, the interrupt routine filters out most key releases.
737 int ch, make, escape;
738 static int CAD_count = 0;
739 static int rebooting = 0;
741 /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would
742 * be better done in keyboard() in case TTY is hung, except control and
743 * alt are set in the high level code.
745 if (ctrl && alt && (scode == DEL_SCAN || scode == INS_SCAN))
747 if (++CAD_count == 3) {
748 cons_stop();
749 sys_abort(RBT_DEFAULT);
751 sys_kill(INIT_PROC_NR, SIGABRT);
752 rebooting = 1;
755 if(rebooting)
756 return -1;
758 /* High-order bit set on key release. */
759 make = (scode & KEY_RELEASE) == 0; /* true if pressed */
761 ch = map_key(scode &= ASCII_MASK); /* map to ASCII */
763 escape = esc; /* Key is escaped? (true if added since the XT) */
764 esc = 0;
766 switch (ch) {
767 case CTRL: /* Left or right control key */
768 *(escape ? &ctrl_r : &ctrl_l) = make;
769 ctrl = ctrl_l | ctrl_r;
770 break;
771 case SHIFT: /* Left or right shift key */
772 *(scode == RSHIFT_SCAN ? &shift_r : &shift_l) = make;
773 shift = shift_l | shift_r;
774 break;
775 case ALT: /* Left or right alt key */
776 *(escape ? &alt_r : &alt_l) = make;
777 alt = alt_l | alt_r;
778 if (sticky_alt_mode && (alt_r && (alt_down < make))) {
779 locks[ccurrent] ^= ALT_LOCK;
781 alt_down = make;
782 break;
783 case CALOCK: /* Caps lock - toggle on 0 -> 1 transition */
784 if (caps_down < make) {
785 locks[ccurrent] ^= CAPS_LOCK;
786 set_leds();
788 caps_down = make;
789 break;
790 case NLOCK: /* Num lock */
791 if (num_down < make) {
792 locks[ccurrent] ^= NUM_LOCK;
793 set_leds();
795 num_down = make;
796 break;
797 case SLOCK: /* Scroll lock */
798 if (scroll_down < make) {
799 locks[ccurrent] ^= SCROLL_LOCK;
800 set_leds();
802 scroll_down = make;
803 break;
804 case EXTKEY: /* Escape keycode */
805 esc = 1; /* Next key is escaped */
806 return(-1);
807 default: /* A normal key */
808 if(!make)
809 return -1;
810 if(ch)
811 return ch;
813 static char seen[2][NR_SCAN_CODES];
814 int notseen = 0, ei;
815 ei = escape ? 1 : 0;
816 if(scode >= 0 && scode < NR_SCAN_CODES) {
817 notseen = !seen[ei][scode];
818 seen[ei][scode] = 1;
819 } else {
820 printf("tty: scode %d makes no sense\n", scode);
822 if(notseen) {
823 printf("tty: ignoring unrecognized %s "
824 "scancode 0x%x\n",
825 escape ? "escaped" : "straight", scode);
828 return -1;
831 /* Key release, or a shift type key. */
832 return(-1);
835 /*===========================================================================*
836 * set_leds *
837 *===========================================================================*/
838 static void set_leds()
840 /* Set the LEDs on the caps, num, and scroll lock keys */
841 int s;
843 kb_wait(); /* wait for buffer empty */
844 if ((s=sys_outb(KEYBD, LED_CODE)) != OK)
845 printf("Warning, sys_outb couldn't prepare for LED values: %d\n", s);
846 /* prepare keyboard to accept LED values */
847 kb_ack(); /* wait for ack response */
849 kb_wait(); /* wait for buffer empty */
850 if ((s=sys_outb(KEYBD, locks[ccurrent])) != OK)
851 printf("Warning, sys_outb couldn't give LED values: %d\n", s);
852 /* give keyboard LED values */
853 kb_ack(); /* wait for ack response */
856 /*===========================================================================*
857 * kbc_cmd0 *
858 *===========================================================================*/
859 static void kbc_cmd0(cmd)
860 int cmd;
862 kb_wait();
863 if(sys_outb(KB_COMMAND, cmd) != OK)
864 printf("kbc_cmd0: sys_outb failed\n");
867 /*===========================================================================*
868 * kbc_cmd1 *
869 *===========================================================================*/
870 static void kbc_cmd1(cmd, data)
871 int cmd;
872 int data;
874 kb_wait();
875 if(sys_outb(KB_COMMAND, cmd) != OK)
876 printf("kbc_cmd1: 1 sys_outb failed\n");
877 kb_wait();
878 if(sys_outb(KEYBD, data) != OK)
879 printf("kbc_cmd1: 2 sys_outb failed\n");
883 /*===========================================================================*
884 * kbc_read *
885 *===========================================================================*/
886 static int kbc_read()
888 int i;
889 u32_t byte, st;
890 #if 0
891 struct micro_state ms;
892 #endif
894 #if DEBUG
895 printf("in kbc_read\n");
896 #endif
898 /* Wait at most 1 second for a byte from the keyboard or
899 * the kbd controller, return -1 on a timeout.
901 for (i= 0; i<1000000; i++)
902 #if 0
903 micro_start(&ms);
905 #endif
907 if(sys_inb(KB_STATUS, &st) != OK)
908 printf("kbc_read: 1 sys_inb failed\n");
909 if (st & KB_OUT_FULL)
911 micro_delay(KBC_IN_DELAY);
912 if(sys_inb(KEYBD, &byte) != OK)
913 printf("kbc_read: 2 sys_inb failed\n");
914 if (st & KB_AUX_BYTE)
915 printf("kbc_read: aux byte 0x%x\n", byte);
916 #if DEBUG
917 printf("keyboard`kbc_read: returning byte 0x%x\n",
918 byte);
919 #endif
920 return byte;
923 #if 0
924 while (micro_elapsed(&ms) < 1000000);
925 #endif
926 panic("kbc_read failed to complete");
927 return EINVAL;
931 /*===========================================================================*
932 * kb_wait *
933 *===========================================================================*/
934 static int kb_wait()
936 /* Wait until the controller is ready; return zero if this times out. */
938 int retries;
939 u32_t status;
940 int s, isaux;
941 unsigned char byte;
943 retries = MAX_KB_BUSY_RETRIES + 1; /* wait until not busy */
944 do {
945 s = sys_inb(KB_STATUS, &status);
946 if(s != OK)
947 printf("kb_wait: sys_inb failed: %d\n", s);
948 if (status & KB_OUT_FULL) {
949 if (scan_keyboard(&byte, &isaux))
951 #if 0
952 printf("ignoring %sbyte in kb_wait\n", isaux ? "AUX " : "");
953 #endif
956 if (! (status & (KB_IN_FULL|KB_OUT_FULL)) )
957 break; /* wait until ready */
958 } while (--retries != 0); /* continue unless timeout */
959 return(retries); /* zero on timeout, positive if ready */
962 /*===========================================================================*
963 * kb_ack *
964 *===========================================================================*/
965 static int kb_ack()
967 /* Wait until kbd acknowledges last command; return zero if this times out. */
969 int retries, s;
970 u32_t 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 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 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 int kbd_loadmap(m)
1059 message *m;
1061 /* Load a new keymap. */
1062 return sys_safecopyfrom(m->m_source, (cp_grant_id_t) m->IO_GRANT,
1063 0, (vir_bytes) keymap, (vir_bytes) sizeof(keymap));
1066 /*===========================================================================*
1067 * do_fkey_ctl *
1068 *===========================================================================*/
1069 void do_fkey_ctl(m_ptr)
1070 message *m_ptr; /* pointer to the request message */
1072 /* This procedure allows processes to register a function key to receive
1073 * notifications if it is pressed. At most one binding per key can exist.
1075 int s, i;
1076 int result = EINVAL;
1078 switch (m_ptr->FKEY_REQUEST) { /* see what we must do */
1079 case FKEY_MAP: /* request for new mapping */
1080 result = OK; /* assume everything will be ok*/
1081 for (i=0; i < 12; i++) { /* check F1-F12 keys */
1082 if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
1083 #if DEAD_CODE
1084 /* Currently, we don't check if the slot is in use, so that IS
1085 * can recover after a crash by overtaking its existing mappings.
1086 * In future, a better solution will be implemented.
1088 if (fkey_obs[i].proc_nr == NONE) {
1089 #endif
1090 fkey_obs[i].proc_nr = m_ptr->m_source;
1091 fkey_obs[i].events = 0;
1092 bit_unset(m_ptr->FKEY_FKEYS, i+1);
1093 #if DEAD_CODE
1094 } else {
1095 printf("WARNING, fkey_map failed F%d\n", i+1);
1096 result = EBUSY; /* report failure, but try rest */
1098 #endif
1101 for (i=0; i < 12; i++) { /* check Shift+F1-F12 keys */
1102 if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
1103 #if DEAD_CODE
1104 if (sfkey_obs[i].proc_nr == NONE) {
1105 #endif
1106 sfkey_obs[i].proc_nr = m_ptr->m_source;
1107 sfkey_obs[i].events = 0;
1108 bit_unset(m_ptr->FKEY_SFKEYS, i+1);
1109 #if DEAD_CODE
1110 } else {
1111 printf("WARNING, fkey_map failed Shift F%d\n", i+1);
1112 result = EBUSY; /* report failure but try rest */
1114 #endif
1117 break;
1118 case FKEY_UNMAP:
1119 result = OK; /* assume everything will be ok*/
1120 for (i=0; i < 12; i++) { /* check F1-F12 keys */
1121 if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
1122 if (fkey_obs[i].proc_nr == m_ptr->m_source) {
1123 fkey_obs[i].proc_nr = NONE;
1124 fkey_obs[i].events = 0;
1125 bit_unset(m_ptr->FKEY_FKEYS, i+1);
1126 } else {
1127 result = EPERM; /* report failure, but try rest */
1131 for (i=0; i < 12; i++) { /* check Shift+F1-F12 keys */
1132 if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
1133 if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
1134 sfkey_obs[i].proc_nr = NONE;
1135 sfkey_obs[i].events = 0;
1136 bit_unset(m_ptr->FKEY_SFKEYS, i+1);
1137 } else {
1138 result = EPERM; /* report failure, but try rest */
1142 break;
1143 case FKEY_EVENTS:
1144 m_ptr->FKEY_FKEYS = m_ptr->FKEY_SFKEYS = 0;
1145 for (i=0; i < 12; i++) { /* check (Shift+) F1-F12 keys */
1146 if (fkey_obs[i].proc_nr == m_ptr->m_source) {
1147 if (fkey_obs[i].events) {
1148 bit_set(m_ptr->FKEY_FKEYS, i+1);
1149 fkey_obs[i].events = 0;
1152 if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
1153 if (sfkey_obs[i].events) {
1154 bit_set(m_ptr->FKEY_SFKEYS, i+1);
1155 sfkey_obs[i].events = 0;
1159 break;
1162 /* Almost done, return result to caller. */
1163 m_ptr->m_type = result;
1164 if ((s = sendnb(m_ptr->m_source, m_ptr)) != OK)
1165 printf("TTY: unable to reply to %d: %d", m_ptr->m_source, s);
1168 /*===========================================================================*
1169 * func_key *
1170 *===========================================================================*/
1171 static int func_key(scode)
1172 int scode; /* scan code for a function key */
1174 /* This procedure traps function keys for debugging purposes. Observers of
1175 * function keys are kept in a global array. If a subject (a key) is pressed
1176 * the observer is notified of the event. Initialization of the arrays is done
1177 * in kb_init, where NONE is set to indicate there is no interest in the key.
1178 * Returns FALSE on a key release or if the key is not observable.
1180 int key;
1181 int proc_nr;
1183 /* Ignore key releases. If this is a key press, get full key code. */
1184 if (scode & KEY_RELEASE) return(FALSE); /* key release */
1185 key = map_key(scode); /* include modifiers */
1187 /* Key pressed, now see if there is an observer for the pressed key.
1188 * F1-F12 observers are in fkey_obs array.
1189 * SHIFT F1-F12 observers are in sfkey_req array.
1190 * CTRL F1-F12 reserved (see kb_read)
1191 * ALT F1-F12 reserved (see kb_read)
1192 * Other combinations are not in use. Note that Alt+Shift+F1-F12 is yet
1193 * defined in <minix/keymap.h>, and thus is easy for future extensions.
1195 if (F1 <= key && key <= F12) { /* F1-F12 */
1196 proc_nr = fkey_obs[key - F1].proc_nr;
1197 fkey_obs[key - F1].events ++ ;
1198 } else if (SF1 <= key && key <= SF12) { /* Shift F2-F12 */
1199 proc_nr = sfkey_obs[key - SF1].proc_nr;
1200 sfkey_obs[key - SF1].events ++;
1202 else {
1203 return(FALSE); /* not observable */
1206 /* See if an observer is registered and send it a message. */
1207 if (proc_nr != NONE) {
1208 notify(proc_nr);
1210 return(TRUE);
1213 /*===========================================================================*
1214 * show_key_mappings *
1215 *===========================================================================*/
1216 static void show_key_mappings()
1218 int i,s;
1219 struct proc proc;
1221 printf("\n");
1222 printf("System information. Known function key mappings to request debug dumps:\n");
1223 printf("-------------------------------------------------------------------------\n");
1224 for (i=0; i<12; i++) {
1226 printf(" %sF%d: ", i+1<10? " ":"", i+1);
1227 if (fkey_obs[i].proc_nr != NONE) {
1228 if ((s = sys_getproc(&proc, fkey_obs[i].proc_nr))!=OK)
1229 printf("%-14.14s", "<unknown>");
1230 else
1231 printf("%-14.14s", proc.p_name);
1232 } else {
1233 printf("%-14.14s", "<none>");
1236 printf(" %sShift-F%d: ", i+1<10? " ":"", i+1);
1237 if (sfkey_obs[i].proc_nr != NONE) {
1238 if ((s = sys_getproc(&proc, sfkey_obs[i].proc_nr))!=OK)
1239 printf("%-14.14s", "<unknown>");
1240 else
1241 printf("%-14.14s", proc.p_name);
1242 } else {
1243 printf("%-14.14s", "<none>");
1245 printf("\n");
1247 printf("\n");
1248 printf("Press one of the registered function keys to trigger a debug dump.\n");
1249 printf("\n");
1252 /*===========================================================================*
1253 * scan_keyboard *
1254 *===========================================================================*/
1255 static int scan_keyboard(bp, isauxp)
1256 unsigned char *bp;
1257 int *isauxp;
1259 u32_t b, sb;
1261 if(sys_inb(KB_STATUS, &sb) != OK)
1262 printf("scan_keyboard: sys_inb failed\n");
1264 if (!(sb & KB_OUT_FULL))
1266 if (kbdout.avail && !kbdout.expect_ack)
1267 kbd_send();
1268 return 0;
1270 if(sys_inb(KEYBD, &b) != OK)
1271 printf("scan_keyboard: 2 sys_inb failed\n");
1272 #if 0
1273 printf("got byte 0x%x from %s\n", b, (sb & KB_AUX_BYTE) ? "AUX" : "keyboard");
1274 #endif
1275 if (!(sb & KB_AUX_BYTE) && b == KB_ACK && kbdout.expect_ack)
1277 #if 0
1278 printf("got ACK from keyboard\n");
1279 #endif
1280 kbdout.expect_ack= 0;
1281 micro_delay(KBC_IN_DELAY);
1282 kbd_send();
1283 return 0;
1285 if (bp)
1286 *bp= b;
1287 if (isauxp)
1288 *isauxp= !!(sb & KB_AUX_BYTE);
1289 if (kbdout.avail && !kbdout.expect_ack)
1291 micro_delay(KBC_IN_DELAY);
1292 kbd_send();
1294 return 1;
1297 /*===========================================================================*
1298 * kbd_watchdog *
1299 *===========================================================================*/
1300 static void kbd_watchdog(timer_t *UNUSED(tmrp))
1303 kbd_watchdog_set= 0;
1304 if (!kbdout.avail)
1305 return; /* Watchdog is no longer needed */
1306 if (!kbd_alive)
1308 printf("kbd_watchdog: should reset keyboard\n");
1310 kbd_alive= 0;
1312 set_timer(&tmr_kbd_wd, system_hz, kbd_watchdog, 0);
1314 kbd_watchdog_set= 1;