mirror of
https://github.com/reactos/reactos.git
synced 2024-10-30 11:35:58 +00:00
277 lines
7.8 KiB
C
277 lines
7.8 KiB
C
/*
|
|
* PROJECT: ReactOS Serial mouse driver
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: drivers/input/sermouse/fdo.c
|
|
* PURPOSE: Read mouse moves and send them to mouclass
|
|
* PROGRAMMERS: Copyright Jason Filby (jasonfilby@yahoo.com)
|
|
Copyright Filip Navara (xnavara@volny.cz)
|
|
Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
|
|
*/
|
|
|
|
#include "sermouse.h"
|
|
|
|
#include <debug.h>
|
|
|
|
static NTSTATUS
|
|
SermouseDeviceIoControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG CtlCode,
|
|
IN PVOID InputBuffer OPTIONAL,
|
|
IN ULONG InputBufferSize,
|
|
IN OUT PVOID OutputBuffer OPTIONAL,
|
|
IN OUT PULONG OutputBufferSize)
|
|
{
|
|
KEVENT Event;
|
|
PIRP Irp;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS Status;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildDeviceIoControlRequest(CtlCode,
|
|
DeviceObject,
|
|
InputBuffer,
|
|
InputBufferSize,
|
|
OutputBuffer,
|
|
(OutputBufferSize) ? *OutputBufferSize : 0,
|
|
FALSE,
|
|
&Event,
|
|
&IoStatus);
|
|
if (Irp == NULL)
|
|
{
|
|
WARN_(SERMOUSE, "IoBuildDeviceIoControlRequest() failed\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
INFO_(SERMOUSE, "Operation pending\n");
|
|
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
|
|
Status = IoStatus.Status;
|
|
}
|
|
|
|
if (OutputBufferSize)
|
|
{
|
|
*OutputBufferSize = (ULONG)IoStatus.Information;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID NTAPI
|
|
SermouseDeviceWorker(
|
|
PVOID Context)
|
|
{
|
|
PSERMOUSE_DEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_OBJECT LowerDevice;
|
|
UCHAR Buffer[PACKET_BUFFER_SIZE];
|
|
PIRP Irp;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
KEVENT event;
|
|
PUCHAR PacketBuffer;
|
|
UCHAR ReceivedByte;
|
|
ULONG Queue;
|
|
PMOUSE_INPUT_DATA Input;
|
|
ULONG ButtonsDifference;
|
|
KIRQL OldIrql;
|
|
ULONG i;
|
|
ULONG Fcr;
|
|
ULONG BaudRate;
|
|
SERIAL_TIMEOUTS Timeouts;
|
|
SERIAL_LINE_CONTROL LCR;
|
|
LARGE_INTEGER Zero;
|
|
NTSTATUS Status;
|
|
|
|
TRACE_(SERMOUSE, "SermouseDeviceWorker() called\n");
|
|
|
|
DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
|
|
LowerDevice = DeviceExtension->LowerDevice;
|
|
Zero.QuadPart = 0;
|
|
PacketBuffer = DeviceExtension->PacketBuffer;
|
|
|
|
ASSERT(LowerDevice);
|
|
|
|
/* Initialize device extension */
|
|
DeviceExtension->ActiveQueue = 0;
|
|
DeviceExtension->PacketBufferPosition = 0;
|
|
DeviceExtension->PreviousButtons = 0;
|
|
|
|
/* Initialize serial port */
|
|
Fcr = 0;
|
|
Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL,
|
|
&Fcr, sizeof(Fcr), NULL, NULL);
|
|
if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
|
|
/* Set serial port speed */
|
|
BaudRate = DeviceExtension->AttributesInformation.SampleRate * 8;
|
|
Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
|
|
&BaudRate, sizeof(BaudRate), NULL, NULL);
|
|
if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
|
|
/* Set LCR */
|
|
LCR.WordLength = 7;
|
|
LCR.Parity = NO_PARITY;
|
|
LCR.StopBits = STOP_BIT_1;
|
|
Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
|
|
&LCR, sizeof(LCR), NULL, NULL);
|
|
if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
|
|
|
|
/* Set timeouts */
|
|
Timeouts.ReadTotalTimeoutConstant = Timeouts.ReadTotalTimeoutMultiplier = 0;
|
|
Timeouts.ReadIntervalTimeout = 100;
|
|
Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
|
|
Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
|
|
&Timeouts, sizeof(Timeouts), NULL, NULL);
|
|
if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
|
|
|
|
/* main read loop */
|
|
RtlZeroMemory(Buffer, PACKET_BUFFER_SIZE);
|
|
while (TRUE)
|
|
{
|
|
Status = KeWaitForSingleObject(
|
|
&DeviceExtension->StopWorkerThreadEvent,
|
|
Executive,
|
|
KernelMode,
|
|
TRUE,
|
|
&Zero);
|
|
if (Status != STATUS_TIMEOUT)
|
|
{
|
|
/* we need to stop the worker thread */
|
|
KeClearEvent(&DeviceExtension->StopWorkerThreadEvent);
|
|
break;
|
|
}
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
Irp = IoBuildSynchronousFsdRequest(
|
|
IRP_MJ_READ,
|
|
LowerDevice,
|
|
Buffer, PACKET_BUFFER_SIZE,
|
|
&Zero,
|
|
&event,
|
|
&ioStatus);
|
|
if (!Irp)
|
|
{
|
|
/* No memory actually, try later */
|
|
INFO_(SERMOUSE, "No memory actually, trying again\n");
|
|
KeStallExecutionProcessor(10);
|
|
continue;
|
|
}
|
|
|
|
Status = IoCallDriver(LowerDevice, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
|
Status = ioStatus.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
continue;
|
|
|
|
/* Read all available data and process */
|
|
for (i = 0; i < ioStatus.Information; i++)
|
|
{
|
|
ReceivedByte = Buffer[i];
|
|
INFO_(SERMOUSE, "ReceivedByte 0x%02x\n", ReceivedByte);
|
|
|
|
/* Synchronize */
|
|
if ((ReceivedByte & 0x40) == 0x40)
|
|
DeviceExtension->PacketBufferPosition = 0;
|
|
|
|
PacketBuffer[DeviceExtension->PacketBufferPosition] = ReceivedByte & 0x7f;
|
|
DeviceExtension->PacketBufferPosition++;
|
|
|
|
/* Process packet if complete */
|
|
if (DeviceExtension->PacketBufferPosition >= 3)
|
|
{
|
|
Queue = DeviceExtension->ActiveQueue % 2;
|
|
|
|
/* Prevent buffer overflow */
|
|
if (DeviceExtension->InputDataCount[Queue] == 1)
|
|
continue;
|
|
|
|
Input = &DeviceExtension->MouseInputData[Queue];
|
|
|
|
if (DeviceExtension->PacketBufferPosition == 3)
|
|
{
|
|
/* Retrieve change in x and y from packet */
|
|
Input->LastX = (signed char)(PacketBuffer[1] | ((PacketBuffer[0] & 0x03) << 6));
|
|
Input->LastY = (signed char)(PacketBuffer[2] | ((PacketBuffer[0] & 0x0c) << 4));
|
|
|
|
/* Determine the current state of the buttons */
|
|
Input->RawButtons = (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE) |
|
|
((UCHAR)(PacketBuffer[0] & LEFT_BUTTON_MASK) >> LEFT_BUTTON_SHIFT) |
|
|
((UCHAR)(PacketBuffer[0] & RIGHT_BUTTON_MASK) >> RIGHT_BUTTON_SHIFT);
|
|
}
|
|
else if (DeviceExtension->PacketBufferPosition == 4)
|
|
{
|
|
DeviceExtension->PacketBufferPosition = 0;
|
|
/* If middle button state changed than report event */
|
|
if (((UCHAR)(PacketBuffer[3] & MIDDLE_BUTTON_MASK) >> MIDDLE_BUTTON_SHIFT) ^
|
|
(DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE))
|
|
{
|
|
Input->RawButtons ^= MOUSE_BUTTON_MIDDLE;
|
|
Input->LastX = 0;
|
|
Input->LastY = 0;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Determine ButtonFlags */
|
|
Input->ButtonFlags = 0;
|
|
ButtonsDifference = DeviceExtension->PreviousButtons ^ Input->RawButtons;
|
|
|
|
if (ButtonsDifference != 0)
|
|
{
|
|
if (ButtonsDifference & MOUSE_BUTTON_LEFT
|
|
&& DeviceExtension->AttributesInformation.NumberOfButtons >= 1)
|
|
{
|
|
if (Input->RawButtons & MOUSE_BUTTON_LEFT)
|
|
Input->ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
|
|
else
|
|
Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
|
|
}
|
|
|
|
if (ButtonsDifference & MOUSE_BUTTON_RIGHT
|
|
&& DeviceExtension->AttributesInformation.NumberOfButtons >= 2)
|
|
{
|
|
if (Input->RawButtons & MOUSE_BUTTON_RIGHT)
|
|
Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
|
|
else
|
|
Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
|
|
}
|
|
|
|
if (ButtonsDifference & MOUSE_BUTTON_MIDDLE
|
|
&& DeviceExtension->AttributesInformation.NumberOfButtons >= 3)
|
|
{
|
|
if (Input->RawButtons & MOUSE_BUTTON_MIDDLE)
|
|
Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
|
|
else
|
|
Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
|
|
}
|
|
}
|
|
|
|
/* Send the Input data to the Mouse Class driver */
|
|
DeviceExtension->InputDataCount[Queue]++;
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
InterlockedIncrement((PLONG)&DeviceExtension->ActiveQueue);
|
|
(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ConnectData.ClassService)(
|
|
DeviceExtension->ConnectData.ClassDeviceObject,
|
|
&DeviceExtension->MouseInputData[Queue],
|
|
&DeviceExtension->MouseInputData[Queue] + 1,
|
|
&DeviceExtension->InputDataCount[Queue]);
|
|
KeLowerIrql(OldIrql);
|
|
DeviceExtension->InputDataCount[Queue] = 0;
|
|
|
|
/* Copy RawButtons to Previous Buttons for Input */
|
|
DeviceExtension->PreviousButtons = Input->RawButtons;
|
|
}
|
|
}
|
|
}
|
|
|
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|
}
|