From 9a74edf2a106ffe4502c5d5a8917c41a491cf9f0 Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Sun, 28 Sep 2003 00:30:34 +0000 Subject: [PATCH] advanced ps/2 mouse driver that supports intellimouse and mice with mouse wheel and 4th and 5th buttons svn path=/trunk/; revision=6173 --- reactos/drivers/input/psaux/logips2pp.c | 239 ++++++ reactos/drivers/input/psaux/logips2pp.h | 19 + reactos/drivers/input/psaux/makefile | 4 +- reactos/drivers/input/psaux/mouse.c | 929 +++++++++++++----------- reactos/drivers/input/psaux/mouse.h | 29 + reactos/drivers/input/psaux/psaux.h | 23 +- reactos/drivers/input/psaux/synaptics.c | 410 +++++++++++ reactos/drivers/input/psaux/synaptics.h | 100 +++ 8 files changed, 1313 insertions(+), 440 deletions(-) create mode 100644 reactos/drivers/input/psaux/logips2pp.c create mode 100644 reactos/drivers/input/psaux/logips2pp.h create mode 100644 reactos/drivers/input/psaux/synaptics.c create mode 100644 reactos/drivers/input/psaux/synaptics.h diff --git a/reactos/drivers/input/psaux/logips2pp.c b/reactos/drivers/input/psaux/logips2pp.c new file mode 100644 index 00000000000..9c24ae99899 --- /dev/null +++ b/reactos/drivers/input/psaux/logips2pp.c @@ -0,0 +1,239 @@ +/* + * Logitech PS/2++ mouse driver + * + * Copyright (c) 1999-2003 Vojtech Pavlik + * Copyright (c) 2003 Eric Wong + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include "mouse.h" +#include "logips2pp.h" + +/* + * Process a PS2++ or PS2T++ packet. + */ + +void ps2pp_process_packet(PDEVICE_EXTENSION DeviceExtension, PMOUSE_INPUT_DATA Input) +{ + unsigned char *packet = DeviceExtension->MouseBuffer; + + if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) { + + switch ((packet[1] >> 4) | (packet[0] & 0x30)) { + + case 0x0d: /* Mouse extra info */ + + /* FIXME - mouse seems to have 2 wheels + input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, + (int) (packet[2] & 8) - (int) (packet[2] & 7)); */ + + Input->ButtonData = (UINT)((WHEEL_DELTA) * ((int)(packet[2] & 8) - (int)(packet[2] & 7))); + Input->RawButtons |= ((packet[2] >> 4) & 1) ? GPM_B_FOURTH : 0; + Input->RawButtons |= ((packet[2] >> 5) & 1) ? GPM_B_FIFTH : 0; + + break; + + case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ + + Input->RawButtons |= (packet[2] & 1) ? GPM_B_FOURTH : 0; + Input->RawButtons |= ((packet[2] >> 1) & 1) ? GPM_B_FIFTH : 0; + + /* FIXME - support those buttons??? + input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); + input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); + */ + + break; + + case 0x0f: /* TouchPad extra info */ + + /* FIXME - mouse seems to have 2 wheels + input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, + (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); */ + + Input->ButtonData = (UINT)((WHEEL_DELTA) *((int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7))); + + packet[0] = packet[2] | 0x08; + break; + + default: + DbgPrint("logips2pp.c: Received PS2++ packet 0x%x, but don't know how to handle.\n", + (packet[1] >> 4) | (packet[0] & 0x30)); + } + + packet[0] &= 0x0f; + packet[1] = 0; + packet[2] = 0; + + } +} + +/* + * ps2pp_cmd() sends a PS2++ command, sliced into two bit + * pieces through the SETRES command. This is needed to send extended + * commands to mice on notebooks that try to understand the PS/2 protocol + * Ugly. + */ + +static int ps2pp_cmd(PDEVICE_EXTENSION DeviceExtension, unsigned char *param, unsigned char command) +{ + unsigned char d; + int i; + + if (psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + d = (command >> i) & 3; + if(psmouse_command(DeviceExtension, &d, PSMOUSE_CMD_SETRES)) + return -1; + } + + if (psmouse_command(DeviceExtension, param, PSMOUSE_CMD_POLL)) + return -1; + + return 0; +} + +/* + * SmartScroll / CruiseControl for some newer Logitech mice Defaults to + * enabled if we do nothing to it. Of course I put this in because I want it + * disabled :P + * 1 - enabled (if previously disabled, also default) + * 0/2 - disabled + */ + +static void ps2pp_set_smartscroll(PDEVICE_EXTENSION DeviceExtension) +{ + unsigned char param[4]; + + ps2pp_cmd(DeviceExtension, param, 0x32); + + param[0] = 0; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + + if (DeviceExtension->psmouse_smartscroll == 1) + param[0] = 1; + else + if (DeviceExtension->psmouse_smartscroll > 2) + return; + + /* else leave param[0] == 0 to disable */ + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); +} + +/* + * Support 800 dpi resolution _only_ if the user wants it (there are good + * reasons to not use it even if the mouse supports it, and of course there are + * also good reasons to use it, let the user decide). + */ + +void ps2pp_set_800dpi(PDEVICE_EXTENSION DeviceExtension) +{ + unsigned char param = 3; + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(DeviceExtension, ¶m, PSMOUSE_CMD_SETRES); +} + +/* + * Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or + * touchpad. + */ + +int ps2pp_detect_model(PDEVICE_EXTENSION DeviceExtension, unsigned char *param) +{ + int i; + //char *vendor, *name; + static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 }; + static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, 112, -1 }; + static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75, + 76, 80, 81, 83, 88, 96, 97, 112, -1 }; + static int logitech_mx[] = { 112, -1 }; + + //vendor = "Logitech"; + //DbgPrint("Vendor: %s, name: %s\n", vendor, name); + DeviceExtension->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); + + /*if (param[1] < 3) + clear_bit(BTN_MIDDLE, DeviceExtension->dev.keybit); + if (param[1] < 2) + clear_bit(BTN_RIGHT, DeviceExtension->dev.keybit);*/ + + DeviceExtension->MouseType = PSMOUSE_PS2; + + for (i = 0; logitech_ps2pp[i] != -1; i++) + if (logitech_ps2pp[i] == DeviceExtension->model) + DeviceExtension->MouseType = PSMOUSE_PS2PP; + + if (DeviceExtension->MouseType == PSMOUSE_PS2PP) { + + /* for (i = 0; logitech_4btn[i] != -1; i++) + if (logitech_4btn[i] == psmouse->model) + set_bit(BTN_SIDE, psmouse->dev.keybit); +*/ + for (i = 0; logitech_wheel[i] != -1; i++) + if (logitech_wheel[i] == DeviceExtension->model) { +// set_bit(REL_WHEEL, psmouse->dev.relbit); + //name = "Wheel Mouse";DbgPrint("Vendor: %s, name: %s\n", vendor, name); + } + + for (i = 0; logitech_mx[i] != -1; i++) + if (logitech_mx[i] == DeviceExtension->model) { + /* set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_BACK, psmouse->dev.keybit); + set_bit(BTN_FORWARD, psmouse->dev.keybit); + set_bit(BTN_TASK, psmouse->dev.keybit); + */ //name = "MX Mouse";DbgPrint("Vendor: %s, name: %s\n", vendor, name); + } + +/* + * Do Logitech PS2++ / PS2T++ magic init. + */ + + if (DeviceExtension->model == 97) { /* TouchPad 3 */ + +// set_bit(REL_WHEEL, psmouse->dev.relbit); +// set_bit(REL_HWHEEL, psmouse->dev.relbit); + + param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ + psmouse_command(DeviceExtension, param, 0x30d1); + param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ + psmouse_command(DeviceExtension, param, 0x30d1); + param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ + psmouse_command(DeviceExtension, param, 0x30d1); + + param[0] = 0; + if (!psmouse_command(DeviceExtension, param, 0x13d1) && + param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { + //name = "TouchPad 3";DbgPrint("Vendor: %s, name: %s\n", vendor, name); + return PSMOUSE_PS2TPP; + } + + } else { + + param[0] = param[1] = param[2] = 0; + ps2pp_cmd(DeviceExtension, param, 0x39); /* Magic knock */ + ps2pp_cmd(DeviceExtension, param, 0xDB); + + if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && + (param[2] & 3) == ((param[1] >> 2) & 3)) { + ps2pp_set_smartscroll(DeviceExtension); + return PSMOUSE_PS2PP; + } + } + } + + return 0; +} + diff --git a/reactos/drivers/input/psaux/logips2pp.h b/reactos/drivers/input/psaux/logips2pp.h new file mode 100644 index 00000000000..06c361af2dd --- /dev/null +++ b/reactos/drivers/input/psaux/logips2pp.h @@ -0,0 +1,19 @@ +/* + * Logitech PS/2++ mouse driver header + * + * Copyright (c) 2003 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include +#include +#include "psaux.h" + +#ifndef _LOGIPS2PP_H +#define _LOGIPS2PP_H +void ps2pp_process_packet(PDEVICE_EXTENSION DeviceExtension, PMOUSE_INPUT_DATA Input); +void ps2pp_set_800dpi(PDEVICE_EXTENSION DeviceExtension); +int ps2pp_detect_model(PDEVICE_EXTENSION DeviceExtension, unsigned char *param); +#endif diff --git a/reactos/drivers/input/psaux/makefile b/reactos/drivers/input/psaux/makefile index 431b0985254..ce6a103f827 100644 --- a/reactos/drivers/input/psaux/makefile +++ b/reactos/drivers/input/psaux/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.7 2001/08/21 20:13:14 chorns Exp $ +# $Id: makefile,v 1.8 2003/09/28 00:30:34 weiden Exp $ PATH_TO_TOP = ../../.. @@ -6,7 +6,7 @@ TARGET_TYPE = driver TARGET_NAME = psaux -TARGET_OBJECTS = $(TARGET_NAME).o controller.o mouse.o +TARGET_OBJECTS = $(TARGET_NAME).o controller.o mouse.o logips2pp.o synaptics.o include $(PATH_TO_TOP)/rules.mak diff --git a/reactos/drivers/input/psaux/mouse.c b/reactos/drivers/input/psaux/mouse.c index 2e90db0d861..051e38662f4 100644 --- a/reactos/drivers/input/psaux/mouse.c +++ b/reactos/drivers/input/psaux/mouse.c @@ -4,277 +4,103 @@ #include "mouse.h" #include "psaux.h" -typedef BOOLEAN FASTCALL (*PS2MOUSEHANDLER)(PMOUSE_INPUT_DATA Input, PDEVICE_OBJECT DeviceObject, PDEVICE_EXTENSION DeviceExtension); +#define PSMOUSE_LOGITECH_SMARTSCROLL 1 -// Have we got a PS/2 mouse port? -static BOOLEAN has_mouse = FALSE; +/* + * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and + * reports relevant events to the input module. + */ -// 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[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; - -// Previous button state -static ULONG PreviousButtons = 0; - -// Standard PS/2 mouse handler - -BOOLEAN FASTCALL -PS2_Standard(PMOUSE_INPUT_DATA Input, PDEVICE_OBJECT DeviceObject, PDEVICE_EXTENSION DeviceExtension) +static void psmouse_process_packet(PDEVICE_EXTENSION DeviceExtension, PMOUSE_INPUT_DATA Input) { - ULONG ButtonsDiff; + ULONG ButtonsDiff; + unsigned char *packet = DeviceExtension->MouseBuffer; + + /* Determine the current state of the buttons */ + Input->RawButtons = (packet[0] & 1) ? GPM_B_LEFT : 0; + Input->RawButtons |= ((packet[0] >> 1) & 1) ? GPM_B_RIGHT : 0; + Input->RawButtons |= ((packet[0] >> 2) & 1) ? GPM_B_MIDDLE : 0; + +/* + * The PS2++ protocol is a little bit complex + */ + + if (DeviceExtension->MouseType == PSMOUSE_PS2PP || DeviceExtension->MouseType == PSMOUSE_PS2TPP) + ps2pp_process_packet(DeviceExtension, Input); + +/* + * Scroll wheel on IntelliMice, scroll buttons on NetMice + */ + + if (DeviceExtension->MouseType == PSMOUSE_IMPS || DeviceExtension->MouseType == PSMOUSE_GENPS) + { + Input->ButtonData = (UINT)((int)((-(signed char) packet[3]) * WHEEL_DELTA)); + } + +/* + * Scroll wheel and buttons on IntelliMouse Explorer + */ + + if (DeviceExtension->MouseType == PSMOUSE_IMEX) + { + Input->ButtonData = (UINT)((WHEEL_DELTA) * ((int)(packet[3] & 8) - (int)(packet[3] & 7))); + Input->RawButtons |= ((packet[3] >> 4) & 1) ? GPM_B_FOURTH : 0; + Input->RawButtons |= ((packet[3] >> 5) & 1) ? GPM_B_FIFTH : 0; + } + +/* + * Extra buttons on Genius NewNet 3D + */ + + if (DeviceExtension->MouseType == PSMOUSE_GENPS) + { + Input->RawButtons |= ((packet[0] >> 6) & 1) ? GPM_B_FOURTH : 0; + Input->RawButtons |= ((packet[0] >> 7) & 1) ? GPM_B_FIFTH : 0; + } + +/* + * Determine ButtonFlags + */ + + Input->ButtonFlags = 0; + ButtonsDiff = DeviceExtension->PreviousButtons ^ Input->RawButtons; + +/* + * Generic PS/2 Mouse + */ - /* 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]); - } - - /* 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; + if(ButtonsDiff & GPM_B_LEFT) + Input->ButtonFlags |= (Input->RawButtons & GPM_B_LEFT) ? MOUSE_BUTTON_1_DOWN : MOUSE_BUTTON_1_UP; - /* 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; -} - - -BOOLEAN FASTCALL -PS2_IntelliMouse5Buttons(PMOUSE_INPUT_DATA Input, PDEVICE_OBJECT DeviceObject, PDEVICE_EXTENSION DeviceExtension) -{ - ULONG ButtonsDiff; + if(ButtonsDiff & GPM_B_RIGHT) + Input->ButtonFlags |= (Input->RawButtons & GPM_B_RIGHT) ? MOUSE_BUTTON_2_DOWN : MOUSE_BUTTON_2_UP; - /* 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 */; + if(ButtonsDiff & GPM_B_MIDDLE) + Input->ButtonFlags |= (Input->RawButtons & GPM_B_MIDDLE) ? MOUSE_BUTTON_3_DOWN : MOUSE_BUTTON_3_UP; + + if(ButtonsDiff & GPM_B_FOURTH) + Input->ButtonFlags |= (Input->RawButtons & GPM_B_FOURTH) ? MOUSE_BUTTON_4_DOWN : MOUSE_BUTTON_4_UP; + + if(ButtonsDiff & GPM_B_FIFTH) + Input->ButtonFlags |= (Input->RawButtons & GPM_B_FIFTH) ? MOUSE_BUTTON_5_DOWN : MOUSE_BUTTON_5_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 ButtonFlags */ - Input->ButtonFlags = 0; - ButtonsDiff = PreviousButtons ^ Input->RawButtons; + /* Determine LastX */ + Input->LastX = packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0; - 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; + /* Determine LastY */ + Input->LastY = packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0; + + /* Copy RawButtons to Previous Buttons for Input */ + DeviceExtension->PreviousButtons = Input->RawButtons; + + if(Input->ButtonData) + Input->ButtonFlags |= MOUSE_WHEEL; } @@ -287,52 +113,62 @@ ps2_mouse_handler(PKINTERRUPT Interrupt, PVOID ServiceContext) PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; PMOUSE_INPUT_DATA Input; ULONG Queue; - BOOLEAN ret; + BOOLEAN ret = FALSE; int state_dx, state_dy; unsigned scancode; unsigned status = controller_read_status(); scancode = controller_read_input(); + if ((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0) + { + return FALSE; // keyboard_handle_event(scancode); + } + + if(DeviceExtension->acking) + { + switch(scancode) + { + case PSMOUSE_RET_ACK: + DeviceExtension->ack = 1; + break; + case PSMOUSE_RET_NAK: + DeviceExtension->ack = -1; + break; + default: + DeviceExtension->ack = 1; /* Workaround for mice which don't ACK the Get ID command */ + if (DeviceExtension->cmdcnt) + DeviceExtension->cmdbuf[--DeviceExtension->cmdcnt] = scancode; + break; + } + DeviceExtension->acking = 0; + return TRUE; + } + + if (DeviceExtension->cmdcnt) + { + DeviceExtension->cmdbuf[--DeviceExtension->cmdcnt] = scancode; + return TRUE; + } + /* 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++; + DeviceExtension->MouseBuffer[DeviceExtension->MouseBufferPosition] = scancode; + DeviceExtension->MouseBufferPosition++; + + Queue = DeviceExtension->ActiveQueue % 2; - /* If the buffer is full, parse this event */ - if (mouse_buffer_position == mouse_buffer_size) + /* If the buffer is full, parse the standard ps/2 packets */ + if (DeviceExtension->MouseBufferPosition == + DeviceExtension->MouseBufferSize + (DeviceExtension->MouseType >= PSMOUSE_GENPS)) { - /* 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; + DeviceExtension->MouseBufferPosition = 0; /* Prevent buffer overflow */ if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE) @@ -341,46 +177,285 @@ ps2_mouse_handler(PKINTERRUPT Interrupt, PVOID ServiceContext) } Input = &DeviceExtension->MouseInputData[Queue] - [DeviceExtension->InputDataCount[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); + psmouse_process_packet(DeviceExtension, Input); - return ret; + goto end; } + + /* + * The synaptics driver has its own resync logic, + * so it needs to receive all bytes one at a time. + */ + if ((DeviceExtension->MouseBufferPosition == 1) && (DeviceExtension->MouseType == PSMOUSE_SYNAPTICS)) + { +// synaptics_process_byte(psmouse, regs); + /* Reset the buffer state. */ + DeviceExtension->MouseBufferPosition = 0; + + return TRUE; + } + + /* FIXME */ + if ((DeviceExtension->MouseBufferPosition == 1) && (DeviceExtension->MouseBuffer[0] == PSMOUSE_RET_BAT)) + { + /* FIXME ????????? */ + DeviceExtension->MouseBufferPosition = 0; + + return TRUE; + } + + return TRUE; + +end: + /* Send the Input data to the Mouse Class driver */ + DeviceExtension->InputDataCount[Queue]++; + KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL); + return ret; } -/* Write a PS/2 mouse command. */ - -static void mouse_write_command (int command) -{ - controller_wait(); - controller_write_command (CONTROLLER_COMMAND_WRITE_MODE); - controller_wait(); - controller_write_output (command); -} - -/* Send a byte to the PS/2 mouse & handle returned ACK. */ - -static void mouse_write_ack (int value) -{ - controller_wait(); - controller_write_command (CONTROLLER_COMMAND_WRITE_MOUSE); - controller_wait(); - controller_write_output (value); - - /* We expect an ACK in response. */ - - mouse_replies_expected++; - controller_wait (); -} +/* + * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge. + * It doesn't handle retransmission, though it could - because when there would + * be need for retransmissions, the mouse has to be replaced anyway. + */ +static int psmouse_sendbyte(PDEVICE_EXTENSION DeviceExtension, unsigned char byte) +{ + int timeout = 100; /* 100 msec */ + LARGE_INTEGER Millisecond_Timeout; + + Millisecond_Timeout.QuadPart = 1; + + DeviceExtension->ack = 0; + DeviceExtension->acking = 1; + + controller_wait(); + controller_write_command(CONTROLLER_COMMAND_WRITE_MOUSE); + controller_wait(); + controller_write_output(byte); + controller_wait(); + while ((DeviceExtension->ack == 0) && timeout--) + { + KeDelayExecutionThread (KernelMode, FALSE, &Millisecond_Timeout); + } + return -(DeviceExtension->ack <= 0); +} + +/* + * psmouse_command() sends a command and its parameters to the mouse, + * then waits for the response and puts it in the param array. + */ + +int psmouse_command(PDEVICE_EXTENSION DeviceExtension, unsigned char *param, int command) +{ + LARGE_INTEGER Millisecond_Timeout; + int timeout = 500; /* 500 msec */ + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + int i; + + Millisecond_Timeout.QuadPart = 1; + + DeviceExtension->cmdcnt = receive; + if (command == PSMOUSE_CMD_RESET_BAT) + timeout = 2000; /* 2 sec */ + + if (command & 0xff) + if (psmouse_sendbyte(DeviceExtension, command & 0xff)) + return (DeviceExtension->cmdcnt = 0) - 1; + + for (i = 0; i < send; i++) + if (psmouse_sendbyte(DeviceExtension, param[i])) + return (DeviceExtension->cmdcnt = 0) - 1; + + while (DeviceExtension->cmdcnt && timeout--) { + + if (DeviceExtension->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT) + timeout = 100; + + if (DeviceExtension->cmdcnt == 1 && command == PSMOUSE_CMD_GETID && + DeviceExtension->cmdbuf[1] != 0xab && DeviceExtension->cmdbuf[1] != 0xac) { + DeviceExtension->cmdcnt = 0; + break; + } + + KeDelayExecutionThread (KernelMode, FALSE, &Millisecond_Timeout); + } + + for (i = 0; i < receive; i++) + param[i] = DeviceExtension->cmdbuf[(receive - 1) - i]; + if (DeviceExtension->cmdcnt) + return (DeviceExtension->cmdcnt = 0) - 1; + + return 0; +} + +/* + * psmouse_extensions() probes for any extensions to the basic PS/2 protocol + * the mouse may have. + */ + +static int psmouse_extensions(PDEVICE_EXTENSION DeviceExtension) +{ + unsigned char param[4]; + + param[0] = 0; + //vendor = "Generic"; + //name = "Mouse"; + DeviceExtension->model = 0; + + if (DeviceExtension->psmouse_noext) + { + return PSMOUSE_PS2; + } + +/* + * Try Synaptics TouchPad magic ID + */ + + param[0] = 0; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_GETINFO); + + if (param[1] == 0x47) { + //vendor = "Synaptics"; + //name = "TouchPad"; + + if (!synaptics_init(DeviceExtension)) + return PSMOUSE_SYNAPTICS; + else + return PSMOUSE_PS2; + } + +/* + * Try Genius NetMouse magic init. + */ + + param[0] = 3; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_GETINFO); + + if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) { + + //set_bit(BTN_EXTRA, psmouse->dev.keybit); + //set_bit(BTN_SIDE, psmouse->dev.keybit); + //set_bit(REL_WHEEL, psmouse->dev.relbit); + + //vendor = "Genius"; + //name = "Wheel Mouse"; + return PSMOUSE_GENPS; + } + +/* + * Try Logitech magic ID. + */ + + param[0] = 0; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + param[1] = 0; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_GETINFO); + + if (param[1]) { + int type = ps2pp_detect_model(DeviceExtension, param); + if (type) + { + return type; + } + } + +/* + * Try IntelliMouse magic init. + */ + + param[0] = 200; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE); + param[0] = 100; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_GETID); + + if (param[0] == 3) { + + // set_bit(REL_WHEEL, DeviceExtension->dev.relbit); + +/* + * Try IntelliMouse/Explorer magic init. + */ + + param[0] = 200; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE); + param[0] = 200; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE); + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_GETID); + + if (param[0] == 4) { + + //set_bit(BTN_SIDE, psmouse->dev.keybit); + //set_bit(BTN_EXTRA, psmouse->dev.keybit); + + //name = "Explorer Mouse"; + return PSMOUSE_IMEX; + } + + //name = "Wheel Mouse"; + return PSMOUSE_IMPS; + } + +/* + * Okay, all failed, we have a standard mouse here. The number of the buttons + * is still a question, though. We assume 3. + */ + return PSMOUSE_PS2; +} + +/* + * psmouse_test() probes for a PS/2 mouse. + */ + +static int psmouse_test(PDEVICE_EXTENSION DeviceExtension) +{ + unsigned char param[2]; +/* + * First, we check if it's a mouse. It should send 0x00 or 0x03 + * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. + */ + + param[0] = param[1] = 0xa5; + + if (psmouse_command(DeviceExtension, param, PSMOUSE_CMD_GETID)) + return -1; + + if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04) + return -1; + +/* + * Then we reset and disable the mouse so that it doesn't generate events. + */ + + if (psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_RESET_DIS)) + return -1; + +/* + * And here we try to determine if it has any extensions over the + * basic PS/2 3-button mouse. + */ + return DeviceExtension->MouseType = psmouse_extensions(DeviceExtension); +} + /* Check if this is a dual port controller. */ BOOLEAN detect_ps2_port(void) @@ -426,139 +501,119 @@ BOOLEAN detect_ps2_port(void) return return_value; } -// Initialize the PS/2 mouse support +/* + * Here we set the mouse resolution. + */ +static void psmouse_set_resolution(PDEVICE_EXTENSION DeviceExtension) +{ + unsigned char param[1]; + + if (DeviceExtension->MouseType == PSMOUSE_PS2PP && DeviceExtension->Resolution > 400) { + ps2pp_set_800dpi(DeviceExtension); + return; + } + + if (!DeviceExtension->Resolution || DeviceExtension->Resolution >= 200) + param[0] = 3; + else if (DeviceExtension->Resolution >= 100) + param[0] = 2; + else if (DeviceExtension->Resolution >= 50) + param[0] = 1; + else if (DeviceExtension->Resolution) + param[0] = 0; + + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRES); +} + +/* + * psmouse_initialize() initializes the mouse to a sane state. + */ + +static void psmouse_initialize(PDEVICE_EXTENSION DeviceExtension) +{ + unsigned char param[2]; +/* + * We set the mouse report rate to a highest possible value. + * We try 100 first in case mouse fails to set 200. + */ + + param[0] = 100; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE); + + param[0] = 200; + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE); + +/* + * We also set the resolution and scaling. + */ + + psmouse_set_resolution(DeviceExtension); + psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11); + +/* + * We set the mouse into streaming mode. + */ + + psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETSTREAM); + +/* + * Last, we enable the mouse so that we get reports from it. + */ + + if (psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_ENABLE)) + DbgPrint("mouse.c: Failed to enable mouse\n"); +} + +/* Initialize the PS/2 mouse support */ BOOLEAN mouse_init (PDEVICE_OBJECT DeviceObject) { PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 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; + DeviceExtension->MouseBufferPosition = 0; + DeviceExtension->MouseBufferSize = 3; /* standard PS/2 packet size */ + DeviceExtension->PreviousButtons = 0; + DeviceExtension->MouseType = 0; + + DeviceExtension->psmouse_noext = 0; // Set this to 1 if you don't want to detect enhanced mice + DeviceExtension->psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL; + DeviceExtension->Resolution = 600; // Set this to the resolution of the mouse - Millisecond_Timeout.QuadPart = 1; - - has_mouse = TRUE; - MouseHandler = PS2_Standard; - DeviceExtension->InputDataCount[0] = 0; DeviceExtension->InputDataCount[1] = 0; DeviceExtension->ActiveQueue = 0; + + DeviceExtension->ack = 0; + DeviceExtension->acking = 0; + + DeviceExtension->HasMouse = detect_ps2_port(); + + if(!DeviceExtension->HasMouse) + return FALSE; // 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); - - // 2:1 scaling - mouse_write_ack (MOUSE_SET_SCALE21); - - // Enable the PS/2 device - mouse_write_ack (MOUSE_ENABLE_DEVICE); + controller_write_command_word (CONTROLLER_COMMAND_MOUSE_ENABLE); // Enable controller interrupts - mouse_write_command (MOUSE_INTERRUPTS_ON); + controller_wait(); + controller_write_command (CONTROLLER_COMMAND_WRITE_MODE); + controller_wait(); + controller_write_output (MOUSE_INTERRUPTS_ON); + controller_wait(); // Connect the interrupt for the mouse irq MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ, &Dirql, &Affinity); IoConnectInterrupt(&DeviceExtension->MouseInterrupt, ps2_mouse_handler, DeviceObject, NULL, MappedIrq, Dirql, Dirql, 0, FALSE, Affinity, FALSE); + + psmouse_test(DeviceExtension); + psmouse_initialize(DeviceExtension); return TRUE; } + diff --git a/reactos/drivers/input/psaux/mouse.h b/reactos/drivers/input/psaux/mouse.h index 39f3735e07f..68afd6c54e3 100644 --- a/reactos/drivers/input/psaux/mouse.h +++ b/reactos/drivers/input/psaux/mouse.h @@ -43,6 +43,35 @@ #define MOUSE_ISINTELLIMOUSE 0x03 #define MOUSE_ISINTELLIMOUSE5BUTTONS 0x04 +// ----------------------------------------------------------------------------- + +#define WHEEL_DELTA 120 + +#define PSMOUSE_CMD_SETSCALE11 0x00e6 +#define PSMOUSE_CMD_SETRES 0x10e8 +#define PSMOUSE_CMD_GETINFO 0x03e9 +#define PSMOUSE_CMD_SETSTREAM 0x00ea +#define PSMOUSE_CMD_POLL 0x03eb +#define PSMOUSE_CMD_GETID 0x02f2 +#define PSMOUSE_CMD_SETRATE 0x10f3 +#define PSMOUSE_CMD_ENABLE 0x00f4 +#define PSMOUSE_CMD_RESET_DIS 0x00f6 +#define PSMOUSE_CMD_RESET_BAT 0x02ff + +#define PSMOUSE_RET_BAT 0xaa +#define PSMOUSE_RET_ACK 0xfa +#define PSMOUSE_RET_NAK 0xfe + +#define PSMOUSE_PS2 1 +#define PSMOUSE_PS2PP 2 +#define PSMOUSE_PS2TPP 3 +#define PSMOUSE_GENPS 4 +#define PSMOUSE_IMPS 5 +#define PSMOUSE_IMEX 6 +#define PSMOUSE_SYNAPTICS 7 + +#define input_regs(a,b) do { (a)->regs = (b); } while (0) + static PIRP CurrentIrp; static ULONG MouseDataRead; static ULONG MouseDataRequired; diff --git a/reactos/drivers/input/psaux/psaux.h b/reactos/drivers/input/psaux/psaux.h index 590d6ba996f..fdd3143d165 100644 --- a/reactos/drivers/input/psaux/psaux.h +++ b/reactos/drivers/input/psaux/psaux.h @@ -1,3 +1,5 @@ +#include +#include typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT DeviceObject; @@ -5,10 +7,29 @@ typedef struct _DEVICE_EXTENSION { ULONG ActiveQueue; ULONG InputDataCount[2]; MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE]; + BOOL HasMouse; + + unsigned char MouseType; + unsigned char model; + + unsigned char MouseBuffer[8]; + UINT MouseBufferPosition; + UINT MouseBufferSize; + UINT Resolution; + + unsigned char cmdbuf[8]; + unsigned char cmdcnt; + unsigned char pktcnt; + char acking; + volatile char ack; + + int psmouse_noext; + int psmouse_smartscroll; + + ULONG PreviousButtons; CLASS_INFORMATION ClassInformation; PKINTERRUPT MouseInterrupt; KDPC IsrDpc; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; - diff --git a/reactos/drivers/input/psaux/synaptics.c b/reactos/drivers/input/psaux/synaptics.c new file mode 100644 index 00000000000..9d0b24c6a82 --- /dev/null +++ b/reactos/drivers/input/psaux/synaptics.c @@ -0,0 +1,410 @@ +/* + * Synaptics TouchPad PS/2 mouse driver + * + * 2003 Peter Osterlund + * Ported to 2.5 input device infrastructure. + * + * Copyright (C) 2001 Stefan Gmeiner + * start merging tpconfig and gpm code to a xfree-input module + * adding some changes and extensions (ex. 3rd and 4th button) + * + * Copyright (c) 1997 C. Scott Ananian + * Copyright (c) 1998-2000 Bruce Kalk + * code for the special synaptics commands (from the tpconfig-source) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + */ + + + + #define NO_SYNAPTICS + + + + +#include +#include +#include +#include "mouse.h" +#include "psaux.h" + +#ifndef NO_SYNAPTICS + +#include "synaptics.h" + +/***************************************************************************** + * Synaptics communications functions + ****************************************************************************/ + +/* + * Use the Synaptics extended ps/2 syntax to write a special command byte. + * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu + * is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd + * and synaptics_set_mode) + */ +static int synaptics_special_cmd(PDEVICE_EXTENSION DeviceExtension, unsigned char command) +{ + int i; + + if (psmouse_command(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + unsigned char d = (command >> i) & 3; + if (psmouse_command(DeviceExtension, &d, PSMOUSE_CMD_SETRES)) + return -1; + } + + return 0; +} + +/* + * Send a command to the synpatics touchpad by special commands + */ +static int synaptics_send_cmd(PDEVICE_EXTENSION DeviceExtension, unsigned char c, unsigned char *param) +{ + if (synaptics_special_cmd(DeviceExtension, c)) + return -1; + if (psmouse_command(DeviceExtension, param, PSMOUSE_CMD_GETINFO)) + return -1; + return 0; +} + +/* + * Set the synaptics touchpad mode byte by special commands + */ +static int synaptics_set_mode(PDEVICE_EXTENSION DeviceExtension, unsigned char mode) +{ + unsigned char param[1]; + + if (synaptics_special_cmd(DeviceExtension, mode)) + return -1; + param[0] = 0x14; + if (psmouse_command(DeviceExtension, param, PSMOUSE_CMD_SETRATE)) + return -1; + return 0; +} + +static int synaptics_reset(PDEVICE_EXTENSION DeviceExtension) +{ + unsigned char r[2]; + + if (psmouse_command(DeviceExtension, r, PSMOUSE_CMD_RESET_BAT)) + return -1; + if (r[0] == 0xAA && r[1] == 0x00) + return 0; + return -1; +} + +/* + * Read the model-id bytes from the touchpad + * see also SYN_MODEL_* macros + */ +static int synaptics_model_id(struct psmouse *psmouse, unsigned long int *model_id) +{ + unsigned char mi[3]; + + if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi)) + return -1; + *model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2]; + return 0; +} + +/* + * Read the capability-bits from the touchpad + * see also the SYN_CAP_* macros + */ +static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability) +{ + unsigned char cap[3]; + + if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) + return -1; + *capability = (cap[0]<<16) | (cap[1]<<8) | cap[2]; + if (SYN_CAP_VALID(*capability)) + return 0; + return -1; +} + +/* + * Identify Touchpad + * See also the SYN_ID_* macros + */ +static int synaptics_identify(struct psmouse *psmouse, unsigned long int *ident) +{ + unsigned char id[3]; + + if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id)) + return -1; + *ident = (id[0]<<16) | (id[1]<<8) | id[2]; + if (SYN_ID_IS_SYNAPTICS(*ident)) + return 0; + return -1; +} + +static int synaptics_enable_device(struct psmouse *psmouse) +{ + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) + return -1; + return 0; +} + +static void print_ident(struct synaptics_data *priv) +{ + printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity)); + printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity), + SYN_ID_MINOR(priv->identity)); + + if (SYN_MODEL_ROT180(priv->model_id)) + printk(KERN_INFO " 180 degree mounted touchpad\n"); + if (SYN_MODEL_PORTRAIT(priv->model_id)) + printk(KERN_INFO " portrait touchpad\n"); + printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id)); + if (SYN_MODEL_NEWABS(priv->model_id)) + printk(KERN_INFO " new absolute packet format\n"); + if (SYN_MODEL_PEN(priv->model_id)) + printk(KERN_INFO " pen detection\n"); + + if (SYN_CAP_EXTENDED(priv->capabilities)) { + printk(KERN_INFO " Touchpad has extended capability bits\n"); + if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) + printk(KERN_INFO " -> four buttons\n"); + if (SYN_CAP_MULTIFINGER(priv->capabilities)) + printk(KERN_INFO " -> multifinger detection\n"); + if (SYN_CAP_PALMDETECT(priv->capabilities)) + printk(KERN_INFO " -> palm detection\n"); + } +} + +static int query_hardware(struct psmouse *psmouse) +{ + struct synaptics_data *priv = psmouse->private; + int retries = 0; + + while ((retries++ < 3) && synaptics_reset(psmouse)) + printk(KERN_ERR "synaptics reset failed\n"); + + if (synaptics_identify(psmouse, &priv->identity)) + return -1; + if (synaptics_model_id(psmouse, &priv->model_id)) + return -1; + if (synaptics_capability(psmouse, &priv->capabilities)) + return -1; + if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE | + SYN_BIT_HIGH_RATE | + SYN_BIT_DISABLE_GESTURE | + SYN_BIT_W_MODE))) + return -1; + + synaptics_enable_device(psmouse); + + print_ident(priv); + + return 0; +} + +/***************************************************************************** + * Driver initialization/cleanup functions + ****************************************************************************/ + +static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat) +{ + dev->absmin[axis] = min; + dev->absmax[axis] = max; + dev->absfuzz[axis] = fuzz; + dev->absflat[axis] = flat; + + set_bit(axis, dev->absbit); +} + +int synaptics_init(struct psmouse *psmouse) +{ + struct synaptics_data *priv; + + psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL); + if (!priv) + return -1; + memset(priv, 0, sizeof(struct synaptics_data)); + + priv->inSync = 1; + + if (query_hardware(psmouse)) { + printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n"); + goto init_fail; + } + + /* + * The x/y limits are taken from the Synaptics TouchPad interfacing Guide, + * which says that they should be valid regardless of the actual size of + * the senser. + */ + set_bit(EV_ABS, psmouse->dev.evbit); + set_abs_params(&psmouse->dev, ABS_X, 1472, 5472, 0, 0); + set_abs_params(&psmouse->dev, ABS_Y, 1408, 4448, 0, 0); + set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 255, 0, 0); + + set_bit(EV_MSC, psmouse->dev.evbit); + set_bit(MSC_GESTURE, psmouse->dev.mscbit); + + set_bit(EV_KEY, psmouse->dev.evbit); + set_bit(BTN_LEFT, psmouse->dev.keybit); + set_bit(BTN_RIGHT, psmouse->dev.keybit); + set_bit(BTN_FORWARD, psmouse->dev.keybit); + set_bit(BTN_BACK, psmouse->dev.keybit); + + clear_bit(EV_REL, psmouse->dev.evbit); + clear_bit(REL_X, psmouse->dev.relbit); + clear_bit(REL_Y, psmouse->dev.relbit); + + return 0; + + init_fail: + kfree(priv); + return -1; +} + +void synaptics_disconnect(struct psmouse *psmouse) +{ + struct synaptics_data *priv = psmouse->private; + + kfree(priv); +} + +/***************************************************************************** + * Functions to interpret the absolute mode packets + ****************************************************************************/ + +static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw) +{ + unsigned char *buf = priv->proto_buf; + + hw->x = (((buf[3] & 0x10) << 8) | + ((buf[1] & 0x0f) << 8) | + buf[4]); + hw->y = (((buf[3] & 0x20) << 7) | + ((buf[1] & 0xf0) << 4) | + buf[5]); + + hw->z = buf[2]; + hw->w = (((buf[0] & 0x30) >> 2) | + ((buf[0] & 0x04) >> 1) | + ((buf[3] & 0x04) >> 2)); + + hw->left = (buf[0] & 0x01) ? 1 : 0; + hw->right = (buf[0] & 0x2) ? 1 : 0; + hw->up = 0; + hw->down = 0; + + if (SYN_CAP_EXTENDED(priv->capabilities) && + (SYN_CAP_FOUR_BUTTON(priv->capabilities))) { + hw->up = ((buf[3] & 0x01)) ? 1 : 0; + if (hw->left) + hw->up = !hw->up; + hw->down = ((buf[3] & 0x02)) ? 1 : 0; + if (hw->right) + hw->down = !hw->down; + } +} + +/* + * called for each full received packet from the touchpad + */ +static void synaptics_process_packet(struct psmouse *psmouse) +{ + struct input_dev *dev = &psmouse->dev; + struct synaptics_data *priv = psmouse->private; + struct synaptics_hw_state hw; + + synaptics_parse_hw_state(priv, &hw); + + if (hw.z > 0) { + int w_ok = 0; + /* + * Use capability bits to decide if the w value is valid. + * If not, set it to 5, which corresponds to a finger of + * normal width. + */ + if (SYN_CAP_EXTENDED(priv->capabilities)) { + switch (hw.w) { + case 0 ... 1: + w_ok = SYN_CAP_MULTIFINGER(priv->capabilities); + break; + case 2: + w_ok = SYN_MODEL_PEN(priv->model_id); + break; + case 4 ... 15: + w_ok = SYN_CAP_PALMDETECT(priv->capabilities); + break; + } + } + if (!w_ok) + hw.w = 5; + } + + /* Post events */ + input_report_abs(dev, ABS_X, hw.x); + input_report_abs(dev, ABS_Y, hw.y); + input_report_abs(dev, ABS_PRESSURE, hw.z); + + if (hw.w != priv->old_w) { + input_event(dev, EV_MSC, MSC_GESTURE, hw.w); + priv->old_w = hw.w; + } + + input_report_key(dev, BTN_LEFT, hw.left); + input_report_key(dev, BTN_RIGHT, hw.right); + input_report_key(dev, BTN_FORWARD, hw.up); + input_report_key(dev, BTN_BACK, hw.down); + + input_sync(dev); +} + +void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) +{ + struct input_dev *dev = &psmouse->dev; + struct synaptics_data *priv = psmouse->private; + unsigned char *pBuf = priv->proto_buf; + unsigned char u = psmouse->packet[0]; + + input_regs(dev, regs); + + pBuf[priv->proto_buf_tail++] = u; + + /* check first byte */ + if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) { + priv->inSync = 0; + priv->proto_buf_tail = 0; + printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n"); + return; + } + + /* check 4th byte */ + if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) { + priv->inSync = 0; + priv->proto_buf_tail = 0; + printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n"); + return; + } + + if (priv->proto_buf_tail >= 6) { /* Full packet received */ + if (!priv->inSync) { + priv->inSync = 1; + printk(KERN_NOTICE "Synaptics driver resynced.\n"); + } + synaptics_process_packet(psmouse); + priv->proto_buf_tail = 0; + } +} + +#else + +int synaptics_init(PDEVICE_EXTENSION DeviceExtension) +{ + return -1; +} + +#endif diff --git a/reactos/drivers/input/psaux/synaptics.h b/reactos/drivers/input/psaux/synaptics.h new file mode 100644 index 00000000000..f7f2259cf3b --- /dev/null +++ b/reactos/drivers/input/psaux/synaptics.h @@ -0,0 +1,100 @@ +/* + * Synaptics TouchPad PS/2 mouse driver + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#ifndef NO_SYNAPTICS + +#ifndef _SYNAPTICS_H +#define _SYNAPTICS_H + +extern void synaptics_process_byte(DeviceExtension, struct pt_regs *regs); +#endif +extern int synaptics_init(DeviceExtension); +#ifndef NO_SYNAPTICS +extern void synaptics_disconnect(DeviceExtension); + +/* synaptics queries */ +#define SYN_QUE_IDENTIFY 0x00 +#define SYN_QUE_MODES 0x01 +#define SYN_QUE_CAPABILITIES 0x02 +#define SYN_QUE_MODEL 0x03 +#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06 +#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07 +#define SYN_QUE_RESOLUTION 0x08 + +/* synatics modes */ +#define SYN_BIT_ABSOLUTE_MODE (1 << 7) +#define SYN_BIT_HIGH_RATE (1 << 6) +#define SYN_BIT_SLEEP_MODE (1 << 3) +#define SYN_BIT_DISABLE_GESTURE (1 << 2) +#define SYN_BIT_W_MODE (1 << 0) + +/* synaptics model ID bits */ +#define SYN_MODEL_ROT180(m) ((m) & (1 << 23)) +#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22)) +#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f) +#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f) +#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7)) +#define SYN_MODEL_PEN(m) ((m) & (1 << 6)) +#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5)) +#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f) + +/* synaptics capability bits */ +#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) +#define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) +#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) +#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) +#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) +#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) + +/* synaptics modes query bits */ +#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) +#define SYN_MODE_RATE(m) ((m) & (1 << 6)) +#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3)) +#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2)) +#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1)) +#define SYN_MODE_WMODE(m) ((m) & (1 << 0)) + +/* synaptics identify query bits */ +#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) +#define SYN_ID_MAJOR(i) ((i) & 0x0f) +#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) +#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) + +/* + * A structure to describe the state of the touchpad hardware (buttons and pad) + */ + +struct synaptics_hw_state { + int x; + int y; + int z; + int w; + int left; + int right; + int up; + int down; +}; + +struct synaptics_data { + /* Data read from the touchpad */ + unsigned long int model_id; /* Model-ID */ + unsigned long int capabilities; /* Capabilities */ + unsigned long int identity; /* Identification */ + + /* Data for normal processing */ + unsigned char proto_buf[6]; /* Buffer for Packet */ + unsigned char last_byte; /* last received byte */ + int inSync; /* Packets in sync */ + int proto_buf_tail; + + int old_w; /* Previous w value */ +}; + +#endif /* _SYNAPTICS_H */ + +#endif /* NO_SYNAPTICS */ +