فهرست منبع

lesson 20, keyboard

Carlos 10 سال پیش
والد
کامیت
6e5a09981a

+ 17 - 1
20-interrupts-timer/README.md

@@ -1,4 +1,4 @@
-*Concepts you may want to Google beforehand: CPU timer, keyboard interrupts*
+*Concepts you may want to Google beforehand: CPU timer, keyboard interrupts, scancode*
 
 **Goal: Implement our first IRQ handlers: the CPU timer and the keyboard**
 
@@ -18,3 +18,19 @@ Finally, go back to the `kernel/kernel.c` and do two things. Enable interrupts a
 (very important!) and then initialize the timer interrupt.
 
 Go `make run` and you'll see the clock ticking!
+
+
+Keyboard
+--------
+
+The keyboard is even easier, with a drawback. The PIC does not send us the ASCII code
+for the pressed key, but the scancode for the key-down and the key-up events, so we
+will need to translate those.
+
+Check out `drivers/keyboard.c` where there are two functions: the callback and
+the initialization which configures the interrupt callback. A new `keyboard.h` was
+created with the definitions.
+
+`keyboard.c` also has a long table to translate scancodes to ASCII keys. For the time
+being, we will only implement a simple subset of the US keyboard. You can read
+more [about scancodes here](http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html)

+ 0 - 17
20-interrupts-timer/cpu/idt.c

@@ -1,17 +0,0 @@
-#include "idt.h"
-#include "../kernel/util.h"
-
-void set_idt_gate(int n, u32 handler) {
-    idt[n].low_offset = low_16(handler);
-    idt[n].sel = KERNEL_CS;
-    idt[n].always0 = 0;
-    idt[n].flags = 0x8E; 
-    idt[n].high_offset = high_16(handler);
-}
-
-void set_idt() {
-    idt_reg.base = (u32) &idt;
-    idt_reg.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
-    /* Don't make the mistake of loading &idt -- always load &idt_reg */
-    __asm__ __volatile__("lidtl (%0)" : : "r" (&idt_reg));
-}

+ 1 - 0
20-interrupts-timer/cpu/idt.c

@@ -0,0 +1 @@
+../../19-interrupts-irqs/cpu/idt.c

+ 0 - 39
20-interrupts-timer/cpu/idt.h

@@ -1,39 +0,0 @@
-#ifndef IDT_H
-#define IDT_H
-
-#include "types.h"
-
-/* Segment selectors */
-#define KERNEL_CS 0x08
-
-/* How every interrupt gate (handler) is defined */
-typedef struct {
-    u16 low_offset; /* Lower 16 bits of handler function address */
-    u16 sel; /* Kernel segment selector */
-    u8 always0;
-    /* First byte
-     * Bit 7: "Interrupt is present"
-     * Bits 6-5: Privilege level of caller (0=kernel..3=user)
-     * Bit 4: Set to 0 for interrupt gates
-     * Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
-    u8 flags; 
-    u16 high_offset; /* Higher 16 bits of handler function address */
-} __attribute__((packed)) idt_gate_t ;
-
-/* A pointer to the array of interrupt handlers.
- * Assembly instruction 'lidt' will read it */
-typedef struct {
-    u16 limit;
-    u32 base;
-} __attribute__((packed)) idt_register_t;
-
-#define IDT_ENTRIES 256
-idt_gate_t idt[IDT_ENTRIES];
-idt_register_t idt_reg;
-
-
-/* Functions implemented in idt.c */
-void set_idt_gate(int n, u32 handler);
-void set_idt();
-
-#endif

+ 1 - 0
20-interrupts-timer/cpu/idt.h

@@ -0,0 +1 @@
+../../19-interrupts-irqs/cpu/idt.h

+ 0 - 425
20-interrupts-timer/cpu/interrupt.asm

