- Don't use buffered I/O, to prevent some lag
[reactos.git] / reactos / drivers / input / mouclass / mouclass.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Mouse class driver
4 * FILE: drivers/mouclass/mouclass.c
5 * PURPOSE: Mouse class driver
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define INITGUID
14 #include "mouclass.h"
15
16 static NTSTATUS
17 SearchForLegacyDrivers(
18 IN PDRIVER_OBJECT DriverObject,
19 IN PCLASS_DRIVER_EXTENSION DriverExtension);
20
21 static VOID NTAPI
22 DriverUnload(IN PDRIVER_OBJECT DriverObject)
23 {
24 // nothing to do here yet
25 }
26
27 static NTSTATUS NTAPI
28 ClassCreate(
29 IN PDEVICE_OBJECT DeviceObject,
30 IN PIRP Irp)
31 {
32 DPRINT("IRP_MJ_CREATE\n");
33
34 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
35 return ForwardIrpAndForget(DeviceObject, Irp);
36
37 /* FIXME: open all associated Port devices */
38 return STATUS_SUCCESS;
39 }
40
41 static NTSTATUS NTAPI
42 ClassClose(
43 IN PDEVICE_OBJECT DeviceObject,
44 IN PIRP Irp)
45 {
46 DPRINT("IRP_MJ_CLOSE\n");
47
48 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
49 return ForwardIrpAndForget(DeviceObject, Irp);
50
51 /* FIXME: close all associated Port devices */
52 return STATUS_SUCCESS;
53 }
54
55 static NTSTATUS NTAPI
56 ClassCleanup(
57 IN PDEVICE_OBJECT DeviceObject,
58 IN PIRP Irp)
59 {
60 DPRINT("IRP_MJ_CLEANUP\n");
61
62 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
63 return ForwardIrpAndForget(DeviceObject, Irp);
64
65 /* FIXME: cleanup all associated Port devices */
66 return STATUS_SUCCESS;
67 }
68
69 static NTSTATUS NTAPI
70 ClassRead(
71 IN PDEVICE_OBJECT DeviceObject,
72 IN PIRP Irp)
73 {
74 DPRINT("IRP_MJ_READ\n");
75
76 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
77 return ForwardIrpAndForget(DeviceObject, Irp);
78
79 if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(MOUSE_INPUT_DATA))
80 {
81 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
82 Irp->IoStatus.Information = 0;
83 IoCompleteRequest(Irp, IO_NO_INCREMENT);
84
85 return STATUS_BUFFER_TOO_SMALL;
86 }
87
88 IoMarkIrpPending(Irp);
89 IoStartPacket(DeviceObject, Irp, NULL, NULL);
90 return STATUS_PENDING;
91 }
92
93 static NTSTATUS NTAPI
94 ClassDeviceControl(
95 IN PDEVICE_OBJECT DeviceObject,
96 IN PIRP Irp)
97 {
98 PCLASS_DEVICE_EXTENSION DeviceExtension;
99 NTSTATUS Status;
100
101 DPRINT("IRP_MJ_DEVICE_CONTROL\n");
102
103 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
104 return ForwardIrpAndForget(DeviceObject, Irp);
105
106 DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
107
108 switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode)
109 {
110 case IOCTL_MOUSE_QUERY_ATTRIBUTES:
111 /* FIXME */
112 Status = STATUS_NOT_SUPPORTED;
113 break;
114 default:
115 DPRINT1("IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
116 IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
117 Status = STATUS_NOT_SUPPORTED;
118 }
119
120 Irp->IoStatus.Status = Status;
121 Irp->IoStatus.Information = 0;
122 IoCompleteRequest(Irp, IO_NO_INCREMENT);
123
124 return Status;
125 }
126
127 static NTSTATUS NTAPI
128 IrpStub(
129 IN PDEVICE_OBJECT DeviceObject,
130 IN PIRP Irp)
131 {
132 NTSTATUS Status = STATUS_NOT_SUPPORTED;
133
134 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
135 {
136 /* Forward some IRPs to lower device */
137 switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
138 {
139 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
140 return ForwardIrpAndForget(DeviceObject, Irp);
141 default:
142 {
143 DPRINT1("Port DO stub for major function 0x%lx\n",
144 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
145 ASSERT(FALSE);
146 Status = Irp->IoStatus.Status;
147 }
148 }
149 }
150 else
151 {
152 DPRINT1("Class DO stub for major function 0x%lx\n",
153 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
154 ASSERT(FALSE);
155 Status = Irp->IoStatus.Status;
156 }
157
158 Irp->IoStatus.Status = Status;
159 IoCompleteRequest(Irp, IO_NO_INCREMENT);
160 return Status;
161 }
162
163 static NTSTATUS
164 ReadRegistryEntries(
165 IN PUNICODE_STRING RegistryPath,
166 IN PCLASS_DRIVER_EXTENSION DriverExtension)
167 {
168 UNICODE_STRING ParametersRegistryKey;
169 RTL_QUERY_REGISTRY_TABLE Parameters[4];
170 NTSTATUS Status;
171
172 ULONG DefaultConnectMultiplePorts = 1;
173 ULONG DefaultDataQueueSize = 0x64;
174 UNICODE_STRING DefaultDeviceBaseName = RTL_CONSTANT_STRING(L"PointerClass");
175
176 ParametersRegistryKey.Length = 0;
177 ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
178 ParametersRegistryKey.Buffer = ExAllocatePool(PagedPool, ParametersRegistryKey.MaximumLength);
179 if (!ParametersRegistryKey.Buffer)
180 {
181 DPRINT("ExAllocatePool() failed\n");
182 return STATUS_INSUFFICIENT_RESOURCES;
183 }
184 RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
185 RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
186 ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
187
188 RtlZeroMemory(Parameters, sizeof(Parameters));
189
190 Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
191 Parameters[0].Name = L"ConnectMultiplePorts";
192 Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts;
193 Parameters[0].DefaultType = REG_DWORD;
194 Parameters[0].DefaultData = &DefaultConnectMultiplePorts;
195 Parameters[0].DefaultLength = sizeof(ULONG);
196
197 Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
198 Parameters[1].Name = L"MouseDataQueueSize";
199 Parameters[1].EntryContext = &DriverExtension->DataQueueSize;
200 Parameters[1].DefaultType = REG_DWORD;
201 Parameters[1].DefaultData = &DefaultDataQueueSize;
202 Parameters[1].DefaultLength = sizeof(ULONG);
203
204 Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
205 Parameters[2].Name = L"PointerDeviceBaseName";
206 Parameters[2].EntryContext = &DriverExtension->DeviceBaseName;
207 Parameters[2].DefaultType = REG_SZ;
208 Parameters[2].DefaultData = &DefaultDeviceBaseName;
209 Parameters[2].DefaultLength = 0;
210
211 Status = RtlQueryRegistryValues(
212 RTL_REGISTRY_ABSOLUTE,
213 ParametersRegistryKey.Buffer,
214 Parameters,
215 NULL,
216 NULL);
217
218 if (NT_SUCCESS(Status))
219 {
220 /* Check values */
221 if (DriverExtension->ConnectMultiplePorts != 0
222 && DriverExtension->ConnectMultiplePorts != 1)
223 {
224 DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
225 }
226 if (DriverExtension->DataQueueSize == 0)
227 {
228 DriverExtension->DataQueueSize = DefaultDataQueueSize;
229 }
230 }
231 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
232 {
233 /* Registry path doesn't exist. Set defaults */
234 DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
235 DriverExtension->DataQueueSize = DefaultDataQueueSize;
236 Status = RtlDuplicateUnicodeString(
237 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
238 &DefaultDeviceBaseName,
239 &DriverExtension->DeviceBaseName);
240 }
241
242 return Status;
243 }
244
245 static NTSTATUS
246 CreateClassDeviceObject(
247 IN PDRIVER_OBJECT DriverObject,
248 OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
249 {
250 PCLASS_DRIVER_EXTENSION DriverExtension;
251 ULONG DeviceId = 0;
252 ULONG PrefixLength;
253 UNICODE_STRING DeviceNameU;
254 PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
255 PDEVICE_OBJECT Fdo;
256 PCLASS_DEVICE_EXTENSION DeviceExtension;
257 NTSTATUS Status;
258
259 DPRINT("CreateClassDeviceObject(0x%p)\n", DriverObject);
260
261 /* Create new device object */
262 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
263 DeviceNameU.Length = 0;
264 DeviceNameU.MaximumLength =
265 wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */
266 + DriverExtension->DeviceBaseName.Length /* "PointerClass" */
267 + 4 * sizeof(WCHAR) /* Id between 0 and 9999 */
268 + sizeof(UNICODE_NULL); /* Final NULL char */
269 DeviceNameU.Buffer = ExAllocatePool(PagedPool, DeviceNameU.MaximumLength);
270 if (!DeviceNameU.Buffer)
271 {
272 DPRINT("ExAllocatePool() failed\n");
273 return STATUS_INSUFFICIENT_RESOURCES;
274 }
275 Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
276 if (!NT_SUCCESS(Status))
277 {
278 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
279 goto cleanup;
280 }
281 Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->DeviceBaseName);
282 if (!NT_SUCCESS(Status))
283 {
284 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
285 goto cleanup;
286 }
287 PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL);
288 DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)];
289 while (DeviceId < 9999)
290 {
291 DeviceNameU.Length = PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR);
292 Status = IoCreateDevice(
293 DriverObject,
294 sizeof(CLASS_DEVICE_EXTENSION),
295 &DeviceNameU,
296 FILE_DEVICE_MOUSE,
297 FILE_DEVICE_SECURE_OPEN,
298 TRUE,
299 &Fdo);
300 if (NT_SUCCESS(Status))
301 goto cleanup;
302 else if (Status != STATUS_OBJECT_NAME_COLLISION)
303 {
304 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
305 goto cleanup;
306 }
307 DeviceId++;
308 }
309 DPRINT("Too much devices starting with '\\Device\\%wZ'\n", &DriverExtension->DeviceBaseName);
310 Status = STATUS_UNSUCCESSFUL;
311 cleanup:
312 if (!NT_SUCCESS(Status))
313 {
314 ExFreePool(DeviceNameU.Buffer);
315 return Status;
316 }
317
318 DeviceExtension = (PCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
319 RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
320 DeviceExtension->Common.IsClassDO = TRUE;
321 DeviceExtension->DriverExtension = DriverExtension;
322 KeInitializeSpinLock(&(DeviceExtension->SpinLock));
323 DeviceExtension->ReadIsPending = FALSE;
324 DeviceExtension->InputCount = 0;
325 DeviceExtension->PortData = ExAllocatePool(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(MOUSE_INPUT_DATA));
326 Fdo->Flags |= DO_POWER_PAGABLE;
327 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
328
329 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
330 RtlWriteRegistryValue(
331 RTL_REGISTRY_DEVICEMAP,
332 DriverExtension->DeviceBaseName.Buffer,
333 DeviceNameU.Buffer,
334 REG_SZ,
335 DriverExtension->RegistryPath.Buffer,
336 DriverExtension->RegistryPath.MaximumLength);
337
338 ExFreePool(DeviceNameU.Buffer);
339
340 if (ClassDO)
341 *ClassDO = Fdo;
342
343 return STATUS_SUCCESS;
344 }
345
346 static BOOLEAN
347 ClassCallback(
348 IN PDEVICE_OBJECT ClassDeviceObject,
349 IN OUT PMOUSE_INPUT_DATA DataStart,
350 IN PMOUSE_INPUT_DATA DataEnd,
351 IN OUT PULONG ConsumedCount)
352 {
353 PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
354 PIRP Irp = NULL;
355 KIRQL OldIrql;
356 PIO_STACK_LOCATION Stack;
357 ULONG InputCount = DataEnd - DataStart;
358 ULONG ReadSize;
359
360 ASSERT(ClassDeviceExtension->Common.IsClassDO);
361
362 KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
363
364 DPRINT("ClassCallback()\n");
365 /* A filter driver might have consumed all the data already; I'm
366 * not sure if they are supposed to move the packets when they
367 * consume them though.
368 */
369 if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
370 {
371 Irp = ClassDeviceObject->CurrentIrp;
372 ClassDeviceObject->CurrentIrp = NULL;
373 Stack = IoGetCurrentIrpStackLocation(Irp);
374
375 /* A read request is waiting for input, so go straight to it */
376 /* FIXME: use SEH */
377 RtlCopyMemory(
378 Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
379 DataStart,
380 sizeof(MOUSE_INPUT_DATA));
381
382 /* Go to next packet and complete this request with STATUS_SUCCESS */
383 Irp->IoStatus.Status = STATUS_SUCCESS;
384 Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
385 Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
386
387 ClassDeviceExtension->ReadIsPending = FALSE;
388
389 /* Skip the packet we just sent away */
390 DataStart++;
391 (*ConsumedCount)++;
392 InputCount--;
393 }
394
395 /* If we have data from the port driver and a higher service to send the data to */
396 if (InputCount != 0)
397 {
398 if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
399 ReadSize = ClassDeviceExtension->DriverExtension->DataQueueSize - ClassDeviceExtension->InputCount;
400 else
401 ReadSize = InputCount;
402
403 /*
404 * FIXME: If we exceed the buffer, data gets thrown away.. better
405 * solution?
406 */
407
408 /*
409 * Move the input data from the port data queue to our class data
410 * queue.
411 */
412 RtlMoveMemory(
413 ClassDeviceExtension->PortData,
414 (PCHAR)DataStart,
415 sizeof(MOUSE_INPUT_DATA) * ReadSize);
416
417 /* Move the pointer and counter up */
418 ClassDeviceExtension->PortData += ReadSize;
419 ClassDeviceExtension->InputCount += ReadSize;
420
421 (*ConsumedCount) += ReadSize;
422 }
423 else
424 {
425 DPRINT("ClassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount);
426 }
427
428 KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
429
430 if (Irp != NULL)
431 {
432 IoStartNextPacket(ClassDeviceObject, FALSE);
433 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
434 }
435
436 DPRINT("Leaving ClassCallback()\n");
437 return TRUE;
438 }
439
440 /* Send IOCTL_INTERNAL_*_CONNECT to port */
441 static NTSTATUS
442 ConnectPortDriver(
443 IN PDEVICE_OBJECT PortDO,
444 IN PDEVICE_OBJECT ClassDO)
445 {
446 KEVENT Event;
447 PIRP Irp;
448 IO_STATUS_BLOCK IoStatus;
449 CONNECT_DATA ConnectData;
450 NTSTATUS Status;
451
452 KeInitializeEvent(&Event, NotificationEvent, FALSE);
453
454 ConnectData.ClassDeviceObject = ClassDO;
455 ConnectData.ClassService = ClassCallback;
456
457 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
458 PortDO,
459 &ConnectData, sizeof(CONNECT_DATA),
460 NULL, 0,
461 TRUE, &Event, &IoStatus);
462
463 Status = IoCallDriver(PortDO, Irp);
464
465 if (Status == STATUS_PENDING)
466 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
467 else
468 IoStatus.Status = Status;
469
470 if (NT_SUCCESS(IoStatus.Status))
471 ObReferenceObject(PortDO);
472
473 return IoStatus.Status;
474 }
475
476 static NTSTATUS NTAPI
477 ClassAddDevice(
478 IN PDRIVER_OBJECT DriverObject,
479 IN PDEVICE_OBJECT Pdo)
480 {
481 PCLASS_DRIVER_EXTENSION DriverExtension;
482 PDEVICE_OBJECT Fdo;
483 PPORT_DEVICE_EXTENSION DeviceExtension;
484 NTSTATUS Status;
485
486 DPRINT("ClassAddDevice called. Pdo = 0x%p\n", Pdo);
487
488 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
489
490 if (Pdo == NULL)
491 /* We're getting a NULL Pdo at the first call as we're a legacy driver.
492 * Use it to search for legacy port drivers. */
493 return SearchForLegacyDrivers(DriverObject, DriverExtension);
494
495 /* Create new device object */
496 Status = IoCreateDevice(
497 DriverObject,
498 sizeof(PORT_DEVICE_EXTENSION),
499 NULL,
500 Pdo->DeviceType,
501 FILE_DEVICE_SECURE_OPEN,
502 TRUE,
503 &Fdo);
504 if (!NT_SUCCESS(Status))
505 {
506 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
507 return Status;
508 }
509
510 DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
511 RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
512 DeviceExtension->Common.IsClassDO = FALSE;
513 DeviceExtension->PnpState = dsStopped;
514 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
515 if (!NT_SUCCESS(Status))
516 {
517 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
518 IoDeleteDevice(Fdo);
519 return Status;
520 }
521 if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
522 Fdo->Flags |= DO_POWER_PAGABLE;
523 if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
524 Fdo->Flags |= DO_BUFFERED_IO;
525
526 if (DriverExtension->ConnectMultiplePorts)
527 Status = ConnectPortDriver(Fdo, DriverExtension->MainClassDeviceObject);
528 else
529 Status = ConnectPortDriver(Fdo, Fdo);
530 if (!NT_SUCCESS(Status))
531 {
532 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
533 IoDetachDevice(DeviceExtension->LowerDevice);
534 /* FIXME: why can't I cleanup without error? */
535 //IoDeleteDevice(Fdo);
536 return Status;
537 }
538 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
539
540 /* Register interface */
541 Status = IoRegisterDeviceInterface(
542 Pdo,
543 &GUID_DEVINTERFACE_MOUSE,
544 NULL,
545 &DeviceExtension->InterfaceName);
546 if (!NT_SUCCESS(Status))
547 {
548 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
549 return Status;
550 }
551
552 return STATUS_SUCCESS;
553 }
554
555 static VOID NTAPI
556 ClassStartIo(
557 IN PDEVICE_OBJECT DeviceObject,
558 IN PIRP Irp)
559 {
560 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
561 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
562
563 ASSERT(DeviceExtension->Common.IsClassDO);
564
565 if (DeviceExtension->InputCount > 0)
566 {
567 KIRQL oldIrql;
568
569 KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
570
571 DPRINT("Mdl: %p, UserBuffer: %p, InputCount: %lu\n",
572 Irp->MdlAddress,
573 Irp->UserBuffer,
574 DeviceExtension->InputCount);
575
576 /* FIXME: use SEH */
577 RtlCopyMemory(
578 Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
579 DeviceExtension->PortData - DeviceExtension->InputCount,
580 sizeof(MOUSE_INPUT_DATA));
581
582 if (DeviceExtension->InputCount > 1)
583 {
584 RtlMoveMemory(
585 DeviceExtension->PortData - DeviceExtension->InputCount,
586 DeviceExtension->PortData - DeviceExtension->InputCount + 1,
587 (DeviceExtension->InputCount - 1) * sizeof(MOUSE_INPUT_DATA));
588 }
589 DeviceExtension->PortData--;
590 DeviceExtension->InputCount--;
591 DeviceExtension->ReadIsPending = FALSE;
592
593 /* Go to next packet and complete this request with STATUS_SUCCESS */
594 Irp->IoStatus.Status = STATUS_SUCCESS;
595 Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
596 Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
597 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
598
599 IoStartNextPacket(DeviceObject, FALSE);
600 KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
601 }
602 else
603 {
604 DeviceExtension->ReadIsPending = TRUE;
605 }
606 }
607
608 static NTSTATUS
609 SearchForLegacyDrivers(
610 IN PDRIVER_OBJECT DriverObject,
611 IN PCLASS_DRIVER_EXTENSION DriverExtension)
612 {
613 UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
614 UNICODE_STRING PortBaseName = {0, };
615 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
616 OBJECT_ATTRIBUTES ObjectAttributes;
617 HANDLE hDeviceMapKey = (HANDLE)-1;
618 HANDLE hPortKey = (HANDLE)-1;
619 ULONG Index = 0;
620 ULONG Size, ResultLength;
621 NTSTATUS Status;
622
623 /* Create port base name, by replacing Class by Port at the end of the class base name */
624 Status = RtlDuplicateUnicodeString(
625 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
626 &DriverExtension->DeviceBaseName,
627 &PortBaseName);
628 if (!NT_SUCCESS(Status))
629 {
630 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
631 goto cleanup;
632 }
633 PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
634 RtlAppendUnicodeToString(&PortBaseName, L"Port");
635
636 /* Allocate memory */
637 Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
638 KeyValueInformation = ExAllocatePool(PagedPool, Size);
639 if (!KeyValueInformation)
640 {
641 DPRINT("ExAllocatePool() failed\n");
642 Status = STATUS_INSUFFICIENT_RESOURCES;
643 goto cleanup;
644 }
645
646 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
647 InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
648 Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
649 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
650 {
651 DPRINT("HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
652 Status = STATUS_SUCCESS;
653 goto cleanup;
654 }
655 else if (!NT_SUCCESS(Status))
656 {
657 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
658 goto cleanup;
659 }
660
661 /* Open sub key */
662 InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
663 Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
664 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
665 {
666 DPRINT("HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName);
667 Status = STATUS_SUCCESS;
668 goto cleanup;
669 }
670 else if (!NT_SUCCESS(Status))
671 {
672 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
673 goto cleanup;
674 }
675
676 /* Read each value name */
677 while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
678 {
679 UNICODE_STRING PortName;
680 PDEVICE_OBJECT PortDeviceObject = NULL;
681 PFILE_OBJECT FileObject = NULL;
682
683 PortName.Length = PortName.MaximumLength = KeyValueInformation->NameLength;
684 PortName.Buffer = KeyValueInformation->Name;
685
686 /* Open the device object pointer */
687 Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
688 if (!NT_SUCCESS(Status))
689 {
690 DPRINT("IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", Status);
691 }
692
693 /* Connect the port device object */
694 if (DriverExtension->ConnectMultiplePorts)
695 {
696 Status = ConnectPortDriver(PortDeviceObject, DriverExtension->MainClassDeviceObject);
697 if (!NT_SUCCESS(Status))
698 {
699 /* FIXME: Log the error */
700 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
701 }
702 }
703 else
704 {
705 PDEVICE_OBJECT ClassDO;
706 Status = CreateClassDeviceObject(DriverObject, &ClassDO);
707 if (!NT_SUCCESS(Status))
708 {
709 /* FIXME: Log the error */
710 DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status);
711 continue;
712 }
713 Status = ConnectPortDriver(PortDeviceObject, ClassDO);
714 if (!NT_SUCCESS(Status))
715 {
716 /* FIXME: Log the error */
717 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
718 IoDeleteDevice(ClassDO);
719 }
720 }
721 }
722 if (Status == STATUS_NO_MORE_ENTRIES)
723 Status = STATUS_SUCCESS;
724
725 cleanup:
726 if (KeyValueInformation != NULL)
727 ExFreePool(KeyValueInformation);
728 if (hDeviceMapKey != (HANDLE)-1)
729 ZwClose(hDeviceMapKey);
730 if (hPortKey != (HANDLE)-1)
731 ZwClose(hPortKey);
732 return Status;
733 }
734
735 /*
736 * Standard DriverEntry method.
737 */
738 NTSTATUS NTAPI
739 DriverEntry(
740 IN PDRIVER_OBJECT DriverObject,
741 IN PUNICODE_STRING RegistryPath)
742 {
743 PCLASS_DRIVER_EXTENSION DriverExtension;
744 ULONG i;
745 NTSTATUS Status;
746
747 Status = IoAllocateDriverObjectExtension(
748 DriverObject,
749 DriverObject,
750 sizeof(CLASS_DRIVER_EXTENSION),
751 (PVOID*)&DriverExtension);
752 if (!NT_SUCCESS(Status))
753 {
754 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
755 return Status;
756 }
757 RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
758
759 Status = RtlDuplicateUnicodeString(
760 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
761 RegistryPath,
762 &DriverExtension->RegistryPath);
763 if (!NT_SUCCESS(Status))
764 {
765 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
766 return Status;
767 }
768
769 Status = ReadRegistryEntries(RegistryPath, DriverExtension);
770 if (!NT_SUCCESS(Status))
771 {
772 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status);
773 return Status;
774 }
775
776 if (DriverExtension->ConnectMultiplePorts == 1)
777 {
778 Status = CreateClassDeviceObject(
779 DriverObject,
780 &DriverExtension->MainClassDeviceObject);
781 if (!NT_SUCCESS(Status))
782 {
783 DPRINT("CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
784 return Status;
785 }
786 }
787
788 DriverObject->DriverExtension->AddDevice = ClassAddDevice;
789 DriverObject->DriverUnload = DriverUnload;
790
791 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
792 DriverObject->MajorFunction[i] = IrpStub;
793
794 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreate;
795 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassClose;
796 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ClassCleanup;
797 DriverObject->MajorFunction[IRP_MJ_READ] = ClassRead;
798 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl;
799 DriverObject->DriverStartIo = ClassStartIo;
800
801 return STATUS_SUCCESS;
802 }