display some extra debug messages on boot to see whats going on.
[reactos.git] / reactos / drivers / input / mouclass / mouclass.c
1 /*
2
3 ** Mouse class driver 0.0.1
4 ** Written by Jason Filby (jasonfilby@yahoo.com)
5 ** For ReactOS (www.reactos.com)
6
7 ** The class driver between win32k and the various mouse port drivers
8
9 ** TODO: Change interface to win32k to a callback instead of ReadFile IO
10 Add support for multiple port devices
11
12 */
13
14 #include <ddk/ntddk.h>
15 #include "../include/mouse.h"
16 #include "mouclass.h"
17
18 BOOLEAN AlreadyOpened = FALSE;
19
20 BOOLEAN MouseClassCallBack(PDEVICE_OBJECT ClassDeviceObject, PMOUSE_INPUT_DATA MouseDataStart,
21 PMOUSE_INPUT_DATA MouseDataEnd, PULONG InputCount)
22 {
23 PDEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
24 PIRP Irp;
25 ULONG ReadSize;
26 PIO_STACK_LOCATION Stack;
27
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.
31
32 /* if(ClassDeviceExtension->ReadIsPending == TRUE)
33 {
34 Irp = ClassDeviceObject->CurrentIrp;
35 ClassDeviceObject->CurrentIrp = NULL;
36 Stack = IoGetCurrentIrpStackLocation(Irp);
37
38 ReadSize = sizeof(MOUSE_INPUT_DATA) * (*InputCount);
39
40 // A read request is waiting for input, so go straight to it
41 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)MouseDataStart, ReadSize);
42
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;
47
48 IoStartNextPacket(ClassDeviceObject, FALSE);
49 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
50 ClassDeviceExtension->ReadIsPending = FALSE;
51 } */
52
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))
55 {
56 if(ClassDeviceExtension->InputCount + *InputCount > MOUSE_BUFFER_SIZE)
57 {
58 ReadSize = MOUSE_BUFFER_SIZE - ClassDeviceExtension->InputCount;
59 } else {
60 ReadSize = *InputCount;
61 }
62
63 // FIXME: If we exceed the buffer, mouse data gets thrown away.. better solution?
64
65
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);
69
70 // Move the pointer and counter up
71 ClassDeviceExtension->PortData += ReadSize;
72 ClassDeviceExtension->InputCount += ReadSize;
73
74 // Throw data up to GDI callback
75 if(*(PGDI_SERVICE_CALLBACK_ROUTINE)ClassDeviceExtension->GDIInformation.CallBack != NULL) {
76 DbgPrint("MouseClassCallBack() Calling GDI callback at %p\n", ClassDeviceExtension->GDIInformation.CallBack);
77 (*(PGDI_SERVICE_CALLBACK_ROUTINE)ClassDeviceExtension->GDIInformation.CallBack)
78 (ClassDeviceExtension->PortData - ReadSize, ReadSize);
79 } else {
80 DbgPrint("MouseClassCallBack() NO GDI callback installed\n");
81 }
82
83 ClassDeviceExtension->PortData -= ReadSize;
84 ClassDeviceExtension->InputCount -= ReadSize;
85 ClassDeviceExtension->ReadIsPending = FALSE;
86 } else {
87 DbgPrint("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount);
88 }
89
90 return TRUE;
91 }
92
93 NTSTATUS ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject)
94 {
95 PDEVICE_OBJECT PortDeviceObject = NULL;
96 PFILE_OBJECT FileObject = NULL;
97 NTSTATUS status;
98 UNICODE_STRING PortName = UNICODE_STRING_INITIALIZER(L"\\Device\\Mouse");
99 IO_STATUS_BLOCK ioStatus;
100 KEVENT event;
101 PIRP irp;
102 CLASS_INFORMATION ClassInformation;
103 PDEVICE_EXTENSION DeviceExtension = ClassDeviceObject->DeviceExtension;
104
105 DeviceExtension->GDIInformation.CallBack = NULL;
106
107 // Get the port driver's DeviceObject
108 // FIXME: The name might change.. find a way to be more dynamic?
109
110 status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
111
112 if(status != STATUS_SUCCESS)
113 {
114 DbgPrint("MOUCLASS: Could not connect to mouse port driver\n");
115 return status;
116 }
117
118 DeviceExtension->PortDeviceObject = PortDeviceObject;
119 DeviceExtension->PortData = ExAllocatePool(NonPagedPool, MOUSE_BUFFER_SIZE * sizeof(MOUSE_INPUT_DATA));
120 DeviceExtension->InputCount = 0;
121 DeviceExtension->ReadIsPending = FALSE;
122
123 // Connect our callback to the port driver
124
125 KeInitializeEvent(&event, NotificationEvent, FALSE);
126
127 ClassInformation.DeviceObject = ClassDeviceObject;
128 ClassInformation.CallBack = MouseClassCallBack;
129
130 irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
131 PortDeviceObject, &ClassInformation, sizeof(CLASS_INFORMATION), NULL, 0, TRUE, &event, &ioStatus);
132
133 status = IoCallDriver(DeviceExtension->PortDeviceObject, irp);
134
135 if (status == STATUS_PENDING) {
136 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
137 } else {
138 ioStatus.Status = status;
139 }
140
141 return ioStatus.Status;
142 }
143
144 NTSTATUS STDCALL MouseClassDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
145 {
146 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
147 NTSTATUS Status;
148
149 switch (Stack->MajorFunction)
150 {
151 case IRP_MJ_CREATE:
152 if (AlreadyOpened == TRUE)
153 {
154 Status = STATUS_SUCCESS;
155 }
156 else
157 {
158 Status = STATUS_SUCCESS;
159 AlreadyOpened = TRUE;
160 }
161 break;
162
163 case IRP_MJ_CLOSE:
164 Status = STATUS_SUCCESS;
165 break;
166
167 case IRP_MJ_READ:
168
169 if (Stack->Parameters.Read.Length == 0) {
170 Status = STATUS_SUCCESS;
171 } else {
172 Status = STATUS_PENDING;
173 }
174 break;
175
176 default:
177 DbgPrint("NOT IMPLEMENTED\n");
178 Status = STATUS_NOT_IMPLEMENTED;
179 break;
180 }
181
182 Irp->IoStatus.Status = Status;
183 Irp->IoStatus.Information = 0;
184 if (Status==STATUS_PENDING)
185 {
186 IoMarkIrpPending(Irp);
187 IoStartPacket(DeviceObject, Irp, NULL, NULL);
188 } else {
189 IoCompleteRequest(Irp, IO_NO_INCREMENT);
190 }
191 return(Status);
192 }
193
194 VOID MouseClassStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
195 {
196 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
197 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
198 ULONG ReadSize;
199
200 if(DeviceExtension->InputCount>0)
201 {
202 // FIXME: We should not send too much input data.. depends on the max buffer size of the win32k
203 ReadSize = DeviceExtension->InputCount * sizeof(MOUSE_INPUT_DATA);
204
205 // Bring the PortData back to base so that it can be copied
206 DeviceExtension->PortData -= DeviceExtension->InputCount;
207 DeviceExtension->InputCount = 0;
208 DeviceExtension->ReadIsPending = FALSE;
209
210 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)DeviceExtension->PortData, ReadSize);
211
212 // Go to next packet and complete this request with STATUS_SUCCESS
213 Irp->IoStatus.Status = STATUS_SUCCESS;
214
215 Irp->IoStatus.Information = ReadSize;
216 Stack->Parameters.Read.Length = ReadSize;
217
218 IoStartNextPacket(DeviceObject, FALSE);
219 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
220 } else {
221 DeviceExtension->ReadIsPending = TRUE;
222 }
223 }
224
225 NTSTATUS STDCALL MouseClassInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
226 {
227 // Retrieve GDI's callback
228
229 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
230 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
231 NTSTATUS status;
232
233 switch(Stack->Parameters.DeviceIoControl.IoControlCode)
234 {
235 case IOCTL_INTERNAL_MOUSE_CONNECT:
236
237 DeviceExtension->GDIInformation =
238 *((PGDI_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
239
240 DbgPrint("MouseClassInternalDeviceControl() installed GDI callback at %p\n", DeviceExtension->GDIInformation.CallBack);
241
242 status = STATUS_SUCCESS;
243 break;
244
245 case IOCTL_INTERNAL_MOUSE_DISCONNECT:
246
247 DeviceExtension->GDIInformation.CallBack = NULL;
248
249 status = STATUS_SUCCESS;
250 break;
251
252 default:
253 status = STATUS_INVALID_DEVICE_REQUEST;
254 break;
255 }
256
257 Irp->IoStatus.Status = status;
258 if (status == STATUS_PENDING) {
259 IoMarkIrpPending(Irp);
260 IoStartPacket(DeviceObject, Irp, NULL, NULL);
261 } else {
262 IoCompleteRequest(Irp, IO_NO_INCREMENT);
263 }
264
265 return status;
266 }
267
268 NTSTATUS STDCALL
269 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
270 {
271 PDEVICE_OBJECT DeviceObject;
272 UNICODE_STRING DeviceName = UNICODE_STRING_INITIALIZER(L"\\Device\\MouseClass");
273 UNICODE_STRING SymlinkName = UNICODE_STRING_INITIALIZER(L"\\??\\MouseClass");
274
275 DriverObject->MajorFunction[IRP_MJ_CREATE] = MouseClassDispatch;
276 // DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouseClassDispatch;
277 // DriverObject->MajorFunction[IRP_MJ_READ] = MouseClassDispatch;
278 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouseClassInternalDeviceControl; // to get GDI callback
279 // DriverObject->DriverStartIo = MouseClassStartIo;
280
281 IoCreateDevice(DriverObject,
282 sizeof(DEVICE_EXTENSION),
283 &DeviceName,
284 FILE_DEVICE_MOUSE,
285 0,
286 TRUE,
287 &DeviceObject);
288 DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
289
290 IoCreateSymbolicLink(&SymlinkName, &DeviceName);
291
292 return ConnectMousePortDriver(DeviceObject);
293 }