@@ -1,425 +0,0 @@
-; Defined in isr.c
-[extern isr_handler]
-[extern irq_handler]
-
-; Common ISR code
-isr_common_stub:
-    ; 1. Save CPU state
-	pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
-	mov ax, ds ; Lower 16-bits of eax = ds.
-	push eax ; save the data segment descriptor
-	mov ax, 0x10  ; kernel data segment descriptor
-	mov ds, ax
-	mov es, ax
-	mov fs, ax
-	mov gs, ax
-	
-    ; 2. Call C handler
-	call isr_handler
-	
-    ; 3. Restore state
-	pop eax 
-	mov ds, ax
-	mov es, ax
-	mov fs, ax
-	mov gs, ax
-	popa
-	add esp, 8 ; Cleans up the pushed error code and pushed ISR number
-	sti
-	iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
-
-; Common IRQ code. Identical to ISR code except for the 'call' 
-; and the 'pop ebx'
-irq_common_stub:
-    pusha 
-    mov ax, ds
-    push eax
-    mov ax, 0x10
-    mov ds, ax
-    mov es, ax
-    mov fs, ax
-    mov gs, ax
-    call irq_handler ; Different than the ISR code
-    pop ebx  ; Different than the ISR code
-    mov ds, bx
-    mov es, bx
-    mov fs, bx
-    mov gs, bx
-    popa
-    add esp, 8
-    sti
-    iret 
-	
-; We don't get information about which interrupt was caller
-; when the handler is run, so we will need to have a different handler
-; for every interrupt.
-; Furthermore, some interrupts push an error code onto the stack but others
-; don't, so we will push a dummy error code for those which don't, so that
-; we have a consistent stack for all of them.
-
-; First make the ISRs global
-global isr0
-global isr1
-global isr2
-global isr3
-global isr4
-global isr5
-global isr6
-global isr7
-global isr8
-global isr9
-global isr10
-global isr11
-global isr12
-global isr13
-global isr14
-global isr15
-global isr16
-global isr17
-global isr18
-global isr19
-global isr20
-global isr21
-global isr22
-global isr23
-global isr24
-global isr25
-global isr26
-global isr27
-global isr28
-global isr29
-global isr30
-global isr31
-; IRQs
-global irq0
-global irq1
-global irq2
-global irq3
-global irq4
-global irq5
-global irq6
-global irq7
-global irq8
-global irq9
-global irq10
-global irq11
-global irq12
-global irq13
-global irq14
-global irq15
-
-; 0: Divide By Zero Exception
-isr0:
-    cli
-    push byte 0
-    push byte 0
-    jmp isr_common_stub
-
-; 1: Debug Exception
-isr1:
-    cli
-    push byte 0
-    push byte 1
-    jmp isr_common_stub
-
-; 2: Non Maskable Interrupt Exception
-isr2:
-    cli
-    push byte 0
-    push byte 2
-    jmp isr_common_stub
-
-; 3: Int 3 Exception
-isr3:
-    cli
-    push byte 0
-    push byte 3
-    jmp isr_common_stub
-
-; 4: INTO Exception
-isr4:
-    cli
-    push byte 0
-    push byte 4
-    jmp isr_common_stub
-
-; 5: Out of Bounds Exception
-isr5:
-    cli
-    push byte 0
-    push byte 5
-    jmp isr_common_stub
-
-; 6: Invalid Opcode Exception
-isr6:
-    cli
-    push byte 0
-    push byte 6
-    jmp isr_common_stub
-
-; 7: Coprocessor Not Available Exception
-isr7:
-    cli
-    push byte 0
-    push byte 7
-    jmp isr_common_stub
-
-; 8: Double Fault Exception (With Error Code!)
-isr8:
-    cli
-    push byte 8
-    jmp isr_common_stub
-
-; 9: Coprocessor Segment Overrun Exception
-isr9:
-    cli
-    push byte 0
-    push byte 9
-    jmp isr_common_stub
-
-; 10: Bad TSS Exception (With Error Code!)
-isr10:
-    cli
-    push byte 10
-    jmp isr_common_stub
-
-; 11: Segment Not Present Exception (With Error Code!)
-isr11:
-    cli
-    push byte 11
-    jmp isr_common_stub
-
-; 12: Stack Fault Exception (With Error Code!)
-isr12:
-    cli
-    push byte 12
-    jmp isr_common_stub
-
-; 13: General Protection Fault Exception (With Error Code!)
-isr13:
-    cli
-    push byte 13
-    jmp isr_common_stub
-
-; 14: Page Fault Exception (With Error Code!)
-isr14:
-    cli
-    push byte 14
-    jmp isr_common_stub
-
-; 15: Reserved Exception
-isr15:
-    cli
-    push byte 0
-    push byte 15
-    jmp isr_common_stub
-
-; 16: Floating Point Exception
-isr16:
-    cli
-    push byte 0
-    push byte 16
-    jmp isr_common_stub
-
-; 17: Alignment Check Exception
-isr17:
-    cli
-    push byte 0
-    push byte 17
-    jmp isr_common_stub
-
-; 18: Machine Check Exception
-isr18:
-    cli
-    push byte 0
-    push byte 18
-    jmp isr_common_stub
-
-; 19: Reserved
-isr19:
-    cli
-    push byte 0
-    push byte 19
-    jmp isr_common_stub
-
-; 20: Reserved
-isr20:
-    cli
-    push byte 0
-    push byte 20
-    jmp isr_common_stub
-
-; 21: Reserved
-isr21:
-    cli
-    push byte 0
-    push byte 21
-    jmp isr_common_stub
-
-; 22: Reserved
-isr22:
-    cli
-    push byte 0
-    push byte 22
-    jmp isr_common_stub
-
-; 23: Reserved
-isr23:
-    cli
-    push byte 0
-    push byte 23
-    jmp isr_common_stub
-
-; 24: Reserved
-isr24:
-    cli
-    push byte 0
-    push byte 24
-    jmp isr_common_stub
-
-; 25: Reserved
-isr25:
-    cli
-    push byte 0
-    push byte 25
-    jmp isr_common_stub
-
-; 26: Reserved
-isr26:
-    cli
-    push byte 0
-    push byte 26
-    jmp isr_common_stub
-
-; 27: Reserved
-isr27:
-    cli
-    push byte 0
-    push byte 27
-    jmp isr_common_stub
-
-; 28: Reserved
-isr28:
-    cli
-    push byte 0
-    push byte 28
-    jmp isr_common_stub
-
-; 29: Reserved
-isr29:
-    cli
-    push byte 0
-    push byte 29
-    jmp isr_common_stub
-
-; 30: Reserved
-isr30:
-    cli
-    push byte 0
-    push byte 30
-    jmp isr_common_stub
-
-; 31: Reserved
-isr31:
-    cli
-    push byte 0
-    push byte 31
-    jmp isr_common_stub
-
-; IRQ handlers
-irq0:
-	cli
-	push byte 0
-	push byte 32
-	jmp irq_common_stub
-
-irq1:
-	cli
-	push byte 1
-	push byte 33
-	jmp irq_common_stub
-
-irq2:
-	cli
-	push byte 2
-	push byte 34
-	jmp irq_common_stub
-
-irq3:
-	cli
-	push byte 3
-	push byte 35
-	jmp irq_common_stub
-
-irq4:
-	cli
-	push byte 4
-	push byte 36
-	jmp irq_common_stub
-
-irq5:
-	cli
-	push byte 5
-	push byte 37
-	jmp irq_common_stub
-
-irq6:
-	cli
-	push byte 6
-	push byte 38
-	jmp irq_common_stub
-
-irq7:
-	cli
-	push byte 7
-	push byte 39
-	jmp irq_common_stub
-
-irq8:
-	cli
-	push byte 8
-	push byte 40
-	jmp irq_common_stub
-
-irq9:
-	cli
-	push byte 9
-	push byte 41
-	jmp irq_common_stub
-
-irq10:
-	cli
-	push byte 10
-	push byte 42
-	jmp irq_common_stub
-
-irq11:
-	cli
-	push byte 11
-	push byte 43
-	jmp irq_common_stub
-
-irq12:
-	cli
-	push byte 12
-	push byte 44
-	jmp irq_common_stub
-
-irq13:
-	cli
-	push byte 13
-	push byte 45
-	jmp irq_common_stub
-
-irq14:
-	cli
-	push byte 14
-	push byte 46
-	jmp irq_common_stub
-
-irq15:
-	cli
-	push byte 15
-	push byte 47
-	jmp irq_common_stub
-

