forked from xamidev/pepperOS
342 lines
8.8 KiB
C
342 lines
8.8 KiB
C
/*
|
|
* @author xamidev <xamidev@riseup.net>
|
|
* @brief PS/2 Keyboard driver
|
|
* @license GPL-3.0-only
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <io/serial/serial.h>
|
|
#include <io/kbd/ps2.h>
|
|
#include <stdint.h>
|
|
#include <io/term/term.h>
|
|
#include <kernel.h>
|
|
#include <stddef.h>
|
|
|
|
// The key status bitfield will be used to see if ALT, CONTROL, or SHIFT is pressed
|
|
uint8_t key_status = 0b00000000;
|
|
|
|
// Keymap pointers so we can change between different layouts
|
|
unsigned char* keymap;
|
|
unsigned char* keymap_shifted;
|
|
|
|
// Keyboard buffer
|
|
char keyboard_buffer[KBD_BUFFER_MAX] = {0};
|
|
int write_index = 0;
|
|
int read_index = 0;
|
|
|
|
extern struct init_status init;
|
|
|
|
unsigned char kbdus[128] =
|
|
{
|
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */
|
|
'9', '0', '-', '=', '\b', /* Backspace */
|
|
'\t', /* Tab */
|
|
'q', 'w', 'e', 'r', /* 19 */
|
|
't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */
|
|
CTRL, /* 29 - Control */
|
|
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */
|
|
'\'', '`', SHIFT, /* Left shift */
|
|
'\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */
|
|
'm', ',', '.', '/', SHIFT, /* Right shift */
|
|
'*',
|
|
ALT, /* Alt */
|
|
' ', /* Space bar */
|
|
0, /* Caps lock */
|
|
0, /* 59 - F1 key ... > */
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, /* < ... F10 */
|
|
0, /* 69 - Num lock*/
|
|
0, /* Scroll Lock */
|
|
0, /* Home key */
|
|
0, /* Up Arrow */
|
|
0, /* Page Up */
|
|
'-',
|
|
0, /* Left Arrow */
|
|
0,
|
|
0, /* Right Arrow */
|
|
'+',
|
|
0, /* 79 - End key*/
|
|
0, /* Down Arrow */
|
|
0, /* Page Down */
|
|
0, /* Insert Key */
|
|
0, /* Delete Key */
|
|
0, 0, 0,
|
|
0, /* F11 Key */
|
|
0, /* F12 Key */
|
|
0, /* All other keys are undefined */
|
|
};
|
|
|
|
unsigned char kbdus_shifted[128] =
|
|
{
|
|
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */
|
|
'(', ')', '_', '+', '\b', /* Backspace */
|
|
'\t', /* Tab */
|
|
'Q', 'W', 'E', 'R', /* 19 */
|
|
'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter */
|
|
CTRL, /* 29 */
|
|
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */
|
|
'"', '~', SHIFT, /* Left shift */
|
|
'|', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */
|
|
'M', '<', '>', '?', SHIFT, /* Right shift */
|
|
'*',
|
|
ALT, /* Alt */
|
|
' ', /* Space */
|
|
0, /* Caps lock */
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, /* F10 */
|
|
0, /* Num lock */
|
|
0, /* Scroll lock */
|
|
0, 0, 0,
|
|
'-',
|
|
0, 0, 0,
|
|
'+',
|
|
0, 0, 0,
|
|
0, 0,
|
|
0, 0, 0,
|
|
0, /* F11 */
|
|
0 /* F12 */
|
|
};
|
|
|
|
// NOT THE REAL FR KEYMAP!!
|
|
// Some French keys have accents or weird symbols that aren't part of ASCII
|
|
// so they won't fit in 1 char. As a substitute for now, these will be
|
|
// changed to their ASCII counterparts (without accents, etc.)
|
|
unsigned char kbdfr[128] =
|
|
{
|
|
0, 27, '&', 'e', '"', '\'', '(', '-', 'e', '_',
|
|
'c', 'a', ')', '=', '\b',
|
|
'\t',
|
|
'a', 'z', 'e', 'r',
|
|
't', 'y', 'u', 'i', 'o', 'p', '^', '$', '\n',
|
|
CTRL,
|
|
'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm',
|
|
'u', '`', SHIFT,
|
|
'*', 'w', 'x', 'c', 'v', 'b', 'n',
|
|
',', ';', ':', '!', SHIFT,
|
|
'*',
|
|
ALT,
|
|
' ',
|
|
0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, 0, 0,
|
|
'-',
|
|
0, 0, 0,
|
|
'+',
|
|
0, 0, 0,
|
|
0, 0,
|
|
0, 0, 0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
unsigned char kbdfr_shifted[128] =
|
|
{
|
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8',
|
|
'9', '0', '^', '+', '\b',
|
|
'\t',
|
|
'A', 'Z', 'E', 'R',
|
|
'T', 'Y', 'U', 'I', 'O', 'P', '^', 'L', '\n',
|
|
CTRL,
|
|
'Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
|
|
'%', '~', SHIFT,
|
|
'u', 'W', 'X', 'C', 'V', 'B', 'N',
|
|
'?', '.', '/', 'S', SHIFT,
|
|
'*',
|
|
ALT,
|
|
' ',
|
|
0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, 0, 0,
|
|
'-',
|
|
0, 0, 0,
|
|
'+',
|
|
0, 0, 0,
|
|
0, 0,
|
|
0, 0, 0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
/*
|
|
* keyboard_handler - Keyboard event handler
|
|
*
|
|
* Is called from the interrupt dispatcher.
|
|
* When a key is pressed or released, we get a scancode, and
|
|
* it is then translated to an ASCII character.
|
|
* Left Shift, Ctrl, and Alt keys are also taken into consideration.
|
|
*/
|
|
void keyboard_handler()
|
|
{
|
|
unsigned char scancode = inb(0x60);
|
|
|
|
// Key release (bit 7 set)
|
|
if (scancode & 0x80) {
|
|
unsigned char code = scancode & 0x7F;
|
|
switch (code) {
|
|
// Clear the corresponding bit if corresponding key is released
|
|
case LEFT_SHIFT_PRESSED:
|
|
case RIGHT_SHIFT_PRESSED:
|
|
key_status &= ~SHIFT_PRESSED_BIT;
|
|
break;
|
|
case CTRL_PRESSED:
|
|
key_status &= ~CTRL_PRESSED_BIT;
|
|
break;
|
|
case ALT_PRESSED:
|
|
key_status &= ~ALT_PRESSED_BIT;
|
|
break;
|
|
}
|
|
return;
|
|
} else {
|
|
// Key press
|
|
switch (scancode) {
|
|
// Set bits for corresponding special key press
|
|
case LEFT_SHIFT_PRESSED:
|
|
case RIGHT_SHIFT_PRESSED:
|
|
key_status |= SHIFT_PRESSED_BIT;
|
|
break;
|
|
case CTRL_PRESSED:
|
|
key_status |= CTRL_PRESSED_BIT;
|
|
break;
|
|
case ALT_PRESSED:
|
|
key_status |= ALT_PRESSED_BIT;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
// Avoiding buffer overflow from extended keys lol
|
|
if (scancode < 128) {
|
|
// Should we get a SHIFTED char or a regular one?
|
|
unsigned char c = (key_status & SHIFT_PRESSED_BIT) ? keymap_shifted[scancode] : keymap[scancode];
|
|
|
|
if (c) {
|
|
if (c == '\n') {
|
|
internal_putc('\r', NULL);
|
|
}
|
|
|
|
internal_putc(c, NULL);
|
|
keyboard_putchar(c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* keyboard_getchar - Get a character from keyboard
|
|
*
|
|
* This function reads one character from the keyboard buffer.
|
|
* If the keyboard buffer is empty, it will block until a key
|
|
* is pressed.
|
|
*
|
|
* Return:
|
|
* <char> - character from keyboard buffer
|
|
*/
|
|
char keyboard_getchar()
|
|
{
|
|
while (read_index == write_index); // Empty buffer
|
|
|
|
char c = keyboard_buffer[read_index];
|
|
read_index = (read_index+1) % KBD_BUFFER_MAX;
|
|
return c;
|
|
}
|
|
|
|
/*
|
|
* keyboard_putchar - Puts a character in the keyboard buffer
|
|
* @c: character to add
|
|
*
|
|
* This function is used in the keyboard handler to add new
|
|
* characters to the keyboard buffer.
|
|
*
|
|
* Return:
|
|
* %-1 - keyboard buffer is full
|
|
* %0 - operation completed successfully
|
|
*/
|
|
int keyboard_putchar(char c)
|
|
{
|
|
if ((write_index+1) % KBD_BUFFER_MAX == read_index) {
|
|
// Full buffer
|
|
return -1;
|
|
}
|
|
|
|
keyboard_buffer[write_index] = c;
|
|
write_index = (write_index+1) % KBD_BUFFER_MAX;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* keyboard_getline - Gets a line of input from keyboard
|
|
* @output: Output string
|
|
* @size: Size of output string
|
|
*
|
|
* Read a line of characters from the keyboard, until the
|
|
* buffer fills or a newline character is read.
|
|
* The output string is NULL-terminated.
|
|
*
|
|
* Return:
|
|
* <num> - the number of characters read
|
|
*/
|
|
int keyboard_getline(char* output, size_t size)
|
|
{
|
|
char c;
|
|
size_t index = 0;
|
|
|
|
// Read until Enter is pressed
|
|
while ((c = keyboard_getchar()) != 0x0A) {
|
|
if (index == size-1) {
|
|
output[index] = c;
|
|
output[index+1] = '\0';
|
|
return index;
|
|
}
|
|
output[index] = c;
|
|
index++;
|
|
}
|
|
output[index+1] = '\0';
|
|
return index;
|
|
}
|
|
|
|
/*
|
|
* keyboard_init - Keyboard initialization
|
|
* @layout: Desired layout
|
|
*
|
|
* Prepares the PS/2 keyboard to recieve input.
|
|
*/
|
|
void keyboard_init(unsigned char layout)
|
|
{
|
|
// Here we might go and select PS/2, USB, or other... (once we implement multiple keyboard protocols)
|
|
|
|
// Keyboard layout selection
|
|
switch (layout) {
|
|
case US:
|
|
keymap = kbdus;
|
|
keymap_shifted = kbdus_shifted;
|
|
break;
|
|
case FR:
|
|
keymap = kbdfr;
|
|
keymap_shifted = kbdfr_shifted;
|
|
break;
|
|
|
|
default:
|
|
panic(NULL, "Unsupported keyboard layout");
|
|
return;
|
|
}
|
|
|
|
// Flush keyboard buffer
|
|
while (inb(0x64) & 1) {
|
|
inb(0x60);
|
|
}
|
|
|
|
// Unmask IRQ1
|
|
uint8_t mask = inb(0x21);
|
|
mask &= ~(1 << 1);
|
|
outb(0x21, mask);
|
|
|
|
DEBUG("PS/2 Keyboard initialized");
|
|
init.keyboard = true;
|
|
} |