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