Added keyboard driver
This commit is contained in:
parent
1eb1e6a0b6
commit
161820eafd
|
@ -0,0 +1,48 @@
|
|||
#ifndef KB_H_
|
||||
#define KB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* kb_init:
|
||||
* Initializes the keyboard module and registers the IRQ.
|
||||
*
|
||||
* Currently this drive only supports PS2 keyboards with
|
||||
* scan code set 1.
|
||||
*
|
||||
*/
|
||||
|
||||
void kb_init(void);
|
||||
|
||||
/*
|
||||
* kb_shortcut_struct:
|
||||
* Data type used to register a keyboard shortcut.
|
||||
*
|
||||
*/
|
||||
|
||||
struct kb_shortcut_struct {
|
||||
|
||||
uint8_t scancode;
|
||||
uint8_t keystate;
|
||||
void (*handler) (void *);
|
||||
void *arg;
|
||||
|
||||
};
|
||||
|
||||
typedef struct kb_shortcut_struct kb_shortcut_t;
|
||||
|
||||
/*
|
||||
* register_shortcut:
|
||||
* Registers a keyboard shortcut.
|
||||
*
|
||||
* @param scancode - Scancode for shortcut
|
||||
* @param keystate - Keystate for shortcut
|
||||
* @param handler - Handler routine for shortcut
|
||||
* @param arg - Argument for handler
|
||||
*
|
||||
*/
|
||||
|
||||
int register_shortcut(uint8_t scancode, uint8_t keystate,
|
||||
void (*handler) (void *), void *arg);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef KB_KEYS_H_
|
||||
#define KB_KEYS_H_
|
||||
|
||||
/* keystate bitfield macros. */
|
||||
|
||||
#define KEYSTATE_PRESSED 0x01
|
||||
#define KEYSTATE_CTRL_PRESSED 0X02
|
||||
#define KEYSTATE_SHIFT_PRESSED 0x04
|
||||
#define KEYSTATE_ALT_PRESSED 0X08
|
||||
#define KEYSTATE_CAPS_LOCKED 0x10
|
||||
|
||||
/* Important scancodes. */
|
||||
|
||||
#define SCANCODE_RELEASED 0x80
|
||||
#define SCANCODE_CTRL 0x1D
|
||||
#define SCANCODE_LSHIFT 0X2A
|
||||
#define SCANCODE_RSHIFT 0X36
|
||||
#define SCANCODE_ALT 0X38
|
||||
#define SCANCODE_CAPS 0x3A
|
||||
|
||||
#endif
|
|
@ -0,0 +1,116 @@
|
|||
#ifndef KB_INTERNALS_H_
|
||||
#define KB_INTERNALS_H_
|
||||
|
||||
#include "kernel/kb.h"
|
||||
#include "kb_tables.h"
|
||||
#include "kb_codes.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* Translation tables.
|
||||
*
|
||||
* keycode - scancode to ascii
|
||||
* keyshift - character when shift is pressed.
|
||||
*
|
||||
*/
|
||||
|
||||
uint8_t keycode[KEYCODE_TABLE_SIZE];
|
||||
uint8_t keyshift[KEYCODE_TABLE_SIZE];
|
||||
|
||||
/* TO BE IMPLEMENTED */
|
||||
|
||||
__attribute__ ((unused)) kb_shortcut_t kb_shortcut[SHORTCUT_TABLE_SIZE];
|
||||
__attribute__ ((unused)) size_t kb_shortcut_ptr;
|
||||
|
||||
/*
|
||||
* keystate:
|
||||
* Bitfield containing the following information:
|
||||
* - current key is pressed
|
||||
* - ctrl is pressed
|
||||
* - shift is pressed
|
||||
* - alt is pressed
|
||||
* - caps lock is on/off
|
||||
*
|
||||
*/
|
||||
|
||||
uint8_t keystate;
|
||||
|
||||
/*
|
||||
* _get_scancode:
|
||||
*
|
||||
*
|
||||
* @return - Scancode for the pressed key.
|
||||
*
|
||||
*/
|
||||
|
||||
uint8_t _get_scancode(void);
|
||||
|
||||
/*
|
||||
* _process_scancode:
|
||||
* Set keystate bitfield using the scancode.
|
||||
*
|
||||
* @param scancode - Current scancode
|
||||
*
|
||||
*/
|
||||
|
||||
void _process_scancode(uint8_t scancode);
|
||||
|
||||
/*
|
||||
* _to_ascii:
|
||||
* Converts a scancode to a ascii code.
|
||||
*
|
||||
* @param scancode - Current scancode
|
||||
* @return - Ascii code for character if scancode valid
|
||||
* 0xFF else
|
||||
*
|
||||
*/
|
||||
|
||||
uint8_t _to_ascii(uint8_t scancode);
|
||||
|
||||
/*
|
||||
* _is_pressed:
|
||||
*
|
||||
*
|
||||
* @return - 1 if key is pressed
|
||||
* 0 else
|
||||
*
|
||||
*/
|
||||
|
||||
static inline int _is_pressed(uint8_t keystate) {
|
||||
|
||||
return keystate & KEYSTATE_PRESSED;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* _is_backspace
|
||||
*
|
||||
*
|
||||
* @return - 1 if scancode is for backspace
|
||||
* 0 else
|
||||
*
|
||||
*/
|
||||
|
||||
static inline int _is_backspace(uint8_t scancode) { return scancode == 0x0E; }
|
||||
|
||||
/*
|
||||
* _is_sequence_released:
|
||||
* Tests if a key is released after being pressed one or more times.
|
||||
*
|
||||
* @param scancode - Current scancode
|
||||
* @param prev_scancode - Previous scancode
|
||||
*
|
||||
*/
|
||||
|
||||
static inline int _is_sequence_released(uint8_t scancode,
|
||||
uint8_t prev_scancode) {
|
||||
|
||||
return ((scancode & 0x80) && !(prev_scancode & 0x80) &&
|
||||
((scancode & 0x7F) == prev_scancode));
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef KB_PORTS_H_
|
||||
#define KB_PORTS_H_
|
||||
|
||||
#define KB_DATA_PORT 0x60
|
||||
#define KB_COMMAND_PORT 0x64
|
||||
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef KB_TABLES_H_
|
||||
#define KB_TABLES_H_
|
||||
|
||||
/* Translation tables sizes. */
|
||||
|
||||
#define KEYCODE_TABLE_SIZE 256
|
||||
#define SHORTCUT_TABLE_SIZE 256
|
||||
|
||||
#endif
|
|
@ -0,0 +1,153 @@
|
|||
#include "kernel/kb.h"
|
||||
#include "kernel/screen.h"
|
||||
|
||||
#include "kb_internals.h"
|
||||
|
||||
#include "i386/context.h"
|
||||
#include "i386/irq.h"
|
||||
|
||||
#include "lib/memio.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* kb_intrpt_handler:
|
||||
* ------------------
|
||||
*
|
||||
* Using a current fetched scancode and a previous fetched scancode,
|
||||
* update the keystate and convert a current scancode if its corresponding
|
||||
* key has not yet been released.
|
||||
*
|
||||
* It also supports special characters, ex: backspace.
|
||||
*
|
||||
*/
|
||||
|
||||
void kb_intrpt_handler(__attribute__ ((unused)) context_t context) {
|
||||
|
||||
static uint8_t prev_scancode;
|
||||
|
||||
uint8_t scancode = _get_scancode();
|
||||
_process_scancode(scancode);
|
||||
|
||||
if (_is_sequence_released(scancode, prev_scancode)) {
|
||||
|
||||
prev_scancode = scancode;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
uint8_t asciicode = _to_ascii(scancode);
|
||||
|
||||
if (_is_backspace(scancode))
|
||||
screen_delete();
|
||||
|
||||
else if (_is_pressed(keystate) && asciicode != 0xFF)
|
||||
screen_write((char *) &asciicode, 1);
|
||||
|
||||
prev_scancode = scancode;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* kb_init:
|
||||
* --------
|
||||
*
|
||||
* Fill the translation tables and register the keyboard interrupt.
|
||||
*
|
||||
* keycode and keyshift will be filled with the default value 0xFF. Later,
|
||||
* keycode will be filled with the corresponding ascii codes for each
|
||||
* scancode and keyshift with the corresponding shift character for each
|
||||
* scancode.
|
||||
*
|
||||
*/
|
||||
|
||||
void kb_init(void) {
|
||||
|
||||
for (int i = 0; i < KEYCODE_TABLE_SIZE; i++)
|
||||
keycode[i] = keyshift[i] = 0xFF;
|
||||
|
||||
keycode[0x02] = '1';
|
||||
keycode[0x03] = '2';
|
||||
keycode[0x04] = '3';
|
||||
keycode[0x05] = '4';
|
||||
keycode[0x06] = '5';
|
||||
keycode[0x07] = '6';
|
||||
keycode[0x08] = '7';
|
||||
keycode[0x09] = '8';
|
||||
|
||||
keycode[0x0a] = '9';
|
||||
keycode[0x0b] = '0';
|
||||
keycode[0x0c] = '-';
|
||||
keycode[0x0d] = '=';
|
||||
keycode[0x0f] = '\t';
|
||||
keycode[0x10] = 'q';
|
||||
keycode[0x11] = 'w';
|
||||
keycode[0x12] = 'e';
|
||||
|
||||
keycode[0x13] = 'r';
|
||||
keycode[0x14] = 't';
|
||||
keycode[0x15] = 'y';
|
||||
keycode[0x16] = 'u';
|
||||
keycode[0x17] = 'i';
|
||||
keycode[0x18] = 'o';
|
||||
keycode[0x19] = 'p';
|
||||
keycode[0x1a] = '[';
|
||||
|
||||
keycode[0x1b] = ']';
|
||||
keycode[0x1c] = '\n';
|
||||
keycode[0x1e] = 'a';
|
||||
keycode[0x1f] = 's';
|
||||
keycode[0x20] = 'd';
|
||||
keycode[0x21] = 'f';
|
||||
keycode[0x22] = 'g';
|
||||
keycode[0x23] = 'h';
|
||||
|
||||
keycode[0x24] = 'j';
|
||||
keycode[0x25] = 'k';
|
||||
keycode[0x26] = 'l';
|
||||
keycode[0x27] = ';';
|
||||
keycode[0x28] = '\'';
|
||||
keycode[0x29] = '`';
|
||||
keycode[0x2b] = '\\';
|
||||
keycode[0x2c] = 'z';
|
||||
|
||||
keycode[0x2d] = 'x';
|
||||
keycode[0x2e] = 'c';
|
||||
keycode[0x2f] = 'v';
|
||||
keycode[0x30] = 'b';
|
||||
keycode[0x31] = 'n';
|
||||
keycode[0x32] = 'm';
|
||||
keycode[0x33] = ',';
|
||||
keycode[0x34] = '.';
|
||||
|
||||
keycode[0x35] = '/';
|
||||
keycode[0x39] = ' ';
|
||||
|
||||
keyshift['`'] = '~';
|
||||
keyshift['1'] = '!';
|
||||
keyshift['2'] = '@';
|
||||
keyshift['3'] = '#';
|
||||
keyshift['4'] = '$';
|
||||
keyshift['5'] = '%';
|
||||
keyshift['6'] = '^';
|
||||
keyshift['7'] = '&';
|
||||
|
||||
keyshift['8'] = '*';
|
||||
keyshift['9'] = '(';
|
||||
keyshift['0'] = ')';
|
||||
keyshift['-'] = '_';
|
||||
keyshift['='] = '+';
|
||||
keyshift['['] = '{';
|
||||
keyshift[']'] = '}';
|
||||
keyshift['\\'] = '|';
|
||||
|
||||
keyshift[';'] = ':';
|
||||
keyshift['\''] = '"';
|
||||
keyshift[','] = '<';
|
||||
keyshift['.'] = '>';
|
||||
keyshift['/'] = '?';
|
||||
|
||||
register_irq(IRQ1, kb_intrpt_handler);
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
#include "kb_internals.h"
|
||||
|
||||
#include "kb_ports.h"
|
||||
#include "kb_codes.h"
|
||||
|
||||
#include "lib/memio.h"
|
||||
|
||||
/*
|
||||
* _get_scancode:
|
||||
* --------------
|
||||
*
|
||||
* Read from KB_DATA_PORT until a nonzero value comes.
|
||||
*
|
||||
*/
|
||||
|
||||
uint8_t _get_scancode(void) {
|
||||
|
||||
uint8_t code = 0;
|
||||
|
||||
do {
|
||||
|
||||
code = inb(KB_DATA_PORT);
|
||||
if (code) break;
|
||||
|
||||
} while (1);
|
||||
|
||||
return code;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* _process_scancode:
|
||||
* ------------------
|
||||
*
|
||||
* Should set or unset each bit described in kb_codes.h.
|
||||
*
|
||||
* side effects:
|
||||
* changed the global variable @keystate.
|
||||
*
|
||||
*/
|
||||
|
||||
void _process_scancode(uint8_t scancode) {
|
||||
|
||||
if (scancode & SCANCODE_RELEASED)
|
||||
keystate &= ~KEYSTATE_PRESSED;
|
||||
else
|
||||
keystate |= KEYSTATE_PRESSED;
|
||||
|
||||
/* Discard released/hit bit to work with the switch cases. */
|
||||
|
||||
scancode &= 0X7F;
|
||||
|
||||
if (keystate & KEYSTATE_PRESSED) {
|
||||
|
||||
switch (scancode) {
|
||||
|
||||
case SCANCODE_CTRL:
|
||||
keystate |= KEYSTATE_CTRL_PRESSED;
|
||||
break;
|
||||
|
||||
case SCANCODE_LSHIFT:
|
||||
case SCANCODE_RSHIFT:
|
||||
keystate |= KEYSTATE_SHIFT_PRESSED;
|
||||
break;
|
||||
|
||||
case SCANCODE_ALT:
|
||||
keystate |= KEYSTATE_ALT_PRESSED;
|
||||
break;
|
||||
|
||||
case SCANCODE_CAPS:
|
||||
keystate = (keystate & KEYSTATE_CAPS_LOCKED) ?
|
||||
keystate & ~KEYSTATE_CAPS_LOCKED :
|
||||
keystate | KEYSTATE_CAPS_LOCKED;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch (scancode) {
|
||||
|
||||
case SCANCODE_CTRL:
|
||||
keystate &= ~KEYSTATE_CTRL_PRESSED;
|
||||
break;
|
||||
|
||||
case SCANCODE_LSHIFT:
|
||||
case SCANCODE_RSHIFT:
|
||||
keystate &= ~KEYSTATE_SHIFT_PRESSED;
|
||||
break;
|
||||
|
||||
case SCANCODE_ALT:
|
||||
keystate &= ~KEYSTATE_ALT_PRESSED;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* _to_ascii:
|
||||
* ----------
|
||||
*
|
||||
* Using the translation tables, keycode and keyshift, and keystate, convert
|
||||
* scancode to ascii char.
|
||||
*
|
||||
*/
|
||||
|
||||
uint8_t _to_ascii(uint8_t scancode) {
|
||||
|
||||
uint8_t ascii_code = keycode[scancode];
|
||||
|
||||
if (ascii_code == 0xFF)
|
||||
return ascii_code;
|
||||
|
||||
if (ascii_code >= 'a' && ascii_code <= 'z' && ((keystate & KEYSTATE_CAPS_LOCKED)
|
||||
|| (keystate & KEYSTATE_SHIFT_PRESSED)))
|
||||
ascii_code += 'A' - 'a';
|
||||
|
||||
else if ((keystate & KEYSTATE_SHIFT_PRESSED) && keyshift[ascii_code] != 0xFF)
|
||||
ascii_code = keyshift[ascii_code];
|
||||
|
||||
return ascii_code;
|
||||
|
||||
}
|
Loading…
Reference in New Issue