From dfd5628d64b9a717916400a5efe6b01403ac07ca Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Sat, 21 Jan 2006 15:45:22 +0000 Subject: [PATCH] implemented basic support for multiple mouse devices, seems to work git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16022 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/bus_managers/ps2/ps2_common.c | 7 - .../kernel/bus_managers/ps2/ps2_common.h | 7 +- src/add-ons/kernel/bus_managers/ps2/ps2_dev.c | 55 +++-- src/add-ons/kernel/bus_managers/ps2/ps2_dev.h | 16 +- .../kernel/bus_managers/ps2/ps2_keyboard.c | 1 + .../kernel/bus_managers/ps2/ps2_mouse.c | 204 ++++++++++-------- 6 files changed, 173 insertions(+), 117 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_common.c b/src/add-ons/kernel/bus_managers/ps2/ps2_common.c index 5d0b1d2fd7..86fb1f23ba 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_common.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_common.c @@ -173,13 +173,6 @@ ps2_keyboard_command(uint8 cmd, const uint8 *out, int out_count, uint8 *in, int return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], cmd, out, out_count, in, in_count); } - -status_t -ps2_mouse_command(uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count) -{ - return ps2_dev_command(&ps2_device[PS2_DEVICE_MOUSE], cmd, out, out_count, in, in_count); -} - // #pragma mark - inline status_t diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_common.h b/src/add-ons/kernel/bus_managers/ps2/ps2_common.h index ae0673ad84..93863606d0 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_common.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_common.h @@ -19,6 +19,7 @@ #include #include "ps2_defs.h" +#include "ps2_dev.h" // debug defines @@ -50,7 +51,6 @@ extern void ps2_flush(); extern status_t ps2_command(uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count); extern status_t ps2_keyboard_command(uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count); -extern status_t ps2_mouse_command(uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count); extern status_t ps2_get_command_byte(uint8 *byte); extern status_t ps2_set_command_byte(uint8 byte); @@ -60,14 +60,11 @@ extern void ps2_unclaim_result(void); extern status_t ps2_wait_for_result(void); extern bool ps2_handle_result(uint8 data); -extern void ps2_common_uninitialize(void); -extern status_t ps2_common_initialize(void); // prototypes from keyboard.c & mouse.c extern status_t probe_keyboard(void); -extern status_t probe_mouse(size_t *probed_packet_size); -extern int32 mouse_handle_int(uint8 data); +extern int32 mouse_handle_int(ps2_dev *dev, uint8 data); extern int32 keyboard_handle_int(uint8 data); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c index c4735b790c..787ed479ae 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c @@ -89,30 +89,43 @@ ps2_dev_unpublish(ps2_dev *dev) int32 ps2_dev_handle_int(ps2_dev *dev, uint8 data) { - if (!dev->active) { - ps2_service_handle_device_added(dev); - } - - if (dev->result_buf_cnt) { - dev->result_buf[dev->result_buf_idx] = data; - dev->result_buf_idx++; - dev->result_buf_cnt--; - if (dev->result_buf_cnt == 0) { - release_sem_etc(dev->result_sem, 1, B_DO_NOT_RESCHEDULE); - return B_INVOKE_SCHEDULER; + uint32 flags; + + flags = atomic_get(&dev->flags); + + if (flags & PS2_FLAG_CMD) { + if ((flags & (PS2_FLAG_ACK | PS2_FLAG_NACK)) == 0) { + atomic_or(&dev->flags, data == 0xfa ? PS2_FLAG_ACK : PS2_FLAG_NACK); + } else if (dev->result_buf_cnt) { + dev->result_buf[dev->result_buf_idx] = data; + dev->result_buf_idx++; + dev->result_buf_cnt--; + if (dev->result_buf_cnt == 0) { + release_sem_etc(dev->result_sem, 1, B_DO_NOT_RESCHEDULE); + return B_INVOKE_SCHEDULER; + } + } else { + dprintf("ps2_dev_handle_int can't handle\n"); } return B_HANDLED_INTERRUPT; } - + if (!dev->active) { + ps2_service_handle_device_added(dev); + dprintf("not active, data dropped\n"); return B_HANDLED_INTERRUPT; } + if ((flags & PS2_FLAG_ENABLED) == 0) { + dprintf("not enabled, data dropped\n"); + return B_HANDLED_INTERRUPT; + } + // temporary hack... - if (dev->flags & PS2_FLAG_KEYB) + if (flags & PS2_FLAG_KEYB) return keyboard_handle_int(data); else - return mouse_handle_int(data); + return mouse_handle_int(dev, data); } @@ -124,6 +137,8 @@ ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 dprintf("ps2_dev_command %02x, %d out, in %d, dev %s\n", cmd, out_count, in_count, dev->name); + dev->flags |= PS2_FLAG_CMD; + dev->flags &= ~(PS2_FLAG_ACK | PS2_FLAG_NACK); dev->result_buf_cnt = in_count; dev->result_buf_idx = 0; @@ -147,6 +162,16 @@ ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 ps2_write_data(i == -1 ? cmd : out[i]); } } + + if (dev->flags & PS2_FLAG_ACK) { + dprintf("ps2_dev_command got ACK\n"); + } + + if (dev->flags & PS2_FLAG_NACK) { + dev->flags &= ~PS2_FLAG_CMD; + dprintf("ps2_dev_command got NACK\n"); + return B_ERROR; + } if (res != B_OK) { dprintf("ps2_dev_command send failed\n"); @@ -166,6 +191,8 @@ ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 dprintf("ps2_dev_command data %02x\n", in[i]); } + dev->flags &= ~PS2_FLAG_CMD; + return res; } diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h index a84fc13469..76c7931d37 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h @@ -10,9 +10,13 @@ #ifndef __PS2_DEV_H #define __PS2_DEV_H +struct ps2_dev; +typedef struct ps2_dev ps2_dev; + #include "ps2_common.h" -typedef struct + +struct ps2_dev { const char * name; bool active; @@ -22,14 +26,20 @@ typedef struct uint8 * result_buf; int result_buf_idx; int result_buf_cnt; -} ps2_dev; + void * cookie; +}; extern ps2_dev ps2_device[5]; #define PS2_DEVICE_MOUSE 0 #define PS2_DEVICE_KEYB 4 -#define PS2_FLAG_KEYB 1 +#define PS2_FLAG_KEYB (1<<0) +#define PS2_FLAG_OPEN (1<<1) +#define PS2_FLAG_ENABLED (1<<2) +#define PS2_FLAG_CMD (1<<3) +#define PS2_FLAG_ACK (1<<4) +#define PS2_FLAG_NACK (1<<5) status_t ps2_dev_init(void); void ps2_dev_exit(void); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c b/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c index f0d4f9e8c4..11e2938181 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_keyboard.c @@ -225,6 +225,7 @@ keyboard_open(const char *name, uint32 flags, void **_cookie) goto err3; } + atomic_or(&ps2_device[PS2_DEVICE_KEYB].flags, PS2_FLAG_ENABLED); release_sem(gDeviceOpenSemaphore); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c b/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c index 2874de0f09..b1b64670c0 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c @@ -60,39 +60,44 @@ #include #include +#include #include "kb_mouse_driver.h" -#include "ps2_common.h" #include "packet_buffer.h" +#include "ps2_common.h" +#include "ps2_dev.h" #define MOUSE_HISTORY_SIZE 256 // we record that many mouse packets before we start to drop them -static sem_id sMouseSem; -static struct packet_buffer *sMouseBuffer; -static int32 sOpenMask; - -static bigtime_t sLastClickTime; -static bigtime_t sClickSpeed; -static int32 sClickCount; -static int sButtonsState; - -static size_t sPacketSize; -static size_t sPacketIndex; -static uint8 sPacketBuffer[PS2_MAX_PACKET_SIZE]; - +typedef struct +{ + ps2_dev * dev; + + sem_id mouse_sem; + packet_buffer * mouse_buffer; + bigtime_t click_last_time; + bigtime_t click_speed; + int click_count; + int buttons_state; + + size_t packet_size; + size_t packet_index; + uint8 packet_buffer[PS2_MAX_PACKET_SIZE]; +} mouse_cookie; + static status_t -ps2_reset_mouse() +ps2_reset_mouse(mouse_cookie *cookie) { uint8 read; status_t status; TRACE(("ps2_reset_mouse()\n")); - status = ps2_mouse_command(PS2_CMD_RESET_MOUSE, NULL, 0, &read, 1); + status = ps2_dev_command(cookie->dev, PS2_CMD_RESET_MOUSE, NULL, 0, &read, 1); TRACE(("reset mouse: status 0x%08x, data 0x%02x\n", status, read)); @@ -105,12 +110,12 @@ ps2_reset_mouse() */ static status_t -ps2_set_sample_rate(uint8 rate) +ps2_set_sample_rate(mouse_cookie *cookie, uint8 rate) { int32 tries = 5; while (--tries > 0) { - status_t status = ps2_mouse_command(PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0); + status_t status = ps2_dev_command(cookie->dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0); if (status == B_OK) return B_OK; @@ -124,7 +129,7 @@ ps2_set_sample_rate(uint8 rate) */ static void -ps2_packet_to_movement(uint8 packet[], mouse_movement *pos) +ps2_packet_to_movement(mouse_cookie *cookie, uint8 packet[], mouse_movement *pos) { int buttons = packet[0] & 7; int xDelta = ((packet[0] & 0x10) ? 0xFFFFFF00 : 0) | packet[1]; @@ -133,17 +138,17 @@ ps2_packet_to_movement(uint8 packet[], mouse_movement *pos) int8 wheel_ydelta = 0; int8 wheel_xdelta = 0; - if (buttons != 0 && sButtonsState == 0) { - if (sLastClickTime + sClickSpeed > currentTime) - sClickCount++; + if (buttons != 0 && cookie->buttons_state == 0) { + if (cookie->click_last_time + cookie->click_speed > currentTime) + cookie->click_count++; else - sClickCount = 1; + cookie->click_count = 1; } - sLastClickTime = currentTime; - sButtonsState = buttons; + cookie->click_last_time = currentTime; + cookie->buttons_state = buttons; - if (sPacketSize == PS2_PACKET_INTELLIMOUSE) { + if (cookie->packet_size == 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 @@ -154,20 +159,20 @@ ps2_packet_to_movement(uint8 packet[], mouse_movement *pos) // dprintf("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, w-yd %d\n", // packet[0], packet[1], packet[2], packet[3], -// xDelta, yDelta, buttons, sClickCount, wheel_xdelta, wheel_ydelta); +// xDelta, yDelta, buttons, cookie->click_count, wheel_xdelta, wheel_ydelta); if (pos) { pos->xdelta = xDelta; pos->ydelta = yDelta; pos->buttons = buttons; - pos->clicks = sClickCount; + pos->clicks = cookie->click_count; pos->modifiers = 0; pos->timestamp = currentTime; pos->wheel_ydelta = (int)wheel_ydelta; pos->wheel_xdelta = (int)wheel_xdelta; TRACE(("xdelta: %d, ydelta: %d, buttons %x, clicks: %ld, timestamp %Ld\n", - xDelta, yDelta, buttons, sClickCount, currentTime)); + xDelta, yDelta, buttons, cookie->click_count, currentTime)); } } @@ -176,18 +181,18 @@ ps2_packet_to_movement(uint8 packet[], mouse_movement *pos) */ static status_t -mouse_read_event(mouse_movement *userMovement) +mouse_read_event(mouse_cookie *cookie, mouse_movement *userMovement) { uint8 packet[PS2_MAX_PACKET_SIZE]; mouse_movement movement; status_t status; TRACE(("mouse_read_event()\n")); - status = acquire_sem_etc(sMouseSem, 1, B_CAN_INTERRUPT, 0); + status = acquire_sem_etc(cookie->mouse_sem, 1, B_CAN_INTERRUPT, 0); if (status < B_OK) return status; - if (packet_buffer_read(sMouseBuffer, packet, sPacketSize) != sPacketSize) { + if (packet_buffer_read(cookie->mouse_buffer, packet, cookie->packet_size) != cookie->packet_size) { TRACE(("error copying buffer\n")); return B_ERROR; } @@ -195,7 +200,7 @@ mouse_read_event(mouse_movement *userMovement) if (!(packet[0] & 8)) panic("ps2_hid: got broken data from packet_buffer_read\n"); - ps2_packet_to_movement(packet, &movement); + ps2_packet_to_movement(cookie, packet, &movement); return user_memcpy(userMovement, &movement, sizeof(mouse_movement)); } @@ -205,12 +210,12 @@ mouse_read_event(mouse_movement *userMovement) */ static status_t -set_mouse_enabled(bool enable) +set_mouse_enabled(mouse_cookie *cookie, bool enable) { int32 tries = 5; while (true) { - if (ps2_mouse_command(enable ? PS2_CMD_ENABLE_MOUSE : PS2_CMD_DISABLE_MOUSE, NULL, 0, NULL, 0) == B_OK) + if (ps2_dev_command(cookie->dev, enable ? PS2_CMD_ENABLE_MOUSE : PS2_CMD_DISABLE_MOUSE, NULL, 0, NULL, 0) == B_OK) return B_OK; if (--tries <= 0) @@ -228,33 +233,32 @@ set_mouse_enabled(bool enable) * calls to the handler, each holds a different byte on the data port. */ -int32 mouse_handle_int(uint8 data) +int32 mouse_handle_int(ps2_dev *dev, uint8 data) { - if (atomic_and(&sOpenMask, 1) == 0) - return B_HANDLED_INTERRUPT; - - if (sPacketIndex == 0 && !(data & 8)) { + mouse_cookie *cookie = dev->cookie; + + if (cookie->packet_index == 0 && !(data & 8)) { TRACE(("bad mouse data, trying resync\n")); return B_HANDLED_INTERRUPT; } - sPacketBuffer[sPacketIndex++] = data; + cookie->packet_buffer[cookie->packet_index++] = data; - if (sPacketIndex != sPacketSize) { + if (cookie->packet_index != cookie->packet_size) { // packet not yet complete return B_HANDLED_INTERRUPT; } // complete packet is assembled - sPacketIndex = 0; + cookie->packet_index = 0; - if (packet_buffer_write(sMouseBuffer, sPacketBuffer, sPacketSize) != sPacketSize) { + if (packet_buffer_write(cookie->mouse_buffer, cookie->packet_buffer, cookie->packet_size) != cookie->packet_size) { // buffer is full, drop new data return B_HANDLED_INTERRUPT; } - release_sem_etc(sMouseSem, 1, B_DO_NOT_RESCHEDULE); + release_sem_etc(cookie->mouse_sem, 1, B_DO_NOT_RESCHEDULE); return B_INVOKE_SCHEDULER; } @@ -263,12 +267,12 @@ int32 mouse_handle_int(uint8 data) status_t -probe_mouse(size_t *probed_packet_size) +probe_mouse(mouse_cookie *cookie, size_t *probed_packet_size) { uint8 deviceId = 0; // get device id - ps2_mouse_command(PS2_CMD_GET_DEVICE_ID, NULL, 0, &deviceId, 1); + ps2_dev_command(cookie->dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, &deviceId, 1); TRACE(("probe_mouse(): device id: %2x\n", deviceId)); @@ -277,11 +281,11 @@ probe_mouse(size_t *probed_packet_size) while (--tries > 0) { // try to switch to intellimouse mode - if (ps2_set_sample_rate(200) == B_OK - && ps2_set_sample_rate(100) == B_OK - && ps2_set_sample_rate(80) == B_OK) { + if (ps2_set_sample_rate(cookie, 200) == B_OK + && ps2_set_sample_rate(cookie, 100) == B_OK + && ps2_set_sample_rate(cookie, 80) == B_OK) { // get device id, again - ps2_mouse_command(PS2_CMD_GET_DEVICE_ID, NULL, 0, &deviceId, 1); + ps2_dev_command(cookie->dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, &deviceId, 1); TRACE(("probe_mouse(): device id: %2x\n", deviceId)); break; } @@ -312,83 +316,105 @@ probe_mouse(size_t *probed_packet_size) status_t mouse_open(const char *name, uint32 flags, void **_cookie) { - status_t status; - int8 commandByte; + mouse_cookie *cookie; + ps2_dev *dev; + status_t status; + int i; + + TRACE(("mouse_open() %s\n", name)); - TRACE(("mouse_open()\n")); - - if (atomic_or(&sOpenMask, 1) != 0) + for (dev = NULL, i = 0; i < 5; i++) { + if (0 == strcmp(ps2_device[i].name, name)) { + dev = &ps2_device[i]; + break; + } + } + + if (dev == NULL) { + TRACE(("dev = NULL\n")); + return B_ERROR; + } + + if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) return B_BUSY; - - acquire_sem(gDeviceOpenSemaphore); - - status = probe_mouse(&sPacketSize); - if (status != B_OK) + + cookie = malloc(sizeof(mouse_cookie)); + if (cookie == NULL) goto err1; - sPacketIndex = 0; + *_cookie = cookie; + memset(cookie, 0, sizeof(*cookie)); - sMouseBuffer = create_packet_buffer(MOUSE_HISTORY_SIZE * sPacketSize); - if (sMouseBuffer == NULL) { + cookie->dev = dev; + dev->cookie = cookie; + + status = probe_mouse(cookie, &cookie->packet_size); + if (status != B_OK) { + TRACE(("can't probe mouse\n")); + goto err1; + } + + cookie->mouse_buffer = create_packet_buffer(MOUSE_HISTORY_SIZE * cookie->packet_size); + if (cookie->mouse_buffer == NULL) { TRACE(("can't allocate mouse actions buffer\n")); - status = B_NO_MEMORY; goto err2; } // 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) { + cookie->mouse_sem = create_sem(0, "ps2_mouse_sem"); + if (cookie->mouse_sem < 0) { TRACE(("failed creating PS/2 mouse semaphore!\n")); - status = sMouseSem; goto err3; } - *_cookie = NULL; - - status = set_mouse_enabled(true); + status = set_mouse_enabled(cookie, true); if (status < B_OK) { TRACE(("mouse_open(): cannot enable PS/2 mouse\n")); goto err4; } - release_sem(gDeviceOpenSemaphore); + atomic_or(&dev->flags, PS2_FLAG_ENABLED); TRACE(("mouse_open(): mouse succesfully enabled\n")); return B_OK; err4: - delete_sem(sMouseSem); + delete_sem(cookie->mouse_sem); err3: - delete_packet_buffer(sMouseBuffer); + delete_packet_buffer(cookie->mouse_buffer); err2: + free(cookie); err1: - atomic_and(&sOpenMask, 0); - release_sem(gDeviceOpenSemaphore); - - return status; + atomic_and(&dev->flags, ~PS2_FLAG_OPEN); + return B_ERROR; } status_t -mouse_close(void *cookie) +mouse_close(void *_cookie) { + mouse_cookie *cookie = _cookie; + TRACE(("mouse_close()\n")); - set_mouse_enabled(false); + set_mouse_enabled(cookie, false); - delete_packet_buffer(sMouseBuffer); - delete_sem(sMouseSem); + delete_packet_buffer(cookie->mouse_buffer); + delete_sem(cookie->mouse_sem); - atomic_and(&sOpenMask, 0); + atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); + atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); return B_OK; } status_t -mouse_freecookie(void *cookie) +mouse_freecookie(void *_cookie) { + mouse_cookie *cookie = _cookie; + free(cookie); return B_OK; } @@ -410,20 +436,22 @@ mouse_write(void *cookie, off_t pos, const void *buffer, size_t *_length) status_t -mouse_ioctl(void *cookie, uint32 op, void *buffer, size_t length) +mouse_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) { + mouse_cookie *cookie = _cookie; + switch (op) { case MS_NUM_EVENTS: { int32 count; TRACE(("MS_NUM_EVENTS\n")); - get_sem_count(sMouseSem, &count); + get_sem_count(cookie->mouse_sem, &count); return count; } case MS_READ: TRACE(("MS_READ\n")); - return mouse_read_event((mouse_movement *)buffer); + return mouse_read_event(cookie, (mouse_movement *)buffer); case MS_SET_TYPE: TRACE(("MS_SET_TYPE not implemented\n")); @@ -443,7 +471,7 @@ mouse_ioctl(void *cookie, uint32 op, void *buffer, size_t length) case MS_SET_CLICKSPEED: TRACE(("MS_SETCLICK (set click speed)\n")); - return user_memcpy(&sClickSpeed, buffer, sizeof(bigtime_t)); + return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t)); default: TRACE(("unknown opcode: %ld\n", op));