Added keyboard driver

This commit is contained in:
lucic71 2022-06-28 19:40:51 +03:00
parent 1eb1e6a0b6
commit 161820eafd
7 changed files with 486 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,7 @@
#ifndef KB_PORTS_H_
#define KB_PORTS_H_
#define KB_DATA_PORT 0x60
#define KB_COMMAND_PORT 0x64
#endif

View File

@ -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

153
kernel/kb/src/kb.c Normal file
View File

@ -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);
}

View File

@ -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;
}