--- /dev/null
+/*
+ * 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 <debug.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <debug.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <debug.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <debug.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <debug.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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 <debug.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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 <debug.h>
+
+#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;
+}
--- /dev/null
+#include <ntifs.h>
+#include <kbdmou.h>
+#include <ntddser.h>
+#include <ntddmou.h>
+
+#if defined(__GNUC__)
+ #include <stdio.h>
+
+ /* 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);
--- /dev/null
+/* $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 <reactos/version.rc>
--- /dev/null
+ 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.
--- /dev/null
+<module name="sermouse" type="kernelmodedriver" installbase="system32/drivers" installname="sermouse.sys">
+ <include base="sermouse">.</include>
+ <define name="__USE_W32API" />
+ <library>ntoskrnl</library>
+ <library>hal</library>
+ <file>createclose.c</file>
+ <file>detect.c</file>
+ <file>fdo.c</file>
+ <file>internaldevctl.c</file>
+ <file>misc.c</file>
+ <file>readmouse.c</file>
+ <file>sermouse.c</file>
+ <file>sermouse.rc</file>
+</module>