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
This commit is contained in:
Marcus Overhagen 2006-01-21 15:45:22 +00:00
parent 098b042978
commit dfd5628d64
6 changed files with 173 additions and 117 deletions

View File

@ -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

View File

@ -19,6 +19,7 @@
#include <OS.h>
#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);

View File

@ -89,11 +89,14 @@ 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);
}
uint32 flags;
if (dev->result_buf_cnt) {
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--;
@ -101,18 +104,28 @@ ps2_dev_handle_int(ps2_dev *dev, uint8 data)
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;
@ -148,6 +163,16 @@ ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8
}
}
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;
}

View File

@ -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);

View File

@ -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);

View File

@ -60,39 +60,44 @@
#include <Drivers.h>
#include <string.h>
#include <malloc.h>
#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;
typedef struct
{
ps2_dev * dev;
static bigtime_t sLastClickTime;
static bigtime_t sClickSpeed;
static int32 sClickCount;
static int sButtonsState;
sem_id mouse_sem;
packet_buffer * mouse_buffer;
bigtime_t click_last_time;
bigtime_t click_speed;
int click_count;
int buttons_state;
static size_t sPacketSize;
static size_t sPacketIndex;
static uint8 sPacketBuffer[PS2_MAX_PACKET_SIZE];
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;
mouse_cookie *cookie = dev->cookie;
if (sPacketIndex == 0 && !(data & 8)) {
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)
{
mouse_cookie *cookie;
ps2_dev *dev;
status_t status;
int8 commandByte;
int i;
TRACE(("mouse_open()\n"));
TRACE(("mouse_open() %s\n", name));
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));