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