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 "../drivers.h"
10 #include <sys/ioctl.h>
11 #include <sys/kbdio.h>
13 #include <sys/select.h>
17 #include <minix/callnr.h>
18 #include <minix/com.h>
19 #include <minix/keymap.h>
21 #include "keymaps/us-std.src"
22 #include "../../kernel/const.h"
23 #include "../../kernel/config.h"
24 #include "../../kernel/type.h"
25 #include "../../kernel/proc.h"
28 int aux_irq_hook_id
= -1;
30 /* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
31 #define KEYBD 0x60 /* I/O port for keyboard data */
34 #define KB_COMMAND 0x64 /* I/O port for commands on AT */
35 #define KB_STATUS 0x64 /* I/O port for status on AT */
36 #define KB_ACK 0xFA /* keyboard ack response */
37 #define KB_AUX_BYTE 0x20 /* Auxiliary Device Output Buffer Full */
38 #define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */
39 #define KB_IN_FULL 0x02 /* status bit set when not ready to receive */
40 #define KBC_RD_RAM_CCB 0x20 /* Read controller command byte */
41 #define KBC_WR_RAM_CCB 0x60 /* Write controller command byte */
42 #define KBC_DI_AUX 0xA7 /* Disable Auxiliary Device */
43 #define KBC_EN_AUX 0xA8 /* Enable Auxiliary Device */
44 #define KBC_DI_KBD 0xAD /* Disable Keybard Interface */
45 #define KBC_EN_KBD 0xAE /* Enable Keybard Interface */
46 #define KBC_WRITE_AUX 0xD4 /* Write to Auxiliary Device */
47 #define LED_CODE 0xED /* command to keyboard to set LEDs */
48 #define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */
49 #define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */
50 #define KBIT 0x80 /* bit used to ack characters to keyboard */
52 #define KBC_IN_DELAY 7 /* wait 7 microseconds when polling */
55 #define ESC_SCAN 0x01 /* reboot key when panicking */
56 #define SLASH_SCAN 0x35 /* to recognize numeric slash */
57 #define RSHIFT_SCAN 0x36 /* to distinguish left and right shift */
58 #define HOME_SCAN 0x47 /* first key on the numeric keypad */
59 #define INS_SCAN 0x52 /* INS for use in CTRL-ALT-INS reboot */
60 #define DEL_SCAN 0x53 /* DEL for use in CTRL-ALT-DEL reboot */
62 #define KBD_BUFSZ 1024 /* Buffer size for raw scan codes */
63 #define KBD_OUT_BUFSZ 16 /* Output buffer to sending data to the
67 #define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1)
69 #define CONSOLE 0 /* line number for console */
70 #define KB_IN_BYTES 32 /* size of keyboard input buffer */
71 PRIVATE
char ibuf
[KB_IN_BYTES
]; /* input buffer */
72 PRIVATE
char *ihead
= ibuf
; /* next free spot in input buffer */
73 PRIVATE
char *itail
= ibuf
; /* scan code to return to TTY */
74 PRIVATE
int icount
; /* # codes in buffer */
76 PRIVATE
int esc
; /* escape scan code detected? */
77 PRIVATE
int alt_l
; /* left alt key state */
78 PRIVATE
int alt_r
; /* right alt key state */
79 PRIVATE
int alt
; /* either alt key */
80 PRIVATE
int ctrl_l
; /* left control key state */
81 PRIVATE
int ctrl_r
; /* right control key state */
82 PRIVATE
int ctrl
; /* either control key */
83 PRIVATE
int shift_l
; /* left shift key state */
84 PRIVATE
int shift_r
; /* right shift key state */
85 PRIVATE
int shift
; /* either shift key */
86 PRIVATE
int num_down
; /* num lock key depressed */
87 PRIVATE
int caps_down
; /* caps lock key depressed */
88 PRIVATE
int scroll_down
; /* scroll lock key depressed */
89 PRIVATE
int locks
[NR_CONS
]; /* per console lock keys state */
91 /* Lock key active bits. Chosen to be equal to the keyboard LED bits. */
92 #define SCROLL_LOCK 0x01
94 #define CAPS_LOCK 0x04
96 PRIVATE
char numpad_map
[] =
97 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
99 /* Variables and definition for observed function keys. */
100 typedef struct observer
{ int proc_nr
; int events
; } obs_t
;
101 PRIVATE obs_t fkey_obs
[12]; /* observers for F1-F12 */
102 PRIVATE obs_t sfkey_obs
[12]; /* observers for SHIFT F1-F12 */
119 /* Data that is to be sent to the keyboard. Each byte is ACKed by the
122 PRIVATE
struct kbd_outack
124 unsigned char buf
[KBD_OUT_BUFSZ
];
130 PRIVATE
int kbd_watchdog_set
= 0;
131 PRIVATE
int kbd_alive
= 1;
132 PRIVATE timer_t tmr_kbd_wd
;
134 FORWARD
_PROTOTYPE( void handle_req
, (struct kbd
*kbdp
, message
*m
) );
135 FORWARD
_PROTOTYPE( int handle_status
, (struct kbd
*kbdp
, message
*m
) );
136 FORWARD
_PROTOTYPE( void kbc_cmd0
, (int cmd
) );
137 FORWARD
_PROTOTYPE( void kbc_cmd1
, (int cmd
, int data
) );
138 FORWARD
_PROTOTYPE( int kbc_read
, (void) );
139 FORWARD
_PROTOTYPE( void kbd_send
, (void) );
140 FORWARD
_PROTOTYPE( int kb_ack
, (void) );
141 FORWARD
_PROTOTYPE( int kb_wait
, (void) );
142 FORWARD
_PROTOTYPE( int func_key
, (int scode
) );
143 FORWARD
_PROTOTYPE( int scan_keyboard
, (unsigned char *bp
, int *isauxp
) );
144 FORWARD
_PROTOTYPE( unsigned make_break
, (int scode
) );
145 FORWARD
_PROTOTYPE( void set_leds
, (void) );
146 FORWARD
_PROTOTYPE( void show_key_mappings
, (void) );
147 FORWARD
_PROTOTYPE( int kb_read
, (struct tty
*tp
, int try) );
148 FORWARD
_PROTOTYPE( unsigned map_key
, (int scode
) );
149 FORWARD
_PROTOTYPE( void micro_delay
, (unsigned long usecs
) );
150 FORWARD
_PROTOTYPE( void kbd_watchdog
, (timer_t
*tmrp
) );
152 /*===========================================================================*
154 *===========================================================================*/
155 PUBLIC
void do_kbd(message
*m
)
161 /*===========================================================================*
163 *===========================================================================*/
164 PUBLIC
int kbd_status(message
*m
)
168 r
= handle_status(&kbd
, m
);
171 return handle_status(&kbdaux
, m
);
175 /*===========================================================================*
177 *===========================================================================*/
178 PUBLIC
void do_kbdaux(message
*m
)
180 handle_req(&kbdaux
, m
);
184 /*===========================================================================*
186 *===========================================================================*/
187 PRIVATE
void handle_req(kbdp
, m
)
191 int i
, n
, r
, ops
, watch
;
194 /* Execute the requested device driver function. */
195 r
= EINVAL
; /* just in case */
203 if (kbdp
->nr_open
< 0)
205 printf("TTY(kbd): open count is negative\n");
208 if (kbdp
->nr_open
== 0)
215 /* We handle only request at a time */
219 if (kbdp
->avail
== 0)
221 /* Should record proc */
222 kbdp
->req_size
= m
->COUNT
;
223 kbdp
->req_proc
= m
->IO_ENDPT
;
224 kbdp
->req_addr
= (vir_bytes
)m
->ADDRESS
;
225 kbdp
->incaller
= m
->m_source
;
230 /* Handle read request */
234 if (kbdp
->offset
+ n
> KBD_BUFSZ
)
235 n
= KBD_BUFSZ
-kbdp
->offset
;
237 panic("TTY", "do_kbd(READ): bad n", n
);
238 r
= sys_vircopy(SELF
, D
, (vir_bytes
)&kbdp
->buf
[kbdp
->offset
],
239 m
->IO_ENDPT
, D
, (vir_bytes
) m
->ADDRESS
, n
);
242 kbdp
->offset
= (kbdp
->offset
+n
) % KBD_BUFSZ
;
252 printf("write to keyboard not implemented\n");
257 /* Assume that output to AUX only happens during
258 * initialization and we can afford to lose input. This should
259 * be fixed at a later time.
261 for (i
= 0; i
<m
->COUNT
; i
++)
263 r
= sys_vircopy(m
->IO_ENDPT
, D
, (vir_bytes
) m
->ADDRESS
+i
,
264 SELF
, D
, (vir_bytes
)&c
, 1);
267 kbc_cmd1(KBC_WRITE_AUX
, c
);
277 ops
= m
->IO_ENDPT
& (SEL_RD
|SEL_WR
|SEL_ERR
);
278 watch
= (m
->IO_ENDPT
& SEL_NOTIFY
) ? 1 : 0;
281 if (kbdp
->avail
&& (ops
& SEL_RD
))
289 kbdp
->select_ops
|= ops
;
290 kbdp
->select_proc
= m
->m_source
;
294 if (kbdp
== &kbd
&& m
->TTY_REQUEST
== KIOCSLEDS
)
299 r
= sys_vircopy(m
->IO_ENDPT
, D
, (vir_bytes
) m
->ADDRESS
,
300 SELF
, D
, (vir_bytes
)&leds
, sizeof(leds
));
304 if (leds
.kl_bits
& KBD_LEDS_NUM
) b
|= NUM_LOCK
;
305 if (leds
.kl_bits
& KBD_LEDS_CAPS
) b
|= CAPS_LOCK
;
306 if (leds
.kl_bits
& KBD_LEDS_SCROLL
) b
|= SCROLL_LOCK
;
307 if (kbdout
.avail
== 0)
309 if (kbdout
.offset
+ kbdout
.avail
+ 2 > KBD_OUT_BUFSZ
)
311 /* Output buffer is full. Ignore this command.
314 kbdout
.expect_ack
= 0;
318 kbdout
.buf
[kbdout
.offset
+kbdout
.avail
]=
320 kbdout
.buf
[kbdout
.offset
+kbdout
.avail
+1]= b
;
323 if (!kbdout
.expect_ack
)
328 if (kbdp
== &kbd
&& m
->TTY_REQUEST
== KIOCBELL
)
333 r
= sys_vircopy(m
->IO_ENDPT
, D
, (vir_bytes
) m
->ADDRESS
,
334 SELF
, D
, (vir_bytes
)&bell
, sizeof(bell
));
338 ticks
= bell
.kb_duration
.tv_usec
* HZ
/ 1000000;
339 ticks
+= bell
.kb_duration
.tv_sec
* HZ
;
342 beep_x(bell
.kb_pitch
, ticks
);
351 printf("Warning, TTY(kbd) got unexpected request %d from %d\n",
352 m
->m_type
, m
->m_source
);
355 tty_reply(TASK_REPLY
, m
->m_source
, m
->IO_ENDPT
, r
);
359 /*===========================================================================*
361 *===========================================================================*/
362 PRIVATE
int handle_status(kbdp
, m
)
368 if (kbdp
->avail
&& kbdp
->req_size
&& m
->m_source
== kbdp
->incaller
)
370 /* Handle read request */
372 if (n
> kbdp
->req_size
)
374 if (kbdp
->offset
+ n
> KBD_BUFSZ
)
375 n
= KBD_BUFSZ
-kbdp
->offset
;
377 panic("TTY", "kbd_status: bad n", n
);
379 r
= sys_vircopy(SELF
, D
, (vir_bytes
)&kbdp
->buf
[kbdp
->offset
],
380 kbdp
->req_proc
, D
, kbdp
->req_addr
, n
);
383 kbdp
->offset
= (kbdp
->offset
+n
) % KBD_BUFSZ
;
388 m
->m_type
= DEV_REVIVE
;
389 m
->REP_ENDPT
= kbdp
->req_proc
;
393 if (kbdp
->avail
&& (kbdp
->select_ops
& SEL_RD
) &&
394 m
->m_source
== kbdp
->select_proc
)
396 m
->m_type
= DEV_IO_READY
;
397 m
->DEV_MINOR
= kbdp
->minor
;
398 m
->DEV_SEL_OPS
= SEL_RD
;
400 kbdp
->select_ops
&= ~SEL_RD
;
408 /*===========================================================================*
410 *===========================================================================*/
411 /* Map a scan code to an ASCII code ignoring modifiers. */
412 #define map_key0(scode) \
413 ((unsigned) keymap[(scode) * MAP_COLS])
415 /*===========================================================================*
417 *===========================================================================*/
418 PRIVATE
unsigned map_key(scode
)
421 /* Map a scan code to an ASCII code. */
423 int caps
, column
, lk
;
426 if (scode
== SLASH_SCAN
&& esc
) return '/'; /* don't map numeric slash */
428 keyrow
= &keymap
[scode
* MAP_COLS
];
431 lk
= locks
[ccurrent
];
432 if ((lk
& NUM_LOCK
) && HOME_SCAN
<= scode
&& scode
<= DEL_SCAN
) caps
= !caps
;
433 if ((lk
& CAPS_LOCK
) && (keyrow
[0] & HASCAPS
)) caps
= !caps
;
437 if (ctrl
|| alt_r
) column
= 3; /* Ctrl + Alt == AltGr */
438 if (caps
) column
= 4;
441 if (caps
) column
= 1;
442 if (ctrl
) column
= 5;
444 return keyrow
[column
] & ~HASCAPS
;
447 /*===========================================================================*
449 *===========================================================================*/
450 PUBLIC
void kbd_interrupt(m_ptr
)
453 /* A keyboard interrupt has occurred. Process it. */
457 static timer_t timer
; /* timer must be static! */
459 /* Fetch the character from the keyboard hardware and acknowledge it. */
460 if (!scan_keyboard(&scode
, &isaux
))
465 else if (kbd
.nr_open
&& !panicing
)
472 /* raw scan codes or aux data */
473 if (kbdp
->avail
>= KBD_BUFSZ
)
475 printf("kbd_interrupt: %s buffer is full\n",
476 isaux
? "kbdaux" : "keyboard");
477 return; /* Buffer is full */
479 o
= (kbdp
->offset
+ kbdp
->avail
) % KBD_BUFSZ
;
483 notify(kbdp
->incaller
);
484 if (kbdp
->select_ops
& SEL_RD
)
485 notify(kbdp
->select_proc
);
489 /* Store the scancode in memory so the task can get at it later. */
490 if (icount
< KB_IN_BYTES
) {
492 if (ihead
== ibuf
+ KB_IN_BYTES
) ihead
= ibuf
;
494 tty_table
[ccurrent
].tty_events
= 1;
495 if (tty_table
[ccurrent
].tty_select_ops
& SEL_RD
) {
496 select_retry(&tty_table
[ccurrent
]);
501 /*===========================================================================*
503 *===========================================================================*/
504 PRIVATE
int kb_read(tp
, try)
508 /* Process characters from the circular keyboard buffer. */
513 tp
= &tty_table
[ccurrent
]; /* always use the current console */
516 if (icount
> 0) return 1;
521 scode
= *itail
++; /* take one key scan code */
522 if (itail
== ibuf
+ KB_IN_BYTES
) itail
= ibuf
;
525 /* Function keys are being used for debug dumps. */
526 if (func_key(scode
)) continue;
528 /* Perform make/break processing. */
529 ch
= make_break(scode
);
532 /* A normal character. */
534 (void) in_process(tp
, buf
, 1);
536 if (HOME
<= ch
&& ch
<= INSRT
) {
537 /* An ASCII escape sequence generated by the numeric pad. */
540 buf
[2] = numpad_map
[ch
- HOME
];
541 (void) in_process(tp
, buf
, 3);
544 /* Choose lower numbered console as current console. */
545 select_console(ccurrent
- 1);
549 /* Choose higher numbered console as current console. */
550 select_console(ccurrent
+ 1);
553 if (AF1
<= ch
&& ch
<= AF12
) {
554 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
555 select_console(ch
- AF1
);
558 if (CF1
<= ch
&& ch
<= CF12
) {
560 case CF1
: show_key_mappings(); break;
561 case CF3
: toggle_scroll(); break; /* hardware <-> software */
562 case CF7
: sigchar(&tty_table
[CONSOLE
], SIGQUIT
); break;
563 case CF8
: sigchar(&tty_table
[CONSOLE
], SIGINT
); break;
564 case CF9
: sigchar(&tty_table
[CONSOLE
], SIGKILL
); break;
572 /*===========================================================================*
574 *===========================================================================*/
575 PRIVATE
void kbd_send()
583 if (kbdout
.expect_ack
)
586 sys_inb(KB_STATUS
, &sb
);
587 if (sb
& (KB_OUT_FULL
|KB_IN_FULL
))
589 printf("not sending 1: sb = 0x%x\n", sb
);
592 micro_delay(KBC_IN_DELAY
);
593 sys_inb(KB_STATUS
, &sb
);
594 if (sb
& (KB_OUT_FULL
|KB_IN_FULL
))
596 printf("not sending 2: sb = 0x%x\n", sb
);
600 /* Okay, buffer is really empty */
602 printf("sending byte 0x%x to keyboard\n", kbdout
.buf
[kbdout
.offset
]);
604 sys_outb(KEYBD
, kbdout
.buf
[kbdout
.offset
]);
607 kbdout
.expect_ack
= 1;
610 if (kbd_watchdog_set
)
612 /* Add a timer to the timers list. Possibly reschedule the
615 if ((r
= getuptime(&now
)) != OK
)
616 panic("TTY","Keyboard couldn't get clock's uptime.", r
);
617 tmrs_settimer(&tty_timers
, &tmr_kbd_wd
, now
+HZ
, kbd_watchdog
,
619 if (tty_timers
->tmr_exp_time
!= tty_next_timeout
) {
620 tty_next_timeout
= tty_timers
->tmr_exp_time
;
621 if ((r
= sys_setalarm(tty_next_timeout
, 1)) != OK
)
622 panic("TTY","Keyboard couldn't set alarm.", r
);
628 /*===========================================================================*
630 *===========================================================================*/
631 PRIVATE
unsigned make_break(scode
)
632 int scode
; /* scan code of key just struck or released */
634 /* This routine can handle keyboards that interrupt only on key depression,
635 * as well as keyboards that interrupt on key depression and key release.
636 * For efficiency, the interrupt routine filters out most key releases.
638 int ch
, make
, escape
;
639 static int CAD_count
= 0;
641 /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would
642 * be better done in keyboard() in case TTY is hung, except control and
643 * alt are set in the high level code.
645 if (ctrl
&& alt
&& (scode
== DEL_SCAN
|| scode
== INS_SCAN
))
647 if (++CAD_count
== 3) {
651 sys_kill(INIT_PROC_NR
, SIGABRT
);
655 /* High-order bit set on key release. */
656 make
= (scode
& KEY_RELEASE
) == 0; /* true if pressed */
658 ch
= map_key(scode
&= ASCII_MASK
); /* map to ASCII */
660 escape
= esc
; /* Key is escaped? (true if added since the XT) */
664 case CTRL
: /* Left or right control key */
665 *(escape
? &ctrl_r
: &ctrl_l
) = make
;
666 ctrl
= ctrl_l
| ctrl_r
;
668 case SHIFT
: /* Left or right shift key */
669 *(scode
== RSHIFT_SCAN
? &shift_r
: &shift_l
) = make
;
670 shift
= shift_l
| shift_r
;
672 case ALT
: /* Left or right alt key */
673 *(escape
? &alt_r
: &alt_l
) = make
;
676 case CALOCK
: /* Caps lock - toggle on 0 -> 1 transition */
677 if (caps_down
< make
) {
678 locks
[ccurrent
] ^= CAPS_LOCK
;
683 case NLOCK
: /* Num lock */
684 if (num_down
< make
) {
685 locks
[ccurrent
] ^= NUM_LOCK
;
690 case SLOCK
: /* Scroll lock */
691 if (scroll_down
< make
) {
692 locks
[ccurrent
] ^= SCROLL_LOCK
;
697 case EXTKEY
: /* Escape keycode */
698 esc
= 1; /* Next key is escaped */
700 default: /* A normal key */
701 if (make
) return(ch
);
704 /* Key release, or a shift type key. */
708 /*===========================================================================*
710 *===========================================================================*/
711 PRIVATE
void set_leds()
713 /* Set the LEDs on the caps, num, and scroll lock keys */
715 if (! machine
.pc_at
) return; /* PC/XT doesn't have LEDs */
717 kb_wait(); /* wait for buffer empty */
718 if ((s
=sys_outb(KEYBD
, LED_CODE
)) != OK
)
719 printf("Warning, sys_outb couldn't prepare for LED values: %d\n", s
);
720 /* prepare keyboard to accept LED values */
721 kb_ack(); /* wait for ack response */
723 kb_wait(); /* wait for buffer empty */
724 if ((s
=sys_outb(KEYBD
, locks
[ccurrent
])) != OK
)
725 printf("Warning, sys_outb couldn't give LED values: %d\n", s
);
726 /* give keyboard LED values */
727 kb_ack(); /* wait for ack response */
730 /*===========================================================================*
732 *===========================================================================*/
733 PRIVATE
void kbc_cmd0(cmd
)
737 sys_outb(KB_COMMAND
, cmd
);
740 /*===========================================================================*
742 *===========================================================================*/
743 PRIVATE
void kbc_cmd1(cmd
, data
)
748 sys_outb(KB_COMMAND
, cmd
);
750 sys_outb(KEYBD
, data
);
754 /*===========================================================================*
756 *===========================================================================*/
757 PRIVATE
int kbc_read()
760 unsigned long byte
, st
;
762 struct micro_state ms
;
766 printf("in kbc_read\n");
769 /* Wait at most 1 second for a byte from the keyboard or
770 * the kbd controller, return -1 on a timeout.
772 for (i
= 0; i
<1000; i
++)
778 sys_inb(KB_STATUS
, &st
);
779 if (st
& KB_OUT_FULL
)
781 micro_delay(KBC_IN_DELAY
);
782 sys_inb(KEYBD
, &byte
);
783 if (st
& KB_AUX_BYTE
)
787 "keyboard`kbc_read: ignoring byte (0x%x) from aux device.\n",
793 printf("keyboard`kbc_read: returning byte 0x%x\n",
800 while (micro_elapsed(&ms
) < 1000000);
802 panic("TTY", "kbc_read failed to complete", NO_NUM
);
807 /*===========================================================================*
809 *===========================================================================*/
810 PRIVATE
int kb_wait()
812 /* Wait until the controller is ready; return zero if this times out. */
815 unsigned long status
, temp
;
819 retries
= MAX_KB_BUSY_RETRIES
+ 1; /* wait until not busy */
821 s
= sys_inb(KB_STATUS
, &status
);
822 if (status
& KB_OUT_FULL
) {
823 if (scan_keyboard(&byte
, &isaux
))
826 printf("ignoring %sbyte in kb_wait\n", isaux
? "AUX " : "");
830 if (! (status
& (KB_IN_FULL
|KB_OUT_FULL
)) )
831 break; /* wait until ready */
832 } while (--retries
!= 0); /* continue unless timeout */
833 return(retries
); /* zero on timeout, positive if ready */
836 /*===========================================================================*
838 *===========================================================================*/
841 /* Wait until kbd acknowledges last command; return zero if this times out. */
847 retries
= MAX_KB_ACK_RETRIES
+ 1;
849 s
= sys_inb(KEYBD
, &u8val
);
851 break; /* wait for ack */
852 } while(--retries
!= 0); /* continue unless timeout */
854 return(retries
); /* nonzero if ack received */
857 /*===========================================================================*
859 *===========================================================================*/
860 PUBLIC
void kb_init(tp
)
863 /* Initialize the keyboard driver. */
865 tp
->tty_devread
= kb_read
; /* input function */
868 /*===========================================================================*
870 *===========================================================================*/
871 PUBLIC
void kb_init_once(void)
876 set_leds(); /* turn off numlock led */
877 scan_keyboard(NULL
, NULL
); /* discard leftover keystroke */
879 /* Clear the function key observers array. Also see func_key(). */
880 for (i
=0; i
<12; i
++) {
881 fkey_obs
[i
].proc_nr
= NONE
; /* F1-F12 observers */
882 fkey_obs
[i
].events
= 0; /* F1-F12 observers */
883 sfkey_obs
[i
].proc_nr
= NONE
; /* Shift F1-F12 observers */
884 sfkey_obs
[i
].events
= 0; /* Shift F1-F12 observers */
887 kbd
.minor
= KBD_MINOR
;
888 kbdaux
.minor
= KBDAUX_MINOR
;
890 /* Set interrupt handler and enable keyboard IRQ. */
891 irq_hook_id
= KEYBOARD_IRQ
; /* id to be returned on interrupt */
892 if ((i
=sys_irqsetpolicy(KEYBOARD_IRQ
, IRQ_REENABLE
, &irq_hook_id
)) != OK
)
893 panic("TTY", "Couldn't set keyboard IRQ policy", i
);
894 if ((i
=sys_irqenable(&irq_hook_id
)) != OK
)
895 panic("TTY", "Couldn't enable keyboard IRQs", i
);
896 kbd_irq_set
|= (1 << KEYBOARD_IRQ
);
898 /* Set AUX interrupt handler and enable AUX IRQ. */
899 aux_irq_hook_id
= KBD_AUX_IRQ
; /* id to be returned on interrupt */
900 if ((i
=sys_irqsetpolicy(KBD_AUX_IRQ
, IRQ_REENABLE
,
901 &aux_irq_hook_id
)) != OK
)
902 panic("TTY", "Couldn't set AUX IRQ policy", i
);
903 if ((i
=sys_irqenable(&aux_irq_hook_id
)) != OK
)
904 panic("TTY", "Couldn't enable AUX IRQs", i
);
905 kbd_irq_set
|= (1 << KBD_AUX_IRQ
);
907 /* Disable the keyboard and aux */
908 kbc_cmd0(KBC_DI_KBD
);
909 kbc_cmd0(KBC_DI_AUX
);
911 /* Get the current configuration byte */
912 kbc_cmd0(KBC_RD_RAM_CCB
);
915 /* Enable both interrupts. */
916 kbc_cmd1(KBC_WR_RAM_CCB
, ccb
| 3);
918 /* Re-enable the keyboard device. */
919 kbc_cmd0(KBC_EN_KBD
);
921 /* Enable the aux device. */
922 kbc_cmd0(KBC_EN_AUX
);
925 /*===========================================================================*
927 *===========================================================================*/
928 PUBLIC
int kbd_loadmap(m
)
931 /* Load a new keymap. */
933 result
= sys_vircopy(m
->IO_ENDPT
, D
, (vir_bytes
) m
->ADDRESS
,
934 SELF
, D
, (vir_bytes
) keymap
,
935 (vir_bytes
) sizeof(keymap
));
939 /*===========================================================================*
941 *===========================================================================*/
942 PUBLIC
void do_fkey_ctl(m_ptr
)
943 message
*m_ptr
; /* pointer to the request message */
945 /* This procedure allows processes to register a function key to receive
946 * notifications if it is pressed. At most one binding per key can exist.
951 switch (m_ptr
->FKEY_REQUEST
) { /* see what we must do */
952 case FKEY_MAP
: /* request for new mapping */
953 result
= OK
; /* assume everything will be ok*/
954 for (i
=0; i
< 12; i
++) { /* check F1-F12 keys */
955 if (bit_isset(m_ptr
->FKEY_FKEYS
, i
+1) ) {
957 /* Currently, we don't check if the slot is in use, so that IS
958 * can recover after a crash by overtaking its existing mappings.
959 * In future, a better solution will be implemented.
961 if (fkey_obs
[i
].proc_nr
== NONE
) {
963 fkey_obs
[i
].proc_nr
= m_ptr
->m_source
;
964 fkey_obs
[i
].events
= 0;
965 bit_unset(m_ptr
->FKEY_FKEYS
, i
+1);
968 printf("WARNING, fkey_map failed F%d\n", i
+1);
969 result
= EBUSY
; /* report failure, but try rest */
974 for (i
=0; i
< 12; i
++) { /* check Shift+F1-F12 keys */
975 if (bit_isset(m_ptr
->FKEY_SFKEYS
, i
+1) ) {
977 if (sfkey_obs
[i
].proc_nr
== NONE
) {
979 sfkey_obs
[i
].proc_nr
= m_ptr
->m_source
;
980 sfkey_obs
[i
].events
= 0;
981 bit_unset(m_ptr
->FKEY_SFKEYS
, i
+1);
984 printf("WARNING, fkey_map failed Shift F%d\n", i
+1);
985 result
= EBUSY
; /* report failure but try rest */
992 result
= OK
; /* assume everything will be ok*/
993 for (i
=0; i
< 12; i
++) { /* check F1-F12 keys */
994 if (bit_isset(m_ptr
->FKEY_FKEYS
, i
+1) ) {
995 if (fkey_obs
[i
].proc_nr
== m_ptr
->m_source
) {
996 fkey_obs
[i
].proc_nr
= NONE
;
997 fkey_obs
[i
].events
= 0;
998 bit_unset(m_ptr
->FKEY_FKEYS
, i
+1);
1000 result
= EPERM
; /* report failure, but try rest */
1004 for (i
=0; i
< 12; i
++) { /* check Shift+F1-F12 keys */
1005 if (bit_isset(m_ptr
->FKEY_SFKEYS
, i
+1) ) {
1006 if (sfkey_obs
[i
].proc_nr
== m_ptr
->m_source
) {
1007 sfkey_obs
[i
].proc_nr
= NONE
;
1008 sfkey_obs
[i
].events
= 0;
1009 bit_unset(m_ptr
->FKEY_SFKEYS
, i
+1);
1011 result
= EPERM
; /* report failure, but try rest */
1017 m_ptr
->FKEY_FKEYS
= m_ptr
->FKEY_SFKEYS
= 0;
1018 for (i
=0; i
< 12; i
++) { /* check (Shift+) F1-F12 keys */
1019 if (fkey_obs
[i
].proc_nr
== m_ptr
->m_source
) {
1020 if (fkey_obs
[i
].events
) {
1021 bit_set(m_ptr
->FKEY_FKEYS
, i
+1);
1022 fkey_obs
[i
].events
= 0;
1025 if (sfkey_obs
[i
].proc_nr
== m_ptr
->m_source
) {
1026 if (sfkey_obs
[i
].events
) {
1027 bit_set(m_ptr
->FKEY_SFKEYS
, i
+1);
1028 sfkey_obs
[i
].events
= 0;
1034 result
= EINVAL
; /* key cannot be observed */
1037 /* Almost done, return result to caller. */
1038 m_ptr
->m_type
= result
;
1039 send(m_ptr
->m_source
, m_ptr
);
1042 /*===========================================================================*
1044 *===========================================================================*/
1045 PRIVATE
int func_key(scode
)
1046 int scode
; /* scan code for a function key */
1048 /* This procedure traps function keys for debugging purposes. Observers of
1049 * function keys are kept in a global array. If a subject (a key) is pressed
1050 * the observer is notified of the event. Initialization of the arrays is done
1051 * in kb_init, where NONE is set to indicate there is no interest in the key.
1052 * Returns FALSE on a key release or if the key is not observable.
1059 /* Ignore key releases. If this is a key press, get full key code. */
1060 if (scode
& KEY_RELEASE
) return(FALSE
); /* key release */
1061 key
= map_key(scode
); /* include modifiers */
1063 /* Key pressed, now see if there is an observer for the pressed key.
1064 * F1-F12 observers are in fkey_obs array.
1065 * SHIFT F1-F12 observers are in sfkey_req array.
1066 * CTRL F1-F12 reserved (see kb_read)
1067 * ALT F1-F12 reserved (see kb_read)
1068 * Other combinations are not in use. Note that Alt+Shift+F1-F12 is yet
1069 * defined in <minix/keymap.h>, and thus is easy for future extensions.
1071 if (F1
<= key
&& key
<= F12
) { /* F1-F12 */
1072 proc_nr
= fkey_obs
[key
- F1
].proc_nr
;
1073 fkey_obs
[key
- F1
].events
++ ;
1074 } else if (SF1
<= key
&& key
<= SF12
) { /* Shift F2-F12 */
1075 proc_nr
= sfkey_obs
[key
- SF1
].proc_nr
;
1076 sfkey_obs
[key
- SF1
].events
++;
1079 return(FALSE
); /* not observable */
1082 /* See if an observer is registered and send it a message. */
1083 if (proc_nr
!= NONE
) {
1084 m
.NOTIFY_TYPE
= FKEY_PRESSED
;
1090 /*===========================================================================*
1091 * show_key_mappings *
1092 *===========================================================================*/
1093 PRIVATE
void show_key_mappings()
1099 printf("System information. Known function key mappings to request debug dumps:\n");
1100 printf("-------------------------------------------------------------------------\n");
1101 for (i
=0; i
<12; i
++) {
1103 printf(" %sF%d: ", i
+1<10? " ":"", i
+1);
1104 if (fkey_obs
[i
].proc_nr
!= NONE
) {
1105 if ((s
=sys_getproc(&proc
, fkey_obs
[i
].proc_nr
))!=OK
)
1106 printf("sys_getproc: %d\n", s
);
1107 printf("%-14.14s", proc
.p_name
);
1109 printf("%-14.14s", "<none>");
1112 printf(" %sShift-F%d: ", i
+1<10? " ":"", i
+1);
1113 if (sfkey_obs
[i
].proc_nr
!= NONE
) {
1114 if ((s
=sys_getproc(&proc
, sfkey_obs
[i
].proc_nr
))!=OK
)
1115 printf("sys_getproc: %d\n", s
);
1116 printf("%-14.14s", proc
.p_name
);
1118 printf("%-14.14s", "<none>");
1123 printf("Press one of the registered function keys to trigger a debug dump.\n");
1127 /*===========================================================================*
1129 *===========================================================================*/
1130 PRIVATE
int scan_keyboard(bp
, isauxp
)
1134 #if 0 /* Is this old XT code? It doesn't match the PS/2 hardware */
1135 /* Fetch the character from the keyboard hardware and acknowledge it. */
1136 pvb_pair_t byte_in
[2], byte_out
[2];
1138 byte_in
[0].port
= KEYBD
; /* get the scan code for the key struck */
1139 byte_in
[1].port
= PORT_B
; /* strobe the keyboard to ack the char */
1140 sys_vinb(byte_in
, 2); /* request actual input */
1142 pv_set(byte_out
[0], PORT_B
, byte_in
[1].value
| KBIT
); /* strobe bit high */
1143 pv_set(byte_out
[1], PORT_B
, byte_in
[1].value
); /* then strobe low */
1144 sys_voutb(byte_out
, 2); /* request actual output */
1146 return(byte_in
[0].value
); /* return scan code */
1148 unsigned long b
, sb
;
1150 sys_inb(KB_STATUS
, &sb
);
1151 if (!(sb
& KB_OUT_FULL
))
1153 if (kbdout
.avail
&& !kbdout
.expect_ack
)
1159 printf("got byte 0x%x from %s\n", b
, (sb
& KB_AUX_BYTE
) ? "AUX" : "keyboard");
1161 if (!(sb
& KB_AUX_BYTE
) && b
== KB_ACK
&& kbdout
.expect_ack
)
1164 printf("got ACK from keyboard\n");
1166 kbdout
.expect_ack
= 0;
1167 micro_delay(KBC_IN_DELAY
);
1174 *isauxp
= !!(sb
& KB_AUX_BYTE
);
1175 if (kbdout
.avail
&& !kbdout
.expect_ack
)
1177 micro_delay(KBC_IN_DELAY
);
1184 static void micro_delay(unsigned long usecs
)
1186 tickdelay(MICROS_TO_TICKS(usecs
));
1189 /*===========================================================================*
1191 *===========================================================================*/
1192 PRIVATE
void kbd_watchdog(tmrp
)
1198 kbd_watchdog_set
= 0;
1200 return; /* Watchdog is no longer needed */
1203 printf("kbd_watchdog: should reset keyboard\n");
1207 if ((r
= getuptime(&now
)) != OK
)
1208 panic("TTY","Keyboard couldn't get clock's uptime.", r
);
1209 tmrs_settimer(&tty_timers
, &tmr_kbd_wd
, now
+HZ
, kbd_watchdog
,
1211 if (tty_timers
->tmr_exp_time
!= tty_next_timeout
) {
1212 tty_next_timeout
= tty_timers
->tmr_exp_time
;
1213 if ((r
= sys_setalarm(tty_next_timeout
, 1)) != OK
)
1214 panic("TTY","Keyboard couldn't set alarm.", r
);
1216 kbd_watchdog_set
= 1;