New serial mouse driver, which is PnP compliant
authorHervé Poussineau <hpoussin@reactos.org>
Wed, 9 Nov 2005 11:57:58 +0000 (11:57 +0000)
committerHervé Poussineau <hpoussin@reactos.org>
Wed, 9 Nov 2005 11:57:58 +0000 (11:57 +0000)
svn path=/trunk/; revision=19100

reactos/drivers/input/sermouse/createclose.c [new file with mode: 0644]
reactos/drivers/input/sermouse/detect.c [new file with mode: 0644]
reactos/drivers/input/sermouse/fdo.c [new file with mode: 0644]
reactos/drivers/input/sermouse/internaldevctl.c [new file with mode: 0644]
reactos/drivers/input/sermouse/misc.c [new file with mode: 0644]
reactos/drivers/input/sermouse/readmouse.c [new file with mode: 0644]
reactos/drivers/input/sermouse/sermouse.c [new file with mode: 0644]
reactos/drivers/input/sermouse/sermouse.h [new file with mode: 0644]
reactos/drivers/input/sermouse/sermouse.rc [new file with mode: 0644]
reactos/drivers/input/sermouse/sermouse.txt [new file with mode: 0644]
reactos/drivers/input/sermouse/sermouse.xml [new file with mode: 0644]

diff --git a/reactos/drivers/input/sermouse/createclose.c b/reactos/drivers/input/sermouse/createclose.c
new file mode 100644 (file)
index 0000000..6f24ec8
--- /dev/null
@@ -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 <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;
+}
diff --git a/reactos/drivers/input/sermouse/detect.c b/reactos/drivers/input/sermouse/detect.c
new file mode 100644 (file)
index 0000000..dfa1ae7
--- /dev/null
@@ -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 <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;
+}
diff --git a/reactos/drivers/input/sermouse/fdo.c b/reactos/drivers/input/sermouse/fdo.c
new file mode 100644 (file)
index 0000000..a20fa5a
--- /dev/null
@@ -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 <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;
+}
diff --git a/reactos/drivers/input/sermouse/internaldevctl.c b/reactos/drivers/input/sermouse/internaldevctl.c
new file mode 100644 (file)
index 0000000..90e1b8c
--- /dev/null
@@ -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 <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;
+}
diff --git a/reactos/drivers/input/sermouse/misc.c b/reactos/drivers/input/sermouse/misc.c
new file mode 100644 (file)
index 0000000..25e3ad0
--- /dev/null
@@ -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 <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);
+}
diff --git a/reactos/drivers/input/sermouse/readmouse.c b/reactos/drivers/input/sermouse/readmouse.c
new file mode 100644 (file)
index 0000000..479095e
--- /dev/null
@@ -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 <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);
+}
diff --git a/reactos/drivers/input/sermouse/sermouse.c b/reactos/drivers/input/sermouse/sermouse.c
new file mode 100644 (file)
index 0000000..9b1effe
--- /dev/null
@@ -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 <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;
+}
diff --git a/reactos/drivers/input/sermouse/sermouse.h b/reactos/drivers/input/sermouse/sermouse.h
new file mode 100644 (file)
index 0000000..f4ca0b5
--- /dev/null
@@ -0,0 +1,151 @@
+#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);
diff --git a/reactos/drivers/input/sermouse/sermouse.rc b/reactos/drivers/input/sermouse/sermouse.rc
new file mode 100644 (file)
index 0000000..81ab2cd
--- /dev/null
@@ -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 <reactos/version.rc>
diff --git a/reactos/drivers/input/sermouse/sermouse.txt b/reactos/drivers/input/sermouse/sermouse.txt
new file mode 100644 (file)
index 0000000..1de8de7
--- /dev/null
@@ -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 (file)
index 0000000..6551d4a
--- /dev/null
@@ -0,0 +1,14 @@
+<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>