Prevent the reinstall of devices that use the NULL driver at each reboot
[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 DPRINT("ClassCallback()\n");
363 /* A filter driver might have consumed all the data already; I'm
364 * not sure if they are supposed to move the packets when they
365 * consume them though.
366 */
367 if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
368 {
369 Irp = ClassDeviceObject->CurrentIrp;
370 ClassDeviceObject->CurrentIrp = NULL;
371 Stack = IoGetCurrentIrpStackLocation(Irp);
372
373 /* A read request is waiting for input, so go straight to it */
374 /* FIXME: use SEH */
375 RtlCopyMemory(
376 Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
377 DataStart,
378 sizeof(MOUSE_INPUT_DATA));
379
380 /* Go to next packet and complete this request with STATUS_SUCCESS */
381 Irp->IoStatus.Status = STATUS_SUCCESS;
382 Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
383 Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
384
385 ClassDeviceExtension->ReadIsPending = FALSE;
386
387 /* Skip the packet we just sent away */
388 DataStart++;
389 (*ConsumedCount)++;
390 InputCount--;
391 }
392
393 /* If we have data from the port driver and a higher service to send the data to */
394 if (InputCount != 0)
395 {
396 KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
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 KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
422 (*ConsumedCount) += ReadSize;
423 }
424 else
425 {
426 DPRINT("ClassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount);
427 }
428
429 if (Irp != NULL)
430 {
431 IoStartNextPacket(ClassDeviceObject, FALSE);
432 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
433 }
434
435 DPRINT("Leaving ClassCallback()\n");
436 return TRUE;
437 }
438
439 /* Send IOCTL_INTERNAL_*_CONNECT to port */
440 static NTSTATUS
441 ConnectPortDriver(
442 IN PDEVICE_OBJECT PortDO,
443 IN PDEVICE_OBJECT ClassDO)
444 {
445 KEVENT Event;
446 PIRP Irp;
447 IO_STATUS_BLOCK IoStatus;
448 CONNECT_DATA ConnectData;
449 NTSTATUS Status;
450
451 KeInitializeEvent(&Event, NotificationEvent, FALSE);
452
453 ConnectData.ClassDeviceObject = ClassDO;
454 ConnectData.ClassService = ClassCallback;
455
456 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
457 PortDO,
458 &ConnectData, sizeof(CONNECT_DATA),
459 NULL, 0,
460 TRUE, &Event, &IoStatus);
461
462 Status = IoCallDriver(PortDO, Irp);
463
464 if (Status == STATUS_PENDING)
465 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
466 else
467 IoStatus.Status = Status;
468
469 if (NT_SUCCESS(IoStatus.Status))
470 ObReferenceObject(PortDO);
471
472 return IoStatus.Status;
473 }
474
475 static NTSTATUS NTAPI
476 ClassAddDevice(
477 IN PDRIVER_OBJECT DriverObject,
478 IN PDEVICE_OBJECT Pdo)
479 {
480 PCLASS_DRIVER_EXTENSION DriverExtension;
481 PDEVICE_OBJECT Fdo;
482 PPORT_DEVICE_EXTENSION DeviceExtension;
483 NTSTATUS Status;
484
485 DPRINT("ClassAddDevice called. Pdo = 0x%p\n", Pdo);
486
487 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
488
489 if (Pdo == NULL)
490 /* We're getting a NULL Pdo at the first call as we're a legacy driver.
491 * Use it to search for legacy port drivers. */
492 return SearchForLegacyDrivers(DriverObject, DriverExtension);
493
494 /* Create new device object */
495 Status = IoCreateDevice(
496 DriverObject,
497 sizeof(PORT_DEVICE_EXTENSION),
498 NULL,
499 Pdo->DeviceType,
500 FILE_DEVICE_SECURE_OPEN,
501 TRUE,
502 &Fdo);
503 if (!NT_SUCCESS(Status))
504 {
505 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
506 return Status;
507 }
508
509 DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
510 RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
511 DeviceExtension->Common.IsClassDO = FALSE;
512 DeviceExtension->PnpState = dsStopped;
513 Fdo->Flags |= DO_POWER_PAGABLE;
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 Fdo->Flags |= DO_BUFFERED_IO;
522
523 if (DriverExtension->ConnectMultiplePorts)
524 Status = ConnectPortDriver(Fdo, DriverExtension->MainClassDeviceObject);
525 else
526 Status = ConnectPortDriver(Fdo, Fdo);
527 if (!NT_SUCCESS(Status))
528 {
529 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
530 IoDetachDevice(DeviceExtension->LowerDevice);
531 /* FIXME: why can't I cleanup without error? */
532 //IoDeleteDevice(Fdo);
533 return Status;
534 }
535 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
536
537 /* Register interface */
538 Status = IoRegisterDeviceInterface(
539 Pdo,
540 &GUID_DEVINTERFACE_MOUSE,
541 NULL,
542 &DeviceExtension->InterfaceName);
543 if (!NT_SUCCESS(Status))
544 {
545 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
546 return Status;
547 }
548
549 return STATUS_SUCCESS;
550 }
551
552 static VOID NTAPI
553 ClassStartIo(
554 IN PDEVICE_OBJECT DeviceObject,
555 IN PIRP Irp)
556 {
557 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
558 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
559
560 ASSERT(DeviceExtension->Common.IsClassDO);
561
562 if (DeviceExtension->InputCount > 0)
563 {
564 KIRQL oldIrql;
565
566 KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
567
568 /* FIXME: use SEH */
569 RtlCopyMemory(
570 Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
571 DeviceExtension->PortData - DeviceExtension->InputCount,
572 sizeof(MOUSE_INPUT_DATA));
573
574 if (DeviceExtension->InputCount > 1)
575 {
576 RtlMoveMemory(
577 DeviceExtension->PortData - DeviceExtension->InputCount,
578 DeviceExtension->PortData - DeviceExtension->InputCount + 1,
579 (DeviceExtension->InputCount - 1) * sizeof(MOUSE_INPUT_DATA));
580 }
581 DeviceExtension->PortData--;
582 DeviceExtension->InputCount--;
583 DeviceExtension->ReadIsPending = FALSE;
584
585 /* Go to next packet and complete this request with STATUS_SUCCESS */
586 Irp->IoStatus.Status = STATUS_SUCCESS;
587 Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
588 Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
589 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
590
591 IoStartNextPacket(DeviceObject, FALSE);
592 KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
593 }
594 else
595 {
596 DeviceExtension->ReadIsPending = TRUE;
597 }
598 }
599
600 static NTSTATUS
601 SearchForLegacyDrivers(
602 IN PDRIVER_OBJECT DriverObject,
603 IN PCLASS_DRIVER_EXTENSION DriverExtension)
604 {
605 UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
606 UNICODE_STRING PortBaseName = {0, };
607 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
608 OBJECT_ATTRIBUTES ObjectAttributes;
609 HANDLE hDeviceMapKey = (HANDLE)-1;
610 HANDLE hPortKey = (HANDLE)-1;
611 ULONG Index = 0;
612 ULONG Size, ResultLength;
613 NTSTATUS Status;
614
615 /* Create port base name, by replacing Class by Port at the end of the class base name */
616 Status = RtlDuplicateUnicodeString(
617 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
618 &DriverExtension->DeviceBaseName,
619 &PortBaseName);
620 if (!NT_SUCCESS(Status))
621 {
622 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
623 goto cleanup;
624 }
625 PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
626 RtlAppendUnicodeToString(&PortBaseName, L"Port");
627
628 /* Allocate memory */
629 Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
630 KeyValueInformation = ExAllocatePool(PagedPool, Size);
631 if (!KeyValueInformation)
632 {
633 DPRINT("ExAllocatePool() failed\n");
634 Status = STATUS_INSUFFICIENT_RESOURCES;
635 goto cleanup;
636 }
637
638 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
639 InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
640 Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
641 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
642 {
643 DPRINT("HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
644 Status = STATUS_SUCCESS;
645 goto cleanup;
646 }
647 else if (!NT_SUCCESS(Status))
648 {
649 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
650 goto cleanup;
651 }
652
653 /* Open sub key */
654 InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
655 Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
656 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
657 {
658 DPRINT("HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName);
659 Status = STATUS_SUCCESS;
660 goto cleanup;
661 }
662 else if (!NT_SUCCESS(Status))
663 {
664 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
665 goto cleanup;
666 }
667
668 /* Read each value name */
669 while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
670 {
671 UNICODE_STRING PortName;
672 PDEVICE_OBJECT PortDeviceObject = NULL;
673 PFILE_OBJECT FileObject = NULL;
674
675 PortName.Length = PortName.MaximumLength = KeyValueInformation->NameLength;
676 PortName.Buffer = KeyValueInformation->Name;
677
678 /* Open the device object pointer */
679 Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
680 if (!NT_SUCCESS(Status))
681 {
682 DPRINT("IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", Status);
683 }
684
685 /* Connect the port device object */
686 if (DriverExtension->ConnectMultiplePorts)
687 {
688 Status = ConnectPortDriver(PortDeviceObject, DriverExtension->MainClassDeviceObject);
689 if (!NT_SUCCESS(Status))
690 {
691 /* FIXME: Log the error */
692 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
693 }
694 }
695 else
696 {
697 PDEVICE_OBJECT ClassDO;
698 Status = CreateClassDeviceObject(DriverObject, &ClassDO);
699 if (!NT_SUCCESS(Status))
700 {
701 /* FIXME: Log the error */
702 DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status);
703 continue;
704 }
705 Status = ConnectPortDriver(PortDeviceObject, ClassDO);
706 if (!NT_SUCCESS(Status))
707 {
708 /* FIXME: Log the error */
709 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
710 IoDeleteDevice(ClassDO);
711 }
712 }
713 }
714 if (Status == STATUS_NO_MORE_ENTRIES)
715 Status = STATUS_SUCCESS;
716
717 cleanup:
718 if (KeyValueInformation != NULL)
719 ExFreePool(KeyValueInformation);
720 if (hDeviceMapKey != (HANDLE)-1)
721 ZwClose(hDeviceMapKey);
722 if (hPortKey != (HANDLE)-1)
723 ZwClose(hPortKey);
724 return Status;
725 }
726
727 /*
728 * Standard DriverEntry method.
729 */
730 NTSTATUS NTAPI
731 DriverEntry(
732 IN PDRIVER_OBJECT DriverObject,
733 IN PUNICODE_STRING RegistryPath)
734 {
735 PCLASS_DRIVER_EXTENSION DriverExtension;
736 ULONG i;
737 NTSTATUS Status;
738
739 Status = IoAllocateDriverObjectExtension(
740 DriverObject,
741 DriverObject,
742 sizeof(CLASS_DRIVER_EXTENSION),
743 (PVOID*)&DriverExtension);
744 if (!NT_SUCCESS(Status))
745 {
746 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
747 return Status;
748 }
749 RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
750
751 Status = RtlDuplicateUnicodeString(
752 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
753 RegistryPath,
754 &DriverExtension->RegistryPath);
755 if (!NT_SUCCESS(Status))
756 {
757 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
758 return Status;
759 }
760
761 Status = ReadRegistryEntries(RegistryPath, DriverExtension);
762 if (!NT_SUCCESS(Status))
763 {
764 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status);
765 return Status;
766 }
767
768 if (DriverExtension->ConnectMultiplePorts == 1)
769 {
770 Status = CreateClassDeviceObject(
771 DriverObject,
772 &DriverExtension->MainClassDeviceObject);
773 if (!NT_SUCCESS(Status))
774 {
775 DPRINT("CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
776 return Status;
777 }
778 }
779
780 DriverObject->DriverExtension->AddDevice = ClassAddDevice;
781 DriverObject->DriverUnload = DriverUnload;
782
783 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
784 DriverObject->MajorFunction[i] = IrpStub;
785
786 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreate;
787 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassClose;
788 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ClassCleanup;
789 DriverObject->MajorFunction[IRP_MJ_READ] = ClassRead;
790 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl;
791 DriverObject->DriverStartIo = ClassStartIo;
792
793 return STATUS_SUCCESS;
794 }