mirror of
https://github.com/reactos/reactos.git
synced 2025-04-22 13:10:39 +00:00
partial support for intellimouse
svn path=/trunk/; revision=6156
This commit is contained in:
parent
82a60ec8d1
commit
b58279d977
2 changed files with 366 additions and 72 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue