summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-06-10 21:26:24 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2017-06-10 21:26:24 +0200
commitd6d1bdfefafff50b7b6d15d218c0a188570be541 (patch)
tree15ee8de727d0be5d126efda146b2879de0a72773 /src/drivers
parenteea5bf4b859eb56c5772c58ca54937a90a10e7ee (diff)
downloadabaos-d6d1bdfefafff50b7b6d15d218c0a188570be541.tar.gz
abaos-d6d1bdfefafff50b7b6d15d218c0a188570be541.tar.bz2
some big renames into subdirs of aspects
updated README removed size_t in sys/types.h and sys/types.h itself, size_t is in stddef.h
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/driver.c65
-rw-r--r--src/drivers/driver.h31
-rw-r--r--src/drivers/hdi/ps2/keyboard.c316
-rw-r--r--src/drivers/hdi/ps2/keyboard.h69
-rw-r--r--src/drivers/hdi/ps2/mouse.c250
-rw-r--r--src/drivers/hdi/ps2/mouse.h65
6 files changed, 796 insertions, 0 deletions
diff --git a/src/drivers/driver.c b/src/drivers/driver.c
new file mode 100644
index 0000000..5a1a479
--- /dev/null
+++ b/src/drivers/driver.c
@@ -0,0 +1,65 @@
+#include "driver.h"
+
+#include "kernel.h"
+#include "string.h"
+
+void driver_manager_init( driver_manager_t *manager )
+{
+ memset( manager, 0, sizeof( driver_manager_t ) );
+
+ manager->nof_drivers = 0;
+}
+
+void driver_manager_add_driver( driver_manager_t *manager, driver_t *driver )
+{
+ if( manager->nof_drivers >= MAX_NOF_DRIVERS - 1 ) {
+ kernel_panic( "Allocating more than %d drivers.. increase kernel constant", MAX_NOF_DRIVERS );
+ }
+
+ manager->driver[manager->nof_drivers] = driver;
+ manager->nof_drivers++;
+}
+
+void driver_manager_activate_all( driver_manager_t *manager )
+{
+ for( int i = 0; i < manager->nof_drivers; i++ ) {
+ driver_t *driver = (driver_t *)manager->driver[i];
+ driver_vtable_t *driver_vtable = driver->vtable;
+ driver_vtable->activate( driver );
+ }
+}
+
+void driver_manager_deactivate_all( driver_manager_t *manager )
+{
+ if( manager->nof_drivers == 0 ) {
+ return;
+ }
+
+ for( int i = manager->nof_drivers - 1; i >= 0; i-- ) {
+ driver_t *driver = (driver_t *)manager->driver[i];
+ driver_vtable_t *driver_vtable = driver->vtable;
+ driver_vtable->deactivate( driver );
+ }
+}
+
+void driver_manager_deinit( driver_manager_t *manager )
+{
+ if( manager->nof_drivers == 0 ) {
+ return;
+ }
+
+ for( int i = manager->nof_drivers - 1; i >= 0; i-- ) {
+ driver_t *driver = (driver_t *)manager->driver[i];
+ driver_vtable_t *driver_vtable = driver->vtable;
+ driver_vtable->deinit( driver );
+ }
+}
+
+void driver_manager_print_info_all( driver_manager_t *manager )
+{
+ for( int i = 0; i < manager->nof_drivers; i++ ) {
+ driver_t *driver = (driver_t *)manager->driver[i];
+ driver_vtable_t *driver_vtable = driver->vtable;
+ driver_vtable->print_info( driver );
+ }
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
new file mode 100644
index 0000000..c110308
--- /dev/null
+++ b/src/drivers/driver.h
@@ -0,0 +1,31 @@
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#include "interrupts.h"
+
+typedef struct {
+ void (*activate)( void *obj );
+ void (*deactivate)( void *obj );
+ void (*deinit)( void *obj );
+ void (*print_info)( void *obj );
+} driver_vtable_t;
+
+typedef struct {
+ driver_vtable_t *vtable;
+} driver_t;
+
+#define MAX_NOF_DRIVERS 256
+
+typedef struct {
+ int nof_drivers;
+ driver_t *driver[MAX_NOF_DRIVERS];
+} driver_manager_t;
+
+void driver_manager_init( driver_manager_t *manager );
+void driver_manager_add_driver( driver_manager_t *manager, driver_t *driver );
+void driver_manager_activate_all( driver_manager_t *manager );
+void driver_manager_deactivate_all( driver_manager_t *manager );
+void driver_manager_deinit( driver_manager_t *manager );
+void driver_manager_print_info_all( driver_manager_t *manager );
+
+#endif // DRIVER_H
diff --git a/src/drivers/hdi/ps2/keyboard.c b/src/drivers/hdi/ps2/keyboard.c
new file mode 100644
index 0000000..d7d8d88
--- /dev/null
+++ b/src/drivers/hdi/ps2/keyboard.c
@@ -0,0 +1,316 @@
+#include "keyboard.h"
+#include "stdio.h"
+
+// status register on command port (read)
+#define STATUS_REG_OUTPUT_BUF_FULL 0x01
+#define STATUS_REG_INPUT_BUF_FULL 0x02
+
+// generic PS/2 commands
+#define COMMAND_GET_STATE 0x20
+#define COMMAND_SET_STATE 0x60
+#define COMMAND_DISABLE_PORT1 0xAD
+#define COMMAND_ENABLE_PORT1 0xAE
+
+// status control register flags
+#define STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT1 0x01
+#define STATUS_CONTROL_CONFIG_CLOCK_PORT1 0x10
+
+// keyboard specific commands, PSAUX1
+#define KBD_COMMAND_SET_LEDS 0xED
+#define KBD_SET_SCANCODE 0xF0
+#define KBD_ACTIVATE 0xF4
+
+// keyboard LED status codes
+#define KBD_LED_SCROLL_LOCK_ON 0x01
+#define KBD_LED_NUM_LOCK_ON 0x02
+#define KBD_LED_CAPS_LOCK_ON 0x04
+#define KBD_LED_ALL_OFF 0x00
+#define KBD_LED_ALL_ON KBD_LED_SCROLL_LOCK_ON | KBD_LED_NUM_LOCK_ON | KBD_LED_CAPS_LOCK_ON
+
+// keyboard scan codes
+#define KBD_SCANCODE_1 0x01
+#define KBD_SCANCODE_2 0x02
+#define KBD_SCANCODE_3 0x03
+
+#undef DEBUG
+
+static uint8_t read_data( keyboard_t *keyboard )
+{
+ while( ( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) == 0 ) { }
+ return port8_read( &keyboard->data_port );
+}
+
+static void send_command( keyboard_t *keyboard, uint8_t command )
+{
+ while( port8_read( &keyboard->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { }
+ port8_write( &keyboard->command_port, command );
+}
+
+static void write_data( keyboard_t *keyboard, uint8_t data )
+{
+ while( port8_read( &keyboard->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { }
+ port8_write( &keyboard->data_port, data );
+}
+
+/*
+static void read_ack( keyboard_t *keyboard )
+{
+ uint8_t data = read_data( keyboard );
+ if( data == 0xFA ) {
+ return;
+ } else {
+ kernel_warn( "ERR PS/2 keyboard: acknoledgment failed 0x%X\n", data );
+ }
+}
+*/
+
+static keyboard_vtable_t keyboard_vtable = {
+ {
+ keyboard_activate,
+ keyboard_deactivate,
+ keyboard_deinit,
+ keyboard_print_info
+ }
+};
+
+void keyboard_init( keyboard_t *keyboard, keyboard_event_handler_t handler, void *context )
+{
+ memset( keyboard, 0, sizeof( keyboard_t ) );
+
+ port8_init( &keyboard->command_port, 0x64 );
+ port8_init( &keyboard->data_port, 0x60 );
+
+ keyboard->shift = false;
+ keyboard->handler = handler;
+ keyboard->context = context;
+
+ keyboard->base.vtable = &keyboard_vtable.base;
+}
+
+void keyboard_activate( void *obj )
+{
+ puts( "Activating driver for PS/2 keyboard.." );
+
+ keyboard_t *keyboard = obj;
+
+ // first switch off port 1
+ send_command( keyboard, COMMAND_DISABLE_PORT1 );
+
+ // consume character pressed before executing the kernel
+ while( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) {
+ port8_read( &keyboard->data_port );
+ }
+
+ // enable interrupts for port 1
+ send_command( keyboard, COMMAND_GET_STATE );
+ uint8_t status = read_data( keyboard );
+ status |= STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT1;
+ status &= ~STATUS_CONTROL_CONFIG_CLOCK_PORT1;
+ send_command( keyboard, COMMAND_SET_STATE );
+ write_data( keyboard, status );
+
+ // disable all LEDs on keyboard
+ //~ send_command( keyboard, KBD_COMMAND_SET_LEDS );
+ //~ write_data( keyboard, KBD_LED_ALL_ON );
+
+ // set scan code
+ //~ send_command( keyboard, KBD_SET_SCANCODE );
+ //~ write_data( keyboard, KBD_SCANCODE_2 );
+
+ // activate keyboard
+ //send_command( keyboard, KBD_ACTIVATE );
+ //read_ack( keyboard );
+
+ // enable port 1
+ send_command( keyboard, COMMAND_ENABLE_PORT1 );
+}
+
+void keyboard_deactivate( void *obj )
+{
+ puts( "Deactivating driver for PS/2 keyboard.." );
+
+ keyboard_t *keyboard = obj;
+
+ send_command( keyboard, COMMAND_DISABLE_PORT1 );
+}
+
+void keyboard_deinit( void *obj )
+{
+ // nothing to do
+}
+
+typedef enum {
+ KEYCODE_UNKNOWN,
+ KEYCODE_ASCII_CHAR
+} keycode_type_t;
+
+typedef struct {
+ keycode_type_t type;
+ char c;
+} keycode_t;
+
+typedef enum {
+ SCANCODE_SET_NORMAL = 0,
+ SCANCODE_SET_SHIFT = 1,
+ SCANCODE_SET_E0 = 2,
+ SCANCODE_SET_E1 = 3
+} scancode_set_t;
+
+// TODO: here come the translations to other keyboard layouts,
+// assumming a QWERTY US keyboard here..
+static char scancode_map[4][128] = {
+ {
+ 0, 0, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', '\b', 0,
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', '\n', 0, 'a', 's',
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '`', 0, '\\', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '/', 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 , 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, 0,
+ 0, 0, 0 , 0 , 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ },
+ {
+ 0, 0, '!', '@', '#', '$', '%', '^',
+ '&', '*', '(', ')', '_', '+', 0, 0,
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', '{', '}', '\n', 0, 'A', 'S',
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '"', '~', 0, '|', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', '<', '>', '?', 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 , 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ }
+};
+
+static keycode_t scancode_to_keycode( scancode_set_t set, uint8_t scan_code )
+{
+ keycode_t key_code;
+ key_code.type = KEYCODE_UNKNOWN;
+
+ key_code.c = scancode_map[set][scan_code];
+ if( key_code.c > 0 ) {
+ key_code.type = KEYCODE_ASCII_CHAR;
+ }
+ return key_code;
+}
+
+#define SCAN_CODE_BREAK_CODE 0x80
+#define SCAN_CODE_LEFT_SHIFT 0x2A
+#define SCAN_CODE_RIGHT_SHIFT 0x36
+
+uint32_t keyboard_handle_interrupt( interrupt_handler_t *handler, uint32_t esp )
+{
+ keyboard_t *keyboard = (keyboard_t *)handler->driver;
+
+ // we can only wake up on IRQ1 because we don't send commands
+ // after initialization
+ uint8_t scan_code = port8_read( &keyboard->data_port );
+
+ // we get break code when the high bit is set, so the
+ // the key is released
+ bool break_code = false;
+ if( scan_code & SCAN_CODE_BREAK_CODE ) {
+ break_code = true;
+ }
+
+ scan_code &= ~SCAN_CODE_BREAK_CODE;
+
+ if( scan_code == SCAN_CODE_LEFT_SHIFT ||
+ scan_code == SCAN_CODE_RIGHT_SHIFT ) {
+ if( break_code ) {
+ keyboard->shift = false;
+ } else {
+ keyboard->shift = true;
+ }
+ }
+
+ scancode_set_t code_set = SCANCODE_SET_NORMAL;
+ if( keyboard->shift ) {
+ code_set = SCANCODE_SET_SHIFT;
+ }
+
+ keycode_t key_code = scancode_to_keycode( code_set, scan_code );
+
+#ifdef DEBUG
+ printf( "KBD SCAN:0x%X S:%d B:%d S:%d T:0x%X '%c' 0x%X\n",
+ scan_code, code_set, break_code, keyboard->shift,
+ key_code.type, key_code.c, key_code.c );
+#endif
+
+ keyboard_event_t event;
+ if( break_code ) {
+ event.type = KEYBOARD_EVENT_TYPE_KEY_RELEASED;
+ } else {
+ event.type = KEYBOARD_EVENT_TYPE_KEY_PRESSED;
+ }
+ event.modifiers = 0;
+ if( keyboard->shift ) {
+ event.modifiers |= KEYBOARD_MODIFIER_SHIFT;
+ }
+ // TODO: for control, alt, meta, etc.
+ event.key = KEYBOARD_KEY_UNKNOWN;
+ if( key_code.type == KEYCODE_ASCII_CHAR ) {
+ event.key = KEYBOARD_KEY_ASCII;
+ event.ascii_key = key_code.c;
+ }
+
+ keyboard->handler( &event, keyboard->context );
+
+ return esp;
+}
+
+void keyboard_print_info( void *obj )
+{
+ puts( "PS/2 keyboard driver" );
+}
diff --git a/src/drivers/hdi/ps2/keyboard.h b/src/drivers/hdi/ps2/keyboard.h
new file mode 100644
index 0000000..5f90ee8
--- /dev/null
+++ b/src/drivers/hdi/ps2/keyboard.h
@@ -0,0 +1,69 @@
+#ifndef KEYBOARD_H
+#define KEYBOARD_H
+
+#include <stdbool.h>
+
+#include "string.h"
+
+#include "interrupts.h"
+#include "port.h"
+
+#include "driver.h"
+
+typedef enum {
+ KEYBOARD_EVENT_TYPE_KEY_PRESSED,
+ KEYBOARD_EVENT_TYPE_KEY_RELEASED
+} keyboard_event_type_t;
+
+typedef enum {
+ KEYBOARD_MODIFIER_SHIFT = 0x01,
+ KEYBOARD_MODIFIER_CTRL = 0x02,
+ KEYBOARD_MODIFIER_ALT = 0x04
+} keyboard_modifier_mask_t;
+
+typedef enum {
+ KEYBOARD_KEY_UNKNOWN,
+ KEYBOARD_KEY_ASCII,
+ KEYBOARD_KEY_ESC,
+ KEYBOARD_KEY_TAB,
+ KEYBOARD_KEY_INS,
+ KEYBAORD_KEY_DEL,
+ KEYBAORD_KEY_BACKSPACE,
+ KEYBAORD_CURSOR_LEFT,
+ KEYBOARD_CURSOR_RIGHT,
+ KEYBOARD_CURSOR_UP,
+ KEYBOARD_CURSOR_DOWN
+} keyboard_key_t;
+
+typedef struct {
+ keyboard_event_type_t type;
+ keyboard_modifier_mask_t modifiers;
+ keyboard_key_t key;
+ char ascii_key;
+} keyboard_event_t;
+
+typedef void (*keyboard_event_handler_t)( keyboard_event_t *event, void *context );
+
+typedef struct {
+ driver_t base;
+ interrupt_t *interrupts;
+ port8_t command_port;
+ port8_t data_port;
+ bool shift;
+ keyboard_event_handler_t handler;
+ void *context;
+} keyboard_t;
+
+typedef struct {
+ driver_vtable_t base;
+} keyboard_vtable_t;
+
+void keyboard_init( keyboard_t *keyboard, keyboard_event_handler_t handler, void *context );
+void keyboard_activate( void *obj );
+void keyboard_deactivate( void *obj );
+void keyboard_deinit( void *obj );
+void keyboard_print_info( void *obj );
+
+uint32_t keyboard_handle_interrupt( interrupt_handler_t *handler, uint32_t esp );
+
+#endif // KEYBOARD_H
diff --git a/src/drivers/hdi/ps2/mouse.c b/src/drivers/hdi/ps2/mouse.c
new file mode 100644
index 0000000..46984eb
--- /dev/null
+++ b/src/drivers/hdi/ps2/mouse.c
@@ -0,0 +1,250 @@
+#include "mouse.h"
+
+#include "stdio.h"
+
+// status register on command port (read)
+#define STATUS_REG_OUTPUT_BUF_FULL 0x01
+#define STATUS_REG_INPUT_BUF_FULL 0x02
+#define STATUS_REG_OUTPUT_BUF2_FULL 0x20
+
+// status control register flags
+#define STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT2 0x02
+#define STATUS_CONTROL_CONFIG_CLOCK_PORT2 0x20
+
+// generic PS/2 commands
+#define COMMAND_GET_STATE 0x20
+#define COMMAND_SET_STATE 0x60
+#define COMMAND_DISABLE_PORT2 0xA7
+#define COMMAND_ENABLE_PORT2 0xA8
+#define COMMAND_SEND_TO_PORT2 0xD4
+
+// mouse commands
+#define MOUSE_COMMAND_GET_DEVICE_ID 0xF2
+#define MOUSE_COMMAND_SET_SAMPLE_RATE 0xF3
+#define MOUSE_COMMAND_ENABLE_DATAREPORTING 0xF4
+#define MOUSE_COMMAND_SET_DEFAULTS 0xF6
+#define DEFAULT_NOF_PACKETS 3
+
+// mouse data packet one
+#define MOUSE_BYTE1_LEFT_BUTTON 0x01
+#define MOUSE_BYTE1_RIGHT_BUTTON 0x02
+#define MOUSE_BYTE1_MIDDLE_BUTTON 0x04
+#define MOUSE_BYTE1_ID_BIT 0x08
+#define MOUSE_BYTE1_X_SIGN 0x10
+#define MOUSE_BYTE1_Y_SIGN 0x20
+#define MOUSE_BYTE1_X_OVERFLOW 0x40
+#define MOUSE_BYTE1_Y_OVERFLOW 0x80
+
+#undef DEBUG
+
+static uint8_t read_data( mouse_t *mouse )
+{
+ while( ( port8_read( &mouse->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) == 0 ) { }
+ return port8_read( &mouse->data_port );
+}
+
+static void send_command( mouse_t *mouse, uint8_t command )
+{
+ while( port8_read( &mouse->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { }
+ port8_write( &mouse->command_port, command );
+}
+
+static void write_data( mouse_t *mouse, uint8_t data )
+{
+ while( port8_read( &mouse->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { }
+ port8_write( &mouse->data_port, data );
+}
+
+static void read_ack( mouse_t *mouse )
+{
+ uint8_t data = read_data( mouse );
+ if( data == 0xFA ) {
+ return;
+ } else {
+ printf( "ERR PS/2 mouse: acknoledgment failed 0x%X\n", data );
+ }
+}
+
+static void set_sample_rate( mouse_t *mouse, uint8_t samples )
+{
+ send_command( mouse, COMMAND_SEND_TO_PORT2 );
+ write_data( mouse, MOUSE_COMMAND_SET_SAMPLE_RATE );
+ read_ack( mouse );
+
+ send_command( mouse, COMMAND_SEND_TO_PORT2 );
+ write_data( mouse, samples );
+ read_ack( mouse );
+}
+
+static mouse_vtable_t mouse_vtable = {
+ {
+ mouse_activate,
+ mouse_deactivate,
+ mouse_deinit,
+ mouse_print_info
+ }
+};
+
+void mouse_init( mouse_t *mouse, mouse_event_handler_t handler, void *context )
+{
+ memset( mouse, 0, sizeof( mouse_t ) );
+
+ // TODO: we should probe for wheel mouse and more than 3 packets
+ mouse->nof_packets = DEFAULT_NOF_PACKETS;
+
+ vga_text_t *vga_text = (vga_text_t *)context;
+
+ mouse->res_x = vga_text->res_x;
+ mouse->res_y = vga_text->res_y;
+ mouse->cursor_x = mouse->res_x / 2;
+ mouse->cursor_y = mouse->res_y / 2;
+ mouse->handler = handler;
+ mouse->context = context;
+
+ port8_init( &mouse->command_port, 0x64 );
+ port8_init( &mouse->data_port, 0x60 );
+
+ mouse->base.vtable = &mouse_vtable.base;
+}
+
+void mouse_activate( void *obj )
+{
+ puts( "Activating driver for PS/2 mouse.." );
+
+ mouse_t *mouse = obj;
+
+ // enable port 2
+ send_command( mouse, COMMAND_ENABLE_PORT2 );
+
+ // enable interrupts for port 2
+ send_command( mouse, COMMAND_GET_STATE );
+ uint8_t status = read_data( mouse );
+ status |= STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT2;
+ status &= ~STATUS_CONTROL_CONFIG_CLOCK_PORT2;
+ send_command( mouse, COMMAND_SET_STATE );
+ write_data( mouse, status );
+
+ // detecting mouse wheel (and 4th data packet)
+ set_sample_rate( mouse, 200 );
+ set_sample_rate( mouse, 100 );
+ set_sample_rate( mouse, 80 );
+ send_command( mouse, COMMAND_SEND_TO_PORT2 );
+ write_data( mouse, MOUSE_COMMAND_GET_DEVICE_ID );
+ read_ack( mouse );
+ uint8_t id = read_data( mouse );
+ printf( "PS/2 mouse model id is 0x%X\n", id );
+ if( id == 0x03 ) {
+ mouse->nof_packets = 4;
+ }
+
+ // set mouse defaults
+// send_command( mouse, COMMAND_SEND_TO_PORT2 );
+// write_data( mouse, MOUSE_COMMAND_SET_DEFAULTS );
+
+ // enable mouse on second port
+ send_command( mouse, COMMAND_SEND_TO_PORT2 );
+ write_data( mouse, MOUSE_COMMAND_ENABLE_DATAREPORTING );
+ read_ack( mouse );
+}
+
+void mouse_deactivate( void *obj )
+{
+ puts( "Dectivating driver for PS/2 mouse.." );
+
+ mouse_t *mouse = obj;
+
+ send_command( mouse, COMMAND_DISABLE_PORT2 );
+}
+
+void mouse_deinit( void *obj )
+{
+ // nothing to do
+}
+
+uint32_t mouse_handle_interrupt( interrupt_handler_t *handler, uint32_t esp )
+{
+ mouse_t *mouse = (mouse_t *)handler->driver;
+
+ uint8_t status = port8_read( &mouse->command_port );
+ if( !( status & STATUS_REG_OUTPUT_BUF2_FULL ) ) {
+ return esp;
+ }
+
+ mouse->buf[mouse->offset] = port8_read( &mouse->data_port );
+
+#ifdef DEBUG
+ printf( "MOUSE: %d 0x%X\n", mouse->offset, mouse->buf[mouse->offset] );
+#endif
+
+ switch( mouse->offset ) {
+ case 0:
+ if( mouse->buf[0] & MOUSE_BYTE1_ID_BIT ) {
+ for( int i = 0; i < 3; i++ ) {
+ if( ( mouse->buf[0] & ( 0x01 << i ) ) != ( mouse->buttons & ( 0x01 << i ) ) ) {
+ mouse_event_t event;
+ event.button = i + 1;
+ if( mouse->buttons & ( 0x01 << i ) ) {
+ event.type = MOUSE_EVENT_TYPE_BUTTON_UP;
+ } else {
+ event.type = MOUSE_EVENT_TYPE_BUTTON_DOWN;
+ }
+ event.cursor_x = mouse->cursor_x;
+ event.cursor_y = mouse->cursor_y;
+ mouse->handler( &event, mouse->context );
+ }
+ }
+ mouse->buttons = mouse->buf[0];
+ }
+ break;
+
+ case 1:
+ // delay evaluation of move events till second byte
+ break;
+
+ case 2:
+ if( mouse->buf[1] !=0 || mouse->buf[2] != 0 ) {
+
+ mouse_event_t event;
+ event.type = MOUSE_EVENT_TYPE_MOVE;
+ event.old_cursor_x = mouse->cursor_x;
+ event.old_cursor_y = mouse->cursor_y;
+
+ mouse->cursor_x += (int8_t)mouse->buf[1];
+ mouse->cursor_y -= (int8_t)mouse->buf[2];
+ if( mouse->cursor_x < 0 ) {
+ mouse->cursor_x = 0;
+ }
+ if( mouse->cursor_x > mouse->res_x - 1 ) {
+ mouse->cursor_x = mouse->res_x - 1;
+ }
+ if( mouse->cursor_y < 0 ) {
+ mouse->cursor_y = 0;
+ }
+ if( mouse->cursor_y > mouse->res_y - 1 ) {
+ mouse->cursor_y = mouse->res_y - 1;
+ }
+
+ event.cursor_x = mouse->cursor_x;
+ event.cursor_y = mouse->cursor_y;
+
+ mouse->handler( &event, mouse->context );
+ }
+
+ break;
+
+ case 3:
+ // TODO: read fourth data packet, but don't handle
+ // it yet
+ break;
+ }
+
+ // advance offset
+ mouse->offset = ( mouse->offset + 1 ) % mouse->nof_packets;
+
+ return esp;
+}
+
+void mouse_print_info( void *obj )
+{
+ puts( "PS/2 mouse driver" );
+}
diff --git a/src/drivers/hdi/ps2/mouse.h b/src/drivers/hdi/ps2/mouse.h
new file mode 100644
index 0000000..cbd02ef
--- /dev/null
+++ b/src/drivers/hdi/ps2/mouse.h
@@ -0,0 +1,65 @@
+#ifndef MOUSE_H
+#define MOUSE_H
+
+#include "string.h"
+
+#include "interrupts.h"
+#include "port.h"
+
+#include "driver.h"
+
+#define MAX_NOF_MOUSE_PACKETS 5
+
+typedef enum {
+ MOUSE_EVENT_TYPE_BUTTON_UP,
+ MOUSE_EVENT_TYPE_BUTTON_DOWN,
+ MOUSE_EVENT_TYPE_MOVE
+} mouse_event_type_t;
+
+typedef enum {
+ MOUSE_BUTTON_LEFT = 1,
+ MOUSE_BUTTON_RIGHT = 2,
+ MOUSE_BUTTON_MIDDLE = 3
+} mouse_button_t;
+
+typedef struct {
+ mouse_event_type_t type;
+ mouse_button_t button;
+ int32_t old_cursor_x;
+ int32_t old_cursor_y;
+ int32_t cursor_x;
+ int32_t cursor_y;
+} mouse_event_t;
+
+typedef void (*mouse_event_handler_t)( mouse_event_t *event, void *context );
+
+typedef struct {
+ driver_t base;
+ interrupt_t *interrupts;
+ port8_t command_port;
+ port8_t data_port;
+ int nof_packets; // 3 or more mouse packets
+ uint8_t buf[MAX_NOF_MOUSE_PACKETS];
+ uint8_t buttons;
+ uint8_t offset;
+ uint32_t res_x;
+ uint32_t res_y;
+ int32_t cursor_x;
+ int32_t cursor_y;
+ mouse_event_handler_t handler;
+ void *context;
+} mouse_t;
+
+typedef struct {
+ driver_vtable_t base;
+} mouse_vtable_t;
+
+void mouse_init( mouse_t *mouse, mouse_event_handler_t handler, void *context );
+void mouse_activate( void *obj );
+void mouse_deactivate( void *obj );
+void mouse_deinit( void *obj );
+void mouse_print_info( void *obj );
+
+uint32_t mouse_handle_interrupt( interrupt_handler_t *handler, uint32_t esp );
+
+#endif // MOUSE_H