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