add/re-enable at_wini debug output
[minix3.git] / drivers / tty / keyboard.c
blob6ab1ad0a21093eb62a1822b15675d85bdb24a4a9
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 "../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 <archtypes.h>
18 #include <minix/callnr.h>
19 #include <minix/com.h>
20 #include <minix/keymap.h>
21 #include "tty.h"
22 #include "keymaps/us-std.src"
23 #include "../../kernel/const.h"
24 #include "../../kernel/config.h"
25 #include "../../kernel/type.h"
26 #include "../../kernel/proc.h"
28 int irq_hook_id = -1;
29 int aux_irq_hook_id = -1;
31 /* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
32 #define KEYBD 0x60 /* I/O port for keyboard data */
34 /* AT keyboard. */
35 #define KB_COMMAND 0x64 /* I/O port for commands on AT */
36 #define KB_STATUS 0x64 /* I/O port for status on AT */
37 #define KB_ACK 0xFA /* keyboard ack response */
38 #define KB_AUX_BYTE 0x20 /* Auxiliary Device Output Buffer Full */
39 #define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */
40 #define KB_IN_FULL 0x02 /* status bit set when not ready to receive */
41 #define KBC_RD_RAM_CCB 0x20 /* Read controller command byte */
42 #define KBC_WR_RAM_CCB 0x60 /* Write controller command byte */
43 #define KBC_DI_AUX 0xA7 /* Disable Auxiliary Device */
44 #define KBC_EN_AUX 0xA8 /* Enable Auxiliary Device */
45 #define KBC_DI_KBD 0xAD /* Disable Keybard Interface */
46 #define KBC_EN_KBD 0xAE /* Enable Keybard Interface */
47 #define KBC_WRITE_AUX 0xD4 /* Write to Auxiliary Device */
48 #define LED_CODE 0xED /* command to keyboard to set LEDs */
49 #define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */
50 #define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */
51 #define KBIT 0x80 /* bit used to ack characters to keyboard */
53 #define KBC_IN_DELAY 7 /* wait 7 microseconds when polling */
55 /* Miscellaneous. */
56 #define ESC_SCAN 0x01 /* reboot key when panicking */
57 #define SLASH_SCAN 0x35 /* to recognize numeric slash */
58 #define RSHIFT_SCAN 0x36 /* to distinguish left and right shift */
59 #define HOME_SCAN 0x47 /* first key on the numeric keypad */
60 #define INS_SCAN 0x52 /* INS for use in CTRL-ALT-INS reboot */
61 #define DEL_SCAN 0x53 /* DEL for use in CTRL-ALT-DEL reboot */
63 #define KBD_BUFSZ 1024 /* Buffer size for raw scan codes */
64 #define KBD_OUT_BUFSZ 16 /* Output buffer to sending data to the
65 * keyboard.
68 #define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1)
70 #define CONSOLE 0 /* line number for console */
71 #define KB_IN_BYTES 32 /* size of keyboard input buffer */
72 PRIVATE char ibuf[KB_IN_BYTES]; /* input buffer */
73 PRIVATE char *ihead = ibuf; /* next free spot in input buffer */
74 PRIVATE char *itail = ibuf; /* scan code to return to TTY */
75 PRIVATE int icount; /* # codes in buffer */
77 PRIVATE int esc; /* escape scan code detected? */
78 PRIVATE int alt_l; /* left alt key state */
79 PRIVATE int alt_r; /* right alt key state */
80 PRIVATE int alt; /* either alt key */
81 PRIVATE int ctrl_l; /* left control key state */
82 PRIVATE int ctrl_r; /* right control key state */
83 PRIVATE int ctrl; /* either control key */
84 PRIVATE int shift_l; /* left shift key state */
85 PRIVATE int shift_r; /* right shift key state */
86 PRIVATE int shift; /* either shift key */
87 PRIVATE int num_down; /* num lock key depressed */
88 PRIVATE int caps_down; /* caps lock key depressed */
89 PRIVATE int scroll_down; /* scroll lock key depressed */
90 PRIVATE int locks[NR_CONS]; /* per console lock keys state */
92 /* Lock key active bits. Chosen to be equal to the keyboard LED bits. */
93 #define SCROLL_LOCK 0x01
94 #define NUM_LOCK 0x02
95 #define CAPS_LOCK 0x04
97 PRIVATE char numpad_map[] =
98 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
100 /* Variables and definition for observed function keys. */
101 typedef struct observer { int proc_nr; int events; } obs_t;
102 PRIVATE obs_t fkey_obs[12]; /* observers for F1-F12 */
103 PRIVATE obs_t sfkey_obs[12]; /* observers for SHIFT F1-F12 */
105 PRIVATE struct kbd
107 int minor;
108 int nr_open;
109 char buf[KBD_BUFSZ];
110 int offset;
111 int avail;
112 int req_size;
113 int req_proc;
114 int req_safe; /* nonzero: safe (req_addr_g is grant) */
115 vir_bytes req_addr_g; /* Virtual address or grant */
116 vir_bytes req_addr_offset;
117 int incaller;
118 int select_ops;
119 int select_proc;
120 } kbd, kbdaux;
122 /* Data that is to be sent to the keyboard. Each byte is ACKed by the
123 * keyboard.
125 PRIVATE struct kbd_outack
127 unsigned char buf[KBD_OUT_BUFSZ];
128 int offset;
129 int avail;
130 int expect_ack;
131 } kbdout;
133 PRIVATE int kbd_watchdog_set= 0;
134 PRIVATE int kbd_alive= 1;
135 PRIVATE timer_t tmr_kbd_wd;
137 FORWARD _PROTOTYPE( void handle_req, (struct kbd *kbdp, message *m) );
138 FORWARD _PROTOTYPE( int handle_status, (struct kbd *kbdp, message *m) );
139 FORWARD _PROTOTYPE( void kbc_cmd0, (int cmd) );
140 FORWARD _PROTOTYPE( void kbc_cmd1, (int cmd, int data) );
141 FORWARD _PROTOTYPE( int kbc_read, (void) );
142 FORWARD _PROTOTYPE( void kbd_send, (void) );
143 FORWARD _PROTOTYPE( int kb_ack, (void) );
144 FORWARD _PROTOTYPE( int kb_wait, (void) );
145 FORWARD _PROTOTYPE( int func_key, (int scode) );
146 FORWARD _PROTOTYPE( int scan_keyboard, (unsigned char *bp, int *isauxp) );
147 FORWARD _PROTOTYPE( unsigned make_break, (int scode) );
148 FORWARD _PROTOTYPE( void set_leds, (void) );
149 FORWARD _PROTOTYPE( void show_key_mappings, (void) );
150 FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try) );
151 FORWARD _PROTOTYPE( unsigned map_key, (int scode) );
152 FORWARD _PROTOTYPE( void micro_delay, (unsigned long usecs) );
153 FORWARD _PROTOTYPE( void kbd_watchdog, (timer_t *tmrp) );
155 /*===========================================================================*
156 * do_kbd *
157 *===========================================================================*/
158 PUBLIC void do_kbd(message *m)
160 handle_req(&kbd, m);
164 /*===========================================================================*
165 * kbd_status *
166 *===========================================================================*/
167 PUBLIC int kbd_status(message *m)
169 int r;
171 r= handle_status(&kbd, m);
172 if (r)
173 return r;
174 return handle_status(&kbdaux, m);
178 /*===========================================================================*
179 * do_kbdaux *
180 *===========================================================================*/
181 PUBLIC void do_kbdaux(message *m)
183 handle_req(&kbdaux, m);
187 /*===========================================================================*
188 * handle_req *
189 *===========================================================================*/
190 PRIVATE void handle_req(kbdp, m)
191 struct kbd *kbdp;
192 message *m;
194 int i, n, r, ops, watch, safecopy = 0;
195 unsigned char c;
197 /* Execute the requested device driver function. */
198 r= EINVAL; /* just in case */
199 switch (m->m_type) {
200 case DEV_OPEN:
201 kbdp->nr_open++;
202 r= OK;
203 break;
204 case DEV_CLOSE:
205 kbdp->nr_open--;
206 if (kbdp->nr_open < 0)
208 printf("TTY(kbd): open count is negative\n");
209 kbdp->nr_open= 0;
211 if (kbdp->nr_open == 0)
212 kbdp->avail= 0;
213 r= OK;
214 break;
215 case DEV_READ_S:
216 safecopy = 1;
217 if (kbdp->req_size)
219 /* We handle only request at a time */
220 r= EIO;
221 break;
223 if (kbdp->avail == 0)
225 /* Should record proc */
226 kbdp->req_size= m->COUNT;
227 kbdp->req_proc= m->IO_ENDPT;
228 kbdp->req_addr_g= (vir_bytes)m->ADDRESS;
229 kbdp->req_addr_offset= 0;
230 kbdp->req_safe= safecopy;
231 kbdp->incaller= m->m_source;
232 r= SUSPEND;
233 break;
236 /* Handle read request */
237 n= kbdp->avail;
238 if (n > m->COUNT)
239 n= m->COUNT;
240 if (kbdp->offset + n > KBD_BUFSZ)
241 n= KBD_BUFSZ-kbdp->offset;
242 if (n <= 0)
243 panic("TTY", "do_kbd(READ): bad n", n);
244 if(safecopy) {
245 r= sys_safecopyto(m->IO_ENDPT, (vir_bytes) m->ADDRESS, 0,
246 (vir_bytes) &kbdp->buf[kbdp->offset], n, D);
247 } else {
248 r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
249 m->IO_ENDPT, D, (vir_bytes) m->ADDRESS, n);
251 if (r == OK)
253 kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
254 kbdp->avail -= n;
255 r= n;
256 } else {
257 printf("copy in read kbd failed: %d\n", r);
260 break;
262 case DEV_WRITE_S:
263 safecopy = 1;
264 if (kbdp != &kbdaux)
266 printf("write to keyboard not implemented\n");
267 r= EINVAL;
268 break;
271 /* Assume that output to AUX only happens during
272 * initialization and we can afford to lose input. This should
273 * be fixed at a later time.
275 for (i= 0; i<m->COUNT; i++)
277 if(safecopy) {
278 r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
279 m->ADDRESS, i, (vir_bytes)&c, 1, D);
280 } else {
281 r= sys_vircopy(m->IO_ENDPT, D,
282 (vir_bytes) m->ADDRESS+i,
283 SELF, D, (vir_bytes)&c, 1);
285 if (r != OK)
286 break;
287 kbc_cmd1(KBC_WRITE_AUX, c);
289 r= i;
290 break;
292 case CANCEL:
293 kbdp->req_size= 0;
294 r= OK;
295 break;
296 case DEV_SELECT:
297 ops = m->IO_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
298 watch = (m->IO_ENDPT & SEL_NOTIFY) ? 1 : 0;
300 r= 0;
301 if (kbdp->avail && (ops & SEL_RD))
303 r |= SEL_RD;
304 break;
307 if (ops && watch)
309 kbdp->select_ops |= ops;
310 kbdp->select_proc= m->m_source;
312 break;
313 case DEV_IOCTL_S:
314 safecopy=1;
315 if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS)
317 kio_leds_t leds;
318 unsigned char b;
321 if(safecopy) {
322 r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
323 m->ADDRESS, 0, (vir_bytes)&leds,
324 sizeof(leds), D);
325 } else {
326 r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
327 SELF, D, (vir_bytes)&leds, sizeof(leds));
329 if (r != OK)
330 break;
331 b= 0;
332 if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK;
333 if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK;
334 if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK;
335 if (kbdout.avail == 0)
336 kbdout.offset= 0;
337 if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ)
339 /* Output buffer is full. Ignore this command.
340 * Reset ACK flag.
342 kbdout.expect_ack= 0;
344 else
346 kbdout.buf[kbdout.offset+kbdout.avail]=
347 LED_CODE;
348 kbdout.buf[kbdout.offset+kbdout.avail+1]= b;
349 kbdout.avail += 2;
351 if (!kbdout.expect_ack)
352 kbd_send();
353 r= OK;
354 break;
356 if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL)
358 kio_bell_t bell;
359 clock_t ticks;
361 if(safecopy) {
362 r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes)
363 m->ADDRESS, 0, (vir_bytes)&bell,
364 sizeof(bell), D);
365 } else {
366 r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
367 SELF, D, (vir_bytes)&bell, sizeof(bell));
369 if (r != OK)
370 break;
372 ticks= bell.kb_duration.tv_usec * HZ / 1000000;
373 ticks += bell.kb_duration.tv_sec * 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->IO_ENDPT, r);
393 /*===========================================================================*
394 * handle_status *
395 *===========================================================================*/
396 PRIVATE 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)
404 /* Handle read request */
405 n= kbdp->avail;
406 if (n > kbdp->req_size)
407 n= kbdp->req_size;
408 if (kbdp->offset + n > KBD_BUFSZ)
409 n= KBD_BUFSZ-kbdp->offset;
410 if (n <= 0)
411 panic("TTY", "kbd_status: bad n", n);
412 kbdp->req_size= 0;
413 if(kbdp->req_safe) {
414 r= sys_safecopyto(kbdp->req_proc, kbdp->req_addr_g, 0,
415 (vir_bytes)&kbdp->buf[kbdp->offset], n, D);
416 } else {
417 r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
418 kbdp->req_proc, D, kbdp->req_addr_g, n);
420 if (r == OK)
422 kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
423 kbdp->avail -= n;
424 r= n;
425 } else printf("copy in revive kbd failed: %d\n", r);
427 m->m_type = DEV_REVIVE;
428 m->REP_ENDPT= kbdp->req_proc;
429 m->REP_IO_GRANT= kbdp->req_addr_g;
430 m->REP_STATUS= r;
431 return 1;
433 if (kbdp->avail && (kbdp->select_ops & SEL_RD) &&
434 m->m_source == kbdp->select_proc)
436 m->m_type = DEV_IO_READY;
437 m->DEV_MINOR = kbdp->minor;
438 m->DEV_SEL_OPS = SEL_RD;
440 kbdp->select_ops &= ~SEL_RD;
441 return 1;
444 return 0;
448 /*===========================================================================*
449 * map_key0 *
450 *===========================================================================*/
451 /* Map a scan code to an ASCII code ignoring modifiers. */
452 #define map_key0(scode) \
453 ((unsigned) keymap[(scode) * MAP_COLS])
455 /*===========================================================================*
456 * map_key *
457 *===========================================================================*/
458 PRIVATE unsigned map_key(scode)
459 int scode;
461 /* Map a scan code to an ASCII code. */
463 int caps, column, lk;
464 u16_t *keyrow;
466 if (scode == SLASH_SCAN && esc) return '/'; /* don't map numeric slash */
468 keyrow = &keymap[scode * MAP_COLS];
470 caps = shift;
471 lk = locks[ccurrent];
472 if ((lk & NUM_LOCK) && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps;
473 if ((lk & CAPS_LOCK) && (keyrow[0] & HASCAPS)) caps = !caps;
475 if (alt) {
476 column = 2;
477 if (ctrl || alt_r) column = 3; /* Ctrl + Alt == AltGr */
478 if (caps) column = 4;
479 } else {
480 column = 0;
481 if (caps) column = 1;
482 if (ctrl) column = 5;
484 return keyrow[column] & ~HASCAPS;
487 /*===========================================================================*
488 * kbd_interrupt *
489 *===========================================================================*/
490 PUBLIC void kbd_interrupt(m_ptr)
491 message *m_ptr;
493 /* A keyboard interrupt has occurred. Process it. */
494 int o, isaux;
495 unsigned char scode;
496 struct kbd *kbdp;
497 static timer_t timer; /* timer must be static! */
499 /* Fetch the character from the keyboard hardware and acknowledge it. */
500 if (!scan_keyboard(&scode, &isaux))
501 return;
503 if (isaux)
504 kbdp= &kbdaux;
505 else if (kbd.nr_open && !panicing)
506 kbdp= &kbd;
507 else
508 kbdp= NULL;
510 if (kbdp)
512 /* raw scan codes or aux data */
513 if (kbdp->avail >= KBD_BUFSZ)
515 #if 0
516 printf("kbd_interrupt: %s buffer is full\n",
517 isaux ? "kbdaux" : "keyboard");
518 #endif
519 return; /* Buffer is full */
521 o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ;
522 kbdp->buf[o]= scode;
523 kbdp->avail++;
524 if (kbdp->req_size) {
525 notify(kbdp->incaller);
527 if (kbdp->select_ops & SEL_RD)
528 notify(kbdp->select_proc);
529 return;
532 /* Store the scancode in memory so the task can get at it later. */
533 if (icount < KB_IN_BYTES) {
534 *ihead++ = scode;
535 if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf;
536 icount++;
537 tty_table[ccurrent].tty_events = 1;
538 if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
539 select_retry(&tty_table[ccurrent]);
544 /*===========================================================================*
545 * kb_read *
546 *===========================================================================*/
547 PRIVATE int kb_read(tp, try)
548 tty_t *tp;
549 int try;
551 /* Process characters from the circular keyboard buffer. */
552 char buf[3];
553 int scode;
554 unsigned ch;
556 tp = &tty_table[ccurrent]; /* always use the current console */
558 if (try) {
559 if (icount > 0) return 1;
560 return 0;
563 while (icount > 0) {
564 scode = *itail++; /* take one key scan code */
565 if (itail == ibuf + KB_IN_BYTES) itail = ibuf;
566 icount--;
568 /* Function keys are being used for debug dumps. */
569 if (func_key(scode)) continue;
571 /* Perform make/break processing. */
572 ch = make_break(scode);
574 if (ch <= 0xFF) {
575 /* A normal character. */
576 buf[0] = ch;
577 (void) in_process(tp, buf, 1);
578 } else
579 if (HOME <= ch && ch <= INSRT) {
580 /* An ASCII escape sequence generated by the numeric pad. */
581 buf[0] = ESC;
582 buf[1] = '[';
583 buf[2] = numpad_map[ch - HOME];
584 (void) in_process(tp, buf, 3);
585 } else
586 if (ch == ALEFT) {
587 /* Choose lower numbered console as current console. */
588 select_console(ccurrent - 1);
589 set_leds();
590 } else
591 if (ch == ARIGHT) {
592 /* Choose higher numbered console as current console. */
593 select_console(ccurrent + 1);
594 set_leds();
595 } else
596 if (AF1 <= ch && ch <= AF12) {
597 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
598 select_console(ch - AF1);
599 set_leds();
600 } else
601 if (CF1 <= ch && ch <= CF12) {
602 switch(ch) {
603 case CF1: show_key_mappings(); break;
604 case CF3: toggle_scroll(); break; /* hardware <-> software */
605 case CF7: sigchar(&tty_table[CONSOLE], SIGQUIT); break;
606 case CF8: sigchar(&tty_table[CONSOLE], SIGINT); break;
607 case CF9: sigchar(&tty_table[CONSOLE], SIGKILL); break;
612 return 1;
615 /*===========================================================================*
616 * kbd_send *
617 *===========================================================================*/
618 PRIVATE void kbd_send()
620 unsigned long sb;
621 int r;
622 clock_t now;
624 if (!kbdout.avail)
625 return;
626 if (kbdout.expect_ack)
627 return;
629 if((r=sys_inb(KB_STATUS, &sb)) != OK) {
630 printf("kbd_send: 1 sys_inb() failed: %d\n", r);
632 if (sb & (KB_OUT_FULL|KB_IN_FULL))
634 printf("not sending 1: sb = 0x%x\n", sb);
635 return;
637 micro_delay(KBC_IN_DELAY);
638 if((r=sys_inb(KB_STATUS, &sb)) != OK) {
639 printf("kbd_send: 2 sys_inb() failed: %d\n", r);
641 if (sb & (KB_OUT_FULL|KB_IN_FULL))
643 printf("not sending 2: sb = 0x%x\n", sb);
644 return;
647 /* Okay, buffer is really empty */
648 #if 0
649 printf("sending byte 0x%x to keyboard\n", kbdout.buf[kbdout.offset]);
650 #endif
651 if((r=sys_outb(KEYBD, kbdout.buf[kbdout.offset])) != OK) {
652 printf("kbd_send: 3 sys_inb() failed: %d\n", r);
654 kbdout.offset++;
655 kbdout.avail--;
656 kbdout.expect_ack= 1;
658 kbd_alive= 1;
659 if (kbd_watchdog_set)
661 /* Add a timer to the timers list. Possibly reschedule the
662 * alarm.
664 if ((r= getuptime(&now)) != OK)
665 panic("TTY","Keyboard couldn't get clock's uptime.", r);
666 tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+HZ, kbd_watchdog,
667 NULL);
668 if (tty_timers->tmr_exp_time != tty_next_timeout) {
669 tty_next_timeout = tty_timers->tmr_exp_time;
670 if ((r= sys_setalarm(tty_next_timeout, 1)) != OK)
671 panic("TTY","Keyboard couldn't set alarm.", r);
673 kbd_watchdog_set= 1;
677 /*===========================================================================*
678 * make_break *
679 *===========================================================================*/
680 PRIVATE unsigned make_break(scode)
681 int scode; /* scan code of key just struck or released */
683 /* This routine can handle keyboards that interrupt only on key depression,
684 * as well as keyboards that interrupt on key depression and key release.
685 * For efficiency, the interrupt routine filters out most key releases.
687 int ch, make, escape;
688 static int CAD_count = 0;
690 /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would
691 * be better done in keyboard() in case TTY is hung, except control and
692 * alt are set in the high level code.
694 if (ctrl && alt && (scode == DEL_SCAN || scode == INS_SCAN))
696 if (++CAD_count == 3) {
697 cons_stop();
698 sys_abort(RBT_HALT);
700 sys_kill(INIT_PROC_NR, SIGABRT);
701 return -1;
704 /* High-order bit set on key release. */
705 make = (scode & KEY_RELEASE) == 0; /* true if pressed */
707 ch = map_key(scode &= ASCII_MASK); /* map to ASCII */
709 escape = esc; /* Key is escaped? (true if added since the XT) */
710 esc = 0;
712 switch (ch) {
713 case CTRL: /* Left or right control key */
714 *(escape ? &ctrl_r : &ctrl_l) = make;
715 ctrl = ctrl_l | ctrl_r;
716 break;
717 case SHIFT: /* Left or right shift key */
718 *(scode == RSHIFT_SCAN ? &shift_r : &shift_l) = make;
719 shift = shift_l | shift_r;
720 break;
721 case ALT: /* Left or right alt key */
722 *(escape ? &alt_r : &alt_l) = make;
723 alt = alt_l | alt_r;
724 break;
725 case CALOCK: /* Caps lock - toggle on 0 -> 1 transition */
726 if (caps_down < make) {
727 locks[ccurrent] ^= CAPS_LOCK;
728 set_leds();
730 caps_down = make;
731 break;
732 case NLOCK: /* Num lock */
733 if (num_down < make) {
734 locks[ccurrent] ^= NUM_LOCK;
735 set_leds();
737 num_down = make;
738 break;
739 case SLOCK: /* Scroll lock */
740 if (scroll_down < make) {
741 locks[ccurrent] ^= SCROLL_LOCK;
742 set_leds();
744 scroll_down = make;
745 break;
746 case EXTKEY: /* Escape keycode */
747 esc = 1; /* Next key is escaped */
748 return(-1);
749 default: /* A normal key */
750 if (make) return(ch);
753 /* Key release, or a shift type key. */
754 return(-1);
757 /*===========================================================================*
758 * set_leds *
759 *===========================================================================*/
760 PRIVATE void set_leds()
762 /* Set the LEDs on the caps, num, and scroll lock keys */
763 int s;
764 if (! machine.pc_at) return; /* PC/XT doesn't have LEDs */
766 kb_wait(); /* wait for buffer empty */
767 if ((s=sys_outb(KEYBD, LED_CODE)) != OK)
768 printf("Warning, sys_outb couldn't prepare for LED values: %d\n", s);
769 /* prepare keyboard to accept LED values */
770 kb_ack(); /* wait for ack response */
772 kb_wait(); /* wait for buffer empty */
773 if ((s=sys_outb(KEYBD, locks[ccurrent])) != OK)
774 printf("Warning, sys_outb couldn't give LED values: %d\n", s);
775 /* give keyboard LED values */
776 kb_ack(); /* wait for ack response */
779 /*===========================================================================*
780 * kbc_cmd0 *
781 *===========================================================================*/
782 PRIVATE void kbc_cmd0(cmd)
783 int cmd;
785 kb_wait();
786 if(sys_outb(KB_COMMAND, cmd) != OK)
787 printf("kbc_cmd0: sys_outb failed\n");
790 /*===========================================================================*
791 * kbc_cmd1 *
792 *===========================================================================*/
793 PRIVATE void kbc_cmd1(cmd, data)
794 int cmd;
795 int data;
797 kb_wait();
798 if(sys_outb(KB_COMMAND, cmd) != OK)
799 printf("kbc_cmd1: 1 sys_outb failed\n");
800 kb_wait();
801 if(sys_outb(KEYBD, data) != OK)
802 printf("kbc_cmd1: 2 sys_outb failed\n");
806 /*===========================================================================*
807 * kbc_read *
808 *===========================================================================*/
809 PRIVATE int kbc_read()
811 int i;
812 unsigned long byte, st;
813 #if 0
814 struct micro_state ms;
815 #endif
817 #if DEBUG
818 printf("in kbc_read\n");
819 #endif
821 /* Wait at most 1 second for a byte from the keyboard or
822 * the kbd controller, return -1 on a timeout.
824 for (i= 0; i<1000; i++)
825 #if 0
826 micro_start(&ms);
828 #endif
830 if(sys_inb(KB_STATUS, &st) != OK)
831 printf("kbc_read: 1 sys_inb failed\n");
832 if (st & KB_OUT_FULL)
834 micro_delay(KBC_IN_DELAY);
835 if(sys_inb(KEYBD, &byte) != OK)
836 printf("kbc_read: 2 sys_inb failed\n");
837 if (st & KB_AUX_BYTE)
839 #if DEBUG
840 printf(
841 "keyboard`kbc_read: ignoring byte (0x%x) from aux device.\n",
842 byte);
843 #endif
844 continue;
846 #if DEBUG
847 printf("keyboard`kbc_read: returning byte 0x%x\n",
848 byte);
849 #endif
850 return byte;
853 #if 0
854 while (micro_elapsed(&ms) < 1000000);
855 #endif
856 panic("TTY", "kbc_read failed to complete", NO_NUM);
861 /*===========================================================================*
862 * kb_wait *
863 *===========================================================================*/
864 PRIVATE int kb_wait()
866 /* Wait until the controller is ready; return zero if this times out. */
868 int retries;
869 unsigned long status, temp;
870 int s, isaux;
871 unsigned char byte;
873 retries = MAX_KB_BUSY_RETRIES + 1; /* wait until not busy */
874 do {
875 s = sys_inb(KB_STATUS, &status);
876 if(s != OK)
877 printf("kb_wait: sys_inb failed: %d\n", s);
878 if (status & KB_OUT_FULL) {
879 if (scan_keyboard(&byte, &isaux))
881 #if 0
882 printf("ignoring %sbyte in kb_wait\n", isaux ? "AUX " : "");
883 #endif
886 if (! (status & (KB_IN_FULL|KB_OUT_FULL)) )
887 break; /* wait until ready */
888 } while (--retries != 0); /* continue unless timeout */
889 return(retries); /* zero on timeout, positive if ready */
892 /*===========================================================================*
893 * kb_ack *
894 *===========================================================================*/
895 PRIVATE int kb_ack()
897 /* Wait until kbd acknowledges last command; return zero if this times out. */
899 int retries, s;
900 unsigned long u8val;
903 retries = MAX_KB_ACK_RETRIES + 1;
904 do {
905 s = sys_inb(KEYBD, &u8val);
906 if(s != OK)
907 printf("kb_ack: sys_inb failed: %d\n", s);
908 if (u8val == KB_ACK)
909 break; /* wait for ack */
910 } while(--retries != 0); /* continue unless timeout */
912 return(retries); /* nonzero if ack received */
915 /*===========================================================================*
916 * kb_init *
917 *===========================================================================*/
918 PUBLIC void kb_init(tp)
919 tty_t *tp;
921 /* Initialize the keyboard driver. */
923 tp->tty_devread = kb_read; /* input function */
926 /*===========================================================================*
927 * kb_init_once *
928 *===========================================================================*/
929 PUBLIC void kb_init_once(void)
931 int i;
932 u8_t ccb;
934 set_leds(); /* turn off numlock led */
935 scan_keyboard(NULL, NULL); /* discard leftover keystroke */
937 /* Clear the function key observers array. Also see func_key(). */
938 for (i=0; i<12; i++) {
939 fkey_obs[i].proc_nr = NONE; /* F1-F12 observers */
940 fkey_obs[i].events = 0; /* F1-F12 observers */
941 sfkey_obs[i].proc_nr = NONE; /* Shift F1-F12 observers */
942 sfkey_obs[i].events = 0; /* Shift F1-F12 observers */
945 kbd.minor= KBD_MINOR;
946 kbdaux.minor= KBDAUX_MINOR;
948 /* Set interrupt handler and enable keyboard IRQ. */
949 irq_hook_id = KEYBOARD_IRQ; /* id to be returned on interrupt */
950 if ((i=sys_irqsetpolicy(KEYBOARD_IRQ, IRQ_REENABLE, &irq_hook_id)) != OK)
951 panic("TTY", "Couldn't set keyboard IRQ policy", i);
952 if ((i=sys_irqenable(&irq_hook_id)) != OK)
953 panic("TTY", "Couldn't enable keyboard IRQs", i);
954 kbd_irq_set |= (1 << KEYBOARD_IRQ);
956 /* Set AUX interrupt handler and enable AUX IRQ. */
957 aux_irq_hook_id = KBD_AUX_IRQ; /* id to be returned on interrupt */
958 if ((i=sys_irqsetpolicy(KBD_AUX_IRQ, IRQ_REENABLE,
959 &aux_irq_hook_id)) != OK)
960 panic("TTY", "Couldn't set AUX IRQ policy", i);
961 if ((i=sys_irqenable(&aux_irq_hook_id)) != OK)
962 panic("TTY", "Couldn't enable AUX IRQs", i);
963 kbd_irq_set |= (1 << KBD_AUX_IRQ);
965 /* Disable the keyboard and aux */
966 kbc_cmd0(KBC_DI_KBD);
967 kbc_cmd0(KBC_DI_AUX);
969 /* Get the current configuration byte */
970 kbc_cmd0(KBC_RD_RAM_CCB);
971 ccb= kbc_read();
973 /* Enable both interrupts. */
974 kbc_cmd1(KBC_WR_RAM_CCB, ccb | 3);
976 /* Re-enable the keyboard device. */
977 kbc_cmd0(KBC_EN_KBD);
979 /* Enable the aux device. */
980 kbc_cmd0(KBC_EN_AUX);
983 /*===========================================================================*
984 * kbd_loadmap *
985 *===========================================================================*/
986 PUBLIC int kbd_loadmap(m, safe)
987 message *m;
988 int safe;
990 /* Load a new keymap. */
991 int result;
992 if(safe) {
993 result = sys_safecopyfrom(m->IO_ENDPT, (vir_bytes) m->ADDRESS,
994 0, (vir_bytes) keymap, (vir_bytes) sizeof(keymap), D);
995 } else {
996 result = sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
997 SELF, D, (vir_bytes) keymap,
998 (vir_bytes) sizeof(keymap));
1000 return(result);
1003 /*===========================================================================*
1004 * do_fkey_ctl *
1005 *===========================================================================*/
1006 PUBLIC void do_fkey_ctl(m_ptr)
1007 message *m_ptr; /* pointer to the request message */
1009 /* This procedure allows processes to register a function key to receive
1010 * notifications if it is pressed. At most one binding per key can exist.
1012 int i;
1013 int result;
1015 switch (m_ptr->FKEY_REQUEST) { /* see what we must do */
1016 case FKEY_MAP: /* request for new mapping */
1017 result = OK; /* assume everything will be ok*/
1018 for (i=0; i < 12; i++) { /* check F1-F12 keys */
1019 if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
1020 #if DEAD_CODE
1021 /* Currently, we don't check if the slot is in use, so that IS
1022 * can recover after a crash by overtaking its existing mappings.
1023 * In future, a better solution will be implemented.
1025 if (fkey_obs[i].proc_nr == NONE) {
1026 #endif
1027 fkey_obs[i].proc_nr = m_ptr->m_source;
1028 fkey_obs[i].events = 0;
1029 bit_unset(m_ptr->FKEY_FKEYS, i+1);
1030 #if DEAD_CODE
1031 } else {
1032 printf("WARNING, fkey_map failed F%d\n", i+1);
1033 result = EBUSY; /* report failure, but try rest */
1035 #endif
1038 for (i=0; i < 12; i++) { /* check Shift+F1-F12 keys */
1039 if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
1040 #if DEAD_CODE
1041 if (sfkey_obs[i].proc_nr == NONE) {
1042 #endif
1043 sfkey_obs[i].proc_nr = m_ptr->m_source;
1044 sfkey_obs[i].events = 0;
1045 bit_unset(m_ptr->FKEY_SFKEYS, i+1);
1046 #if DEAD_CODE
1047 } else {
1048 printf("WARNING, fkey_map failed Shift F%d\n", i+1);
1049 result = EBUSY; /* report failure but try rest */
1051 #endif
1054 break;
1055 case FKEY_UNMAP:
1056 result = OK; /* assume everything will be ok*/
1057 for (i=0; i < 12; i++) { /* check F1-F12 keys */
1058 if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
1059 if (fkey_obs[i].proc_nr == m_ptr->m_source) {
1060 fkey_obs[i].proc_nr = NONE;
1061 fkey_obs[i].events = 0;
1062 bit_unset(m_ptr->FKEY_FKEYS, i+1);
1063 } else {
1064 result = EPERM; /* report failure, but try rest */
1068 for (i=0; i < 12; i++) { /* check Shift+F1-F12 keys */
1069 if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
1070 if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
1071 sfkey_obs[i].proc_nr = NONE;
1072 sfkey_obs[i].events = 0;
1073 bit_unset(m_ptr->FKEY_SFKEYS, i+1);
1074 } else {
1075 result = EPERM; /* report failure, but try rest */
1079 break;
1080 case FKEY_EVENTS:
1081 m_ptr->FKEY_FKEYS = m_ptr->FKEY_SFKEYS = 0;
1082 for (i=0; i < 12; i++) { /* check (Shift+) F1-F12 keys */
1083 if (fkey_obs[i].proc_nr == m_ptr->m_source) {
1084 if (fkey_obs[i].events) {
1085 bit_set(m_ptr->FKEY_FKEYS, i+1);
1086 fkey_obs[i].events = 0;
1089 if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
1090 if (sfkey_obs[i].events) {
1091 bit_set(m_ptr->FKEY_SFKEYS, i+1);
1092 sfkey_obs[i].events = 0;
1096 break;
1097 default:
1098 result = EINVAL; /* key cannot be observed */
1101 /* Almost done, return result to caller. */
1102 m_ptr->m_type = result;
1103 send(m_ptr->m_source, m_ptr);
1106 /*===========================================================================*
1107 * func_key *
1108 *===========================================================================*/
1109 PRIVATE int func_key(scode)
1110 int scode; /* scan code for a function key */
1112 /* This procedure traps function keys for debugging purposes. Observers of
1113 * function keys are kept in a global array. If a subject (a key) is pressed
1114 * the observer is notified of the event. Initialization of the arrays is done
1115 * in kb_init, where NONE is set to indicate there is no interest in the key.
1116 * Returns FALSE on a key release or if the key is not observable.
1118 message m;
1119 int key;
1120 int proc_nr;
1121 int i,s;
1123 /* Ignore key releases. If this is a key press, get full key code. */
1124 if (scode & KEY_RELEASE) return(FALSE); /* key release */
1125 key = map_key(scode); /* include modifiers */
1127 /* Key pressed, now see if there is an observer for the pressed key.
1128 * F1-F12 observers are in fkey_obs array.
1129 * SHIFT F1-F12 observers are in sfkey_req array.
1130 * CTRL F1-F12 reserved (see kb_read)
1131 * ALT F1-F12 reserved (see kb_read)
1132 * Other combinations are not in use. Note that Alt+Shift+F1-F12 is yet
1133 * defined in <minix/keymap.h>, and thus is easy for future extensions.
1135 if (F1 <= key && key <= F12) { /* F1-F12 */
1136 proc_nr = fkey_obs[key - F1].proc_nr;
1137 fkey_obs[key - F1].events ++ ;
1138 } else if (SF1 <= key && key <= SF12) { /* Shift F2-F12 */
1139 proc_nr = sfkey_obs[key - SF1].proc_nr;
1140 sfkey_obs[key - SF1].events ++;
1142 else {
1143 return(FALSE); /* not observable */
1146 /* See if an observer is registered and send it a message. */
1147 if (proc_nr != NONE) {
1148 m.NOTIFY_TYPE = FKEY_PRESSED;
1149 notify(proc_nr);
1151 return(TRUE);
1154 /*===========================================================================*
1155 * show_key_mappings *
1156 *===========================================================================*/
1157 PRIVATE void show_key_mappings()
1159 int i,s;
1160 struct proc proc;
1162 printf("\n");
1163 printf("System information. Known function key mappings to request debug dumps:\n");
1164 printf("-------------------------------------------------------------------------\n");
1165 for (i=0; i<12; i++) {
1167 printf(" %sF%d: ", i+1<10? " ":"", i+1);
1168 if (fkey_obs[i].proc_nr != NONE) {
1169 if ((s=sys_getproc(&proc, fkey_obs[i].proc_nr))!=OK)
1170 printf("sys_getproc: %d\n", s);
1171 printf("%-14.14s", proc.p_name);
1172 } else {
1173 printf("%-14.14s", "<none>");
1176 printf(" %sShift-F%d: ", i+1<10? " ":"", i+1);
1177 if (sfkey_obs[i].proc_nr != NONE) {
1178 if ((s=sys_getproc(&proc, sfkey_obs[i].proc_nr))!=OK)
1179 printf("sys_getproc: %d\n", s);
1180 printf("%-14.14s", proc.p_name);
1181 } else {
1182 printf("%-14.14s", "<none>");
1184 printf("\n");
1186 printf("\n");
1187 printf("Press one of the registered function keys to trigger a debug dump.\n");
1188 printf("\n");
1191 /*===========================================================================*
1192 * scan_keyboard *
1193 *===========================================================================*/
1194 PRIVATE int scan_keyboard(bp, isauxp)
1195 unsigned char *bp;
1196 int *isauxp;
1198 #if 0 /* Is this old XT code? It doesn't match the PS/2 hardware */
1199 /* Fetch the character from the keyboard hardware and acknowledge it. */
1200 pvb_pair_t byte_in[2], byte_out[2];
1202 byte_in[0].port = KEYBD; /* get the scan code for the key struck */
1203 byte_in[1].port = PORT_B; /* strobe the keyboard to ack the char */
1204 if(sys_vinb(byte_in, 2) != OK) /* request actual input */
1205 printf("scan_keyboard: sys_vinb failed\n");
1207 pv_set(byte_out[0], PORT_B, byte_in[1].value | KBIT); /* strobe bit high */
1208 pv_set(byte_out[1], PORT_B, byte_in[1].value); /* then strobe low */
1209 if(sys_voutb(byte_out, 2) != OK) /* request actual output */
1210 printf("scan_keyboard: sys_voutb failed\n");
1212 return(byte_in[0].value); /* return scan code */
1213 #else
1214 unsigned long b, sb;
1216 if(sys_inb(KB_STATUS, &sb) != OK)
1217 printf("scan_keyboard: sys_inb failed\n");
1219 if (!(sb & KB_OUT_FULL))
1221 if (kbdout.avail && !kbdout.expect_ack)
1222 kbd_send();
1223 return 0;
1225 if(sys_inb(KEYBD, &b) != OK)
1226 printf("scan_keyboard: 2 sys_inb failed\n");
1227 #if 0
1228 printf("got byte 0x%x from %s\n", b, (sb & KB_AUX_BYTE) ? "AUX" : "keyboard");
1229 #endif
1230 if (!(sb & KB_AUX_BYTE) && b == KB_ACK && kbdout.expect_ack)
1232 #if 0
1233 printf("got ACK from keyboard\n");
1234 #endif
1235 kbdout.expect_ack= 0;
1236 micro_delay(KBC_IN_DELAY);
1237 kbd_send();
1238 return 0;
1240 if (bp)
1241 *bp= b;
1242 if (isauxp)
1243 *isauxp= !!(sb & KB_AUX_BYTE);
1244 if (kbdout.avail && !kbdout.expect_ack)
1246 micro_delay(KBC_IN_DELAY);
1247 kbd_send();
1249 return 1;
1250 #endif
1253 static void micro_delay(unsigned long usecs)
1255 tickdelay(MICROS_TO_TICKS(usecs));
1258 /*===========================================================================*
1259 * kbd_watchdog *
1260 *===========================================================================*/
1261 PRIVATE void kbd_watchdog(tmrp)
1262 timer_t *tmrp;
1264 int r;
1265 clock_t now;
1267 kbd_watchdog_set= 0;
1268 if (!kbdout.avail)
1269 return; /* Watchdog is no longer needed */
1270 if (!kbd_alive)
1272 printf("kbd_watchdog: should reset keyboard\n");
1274 kbd_alive= 0;
1276 if ((r= getuptime(&now)) != OK)
1277 panic("TTY","Keyboard couldn't get clock's uptime.", r);
1278 tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+HZ, kbd_watchdog,
1279 NULL);
1280 if (tty_timers->tmr_exp_time != tty_next_timeout) {
1281 tty_next_timeout = tty_timers->tmr_exp_time;
1282 if ((r= sys_setalarm(tty_next_timeout, 1)) != OK)
1283 panic("TTY","Keyboard couldn't set alarm.", r);
1285 kbd_watchdog_set= 1;