Files
Espresso/drivers/ps2_keyboard.c

179 lines
3.6 KiB
C
Raw Normal View History

2025-05-28 14:41:02 -05:00
#include <stdio.h>
#include <port_io.h>
2025-06-13 19:53:54 -05:00
#include <tty.h>
2025-06-17 15:50:07 -05:00
#include <stdlib.h>
2025-05-28 14:41:02 -05:00
#include <drivers/ps2_keyboard.h>
/*
2025-06-13 18:03:39 -05:00
PS/2 Controller IO Ports
2025-05-28 14:41:02 -05:00
2025-06-13 18:03:39 -05:00
The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers.
2025-05-28 14:41:02 -05:00
2025-06-13 18:03:39 -05:00
Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles.
IO Port Access Type Purpose
0x60 Read/Write Data Port
0x64 Read Status Register
0x64 Write Command Register
2025-05-28 14:41:02 -05:00
*/
2025-06-13 19:53:54 -05:00
/*
Note:
The interrupt number for keyboard input in 1.
*/
#define PS2_DATA_PORT 0x60
#define PS2_STATUS_PORT 0x64
#define KEYBOARD_IRQ 1
2025-06-17 15:50:07 -05:00
bool ps2keyboard_initialized = false;
2025-06-13 19:53:54 -05:00
/* State for shift key */
static bool shift_pressed = false;
2025-06-17 15:50:07 -05:00
/* State for caps-lock key */
static bool capslock_pressed = false;
volatile char current_char;
volatile char* current_string = NULL;
volatile int32_t current_length = 0;
volatile int32_t capacity = 0;
2025-06-13 19:53:54 -05:00
static const char scancode_map[128] = {
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
'\t', // Tab
'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */
0, /* Control */
'a','s','d','f','g','h','j','k','l',';','\'','`',
0, /* Left shift */
'\\','z','x','c','v','b','n','m',',','.','/',
0, /* Right shift */
'*',
0, /* Alt */
' ', /* Spacebar */
0, /* Caps lock */
/* The rest are function and control keys */
};
2025-05-28 14:41:02 -05:00
void keyboard_init(void)
{
2025-06-13 19:53:54 -05:00
outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */
2025-06-17 15:50:07 -05:00
ps2keyboard_initialized = true;
}
char get_char(void)
{
return current_char;
}
char* get_string(void)
{
return current_string;
}
static void append_char(char c)
{
if (current_length + 1 >= capacity)
{
2025-06-27 14:48:06 -05:00
/* Need more space (+1 for the null zero) */
2025-06-17 15:50:07 -05:00
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
char* new_str = (char*)malloc(new_capacity);
if (!new_str) {
return;
}
if (current_string)
{
memcpy(new_str, current_string, current_length);
free(current_string);
}
2025-06-27 14:48:06 -05:00
if (!current_string)
{
return;
}
2025-06-17 15:50:07 -05:00
current_string = new_str;
capacity = new_capacity;
}
current_string[current_length] = c;
current_length++;
current_string[current_length] = '\0'; /* Maintain null terminator */
}
static void free_current_string(void)
{
if (current_string)
{
free(current_string);
current_string = NULL;
current_length = 0;
capacity = 0;
}
2025-06-13 19:53:54 -05:00
}
void keyboard_handler(void) {
uint8_t scancode = inb(PS2_DATA_PORT);
/* Handle shift press/release */
if (scancode == 0x2A || scancode == 0x36)
{
shift_pressed = true;
return;
}
else if (scancode == 0xAA || scancode == 0xB6)
{
shift_pressed = false;
return;
}
2025-06-17 15:50:07 -05:00
else if (scancode == 0x3A)
{
capslock_pressed = !capslock_pressed;
return;
}
2025-06-13 19:53:54 -05:00
if (scancode & 0x80)
{
/* Key release event, ignore for now */
} else
{
char c = scancode_map[scancode];
2025-06-17 15:50:07 -05:00
if ((shift_pressed ^ capslock_pressed) && c >= 'a' && c <= 'z') {
2025-06-13 19:53:54 -05:00
c -= 32; /* Convert to uppercase */
}
else if (shift_pressed)
{
c = (char) terminal_get_shifted((unsigned char) c);
}
2025-06-27 14:48:06 -05:00
if (scancode == 0x1C) {
printf("\n");
return;
}
2025-06-13 19:53:54 -05:00
if (c)
{
2025-06-17 15:50:07 -05:00
current_char = c;
if (c == '\n')
{
free_current_string();
}
else
{
append_char(c);
printf("%c", c);
}
2025-06-13 19:53:54 -05:00
}
}
2025-05-28 14:41:02 -05:00
}
2025-06-27 14:48:06 -05:00