diff --git a/reactos/drivers/input/sermouse/createclose.c b/reactos/drivers/input/sermouse/createclose.c new file mode 100644 index 00000000000..6f24ec8ad4b --- /dev/null +++ b/reactos/drivers/input/sermouse/createclose.c @@ -0,0 +1,58 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Serial mouse driver + * FILE: drivers/input/sermouse/fdo.c + * PURPOSE: IRP_MJ_CREATE and IRP_MJ_CLOSE operations + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#include "sermouse.h" + +NTSTATUS NTAPI +SermouseStartDevice( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); /* FIXME: remove the declaration */ + +NTSTATUS NTAPI +SermouseCreate( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + DPRINT("IRP_MJ_CREATE\n"); + ASSERT(((PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->PnpState == dsStarted); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +SermouseClose( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + DPRINT("IRP_MJ_CLOSE\n"); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +SermouseCleanup( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + DPRINT("IRP_MJ_CLEANUP\n"); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/input/sermouse/detect.c b/reactos/drivers/input/sermouse/detect.c new file mode 100644 index 00000000000..dfa1ae77fb2 --- /dev/null +++ b/reactos/drivers/input/sermouse/detect.c @@ -0,0 +1,282 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Serial mouse driver + * FILE: drivers/input/sermouse/detect.c + * PURPOSE: Detect serial mouse type + * + * PROGRAMMERS: Jason Filby (jasonfilby@yahoo.com) + * Filip Navara (xnavara@volny.cz) + * Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#include "sermouse.h" + +/* Most of this file is ripped from reactos/drivers/bus/serenum/detect.c */ + +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) + { + DPRINT("IoBuildDeviceIoControlRequest() failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = IoCallDriver(DeviceObject, Irp); + + if (Status == STATUS_PENDING) + { + DPRINT("Operation pending\n"); + KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + + if (OutputBufferSize) + { + *OutputBufferSize = IoStatus.Information; + } + + return Status; +} + +static NTSTATUS +SermouseSendIrp( + IN PDEVICE_OBJECT DeviceObject, + IN ULONG MajorFunction) +{ + KEVENT Event; + PIRP Irp; + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildSynchronousFsdRequest( + MajorFunction, + DeviceObject, + NULL, + 0, + NULL, + &Event, + &IoStatus); + if (Irp == NULL) + { + DPRINT("IoBuildSynchronousFsdRequest() failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = IoCallDriver(DeviceObject, Irp); + + if (Status == STATUS_PENDING) + { + DPRINT("Operation pending\n"); + KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + + return Status; +} + +static NTSTATUS +ReadBytes( + IN PDEVICE_OBJECT LowerDevice, + OUT PUCHAR Buffer, + IN ULONG BufferSize, + OUT PULONG FilledBytes) +{ + PIRP Irp; + IO_STATUS_BLOCK ioStatus; + KEVENT event; + LARGE_INTEGER zero; + NTSTATUS Status; + + KeInitializeEvent(&event, NotificationEvent, FALSE); + zero.QuadPart = 0; + Irp = IoBuildSynchronousFsdRequest( + IRP_MJ_READ, + LowerDevice, + Buffer, BufferSize, + &zero, + &event, + &ioStatus); + if (!Irp) + return FALSE; + + Status = IoCallDriver(LowerDevice, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); + Status = ioStatus.Status; + } + DPRINT("Bytes received: %lu/%lu\n", + ioStatus.Information, BufferSize); + *FilledBytes = ioStatus.Information; + return Status; +} + +static NTSTATUS +SermouseWait(ULONG milliseconds) +{ + KTIMER Timer; + LARGE_INTEGER DueTime; + + DueTime.QuadPart = milliseconds * -10; + KeInitializeTimer(&Timer); + KeSetTimer(&Timer, DueTime, NULL); + return KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL); +} + +SERMOUSE_MOUSE_TYPE +SermouseDetectLegacyDevice( + IN PDEVICE_OBJECT LowerDevice) +{ + ULONG Fcr, Mcr; + ULONG BaudRate; + ULONG Command; + SERIAL_TIMEOUTS Timeouts; + SERIAL_LINE_CONTROL LCR; + ULONG i, Count; + UCHAR Buffer[16]; + SERMOUSE_MOUSE_TYPE MouseType = mtNone; + NTSTATUS Status; + + RtlZeroMemory(Buffer, sizeof(Buffer)); + + /* Open port */ + Status = SermouseSendIrp(LowerDevice, IRP_MJ_CREATE); + if (!NT_SUCCESS(Status)) return mtNone; + + /* Reset UART */ + CHECKPOINT; + Mcr = 0; /* MCR: DTR/RTS/OUT2 off */ + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL, + &Mcr, sizeof(Mcr), NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + + /* Set communications parameters */ + CHECKPOINT; + /* DLAB off */ + Fcr = 0; + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL, + &Fcr, sizeof(Fcr), NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + /* Set serial port speed */ + BaudRate = SERIAL_BAUD_1200; + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE, + &BaudRate, sizeof(BaudRate), NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + /* Set LCR */ + LCR.WordLength = 7; + LCR.Parity = NO_PARITY; + LCR.StopBits = STOP_BITS_2; + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL, + &LCR, sizeof(LCR), NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + + /* Disable DTR/RTS */ + CHECKPOINT; + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR, + NULL, 0, NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS, + NULL, 0, NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + + /* Flush receive buffer */ + CHECKPOINT; + Command = SERIAL_PURGE_RXCLEAR; + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL, + &Command, sizeof(Command), NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + /* Wait 100 ms */ + SermouseWait(100); + + /* Enable DTR/RTS */ + CHECKPOINT; + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR, + NULL, 0, NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + SermouseWait(200); + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS, + NULL, 0, NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + + /* Set timeout to 500 microseconds */ + CHECKPOINT; + Timeouts.ReadIntervalTimeout = 0; + Timeouts.ReadTotalTimeoutMultiplier = 0; + Timeouts.ReadTotalTimeoutConstant = 500; + Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0; + Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS, + &Timeouts, sizeof(Timeouts), NULL, NULL); + if (!NT_SUCCESS(Status)) goto ByeBye; + + /* Fill the read buffer */ + CHECKPOINT; + Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), &Count); + if (!NT_SUCCESS(Status)) goto ByeBye; + + for (i = 0; i < Count; i++) + { + if (Buffer[i] == 'B') + { + /* Sign for Microsoft Ballpoint */ + DPRINT1("Microsoft Ballpoint device detected. THIS DEVICE IS NOT YET SUPPORTED"); + MouseType = mtNone; + goto ByeBye; + } + else if (Buffer[i] == 'M') + { + /* Sign for Microsoft Mouse protocol followed by button specifier */ + if (i == sizeof(Buffer) - 1) + { + /* Overflow Error */ + goto ByeBye; + } + switch (Buffer[i + 1]) + { + case '3': + DPRINT("Microsoft Mouse with 3-buttons detected\n"); + MouseType = mtLogitech; + case 'Z': + DPRINT("Microsoft Wheel Mouse detected\n"); + MouseType = mtWheelZ; + default: + DPRINT("Microsoft Mouse with 2-buttons detected\n"); + MouseType = mtMicrosoft; + } + goto ByeBye; + } + } + +ByeBye: + /* Close port */ + SermouseSendIrp(LowerDevice, IRP_MJ_CLOSE); + SermouseSendIrp(LowerDevice, IRP_MJ_CLEANUP); + return MouseType; +} diff --git a/reactos/drivers/input/sermouse/fdo.c b/reactos/drivers/input/sermouse/fdo.c new file mode 100644 index 00000000000..a20fa5a14e0 --- /dev/null +++ b/reactos/drivers/input/sermouse/fdo.c @@ -0,0 +1,239 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Serial mouse driver + * FILE: drivers/input/sermouse/fdo.c + * PURPOSE: IRP_MJ_PNP operations for FDOs + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#include "sermouse.h" + +NTSTATUS NTAPI +SermouseAddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT Pdo) +{ + PSERMOUSE_DRIVER_EXTENSION DriverExtension; + ULONG DeviceId = 0; + ULONG PrefixLength; + UNICODE_STRING DeviceNameU; + PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */ + PDEVICE_OBJECT Fdo; + PSERMOUSE_DEVICE_EXTENSION DeviceExtension; + NTSTATUS Status; + + DPRINT("SermouseAddDevice called. Pdo = 0x%p\n", Pdo); + + /* Create new device object */ + DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); + DeviceNameU.Length = 0; + DeviceNameU.MaximumLength = + wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */ + + DriverExtension->PointerDeviceBaseName.Length /* "PointerPort" */ + + 4 * sizeof(WCHAR) /* Id between 0 and 9999 */ + + sizeof(UNICODE_NULL); /* Final NULL char */ + DeviceNameU.Buffer = ExAllocatePool(PagedPool, DeviceNameU.MaximumLength); + if (!DeviceNameU.Buffer) + { + DPRINT("ExAllocatePool() failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\"); + if (!NT_SUCCESS(Status)) + { + DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status); + goto cleanup; + } + Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->PointerDeviceBaseName); + if (!NT_SUCCESS(Status)) + { + DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status); + goto cleanup; + } + PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL); + DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)]; + while (DeviceId < 9999) + { + DeviceNameU.Length = PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR); + Status = IoCreateDevice( + DriverObject, + sizeof(SERMOUSE_DEVICE_EXTENSION), + &DeviceNameU, + FILE_DEVICE_SERIAL_MOUSE_PORT, + FILE_DEVICE_SECURE_OPEN, + TRUE, + &Fdo); + if (NT_SUCCESS(Status)) + goto cleanup; + else if (Status != STATUS_OBJECT_NAME_COLLISION) + { + DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status); + goto cleanup; + } + DeviceId++; + } + DPRINT("Too much devices starting with '\\Device\\%wZ'\n", &DriverExtension->PointerDeviceBaseName); + Status = STATUS_UNSUCCESSFUL; +cleanup: + if (!NT_SUCCESS(Status)) + { + ExFreePool(DeviceNameU.Buffer); + return Status; + } + + DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)Fdo->DeviceExtension; + RtlZeroMemory(DeviceExtension, sizeof(SERMOUSE_DEVICE_EXTENSION)); + DeviceExtension->MouseType = mtNone; + DeviceExtension->PnpState = dsStopped; + DeviceExtension->DriverExtension = DriverExtension; + KeInitializeEvent(&DeviceExtension->StopWorkerThreadEvent, NotificationEvent, FALSE); + DeviceExtension->MouseInputData[0] = ExAllocatePool(NonPagedPool, DeviceExtension->DriverExtension->MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA)); + if (!DeviceExtension->MouseInputData[0]) + { + DPRINT("ExAllocatePool() failed\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto cleanupFDO; + } + DeviceExtension->MouseInputData[1] = ExAllocatePool(NonPagedPool, DeviceExtension->DriverExtension->MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA)); + if (!DeviceExtension->MouseInputData[1]) + { + DPRINT("ExAllocatePool() failed\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto cleanupFDO; + } + Fdo->Flags |= DO_POWER_PAGABLE; + Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice); + if (!NT_SUCCESS(Status)) + { + DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status); + goto cleanupFDO; + } + Fdo->Flags |= DO_BUFFERED_IO; + Fdo->Flags &= ~DO_DEVICE_INITIALIZING; + + /* FIXME: create registry entry in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */ + + ExFreePool(DeviceNameU.Buffer); + + return STATUS_SUCCESS; + +cleanupFDO: + if (DeviceExtension) + { + ExFreePool(DeviceExtension->MouseInputData[0]); + ExFreePool(DeviceExtension->MouseInputData[1]); + } + if (Fdo) + { + IoDeleteDevice(Fdo); + } + return Status; +} + +NTSTATUS NTAPI +SermouseStartDevice( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PSERMOUSE_DEVICE_EXTENSION DeviceExtension; + SERMOUSE_MOUSE_TYPE MouseType; + + DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + ASSERT(DeviceExtension->PnpState == dsStopped); + ASSERT(DeviceExtension->LowerDevice); + MouseType = SermouseDetectLegacyDevice(DeviceExtension->LowerDevice); + if (MouseType == mtNone) + { + DPRINT("No mouse connected to Fdo %p\n", + DeviceExtension->LowerDevice); + return STATUS_DEVICE_NOT_CONNECTED; + } + + switch (MouseType) + { + case mtMicrosoft: + DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE; + DeviceExtension->AttributesInformation.NumberOfButtons = 2; + break; + case mtLogitech: + DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE; + DeviceExtension->AttributesInformation.NumberOfButtons = 3; + break; + case mtWheelZ: + DeviceExtension->AttributesInformation.MouseIdentifier = WHEELMOUSE_SERIAL_HARDWARE; + DeviceExtension->AttributesInformation.NumberOfButtons = 3; + break; + default: + CHECKPOINT; + return STATUS_UNSUCCESSFUL; + } + + if (DeviceExtension->DriverExtension->NumberOfButtons != 0) + /* Override the number of buttons */ + DeviceExtension->AttributesInformation.NumberOfButtons = DeviceExtension->DriverExtension->NumberOfButtons; + + DeviceExtension->AttributesInformation.SampleRate = 1200 / 8; + DeviceExtension->AttributesInformation.InputDataQueueLength = DeviceExtension->DriverExtension->MouseDataQueueSize; + DeviceExtension->MouseType = MouseType; + DeviceExtension->PnpState = dsStarted; + + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +SermousePnp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + ULONG MinorFunction; + PIO_STACK_LOCATION Stack; + ULONG Information = 0; + NTSTATUS Status; + + Stack = IoGetCurrentIrpStackLocation(Irp); + MinorFunction = Stack->MinorFunction; + + switch (MinorFunction) + { + /* FIXME: do all these minor functions + IRP_MN_QUERY_REMOVE_DEVICE 0x1 + IRP_MN_REMOVE_DEVICE 0x2 + IRP_MN_CANCEL_REMOVE_DEVICE 0x3 + IRP_MN_STOP_DEVICE 0x4 + IRP_MN_QUERY_STOP_DEVICE 0x5 + IRP_MN_CANCEL_STOP_DEVICE 0x6 + IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) 0x7 + IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7 + IRP_MN_QUERY_INTERFACE (optional) 0x8 + IRP_MN_QUERY_CAPABILITIES (optional) 0x9 + IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional or required) 0xd + IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14 + IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16 + IRP_MN_SURPRISE_REMOVAL 0x17 + */ + case IRP_MN_START_DEVICE: /* 0x0 */ + { + DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); + /* Call lower driver */ + Status = ForwardIrpAndWait(DeviceObject, Irp); + if (NT_SUCCESS(Status)) + Status = SermouseStartDevice(DeviceObject, Irp); + break; + } + default: + { + DPRINT1("IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction); + return ForwardIrpAndForget(DeviceObject, Irp); + } + } + + Irp->IoStatus.Information = Information; + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} diff --git a/reactos/drivers/input/sermouse/internaldevctl.c b/reactos/drivers/input/sermouse/internaldevctl.c new file mode 100644 index 00000000000..90e1b8cd895 --- /dev/null +++ b/reactos/drivers/input/sermouse/internaldevctl.c @@ -0,0 +1,89 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Serial mouse driver + * FILE: drivers/input/sermouse/internaldevctl.c + * PURPOSE: IRP_MJ_INTERNAL_DEVICE_CONTROL operations + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#include "sermouse.h" + +NTSTATUS NTAPI +SermouseInternalDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PSERMOUSE_DEVICE_EXTENSION DeviceExtension; + PIO_STACK_LOCATION Stack; + NTSTATUS Status; + + DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + Stack = IoGetCurrentIrpStackLocation(Irp); + + switch (Stack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_INTERNAL_MOUSE_CONNECT: + { + DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n"); + DeviceExtension->ConnectData = + *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer); + + /* Start read loop */ + Status = PsCreateSystemThread( + &DeviceExtension->WorkerThreadHandle, + (ACCESS_MASK)0L, + NULL, + NULL, + NULL, + SermouseDeviceWorker, + DeviceObject); + break; + } + case IOCTL_INTERNAL_MOUSE_DISCONNECT: + { + DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n"); + + /* Ask read loop to end */ + KeSetEvent(&DeviceExtension->StopWorkerThreadEvent, (KPRIORITY)0, FALSE); + break; + } + case IOCTL_MOUSE_QUERY_ATTRIBUTES: + { + DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n"); + if (Stack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(MOUSE_ATTRIBUTES)) + { + *(PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer = + DeviceExtension->AttributesInformation; + Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES); + Status = STATUS_SUCCESS; + } else { + Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + default: + { + DPRINT1("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n", + Stack->Parameters.DeviceIoControl.IoControlCode); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + } + + Irp->IoStatus.Status = Status; + if (Status == STATUS_PENDING) + { + IoMarkIrpPending(Irp); + IoStartPacket(DeviceObject, Irp, NULL, NULL); + } + else + { + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return Status; +} diff --git a/reactos/drivers/input/sermouse/misc.c b/reactos/drivers/input/sermouse/misc.c new file mode 100644 index 00000000000..25e3ad09302 --- /dev/null +++ b/reactos/drivers/input/sermouse/misc.c @@ -0,0 +1,61 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Serial mouse driver + * FILE: drivers/input/sermouse/misc.c + * PURPOSE: Misceallenous operations + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#include "sermouse.h" + +static NTSTATUS NTAPI +ForwardIrpAndWaitCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + if (Irp->PendingReturned) + KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +ForwardIrpAndWait( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PDEVICE_OBJECT LowerDevice = ((PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice; + KEVENT Event; + NTSTATUS Status; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + IoCopyCurrentIrpStackLocationToNext(Irp); + + DPRINT("Calling lower device %p [%wZ]\n", LowerDevice, &LowerDevice->DriverObject->DriverName); + IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE); + + Status = IoCallDriver(LowerDevice, Irp); + if (Status == STATUS_PENDING) + { + Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + if (NT_SUCCESS(Status)) + Status = Irp->IoStatus.Status; + } + + return Status; +} + +NTSTATUS NTAPI +ForwardIrpAndForget( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PDEVICE_OBJECT LowerDevice = ((PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice; + + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(LowerDevice, Irp); +} diff --git a/reactos/drivers/input/sermouse/readmouse.c b/reactos/drivers/input/sermouse/readmouse.c new file mode 100644 index 00000000000..479095ebee4 --- /dev/null +++ b/reactos/drivers/input/sermouse/readmouse.c @@ -0,0 +1,277 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Serial mouse driver + * FILE: drivers/input/sermouse/readmouse.c + * PURPOSE: Read mouse moves and send them to mouclass + * + * PROGRAMMERS: Jason Filby (jasonfilby@yahoo.com) + * Filip Navara (xnavara@volny.cz) + * Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#include "sermouse.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) + { + DPRINT("IoBuildDeviceIoControlRequest() failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = IoCallDriver(DeviceObject, Irp); + + if (Status == STATUS_PENDING) + { + DPRINT("Operation pending\n"); + KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + + if (OutputBufferSize) + { + *OutputBufferSize = 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; + + DPRINT("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->DriverExtension->SampleRate; + 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 */ + while (TRUE) + { + Status = KeWaitForSingleObject( + &DeviceExtension->StopWorkerThreadEvent, + Executive, + KernelMode, + TRUE, + &Zero); + if (Status != STATUS_TIMEOUT) + { + /* we need to stop the worker thread */ + KeResetEvent(&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 */ + CHECKPOINT; + 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]; + DPRINT1("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] == DeviceExtension->DriverExtension->MouseDataQueueSize) + continue; + + Input = &DeviceExtension->MouseInputData[Queue][DeviceExtension->InputDataCount[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); +} diff --git a/reactos/drivers/input/sermouse/sermouse.c b/reactos/drivers/input/sermouse/sermouse.c new file mode 100644 index 00000000000..9b1effe2290 --- /dev/null +++ b/reactos/drivers/input/sermouse/sermouse.c @@ -0,0 +1,167 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Serial mouse driver + * FILE: drivers/input/sermouse/sermouse.c + * PURPOSE: Serial mouse driver entry point + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#define INITGUID +#include "sermouse.h" + +VOID NTAPI +DriverUnload(IN PDRIVER_OBJECT DriverObject) +{ + // nothing to do here yet +} + +NTSTATUS NTAPI +IrpStub( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + DPRINT1("Irp stub for major function 0x%lx\n", + IoGetCurrentIrpStackLocation(Irp)->MajorFunction); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_SUPPORTED; +} + +static NTSTATUS +ReadRegistryEntries( + IN PUNICODE_STRING RegistryPath, + IN PSERMOUSE_DRIVER_EXTENSION DriverExtension) +{ + UNICODE_STRING ParametersRegistryKey; + RTL_QUERY_REGISTRY_TABLE Parameters[5]; + NTSTATUS Status; + + ULONG DefaultMouseDataQueueSize = 0x64; + ULONG DefaultNumberOfButtons = 0; + UNICODE_STRING DefaultPointerDeviceBaseName = RTL_CONSTANT_STRING(L"PointerPort"); + ULONG DefaultSampleRate = SERIAL_BAUD_1200; + + ParametersRegistryKey.Length = 0; + ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL); + ParametersRegistryKey.Buffer = ExAllocatePool(PagedPool, ParametersRegistryKey.MaximumLength); + if (!ParametersRegistryKey.Buffer) + { + DPRINT("ExAllocatePool() failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath); + RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters"); + ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL; + + RtlZeroMemory(Parameters, sizeof(Parameters)); + + Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL; + Parameters[0].Name = L"MouseDataQueueSize"; + Parameters[0].EntryContext = &DriverExtension->MouseDataQueueSize; + Parameters[0].DefaultType = REG_DWORD; + Parameters[0].DefaultData = &DefaultMouseDataQueueSize; + Parameters[0].DefaultLength = sizeof(ULONG); + + Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL; + Parameters[1].Name = L"NumberOfButtons"; + Parameters[1].EntryContext = &DriverExtension->NumberOfButtons; + Parameters[1].DefaultType = REG_DWORD; + Parameters[1].DefaultData = &DefaultNumberOfButtons; + Parameters[1].DefaultLength = sizeof(ULONG); + + Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL; + Parameters[2].Name = L"PointerDeviceBaseName"; + Parameters[2].EntryContext = &DriverExtension->PointerDeviceBaseName; + Parameters[2].DefaultType = REG_SZ; + Parameters[2].DefaultData = &DefaultPointerDeviceBaseName; + Parameters[2].DefaultLength = 0; + + Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL; + Parameters[3].Name = L"SampleRate"; + Parameters[3].EntryContext = &DriverExtension->SampleRate; + Parameters[3].DefaultType = REG_DWORD; + Parameters[3].DefaultData = &DefaultSampleRate; + Parameters[3].DefaultLength = sizeof(ULONG); + + Status = RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE, + ParametersRegistryKey.Buffer, + Parameters, + NULL, + NULL); + + if (NT_SUCCESS(Status)) + { + /* Check values */ + if (DriverExtension->MouseDataQueueSize == 0) + { + DriverExtension->MouseDataQueueSize = DefaultMouseDataQueueSize; + } + } + else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) + { + /* Registry path doesn't exist. Set defaults */ + DriverExtension->MouseDataQueueSize = DefaultMouseDataQueueSize; + DriverExtension->NumberOfButtons = DefaultNumberOfButtons; + Status = RtlDuplicateUnicodeString( + RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, + &DefaultPointerDeviceBaseName, + &DriverExtension->PointerDeviceBaseName); + DriverExtension->SampleRate = DefaultSampleRate; + } + + return Status; +} + +/* + * Standard DriverEntry method. + */ +NTSTATUS NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + PSERMOUSE_DRIVER_EXTENSION DriverExtension; + ULONG i; + NTSTATUS Status; + + Status = IoAllocateDriverObjectExtension( + DriverObject, + DriverObject, + sizeof(SERMOUSE_DRIVER_EXTENSION), + (PVOID*)&DriverExtension); + if (!NT_SUCCESS(Status)) + { + DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status); + return Status; + } + RtlZeroMemory(DriverExtension, sizeof(SERMOUSE_DRIVER_EXTENSION)); + + Status = ReadRegistryEntries(RegistryPath, DriverExtension); + if (!NT_SUCCESS(Status)) + { + DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status); + return Status; + } + + DriverObject->DriverUnload = DriverUnload; + DriverObject->DriverExtension->AddDevice = SermouseAddDevice; + + for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) + DriverObject->MajorFunction[i] = IrpStub; + + DriverObject->MajorFunction[IRP_MJ_CREATE] = SermouseCreate; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = SermouseClose; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SermouseCleanup; + //DriverObject->MajorFunction[IRP_MJ_READ] = SermouseRead; + //DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SermouseDeviceControl; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SermouseInternalDeviceControl; + //DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = SermouseQueryInformation; + DriverObject->MajorFunction[IRP_MJ_PNP] = SermousePnp; + //DriverObject->MajorFunction[IRP_MJ_POWER] = SermousePower; + + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/input/sermouse/sermouse.h b/reactos/drivers/input/sermouse/sermouse.h new file mode 100644 index 00000000000..f4ca0b57995 --- /dev/null +++ b/reactos/drivers/input/sermouse/sermouse.h @@ -0,0 +1,151 @@ +#include +#include +#include +#include + +#if defined(__GNUC__) + #include + + /* FIXME: these prototypes MUST NOT be here! */ + NTSTATUS NTAPI + IoAttachDeviceToDeviceStackSafe( + IN PDEVICE_OBJECT SourceDevice, + IN PDEVICE_OBJECT TargetDevice, + OUT PDEVICE_OBJECT *AttachedToDeviceObject); +#elif defined(_MSC_VER) + NTSTATUS NTAPI + IoAttachDeviceToDeviceStackSafe( + IN PDEVICE_OBJECT SourceDevice, + IN PDEVICE_OBJECT TargetDevice, + OUT PDEVICE_OBJECT *AttachedToDeviceObject); +#else + #error Unknown compiler! +#endif + +typedef enum +{ + dsStopped, + dsStarted, + dsPaused, + dsRemoved, + dsSurpriseRemoved +} SERMOUSE_DEVICE_STATE; + +typedef enum +{ + mtNone, /* No Mouse */ + mtMicrosoft, /* Microsoft Mouse with 2 buttons */ + mtLogitech, /* Logitech Mouse with 3 buttons */ + mtWheelZ /* Microsoft Wheel Mouse (aka Z Mouse) */ +} SERMOUSE_MOUSE_TYPE; + +/* Size for packet buffer used in interrupt routine */ +#define PACKET_BUFFER_SIZE 4 + +/* Hardware byte mask for left button */ +#define LEFT_BUTTON_MASK 0x20 +/* Hardware to Microsoft specific code byte shift for left button */ +#define LEFT_BUTTON_SHIFT 5 +/* Hardware byte mask for right button */ +#define RIGHT_BUTTON_MASK 0x10 +/* Hardware to Microsoft specific code byte shift for right button */ +#define RIGHT_BUTTON_SHIFT 3 +/* Hardware byte mask for middle button */ +#define MIDDLE_BUTTON_MASK 0x20 +/* Hardware to Microsoft specific code byte shift for middle button */ +#define MIDDLE_BUTTON_SHIFT 3 + +/* Microsoft byte mask for left button */ +#define MOUSE_BUTTON_LEFT 0x01 +/* Microsoft byte mask for right button */ +#define MOUSE_BUTTON_RIGHT 0x02 +/* Microsoft byte mask for middle button */ +#define MOUSE_BUTTON_MIDDLE 0x04 + +typedef struct _SERMOUSE_DRIVER_EXTENSION +{ + ULONG MouseDataQueueSize; + ULONG NumberOfButtons; + UNICODE_STRING PointerDeviceBaseName; + ULONG SampleRate; +} SERMOUSE_DRIVER_EXTENSION, *PSERMOUSE_DRIVER_EXTENSION; + +typedef struct _SERMOUSE_DEVICE_EXTENSION +{ + PDEVICE_OBJECT LowerDevice; + SERMOUSE_DEVICE_STATE PnpState; + SERMOUSE_MOUSE_TYPE MouseType; + PSERMOUSE_DRIVER_EXTENSION DriverExtension; + + HANDLE WorkerThreadHandle; + KEVENT StopWorkerThreadEvent; + + ULONG ActiveQueue; + ULONG InputDataCount[2]; + CONNECT_DATA ConnectData; + MOUSE_INPUT_DATA* MouseInputData[2]; + UCHAR PacketBuffer[PACKET_BUFFER_SIZE]; + ULONG PacketBufferPosition; + ULONG PreviousButtons; + MOUSE_ATTRIBUTES AttributesInformation; +} SERMOUSE_DEVICE_EXTENSION, *PSERMOUSE_DEVICE_EXTENSION; + +/************************************ createclose.c */ + +NTSTATUS NTAPI +SermouseCreate( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS NTAPI +SermouseClose( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS NTAPI +SermouseCleanup( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +/************************************ detect.c */ + +SERMOUSE_MOUSE_TYPE +SermouseDetectLegacyDevice( + IN PDEVICE_OBJECT LowerDevice); + +/************************************ fdo.c */ + +NTSTATUS NTAPI +SermouseAddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT Pdo); + +NTSTATUS NTAPI +SermousePnp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +/************************************ internaldevctl.c */ + +NTSTATUS NTAPI +SermouseInternalDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +/************************************ misc.c */ + +NTSTATUS +ForwardIrpAndWait( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS NTAPI +ForwardIrpAndForget( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +/************************************ readmouse.c */ + +VOID NTAPI +SermouseDeviceWorker( + PVOID Context); diff --git a/reactos/drivers/input/sermouse/sermouse.rc b/reactos/drivers/input/sermouse/sermouse.rc new file mode 100644 index 00000000000..81ab2cd4825 --- /dev/null +++ b/reactos/drivers/input/sermouse/sermouse.rc @@ -0,0 +1,7 @@ +/* $Id$ */ + +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "Serial mouse device driver\0" +#define REACTOS_STR_INTERNAL_NAME "sermouse\0" +#define REACTOS_STR_ORIGINAL_FILENAME "sermouse.sys\0" +#include diff --git a/reactos/drivers/input/sermouse/sermouse.txt b/reactos/drivers/input/sermouse/sermouse.txt new file mode 100644 index 00000000000..1de8de7f8fd --- /dev/null +++ b/reactos/drivers/input/sermouse/sermouse.txt @@ -0,0 +1,82 @@ + Following information obtained from Tomi Engdahl (then@delta.hut.fi), + http://www.hut.fi/~then/mytexts/mouse.html + + Microsoft serial mouse + + Serial data parameters: + 1200bps, 7 databits, 1 stop-bit + + Data packet format: + Data packet is 3 byte packet. It is send to the computer every time mouse + state changes (mouse moves or keys are pressed/released). + D7 D6 D5 D4 D3 D2 D1 D0 + 1. X 1 LB RB Y7 Y6 X7 X6 + 2. X 0 X5 X4 X3 X2 X1 X0 + 3. X 0 Y5 Y4 Y3 Y2 Y1 Y0 + + Note: The bit marked with X is 0 if the mouse received with 7 databits + and 2 stop bits format. It is also possible to use 8 databits and 1 stop + bit format for receiving. In this case X gets value 1. The safest thing + to get everything working is to use 7 databits and 1 stopbit when + receiving mouse information (and if you are making mouse then send out + 7 databits and 2 stop bits). + The byte marked with 1. is send first, then the others. The bit D6 in + the first byte is used for syncronizing the software to mouse packets + if it goes out of sync. + + LB is the state of the left button (1 means pressed down) + RB is the state of the right button (1 means pressed down) + X7-X0 movement in X direction since last packet (signed byte) + Y7-Y0 movement in Y direction since last packet (signed byte) + + Mouse identification + When DTR line is toggled, mouse should send one data byte containing + letter 'M' (ascii 77). + + + Logitech serial mouse + + Logitech uses the Microsoft serial mouse protocol in their mouses (for + example Logitech Pilot mouse and others). The origianal protocol supports + only two buttons, but logitech as added third button to some of their + mouse models. To make this possible logitech has made one extension to + the protocol. + I have not seen any documentation about the exact documents, but here is + what I have found out: The information of the third button state is sent + using one extra byte which is send after the normal packet when needed. + Value 32 (dec) is sent every time when the center button is pressed down. + It is also sent every time with the data packet when center button is kept + down and the mouse data packet is sent for other reasons. When center + button is released, the mouse sends the normal data packet followed by + data bythe which has value 0 (dec). As you can see the extra data byte + is sent only when you mess with the center button. + + + Mouse systems mouse + + Serial data parameters: + 1200bps, 8 databits, 1 stop-bit + + Data packet format: + D7 D6 D5 D4 D3 D2 D1 D0 + 1. 1 0 0 0 0 LB CB RB + 2. X7 X6 X5 X4 X3 X2 X1 X0 + 3. Y7 Y6 Y5 Y4 Y3 Y4 Y1 Y0 + 4. X7' X6' X5' X4' X3' X2' X1' X0' + 5. Y7' Y6' Y5' Y4' Y3' Y4' Y1' Y0' + + LB is left button state (0 = pressed, 1 = released) + CB is center button state (0 = pressed, 1 = released) + RB is right button state (0 = pressed, 1 = released) + X7-X0 movement in X direction since last packet in signed byte + format (-128..+127), positive direction right + Y7-Y0 movement in Y direction since last packet in signed byte + format (-128..+127), positive direction up + X7'-X0' movement in X direction since sending of X7-X0 packet in + signed byte format (-128..+127), positive direction right + Y7'-Y0' movement in Y direction since sending of Y7-Y0 packet in + signed byte format (-128..+127), positive direction up + + The last two bytes in the packet (bytes 4 and 5) contains information + about movement data changes which have occured after data bytes 2 and 3 + have been sent. diff --git a/reactos/drivers/input/sermouse/sermouse.xml b/reactos/drivers/input/sermouse/sermouse.xml new file mode 100644 index 00000000000..6551d4af28a --- /dev/null +++ b/reactos/drivers/input/sermouse/sermouse.xml @@ -0,0 +1,14 @@ + + . + + ntoskrnl + hal + createclose.c + detect.c + fdo.c + internaldevctl.c + misc.c + readmouse.c + sermouse.c + sermouse.rc +