Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441/* * PROJECT: ReactOS InPort (Bus) Mouse Driver * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Hardware support code * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com) */
/* Note: Some code was taken from Linux */
/* INCLUDES *******************************************************************/
#include "inport.h"
#define NDEBUG#include <debug.h>
/* GLOBALS ********************************************************************/
#define READ_MOUSE(DeviceExtension, Port) \ READ_PORT_UCHAR((DeviceExtension)->IoBase + (Port))
#define WRITE_MOUSE(DeviceExtension, Port, Data) \ WRITE_PORT_UCHAR((DeviceExtension)->IoBase + (Port), (Data))
/* * NEC */#define NEC_BM_DATA 0x00
#define NEC_BM_CONTROL 0x04 #define NEC_INT_ENABLE 0x00 #define NEC_INT_DISABLE 0x10
#define NEC_READ_X_LOW 0x00 #define NEC_READ_X_HIGH 0x20 #define NEC_READ_Y_LOW 0x40 #define NEC_READ_Y_HIGH 0x60
#define NEC_INPUT_CAPTURE 0x00 #define NEC_INPUT_HOLD 0x80
#define NEC_BM_CONFIG 0x06 #define NEC_PPI_INT_ENABLE 0x08 #define NEC_PPI_INT_DISABLE 0x09 #define NEC_PPI_HC_NO_CLEAR 0x0E #define NEC_PPI_HC_CLEAR 0x0F #define NEC_PPI_DEFAULT_MODE 0x93
#define NEC_BM_INT_RATE 0x4002 #define NEC_RATE_120_HZ 0x00 #define NEC_RATE_60_HZ 0x01 #define NEC_RATE_30_HZ 0x02 #define NEC_RATE_15_HZ 0x03
#define NEC_BM_HIRESO_BASE (PUCHAR)0x61
#define NEC_BUTTON_RIGHT 0x20#define NEC_BUTTON_LEFT 0x80
/* * Microsoft InPort */#define MS_INPORT_CONTROL 0x00 #define INPORT_REG_BTNS 0x00 #define INPORT_REG_X 0x01 #define INPORT_REG_Y 0x02 #define INPORT_REG_MODE 0x07 #define INPORT_RESET 0x80
#define MS_INPORT_DATA 0x01 #define INPORT_MODE_IRQ 0x01 #define INPORT_MODE_BASE 0x10 #define INPORT_MODE_HOLD 0x20 #define INPORT_HAS_MOVED 0x40
#define MS_INPORT_SIGNATURE 0x02
#define MS_BUTTON_RIGHT 0x01#define MS_BUTTON_MIDDLE 0x02#define MS_BUTTON_LEFT 0x04
/* * Logitech */#define LOG_BM_DATA 0x00
#define LOG_BM_SIGNATURE 0x01 #define LOG_SIGNATURE_BYTE 0xA5
#define LOG_BM_CONTROL 0x02 #define LOG_ENABLE_IRQ 0x00 #define LOG_DISABLE_IRQ 0x10
#define LOG_READ_X_LOW 0x80 #define LOG_READ_X_HIGH 0xA0 #define LOG_READ_Y_LOW 0xC0 #define LOG_READ_Y_HIGH 0xE0
#define LOG_BM_CONFIG 0x03 #define LOG_DEFAULT_MODE 0x90 #define LOG_CONFIG_BYTE 0x91
#define LOG_BUTTON_RIGHT 0x20#define LOG_BUTTON_MIDDLE 0x40#define LOG_BUTTON_LEFT 0x80
/* FUNCTIONS ******************************************************************/
VOIDNTAPIInPortDpcForIsr( _In_ PKDPC Dpc, _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _In_opt_ PVOID Context){ PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; KIRQL OldIrql; ULONG DummyInputDataConsumed; INPORT_RAW_DATA RawData;
UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(Irp); UNREFERENCED_PARAMETER(Context);
/* Copy raw data */ OldIrql = KeAcquireInterruptSpinLock(DeviceExtension->InterruptObject); RawData = DeviceExtension->RawData; KeReleaseInterruptSpinLock(DeviceExtension->InterruptObject, OldIrql);
/* Fill out fields */ DeviceExtension->MouseInputData.LastX = RawData.DeltaX; DeviceExtension->MouseInputData.LastY = RawData.DeltaY; DeviceExtension->MouseInputData.ButtonFlags = 0; if (RawData.ButtonDiff != 0) { switch (DeviceExtension->MouseType) { case NecBusMouse: { if (RawData.ButtonDiff & NEC_BUTTON_LEFT) { if (RawData.Buttons & NEC_BUTTON_LEFT) DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_UP; else DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN; } if (RawData.ButtonDiff & NEC_BUTTON_RIGHT) { if (RawData.Buttons & NEC_BUTTON_RIGHT) DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_UP; else DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN; }
break; }
case MsInPortMouse: { /* Button flags have to be inverted */ if (RawData.ButtonDiff & MS_BUTTON_LEFT) { if (RawData.Buttons & MS_BUTTON_LEFT) DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN; else DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_UP; } if (RawData.ButtonDiff & MS_BUTTON_RIGHT) { if (RawData.Buttons & MS_BUTTON_RIGHT) DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN; else DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_UP; } if (RawData.ButtonDiff & MS_BUTTON_MIDDLE) { if (RawData.Buttons & MS_BUTTON_MIDDLE) DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN; else DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP; }
break; }
case LogitechBusMouse: { if (RawData.ButtonDiff & LOG_BUTTON_LEFT) { if (RawData.Buttons & LOG_BUTTON_LEFT) DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_UP; else DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN; } if (RawData.ButtonDiff & LOG_BUTTON_RIGHT) { if (RawData.Buttons & LOG_BUTTON_RIGHT) DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_UP; else DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN; } if (RawData.ButtonDiff & LOG_BUTTON_MIDDLE) { if (RawData.Buttons & LOG_BUTTON_MIDDLE) DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP; else DeviceExtension->MouseInputData.ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN; }
break; } } }
/* Send mouse packet */ (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)( DeviceExtension->ClassDeviceObject, &DeviceExtension->MouseInputData, &DeviceExtension->MouseInputData + 1, &DummyInputDataConsumed);}
BOOLEANNTAPIInPortIsr( _In_ PKINTERRUPT Interrupt, _In_ PVOID Context){ UCHAR Buttons; ULONG ButtonDiff; CHAR DeltaX, DeltaY; PINPORT_DEVICE_EXTENSION DeviceExtension = Context;
UNREFERENCED_PARAMETER(Interrupt);
switch (DeviceExtension->MouseType) { case NecBusMouse: { WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL, NEC_INPUT_CAPTURE | NEC_INT_DISABLE);
WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL, NEC_INPUT_HOLD | NEC_INT_DISABLE | NEC_READ_X_LOW); DeltaX = READ_MOUSE(DeviceExtension, NEC_BM_DATA) & 0x0F;
WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL, NEC_INPUT_HOLD | NEC_INT_DISABLE | NEC_READ_X_HIGH); DeltaX |= READ_MOUSE(DeviceExtension, NEC_BM_DATA) << 4;
WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL, NEC_INPUT_HOLD | NEC_INT_DISABLE | NEC_READ_Y_LOW); DeltaY = READ_MOUSE(DeviceExtension, NEC_BM_DATA) & 0x0F;
WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL, NEC_INPUT_HOLD | NEC_INT_DISABLE | NEC_READ_Y_HIGH); Buttons = READ_MOUSE(DeviceExtension, NEC_BM_DATA); DeltaY |= Buttons << 4; Buttons &= (NEC_BUTTON_LEFT | NEC_BUTTON_RIGHT);
WRITE_MOUSE(DeviceExtension, NEC_BM_CONTROL, NEC_INPUT_HOLD | NEC_INT_ENABLE);
break; }
case MsInPortMouse: { WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE); WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA, INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE);
WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_BTNS); Buttons = READ_MOUSE(DeviceExtension, MS_INPORT_DATA);
if (Buttons & INPORT_HAS_MOVED) { WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_X); DeltaX = READ_MOUSE(DeviceExtension, MS_INPORT_DATA);
WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_Y); DeltaY = READ_MOUSE(DeviceExtension, MS_INPORT_DATA); } else { DeltaX = 0; DeltaY = 0; }
Buttons &= (MS_BUTTON_MIDDLE | MS_BUTTON_LEFT | MS_BUTTON_RIGHT);
WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE); WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA, INPORT_MODE_IRQ | INPORT_MODE_BASE);
break; }
case LogitechBusMouse: { WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_X_LOW); DeltaX = READ_MOUSE(DeviceExtension, LOG_BM_DATA) & 0x0F;
WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_X_HIGH); DeltaX |= READ_MOUSE(DeviceExtension, LOG_BM_DATA) << 4;
WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_Y_LOW); DeltaY = READ_MOUSE(DeviceExtension, LOG_BM_DATA) & 0x0F;
WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_READ_Y_HIGH); Buttons = READ_MOUSE(DeviceExtension, LOG_BM_DATA); DeltaY |= Buttons << 4; Buttons &= (LOG_BUTTON_RIGHT | LOG_BUTTON_MIDDLE | LOG_BUTTON_LEFT);
WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_ENABLE_IRQ);
break; } }
ButtonDiff = DeviceExtension->MouseButtonState ^ Buttons; DeviceExtension->MouseButtonState = Buttons;
/* * Bus mouse devices don't have a status register to check * whether this interrupt is indeed for us. */ if ((DeltaX == 0) && (DeltaY == 0) && (ButtonDiff == 0)) { /* We just pretend that the interrupt is not ours */ return FALSE; } else { DeviceExtension->RawData.DeltaX = DeltaX; DeviceExtension->RawData.DeltaY = DeltaY; DeviceExtension->RawData.Buttons = Buttons; DeviceExtension->RawData.ButtonDiff = ButtonDiff;
IoRequestDpc(DeviceExtension->Self, NULL, NULL);
return TRUE; }}
CODE_SEG("PAGE")VOIDNTAPIInPortInitializeMouse( _In_ PINPORT_DEVICE_EXTENSION DeviceExtension){ PAGED_CODE();
/* Initialize mouse and disable interrupts */ switch (DeviceExtension->MouseType) { case NecBusMouse: WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_DEFAULT_MODE);
/* Setup interrupt rate (unavailable on hireso machines) */ if (DeviceExtension->IoBase != NEC_BM_HIRESO_BASE) WRITE_MOUSE(DeviceExtension, NEC_BM_INT_RATE, NEC_RATE_60_HZ);
WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_INT_DISABLE); WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_NO_CLEAR); WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR); break;
case MsInPortMouse: WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_RESET); WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE); WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA, INPORT_MODE_BASE); break;
case LogitechBusMouse: WRITE_MOUSE(DeviceExtension, LOG_BM_CONFIG, LOG_DEFAULT_MODE); WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_DISABLE_IRQ); break; }}
BOOLEANNTAPIInPortStartMouse( _In_ PVOID SynchronizeContext){ PINPORT_DEVICE_EXTENSION DeviceExtension = SynchronizeContext;
/* Enable interrupts */ switch (DeviceExtension->MouseType) { case NecBusMouse: WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_INT_ENABLE); WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_NO_CLEAR); WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR); break;
case MsInPortMouse: WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE); WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA, INPORT_MODE_IRQ | INPORT_MODE_BASE); break;
case LogitechBusMouse: WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_ENABLE_IRQ); break; }
return TRUE;}
BOOLEANNTAPIInPortStopMouse( _In_ PVOID SynchronizeContext){ PINPORT_DEVICE_EXTENSION DeviceExtension = SynchronizeContext;
/* Disable interrupts */ switch (DeviceExtension->MouseType) { case NecBusMouse: WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_INT_DISABLE); WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_NO_CLEAR); WRITE_MOUSE(DeviceExtension, NEC_BM_CONFIG, NEC_PPI_HC_CLEAR); break;
case MsInPortMouse: WRITE_MOUSE(DeviceExtension, MS_INPORT_CONTROL, INPORT_REG_MODE); WRITE_MOUSE(DeviceExtension, MS_INPORT_DATA, INPORT_MODE_BASE); break;
case LogitechBusMouse: WRITE_MOUSE(DeviceExtension, LOG_BM_CONTROL, LOG_DISABLE_IRQ); break; }
return TRUE;}