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/reboot.h>
14 #include <sys/select.h>
15 #include <sys/termios.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>
26 static u16_t keymap
[NR_SCAN_CODES
][MAP_COLS
] = {
27 #include "keymaps/us-std.src"
30 #define KB_IN_BYTES 32 /* size of keyboard input buffer */
32 /* Scan codes in the input buffer are in the 0000h-00E7h range inclusive, plus
33 * the following bit if the key was released rather than pressed.
35 #define RELEASE_BIT 0x8000
37 static unsigned short inbuf
[KB_IN_BYTES
];
38 static unsigned short *inhead
= inbuf
;
39 static unsigned short *intail
= inbuf
;
42 static int alt_l
; /* left alt key state */
43 static int alt_r
; /* right alt key state */
44 static int alt
; /* either alt key */
45 static int ctrl_l
; /* left control key state */
46 static int ctrl_r
; /* right control key state */
47 static int ctrl
; /* either control key */
48 static int shift_l
; /* left shift key state */
49 static int shift_r
; /* right shift key state */
50 static int shift
; /* either shift key */
51 static int num_down
; /* num lock key depressed */
52 static int caps_down
; /* caps lock key depressed */
53 static int scroll_down
; /* scroll lock key depressed */
54 static int alt_down
; /* alt key depressed */
55 static int locks
[NR_CONS
]; /* per console lock keys state */
57 /* Lock key active bits. Chosen to be equal to the input LED mask bits. */
58 #define SCROLL_LOCK (1 << INPUT_LED_SCROLLLOCK)
59 #define NUM_LOCK (1 << INPUT_LED_NUMLOCK)
60 #define CAPS_LOCK (1 << INPUT_LED_CAPSLOCK)
63 static char numpad_map
[12] =
64 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
66 static char *fkey_map
[12] =
67 {"11", "12", "13", "14", "15", "17", /* F1-F6 */
68 "18", "19", "20", "21", "23", "24"}; /* F7-F12 */
70 /* Variables and definition for observed function keys. */
71 typedef struct observer
{ endpoint_t proc_nr
; int events
; } obs_t
;
72 static obs_t fkey_obs
[12]; /* observers for F1-F12 */
73 static obs_t sfkey_obs
[12]; /* observers for SHIFT F1-F12 */
75 static endpoint_t input_endpt
= NONE
;
77 static long sticky_alt_mode
= 0;
78 static long debug_fkeys
= 1;
80 static int func_key(int scode
);
81 static unsigned make_break(int scode
);
82 static void set_leds(void);
83 static void show_key_mappings(void);
84 static unsigned map_key(int scode
);
86 /*===========================================================================*
88 *===========================================================================*/
89 static unsigned map_key(scode
)
92 /* Map a scan code to an ASCII code. */
97 keyrow
= keymap
[scode
];
100 lk
= locks
[ccurrent
];
101 if ((lk
& NUM_LOCK
) && (keyrow
[0] & HASNUM
)) caps
= !caps
;
102 if ((lk
& CAPS_LOCK
) && (keyrow
[0] & HASCAPS
)) caps
= !caps
;
106 if (ctrl
|| alt_r
) column
= 3; /* Ctrl + Alt == AltGr */
107 if (caps
) column
= 4;
109 if (sticky_alt_mode
&& (lk
& ALT_LOCK
)) {
111 if (caps
) column
= 4;
114 if (caps
) column
= 1;
115 if (ctrl
) column
= 5;
118 return keyrow
[column
] & ~(HASNUM
| HASCAPS
);
121 /*===========================================================================*
123 *===========================================================================*/
124 void do_input(message
*msg
)
126 unsigned short scode
;
130 switch (msg
->m_type
) {
132 if ((r
= ds_retrieve_label_endpt("input", &endpt
)) != OK
) {
133 printf("TTY: unable to retrieve INPUT endpoint (%d)\n", r
);
136 if (endpt
!= msg
->m_source
) {
137 printf("TTY: up request from non-INPUT %u\n", msg
->m_source
);
141 input_endpt
= msg
->m_source
;
143 /* Pass the current state of the LEDs to INPUT. */
148 case TTY_INPUT_EVENT
:
149 if (msg
->m_source
!= input_endpt
) {
150 printf("TTY: input event from non-INPUT %u\n", msg
->m_source
);
154 /* Only handle keyboard keys. */
155 if (msg
->INPUT_PAGE
!= INPUT_PAGE_KEY
)
158 /* Only handle known USB HID keyboard codes (the 00h-E7h range). */
159 scode
= msg
->INPUT_CODE
;
160 if (scode
>= NR_SCAN_CODES
)
163 /* Is it a KEY RELEASE? */
164 if (msg
->INPUT_VALUE
== INPUT_RELEASE
)
165 scode
|= RELEASE_BIT
;
167 if (incount
< KB_IN_BYTES
) {
169 if (inhead
== inbuf
+ KB_IN_BYTES
) inhead
= inbuf
;
171 tty_table
[ccurrent
].tty_events
= 1;
177 panic("do_input called for unknown message type %x", msg
->m_type
);
181 /*===========================================================================*
183 *===========================================================================*/
184 static int kb_read(tp
, try)
188 /* Process characters from the circular keyboard buffer. */
189 char buf
[7], *p
, suffix
;
190 unsigned short scode
;
193 /* always use the current console */
194 tp
= &tty_table
[ccurrent
];
197 return (incount
> 0);
199 while (incount
> 0) {
200 /* Take one key scan code. */
202 if (intail
== inbuf
+ KB_IN_BYTES
) intail
= inbuf
;
205 /* Function keys are being used for debug dumps (if enabled). */
206 if (debug_fkeys
&& func_key(scode
)) continue;
208 /* Perform make/break processing. */
209 ch
= make_break(scode
);
212 /* A normal character. */
214 (void) in_process(tp
, buf
, 1);
216 if (HOME
<= ch
&& ch
<= INSRT
) {
217 /* An ASCII escape sequence generated by the numeric pad. */
220 buf
[2] = numpad_map
[ch
- HOME
];
221 (void) in_process(tp
, buf
, 3);
223 if ((F1
<= ch
&& ch
<= F12
) || (SF1
<= ch
&& ch
<= SF12
) ||
224 (CF1
<= ch
&& ch
<= CF12
&& !debug_fkeys
)) {
225 /* An escape sequence generated by function keys. */
226 if (F1
<= ch
&& ch
<= F12
) {
230 if (SF1
<= ch
&& ch
<= SF12
) {
234 /* (CF1 <= ch && ch <= CF12) */ {
236 suffix
= shift
? '6' : '5';
238 /* ^[[11~ for F1, ^[[24;5~ for CF12 etc */
241 buf
[2] = fkey_map
[ch
][0];
242 buf
[3] = fkey_map
[ch
][1];
249 (void) in_process(tp
, buf
, p
- buf
);
252 /* Choose lower numbered console as current console. */
253 select_console(ccurrent
- 1);
257 /* Choose higher numbered console as current console. */
258 select_console(ccurrent
+ 1);
261 if (AF1
<= ch
&& ch
<= AF12
) {
262 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
263 select_console(ch
- AF1
);
266 if (CF1
<= ch
&& ch
<= CF12
) {
268 case CF1
: show_key_mappings(); break;
269 case CF3
: toggle_scroll(); break; /* hardware <-> software */
270 case CF7
: sigchar(line2tty(CONS_MINOR
), SIGQUIT
, 1); break;
271 case CF8
: sigchar(line2tty(CONS_MINOR
), SIGINT
, 1); break;
272 case CF9
: sigchar(line2tty(CONS_MINOR
), SIGKILL
, 1); break;
280 /*===========================================================================*
282 *===========================================================================*/
283 static unsigned make_break(int scode
)
285 /* This routine can handle keyboards that interrupt only on key depression,
286 * as well as keyboards that interrupt on key depression and key release.
287 * For efficiency, the interrupt routine filters out most key releases.
290 static int CAD_count
= 0;
291 static int rebooting
= 0;
293 /* Check for CTRL-ALT-DEL, and if found, halt the computer. */
294 if (ctrl
&& alt
&& (scode
== INPUT_KEY_DELETE
|| scode
== INPUT_KEY_INSERT
))
296 if (++CAD_count
== 3) {
298 sys_abort(RB_AUTOBOOT
);
300 sys_kill(INIT_PROC_NR
, SIGABRT
);
307 /* High-order bit set on key release. */
308 make
= !(scode
& RELEASE_BIT
); /* true if pressed */
310 ch
= map_key(scode
&= ~RELEASE_BIT
); /* map to ASCII */
313 case LCTRL
: /* Left or right control key */
315 *(ch
== RCTRL
? &ctrl_r
: &ctrl_l
) = make
;
316 ctrl
= ctrl_l
| ctrl_r
;
318 case LSHIFT
: /* Left or right shift key */
320 *(ch
== RSHIFT
? &shift_r
: &shift_l
) = make
;
321 shift
= shift_l
| shift_r
;
323 case LALT
: /* Left or right alt key */
325 *(ch
== RALT
? &alt_r
: &alt_l
) = make
;
327 if (sticky_alt_mode
&& (alt_r
&& (alt_down
< make
))) {
328 locks
[ccurrent
] ^= ALT_LOCK
;
332 case CALOCK
: /* Caps lock - toggle on 0 -> 1 transition */
333 if (caps_down
< make
) {
334 locks
[ccurrent
] ^= CAPS_LOCK
;
339 case NLOCK
: /* Num lock */
340 if (num_down
< make
) {
341 locks
[ccurrent
] ^= NUM_LOCK
;
346 case SLOCK
: /* Scroll lock */
347 if (scroll_down
< make
) {
348 locks
[ccurrent
] ^= SCROLL_LOCK
;
353 default: /* A normal key */
358 /* Ignore unmapped key codes. */
362 /* Key release, or a shift type key. */
366 /*===========================================================================*
368 *===========================================================================*/
369 static void set_leds(void)
371 /* Make INPUT set the LEDs on the caps, num, and scroll lock keys. */
375 if (input_endpt
== NONE
)
378 memset(&m
, 0, sizeof(m
));
380 m
.m_type
= INPUT_SETLEDS
;
381 m
.INPUT_LED_MASK
= locks
[ccurrent
] & ~ALT_LOCK
;
383 if ((r
= asynsend3(input_endpt
, &m
, AMF_NOREPLY
)) != OK
)
384 printf("TTY: asynsend to INPUT %u failed (%d)\n", input_endpt
, r
);
387 /*===========================================================================*
389 *===========================================================================*/
393 /* Initialize the keyboard driver. */
395 tp
->tty_devread
= kb_read
; /* input function */
398 /*===========================================================================*
400 *===========================================================================*/
401 void kb_init_once(void)
405 env_parse("sticky_alt", "d", 0, &sticky_alt_mode
, 0, 1);
406 env_parse("debug_fkeys", "d", 0, &debug_fkeys
, 0, 1);
408 /* Clear the function key observers array. Also see func_key(). */
409 for (i
= 0; i
< 12; i
++) {
410 fkey_obs
[i
].proc_nr
= NONE
; /* F1-F12 observers */
411 fkey_obs
[i
].events
= 0; /* F1-F12 observers */
412 sfkey_obs
[i
].proc_nr
= NONE
; /* Shift F1-F12 observers */
413 sfkey_obs
[i
].events
= 0; /* F1-F12 observers */
417 /*===========================================================================*
419 *===========================================================================*/
420 int kbd_loadmap(endpoint_t endpt
, cp_grant_id_t grant
)
422 /* Load a new keymap. */
423 return sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) keymap
, sizeof(keymap
));
426 /*===========================================================================*
428 *===========================================================================*/
429 void do_fkey_ctl(m_ptr
)
430 message
*m_ptr
; /* pointer to the request message */
432 /* This procedure allows processes to register a function key to receive
433 * notifications if it is pressed. At most one binding per key can exist.
438 switch (m_ptr
->FKEY_REQUEST
) { /* see what we must do */
439 case FKEY_MAP
: /* request for new mapping */
440 result
= OK
; /* assume everything will be ok*/
441 for (i
=0; i
< 12; i
++) { /* check F1-F12 keys */
442 if (bit_isset(m_ptr
->FKEY_FKEYS
, i
+1) ) {
444 /* Currently, we don't check if the slot is in use, so that IS
445 * can recover after a crash by overtaking its existing mappings.
446 * In future, a better solution will be implemented.
448 if (fkey_obs
[i
].proc_nr
== NONE
) {
450 fkey_obs
[i
].proc_nr
= m_ptr
->m_source
;
451 fkey_obs
[i
].events
= 0;
452 bit_unset(m_ptr
->FKEY_FKEYS
, i
+1);
455 printf("WARNING, fkey_map failed F%d\n", i
+1);
456 result
= EBUSY
; /* report failure, but try rest */
461 for (i
=0; i
< 12; i
++) { /* check Shift+F1-F12 keys */
462 if (bit_isset(m_ptr
->FKEY_SFKEYS
, i
+1) ) {
464 if (sfkey_obs
[i
].proc_nr
== NONE
) {
466 sfkey_obs
[i
].proc_nr
= m_ptr
->m_source
;
467 sfkey_obs
[i
].events
= 0;
468 bit_unset(m_ptr
->FKEY_SFKEYS
, i
+1);
471 printf("WARNING, fkey_map failed Shift F%d\n", i
+1);
472 result
= EBUSY
; /* report failure but try rest */
479 result
= OK
; /* assume everything will be ok*/
480 for (i
=0; i
< 12; i
++) { /* check F1-F12 keys */
481 if (bit_isset(m_ptr
->FKEY_FKEYS
, i
+1) ) {
482 if (fkey_obs
[i
].proc_nr
== m_ptr
->m_source
) {
483 fkey_obs
[i
].proc_nr
= NONE
;
484 fkey_obs
[i
].events
= 0;
485 bit_unset(m_ptr
->FKEY_FKEYS
, i
+1);
487 result
= EPERM
; /* report failure, but try rest */
491 for (i
=0; i
< 12; i
++) { /* check Shift+F1-F12 keys */
492 if (bit_isset(m_ptr
->FKEY_SFKEYS
, i
+1) ) {
493 if (sfkey_obs
[i
].proc_nr
== m_ptr
->m_source
) {
494 sfkey_obs
[i
].proc_nr
= NONE
;
495 sfkey_obs
[i
].events
= 0;
496 bit_unset(m_ptr
->FKEY_SFKEYS
, i
+1);
498 result
= EPERM
; /* report failure, but try rest */
504 m_ptr
->FKEY_FKEYS
= m_ptr
->FKEY_SFKEYS
= 0;
505 for (i
=0; i
< 12; i
++) { /* check (Shift+) F1-F12 keys */
506 if (fkey_obs
[i
].proc_nr
== m_ptr
->m_source
) {
507 if (fkey_obs
[i
].events
) {
508 bit_set(m_ptr
->FKEY_FKEYS
, i
+1);
509 fkey_obs
[i
].events
= 0;
512 if (sfkey_obs
[i
].proc_nr
== m_ptr
->m_source
) {
513 if (sfkey_obs
[i
].events
) {
514 bit_set(m_ptr
->FKEY_SFKEYS
, i
+1);
515 sfkey_obs
[i
].events
= 0;
522 /* Almost done, return result to caller. */
523 m_ptr
->m_type
= result
;
524 if ((s
= ipc_sendnb(m_ptr
->m_source
, m_ptr
)) != OK
)
525 printf("TTY: unable to reply to %d: %d", m_ptr
->m_source
, s
);
528 /*===========================================================================*
530 *===========================================================================*/
531 static int func_key(scode
)
532 int scode
; /* scan code for a function key */
534 /* This procedure traps function keys for debugging purposes. Observers of
535 * function keys are kept in a global array. If a subject (a key) is pressed
536 * the observer is notified of the event. Initialization of the arrays is done
537 * in kb_init, where NONE is set to indicate there is no interest in the key.
538 * Returns FALSE on a key release or if the key is not observable.
543 /* Ignore key releases. If this is a key press, get full key code. */
544 if (scode
& RELEASE_BIT
) return(FALSE
); /* key release */
545 key
= map_key(scode
); /* include modifiers */
547 /* Key pressed, now see if there is an observer for the pressed key.
548 * F1-F12 observers are in fkey_obs array.
549 * SHIFT F1-F12 observers are in sfkey_req array.
550 * CTRL F1-F12 reserved (see kb_read)
551 * ALT F1-F12 reserved (see kb_read)
552 * Other combinations are not in use. Note that Alt+Shift+F1-F12 is yet
553 * defined in <minix/keymap.h>, and thus is easy for future extensions.
555 if (F1
<= key
&& key
<= F12
) { /* F1-F12 */
556 proc_nr
= fkey_obs
[key
- F1
].proc_nr
;
557 fkey_obs
[key
- F1
].events
++ ;
558 } else if (SF1
<= key
&& key
<= SF12
) { /* Shift F2-F12 */
559 proc_nr
= sfkey_obs
[key
- SF1
].proc_nr
;
560 sfkey_obs
[key
- SF1
].events
++;
563 return(FALSE
); /* not observable */
566 /* See if an observer is registered and send it a message. */
567 if (proc_nr
!= NONE
) {
573 /*===========================================================================*
574 * show_key_mappings *
575 *===========================================================================*/
576 static void show_key_mappings()
581 printf("System information. Known function key mappings to request debug dumps:\n");
582 printf("-------------------------------------------------------------------------\n");
583 for (i
=0; i
<12; i
++) {
585 printf(" %sF%d: ", i
+1<10? " ":"", i
+1);
586 if (fkey_obs
[i
].proc_nr
!= NONE
) {
587 printf("%-14u", fkey_obs
[i
].proc_nr
);
589 printf("%-14.14s", "<none>");
592 printf(" %sShift-F%d: ", i
+1<10? " ":"", i
+1);
593 if (sfkey_obs
[i
].proc_nr
!= NONE
) {
594 printf("%-14u", sfkey_obs
[i
].proc_nr
);
596 printf("%-14.14s", "<none>");
601 printf("Press one of the registered function keys to trigger a debug dump.\n");