1 /* Keyboard driver for PC's and AT's.
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)
9 #include <minix/drivers.h>
10 #include <sys/ioctl.h>
11 #include <sys/kbdio.h>
13 #include <sys/select.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>
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 */
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 */
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
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
;
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 */
132 cp_grant_id_t req_grant
;
133 vir_bytes req_addr_offset
;
139 /* Data that is to be sent to the keyboard. Each byte is ACKed by the
142 static struct kbd_outack
144 unsigned char buf
[KBD_OUT_BUFSZ
];
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
));
180 /*===========================================================================*
182 *===========================================================================*/
183 void do_kbd(message
*m
)
189 /*===========================================================================*
191 *===========================================================================*/
192 int kbd_status(message
*m
)
196 r
= handle_status(&kbd
, m
);
199 return handle_status(&kbdaux
, m
);
203 /*===========================================================================*
205 *===========================================================================*/
206 void do_kbdaux(message
*m
)
208 handle_req(&kbdaux
, m
);
212 /*===========================================================================*
214 *===========================================================================*/
215 static void handle_req(kbdp
, m
)
219 int i
, n
, r
, ops
, watch
;
222 /* Execute the requested device driver function. */
223 r
= EINVAL
; /* just in case */
231 if (kbdp
->nr_open
< 0)
233 printf("TTY(kbd): open count is negative\n");
236 if (kbdp
->nr_open
== 0)
243 /* We handle only request at a time */
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
;
259 /* Handle read request */
263 if (kbdp
->offset
+ n
> KBD_BUFSZ
)
264 n
= KBD_BUFSZ
-kbdp
->offset
;
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
);
271 kbdp
->offset
= (kbdp
->offset
+n
) % KBD_BUFSZ
;
275 printf("copy in read kbd failed: %d\n", r
);
283 printf("write to keyboard not implemented\n");
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);
298 kbc_cmd1(KBC_WRITE_AUX
, c
);
308 ops
= m
->USER_ENDPT
& (SEL_RD
|SEL_WR
|SEL_ERR
);
309 watch
= (m
->USER_ENDPT
& SEL_NOTIFY
) ? 1 : 0;
312 if (kbdp
->avail
&& (ops
& SEL_RD
))
320 kbdp
->select_ops
|= ops
;
321 kbdp
->select_proc
= m
->m_source
;
325 if (kbdp
== &kbd
&& m
->TTY_REQUEST
== KIOCSLEDS
)
331 r
= sys_safecopyfrom(m
->m_source
, (cp_grant_id_t
)
332 m
->IO_GRANT
, 0, (vir_bytes
) &leds
,
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)
342 if (kbdout
.offset
+ kbdout
.avail
+ 2 > KBD_OUT_BUFSZ
)
344 /* Output buffer is full. Ignore this command.
347 kbdout
.expect_ack
= 0;
351 kbdout
.buf
[kbdout
.offset
+kbdout
.avail
]=
353 kbdout
.buf
[kbdout
.offset
+kbdout
.avail
+1]= b
;
356 if (!kbdout
.expect_ack
)
361 if (kbdp
== &kbd
&& m
->TTY_REQUEST
== KIOCBELL
)
366 r
= sys_safecopyfrom(m
->m_source
, (cp_grant_id_t
)
367 m
->IO_GRANT
, 0, (vir_bytes
) &bell
,
372 ticks
= bell
.kb_duration
.tv_usec
* system_hz
/ 1000000;
373 ticks
+= bell
.kb_duration
.tv_sec
* system_hz
;
376 beep_x(bell
.kb_pitch
, ticks
);
385 printf("Warning, TTY(kbd) got unexpected request %d from %d\n",
386 m
->m_type
, m
->m_source
);
389 tty_reply(TASK_REPLY
, m
->m_source
, m
->USER_ENDPT
, r
);
393 /*===========================================================================*
395 *===========================================================================*/
396 static int handle_status(kbdp
, m
)
402 if (kbdp
->avail
&& kbdp
->req_size
&& m
->m_source
== kbdp
->incaller
&&
403 kbdp
->req_grant
!= GRANT_INVALID
)
405 /* Handle read request */
407 if (n
> kbdp
->req_size
)
409 if (kbdp
->offset
+ n
> KBD_BUFSZ
)
410 n
= KBD_BUFSZ
-kbdp
->offset
;
412 panic("kbd_status: bad n: %d", n
);
414 r
= sys_safecopyto(kbdp
->incaller
, kbdp
->req_grant
, 0,
415 (vir_bytes
)&kbdp
->buf
[kbdp
->offset
], n
);
418 kbdp
->offset
= (kbdp
->offset
+n
) % KBD_BUFSZ
;
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
;
427 kbdp
->req_grant
= GRANT_INVALID
;
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
;
445 /*===========================================================================*
447 *===========================================================================*/
448 static unsigned map_key(scode
)
451 /* Map a scan code to an ASCII code. */
453 int caps
, column
, lk
;
457 keyrow
= &keymap_escaped
[scode
* MAP_COLS
];
459 keyrow
= &keymap
[scode
* MAP_COLS
];
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
;
468 if (ctrl
|| alt_r
) column
= 3; /* Ctrl + Alt == AltGr */
469 if (caps
) column
= 4;
471 if (sticky_alt_mode
&& (lk
& ALT_LOCK
)) {
473 if (caps
) column
= 4;
476 if (caps
) column
= 1;
477 if (ctrl
) column
= 5;
480 return keyrow
[column
] & ~HASCAPS
;
483 /*===========================================================================*
485 *===========================================================================*/
486 void kbd_interrupt(message
*UNUSED(m_ptr
))
488 /* A keyboard interrupt has occurred. Process it. */
493 /* Fetch the character from the keyboard hardware and acknowledge it. */
494 if (!scan_keyboard(&scode
, &isaux
))
499 else if (kbd
.nr_open
)
506 /* raw scan codes or aux data */
507 if (kbdp
->avail
>= KBD_BUFSZ
)
510 printf("kbd_interrupt: %s buffer is full\n",
511 isaux
? "kbdaux" : "keyboard");
513 return; /* Buffer is full */
515 o
= (kbdp
->offset
+ kbdp
->avail
) % KBD_BUFSZ
;
518 if (kbdp
->req_size
) {
519 notify(kbdp
->incaller
);
521 if (kbdp
->select_ops
& SEL_RD
)
522 notify(kbdp
->select_proc
);
526 /* Store the scancode in memory so the task can get at it later. */
527 if (icount
< KB_IN_BYTES
) {
529 if (ihead
== ibuf
+ KB_IN_BYTES
) ihead
= ibuf
;
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
)
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
) {
553 if (injhead
== injbuf
+ KB_IN_BYTES
) injhead
= injbuf
;
555 tty_table
[ccurrent
].tty_events
= 1;
556 if (tty_table
[ccurrent
].tty_select_ops
& SEL_RD
) {
557 select_retry(&tty_table
[ccurrent
]);
563 /*===========================================================================*
565 *===========================================================================*/
566 static int kb_read(tp
, try)
570 /* Process characters from the circular keyboard buffer. */
571 char buf
[7], *p
, suffix
;
575 /* always use the current console */
576 tp
= &tty_table
[ccurrent
];
579 if (icount
> 0) return 1;
583 while (icount
> 0 || injcount
> 0) {
585 /* take one key scan code */
587 if (injtail
== injbuf
+ KB_IN_BYTES
) injtail
= injbuf
;
590 /* take one key scan code */
592 if (itail
== ibuf
+ KB_IN_BYTES
) itail
= ibuf
;
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
);
604 /* A normal character. */
606 (void) in_process(tp
, buf
, 1, scode
);
608 if (HOME
<= ch
&& ch
<= INSRT
) {
609 /* An ASCII escape sequence generated by the numeric pad. */
612 buf
[2] = numpad_map
[ch
- HOME
];
613 (void) in_process(tp
, buf
, 3, scode
);
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
) {
622 if (SF1
<= ch
&& ch
<= SF12
) {
626 /* (CF1 <= ch && ch <= CF12) */ {
628 suffix
= shift
? '6' : '5';
630 /* ^[[11~ for F1, ^[[24;5~ for CF12 etc */
633 buf
[2] = fkey_map
[ch
][0];
634 buf
[3] = fkey_map
[ch
][1];
641 (void) in_process(tp
, buf
, p
- buf
, scode
);
644 /* Choose lower numbered console as current console. */
645 select_console(ccurrent
- 1);
649 /* Choose higher numbered console as current console. */
650 select_console(ccurrent
+ 1);
653 if (AF1
<= ch
&& ch
<= AF12
) {
654 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
655 select_console(ch
- AF1
);
658 if (CF1
<= ch
&& ch
<= CF12
) {
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;
667 /* pass on scancode even though there is no character code */
668 (void) in_process(tp
, NULL
, 0, scode
);
675 /*===========================================================================*
677 *===========================================================================*/
678 static void kbd_send()
685 if (kbdout
.expect_ack
)
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
);
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
);
706 /* Okay, buffer is really empty */
708 printf("sending byte 0x%x to keyboard\n", kbdout
.buf
[kbdout
.offset
]);
710 if((r
=sys_outb(KEYBD
, kbdout
.buf
[kbdout
.offset
])) != OK
) {
711 printf("kbd_send: 3 sys_outb() failed: %d\n", r
);
715 kbdout
.expect_ack
= 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);
727 /*===========================================================================*
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) {
749 sys_abort(RBT_DEFAULT
);
751 sys_kill(INIT_PROC_NR
, SIGABRT
);
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) */
767 case CTRL
: /* Left or right control key */
768 *(escape
? &ctrl_r
: &ctrl_l
) = make
;
769 ctrl
= ctrl_l
| ctrl_r
;
771 case SHIFT
: /* Left or right shift key */
772 *(scode
== RSHIFT_SCAN
? &shift_r
: &shift_l
) = make
;
773 shift
= shift_l
| shift_r
;
775 case ALT
: /* Left or right alt key */
776 *(escape
? &alt_r
: &alt_l
) = make
;
778 if (sticky_alt_mode
&& (alt_r
&& (alt_down
< make
))) {
779 locks
[ccurrent
] ^= ALT_LOCK
;
783 case CALOCK
: /* Caps lock - toggle on 0 -> 1 transition */
784 if (caps_down
< make
) {
785 locks
[ccurrent
] ^= CAPS_LOCK
;
790 case NLOCK
: /* Num lock */
791 if (num_down
< make
) {
792 locks
[ccurrent
] ^= NUM_LOCK
;
797 case SLOCK
: /* Scroll lock */
798 if (scroll_down
< make
) {
799 locks
[ccurrent
] ^= SCROLL_LOCK
;
804 case EXTKEY
: /* Escape keycode */
805 esc
= 1; /* Next key is escaped */
807 default: /* A normal key */
813 static char seen
[2][NR_SCAN_CODES
];
816 if(scode
>= 0 && scode
< NR_SCAN_CODES
) {
817 notseen
= !seen
[ei
][scode
];
820 printf("tty: scode %d makes no sense\n", scode
);
823 printf("tty: ignoring unrecognized %s "
825 escape
? "escaped" : "straight", scode
);
831 /* Key release, or a shift type key. */
835 /*===========================================================================*
837 *===========================================================================*/
838 static void set_leds()
840 /* Set the LEDs on the caps, num, and scroll lock keys */
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 /*===========================================================================*
858 *===========================================================================*/
859 static void kbc_cmd0(cmd
)
863 if(sys_outb(KB_COMMAND
, cmd
) != OK
)
864 printf("kbc_cmd0: sys_outb failed\n");
867 /*===========================================================================*
869 *===========================================================================*/
870 static void kbc_cmd1(cmd
, data
)
875 if(sys_outb(KB_COMMAND
, cmd
) != OK
)
876 printf("kbc_cmd1: 1 sys_outb failed\n");
878 if(sys_outb(KEYBD
, data
) != OK
)
879 printf("kbc_cmd1: 2 sys_outb failed\n");
883 /*===========================================================================*
885 *===========================================================================*/
886 static int kbc_read()
891 struct micro_state ms
;
895 printf("in kbc_read\n");
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
++)
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
);
917 printf("keyboard`kbc_read: returning byte 0x%x\n",
924 while (micro_elapsed(&ms
) < 1000000);
926 panic("kbc_read failed to complete");
931 /*===========================================================================*
933 *===========================================================================*/
936 /* Wait until the controller is ready; return zero if this times out. */
943 retries
= MAX_KB_BUSY_RETRIES
+ 1; /* wait until not busy */
945 s
= sys_inb(KB_STATUS
, &status
);
947 printf("kb_wait: sys_inb failed: %d\n", s
);
948 if (status
& KB_OUT_FULL
) {
949 if (scan_keyboard(&byte
, &isaux
))
952 printf("ignoring %sbyte in kb_wait\n", isaux
? "AUX " : "");
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 /*===========================================================================*
964 *===========================================================================*/
967 /* Wait until kbd acknowledges last command; return zero if this times out. */
972 retries
= MAX_KB_ACK_RETRIES
+ 1;
974 s
= sys_inb(KEYBD
, &u8val
);
976 printf("kb_ack: sys_inb failed: %d\n", s
);
978 break; /* wait for ack */
979 } while(--retries
!= 0); /* continue unless timeout */
981 return(retries
); /* nonzero if ack received */
984 /*===========================================================================*
986 *===========================================================================*/
990 /* Initialize the keyboard driver. */
992 tp
->tty_devread
= kb_read
; /* input function */
995 /*===========================================================================*
997 *===========================================================================*/
998 void kb_init_once(void)
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
);
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 /*===========================================================================*
1057 *===========================================================================*/
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 /*===========================================================================*
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.
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) ) {
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
) {
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);
1095 printf("WARNING, fkey_map failed F%d\n", i
+1);
1096 result
= EBUSY
; /* report failure, but try rest */
1101 for (i
=0; i
< 12; i
++) { /* check Shift+F1-F12 keys */
1102 if (bit_isset(m_ptr
->FKEY_SFKEYS
, i
+1) ) {
1104 if (sfkey_obs
[i
].proc_nr
== NONE
) {
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);
1111 printf("WARNING, fkey_map failed Shift F%d\n", i
+1);
1112 result
= EBUSY
; /* report failure but try rest */
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);
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);
1138 result
= EPERM
; /* report failure, but try rest */
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;
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 /*===========================================================================*
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.
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
++;
1203 return(FALSE
); /* not observable */
1206 /* See if an observer is registered and send it a message. */
1207 if (proc_nr
!= NONE
) {
1213 /*===========================================================================*
1214 * show_key_mappings *
1215 *===========================================================================*/
1216 static void show_key_mappings()
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>");
1231 printf("%-14.14s", proc
.p_name
);
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>");
1241 printf("%-14.14s", proc
.p_name
);
1243 printf("%-14.14s", "<none>");
1248 printf("Press one of the registered function keys to trigger a debug dump.\n");
1252 /*===========================================================================*
1254 *===========================================================================*/
1255 static int scan_keyboard(bp
, isauxp
)
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
)
1270 if(sys_inb(KEYBD
, &b
) != OK
)
1271 printf("scan_keyboard: 2 sys_inb failed\n");
1273 printf("got byte 0x%x from %s\n", b
, (sb
& KB_AUX_BYTE
) ? "AUX" : "keyboard");
1275 if (!(sb
& KB_AUX_BYTE
) && b
== KB_ACK
&& kbdout
.expect_ack
)
1278 printf("got ACK from keyboard\n");
1280 kbdout
.expect_ack
= 0;
1281 micro_delay(KBC_IN_DELAY
);
1288 *isauxp
= !!(sb
& KB_AUX_BYTE
);
1289 if (kbdout
.avail
&& !kbdout
.expect_ack
)
1291 micro_delay(KBC_IN_DELAY
);
1297 /*===========================================================================*
1299 *===========================================================================*/
1300 static void kbd_watchdog(timer_t
*UNUSED(tmrp
))
1303 kbd_watchdog_set
= 0;
1305 return; /* Watchdog is no longer needed */
1308 printf("kbd_watchdog: should reset keyboard\n");
1312 set_timer(&tmr_kbd_wd
, system_hz
, kbd_watchdog
, 0);
1314 kbd_watchdog_set
= 1;