source: trunk/minix/drivers/tty/keyboard.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 34.0 KB
Line 
1/* Keyboard driver for PC's and AT's.
2 *
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 */
8
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 <minix/callnr.h>
18#include <minix/com.h>
19#include <minix/keymap.h>
20#include "tty.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"
26
27int irq_hook_id = -1;
28int aux_irq_hook_id = -1;
29
30/* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
31#define KEYBD 0x60 /* I/O port for keyboard data */
32
33/* AT keyboard. */
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 */
51
52#define KBC_IN_DELAY 7 /* wait 7 microseconds when polling */
53
54/* Miscellaneous. */
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 */
61
62#define KBD_BUFSZ 1024 /* Buffer size for raw scan codes */
63#define KBD_OUT_BUFSZ 16 /* Output buffer to sending data to the
64 * keyboard.
65 */
66
67#define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1)
68
69#define CONSOLE 0 /* line number for console */
70#define KB_IN_BYTES 32 /* size of keyboard input buffer */
71PRIVATE char ibuf[KB_IN_BYTES]; /* input buffer */
72PRIVATE char *ihead = ibuf; /* next free spot in input buffer */
73PRIVATE char *itail = ibuf; /* scan code to return to TTY */
74PRIVATE int icount; /* # codes in buffer */
75
76PRIVATE int esc; /* escape scan code detected? */
77PRIVATE int alt_l; /* left alt key state */
78PRIVATE int alt_r; /* right alt key state */
79PRIVATE int alt; /* either alt key */
80PRIVATE int ctrl_l; /* left control key state */
81PRIVATE int ctrl_r; /* right control key state */
82PRIVATE int ctrl; /* either control key */
83PRIVATE int shift_l; /* left shift key state */
84PRIVATE int shift_r; /* right shift key state */
85PRIVATE int shift; /* either shift key */
86PRIVATE int num_down; /* num lock key depressed */
87PRIVATE int caps_down; /* caps lock key depressed */
88PRIVATE int scroll_down; /* scroll lock key depressed */
89PRIVATE int locks[NR_CONS]; /* per console lock keys state */
90
91/* Lock key active bits. Chosen to be equal to the keyboard LED bits. */
92#define SCROLL_LOCK 0x01
93#define NUM_LOCK 0x02
94#define CAPS_LOCK 0x04
95
96PRIVATE char numpad_map[] =
97 {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
98
99/* Variables and definition for observed function keys. */
100typedef struct observer { int proc_nr; int events; } obs_t;
101PRIVATE obs_t fkey_obs[12]; /* observers for F1-F12 */
102PRIVATE obs_t sfkey_obs[12]; /* observers for SHIFT F1-F12 */
103
104PRIVATE struct kbd
105{
106 int minor;
107 int nr_open;
108 char buf[KBD_BUFSZ];
109 int offset;
110 int avail;
111 int req_size;
112 int req_proc;
113 vir_bytes req_addr;
114 int incaller;
115 int select_ops;
116 int select_proc;
117} kbd, kbdaux;
118
119/* Data that is to be sent to the keyboard. Each byte is ACKed by the
120 * keyboard.
121 */
122PRIVATE struct kbd_outack
123{
124 unsigned char buf[KBD_OUT_BUFSZ];
125 int offset;
126 int avail;
127 int expect_ack;
128} kbdout;
129
130PRIVATE int kbd_watchdog_set= 0;
131PRIVATE int kbd_alive= 1;
132PRIVATE timer_t tmr_kbd_wd;
133
134FORWARD _PROTOTYPE( void handle_req, (struct kbd *kbdp, message *m) );
135FORWARD _PROTOTYPE( int handle_status, (struct kbd *kbdp, message *m) );
136FORWARD _PROTOTYPE( void kbc_cmd0, (int cmd) );
137FORWARD _PROTOTYPE( void kbc_cmd1, (int cmd, int data) );
138FORWARD _PROTOTYPE( int kbc_read, (void) );
139FORWARD _PROTOTYPE( void kbd_send, (void) );
140FORWARD _PROTOTYPE( int kb_ack, (void) );
141FORWARD _PROTOTYPE( int kb_wait, (void) );
142FORWARD _PROTOTYPE( int func_key, (int scode) );
143FORWARD _PROTOTYPE( int scan_keyboard, (unsigned char *bp, int *isauxp) );
144FORWARD _PROTOTYPE( unsigned make_break, (int scode) );
145FORWARD _PROTOTYPE( void set_leds, (void) );
146FORWARD _PROTOTYPE( void show_key_mappings, (void) );
147FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try) );
148FORWARD _PROTOTYPE( unsigned map_key, (int scode) );
149FORWARD _PROTOTYPE( void micro_delay, (unsigned long usecs) );
150FORWARD _PROTOTYPE( void kbd_watchdog, (timer_t *tmrp) );
151
152/*===========================================================================*
153 * do_kbd *
154 *===========================================================================*/
155PUBLIC void do_kbd(message *m)
156{
157 handle_req(&kbd, m);
158}
159
160
161/*===========================================================================*
162 * kbd_status *
163 *===========================================================================*/
164PUBLIC int kbd_status(message *m)
165{
166 int r;
167
168 r= handle_status(&kbd, m);
169 if (r)
170 return r;
171 return handle_status(&kbdaux, m);
172}
173
174
175/*===========================================================================*
176 * do_kbdaux *
177 *===========================================================================*/
178PUBLIC void do_kbdaux(message *m)
179{
180 handle_req(&kbdaux, m);
181}
182
183
184/*===========================================================================*
185 * handle_req *
186 *===========================================================================*/
187PRIVATE void handle_req(kbdp, m)
188struct kbd *kbdp;
189message *m;
190{
191 int i, n, r, ops, watch;
192 unsigned char c;
193
194 /* Execute the requested device driver function. */
195 r= EINVAL; /* just in case */
196 switch (m->m_type) {
197 case DEV_OPEN:
198 kbdp->nr_open++;
199 r= OK;
200 break;
201 case DEV_CLOSE:
202 kbdp->nr_open--;
203 if (kbdp->nr_open < 0)
204 {
205 printf("TTY(kbd): open count is negative\n");
206 kbdp->nr_open= 0;
207 }
208 if (kbdp->nr_open == 0)
209 kbdp->avail= 0;
210 r= OK;
211 break;
212 case DEV_READ:
213 if (kbdp->req_size)
214 {
215 /* We handle only request at a time */
216 r= EIO;
217 break;
218 }
219 if (kbdp->avail == 0)
220 {
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;
226 r= SUSPEND;
227 break;
228 }
229
230 /* Handle read request */
231 n= kbdp->avail;
232 if (n > m->COUNT)
233 n= m->COUNT;
234 if (kbdp->offset + n > KBD_BUFSZ)
235 n= KBD_BUFSZ-kbdp->offset;
236 if (n <= 0)
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);
240 if (r == OK)
241 {
242 kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
243 kbdp->avail -= n;
244 r= n;
245 }
246
247 break;
248
249 case DEV_WRITE:
250 if (kbdp != &kbdaux)
251 {
252 printf("write to keyboard not implemented\n");
253 r= EINVAL;
254 break;
255 }
256
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.
260 */
261 for (i= 0; i<m->COUNT; i++)
262 {
263 r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS+i,
264 SELF, D, (vir_bytes)&c, 1);
265 if (r != OK)
266 break;
267 kbc_cmd1(KBC_WRITE_AUX, c);
268 }
269 r= i;
270 break;
271
272 case CANCEL:
273 kbdp->req_size= 0;
274 r= OK;
275 break;
276 case DEV_SELECT:
277 ops = m->IO_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
278 watch = (m->IO_ENDPT & SEL_NOTIFY) ? 1 : 0;
279
280 r= 0;
281 if (kbdp->avail && (ops & SEL_RD))
282 {
283 r |= SEL_RD;
284 break;
285 }
286
287 if (ops && watch)
288 {
289 kbdp->select_ops |= ops;
290 kbdp->select_proc= m->m_source;
291 }
292 break;
293 case DEV_IOCTL:
294 if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS)
295 {
296 kio_leds_t leds;
297 unsigned char b;
298
299 r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
300 SELF, D, (vir_bytes)&leds, sizeof(leds));
301 if (r != OK)
302 break;
303 b= 0;
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)
308 kbdout.offset= 0;
309 if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ)
310 {
311 /* Output buffer is full. Ignore this command.
312 * Reset ACK flag.
313 */
314 kbdout.expect_ack= 0;
315 }
316 else
317 {
318 kbdout.buf[kbdout.offset+kbdout.avail]=
319 LED_CODE;
320 kbdout.buf[kbdout.offset+kbdout.avail+1]= b;
321 kbdout.avail += 2;
322 }
323 if (!kbdout.expect_ack)
324 kbd_send();
325 r= OK;
326 break;
327 }
328 if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL)
329 {
330 kio_bell_t bell;
331 clock_t ticks;
332
333 r= sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
334 SELF, D, (vir_bytes)&bell, sizeof(bell));
335 if (r != OK)
336 break;
337
338 ticks= bell.kb_duration.tv_usec * HZ / 1000000;
339 ticks += bell.kb_duration.tv_sec * HZ;
340 if (!ticks)
341 ticks++;
342 beep_x(bell.kb_pitch, ticks);
343
344 r= OK;
345 break;
346 }
347 r= ENOTTY;
348 break;
349
350 default:
351 printf("Warning, TTY(kbd) got unexpected request %d from %d\n",
352 m->m_type, m->m_source);
353 r= EINVAL;
354 }
355 tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
356}
357
358
359/*===========================================================================*
360 * handle_status *
361 *===========================================================================*/
362PRIVATE int handle_status(kbdp, m)
363struct kbd *kbdp;
364message *m;
365{
366 int n, r;
367
368 if (kbdp->avail && kbdp->req_size && m->m_source == kbdp->incaller)
369 {
370 /* Handle read request */
371 n= kbdp->avail;
372 if (n > kbdp->req_size)
373 n= kbdp->req_size;
374 if (kbdp->offset + n > KBD_BUFSZ)
375 n= KBD_BUFSZ-kbdp->offset;
376 if (n <= 0)
377 panic("TTY", "kbd_status: bad n", n);
378 kbdp->req_size= 0;
379 r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset],
380 kbdp->req_proc, D, kbdp->req_addr, n);
381 if (r == OK)
382 {
383 kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
384 kbdp->avail -= n;
385 r= n;
386 }
387
388 m->m_type = DEV_REVIVE;
389 m->REP_ENDPT= kbdp->req_proc;
390 m->REP_STATUS= r;
391 return 1;
392 }
393 if (kbdp->avail && (kbdp->select_ops & SEL_RD) &&
394 m->m_source == kbdp->select_proc)
395 {
396 m->m_type = DEV_IO_READY;
397 m->DEV_MINOR = kbdp->minor;
398 m->DEV_SEL_OPS = SEL_RD;
399
400 kbdp->select_ops &= ~SEL_RD;
401 return 1;
402 }
403
404 return 0;
405}
406
407
408/*===========================================================================*
409 * map_key0 *
410 *===========================================================================*/
411/* Map a scan code to an ASCII code ignoring modifiers. */
412#define map_key0(scode) \
413 ((unsigned) keymap[(scode) * MAP_COLS])
414
415/*===========================================================================*
416 * map_key *
417 *===========================================================================*/
418PRIVATE unsigned map_key(scode)
419int scode;
420{
421/* Map a scan code to an ASCII code. */
422
423 int caps, column, lk;
424 u16_t *keyrow;
425
426 if (scode == SLASH_SCAN && esc) return '/'; /* don't map numeric slash */
427
428 keyrow = &keymap[scode * MAP_COLS];
429
430 caps = shift;
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;
434
435 if (alt) {
436 column = 2;
437 if (ctrl || alt_r) column = 3; /* Ctrl + Alt == AltGr */
438 if (caps) column = 4;
439 } else {
440 column = 0;
441 if (caps) column = 1;
442 if (ctrl) column = 5;
443 }
444 return keyrow[column] & ~HASCAPS;
445}
446
447/*===========================================================================*
448 * kbd_interrupt *
449 *===========================================================================*/
450PUBLIC void kbd_interrupt(m_ptr)
451message *m_ptr;
452{
453/* A keyboard interrupt has occurred. Process it. */
454 int o, isaux;
455 unsigned char scode;
456 struct kbd *kbdp;
457 static timer_t timer; /* timer must be static! */
458
459 /* Fetch the character from the keyboard hardware and acknowledge it. */
460 if (!scan_keyboard(&scode, &isaux))
461 return;
462
463 if (isaux)
464 kbdp= &kbdaux;
465 else if (kbd.nr_open && !panicing)
466 kbdp= &kbd;
467 else
468 kbdp= NULL;
469
470 if (kbdp)
471 {
472 /* raw scan codes or aux data */
473 if (kbdp->avail >= KBD_BUFSZ)
474 {
475 printf("kbd_interrupt: %s buffer is full\n",
476 isaux ? "kbdaux" : "keyboard");
477 return; /* Buffer is full */
478 }
479 o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ;
480 kbdp->buf[o]= scode;
481 kbdp->avail++;
482 if (kbdp->req_size)
483 notify(kbdp->incaller);
484 if (kbdp->select_ops & SEL_RD)
485 notify(kbdp->select_proc);
486 return;
487 }
488
489 /* Store the scancode in memory so the task can get at it later. */
490 if (icount < KB_IN_BYTES) {
491 *ihead++ = scode;
492 if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf;
493 icount++;
494 tty_table[ccurrent].tty_events = 1;
495 if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
496 select_retry(&tty_table[ccurrent]);
497 }
498 }
499}
500
501/*===========================================================================*
502 * kb_read *
503 *===========================================================================*/
504PRIVATE int kb_read(tp, try)
505tty_t *tp;
506int try;
507{
508/* Process characters from the circular keyboard buffer. */
509 char buf[3];
510 int scode;
511 unsigned ch;
512
513 tp = &tty_table[ccurrent]; /* always use the current console */
514
515 if (try) {
516 if (icount > 0) return 1;
517 return 0;
518 }
519
520 while (icount > 0) {
521 scode = *itail++; /* take one key scan code */
522 if (itail == ibuf + KB_IN_BYTES) itail = ibuf;
523 icount--;
524
525 /* Function keys are being used for debug dumps. */
526 if (func_key(scode)) continue;
527
528 /* Perform make/break processing. */
529 ch = make_break(scode);
530
531 if (ch <= 0xFF) {
532 /* A normal character. */
533 buf[0] = ch;
534 (void) in_process(tp, buf, 1);
535 } else
536 if (HOME <= ch && ch <= INSRT) {
537 /* An ASCII escape sequence generated by the numeric pad. */
538 buf[0] = ESC;
539 buf[1] = '[';
540 buf[2] = numpad_map[ch - HOME];
541 (void) in_process(tp, buf, 3);
542 } else
543 if (ch == ALEFT) {
544 /* Choose lower numbered console as current console. */
545 select_console(ccurrent - 1);
546 set_leds();
547 } else
548 if (ch == ARIGHT) {
549 /* Choose higher numbered console as current console. */
550 select_console(ccurrent + 1);
551 set_leds();
552 } else
553 if (AF1 <= ch && ch <= AF12) {
554 /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */
555 select_console(ch - AF1);
556 set_leds();
557 } else
558 if (CF1 <= ch && ch <= CF12) {
559 switch(ch) {
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;
565 }
566 }
567 }
568
569 return 1;
570}
571
572/*===========================================================================*
573 * kbd_send *
574 *===========================================================================*/
575PRIVATE void kbd_send()
576{
577 unsigned long sb;
578 int r;
579 clock_t now;
580
581 if (!kbdout.avail)
582 return;
583 if (kbdout.expect_ack)
584 return;
585
586 sys_inb(KB_STATUS, &sb);
587 if (sb & (KB_OUT_FULL|KB_IN_FULL))
588 {
589 printf("not sending 1: sb = 0x%x\n", sb);
590 return;
591 }
592 micro_delay(KBC_IN_DELAY);
593 sys_inb(KB_STATUS, &sb);
594 if (sb & (KB_OUT_FULL|KB_IN_FULL))
595 {
596 printf("not sending 2: sb = 0x%x\n", sb);
597 return;
598 }
599
600 /* Okay, buffer is really empty */
601#if 0
602 printf("sending byte 0x%x to keyboard\n", kbdout.buf[kbdout.offset]);
603#endif
604 sys_outb(KEYBD, kbdout.buf[kbdout.offset]);
605 kbdout.offset++;
606 kbdout.avail--;
607 kbdout.expect_ack= 1;
608
609 kbd_alive= 1;
610 if (kbd_watchdog_set)
611 {
612 /* Add a timer to the timers list. Possibly reschedule the
613 * alarm.
614 */
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,
618 NULL);
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);
623 }
624 kbd_watchdog_set= 1;
625 }
626}
627
628/*===========================================================================*
629 * make_break *
630 *===========================================================================*/
631PRIVATE unsigned make_break(scode)
632int scode; /* scan code of key just struck or released */
633{
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.
637 */
638 int ch, make, escape;
639 static int CAD_count = 0;
640
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.
644 */
645 if (ctrl && alt && (scode == DEL_SCAN || scode == INS_SCAN))
646 {
647 if (++CAD_count == 3) sys_abort(RBT_HALT);
648 sys_kill(INIT_PROC_NR, SIGABRT);
649 return -1;
650 }
651
652 /* High-order bit set on key release. */
653 make = (scode & KEY_RELEASE) == 0; /* true if pressed */
654
655 ch = map_key(scode &= ASCII_MASK); /* map to ASCII */
656
657 escape = esc; /* Key is escaped? (true if added since the XT) */
658 esc = 0;
659
660 switch (ch) {
661 case CTRL: /* Left or right control key */
662 *(escape ? &ctrl_r : &ctrl_l) = make;
663 ctrl = ctrl_l | ctrl_r;
664 break;
665 case SHIFT: /* Left or right shift key */
666 *(scode == RSHIFT_SCAN ? &shift_r : &shift_l) = make;
667 shift = shift_l | shift_r;
668 break;
669 case ALT: /* Left or right alt key */
670 *(escape ? &alt_r : &alt_l) = make;
671 alt = alt_l | alt_r;
672 break;
673 case CALOCK: /* Caps lock - toggle on 0 -> 1 transition */
674 if (caps_down < make) {
675 locks[ccurrent] ^= CAPS_LOCK;
676 set_leds();
677 }
678 caps_down = make;
679 break;
680 case NLOCK: /* Num lock */
681 if (num_down < make) {
682 locks[ccurrent] ^= NUM_LOCK;
683 set_leds();
684 }
685 num_down = make;
686 break;
687 case SLOCK: /* Scroll lock */
688 if (scroll_down < make) {
689 locks[ccurrent] ^= SCROLL_LOCK;
690 set_leds();
691 }
692 scroll_down = make;
693 break;
694 case EXTKEY: /* Escape keycode */
695 esc = 1; /* Next key is escaped */
696 return(-1);
697 default: /* A normal key */
698 if (make) return(ch);
699 }
700
701 /* Key release, or a shift type key. */
702 return(-1);
703}
704
705/*===========================================================================*
706 * set_leds *
707 *===========================================================================*/
708PRIVATE void set_leds()
709{
710/* Set the LEDs on the caps, num, and scroll lock keys */
711 int s;
712 if (! machine.pc_at) return; /* PC/XT doesn't have LEDs */
713
714 kb_wait(); /* wait for buffer empty */
715 if ((s=sys_outb(KEYBD, LED_CODE)) != OK)
716 printf("Warning, sys_outb couldn't prepare for LED values: %d\n", s);
717 /* prepare keyboard to accept LED values */
718 kb_ack(); /* wait for ack response */
719
720 kb_wait(); /* wait for buffer empty */
721 if ((s=sys_outb(KEYBD, locks[ccurrent])) != OK)
722 printf("Warning, sys_outb couldn't give LED values: %d\n", s);
723 /* give keyboard LED values */
724 kb_ack(); /* wait for ack response */
725}
726
727/*===========================================================================*
728 * kbc_cmd0 *
729 *===========================================================================*/
730PRIVATE void kbc_cmd0(cmd)
731int cmd;
732{
733 kb_wait();
734 sys_outb(KB_COMMAND, cmd);
735}
736
737/*===========================================================================*
738 * kbc_cmd1 *
739 *===========================================================================*/
740PRIVATE void kbc_cmd1(cmd, data)
741int cmd;
742int data;
743{
744 kb_wait();
745 sys_outb(KB_COMMAND, cmd);
746 kb_wait();
747 sys_outb(KEYBD, data);
748}
749
750
751/*===========================================================================*
752* kbc_read *
753*===========================================================================*/
754PRIVATE int kbc_read()
755{
756 int i;
757 unsigned long byte, st;
758#if 0
759 struct micro_state ms;
760#endif
761
762#if DEBUG
763 printf("in kbc_read\n");
764#endif
765
766 /* Wait at most 1 second for a byte from the keyboard or
767 * the kbd controller, return -1 on a timeout.
768 */
769 for (i= 0; i<1000; i++)
770 #if 0
771 micro_start(&ms);
772 do
773#endif
774 {
775 sys_inb(KB_STATUS, &st);
776 if (st & KB_OUT_FULL)
777 {
778 micro_delay(KBC_IN_DELAY);
779 sys_inb(KEYBD, &byte);
780 if (st & KB_AUX_BYTE)
781 {
782#if DEBUG
783 printf(
784 "keyboard`kbc_read: ignoring byte (0x%x) from aux device.\n",
785 byte);
786#endif
787 continue;
788 }
789#if DEBUG
790 printf("keyboard`kbc_read: returning byte 0x%x\n",
791 byte);
792#endif
793 return byte;
794 }
795 }
796#if 0
797 while (micro_elapsed(&ms) < 1000000);
798#endif
799 panic("TTY", "kbc_read failed to complete", NO_NUM);
800}
801
802
803
804/*===========================================================================*
805 * kb_wait *
806 *===========================================================================*/
807PRIVATE int kb_wait()
808{
809/* Wait until the controller is ready; return zero if this times out. */
810
811 int retries;
812 unsigned long status, temp;
813 int s, isaux;
814 unsigned char byte;
815
816 retries = MAX_KB_BUSY_RETRIES + 1; /* wait until not busy */
817 do {
818 s = sys_inb(KB_STATUS, &status);
819 if (status & KB_OUT_FULL) {
820 if (scan_keyboard(&byte, &isaux))
821 {
822#if 0
823 printf("ignoring %sbyte in kb_wait\n", isaux ? "AUX " : "");
824#endif
825 }
826 }
827 if (! (status & (KB_IN_FULL|KB_OUT_FULL)) )
828 break; /* wait until ready */
829 } while (--retries != 0); /* continue unless timeout */
830 return(retries); /* zero on timeout, positive if ready */
831}
832
833/*===========================================================================*
834 * kb_ack *
835 *===========================================================================*/
836PRIVATE int kb_ack()
837{
838/* Wait until kbd acknowledges last command; return zero if this times out. */
839
840 int retries, s;
841 unsigned long u8val;
842
843
844 retries = MAX_KB_ACK_RETRIES + 1;
845 do {
846 s = sys_inb(KEYBD, &u8val);
847 if (u8val == KB_ACK)
848 break; /* wait for ack */
849 } while(--retries != 0); /* continue unless timeout */
850
851 return(retries); /* nonzero if ack received */
852}
853
854/*===========================================================================*
855 * kb_init *
856 *===========================================================================*/
857PUBLIC void kb_init(tp)
858tty_t *tp;
859{
860/* Initialize the keyboard driver. */
861
862 tp->tty_devread = kb_read; /* input function */
863}
864
865/*===========================================================================*
866 * kb_init_once *
867 *===========================================================================*/
868PUBLIC void kb_init_once(void)
869{
870 int i;
871 u8_t ccb;
872
873 set_leds(); /* turn off numlock led */
874 scan_keyboard(NULL, NULL); /* discard leftover keystroke */
875
876 /* Clear the function key observers array. Also see func_key(). */
877 for (i=0; i<12; i++) {
878 fkey_obs[i].proc_nr = NONE; /* F1-F12 observers */
879 fkey_obs[i].events = 0; /* F1-F12 observers */
880 sfkey_obs[i].proc_nr = NONE; /* Shift F1-F12 observers */
881 sfkey_obs[i].events = 0; /* Shift F1-F12 observers */
882 }
883
884 kbd.minor= KBD_MINOR;
885 kbdaux.minor= KBDAUX_MINOR;
886
887 /* Set interrupt handler and enable keyboard IRQ. */
888 irq_hook_id = KEYBOARD_IRQ; /* id to be returned on interrupt */
889 if ((i=sys_irqsetpolicy(KEYBOARD_IRQ, IRQ_REENABLE, &irq_hook_id)) != OK)
890 panic("TTY", "Couldn't set keyboard IRQ policy", i);
891 if ((i=sys_irqenable(&irq_hook_id)) != OK)
892 panic("TTY", "Couldn't enable keyboard IRQs", i);
893 kbd_irq_set |= (1 << KEYBOARD_IRQ);
894
895 /* Set AUX interrupt handler and enable AUX IRQ. */
896 aux_irq_hook_id = KBD_AUX_IRQ; /* id to be returned on interrupt */
897 if ((i=sys_irqsetpolicy(KBD_AUX_IRQ, IRQ_REENABLE,
898 &aux_irq_hook_id)) != OK)
899 panic("TTY", "Couldn't set AUX IRQ policy", i);
900 if ((i=sys_irqenable(&aux_irq_hook_id)) != OK)
901 panic("TTY", "Couldn't enable AUX IRQs", i);
902 kbd_irq_set |= (1 << KBD_AUX_IRQ);
903
904 /* Disable the keyboard and aux */
905 kbc_cmd0(KBC_DI_KBD);
906 kbc_cmd0(KBC_DI_AUX);
907
908 /* Get the current configuration byte */
909 kbc_cmd0(KBC_RD_RAM_CCB);
910 ccb= kbc_read();
911
912 /* Enable both interrupts. */
913 kbc_cmd1(KBC_WR_RAM_CCB, ccb | 3);
914
915 /* Re-enable the keyboard device. */
916 kbc_cmd0(KBC_EN_KBD);
917
918 /* Enable the aux device. */
919 kbc_cmd0(KBC_EN_AUX);
920}
921
922/*===========================================================================*
923 * kbd_loadmap *
924 *===========================================================================*/
925PUBLIC int kbd_loadmap(m)
926message *m;
927{
928/* Load a new keymap. */
929 int result;
930 result = sys_vircopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS,
931 SELF, D, (vir_bytes) keymap,
932 (vir_bytes) sizeof(keymap));
933 return(result);
934}
935
936/*===========================================================================*
937 * do_fkey_ctl *
938 *===========================================================================*/
939PUBLIC void do_fkey_ctl(m_ptr)
940message *m_ptr; /* pointer to the request message */
941{
942/* This procedure allows processes to register a function key to receive
943 * notifications if it is pressed. At most one binding per key can exist.
944 */
945 int i;
946 int result;
947
948 switch (m_ptr->FKEY_REQUEST) { /* see what we must do */
949 case FKEY_MAP: /* request for new mapping */
950 result = OK; /* assume everything will be ok*/
951 for (i=0; i < 12; i++) { /* check F1-F12 keys */
952 if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
953#if DEAD_CODE
954 /* Currently, we don't check if the slot is in use, so that IS
955 * can recover after a crash by overtaking its existing mappings.
956 * In future, a better solution will be implemented.
957 */
958 if (fkey_obs[i].proc_nr == NONE) {
959#endif
960 fkey_obs[i].proc_nr = m_ptr->m_source;
961 fkey_obs[i].events = 0;
962 bit_unset(m_ptr->FKEY_FKEYS, i+1);
963#if DEAD_CODE
964 } else {
965 printf("WARNING, fkey_map failed F%d\n", i+1);
966 result = EBUSY; /* report failure, but try rest */
967 }
968#endif
969 }
970 }
971 for (i=0; i < 12; i++) { /* check Shift+F1-F12 keys */
972 if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
973#if DEAD_CODE
974 if (sfkey_obs[i].proc_nr == NONE) {
975#endif
976 sfkey_obs[i].proc_nr = m_ptr->m_source;
977 sfkey_obs[i].events = 0;
978 bit_unset(m_ptr->FKEY_SFKEYS, i+1);
979#if DEAD_CODE
980 } else {
981 printf("WARNING, fkey_map failed Shift F%d\n", i+1);
982 result = EBUSY; /* report failure but try rest */
983 }
984#endif
985 }
986 }
987 break;
988 case FKEY_UNMAP:
989 result = OK; /* assume everything will be ok*/
990 for (i=0; i < 12; i++) { /* check F1-F12 keys */
991 if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
992 if (fkey_obs[i].proc_nr == m_ptr->m_source) {
993 fkey_obs[i].proc_nr = NONE;
994 fkey_obs[i].events = 0;
995 bit_unset(m_ptr->FKEY_FKEYS, i+1);
996 } else {
997 result = EPERM; /* report failure, but try rest */
998 }
999 }
1000 }
1001 for (i=0; i < 12; i++) { /* check Shift+F1-F12 keys */
1002 if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
1003 if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
1004 sfkey_obs[i].proc_nr = NONE;
1005 sfkey_obs[i].events = 0;
1006 bit_unset(m_ptr->FKEY_SFKEYS, i+1);
1007 } else {
1008 result = EPERM; /* report failure, but try rest */
1009 }
1010 }
1011 }
1012 break;
1013 case FKEY_EVENTS:
1014 m_ptr->FKEY_FKEYS = m_ptr->FKEY_SFKEYS = 0;
1015 for (i=0; i < 12; i++) { /* check (Shift+) F1-F12 keys */
1016 if (fkey_obs[i].proc_nr == m_ptr->m_source) {
1017 if (fkey_obs[i].events) {
1018 bit_set(m_ptr->FKEY_FKEYS, i+1);
1019 fkey_obs[i].events = 0;
1020 }
1021 }
1022 if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
1023 if (sfkey_obs[i].events) {
1024 bit_set(m_ptr->FKEY_SFKEYS, i+1);
1025 sfkey_obs[i].events = 0;
1026 }
1027 }
1028 }
1029 break;
1030 default:
1031 result = EINVAL; /* key cannot be observed */
1032 }
1033
1034 /* Almost done, return result to caller. */
1035 m_ptr->m_type = result;
1036 send(m_ptr->m_source, m_ptr);
1037}
1038
1039/*===========================================================================*
1040 * func_key *
1041 *===========================================================================*/
1042PRIVATE int func_key(scode)
1043int scode; /* scan code for a function key */
1044{
1045/* This procedure traps function keys for debugging purposes. Observers of
1046 * function keys are kept in a global array. If a subject (a key) is pressed
1047 * the observer is notified of the event. Initialization of the arrays is done
1048 * in kb_init, where NONE is set to indicate there is no interest in the key.
1049 * Returns FALSE on a key release or if the key is not observable.
1050 */
1051 message m;
1052 int key;
1053 int proc_nr;
1054 int i,s;
1055
1056 /* Ignore key releases. If this is a key press, get full key code. */
1057 if (scode & KEY_RELEASE) return(FALSE); /* key release */
1058 key = map_key(scode); /* include modifiers */
1059
1060 /* Key pressed, now see if there is an observer for the pressed key.
1061 * F1-F12 observers are in fkey_obs array.
1062 * SHIFT F1-F12 observers are in sfkey_req array.
1063 * CTRL F1-F12 reserved (see kb_read)
1064 * ALT F1-F12 reserved (see kb_read)
1065 * Other combinations are not in use. Note that Alt+Shift+F1-F12 is yet
1066 * defined in <minix/keymap.h>, and thus is easy for future extensions.
1067 */
1068 if (F1 <= key && key <= F12) { /* F1-F12 */
1069 proc_nr = fkey_obs[key - F1].proc_nr;
1070 fkey_obs[key - F1].events ++ ;
1071 } else if (SF1 <= key && key <= SF12) { /* Shift F2-F12 */
1072 proc_nr = sfkey_obs[key - SF1].proc_nr;
1073 sfkey_obs[key - SF1].events ++;
1074 }
1075 else {
1076 return(FALSE); /* not observable */
1077 }
1078
1079 /* See if an observer is registered and send it a message. */
1080 if (proc_nr != NONE) {
1081 m.NOTIFY_TYPE = FKEY_PRESSED;
1082 notify(proc_nr);
1083 }
1084 return(TRUE);
1085}
1086
1087/*===========================================================================*
1088 * show_key_mappings *
1089 *===========================================================================*/
1090PRIVATE void show_key_mappings()
1091{
1092 int i,s;
1093 struct proc proc;
1094
1095 printf("\n");
1096 printf("System information. Known function key mappings to request debug dumps:\n");
1097 printf("-------------------------------------------------------------------------\n");
1098 for (i=0; i<12; i++) {
1099
1100 printf(" %sF%d: ", i+1<10? " ":"", i+1);
1101 if (fkey_obs[i].proc_nr != NONE) {
1102 if ((s=sys_getproc(&proc, fkey_obs[i].proc_nr))!=OK)
1103 printf("sys_getproc: %d\n", s);
1104 printf("%-14.14s", proc.p_name);
1105 } else {
1106 printf("%-14.14s", "<none>");
1107 }
1108
1109 printf(" %sShift-F%d: ", i+1<10? " ":"", i+1);
1110 if (sfkey_obs[i].proc_nr != NONE) {
1111 if ((s=sys_getproc(&proc, sfkey_obs[i].proc_nr))!=OK)
1112 printf("sys_getproc: %d\n", s);
1113 printf("%-14.14s", proc.p_name);
1114 } else {
1115 printf("%-14.14s", "<none>");
1116 }
1117 printf("\n");
1118 }
1119 printf("\n");
1120 printf("Press one of the registered function keys to trigger a debug dump.\n");
1121 printf("\n");
1122}
1123
1124/*===========================================================================*
1125 * scan_keyboard *
1126 *===========================================================================*/
1127PRIVATE int scan_keyboard(bp, isauxp)
1128unsigned char *bp;
1129int *isauxp;
1130{
1131#if 0 /* Is this old XT code? It doesn't match the PS/2 hardware */
1132/* Fetch the character from the keyboard hardware and acknowledge it. */
1133 pvb_pair_t byte_in[2], byte_out[2];
1134
1135 byte_in[0].port = KEYBD; /* get the scan code for the key struck */
1136 byte_in[1].port = PORT_B; /* strobe the keyboard to ack the char */
1137 sys_vinb(byte_in, 2); /* request actual input */
1138
1139 pv_set(byte_out[0], PORT_B, byte_in[1].value | KBIT); /* strobe bit high */
1140 pv_set(byte_out[1], PORT_B, byte_in[1].value); /* then strobe low */
1141 sys_voutb(byte_out, 2); /* request actual output */
1142
1143 return(byte_in[0].value); /* return scan code */
1144#else
1145 unsigned long b, sb;
1146
1147 sys_inb(KB_STATUS, &sb);
1148 if (!(sb & KB_OUT_FULL))
1149 {
1150 if (kbdout.avail && !kbdout.expect_ack)
1151 kbd_send();
1152 return 0;
1153 }
1154 sys_inb(KEYBD, &b);
1155#if 0
1156 printf("got byte 0x%x from %s\n", b, (sb & KB_AUX_BYTE) ? "AUX" : "keyboard");
1157#endif
1158 if (!(sb & KB_AUX_BYTE) && b == KB_ACK && kbdout.expect_ack)
1159 {
1160#if 1
1161 printf("got ACK from keyboard\n");
1162#endif
1163 kbdout.expect_ack= 0;
1164 micro_delay(KBC_IN_DELAY);
1165 kbd_send();
1166 return 0;
1167 }
1168 if (bp)
1169 *bp= b;
1170 if (isauxp)
1171 *isauxp= !!(sb & KB_AUX_BYTE);
1172 if (kbdout.avail && !kbdout.expect_ack)
1173 {
1174 micro_delay(KBC_IN_DELAY);
1175 kbd_send();
1176 }
1177 return 1;
1178#endif
1179}
1180
1181static void micro_delay(unsigned long usecs)
1182{
1183 tickdelay(MICROS_TO_TICKS(usecs));
1184}
1185
1186/*===========================================================================*
1187 * kbd_watchdog *
1188 *===========================================================================*/
1189PRIVATE void kbd_watchdog(tmrp)
1190timer_t *tmrp;
1191{
1192 int r;
1193 clock_t now;
1194
1195 kbd_watchdog_set= 0;
1196 if (!kbdout.avail)
1197 return; /* Watchdog is no longer needed */
1198 if (!kbd_alive)
1199 {
1200 printf("kbd_watchdog: should reset keyboard\n");
1201 }
1202 kbd_alive= 0;
1203
1204 if ((r= getuptime(&now)) != OK)
1205 panic("TTY","Keyboard couldn't get clock's uptime.", r);
1206 tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+HZ, kbd_watchdog,
1207 NULL);
1208 if (tty_timers->tmr_exp_time != tty_next_timeout) {
1209 tty_next_timeout = tty_timers->tmr_exp_time;
1210 if ((r= sys_setalarm(tty_next_timeout, 1)) != OK)
1211 panic("TTY","Keyboard couldn't set alarm.", r);
1212 }
1213 kbd_watchdog_set= 1;
1214}
Note: See TracBrowser for help on using the repository browser.