+ 1 - 0
20-interrupts-timer/cpu/interrupt.asm

@@ -0,0 +1 @@
+../../19-interrupts-irqs/cpu/interrupt.asm

+ 0 - 140
20-interrupts-timer/cpu/isr.c

@@ -1,140 +0,0 @@
-#include "isr.h"
-#include "idt.h"
-#include "../drivers/screen.h"
-#include "../kernel/util.h"
-#include "../drivers/ports.h"
-
-isr_t interrupt_handlers[256];
-
-/* Can't do this with a loop because we need the address
- * of the function names */
-void isr_install() {
-    set_idt_gate(0, (u32)isr0);
-    set_idt_gate(1, (u32)isr1);
-    set_idt_gate(2, (u32)isr2);
-    set_idt_gate(3, (u32)isr3);
-    set_idt_gate(4, (u32)isr4);
-    set_idt_gate(5, (u32)isr5);
-    set_idt_gate(6, (u32)isr6);
-    set_idt_gate(7, (u32)isr7);
-    set_idt_gate(8, (u32)isr8);
-    set_idt_gate(9, (u32)isr9);
-    set_idt_gate(10, (u32)isr10);
-    set_idt_gate(11, (u32)isr11);
-    set_idt_gate(12, (u32)isr12);
-    set_idt_gate(13, (u32)isr13);
-    set_idt_gate(14, (u32)isr14);
-    set_idt_gate(15, (u32)isr15);
-    set_idt_gate(16, (u32)isr16);
-    set_idt_gate(17, (u32)isr17);
-    set_idt_gate(18, (u32)isr18);
-    set_idt_gate(19, (u32)isr19);
-    set_idt_gate(20, (u32)isr20);
-    set_idt_gate(21, (u32)isr21);
-    set_idt_gate(22, (u32)isr22);
-    set_idt_gate(23, (u32)isr23);
-    set_idt_gate(24, (u32)isr24);
-    set_idt_gate(25, (u32)isr25);
-    set_idt_gate(26, (u32)isr26);
-    set_idt_gate(27, (u32)isr27);
-    set_idt_gate(28, (u32)isr28);
-    set_idt_gate(29, (u32)isr29);
-    set_idt_gate(30, (u32)isr30);
-    set_idt_gate(31, (u32)isr31);
-
-    // Remap the PIC
-    port_byte_out(0x20, 0x11);
-    port_byte_out(0xA0, 0x11);
-    port_byte_out(0x21, 0x20);
-    port_byte_out(0xA1, 0x28);
-    port_byte_out(0x21, 0x04);
-    port_byte_out(0xA1, 0x02);
-    port_byte_out(0x21, 0x01);
-    port_byte_out(0xA1, 0x01);
-    port_byte_out(0x21, 0x0);
-    port_byte_out(0xA1, 0x0); 
-
-    // Install the IRQs
-    set_idt_gate(32, (u32)irq0);
-    set_idt_gate(33, (u32)irq1);
-    set_idt_gate(34, (u32)irq2);
-    set_idt_gate(35, (u32)irq3);
-    set_idt_gate(36, (u32)irq4);
-    set_idt_gate(37, (u32)irq5);
-    set_idt_gate(38, (u32)irq6);
-    set_idt_gate(39, (u32)irq7);
-    set_idt_gate(40, (u32)irq8);
-    set_idt_gate(41, (u32)irq9);
-    set_idt_gate(42, (u32)irq10);
-    set_idt_gate(43, (u32)irq11);
-    set_idt_gate(44, (u32)irq12);
-    set_idt_gate(45, (u32)irq13);
-    set_idt_gate(46, (u32)irq14);
-    set_idt_gate(47, (u32)irq15);
-
-    set_idt(); // Load with ASM
-}
-
-/* To print the message which defines every exception */
-char *exception_messages[] = {
-    "Division By Zero",
-    "Debug",
-    "Non Maskable Interrupt",
-    "Breakpoint",
-    "Into Detected Overflow",
-    "Out of Bounds",
-    "Invalid Opcode",
-    "No Coprocessor",
-
-    "Double Fault",
-    "Coprocessor Segment Overrun",
-    "Bad TSS",
-    "Segment Not Present",
-    "Stack Fault",
-    "General Protection Fault",
-    "Page Fault",
-    "Unknown Interrupt",
-
-    "Coprocessor Fault",
-    "Alignment Check",
-    "Machine Check",
-    "Reserved",
-    "Reserved",
-    "Reserved",
-    "Reserved",
-    "Reserved",
-
-    "Reserved",
-    "Reserved",
-    "Reserved",
-    "Reserved",
-    "Reserved",
-    "Reserved",
-    "Reserved",
-    "Reserved"
-};
-
-void isr_handler(registers_t r) {
-    kprint("received interrupt: ");
-    char s[3];
-    int_to_ascii(r.int_no, s);
-    kprint(s);
-    kprint("\n");
-    kprint(exception_messages[r.int_no]);
-    kprint("\n");
-}
-
-void register_interrupt_handler(u8 n, isr_t handler) {
-    interrupt_handlers[n] = handler;
-}
-
-void irq_handler(registers_t r) {
-    /* If the irq involves the slave (IRQ > 7), send an EOI to it */
-    if (r.int_no >= 40) port_byte_out(0xA0, 0x20);
-    port_byte_out(0x20, 0x20); /* Send EOI to master */
-    /* Handle the interrupt in a more modular way */
-    if (interrupt_handlers[r.int_no] != 0) {
-        isr_t handler = interrupt_handlers[r.int_no];
-        handler(r);
-    }
-}

