3 ** Mouse class driver 0.0.1
4 ** Written by Jason Filby (jasonfilby@yahoo.com)
5 ** For ReactOS (www.reactos.com)
7 ** The class driver between win32k and the various mouse port drivers
9 ** TODO: Change interface to win32k to a callback instead of ReadFile IO
10 Add support for multiple port devices
14 #include <ddk/ntddk.h>
15 #include "../include/mouse.h"
18 BOOLEAN AlreadyOpened = FALSE;
20 BOOLEAN MouseClassCallBack(PDEVICE_OBJECT ClassDeviceObject, PMOUSE_INPUT_DATA MouseDataStart,
21 PMOUSE_INPUT_DATA MouseDataEnd, PULONG InputCount)
23 PDEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
26 PIO_STACK_LOCATION Stack;
28 // In classical NT, you would take the input data and pipe it through the IO system, for the GDI to read.
29 // In ReactOS, however, we use a GDI callback for increased mouse responsiveness. The reason we don't
30 // simply call from the port driver is so that our mouse class driver can support NT mouse port drivers.
32 /* if(ClassDeviceExtension->ReadIsPending == TRUE)
34 Irp = ClassDeviceObject->CurrentIrp;
35 ClassDeviceObject->CurrentIrp = NULL;
36 Stack = IoGetCurrentIrpStackLocation(Irp);
38 ReadSize = sizeof(MOUSE_INPUT_DATA) * (*InputCount);
40 // A read request is waiting for input, so go straight to it
41 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)MouseDataStart, ReadSize);
43 // Go to next packet and complete this request with STATUS_SUCCESS
44 Irp->IoStatus.Status = STATUS_SUCCESS;
45 Irp->IoStatus.Information = ReadSize;
46 Stack->Parameters.Read.Length = ReadSize;
48 IoStartNextPacket(ClassDeviceObject, FALSE);
49 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
50 ClassDeviceExtension->ReadIsPending = FALSE;
53 // If we have data from the port driver and a higher service to send the data to
54 if((*InputCount>0) && (*(PGDI_SERVICE_CALLBACK_ROUTINE)ClassDeviceExtension->GDIInformation.CallBack != NULL))
56 if(ClassDeviceExtension->InputCount + *InputCount > MOUSE_BUFFER_SIZE)
58 ReadSize = MOUSE_BUFFER_SIZE - ClassDeviceExtension->InputCount;
60 ReadSize = *InputCount;
63 // FIXME: If we exceed the buffer, mouse data gets thrown away.. better solution?
66 // Move the mouse input data from the port data queue to our class data queue
67 RtlMoveMemory(ClassDeviceExtension->PortData, (PCHAR)MouseDataStart,
68 sizeof(MOUSE_INPUT_DATA) * ReadSize);
70 // Move the pointer and counter up
71 ClassDeviceExtension->PortData += ReadSize;
72 ClassDeviceExtension->InputCount += ReadSize;
74 // Throw data up to GDI callback
75 if(*(PGDI_SERVICE_CALLBACK_ROUTINE)ClassDeviceExtension->GDIInformation.CallBack != NULL) {
76 (*(PGDI_SERVICE_CALLBACK_ROUTINE)ClassDeviceExtension->GDIInformation.CallBack)
77 (ClassDeviceExtension->PortData - ReadSize, ReadSize);
80 ClassDeviceExtension->PortData -= ReadSize;
81 ClassDeviceExtension->InputCount -= ReadSize;
82 ClassDeviceExtension->ReadIsPending = FALSE;
88 NTSTATUS ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject)
90 PDEVICE_OBJECT PortDeviceObject = NULL;
91 PFILE_OBJECT FileObject = NULL;
93 UNICODE_STRING PortName = UNICODE_STRING_INITIALIZER(L"\\Device\\Mouse");
94 IO_STATUS_BLOCK ioStatus;
97 CLASS_INFORMATION ClassInformation;
98 PDEVICE_EXTENSION DeviceExtension = ClassDeviceObject->DeviceExtension;
100 DeviceExtension->GDIInformation.CallBack = NULL;
102 // Get the port driver's DeviceObject
103 // FIXME: The name might change.. find a way to be more dynamic?
105 status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
107 if(status != STATUS_SUCCESS)
109 DbgPrint("MOUCLASS: Could not connect to mouse port driver\n");
113 DeviceExtension->PortDeviceObject = PortDeviceObject;
114 DeviceExtension->PortData = ExAllocatePool(NonPagedPool, MOUSE_BUFFER_SIZE * sizeof(MOUSE_INPUT_DATA));
115 DeviceExtension->InputCount = 0;
116 DeviceExtension->ReadIsPending = FALSE;
118 // Connect our callback to the port driver
120 KeInitializeEvent(&event, NotificationEvent, FALSE);
122 ClassInformation.DeviceObject = ClassDeviceObject;
123 ClassInformation.CallBack = MouseClassCallBack;
125 irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
126 PortDeviceObject, &ClassInformation, sizeof(CLASS_INFORMATION), NULL, 0, TRUE, &event, &ioStatus);
128 status = IoCallDriver(DeviceExtension->PortDeviceObject, irp);
130 if (status == STATUS_PENDING) {
131 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
133 ioStatus.Status = status;
136 return ioStatus.Status;
139 NTSTATUS STDCALL MouseClassDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
141 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
144 switch (Stack->MajorFunction)
147 if (AlreadyOpened == TRUE)
149 Status = STATUS_SUCCESS;
153 Status = STATUS_SUCCESS;
154 AlreadyOpened = TRUE;
159 Status = STATUS_SUCCESS;
164 if (Stack->Parameters.Read.Length == 0) {
165 Status = STATUS_SUCCESS;
167 Status = STATUS_PENDING;
172 DbgPrint("NOT IMPLEMENTED\n");
173 Status = STATUS_NOT_IMPLEMENTED;
177 Irp->IoStatus.Status = Status;
178 Irp->IoStatus.Information = 0;
179 if (Status==STATUS_PENDING)
181 IoMarkIrpPending(Irp);
182 IoStartPacket(DeviceObject, Irp, NULL, NULL);
184 IoCompleteRequest(Irp, IO_NO_INCREMENT);
189 VOID MouseClassStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
191 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
192 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
195 if(DeviceExtension->InputCount>0)
197 // FIXME: We should not send too much input data.. depends on the max buffer size of the win32k
198 ReadSize = DeviceExtension->InputCount * sizeof(MOUSE_INPUT_DATA);
200 // Bring the PortData back to base so that it can be copied
201 DeviceExtension->PortData -= DeviceExtension->InputCount;
202 DeviceExtension->InputCount = 0;
203 DeviceExtension->ReadIsPending = FALSE;
205 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)DeviceExtension->PortData, ReadSize);
207 // Go to next packet and complete this request with STATUS_SUCCESS
208 Irp->IoStatus.Status = STATUS_SUCCESS;
210 Irp->IoStatus.Information = ReadSize;
211 Stack->Parameters.Read.Length = ReadSize;
213 IoStartNextPacket(DeviceObject, FALSE);
214 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
216 DeviceExtension->ReadIsPending = TRUE;
220 NTSTATUS STDCALL MouseClassInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
222 // Retrieve GDI's callback
224 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
225 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
228 switch(Stack->Parameters.DeviceIoControl.IoControlCode)
230 case IOCTL_INTERNAL_MOUSE_CONNECT:
232 DeviceExtension->GDIInformation =
233 *((PGDI_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
235 status = STATUS_SUCCESS;
238 case IOCTL_INTERNAL_MOUSE_DISCONNECT:
240 DeviceExtension->GDIInformation.CallBack = NULL;
242 status = STATUS_SUCCESS;
246 status = STATUS_INVALID_DEVICE_REQUEST;
250 Irp->IoStatus.Status = status;
251 if (status == STATUS_PENDING) {
252 IoMarkIrpPending(Irp);
253 IoStartPacket(DeviceObject, Irp, NULL, NULL);
255 IoCompleteRequest(Irp, IO_NO_INCREMENT);
262 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
264 PDEVICE_OBJECT DeviceObject;
265 UNICODE_STRING DeviceName = UNICODE_STRING_INITIALIZER(L"\\Device\\MouseClass");
266 UNICODE_STRING SymlinkName = UNICODE_STRING_INITIALIZER(L"\\??\\MouseClass");
268 DriverObject->MajorFunction[IRP_MJ_CREATE] = MouseClassDispatch;
269 // DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouseClassDispatch;
270 // DriverObject->MajorFunction[IRP_MJ_READ] = MouseClassDispatch;
271 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouseClassInternalDeviceControl; // to get GDI callback
272 // DriverObject->DriverStartIo = MouseClassStartIo;
274 IoCreateDevice(DriverObject,
275 sizeof(DEVICE_EXTENSION),
281 DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
283 IoCreateSymbolicLink(&SymlinkName, &DeviceName);
285 return ConnectMousePortDriver(DeviceObject);