From fa2e9866deadfef5fee1ddcaf8aca06b566dcf92 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 17 Apr 2018 20:13:28 +0800 Subject: [PATCH] Keyboard working. Link C code from xv6 x86_64. --- build.rs | 1 + src/arch/x86_64/driver/keyboard/keyboard.c | 165 ++++++++++++++++++ .../driver/{keyboard.rs => keyboard/mod.rs} | 8 + src/arch/x86_64/interrupt/irq.rs | 5 +- 4 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 src/arch/x86_64/driver/keyboard/keyboard.c rename src/arch/x86_64/driver/{keyboard.rs => keyboard/mod.rs} (66%) diff --git a/build.rs b/build.rs index f1fd01a..ee557b4 100644 --- a/build.rs +++ b/build.rs @@ -3,5 +3,6 @@ extern crate cc; fn main() { cc::Build::new() .file("src/arch/x86_64/driver/apic/lapic.c") + .file("src/arch/x86_64/driver/keyboard/keyboard.c") .compile("cobj"); } \ No newline at end of file diff --git a/src/arch/x86_64/driver/keyboard/keyboard.c b/src/arch/x86_64/driver/keyboard/keyboard.c new file mode 100644 index 0000000..d8b75ff --- /dev/null +++ b/src/arch/x86_64/driver/keyboard/keyboard.c @@ -0,0 +1,165 @@ +// xv6 x86_64 kbd.c + +// PC keyboard interface constants + +#define KBSTATP 0x64 // kbd controller status port(I) +#define KBS_DIB 0x01 // kbd data in buffer +#define KBDATAP 0x60 // kbd data port(I) + +#define NO 0 + +#define SHIFT (1<<0) +#define CTL (1<<1) +#define ALT (1<<2) + +#define CAPSLOCK (1<<3) +#define NUMLOCK (1<<4) +#define SCROLLLOCK (1<<5) + +#define E0ESC (1<<6) + +// Special keycodes +#define KEY_HOME 0xE0 +#define KEY_END 0xE1 +#define KEY_UP 0xE2 +#define KEY_DN 0xE3 +#define KEY_LF 0xE4 +#define KEY_RT 0xE5 +#define KEY_PGUP 0xE6 +#define KEY_PGDN 0xE7 +#define KEY_INS 0xE8 +#define KEY_DEL 0xE9 + +// C('A') == Control-A +#define C(x) (x - '@') + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +static inline uchar +inb(ushort port) +{ + uchar data; + + asm volatile("in %1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static uchar shiftcode[256] = + { + [0x1D] = CTL, + [0x2A] = SHIFT, + [0x36] = SHIFT, + [0x38] = ALT, + [0x9D] = CTL, + [0xB8] = ALT + }; + +static uchar togglecode[256] = + { + [0x3A] = CAPSLOCK, + [0x45] = NUMLOCK, + [0x46] = SCROLLLOCK + }; + +static uchar normalmap[256] = + { + NO, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00 + '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10 + 'o', 'p', '[', ']', '\n', NO, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20 + '\'', '`', NO, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', NO, '*', // 0x30 + NO, ' ', NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, '7', // 0x40 + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', NO, NO, NO, NO, // 0x50 + [0x9C] = '\n', // KP_Enter + [0xB5] = '/', // KP_Div + [0xC8] = KEY_UP, [0xD0] = KEY_DN, + [0xC9] = KEY_PGUP, [0xD1] = KEY_PGDN, + [0xCB] = KEY_LF, [0xCD] = KEY_RT, + [0x97] = KEY_HOME, [0xCF] = KEY_END, + [0xD2] = KEY_INS, [0xD3] = KEY_DEL + }; + +static uchar shiftmap[256] = + { + NO, 033, '!', '@', '#', '$', '%', '^', // 0x00 + '&', '*', '(', ')', '_', '+', '\b', '\t', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10 + 'O', 'P', '{', '}', '\n', NO, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20 + '"', '~', NO, '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', NO, '*', // 0x30 + NO, ' ', NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, '7', // 0x40 + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', NO, NO, NO, NO, // 0x50 + [0x9C] = '\n', // KP_Enter + [0xB5] = '/', // KP_Div + [0xC8] = KEY_UP, [0xD0] = KEY_DN, + [0xC9] = KEY_PGUP, [0xD1] = KEY_PGDN, + [0xCB] = KEY_LF, [0xCD] = KEY_RT, + [0x97] = KEY_HOME, [0xCF] = KEY_END, + [0xD2] = KEY_INS, [0xD3] = KEY_DEL + }; + +static uchar ctlmap[256] = + { + NO, NO, NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, NO, + C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'), + C('O'), C('P'), NO, NO, '\r', NO, C('A'), C('S'), + C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), NO, + NO, NO, NO, C('\\'), C('Z'), C('X'), C('C'), C('V'), + C('B'), C('N'), C('M'), NO, NO, C('/'), NO, NO, + [0x9C] = '\r', // KP_Enter + [0xB5] = C('/'), // KP_Div + [0xC8] = KEY_UP, [0xD0] = KEY_DN, + [0xC9] = KEY_PGUP, [0xD1] = KEY_PGDN, + [0xCB] = KEY_LF, [0xCD] = KEY_RT, + [0x97] = KEY_HOME, [0xCF] = KEY_END, + [0xD2] = KEY_INS, [0xD3] = KEY_DEL + }; + +int +kbdgetc(void) { + static uint shift; + static uchar *charcode[4] = { + normalmap, shiftmap, ctlmap, ctlmap + }; + uint st, data, c; + + st = inb(KBSTATP); + if ((st & KBS_DIB) == 0) + return -1; + data = inb(KBDATAP); + + if (data == 0xE0) { + shift |= E0ESC; + return 0; + } else if (data & 0x80) { + // Key released + data = (shift & E0ESC ? data : data & 0x7F); + shift &= ~(shiftcode[data] | E0ESC); + return 0; + } else if (shift & E0ESC) { + // Last character was an E0 escape; or with 0x80 + data |= 0x80; + shift &= ~E0ESC; + } + + shift |= shiftcode[data]; + shift ^= togglecode[data]; + c = charcode[shift & (CTL | SHIFT)][data]; + if (shift & CAPSLOCK) { + if ('a' <= c && c <= 'z') + c += 'A' - 'a'; + else if ('A' <= c && c <= 'Z') + c += 'a' - 'A'; + } + return c; +} \ No newline at end of file diff --git a/src/arch/x86_64/driver/keyboard.rs b/src/arch/x86_64/driver/keyboard/mod.rs similarity index 66% rename from src/arch/x86_64/driver/keyboard.rs rename to src/arch/x86_64/driver/keyboard/mod.rs index cb44a0b..d922bea 100644 --- a/src/arch/x86_64/driver/keyboard.rs +++ b/src/arch/x86_64/driver/keyboard/mod.rs @@ -4,4 +4,12 @@ pub fn init() { use consts::irq::*; use arch::interrupt::enable_irq; enable_irq(IRQ_KBD); +} + +pub fn get() -> i32 { + unsafe{ kbdgetc() } +} + +extern { + fn kbdgetc() -> i32; } \ No newline at end of file diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index 7de145a..0780344 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -30,7 +30,10 @@ use consts::irq::*; pub extern "x86-interrupt" fn keyboard_handler( stack_frame: &mut ExceptionStackFrame) { - println!("\nInterupt: Keyboard \n{:#?}", stack_frame); + use arch::driver::keyboard; + println!("\nInterupt: Keyboard"); + let c = keyboard::get(); + println!("Key = '{}' {}", c as u8 as char, c); ack(IRQ_KBD); }