+ 1 - 0
20-interrupts-timer/cpu/isr.c

@@ -0,0 +1 @@
+../../19-interrupts-irqs/cpu/isr.c

+ 0 - 88
20-interrupts-timer/cpu/isr.h

@@ -1,88 +0,0 @@
-#ifndef ISR_H
-#define ISR_H
-
-#include "types.h"
-
-/* ISRs reserved for CPU exceptions */
-extern void isr0();
-extern void isr1();
-extern void isr2();
-extern void isr3();
-extern void isr4();
-extern void isr5();
-extern void isr6();
-extern void isr7();
-extern void isr8();
-extern void isr9();
-extern void isr10();
-extern void isr11();
-extern void isr12();
-extern void isr13();
-extern void isr14();
-extern void isr15();
-extern void isr16();
-extern void isr17();
-extern void isr18();
-extern void isr19();
-extern void isr20();
-extern void isr21();
-extern void isr22();
-extern void isr23();
-extern void isr24();
-extern void isr25();
-extern void isr26();
-extern void isr27();
-extern void isr28();
-extern void isr29();
-extern void isr30();
-extern void isr31();
-/* IRQ definitions */
-extern void irq0();
-extern void irq1();
-extern void irq2();
-extern void irq3();
-extern void irq4();
-extern void irq5();
-extern void irq6();
-extern void irq7();
-extern void irq8();
-extern void irq9();
-extern void irq10();
-extern void irq11();
-extern void irq12();
-extern void irq13();
-extern void irq14();
-extern void irq15();
-
-#define IRQ0 32
-#define IRQ1 33
-#define IRQ2 34
-#define IRQ3 35
-#define IRQ4 36
-#define IRQ5 37
-#define IRQ6 38
-#define IRQ7 39
-#define IRQ8 40
-#define IRQ9 41
-#define IRQ10 42
-#define IRQ11 43
-#define IRQ12 44
-#define IRQ13 45
-#define IRQ14 46
-#define IRQ15 47
-
-/* Struct which aggregates many registers */
-typedef struct {
-   u32 ds; /* Data segment selector */
-   u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
-   u32 int_no, err_code; /* Interrupt number and error code (if applicable) */
-   u32 eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
-} registers_t;
-
-void isr_install();
-void isr_handler(registers_t r);
-
-typedef void (*isr_t)(registers_t);
-void register_interrupt_handler(u8 n, isr_t handler);
-
-#endif

