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