diff --git a/src/add-ons/kernel/drivers/input/ps2_hid/Jamfile b/src/add-ons/kernel/drivers/input/ps2_hid/Jamfile index 9c6260be86..c20326858c 100644 --- a/src/add-ons/kernel/drivers/input/ps2_hid/Jamfile +++ b/src/add-ons/kernel/drivers/input/ps2_hid/Jamfile @@ -16,6 +16,7 @@ KernelAddon ps2_hid : kernel drivers bin : common.c keyboard.c mouse.c + packet_buffer.cpp ; } diff --git a/src/add-ons/kernel/drivers/input/ps2_hid/common.c b/src/add-ons/kernel/drivers/input/ps2_hid/common.c index 7c68778bbb..df06b1c964 100644 --- a/src/add-ons/kernel/drivers/input/ps2_hid/common.c +++ b/src/add-ons/kernel/drivers/input/ps2_hid/common.c @@ -8,18 +8,18 @@ * Stefano Ceccherini (burton666@libero.it) */ + #include #include #include "common.h" + #define DEVICE_MOUSE_NAME "input/mouse/ps2/0" #define DEVICE_KEYBOARD_NAME "input/keyboard/at/0" int32 api_version = B_CUR_DRIVER_API_VERSION; isa_module_info *gIsa = NULL; -int32 gMouseOpenMask; -int32 gKeyboardOpenMask; device_hooks keyboard_hooks = { @@ -58,7 +58,7 @@ mouse_hooks = { * port is still busy. */ -bool +bool wait_write_ctrl(void) { int8 read; @@ -68,7 +68,7 @@ wait_write_ctrl(void) read = gIsa->read_io_8(PS2_PORT_CTRL); spin(100); } while ((read & (PS2_IBUF_FULL | PS2_OBUF_FULL)) && tries-- > 0); - + return tries > 0; } @@ -77,7 +77,7 @@ wait_write_ctrl(void) * the "Input buffer full" bit will be set to 0. */ -bool +bool wait_write_data(void) { int8 read; @@ -87,7 +87,7 @@ wait_write_data(void) read = gIsa->read_io_8(PS2_PORT_CTRL); spin(100); } while ((read & PS2_IBUF_FULL) && tries-- > 0); - + return tries > 0; } @@ -96,7 +96,7 @@ wait_write_data(void) * "Output buffer full" bit will be set to 1. */ -bool +bool wait_read_data(void) { int8 read; @@ -106,25 +106,25 @@ wait_read_data(void) read = gIsa->read_io_8(PS2_PORT_CTRL); spin(100); } while (!(read & PS2_OBUF_FULL) && tries-- > 0); - + return tries > 0; } /** Get the ps2 command byte. */ -int8 +int8 get_command_byte(void) { int8 read = 0; - + TRACE(("set_command_byte()\n")); if (wait_write_ctrl()) { gIsa->write_io_8(PS2_PORT_CTRL, PS2_CTRL_READ_CMD); if (wait_read_data()) read = gIsa->read_io_8(PS2_PORT_DATA); } - + return read; } @@ -134,7 +134,7 @@ get_command_byte(void) * unsigned char, byte to write */ -void +void set_command_byte(unsigned char cmd) { TRACE(("set_command_byte()\n")); @@ -173,23 +173,25 @@ read_data_byte(void) * unsigned char, byte to write */ -void +void write_aux_byte(unsigned char cmd) { TRACE(("write_aux_byte()\n")); if (wait_write_ctrl()) { gIsa->write_io_8(PS2_PORT_CTRL, PS2_CTRL_WRITE_AUX); - + if (wait_write_data()) gIsa->write_io_8(PS2_PORT_DATA, cmd); } } -// driver stuff +// #pragma mark - +// driver interface -status_t -init_hardware() + +status_t +init_hardware(void) { return B_OK; } @@ -222,26 +224,23 @@ find_device(const char *name) } -status_t -init_driver() +status_t +init_driver(void) { status_t status; - + status = get_module(B_ISA_MODULE_NAME, (module_info **)&gIsa); if (status < B_OK) { TRACE(("Failed getting isa module: %s\n", strerror(status))); return status; } - - gMouseOpenMask = 0; - gKeyboardOpenMask = 0; - + return B_OK; } -void -uninit_driver() +void +uninit_driver(void) { put_module(B_ISA_MODULE_NAME); } diff --git a/src/add-ons/kernel/drivers/input/ps2_hid/common.h b/src/add-ons/kernel/drivers/input/ps2_hid/common.h index a1d8b2b400..38c37c87dd 100644 --- a/src/add-ons/kernel/drivers/input/ps2_hid/common.h +++ b/src/add-ons/kernel/drivers/input/ps2_hid/common.h @@ -1,152 +1,110 @@ -/* - * Copyright 2004 Haiku, Inc. - * Distributed under the terms of the Haiku License. - * - * common.h: - * PS/2 hid device driver - * Authors (in chronological order): - * Elad Lahav (elad@eldarshany.com) - * Stefano Ceccherini (burton666@libero.it) - */ - -/* - * A PS/2 mouse is connected to the IBM 8042 controller, and gets its - * name from the IBM PS/2 personal computer, which was the first to - * use this device. All resources are shared between the keyboard, and - * the mouse, referred to as the "Auxiliary Device". - * I/O: - * ~~~ - * The controller has 3 I/O registers: - * 1. Status (input), mapped to port 64h - * 2. Control (output), mapped to port 64h - * 3. Data (input/output), mapped to port 60h - * Data: - * ~~~~ - * Since a mouse is an input only device, data can only be read, and - * not written. A packet read from the mouse data port is composed of - * three bytes: - * byte 0: status byte, where - * - bit 0: Y overflow (1 = true) - * - bit 1: X overflow (1 = true) - * - bit 2: MSB of Y offset - * - bit 3: MSB of X offset - * - bit 4: Syncronization bit (always 1) - * - bit 5: Middle button (1 = down) - * - bit 6: Right button (1 = down) - * - bit 7: Left button (1 = down) - * byte 1: X position change, since last probed (-127 to +127) - * byte 2: Y position change, since last probed (-127 to +127) - * Interrupts: - * ~~~~~~~~~~ - * The PS/2 mouse device is connected to interrupt 12, which means that - * it uses the second interrupt controller (handles INT8 to INT15). In - * order for this interrupt to be enabled, both the 5th interrupt of - * the second controller AND the 3rd interrupt of the first controller - * (cascade mode) should be unmasked. - * The controller uses 3 consecutive interrupts to inform the computer - * that it has new data. On the first the data register holds the status - * byte, on the second the X offset, and on the 3rd the Y offset. - */ - -#ifndef __PS2COMMON_H -#define __PS2COMMON_H - -#include -#include -#include - -///////////////////////////////////////////////////////////////////////// -// definitions - -// I/O addresses -#define PS2_PORT_DATA 0x60 -#define PS2_PORT_CTRL 0x64 - -// data port bits -#define PS2_OBUF_FULL 0x01 -#define PS2_IBUF_FULL 0x02 -#define PS2_MOUSE_OBUF_FULL 0x20 -#define PS2_TIMEOUT 0x40 - -// control words -#define PS2_CTRL_READ_CMD 0x20 -#define PS2_CTRL_WRITE_CMD 0x60 -#define PS2_CTRL_WRITE_AUX 0xD4 -#define PS2_CTRL_MOUSE_DISABLE 0xA7 -#define PS2_CTRL_MOUSE_ENABLE 0xA8 -#define PS2_CTRL_MOUSE_TEST 0xA9 - -// command bytes -#define PS2_CMD_DEV_INIT 0x43 - -// command bits -#define PS2_BITS_AUX_INTERRUPT 0x02 -#define PS2_BITS_MOUSE_DISABLED 0x20 - -// data words -#define PS2_CMD_TEST_PASSED 0xAA -#define PS2_CMD_GET_DEVICE_ID 0xF2 -#define PS2_CMD_SET_SAMPLE_RATE 0xF3 -#define PS2_CMD_ENABLE_MOUSE 0xF4 -#define PS2_CMD_DISABLE_MOUSE 0xF5 -#define PS2_CMD_RESET_MOUSE 0xFF - -// reply codes -#define PS2_RES_TEST_PASSED 0x55 -#define PS2_RES_ACK 0xFA -#define PS2_RES_RESEND 0xFE -#define PS2_ERROR 0xFC - -// interrupts -#define INT_PS2_MOUSE 0x0C -#define INT_PS2_KEYBOARD 0x01 - -// other stuff -#define MOUSE_HISTORY_SIZE 256 - -// mouse device IDs -#define PS2_DEV_ID_STANDARD 0 -#define PS2_DEV_ID_INTELLIMOUSE 3 - -// packet sizes -#define PS2_PACKET_STANDARD 3 -#define PS2_PACKET_INTELLIMOUSE 4 -#define PS2_MAX_PACKET_SIZE 4 // Should be equal to the biggest packet size - -// debug defines -#ifdef DEBUG - #define TRACE(x) dprintf x -#else - #define TRACE(x) -#endif - -// global variables -extern isa_module_info *gIsa; -extern int32 gMouseOpenMask; -extern int32 gKeyboardOpenMask; - -// prototypes -bool wait_write_ctrl(void); -bool wait_write_data(void); -bool wait_read_data(void); -void write_aux_byte(unsigned char cmd); -uint8 read_data_byte(void); - -int8 get_command_byte(void); -void set_command_byte(unsigned char cmd); - -extern status_t keyboard_open(const char *name, uint32 flags, void **cookie); -extern status_t keyboard_close(void *cookie); -extern status_t keyboard_freecookie(void *cookie); -extern status_t keyboard_read(void *cookie, off_t pos, void *buf, size_t *len); -extern status_t keyboard_write(void * cookie, off_t pos, const void *buf, size_t *len); -extern status_t keyboard_ioctl(void *cookie, uint32 op, void *buf, size_t len); - -extern status_t mouse_open(const char *name, uint32 flags, void **cookie); -extern status_t mouse_close(void *cookie); -extern status_t mouse_freecookie(void *cookie); -extern status_t mouse_read(void *cookie, off_t pos, void *buf, size_t *len); -extern status_t mouse_write(void * cookie, off_t pos, const void *buf, size_t *len); -extern status_t mouse_ioctl(void *cookie, uint32 op, void *buf, size_t len); - -#endif /* __PS2COMMON_H */ +/* + * Copyright 2004-2005 Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * PS/2 hid device driver + * + * Authors (in chronological order): + * Elad Lahav (elad@eldarshany.com) + * Stefano Ceccherini (burton666@libero.it) + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef __PS2_COMMON_H +#define __PS2_COMMON_H + + +#include +#include +#include + + +///////////////////////////////////////////////////////////////////////// +// definitions + +// I/O addresses +#define PS2_PORT_DATA 0x60 +#define PS2_PORT_CTRL 0x64 + +// data port bits +#define PS2_OBUF_FULL 0x01 +#define PS2_IBUF_FULL 0x02 +#define PS2_MOUSE_OBUF_FULL 0x20 +#define PS2_TIMEOUT 0x40 + +// control words +#define PS2_CTRL_READ_CMD 0x20 +#define PS2_CTRL_WRITE_CMD 0x60 +#define PS2_CTRL_WRITE_AUX 0xD4 +#define PS2_CTRL_MOUSE_DISABLE 0xA7 +#define PS2_CTRL_MOUSE_ENABLE 0xA8 +#define PS2_CTRL_MOUSE_TEST 0xA9 + +// command bytes +#define PS2_CMD_DEV_INIT 0x43 + +// command bits +#define PS2_BITS_AUX_INTERRUPT 0x02 +#define PS2_BITS_MOUSE_DISABLED 0x20 + +// data words +#define PS2_CMD_TEST_PASSED 0xAA +#define PS2_CMD_GET_DEVICE_ID 0xF2 +#define PS2_CMD_SET_SAMPLE_RATE 0xF3 +#define PS2_CMD_ENABLE_MOUSE 0xF4 +#define PS2_CMD_DISABLE_MOUSE 0xF5 +#define PS2_CMD_RESET_MOUSE 0xFF + +// reply codes +#define PS2_RES_TEST_PASSED 0x55 +#define PS2_RES_ACK 0xFA +#define PS2_RES_RESEND 0xFE +#define PS2_ERROR 0xFC + +// interrupts +#define INT_PS2_MOUSE 0x0C +#define INT_PS2_KEYBOARD 0x01 + +// mouse device IDs +#define PS2_DEV_ID_STANDARD 0 +#define PS2_DEV_ID_INTELLIMOUSE 3 + +// packet sizes +#define PS2_PACKET_STANDARD 3 +#define PS2_PACKET_INTELLIMOUSE 4 +#define PS2_MAX_PACKET_SIZE 4 // Should be equal to the biggest packet size + +// debug defines +#ifdef DEBUG +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + +// global variables +extern isa_module_info *gIsa; + +// prototypes +bool wait_write_ctrl(void); +bool wait_write_data(void); +bool wait_read_data(void); +void write_aux_byte(unsigned char cmd); +uint8 read_data_byte(void); + +int8 get_command_byte(void); +void set_command_byte(unsigned char cmd); + +extern status_t keyboard_open(const char *name, uint32 flags, void **cookie); +extern status_t keyboard_close(void *cookie); +extern status_t keyboard_freecookie(void *cookie); +extern status_t keyboard_read(void *cookie, off_t pos, void *buf, size_t *len); +extern status_t keyboard_write(void * cookie, off_t pos, const void *buf, size_t *len); +extern status_t keyboard_ioctl(void *cookie, uint32 op, void *buf, size_t len); + +extern status_t mouse_open(const char *name, uint32 flags, void **cookie); +extern status_t mouse_close(void *cookie); +extern status_t mouse_freecookie(void *cookie); +extern status_t mouse_read(void *cookie, off_t pos, void *buf, size_t *len); +extern status_t mouse_write(void * cookie, off_t pos, const void *buf, size_t *len); +extern status_t mouse_ioctl(void *cookie, uint32 op, void *buf, size_t len); + +#endif /* __PS2_COMMON_H */ diff --git a/src/add-ons/kernel/drivers/input/ps2_hid/keyboard.c b/src/add-ons/kernel/drivers/input/ps2_hid/keyboard.c index f450870ba7..bc8d121c5f 100644 --- a/src/add-ons/kernel/drivers/input/ps2_hid/keyboard.c +++ b/src/add-ons/kernel/drivers/input/ps2_hid/keyboard.c @@ -2,28 +2,23 @@ * Copyright 2004-2005 Haiku, Inc. * Distributed under the terms of the MIT License. * - * keyboard.c: * PS/2 keyboard device driver + * * Authors (in chronological order): * Stefano Ceccherini (burton666@libero.it) + * Axel Dörfler, axeld@pinc-software.de */ -// TODO: Uncomment locking code -// We probably need to lock to avoid misbehaving on SMP machines, -// although the kb_mouse replacement driver never locks. #include "common.h" -#ifdef COMPILE_FOR_R5 -#include "cbuf_adapter.h" -#else -#include "cbuf.h" -#endif +#include "kb_mouse_driver.h" +#include "packet_buffer.h" #include -//#include -#include "kb_mouse_driver.h" +#define KEY_BUFFER_SIZE 100 + // we will buffer 100 key strokes before we start dropping them enum { LED_SCROLL = 1, @@ -31,15 +26,14 @@ enum { LED_CAPS = 4 } leds_status; - enum { PS2_SET_LEDS = 0xed } commands; +static int32 sKeyboardOpenMask; static sem_id sKeyboardSem; -//static mutex keyboard_read_mutex; -static cbuf *keyboard_buf; +static struct packet_buffer *sKeyBuffer; static bool sIsExtended = false; @@ -53,7 +47,7 @@ set_leds(led_info *ledInfo) leds |= LED_NUM; if (ledInfo->caps_lock) leds |= LED_CAPS; - + wait_write_data(); gIsa->write_io_8(PS2_PORT_DATA, PS2_SET_LEDS); wait_write_data(); @@ -67,7 +61,7 @@ handle_keyboard_interrupt(void *data) // TODO: Handle braindead "pause" key special case at_kbd_io keyInfo; unsigned char read, scancode; - + read = gIsa->read_io_8(PS2_PORT_DATA); TRACE(("handle_keyboard_interrupt: read = 0x%x\n", read)); @@ -76,9 +70,9 @@ handle_keyboard_interrupt(void *data) TRACE(("Extended key\n")); return B_HANDLED_INTERRUPT; } - + scancode = read; - + TRACE(("scancode: %x\n", scancode)); // For now, F12 enters the kernel debugger @@ -92,67 +86,72 @@ handle_keyboard_interrupt(void *data) } else keyInfo.is_keydown = true; - if (sIsExtended) + if (sIsExtended) { scancode |= 0x80; - + sIsExtended = false; + } + keyInfo.timestamp = system_time(); keyInfo.scancode = scancode; + + while (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo, sizeof(keyInfo)) == 0) { + // if there is no space left in the buffer, we start dropping old key strokes + packet_buffer_flush(sKeyBuffer, sizeof(keyInfo)); + } - // TODO: Check return value - cbuf_memcpy_to_chain(keyboard_buf, 0, (void *)&keyInfo, sizeof(keyInfo)); release_sem_etc(sKeyboardSem, 1, B_DO_NOT_RESCHEDULE); - - sIsExtended = false; - + return B_INVOKE_SCHEDULER; } static status_t -read_keyboard_packet(at_kbd_io *buffer) +read_keyboard_packet(at_kbd_io *userBuffer) { - status_t status; - status = acquire_sem_etc(sKeyboardSem, 1, B_CAN_INTERRUPT, 0); + at_kbd_io packet; + + status_t status = acquire_sem_etc(sKeyboardSem, 1, B_CAN_INTERRUPT, 0); if (status < B_OK) return status; - - status = cbuf_memcpy_from_chain((void *)buffer, keyboard_buf, 0, sizeof(at_kbd_io)); - if (status < B_OK) - TRACE(("read_keyboard_packet(): error reading packet: %s\n", strerror(status))); - TRACE(("scancode: %x, keydown: %s\n", buffer->scancode, buffer->is_keydown ? "true" : "false")); - return status; + if (packet_buffer_read(sKeyBuffer, (uint8 *)&packet, sizeof(at_kbd_io)) == 0) { + TRACE(("read_keyboard_packet(): error reading packet: %s\n", strerror(status))); + return B_ERROR; + } + + TRACE(("scancode: %x, keydown: %s\n", packet.scancode, packet.is_keydown ? "true" : "false")); + + return user_memcpy(userBuffer, &packet, sizeof(at_kbd_io)); } +// #pragma mark - + + status_t -keyboard_open(const char *name, uint32 flags, void **cookie) +keyboard_open(const char *name, uint32 flags, void **_cookie) { - status_t status; - TRACE(("keyboard open()\n")); - if (atomic_or(&gKeyboardOpenMask, 1) != 0) + + if (atomic_or(&sKeyboardOpenMask, 1) != 0) return B_BUSY; sKeyboardSem = create_sem(0, "keyboard_sem"); if (sKeyboardSem < 0) { - atomic_and(&gKeyboardOpenMask, 0); - status = sKeyboardSem; - return status; + atomic_and(&sKeyboardOpenMask, 0); + return sKeyboardSem; } - - //if (mutex_init(&keyboard_read_mutex, "keyboard_read_mutex") < 0) - // panic("could not create keyboard read mutex!\n"); - keyboard_buf = cbuf_get_chain(1024); - if (keyboard_buf == NULL) - panic("could not create keyboard cbuf chain!\n"); + sKeyBuffer = create_packet_buffer(KEY_BUFFER_SIZE * sizeof(at_kbd_io)); + if (sKeyBuffer == NULL) { + panic("could not create keyboard packet buffer!\n"); + atomic_and(&sKeyboardOpenMask, 0); + return B_NO_MEMORY; + } - status = install_io_interrupt_handler(1, &handle_keyboard_interrupt, NULL, 0); - - *cookie = NULL; - - return status; + *_cookie = NULL; + + return install_io_interrupt_handler(1, &handle_keyboard_interrupt, NULL, 0); } @@ -161,12 +160,11 @@ keyboard_close(void *cookie) { remove_io_interrupt_handler(1, &handle_keyboard_interrupt, NULL); - cbuf_free_chain(keyboard_buf); + delete_packet_buffer(sKeyBuffer); delete_sem(sKeyboardSem); - //mutex_destroy(&keyboard_read_mutex); - - atomic_and(&gKeyboardOpenMask, 0); - + + atomic_and(&sKeyboardOpenMask, 0); + return B_OK; } @@ -188,30 +186,39 @@ keyboard_read(void *cookie, off_t pos, void *buffer, size_t *_length) status_t -keyboard_write(void *cookie, off_t pos, const void *buf, size_t *len) +keyboard_write(void *cookie, off_t pos, const void *buffer, size_t *_length) { TRACE(("keyboard write()\n")); - *len = 0; + *_length = 0; return B_NOT_ALLOWED; } status_t -keyboard_ioctl(void *cookie, uint32 op, void *buf, size_t len) +keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length) { TRACE(("keyboard ioctl()\n")); switch (op) { case KB_READ: TRACE(("KB_READ\n")); - return read_keyboard_packet((at_kbd_io *)buf); + return read_keyboard_packet((at_kbd_io *)buffer); + case KB_SET_LEDS: - set_leds((led_info *)buf); + { + led_info info; + if (user_memcpy(&info, buffer, sizeof(led_info)) < B_OK) + return B_BAD_ADDRESS; + TRACE(("KB_SET_LEDS\n")); + set_leds(&info); return B_OK; + } + case KB_SET_KEY_REPEATING: case KB_SET_KEY_NONREPEATING: TRACE(("ioctl 0x%x not implemented yet, returning B_OK\n", op)); return B_OK; + default: TRACE(("invalid ioctl 0x%x\n", op)); return EINVAL; diff --git a/src/add-ons/kernel/drivers/input/ps2_hid/mouse.c b/src/add-ons/kernel/drivers/input/ps2_hid/mouse.c index f23f987b99..aed171ee45 100644 --- a/src/add-ons/kernel/drivers/input/ps2_hid/mouse.c +++ b/src/add-ons/kernel/drivers/input/ps2_hid/mouse.c @@ -2,11 +2,12 @@ * Copyright 2001-2005 Haiku, Inc. * Distributed under the terms of the MIT License. * - * ps2mouse.c: * PS/2 mouse device driver + * * Authors (in chronological order): * Elad Lahav (elad@eldarshany.com) * Stefano Ceccherini (burton666@libero.it) + * Axel Dörfler, axeld@pinc-software.de */ /* @@ -14,12 +15,14 @@ * name from the IBM PS/2 personal computer, which was the first to * use this device. All resources are shared between the keyboard, and * the mouse, referred to as the "Auxiliary Device". + * * I/O: * ~~~ * The controller has 3 I/O registers: * 1. Status (input), mapped to port 64h * 2. Control (output), mapped to port 64h * 3. Data (input/output), mapped to port 60h + * * Data: * ~~~~ * A packet read from the mouse data port is composed of @@ -54,24 +57,21 @@ * byte, on the second the X offset, and on the 3rd the Y offset. */ -#include -#include +#include #include #include "kb_mouse_driver.h" - #include "common.h" +#include "packet_buffer.h" -#ifdef COMPILE_FOR_R5 - #include "cbuf_adapter.h" -#else - #include -#endif + +#define MOUSE_HISTORY_SIZE 256 + // we record that many mouse packets before we start to drop them static sem_id sMouseSem; static int32 sSync; -static cbuf *sMouseChain; +static struct packet_buffer *sMouseBuffer; static int32 sOpenMask; static bigtime_t sLastClickTime; @@ -81,6 +81,7 @@ static int sButtonsState; static int32 sPacketSize; + ///////////////////////////////////////////////////////////////////////// // mouse functions @@ -109,7 +110,7 @@ ps2_enable_mouse(bool enable) { int32 tries = 2; uint8 read; - + do { write_aux_byte(enable ? PS2_CMD_ENABLE_MOUSE : PS2_CMD_DISABLE_MOUSE); read = read_data_byte(); @@ -117,7 +118,7 @@ ps2_enable_mouse(bool enable) break; spin(100); } while (read == PS2_RES_RESEND && tries-- > 0); - + if (read != PS2_RES_ACK) return B_ERROR; @@ -132,14 +133,14 @@ static status_t ps2_set_sample_rate(uint32 rate) { status_t status = B_ERROR; - + write_aux_byte(PS2_CMD_SET_SAMPLE_RATE); if (read_data_byte() == PS2_RES_ACK) { write_aux_byte(rate); if (read_data_byte() == PS2_RES_ACK) status = B_OK; } - + return status; } @@ -153,32 +154,30 @@ ps2_packet_to_movement(uint8 packet[], mouse_movement *pos) int buttons = packet[0] & 7; int xDelta = ((packet[0] & 0x10) ? 0xFFFFFF00 : 0) | packet[1]; int yDelta = ((packet[0] & 0x20) ? 0xFFFFFF00 : 0) | packet[2]; - bigtime_t currentTime = system_time(); + bigtime_t currentTime = system_time(); int8 wheel_ydelta = 0; int8 wheel_xdelta = 0; - - if (buttons != 0) { - if (sButtonsState == 0) { - if (sLastClickTime + sClickSpeed > currentTime) - sClickCount++; - else - sClickCount = 1; - } - } - - sLastClickTime = currentTime; - sButtonsState = buttons; - - if (sPacketSize == PS2_PACKET_INTELLIMOUSE) { - switch (packet[3] & 0x0F) { + + if (buttons != 0 && sButtonsState == 0) { + if (sLastClickTime + sClickSpeed > currentTime) + sClickCount++; + else + sClickCount = 1; + } + + sLastClickTime = currentTime; + sButtonsState = buttons; + + if (sPacketSize == PS2_PACKET_INTELLIMOUSE) { + switch (packet[3] & 0x0F) { case 0x01: wheel_ydelta = +1; break; // wheel 1 down case 0x0F: wheel_ydelta = -1; break; // wheel 1 up case 0x02: wheel_xdelta = +1; break; // wheel 2 down case 0x0E: wheel_xdelta = -1; break; // wheel 2 up } - } - - if (pos) { + } + + if (pos) { pos->xdelta = xDelta; pos->ydelta = yDelta; pos->buttons = buttons; @@ -188,33 +187,35 @@ ps2_packet_to_movement(uint8 packet[], mouse_movement *pos) pos->wheel_ydelta = (int)wheel_ydelta; pos->wheel_xdelta = (int)wheel_xdelta; - TRACE(("xdelta: %d, ydelta: %d, buttons %x, clicks: %d, timestamp %Ld\n", xDelta, yDelta, buttons, sClickCount, currentTime)); + TRACE(("xdelta: %d, ydelta: %d, buttons %x, clicks: %d, timestamp %Ld\n", + xDelta, yDelta, buttons, sClickCount, currentTime)); } } /** Read a mouse event from the mouse events chain buffer. */ + static status_t -ps2_mouse_read(mouse_movement *pos) +ps2_mouse_read(mouse_movement *userMovement) { - status_t status; uint8 packet[PS2_MAX_PACKET_SIZE]; - + mouse_movement movement; + status_t status; + TRACE(("ps2_mouse_read()\n")); status = acquire_sem_etc(sMouseSem, 1, B_CAN_INTERRUPT, 0); if (status < B_OK) return status; - - status = cbuf_memcpy_from_chain(packet, sMouseChain, 0, sPacketSize); - if (status < B_OK) { + + if (packet_buffer_read(sMouseBuffer, packet, sPacketSize) < (size_t)sPacketSize) { TRACE(("error copying buffer\n")); return status; } - - ps2_packet_to_movement(packet, pos); - - return B_OK; + + ps2_packet_to_movement(packet, &movement); + + return user_memcpy(userMovement, &movement, sizeof(mouse_movement)); } @@ -228,74 +229,74 @@ ps2_mouse_read(mouse_movement *pos) * by read() operations. The full data is obtained using 3 consecutive * calls to the handler, each holds a different byte on the data port. */ + static int32 handle_mouse_interrupt(void* data) { - int8 read; - //TRACE(("mouse interrupt occurred!!!\n")); - - read = gIsa->read_io_8(PS2_PORT_CTRL); - + int8 read = gIsa->read_io_8(PS2_PORT_CTRL); if (read < 0) { TRACE(("Interrupt was not generated by the ps2 mouse\n")); return B_UNHANDLED_INTERRUPT; } - + read = read_data_byte(); TRACE(("mouse interrupt : byte %x\n", read)); - cbuf_memcpy_to_chain(sMouseChain, sSync, &read, sizeof(read)); - + while (packet_buffer_write(sMouseBuffer, &read, sizeof(read)) == 0) { + // we start dropping packets when the buffer is full + packet_buffer_flush(sMouseBuffer, sPacketSize); + } + if (sSync == 0 && !(read & 8)) { TRACE(("mouse resynched, bad data\n")); return B_HANDLED_INTERRUPT; } - + if (++sSync == sPacketSize) { TRACE(("mouse synched\n")); sSync = 0; release_sem_etc(sMouseSem, 1, B_DO_NOT_RESCHEDULE); - + return B_INVOKE_SCHEDULER; } - + return B_HANDLED_INTERRUPT; } -///////////////////////////////////////////////////////////////////////// -// file operations +// #pragma mark - +// Device functions status_t -mouse_open(const char *name, uint32 flags, void **cookie) +mouse_open(const char *name, uint32 flags, void **_cookie) { status_t status; int8 commandByte; int8 deviceId = -1; - + TRACE(("mouse_open()\n")); - + if (atomic_or(&sOpenMask, 1) != 0) return B_BUSY; - + // get device id write_aux_byte(PS2_CMD_GET_DEVICE_ID); if (read_data_byte() == PS2_RES_ACK) deviceId = read_data_byte(); - + TRACE(("init_driver: device id: %2x\n", deviceId)); if (deviceId == 0) { // try to switch to intellimouse mode ps2_set_sample_rate(200); ps2_set_sample_rate(100); ps2_set_sample_rate(80); - } - + } + // get device id, again write_aux_byte(PS2_CMD_GET_DEVICE_ID); if (read_data_byte() == PS2_RES_ACK) deviceId = read_data_byte(); - + if (deviceId == PS2_DEV_ID_STANDARD) { sPacketSize = PS2_PACKET_STANDARD; TRACE(("Standard ps2 mouse found\n")); @@ -307,92 +308,89 @@ mouse_open(const char *name, uint32 flags, void **cookie) put_module(B_ISA_MODULE_NAME); return B_ERROR; // Something's wrong. Better quit } - - sMouseChain = cbuf_get_chain(MOUSE_HISTORY_SIZE); - if (sMouseChain == NULL) { - TRACE(("can't allocate cbuf chain\n")); + + sMouseBuffer = create_packet_buffer(MOUSE_HISTORY_SIZE * sPacketSize); + if (sMouseBuffer == NULL) { + TRACE(("can't allocate mouse actions buffer\n")); put_module(B_ISA_MODULE_NAME); return B_ERROR; } - + // create the mouse semaphore, used for synchronization between // the interrupt handler and the read operation sMouseSem = create_sem(0, "ps2_mouse_sem"); if (sMouseSem < 0) { TRACE(("failed creating PS/2 mouse semaphore!\n")); - cbuf_free_chain(sMouseChain); + delete_packet_buffer(sMouseBuffer); put_module(B_ISA_MODULE_NAME); return sMouseSem; } - + set_sem_owner(sMouseSem, B_SYSTEM_TEAM); - - *cookie = NULL; - + + *_cookie = NULL; + commandByte = get_command_byte(); commandByte |= PS2_BITS_AUX_INTERRUPT; commandByte &= ~PS2_BITS_MOUSE_DISABLED; set_command_byte(commandByte); - + status = ps2_enable_mouse(true); if (status < B_OK) { TRACE(("mouse_open(): cannot enable PS/2 mouse\n")); return B_ERROR; } - + TRACE(("mouse_open(): mouse succesfully enabled\n")); - + // register interrupt handler - status = install_io_interrupt_handler(INT_PS2_MOUSE, handle_mouse_interrupt, NULL, 0); - - return status; + return install_io_interrupt_handler(INT_PS2_MOUSE, handle_mouse_interrupt, NULL, 0); } -status_t -mouse_close(void * cookie) +status_t +mouse_close(void *cookie) { TRACE(("mouse_close()\n")); ps2_enable_mouse(false); - - cbuf_free_chain(sMouseChain); + + delete_packet_buffer(sMouseBuffer); delete_sem(sMouseSem); - + remove_io_interrupt_handler(INT_PS2_MOUSE, handle_mouse_interrupt, NULL); - + atomic_and(&sOpenMask, 0); - + return B_OK; } status_t -mouse_freecookie(void * cookie) +mouse_freecookie(void *cookie) { return B_OK; } status_t -mouse_read(void *cookie, off_t pos, void *buf, size_t *len) +mouse_read(void *cookie, off_t pos, void *buffer, size_t *_length) { - *len = 0; + *_length = 0; return B_NOT_ALLOWED; } -status_t -mouse_write(void * cookie, off_t pos, const void *buf, size_t *len) +status_t +mouse_write(void *cookie, off_t pos, const void *buffer, size_t *_length) { - *len = 0; + *_length = 0; return B_NOT_ALLOWED; } -status_t -mouse_ioctl(void *cookie, uint32 op, void *buf, size_t len) +status_t +mouse_ioctl(void *cookie, uint32 op, void *buffer, size_t length) { - mouse_movement *pos = (mouse_movement *)buf; switch (op) { case MS_NUM_EVENTS: { @@ -401,28 +399,34 @@ mouse_ioctl(void *cookie, uint32 op, void *buf, size_t len) get_sem_count(sMouseSem, &count); return count; } + case MS_READ: TRACE(("MS_READ\n")); - return ps2_mouse_read(pos); + return ps2_mouse_read((mouse_movement *)buffer); + case MS_SET_TYPE: TRACE(("MS_SET_TYPE not implemented\n")); - return EINVAL; + return B_BAD_VALUE; + case MS_SET_MAP: TRACE(("MS_SET_MAP (set mouse mapping) not implemented\n")); - return EINVAL; + return B_BAD_VALUE; + case MS_GET_ACCEL: TRACE(("MS_GET_ACCEL (get mouse acceleration) not implemented\n")); - return EINVAL; + return B_BAD_VALUE; + case MS_SET_ACCEL: TRACE(("MS_SET_ACCEL (set mouse acceleration) not implemented\n")); - return EINVAL; + return B_BAD_VALUE; + case MS_SET_CLICKSPEED: TRACE(("MS_SETCLICK (set click speed)\n")); - sClickSpeed = *(bigtime_t *)buf; - return B_OK; + return user_memcpy(&sClickSpeed, buffer, sizeof(bigtime_t)); + default: TRACE(("unknown opcode: %ld\n", op)); - return EINVAL; + return B_BAD_VALUE; } } diff --git a/src/add-ons/kernel/drivers/input/ps2_hid/packet_buffer.cpp b/src/add-ons/kernel/drivers/input/ps2_hid/packet_buffer.cpp new file mode 100644 index 0000000000..6bf52e08d2 --- /dev/null +++ b/src/add-ons/kernel/drivers/input/ps2_hid/packet_buffer.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "packet_buffer.h" + +#include +#include + +#include +#include + + +/** The idea behind this packet buffer is to have multi-threading safe + * implementation that can be used in interrupts on top of the + * ring_buffer implementation provided by the kernel. + * It uses a spinlock for synchronization. + * + * IOW if you don't have such high restrictions in your environment, + * you better don't want to use it at all. + */ + +struct packet_buffer { + struct ring_buffer *buffer; + spinlock lock; +}; + + +struct packet_buffer * +create_packet_buffer(size_t size) +{ + struct packet_buffer *buffer = (packet_buffer *)malloc(sizeof(packet_buffer)); + if (buffer == NULL) + return NULL; + + buffer->buffer = create_ring_buffer(size); + if (buffer->buffer == NULL) { + free(buffer); + return NULL; + } + buffer->lock = 0; + + return buffer; +} + + +void +delete_packet_buffer(struct packet_buffer *buffer) +{ + delete_ring_buffer(buffer->buffer); + free(buffer); +} + + +void +packet_buffer_clear(struct packet_buffer *buffer) +{ + cpu_status state = disable_interrupts(); + acquire_spinlock(&buffer->lock); + + ring_buffer_clear(buffer->buffer); + + release_spinlock(&buffer->lock); + restore_interrupts(state); +} + + +size_t +packet_buffer_readable(struct packet_buffer *buffer) +{ + cpu_status state = disable_interrupts(); + acquire_spinlock(&buffer->lock); + + size_t available = ring_buffer_readable(buffer->buffer); + + release_spinlock(&buffer->lock); + restore_interrupts(state); + + return available; +} + + +size_t +packet_buffer_writable(struct packet_buffer *buffer) +{ + cpu_status state = disable_interrupts(); + acquire_spinlock(&buffer->lock); + + size_t left = ring_buffer_writable(buffer->buffer); + + release_spinlock(&buffer->lock); + restore_interrupts(state); + + return left; +} + + +void +packet_buffer_flush(struct packet_buffer *buffer, size_t length) +{ + cpu_status state = disable_interrupts(); + acquire_spinlock(&buffer->lock); + + ring_buffer_flush(buffer->buffer, length); + + release_spinlock(&buffer->lock); + restore_interrupts(state); +} + + +size_t +packet_buffer_read(struct packet_buffer *buffer, uint8 *data, size_t length) +{ + cpu_status state = disable_interrupts(); + acquire_spinlock(&buffer->lock); + + size_t bytesRead = ring_buffer_read(buffer->buffer, data, length); + + release_spinlock(&buffer->lock); + restore_interrupts(state); + + return bytesRead; +} + + +size_t +packet_buffer_write(struct packet_buffer *buffer, const uint8 *data, size_t length) +{ + cpu_status state = disable_interrupts(); + acquire_spinlock(&buffer->lock); + + size_t bytesWritten = ring_buffer_write(buffer->buffer, data, length); + + release_spinlock(&buffer->lock); + restore_interrupts(state); + + return bytesWritten; +} + diff --git a/src/add-ons/kernel/drivers/input/ps2_hid/packet_buffer.h b/src/add-ons/kernel/drivers/input/ps2_hid/packet_buffer.h new file mode 100644 index 0000000000..97a3f6b6ec --- /dev/null +++ b/src/add-ons/kernel/drivers/input/ps2_hid/packet_buffer.h @@ -0,0 +1,32 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKET_BUFFER_H +#define PACKET_BUFFER_H + + +#include + + +struct packet_buffer; + +#ifdef __cplusplus +extern "C" { +#endif + +struct packet_buffer *create_packet_buffer(size_t size); +void delete_packet_buffer(struct packet_buffer *buffer); + +void packet_buffer_clear(struct packet_buffer *buffer); +size_t packet_buffer_readable(struct packet_buffer *buffer); +size_t packet_buffer_writable(struct packet_buffer *buffer); +void packet_buffer_flush(struct packet_buffer *buffer, size_t bytes); +size_t packet_buffer_read(struct packet_buffer *buffer, uint8 *data, size_t length); +size_t packet_buffer_write(struct packet_buffer *buffer, const uint8 *data, size_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* PACKET_BUFFER_H */