+ 1 - 0
20-interrupts-timer/cpu/isr.h

@@ -0,0 +1 @@
+../../19-interrupts-irqs/cpu/isr.h

+ 0 - 16
20-interrupts-timer/cpu/types.h

@@ -1,16 +0,0 @@
-#ifndef TYPES_H
-#define TYPES_H
-
-/* Instead of using 'chars' to allocate non-character bytes,
- * we will use these new type with no semantic meaning */
-typedef unsigned int   u32;
-typedef          int   s32;
-typedef unsigned short u16;
-typedef          short s16;
-typedef unsigned char  u8;
-typedef          char  s8;
-
-#define low_16(address) (u16)((address) & 0xFFFF)
-#define high_16(address) (u16)(((address) >> 16) & 0xFFFF)
-
-#endif

+ 1 - 0
20-interrupts-timer/cpu/types.h

@@ -0,0 +1 @@
+../../19-interrupts-irqs/cpu/types.h

+ 208 - 0
20-interrupts-timer/drivers/keyboard.c

@@ -0,0 +1,208 @@
+#include "keyboard.h"
+#include "ports.h"
+#include "../cpu/isr.h"
+#include "screen.h"
+
+static void keyboard_callback(registers_t regs) {
+    /* The PIC leaves us the scancode in port 0x60 */
+    u8 scancode = port_byte_in(0x60);
+    char *sc_ascii;
+    int_to_ascii(scancode, sc_ascii);
+    kprint("Keyboard scancode: ");
+    kprint(sc_ascii);
+    kprint(", ");
+    print_letter(scancode);
+    kprint("\n");
+}
+
+void init_keyboard() {
+   register_interrupt_handler(IRQ1, keyboard_callback); 
+}
+
+void print_letter(u8 scancode) {
+    switch (scancode) {
+        case 0x0:
+            kprint("ERROR");
+            break;
+        case 0x1:
+            kprint("ESC");
+            break;
+        case 0x2:
+            kprint("1");
+            break;
+        case 0x3:
+            kprint("2");
+            break;
+        case 0x4:
+            kprint("3");
+            break;
+        case 0x5:
+            kprint("4");
+            break;
+        case 0x6:
+            kprint("5");
+            break;
+        case 0x7:
+            kprint("6");
+            break;
+        case 0x8:
+            kprint("7");
+            break;
+        case 0x9:
+            kprint("8");
+            break;
+        case 0x0A:
+            kprint("9");
+            break;
+        case 0x0B:
+            kprint("0");
+            break;
+        case 0x0C:
+            kprint("-");
+            break;
+        case 0x0D:
+            kprint("+");
+            break;
+        case 0x0E:
+            kprint("Backspace");
+            break;
+        case 0x0F:
+            kprint("Tab");
+            break;
+        case 0x10:
+            kprint("Q");
+            break;
+        case 0x11:
+            kprint("W");
+            break;
+        case 0x12:
+            kprint("E");
+            break;
+        case 0x13:
+            kprint("R");
+            break;
+        case 0x14:
+            kprint("T");
+            break;
+        case 0x15:
+            kprint("Y");
+            break;
+        case 0x16:
+            kprint("U");
+            break;
+        case 0x17:
+            kprint("I");
+            break;
+        case 0x18:
+            kprint("O");
+            break;
+        case 0x19:
+            kprint("P");
+            break;
+		case 0x1A:
+			kprint("[");
+			break;
+		case 0x1B:
+			kprint("]");
+			break;
+		case 0x1C:
+			kprint("ENTER");
+			break;
+		case 0x1D:
+			kprint("LCtrl");
+			break;
+		case 0x1E:
+			kprint("A");
+			break;
+		case 0x1F:
+			kprint("S");
+			break;
+        case 0x20:
+            kprint("D");
+            break;
+        case 0x21:
+            kprint("F");
+            break;
+        case 0x22:
+            kprint("G");
+            break;
+        case 0x23:
+            kprint("H");
+            break;
+        case 0x24:
+            kprint("J");
+            break;
+        case 0x25:
+            kprint("K");
+            break;
+        case 0x26:
+            kprint("L");
+            break;
+        case 0x27:
+            kprint(";");
+            break;
+        case 0x28:
+            kprint("'");
+            break;
+        case 0x29:
+            kprint("`");
+            break;
+		case 0x2A:
+			kprint("LShift");
+			break;
+		case 0x2B:
+			kprint("\\");
+			break;
+		case 0x2C:
+			kprint("Z");
+			break;
+		case 0x2D:
+			kprint("X");
+			break;
+		case 0x2E:
+			kprint("C");
+			break;
+		case 0x2F:
+			kprint("V");
+			break;
+        case 0x30:
+            kprint("B");
+            break;
+        case 0x31:
+            kprint("N");
+            break;
+        case 0x32:
+            kprint("M");
+            break;
+        case 0x33:
+            kprint(",");
+            break;
+        case 0x34:
+            kprint(".");
+            break;
+        case 0x35:
+            kprint("/");
+            break;
+        case 0x36:
+            kprint("Rshift");
+            break;
+        case 0x37:
+            kprint("Keypad *");
+            break;
+        case 0x38:
+            kprint("LAlt");
+            break;
+        case 0x39:
+            kprint("Spc");
+            break;
+        default:
+            /* 'keuyp' event corresponds to the 'keydown' + 0x80 
+             * it may still be a scancode we haven't implemented yet */
+            if (scancode - 0x80 <= 0x39) {
+                kprint("key up ");
+                print_letter(scancode - 0x80);
+            } else kprint("Unknown");
+            break;
+    }
+}
+

+ 3 - 0
20-interrupts-timer/drivers/keyboard.h

@@ -0,0 +1,3 @@
+#include "../cpu/types.h"
+
+void init_keyboard();

+ 5 - 1
20-interrupts-timer/kernel/kernel.c

@@ -1,9 +1,13 @@
 #include "../cpu/isr.h"
 #include "../cpu/timer.h"
+#include "../drivers/keyboard.h"
 
 void main() {
     isr_install();
 
     asm volatile("sti");
-    init_timer(50);
+//    init_timer(50);
+    /* Comment out the timer IRQ handler to read
+     * the keyboard IRQs easier */
+    init_keyboard();
 }