partial support for intellimouse

svn path=/trunk/; revision=6156
This commit is contained in:
Thomas Bluemel 2003-09-27 01:08:19 +00:00
parent 82a60ec8d1
commit b58279d977
2 changed files with 366 additions and 72 deletions

View file

@ -4,12 +4,19 @@
#include "mouse.h"
#include "psaux.h"
typedef BOOLEAN FASTCALL (*PS2MOUSEHANDLER)(PMOUSE_INPUT_DATA Input, PDEVICE_OBJECT DeviceObject, PDEVICE_EXTENSION DeviceExtension);
// Have we got a PS/2 mouse port?
static BOOLEAN has_mouse = FALSE;
// This points to the function of our mouse handler
static PS2MOUSEHANDLER MouseHandler = NULL;
// This buffer holds the mouse scan codes. The PS/2 protocol sends three characters for each event.
static unsigned mouse_buffer[3];
static unsigned mouse_buffer[4];
static int mouse_buffer_position = 0;
static int mouse_buffer_size = 3;
// The number of mouse replies expected
static int mouse_replies_expected = 0;
@ -17,73 +24,16 @@ static int mouse_replies_expected = 0;
// Previous button state
static ULONG PreviousButtons = 0;
// Handle a mouse event
// Standard PS/2 mouse handler
BOOLEAN STDCALL
ps2_mouse_handler(PKINTERRUPT Interrupt, PVOID ServiceContext)
BOOLEAN FASTCALL
PS2_Standard(PMOUSE_INPUT_DATA Input, PDEVICE_OBJECT DeviceObject, PDEVICE_EXTENSION DeviceExtension)
{
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PMOUSE_INPUT_DATA Input;
ULONG Queue, ButtonsDiff;
int state_dx, state_dy;
unsigned scancode;
unsigned status = controller_read_status();
scancode = controller_read_input();
/* Don't handle the mouse event if we aren't connected to the mouse class driver */
if (DeviceExtension->ClassInformation.CallBack == NULL)
{
return FALSE;
}
if ((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
{
// mouse_handle_event(scancode); proceed to handle it
}
else
{
return FALSE; // keyboard_handle_event(scancode);
}
if (mouse_replies_expected > 0)
{
if (scancode == MOUSE_ACK)
{
mouse_replies_expected--;
return;
}
mouse_replies_expected = 0;
}
/* Add this scancode to the mouse event queue. */
mouse_buffer[mouse_buffer_position] = scancode;
mouse_buffer_position++;
/* If the buffer is full, parse this event */
if (mouse_buffer_position == 3)
{
/* Set local variables for DeviceObject and DeviceExtension */
DeviceObject = (PDEVICE_OBJECT)ServiceContext;
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
Queue = DeviceExtension->ActiveQueue % 2;
/* Reset the buffer state. */
mouse_buffer_position = 0;
/* Prevent buffer overflow */
if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
{
return TRUE;
}
Input = &DeviceExtension->MouseInputData[Queue]
[DeviceExtension->InputDataCount[Queue]];
ULONG ButtonsDiff;
/* Determine the current state of the buttons */
Input->RawButtons = (mouse_buffer[0] & 1) /* * GPM_B_LEFT */ +
(mouse_buffer[0] & 2) /* * GPM_B_RIGHT */ +
Input->RawButtons = (mouse_buffer[0] & 1) /* * GPM_B_LEFT */ |
(mouse_buffer[0] & 2) /* * GPM_B_RIGHT */ |
(mouse_buffer[0] & 4) /* * GPM_B_MIDDLE */;
/* Determine ButtonFlags */
@ -148,14 +98,261 @@ ps2_mouse_handler(PKINTERRUPT Interrupt, PVOID ServiceContext)
: mouse_buffer[2]);
}
/* Send the Input data to the Mouse Class driver */
DeviceExtension->InputDataCount[Queue]++;
KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
/* Copy RawButtons to Previous Buttons for Input */
PreviousButtons = Input->RawButtons;
return TRUE;
}
BOOLEAN FASTCALL
PS2_IntelliMouse(PMOUSE_INPUT_DATA Input, PDEVICE_OBJECT DeviceObject, PDEVICE_EXTENSION DeviceExtension)
{
ULONG ButtonsDiff;
/* Determine the current state of the buttons */
Input->RawButtons = (mouse_buffer[0] & 1) /* * GPM_B_LEFT */ |
(mouse_buffer[0] & 2) /* * GPM_B_RIGHT */ |
(mouse_buffer[0] & 4) /* * GPM_B_MIDDLE */;
/* Determine ButtonFlags */
Input->ButtonFlags = 0;
ButtonsDiff = PreviousButtons ^ Input->RawButtons;
if (ButtonsDiff & GPM_B_LEFT)
{
if (Input->RawButtons & GPM_B_LEFT)
{
Input->ButtonFlags |= MOUSE_BUTTON_1_DOWN;
} else {
Input->ButtonFlags |= MOUSE_BUTTON_1_UP;
}
}
if (ButtonsDiff & GPM_B_RIGHT)
{
if (Input->RawButtons & GPM_B_RIGHT)
{
Input->ButtonFlags |= MOUSE_BUTTON_2_DOWN;
} else {
Input->ButtonFlags |= MOUSE_BUTTON_2_UP;
}
}
if (ButtonsDiff & GPM_B_MIDDLE)
{
if (Input->RawButtons & GPM_B_MIDDLE)
{
Input->ButtonFlags |= MOUSE_BUTTON_3_DOWN;
} else {
Input->ButtonFlags |= MOUSE_BUTTON_3_UP;
}
}
/* Some PS/2 mice send reports with negative bit set in data[0] and zero for
* movement. I think this is a bug in the mouse, but working around it only
* causes artifacts when the actual report is -256; they'll be treated as zero.
* This should be rare if the mouse sampling rate is set to a reasonable value;
* the default of 100 Hz is plenty. (Stephen Tell) */
/* Determine LastX */
if (mouse_buffer[1] == 0)
{
Input->LastX = 0;
}
else
{
Input->LastX = (mouse_buffer[0] & 0x10) ? mouse_buffer[1] - 256
: mouse_buffer[1];
}
/* Determine LastY */
if (mouse_buffer[2] == 0)
{
Input->LastY = 0;
}
else
{
Input->LastY = -((mouse_buffer[0] & 0x20) ? mouse_buffer[2] - 256
: mouse_buffer[2]);
}
/* wheel data */
if (mouse_buffer[3])
{
/* FIXME - store it here? */
Input->ExtraInformation = (UINT)mouse_buffer[3];
}
/* Copy RawButtons to Previous Buttons for Input */
PreviousButtons = Input->RawButtons;
return TRUE;
return TRUE;
}
BOOLEAN FASTCALL
PS2_IntelliMouse5Buttons(PMOUSE_INPUT_DATA Input, PDEVICE_OBJECT DeviceObject, PDEVICE_EXTENSION DeviceExtension)
{
ULONG ButtonsDiff;
/* Determine the current state of the buttons */
Input->RawButtons = (mouse_buffer[0] & 1) /* * GPM_B_LEFT */ |
(mouse_buffer[0] & 2) /* * GPM_B_RIGHT */ |
(mouse_buffer[0] & 4) /* * GPM_B_MIDDLE */;
/* Determine ButtonFlags */
Input->ButtonFlags = 0;
ButtonsDiff = PreviousButtons ^ Input->RawButtons;
if (ButtonsDiff & GPM_B_LEFT)
{
if (Input->RawButtons & GPM_B_LEFT)
{
Input->ButtonFlags |= MOUSE_BUTTON_1_DOWN;
} else {
Input->ButtonFlags |= MOUSE_BUTTON_1_UP;
}
}
if (ButtonsDiff & GPM_B_RIGHT)
{
if (Input->RawButtons & GPM_B_RIGHT)
{
Input->ButtonFlags |= MOUSE_BUTTON_2_DOWN;
} else {
Input->ButtonFlags |= MOUSE_BUTTON_2_UP;
}
}
if (ButtonsDiff & GPM_B_MIDDLE)
{
if (Input->RawButtons & GPM_B_MIDDLE)
{
Input->ButtonFlags |= MOUSE_BUTTON_3_DOWN;
} else {
Input->ButtonFlags |= MOUSE_BUTTON_3_UP;
}
}
/* FIXME - get status of XBUTTON1 and XBUTTON2 */
/* Some PS/2 mice send reports with negative bit set in data[0] and zero for
* movement. I think this is a bug in the mouse, but working around it only
* causes artifacts when the actual report is -256; they'll be treated as zero.
* This should be rare if the mouse sampling rate is set to a reasonable value;
* the default of 100 Hz is plenty. (Stephen Tell) */
/* Determine LastX */
if (mouse_buffer[1] == 0)
{
Input->LastX = 0;
}
else
{
Input->LastX = (mouse_buffer[0] & 0x10) ? mouse_buffer[1] - 256
: mouse_buffer[1];
}
/* Determine LastY */
if (mouse_buffer[2] == 0)
{
Input->LastY = 0;
}
else
{
Input->LastY = -((mouse_buffer[0] & 0x20) ? mouse_buffer[2] - 256
: mouse_buffer[2]);
}
/* wheel data */
if (mouse_buffer[3])
{
/* FIXME - store it here? */
Input->ExtraInformation = (UINT)mouse_buffer[3];
}
/* Copy RawButtons to Previous Buttons for Input */
PreviousButtons = Input->RawButtons;
return TRUE;
}
// Handle a mouse event
BOOLEAN STDCALL
ps2_mouse_handler(PKINTERRUPT Interrupt, PVOID ServiceContext)
{
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PMOUSE_INPUT_DATA Input;
ULONG Queue;
BOOLEAN ret;
int state_dx, state_dy;
unsigned scancode;
unsigned status = controller_read_status();
scancode = controller_read_input();
/* Don't handle the mouse event if we aren't connected to the mouse class driver */
if (DeviceExtension->ClassInformation.CallBack == NULL)
{
return FALSE;
}
if ((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
{
// mouse_handle_event(scancode); proceed to handle it
}
else
{
return FALSE; // keyboard_handle_event(scancode);
}
if (mouse_replies_expected > 0)
{
if (scancode == MOUSE_ACK)
{
mouse_replies_expected--;
return;
}
mouse_replies_expected = 0;
}
/* Add this scancode to the mouse event queue. */
mouse_buffer[mouse_buffer_position] = scancode;
mouse_buffer_position++;
/* If the buffer is full, parse this event */
if (mouse_buffer_position == mouse_buffer_size)
{
/* Set local variables for DeviceObject and DeviceExtension */
DeviceObject = (PDEVICE_OBJECT)ServiceContext;
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
Queue = DeviceExtension->ActiveQueue % 2;
/* Reset the buffer state. */
mouse_buffer_position = 0;
/* Prevent buffer overflow */
if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
{
return TRUE;
}
Input = &DeviceExtension->MouseInputData[Queue]
[DeviceExtension->InputDataCount[Queue]];
if(MouseHandler)
ret = MouseHandler(Input, DeviceObject, DeviceExtension);
else
ret = FALSE;
/* Send the Input data to the Mouse Class driver */
DeviceExtension->InputDataCount[Queue]++;
KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
return ret;
}
}
@ -189,6 +386,7 @@ static void mouse_write_ack (int value)
BOOLEAN detect_ps2_port(void)
{
int loops;
unsigned scancode;
BOOLEAN return_value = FALSE;
LARGE_INTEGER Millisecond_Timeout;
@ -214,7 +412,7 @@ BOOLEAN detect_ps2_port(void)
if((status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
{
controller_read_input();
scancode = controller_read_input();
if ((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
{
return_value = TRUE;
@ -236,10 +434,17 @@ BOOLEAN mouse_init (PDEVICE_OBJECT DeviceObject)
ULONG MappedIrq;
KIRQL Dirql;
KAFFINITY Affinity;
BOOL ScanIntelli = TRUE, ScanIntelli5Btns = TRUE;
unsigned scancode;
unsigned char status;
LARGE_INTEGER Millisecond_Timeout;
if (!detect_ps2_port ()) return FALSE;
Millisecond_Timeout.QuadPart = 1;
has_mouse = TRUE;
MouseHandler = PS2_Standard;
DeviceExtension->InputDataCount[0] = 0;
DeviceExtension->InputDataCount[1] = 0;
@ -248,10 +453,94 @@ BOOLEAN mouse_init (PDEVICE_OBJECT DeviceObject)
// Enable the PS/2 mouse port
controller_write_command_word (CONTROLLER_COMMAND_MOUSE_ENABLE);
// Attempt to enter ms scrolling mouse mode
init:
// 200 samples/sec
mouse_write_ack (MOUSE_SET_SAMPLE_RATE);
mouse_write_ack (200);
if(ScanIntelli)
{
// 100 samples/sec
mouse_write_ack (MOUSE_SET_SAMPLE_RATE);
mouse_write_ack (100);
// 80 samples/sec
mouse_write_ack (MOUSE_SET_SAMPLE_RATE);
mouse_write_ack (80);
// let's test if it's a ms scrolling mouse
mouse_write_ack (MOUSE_READ_DEVICETYPE);
/* check if it is a ms intellimouse */
scancode = controller_read_input();
switch(scancode)
{
case MOUSE_ISINTELLIMOUSE:
/* detected a ms intellimouse with a mouse wheel */
mouse_buffer_size = 4;
MouseHandler = PS2_IntelliMouse;
if(!ScanIntelli5Btns)
break;
/* FIXME - do we ever get here? see
http://perso.wanadoo.es/juanramon.villodas/PS-2%20Mouse%20Interfacing.htm
*/
/* let's check if the mouse has 5 buttons */
// 200 samples/sec
mouse_write_ack (MOUSE_SET_SAMPLE_RATE);
mouse_write_ack (200);
// 100 samples/sec
mouse_write_ack (MOUSE_SET_SAMPLE_RATE);
mouse_write_ack (200);
// 80 samples/sec
mouse_write_ack (MOUSE_SET_SAMPLE_RATE);
mouse_write_ack (80);
// let's test if it's a ms scrolling mouse with 5 buttons
mouse_write_ack (MOUSE_READ_DEVICETYPE);
scancode = controller_read_input();
if(scancode == MOUSE_ISINTELLIMOUSE5BUTTONS)
{
/* detected a ms intellimouse with 5 mouse buttons */
mouse_buffer_size = 4;
MouseHandler = PS2_IntelliMouse5Buttons;
}
else
{
/* the mouse doesn't have 5 buttons, reset and init the standard intellimouse */
mouse_write_ack (MOUSE_RESET);
ScanIntelli5Btns = FALSE;
goto init;
}
break;
/* FIXME - does this ever happen or did i just misunderstood something? */
case MOUSE_ISINTELLIMOUSE5BUTTONS:
/* detected a ms intellimouse with a mouse wheel */
mouse_buffer_size = 4;
MouseHandler = PS2_IntelliMouse5Buttons;
break;
default:
/* this is a standard ps/2 mouse only, reset and init it again */
mouse_write_ack (MOUSE_RESET);
ScanIntelli = FALSE;
goto init;
break;
}
}
// 8 counts per mm
mouse_write_ack (MOUSE_SET_RESOLUTION);
mouse_write_ack (3);

View file

@ -7,6 +7,7 @@
#define MOUSE_SET_SCALE21 0xE7 // Set 2:1 scaling
#define MOUSE_GET_SCALE 0xE9 // Get scaling factor
#define MOUSE_SET_STREAM 0xEA // Set stream mode
#define MOUSE_READ_DEVICETYPE 0xF2 // Read Device Type
#define MOUSE_SET_SAMPLE_RATE 0xF3 /* Set sample rate (number of times
* the controller will poll the port
* per second */
@ -29,6 +30,8 @@
#define GPM_B_LEFT 1
#define GPM_B_RIGHT 2
#define GPM_B_MIDDLE 4
#define GPM_B_FOURTH 0x10
#define GPM_B_FIFTH 0x20
// Some aux operations take long time
#define MAX_RETRIES 60
@ -37,6 +40,9 @@
#define MOUSE_IRQ 12
#define MOUSE_WRAP_MASK 0x1F
#define MOUSE_ISINTELLIMOUSE 0x03
#define MOUSE_ISINTELLIMOUSE5BUTTONS 0x04
static PIRP CurrentIrp;
static ULONG MouseDataRead;
static ULONG MouseDataRequired;
@ -47,4 +53,3 @@ static VOID MouseDpcRoutine(PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2);