From d6d1bdfefafff50b7b6d15d218c0a188570be541 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 10 Jun 2017 21:26:24 +0200 Subject: 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 --- src/drivers/driver.c | 65 +++++++++ src/drivers/driver.h | 31 ++++ src/drivers/hdi/ps2/keyboard.c | 316 +++++++++++++++++++++++++++++++++++++++++ src/drivers/hdi/ps2/keyboard.h | 69 +++++++++ src/drivers/hdi/ps2/mouse.c | 250 ++++++++++++++++++++++++++++++++ src/drivers/hdi/ps2/mouse.h | 65 +++++++++ 6 files changed, 796 insertions(+) create mode 100644 src/drivers/driver.c create mode 100644 src/drivers/driver.h create mode 100644 src/drivers/hdi/ps2/keyboard.c create mode 100644 src/drivers/hdi/ps2/keyboard.h create mode 100644 src/drivers/hdi/ps2/mouse.c create mode 100644 src/drivers/hdi/ps2/mouse.h (limited to 'src/drivers') 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 + +#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 -- cgit v1.2.3-54-g00ecf