📄 keyboard.c
字号:
/* Keyboard driver for PC's and AT's. * * Changes: * Jul 13, 2004 processes can observe function keys (Jorrit N. Herder) * Jun 15, 2004 removed wreboot(), except panic dumps (Jorrit N. Herder) * Feb 04, 1994 loadable keymaps (Marcus Hampel) */#include "../drivers.h"#include <sys/time.h>#include <sys/select.h>#include <termios.h>#include <signal.h>#include <unistd.h>#include <minix/callnr.h>#include <minix/com.h>#include <minix/keymap.h>#include "tty.h"#include "keymaps/us-std.src"#include "../../kernel/const.h"#include "../../kernel/config.h"#include "../../kernel/type.h"#include "../../kernel/proc.h"int irq_hook_id = -1;/* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */#define KEYBD 0x60 /* I/O port for keyboard data *//* AT keyboard. */#define KB_COMMAND 0x64 /* I/O port for commands on AT */#define KB_STATUS 0x64 /* I/O port for status on AT */#define KB_ACK 0xFA /* keyboard ack response */#define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */#define KB_IN_FULL 0x02 /* status bit set when not ready to receive */#define LED_CODE 0xED /* command to keyboard to set LEDs */#define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */#define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */#define KBIT 0x80 /* bit used to ack characters to keyboard *//* Miscellaneous. */#define ESC_SCAN 0x01 /* reboot key when panicking */#define SLASH_SCAN 0x35 /* to recognize numeric slash */#define RSHIFT_SCAN 0x36 /* to distinguish left and right shift */#define HOME_SCAN 0x47 /* first key on the numeric keypad */#define INS_SCAN 0x52 /* INS for use in CTRL-ALT-INS reboot */#define DEL_SCAN 0x53 /* DEL for use in CTRL-ALT-DEL reboot */#define CONSOLE 0 /* line number for console */#define KB_IN_BYTES 32 /* size of keyboard input buffer */PRIVATE char ibuf[KB_IN_BYTES]; /* input buffer */PRIVATE char *ihead = ibuf; /* next free spot in input buffer */PRIVATE char *itail = ibuf; /* scan code to return to TTY */PRIVATE int icount; /* # codes in buffer */PRIVATE int esc; /* escape scan code detected? */PRIVATE int alt_l; /* left alt key state */PRIVATE int alt_r; /* right alt key state */PRIVATE int alt; /* either alt key */PRIVATE int ctrl_l; /* left control key state */PRIVATE int ctrl_r; /* right control key state */PRIVATE int ctrl; /* either control key */PRIVATE int shift_l; /* left shift key state */PRIVATE int shift_r; /* right shift key state */PRIVATE int shift; /* either shift key */PRIVATE int num_down; /* num lock key depressed */PRIVATE int caps_down; /* caps lock key depressed */PRIVATE int scroll_down; /* scroll lock key depressed */PRIVATE int locks[NR_CONS]; /* per console lock keys state *//* Lock key active bits. Chosen to be equal to the keyboard LED bits. */#define SCROLL_LOCK 0x01#define NUM_LOCK 0x02#define CAPS_LOCK 0x04PRIVATE char numpad_map[] = {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};/* Variables and definition for observed function keys. */typedef struct observer { int proc_nr; int events; } obs_t;PRIVATE obs_t fkey_obs[12]; /* observers for F1-F12 */PRIVATE obs_t sfkey_obs[12]; /* observers for SHIFT F1-F12 */FORWARD _PROTOTYPE( int kb_ack, (void) );FORWARD _PROTOTYPE( int kb_wait, (void) );FORWARD _PROTOTYPE( int func_key, (int scode) );FORWARD _PROTOTYPE( int scan_keyboard, (void) );FORWARD _PROTOTYPE( unsigned make_break, (int scode) );FORWARD _PROTOTYPE( void set_leds, (void) );FORWARD _PROTOTYPE( void show_key_mappings, (void) );FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try) );FORWARD _PROTOTYPE( unsigned map_key, (int scode) );/*===========================================================================* * map_key0 * *===========================================================================*//* Map a scan code to an ASCII code ignoring modifiers. */#define map_key0(scode) \ ((unsigned) keymap[(scode) * MAP_COLS])/*===========================================================================* * map_key * *===========================================================================*/PRIVATE unsigned map_key(scode)int scode;{/* Map a scan code to an ASCII code. */ int caps, column, lk; u16_t *keyrow; if (scode == SLASH_SCAN && esc) return '/'; /* don't map numeric slash */ keyrow = &keymap[scode * MAP_COLS]; caps = shift; lk = locks[ccurrent]; if ((lk & NUM_LOCK) && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps; if ((lk & CAPS_LOCK) && (keyrow[0] & HASCAPS)) caps = !caps; if (alt) { column = 2; if (ctrl || alt_r) column = 3; /* Ctrl + Alt == AltGr */ if (caps) column = 4; } else { column = 0; if (caps) column = 1; if (ctrl) column = 5; } return keyrow[column] & ~HASCAPS;}/*===========================================================================* * kbd_interrupt * *===========================================================================*/PUBLIC void kbd_interrupt(m_ptr)message *m_ptr;{/* A keyboard interrupt has occurred. Process it. */ int scode; static timer_t timer; /* timer must be static! */ /* Fetch the character from the keyboard hardware and acknowledge it. */ scode = scan_keyboard(); /* Store the scancode in memory so the task can get at it later. */ if (icount < KB_IN_BYTES) { *ihead++ = scode; if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf; icount++; tty_table[ccurrent].tty_events = 1; if (tty_table[ccurrent].tty_select_ops & SEL_RD) { select_retry(&tty_table[ccurrent]); } }}/*===========================================================================* * kb_read * *===========================================================================*/PRIVATE int kb_read(tp, try)tty_t *tp;int try;{/* Process characters from the circular keyboard buffer. */ char buf[3]; int scode; unsigned ch; tp = &tty_table[ccurrent]; /* always use the current console */ if (try) { if (icount > 0) return 1; return 0; } while (icount > 0) { scode = *itail++; /* take one key scan code */ if (itail == ibuf + KB_IN_BYTES) itail = ibuf; icount--; /* Function keys are being used for debug dumps. */ if (func_key(scode)) continue; /* Perform make/break processing. */ ch = make_break(scode); if (ch <= 0xFF) { /* A normal character. */ buf[0] = ch; (void) in_process(tp, buf, 1); } else if (HOME <= ch && ch <= INSRT) { /* An ASCII escape sequence generated by the numeric pad. */ buf[0] = ESC; buf[1] = '['; buf[2] = numpad_map[ch - HOME]; (void) in_process(tp, buf, 3); } else if (ch == ALEFT) { /* Choose lower numbered console as current console. */ select_console(ccurrent - 1); set_leds(); } else if (ch == ARIGHT) { /* Choose higher numbered console as current console. */ select_console(ccurrent + 1); set_leds(); } else if (AF1 <= ch && ch <= AF12) { /* Alt-F1 is console, Alt-F2 is ttyc1, etc. */ select_console(ch - AF1); set_leds(); } else if (CF1 <= ch && ch <= CF12) { switch(ch) { case CF1: show_key_mappings(); break; case CF3: toggle_scroll(); break; /* hardware <-> software */ case CF7: sigchar(&tty_table[CONSOLE], SIGQUIT); break; case CF8: sigchar(&tty_table[CONSOLE], SIGINT); break; case CF9: sigchar(&tty_table[CONSOLE], SIGKILL); break; } } } return 1;}/*===========================================================================* * make_break * *===========================================================================*/PRIVATE unsigned make_break(scode)int scode; /* scan code of key just struck or released */{/* This routine can handle keyboards that interrupt only on key depression, * as well as keyboards that interrupt on key depression and key release. * For efficiency, the interrupt routine filters out most key releases. */ int ch, make, escape; static int CAD_count = 0; /* Check for CTRL-ALT-DEL, and if found, halt the computer. This would * be better done in keyboard() in case TTY is hung, except control and * alt are set in the high level code. */ if (ctrl && alt && (scode == DEL_SCAN || scode == INS_SCAN)) { if (++CAD_count == 3) sys_abort(RBT_HALT); sys_kill(INIT_PROC_NR, SIGABRT); return -1; } /* High-order bit set on key release. */ make = (scode & KEY_RELEASE) == 0; /* true if pressed */ ch = map_key(scode &= ASCII_MASK); /* map to ASCII */ escape = esc; /* Key is escaped? (true if added since the XT) */ esc = 0; switch (ch) { case CTRL: /* Left or right control key */ *(escape ? &ctrl_r : &ctrl_l) = make; ctrl = ctrl_l | ctrl_r; break; case SHIFT: /* Left or right shift key */ *(scode == RSHIFT_SCAN ? &shift_r : &shift_l) = make; shift = shift_l | shift_r; break; case ALT: /* Left or right alt key */ *(escape ? &alt_r : &alt_l) = make; alt = alt_l | alt_r; break; case CALOCK: /* Caps lock - toggle on 0 -> 1 transition */ if (caps_down < make) { locks[ccurrent] ^= CAPS_LOCK; set_leds(); } caps_down = make; break; case NLOCK: /* Num lock */ if (num_down < make) { locks[ccurrent] ^= NUM_LOCK; set_leds(); } num_down = make; break; case SLOCK: /* Scroll lock */ if (scroll_down < make) { locks[ccurrent] ^= SCROLL_LOCK; set_leds(); } scroll_down = make; break; case EXTKEY: /* Escape keycode */ esc = 1; /* Next key is escaped */ return(-1); default: /* A normal key */ if (make) return(ch); } /* Key release, or a shift type key. */ return(-1);}/*===========================================================================* * set_leds * *===========================================================================*/PRIVATE void set_leds(){/* Set the LEDs on the caps, num, and scroll lock keys */ int s; if (! machine.pc_at) return; /* PC/XT doesn't have LEDs */ kb_wait(); /* wait for buffer empty */ if ((s=sys_outb(KEYBD, LED_CODE)) != OK) printf("Warning, sys_outb couldn't prepare for LED values: %d\n", s); /* prepare keyboard to accept LED values */ kb_ack(); /* wait for ack response */ kb_wait(); /* wait for buffer empty */ if ((s=sys_outb(KEYBD, locks[ccurrent])) != OK) printf("Warning, sys_outb couldn't give LED values: %d\n", s); /* give keyboard LED values */ kb_ack(); /* wait for ack response */}/*===========================================================================* * kb_wait * *===========================================================================*/PRIVATE int kb_wait(){/* Wait until the controller is ready; return zero if this times out. */ int retries, status, temp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -