Skip to content

Commit

Permalink
drivers: basic keyboard support
Browse files Browse the repository at this point in the history
Basic keyboard support with PIC interrupt

Signed-off-by: Daniele Ahmed <ahmeddan 2 amazon ;com>
  • Loading branch information
82marbag authored and wipawel committed Nov 10, 2020
1 parent 21acd67 commit 6e57181
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 5 deletions.
1 change: 1 addition & 0 deletions arch/x86/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ END_FUNC(handle_exception)

interrupt_handler pit pit_interrupt_handler
interrupt_handler uart uart_interrupt_handler
interrupt_handler keyboard keyboard_interrupt_handler

ENTRY(usermode_call_asm)
/* FIXME: Add 32-bit support */
Expand Down
4 changes: 4 additions & 0 deletions arch/x86/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <console.h>
#include <drivers/pit.h>
#include <drivers/serial.h>
#include <drivers/keyboard.h>
#include <ktf.h>
#include <lib.h>
#include <percpu.h>
Expand All @@ -40,6 +41,7 @@

extern void asm_interrupt_handler_uart(void);
extern void asm_interrupt_handler_pit(void);
extern void asm_interrupt_handler_keyboard(void);

static void ret2kern_handler(void) {
/* clang-format off */
Expand Down Expand Up @@ -160,6 +162,8 @@ void init_traps(unsigned int cpu) {
_ul(asm_interrupt_handler_uart), GATE_DPL0, GATE_PRESENT, 0);
set_intr_gate(&percpu->idt[PIT_IRQ0_OFFSET], __KERN_CS,
_ul(asm_interrupt_handler_pit), GATE_DPL0, GATE_PRESENT, 0);
set_intr_gate(&percpu->idt[KEYBOARD_IRQ0_OFFSET], __KERN_CS,
_ul(asm_interrupt_handler_keyboard), GATE_DPL0, GATE_PRESENT, 0);

barrier();
lidt(&percpu->idt_ptr);
Expand Down
8 changes: 8 additions & 0 deletions common/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <console.h>
#include <drivers/keyboard.h>
#include <ktf.h>
#include <lib.h>
#include <multiboot.h>
Expand All @@ -40,6 +41,13 @@ int usermode_call(user_func_t fn, void *fn_arg) {
PERCPU_OFFSET(user_stack));
}

static void echo_loop(void) {
while (1) {
io_delay();
keyboard_process_keys();
}
}

void kernel_main(void) {
printk("\nKTF - Kernel Test Framework!\n\n");

Expand Down
4 changes: 4 additions & 0 deletions common/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <console.h>
#include <cpuid.h>
#include <ioapic.h>
#include <drivers/keyboard.h>
#include <ktf.h>
#include <lib.h>
#include <multiboot.h>
Expand Down Expand Up @@ -235,6 +236,9 @@ void __noreturn __text_init kernel_start(uint32_t multiboot_magic,
/* Initialize Programmable Interrupt Timer */
init_pit(get_bsp_cpu_id());

/* Initialize keyboard */
init_keyboard();

/* Jump from .text.init section to .text */
asm volatile("push %0; ret" ::"r"(&kernel_main));

Expand Down
115 changes: 115 additions & 0 deletions drivers/keyboard.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright © 2020 Amazon.com, Inc. or its affiliates.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <drivers/keyboard.h>
#include <drivers/pic.h>
#include <lib.h>
#include <string.h>

static struct {
int shift, caps, ctrl, alt;

char buf[KEY_BUF];
unsigned curr;
unsigned init;
} keyboard_state;

void init_keyboard(void) {
outb(PIC1_PORT_DATA, KEYBOARD_IRQ_UNMASK); /* unmask keyboard irq */

memset(&keyboard_state, 0, sizeof(keyboard_state));
}

static char keyboard_scan_to_key(char scan) {
if ((unsigned long) scan < sizeof(key_map)) {
unsigned char key = key_map[(unsigned) scan];

if (key >= 'a' && key <= 'z')
return key + ('A' - 'a') * (keyboard_state.caps ^ keyboard_state.shift);
else if (keyboard_state.shift && (unsigned long) scan < sizeof(key_map_up))
return key_map_up[(unsigned) scan];

return key;
}

return scan;
}

unsigned int keyboard_process_keys(void) {
unsigned n = 0;
unsigned char key, scan;

while (keyboard_state.curr != keyboard_state.init) {
scan = keyboard_state.buf[keyboard_state.init];

key = keyboard_scan_to_key(scan);

if (isprint(key))
printk("%c", key);

keyboard_state.init = (keyboard_state.init + 1) % KEY_BUF;
++n;
}
return n;
}

void keyboard_interrupt_handler(void) {
unsigned char status;
int released;

status = inb(KEYBOARD_PORT_CMD);
if (status & KEYBOARD_STATUS_OUT_FULL) {
char scan = inb(KEYBOARD_PORT_DATA);

released = !!(scan & SCAN_RELEASE_MASK);
scan = scan & (SCAN_RELEASE_MASK - 1);

switch (scan) {
case SCAN_LSHIFT:
case SCAN_RSHIFT:
keyboard_state.shift = !released;
break;
case SCAN_CAPS:
if (!released)
keyboard_state.caps = !keyboard_state.caps;
break;
case SCAN_CTRL:
keyboard_state.ctrl = !released;
break;
case SCAN_ALT:
keyboard_state.alt = !released;
break;
default:
if (!released) {
if ((long unsigned) scan < sizeof(key_map)) {
keyboard_state.buf[keyboard_state.curr] = scan;
keyboard_state.curr = (keyboard_state.curr + 1) % KEY_BUF;
}
break;
}
}
}

outb(PIC1_PORT_CMD, PIC_EOI);
}
10 changes: 5 additions & 5 deletions drivers/pic.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ static inline void pic_outb(io_port_t port, unsigned char value) {

void init_pic(void) {
/* Cascade mode initialization sequence */
pic_outb(PIC1_PORT_CMD, PIC_ICW1_INIT | PIC_ICW1_ICW4);
pic_outb(PIC2_PORT_CMD, PIC_ICW1_INIT | PIC_ICW1_ICW4);
pic_outb(PIC1_PORT_CMD, PIC_ICW1_INIT | PIC_ICW1_LEVEL | PIC_ICW1_ICW4);
pic_outb(PIC2_PORT_CMD, PIC_ICW1_INIT | PIC_ICW1_LEVEL | PIC_ICW1_ICW4);

/* Remap PICs interrupt vectors */
pic_outb(PIC1_PORT_DATA, PIC_IRQ0_OFFSET);
Expand All @@ -44,9 +44,9 @@ void init_pic(void) {
outb(PIC1_PORT_DATA, PIC_CASCADE_PIC1_IRQ);
outb(PIC2_PORT_DATA, PIC_CASCADE_PIC2_IRQ);

/* PIC mode: 80x86, Automatic EOI */
outb(PIC1_PORT_DATA, PIC_ICW4_8086 | PIC_ICW4_AUTO);
outb(PIC2_PORT_DATA, PIC_ICW4_8086 | PIC_ICW4_AUTO);
/* PIC mode: 80x86 */
outb(PIC1_PORT_DATA, PIC_ICW4_8086);
outb(PIC2_PORT_DATA, PIC_ICW4_8086);

/* Mask the 8259A PICs by setting all IMR bits */
outb(PIC1_PORT_DATA, 0xFF);
Expand Down
103 changes: 103 additions & 0 deletions include/drivers/keyboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright © 2020 Amazon.com, Inc. or its affiliates.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef KTF_KEYBOARD_H
#define KTF_KEYBOARD_H

#include <drivers/pic.h>

#define KEYBOARD_PORT_CMD 0x64 /* keyboard command port */
#define KEYBOARD_PORT_DATA 0x60 /* keyboard data port */

#define KEYBOARD_IRQ0_OFFSET (PIC_IRQ0_OFFSET + 1) /* keyboard irq offset */
#define KEYBOARD_IRQ_UNMASK (~2) /* mask with keyboard irq enabled, others disabled */

#define KEYBOARD_STATUS_OUT_FULL 1 /* bit set when the keyboard buffer is full */

#define KEY_BUF 80 /* size of internal input buffer */

#define SCAN_RELEASE_MASK 0x80 /* bit set on key release */

#define KEY_NULL 0x0 /* no key */

/* scan codes */
#define SCAN_NULL 0x0
#define SCAN_ESC 0x1
#define SCAN_ENTER 0x1c
#define SCAN_CTRL 0x1d
#define SCAN_LSHIFT 0x2a
#define SCAN_RSHIFT 0x36
#define SCAN_ALT 0x38
#define SCAN_CAPS 0x3a
#define SCAN_F1 0x3b
#define SCAN_F2 0x3c
#define SCAN_F3 0x3d
#define SCAN_F4 0x3e
#define SCAN_F5 0x3f
#define SCAN_F6 0x40
#define SCAN_F7 0x41
#define SCAN_F8 0x42
#define SCAN_F9 0x43
#define SCAN_F10 0x44
#define SCAN_F11 0x55
#define SCAN_F12 0x58
#define SCAN_NUMLOCK 0x45
#define SCAN_SCROLLLOCK 0x46
#define SCAN_HOME 0x47
#define SCAN_UP 0x48
#define SCAN_PAGEUP 0x49
#define SCAN_LEFT 0x4b
#define SCAN_KEYPAD5 0x4c
#define SCAN_RIGHT 0x4d
#define SCAN_END 0x4f
#define SCAN_DOWN 0x50
#define SCAN_PAGEDOWN 0x51
#define SCAN_INS 0x52
#define SCAN_DEL 0x53

void init_keyboard(void);
void keyboard_interrupt_handler(void);
unsigned int keyboard_process_keys(void);

/* clang-format off */
static const unsigned char key_map[] = { /* map scan code to key */
0xff, SCAN_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',
'\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
SCAN_ENTER, SCAN_CTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
SCAN_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
SCAN_RSHIFT, 0x37, SCAN_ALT, ' ', SCAN_CAPS,
SCAN_F1, SCAN_F2, SCAN_F3, SCAN_F4, SCAN_F5, SCAN_F6, SCAN_F7, SCAN_F8, SCAN_F9, SCAN_F10,
SCAN_NUMLOCK, SCAN_SCROLLLOCK, SCAN_HOME, SCAN_UP, SCAN_PAGEUP, 0x4a, SCAN_LEFT,
SCAN_KEYPAD5, SCAN_RIGHT, 0x4e, SCAN_END, SCAN_DOWN, SCAN_PAGEDOWN, SCAN_INS, SCAN_DEL,
0x54, SCAN_F11, 0x56, 0x57, SCAN_F12
};

static const unsigned char key_map_up[] = { /* map scan code to upper key */
0xff, SCAN_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',
'\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}',
SCAN_ENTER, SCAN_CTRL, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',
SCAN_LSHIFT, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?'};
/* clang-format on */

#endif
2 changes: 2 additions & 0 deletions include/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ static inline int isupper(int c) { return c >= 'A' && c <= 'Z'; }

static inline int isalpha(int c) { return islower(c) || isupper(c); }

static inline int isprint(char c) { return c >= 0x20 && c <= 0x7e; }

static inline size_t strlen(const char *str) {
size_t len = 0;

Expand Down

0 comments on commit 6e57181

Please sign in to comment.