elks-enhanced
public
Read
Owner: themaster
Branch: master
Commits: 6893
Updated: 2026-04-19 00:15
Git CLI clone URL
git clone https://www.xt-emporium.com/git/elks-enhanced.git
Fullscreen desktop URL
Code
Commits
History
Branches
Bug Reports
Discussions
Compare
Settings
elks-enhanced
/
elks
/
arch
/
i86
/
drivers
/
char
/
kbd-scancode.c
File editor
/* * Direct console XT and AT keyboard driver * * Tables from the Minix book, as that's all I have on XT keyboard * controllers. They need to be loadable, this doesn't look good on * my Finnish keyboard. * * Added primitive buffering, and function stubs for vfs calls * Removed vfs funcs, they belong better to the console driver * Changed this a lot. Made it work, too. ;) * Saku Airila 1996 * * Changed code to work with belgian keyboard * Stefaan (Stefke) Van Dooren 1998 * * Changed code to support int'l keys 42 + 45, enable caps lock * preliminary F11+F12 support, add comments to increase readability * Georg Potthast 2017 * * 14 Jul 20 Helge Skrivervik Added LED and NUMLOCK/CAPSLOCK processing. * 17 Jul 20 Greg Haerr Added SCRLOCK processing, documentation, rewrite for clarity. * 15 Apr 21 TK Chia Using interrupt-driven I/O to update keyboard LEDs. */ #include <linuxmt/config.h> #include <linuxmt/kernel.h> #include <linuxmt/sched.h> #include <linuxmt/types.h> #include <linuxmt/errno.h> #include <linuxmt/fs.h> #include <linuxmt/fcntl.h> #include <linuxmt/timer.h> #include <linuxmt/chqueue.h> #include <linuxmt/signal.h> #include <linuxmt/ntty.h> #include <arch/io.h> #include <arch/irq.h> #include <arch/ports.h> #include <arch/system.h> #include "console.h" static void keyboard_irq(int irq, struct pt_regs *regs); static void set_leds(void); static int kb_read(void); #define ESC 27 /* ascii value for Escape*/ #define SCAN_DEL 0x53 /* scan code for Delete key*/ #define SCAN_F1 0x3B /* scan code for F1 key*/ #define SCAN_KP7 0x47 /* scan code for Keypad 7 key*/ char kbd_name[] = "scan"; /* * Include the relevant keymap. */ #include "KeyMaps/keymaps.h" extern int kraw; /* * Keyboard state - the poor little keyboard controller hasnt * got the brains to remember itself. */ #define SLOCK 0x00 #define LSHIFT 0x01 #define RSHIFT 0x02 #define CTRL 0x04 #define ALT 0x08 #define CAPS 0x10 #define NUM 0x20 #define ALT_GR 0x40 /* shared with alpha 'a'-'l' fnkeys*/ #define EXT 0x80 /* extended scan code, generated by controller*/ #define SSC 0xC0 /* simple scan code*/ static unsigned int ModeState = 0; static int capslock; static int numlock; static int scrlock; /* * Whether we are currently trying to send a command to the keyboard * controller to update the LEDs, and at what stage are we in sending the * command. */ static enum { KS_FREE, KS_SETTING_LED_1, KS_SETTING_LED_2 } kb_cmd_state; static struct timer_list kb_cmd_timer; /* * Table for mapping scancodes >= 0x1C into scan code class. * scancodes < 0x1C are all simple scan codes (SSC). */ static unsigned char tb_state[] = { SSC, CTRL, SSC, SSC, /*1C->1F*/ SSC, SSC, SSC, SSC, SSC, SSC, SSC, SSC, /*20->27*/ SSC, SSC, LSHIFT, SSC, SSC, SSC, SSC, SSC, /*28->2F*/ SSC, SSC, SSC, SSC, SSC, SSC, RSHIFT, SSC, /*30->37*/ ALT, SSC, CAPS, /*38->3A*/ 'a', 'b', 'c', 'd', 'e', /*3B->3F, Function Keys*/ 'f', 'g', 'h', 'i', 'j', /*40->44, Function Keys*/ NUM, SLOCK, SSC, /*45->47*/ SSC, SSC, SSC, SSC, SSC, SSC, SSC, SSC, /*48->4F*/ SSC, SSC, SSC, SSC, SSC, SSC, SSC, 'k', 'l' /*50->58, F11-F12*/ }; #define TB_STATE_MAX (sizeof(tb_state) / sizeof(tb_state[0]) - 1) /* * Map CAPS|ALT|CTL|SHIFT into NORMAL,SHIFT,CAPS,CTL-ALT, * which are used to index into scan_tabs[]. */ static unsigned char state_code[] = { 0, /*0= All status are 0 */ 1, /*1= SHIFT */ 0, /*2= CTRL */ 1, /*3= SHIFT CTRL */ 0, /*4= ALT */ 1, /*5= SHIFT ALT */ 3, /*6= CTRL ALT */ 1, /*7= SHIFT CTRL ALT */ 2, /*8= CAPS */ 2, /*9= CAPS SHIFT */ 0, /*10= CAPS CTRL */ 2, /*11= CAPS SHIFT CTRL */ 0, /*12= CAPS ALT */ 2, /*13= CAPS SHIFT ALT */ 3, /*14= CAPS CTRL ALT */ 3, /*15= CAPS SHIFT CTRL ALT */ }; /* * Map NORMAL,SHIFT,CAPS,CTL-ALT into per-country kbd tables * defined in KeyMaps/keys-xx.h files by config option. */ static unsigned char *scan_tabs[] = { xtkb_scan, /*mode = 0*/ xtkb_scan_shifted, /*mode = 1*/ xtkb_scan_caps, /*mode = 2*/ xtkb_scan_ctrl_alt, /*mode = 3*/ }; void kbd_init(void) { /* Set off the initial keyboard interrupt handler */ flag_t flags; if (request_irq(KBD_IRQ, keyboard_irq, INT_GENERIC)) panic("Unable to get keyboard"); save_flags(flags); clr_irq(); kb_read(); /* discard any unread keyboard input*/ restore_flags(flags); set_leds(); } /* Definitions from MINIX 2*/ /* 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 KBIT 0x80 /* bit used to ack characters to keyboard */ static void kbd_send_cmd(int); /* * XT style keyboard I/O is almost civilised compared * with the monstrosity AT keyboards became. */ static void keyboard_irq(int irq, struct pt_regs *regs) { static int E0Prefix = 0; int code, mode; int E0key = 0; unsigned int key; int keyReleased; /* read XT or AT keyboard*/ code = kb_read(); if (kraw) { Console_conin(code & 255); return; } /*extended keys are preceded by a E0 scancode*/ if (code == 0xE0) { /* Remember this has been received */ E0Prefix = 1; return; } if (E0Prefix) { E0key = 1; E0Prefix = 0; } /* high bit set when key released */ keyReleased = code & 0x80; code &= 0x7F; /* * Three tables and seven steps are used to get from scancode to returned keyboard character: * First, scancode is classified into Status, FnKey, Extended or Simple * directly by value if < 0x1C, or using tb_state[] lookup if >= 0x1C. * Status, FnKey or Extended scan code classes are handled specially. * For simple scan codes, ModeState (CAPS|ALT|CTL|SHIFT) values are used to * index into state_code[] to map state to NORMAL, SHIFT, CAPS or CTL-ALT. * Handle CAPS state processing and caps table zero entries (which use normal/shift tables). * Then, further processing is done to the map state for some special status cases (ALT_GR, NUM and CTL). * The NORMAL,SHIFT,CAPS,CTL-ALT map state is used to index the per-country scan-tabs[] * array to get the keyboard character. * Further process the keyboard character based on special status cases (CTL and ALT). * Finally, if the keyboard character is octal 0260-277, it is converted into an ANSI * function key sequence. */ /* * Step 1: Classify scancode such that * mode = 00xx xxxxB, 0x00 Status key * 01xx xxxxB, 0x40 Function key * 10xx xxxxB, 0x80 Extended scan code * 11xx xxxxB, 0xC0 Simple Scan Code */ if (code >= 0x1C && code - 0x1C <= TB_STATE_MAX) mode = tb_state[code - 0x1C]; /*is key a modifier key?*/ else mode = SSC; /* --------------Process status keys-------------- */ if (!(mode & 0xC0)) { /* Not a simple scancode or fnkey*/ #if defined(CONFIG_KEYMAP_DE) || defined(CONFIG_KEYMAP_SE) || defined(CONFIG_KEYMAP_FR) || defined(CONFIG_KEYMAP_ES) if ((mode == ALT) && E0key) /* ALT_GR has a E0 prefix*/ mode = ALT_GR; #endif if (keyReleased) { switch (mode) { case CAPS: capslock = !capslock; if (capslock) mode = 0; set_leds(); break; case NUM: numlock = !numlock; if (numlock) mode = 0; set_leds(); break; case SLOCK: scrlock = !scrlock; if (scrlock) mode = 0; set_leds(); break; } ModeState &= ~mode; /* key up: clear these and other modes*/ } else ModeState |= mode; /* key down: set mode bit */ /* ModeState updated - now return */ return; } /* no further processing on key release for non-status keys*/ if (keyReleased) return; switch(mode & 0xC0) { /* --------------Handle Function keys-------------- */ case 0x40: /* F1 .. F10*/ /* F11 and F12 function keys need 89 byte table like keys-de.h */ /* function keys are not posix standard here */ /* AltF1-F4 are console switch*/ if ((ModeState & ALT) && code <= SCAN_F1+3) { Console_set_vc(code - SCAN_F1); return; } Console_conin(ESC); /* F1 = ESC a, F2 = ESC b, etc*/ Console_conin(mode); return; /* --------------Handle extended scancodes-------------- */ case 0x80: if (E0key) { /* Is extended scancode? */ mode &= 0x3F; if (mode) { Console_conin(ESC); #ifdef CONFIG_EMUL_ANSI Console_conin('['); #endif } /* Up=0x37 -> ESC [ A, Down=0x38 -> ESC [ B, etc*/ Console_conin(mode + 10); return; } /* fall through*/ default: /* --------------Handle simple scan codes-------------- */ if (code == SCAN_DEL && ((ModeState & (CTRL|ALT)) == (CTRL|ALT))) ctrl_alt_del(); /* Step 2: * Pick the right keymap determined by ModeState bits: * 8 7 6 5 4 3 2 1 0 * SLCK SSC AGR NUM CAPS ALT CTL RS LS * * CAPS|ALT|CTL|RS are shifted right and OR'd with LS, forming * 4-bit entry into state_code[], which maps multiple status keys * (CAPS|ALT|CTL|SHIFT) into into a 2-bit table of per-country tables * which are indexed by (NORMAL,SHIFT,CAPS,CTL-ALT) in scan_tabs[] which * point to the actual keyboard maps, which then have ASCII or octal * values for keys or function keys. */ mode = ((ModeState & (CAPS|ALT|CTRL|RSHIFT)) >> 1) | (ModeState & LSHIFT); mode = state_code[mode]; /* Step 3: * Handle CAPS table specially based on SHIFT status. */ if (mode == 2) { key = *(scan_tabs[2] + code); if(!key) /* zero caps table value means use normal/shift table*/ mode = (ModeState & (RSHIFT|LSHIFT))? 1: 0; /* normal SHIFT for non-CAPS chars*/ else mode = (ModeState & (RSHIFT|LSHIFT))? 0: 2; /* reversed SHIFT for CAPS characters*/ } /* Step 4: * Perform additional special processing for: * ALT_GR -> CTL-ALT * NUM & code >= KP7 -> SHIFT handle 10 keypad when numlock * ALT-code -> code | 0x80 * CTL-code -> code & 0x1f * Zero table entries -> '@' */ if (!mode && (ModeState & ALT_GR)) mode = 3; /* CTRL-ALT-.. */ if ((ModeState & NUM) && code >= SCAN_KP7) { /* 10 key keypad */ if (ModeState & LSHIFT) /* LSHIFT added by controller for arrow keys*/ mode = 0; /* NORMAL for arrow keys*/ else mode = 1; /* SHIFT-.. for keypad keys*/ } /* Step 5: Read the key code from the selected table by mode */ key = *(scan_tabs[mode] + code); /* Step 6: Modify keyboard character based on some special states*/ if ((ModeState & (CTRL|ALT)) == ALT) { /* Alt-1 - Alt-4 are also console switch (for systems w/no fnkeys)*/ if (key >= '1' && key <= '4') { Console_set_vc(key - '1'); return; } /* map Alt-a - Alt-z to ESC A - Z */ if (key >= 'a' && key <= 'z') { Console_conin(ESC); Console_conin(key-'a'+'A'); return; } key |= 0x80; /* ALT-.. (assume codepage is OEM 437) */ } if (!key) /* map zero table entries to '@' */ key = '@'; if ((ModeState & (CTRL|ALT)) == CTRL) key &= 0x1F; /* CTRL-.. */ #ifdef CONFIG_EMUL_ANSI /* Step 7: Convert octal 0260-0277 values to ANSI escape sequences*/ code = mode = 0; switch (key) { /* FIXME need octal func key list*/ case 0270: code = 'A'; break; /* up*/ case 0262: code = 'B'; break; /* down*/ case 0266: code = 'C'; break; /* right*/ case 0264: code = 'D'; break; /* left*/ case 0267: code = 'H'; break; /* home*/ case 0261: code = 'F'; break; /* end*/ case 0272: code = '2'; mode = '~'; break; /* insert*/ case 0271: code = '5'; mode = '~'; break; /* page up*/ case 0263: code = '6'; mode = '~'; break; /* page dn*/ //default: if (key > 127) printk("Unknown key (0%o 0x%x)\n", key, key); } if (code) { Console_conin(ESC); Console_conin('['); Console_conin(code); if (mode) Console_conin(mode); return; } #endif Console_conin(key); } } /* Read keyboard and acknowledge controller */ static int kb_read(void) { int code, mode; code = inb_p(KBD_IO); mode = inb_p(KBD_CTL); outb_p((mode | 0x80), KBD_CTL); outb_p(mode, KBD_CTL); return(code); } static void restart_timer(void); /* Called by the scheduler or keyboard_irq() to send a command to the keyboard controller. IRQs are assumed to be enabled. */ static void kbd_send_cmd(int data) { unsigned char leds; for (;;) { switch (kb_cmd_state) { case KS_SETTING_LED_1: /* poll for buffer empty */ if (inb_p(KB_STATUS) & KB_IN_FULL) { restart_timer(); /* if not, schedule a later poll */ return; } outb_p(LED_CODE, KEYBD); /* prepare keyboard to accept LED values */ kb_cmd_state = KS_SETTING_LED_2; break; case KS_SETTING_LED_2: if (inb_p(KB_STATUS) & KB_IN_FULL) { restart_timer(); return; } /* encode LED bits */ leds = scrlock | (numlock << 1) | (capslock << 2); outb_p(leds, KEYBD); /* give keyboard LED values */ kb_cmd_state = KS_FREE; default: return; } } } /* Arrange to call kbd_send_cmd() after a short period of time. */ static void restart_timer(void) { del_timer(&kb_cmd_timer); /* required in case set_leds called before expiration*/ kb_cmd_timer.tl_expires = jiffies + (2 * HZ/100); /* every 2/100 second*/ kb_cmd_timer.tl_function = kbd_send_cmd; add_timer(&kb_cmd_timer); } /* Set the LEDs on the caps, num, and scroll lock keys. IRQs are assumed to be enabled. */ static void set_leds(void) { flag_t flags; if (!(sys_caps & CAP_KBD_LEDS)) return; /* PC/XT doesn't have LEDs */ save_flags(flags); clr_irq(); if (kb_cmd_state == KS_FREE) { /* if already in the middle of setting LEDs, then nothing to do; otherwise, schedule a timer event to to set LEDs */ kb_cmd_state = KS_SETTING_LED_1; restart_timer(); } restore_flags(flags); }
Commit message
This repository is read-only for this account.
Repository snapshot
Current branch
master
Visibility
public
Your access
Read
Remote
Configured
File activity
View file history