From b58279d977276fa31137a12f8fc22beecd23774d Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Sat, 27 Sep 2003 01:08:19 +0000 Subject: [PATCH] partial support for intellimouse svn path=/trunk/; revision=6156 --- reactos/drivers/input/psaux/mouse.c | 431 +++++++++++++++++++++++----- reactos/drivers/input/psaux/mouse.h | 7 +- 2 files changed, 366 insertions(+), 72 deletions(-) diff --git a/reactos/drivers/input/psaux/mouse.c b/reactos/drivers/input/psaux/mouse.c index 72daea3ffbf..2e90db0d861 100644 --- a/reactos/drivers/input/psaux/mouse.c +++ b/reactos/drivers/input/psaux/mouse.c @@ -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; @@ -247,10 +452,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); @@ -258,7 +547,7 @@ BOOLEAN mouse_init (PDEVICE_OBJECT DeviceObject) // 2:1 scaling mouse_write_ack (MOUSE_SET_SCALE21); - + // Enable the PS/2 device mouse_write_ack (MOUSE_ENABLE_DEVICE); diff --git a/reactos/drivers/input/psaux/mouse.h b/reactos/drivers/input/psaux/mouse.h index ed568d789c1..39f3735e07f 100644 --- a/reactos/drivers/input/psaux/mouse.h +++ b/reactos/drivers/input/psaux/mouse.h @@ -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); -