2 * PROJECT: ReactOS Universal Serial Bus Human Interface Device Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/hid/hidclass/hidclass.c
5 * PURPOSE: HID Class Driver
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
16 static LPWSTR ClientIdentificationAddress
= L
"HIDCLASS";
17 static ULONG HidClassDeviceNumber
= 0;
22 IN PUNICODE_STRING RegistryPath
)
24 return STATUS_SUCCESS
;
31 return STATUS_SUCCESS
;
37 IN PDRIVER_OBJECT DriverObject
,
38 IN PDEVICE_OBJECT PhysicalDeviceObject
)
40 WCHAR CharDeviceName
[64];
42 UNICODE_STRING DeviceName
;
43 PDEVICE_OBJECT NewDeviceObject
;
44 PHIDCLASS_FDO_EXTENSION FDODeviceExtension
;
45 ULONG DeviceExtensionSize
;
46 PHIDCLASS_DRIVER_EXTENSION DriverExtension
;
48 /* increment device number */
49 InterlockedIncrement((PLONG
)&HidClassDeviceNumber
);
51 /* construct device name */
52 swprintf(CharDeviceName
, L
"\\Device\\_HID%08x", HidClassDeviceNumber
);
54 /* initialize device name */
55 RtlInitUnicodeString(&DeviceName
, CharDeviceName
);
57 /* get driver object extension */
58 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, ClientIdentificationAddress
);
63 return STATUS_DEVICE_CONFIGURATION_ERROR
;
66 /* calculate device extension size */
67 DeviceExtensionSize
= sizeof(HIDCLASS_FDO_EXTENSION
) + DriverExtension
->DeviceExtensionSize
;
69 /* now create the device */
70 Status
= IoCreateDevice(DriverObject
, DeviceExtensionSize
, &DeviceName
, FILE_DEVICE_UNKNOWN
, 0, FALSE
, &NewDeviceObject
);
71 if (!NT_SUCCESS(Status
))
73 /* failed to create device object */
78 /* get device extension */
79 FDODeviceExtension
= NewDeviceObject
->DeviceExtension
;
81 /* zero device extension */
82 RtlZeroMemory(FDODeviceExtension
, sizeof(HIDCLASS_FDO_EXTENSION
));
84 /* initialize device extension */
85 FDODeviceExtension
->Common
.IsFDO
= TRUE
;
86 FDODeviceExtension
->Common
.DriverExtension
= DriverExtension
;
87 FDODeviceExtension
->Common
.HidDeviceExtension
.PhysicalDeviceObject
= PhysicalDeviceObject
;
88 FDODeviceExtension
->Common
.HidDeviceExtension
.MiniDeviceExtension
= (PVOID
)((ULONG_PTR
)FDODeviceExtension
+ sizeof(HIDCLASS_FDO_EXTENSION
));
89 FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
= IoAttachDeviceToDeviceStack(NewDeviceObject
, PhysicalDeviceObject
);
90 if (FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
== NULL
)
93 IoDeleteDevice(NewDeviceObject
);
94 DPRINT1("[HIDCLASS] failed to attach to device stack\n");
95 return STATUS_DEVICE_REMOVED
;
99 ASSERT(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
);
101 /* increment stack size */
102 NewDeviceObject
->StackSize
++;
104 /* init device object */
105 NewDeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
106 NewDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
108 /* now call driver provided add device routine */
109 ASSERT(DriverExtension
->AddDevice
!= 0);
110 Status
= DriverExtension
->AddDevice(DriverObject
, NewDeviceObject
);
111 if (!NT_SUCCESS(Status
))
114 DPRINT1("HIDCLASS: AddDevice failed with %x\n", Status
);
115 IoDetachDevice(FDODeviceExtension
->Common
.HidDeviceExtension
.NextDeviceObject
);
116 IoDeleteDevice(NewDeviceObject
);
126 HidClassDriverUnload(
127 IN PDRIVER_OBJECT DriverObject
)
135 IN PDEVICE_OBJECT DeviceObject
,
138 PIO_STACK_LOCATION IoStack
;
139 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
140 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
141 PHIDCLASS_FILEOP_CONTEXT Context
;
144 // get device extension
146 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
147 if (CommonDeviceExtension
->IsFDO
)
150 // only supported for PDO
152 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
153 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
154 return STATUS_UNSUCCESSFUL
;
160 ASSERT(CommonDeviceExtension
->IsFDO
== FALSE
);
163 // get device extension
165 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
168 // get stack location
170 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
172 DPRINT("ShareAccess %x\n", IoStack
->Parameters
.Create
.ShareAccess
);
173 DPRINT("Options %x\n", IoStack
->Parameters
.Create
.Options
);
174 DPRINT("DesiredAccess %x\n", IoStack
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
179 Context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(HIDCLASS_FILEOP_CONTEXT
), HIDCLASS_TAG
);
185 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
186 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
187 return STATUS_INSUFFICIENT_RESOURCES
;
193 RtlZeroMemory(Context
, sizeof(HIDCLASS_FILEOP_CONTEXT
));
194 Context
->DeviceExtension
= PDODeviceExtension
;
195 KeInitializeSpinLock(&Context
->Lock
);
196 InitializeListHead(&Context
->ReadPendingIrpListHead
);
197 InitializeListHead(&Context
->IrpCompletedListHead
);
198 KeInitializeEvent(&Context
->IrpReadComplete
, NotificationEvent
, FALSE
);
203 ASSERT(IoStack
->FileObject
);
204 IoStack
->FileObject
->FsContext
= Context
;
209 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
210 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
211 return STATUS_SUCCESS
;
217 IN PDEVICE_OBJECT DeviceObject
,
220 PIO_STACK_LOCATION IoStack
;
221 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
222 PHIDCLASS_FILEOP_CONTEXT IrpContext
;
223 BOOLEAN IsRequestPending
= FALSE
;
229 // get device extension
231 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
234 // is it a FDO request
236 if (CommonDeviceExtension
->IsFDO
)
239 // how did the request get there
241 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER_1
;
242 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
243 return STATUS_INVALID_PARAMETER_1
;
247 // get stack location
249 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
254 ASSERT(IoStack
->FileObject
);
255 ASSERT(IoStack
->FileObject
->FsContext
);
260 IrpContext
= IoStack
->FileObject
->FsContext
;
266 KeAcquireSpinLock(&IrpContext
->Lock
, &OldLevel
);
268 if (!IsListEmpty(&IrpContext
->ReadPendingIrpListHead
))
273 IsRequestPending
= TRUE
;
279 IrpContext
->StopInProgress
= TRUE
;
284 KeReleaseSpinLock(&IrpContext
->Lock
, OldLevel
);
286 if (IsRequestPending
)
289 // wait for request to complete
291 DPRINT1("[HIDCLASS] Waiting for read irp completion...\n");
292 KeWaitForSingleObject(&IrpContext
->IrpReadComplete
, Executive
, KernelMode
, FALSE
, NULL
);
298 KeAcquireSpinLock(&IrpContext
->Lock
, &OldLevel
);
303 ASSERT(IsListEmpty(&IrpContext
->ReadPendingIrpListHead
));
308 while (!IsListEmpty(&IrpContext
->IrpCompletedListHead
))
313 Entry
= RemoveHeadList(&IrpContext
->IrpCompletedListHead
);
318 ListIrp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.ListEntry
);
329 KeReleaseSpinLock(&IrpContext
->Lock
, OldLevel
);
334 IoStack
->FileObject
->FsContext
= NULL
;
339 ExFreePoolWithTag(IrpContext
, HIDCLASS_TAG
);
344 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
345 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
346 return STATUS_SUCCESS
;
351 HidClass_ReadCompleteIrp(
352 IN PDEVICE_OBJECT DeviceObject
,
356 PHIDCLASS_IRP_CONTEXT IrpContext
;
360 PHIDP_COLLECTION_DESC CollectionDescription
;
361 PHIDP_REPORT_IDS ReportDescription
;
369 DPRINT("HidClass_ReadCompleteIrp Irql %lu\n", KeGetCurrentIrql());
370 DPRINT("HidClass_ReadCompleteIrp Status %lx\n", Irp
->IoStatus
.Status
);
371 DPRINT("HidClass_ReadCompleteIrp Length %lu\n", Irp
->IoStatus
.Information
);
372 DPRINT("HidClass_ReadCompleteIrp Irp %p\n", Irp
);
373 DPRINT("HidClass_ReadCompleteIrp InputReportBuffer %p\n", IrpContext
->InputReportBuffer
);
374 DPRINT("HidClass_ReadCompleteIrp InputReportBufferLength %li\n", IrpContext
->InputReportBufferLength
);
375 DPRINT("HidClass_ReadCompleteIrp OriginalIrp %p\n", IrpContext
->OriginalIrp
);
380 if (Irp
->IoStatus
.Information
)
385 Address
= MmGetSystemAddressForMdlSafe(IrpContext
->OriginalIrp
->MdlAddress
, NormalPagePriority
);
389 // reports may have a report id prepended
394 // get collection description
396 CollectionDescription
= HidClassPDO_GetCollectionDescription(&IrpContext
->FileOp
->DeviceExtension
->Common
.DeviceDescription
,
397 IrpContext
->FileOp
->DeviceExtension
->CollectionNumber
);
398 ASSERT(CollectionDescription
);
401 // get report description
403 ReportDescription
= HidClassPDO_GetReportDescription(&IrpContext
->FileOp
->DeviceExtension
->Common
.DeviceDescription
,
404 IrpContext
->FileOp
->DeviceExtension
->CollectionNumber
);
405 ASSERT(ReportDescription
);
407 if (CollectionDescription
&& ReportDescription
)
412 ASSERT(CollectionDescription
->InputLength
>= ReportDescription
->InputLength
);
413 Offset
= CollectionDescription
->InputLength
- ReportDescription
->InputLength
;
419 RtlCopyMemory(&Address
[Offset
], IrpContext
->InputReportBuffer
, IrpContext
->InputReportBufferLength
);
424 // copy result status
426 IrpContext
->OriginalIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
427 IrpContext
->OriginalIrp
->IoStatus
.Information
= Irp
->IoStatus
.Information
;
430 // free input report buffer
432 ExFreePoolWithTag(IrpContext
->InputReportBuffer
, HIDCLASS_TAG
);
435 // remove us from pending list
437 KeAcquireSpinLock(&IrpContext
->FileOp
->Lock
, &OldLevel
);
440 // remove from pending list
442 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
447 IsEmpty
= IsListEmpty(&IrpContext
->FileOp
->ReadPendingIrpListHead
);
450 // insert into completed list
452 InsertTailList(&IrpContext
->FileOp
->IrpCompletedListHead
, &Irp
->Tail
.Overlay
.ListEntry
);
457 KeReleaseSpinLock(&IrpContext
->FileOp
->Lock
, OldLevel
);
460 // complete original request
462 IoCompleteRequest(IrpContext
->OriginalIrp
, IO_NO_INCREMENT
);
465 DPRINT("StopInProgress %x IsEmpty %x\n", IrpContext
->FileOp
->StopInProgress
, IsEmpty
);
466 if (IrpContext
->FileOp
->StopInProgress
&& IsEmpty
)
471 DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
472 KeSetEvent(&IrpContext
->FileOp
->IrpReadComplete
, 0, FALSE
);
475 if (IrpContext
->FileOp
->StopInProgress
&& IsEmpty
)
480 DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
481 KeSetEvent(&IrpContext
->FileOp
->IrpReadComplete
, 0, FALSE
);
487 ExFreePoolWithTag(IrpContext
, HIDCLASS_TAG
);
492 return STATUS_MORE_PROCESSING_REQUIRED
;
497 IN PHIDCLASS_FILEOP_CONTEXT Context
)
501 PLIST_ENTRY ListEntry
;
506 KeAcquireSpinLock(&Context
->Lock
, &OldLevel
);
511 if (!IsListEmpty(&Context
->IrpCompletedListHead
))
516 ListEntry
= RemoveHeadList(&Context
->IrpCompletedListHead
);
521 Irp
= CONTAINING_RECORD(ListEntry
, IRP
, Tail
.Overlay
.ListEntry
);
527 KeReleaseSpinLock(&Context
->Lock
, OldLevel
);
537 IN PDEVICE_OBJECT DeviceObject
,
539 IN PHIDCLASS_FILEOP_CONTEXT Context
,
540 IN ULONG DeviceIoControlCode
,
541 IN ULONG BufferLength
,
543 OUT PHIDCLASS_IRP_CONTEXT
*OutIrpContext
)
546 PIO_STACK_LOCATION IoStack
;
547 PHIDCLASS_IRP_CONTEXT IrpContext
;
548 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
549 PHIDP_COLLECTION_DESC CollectionDescription
;
550 PHIDP_REPORT_IDS ReportDescription
;
553 // get an irp from fresh list
555 Irp
= HidClass_GetIrp(Context
);
561 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
567 return STATUS_INSUFFICIENT_RESOURCES
;
575 IoReuseIrp(Irp
, STATUS_SUCCESS
);
579 // allocate completion context
581 IrpContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(HIDCLASS_IRP_CONTEXT
), HIDCLASS_TAG
);
588 return STATUS_INSUFFICIENT_RESOURCES
;
592 // get device extension
594 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
595 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
600 RtlZeroMemory(IrpContext
, sizeof(HIDCLASS_IRP_CONTEXT
));
601 IrpContext
->OriginalIrp
= RequestIrp
;
602 IrpContext
->FileOp
= Context
;
605 // get collection description
607 CollectionDescription
= HidClassPDO_GetCollectionDescription(&IrpContext
->FileOp
->DeviceExtension
->Common
.DeviceDescription
,
608 IrpContext
->FileOp
->DeviceExtension
->CollectionNumber
);
609 ASSERT(CollectionDescription
);
612 // get report description
614 ReportDescription
= HidClassPDO_GetReportDescription(&IrpContext
->FileOp
->DeviceExtension
->Common
.DeviceDescription
,
615 IrpContext
->FileOp
->DeviceExtension
->CollectionNumber
);
616 ASSERT(ReportDescription
);
621 ASSERT(CollectionDescription
->InputLength
>= ReportDescription
->InputLength
);
623 if (Context
->StopInProgress
)
628 DPRINT1("[HIDCLASS] Stop In Progress\n");
629 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
630 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
631 return STATUS_CANCELLED
;
636 // store report length
638 IrpContext
->InputReportBufferLength
= ReportDescription
->InputLength
;
643 IrpContext
->InputReportBuffer
= ExAllocatePoolWithTag(NonPagedPool
, IrpContext
->InputReportBufferLength
, HIDCLASS_TAG
);
644 if (!IrpContext
->InputReportBuffer
)
650 ExFreePoolWithTag(IrpContext
, HIDCLASS_TAG
);
651 return STATUS_INSUFFICIENT_RESOURCES
;
655 // get stack location
657 IoStack
= IoGetNextIrpStackLocation(Irp
);
660 // init stack location
662 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
663 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= DeviceIoControlCode
;
664 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= IrpContext
->InputReportBufferLength
;
665 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
= 0;
666 IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= NULL
;
667 Irp
->UserBuffer
= IrpContext
->InputReportBuffer
;
668 IoStack
->DeviceObject
= DeviceObject
;
674 *OutIrpContext
= IrpContext
;
679 return STATUS_SUCCESS
;
685 IN PDEVICE_OBJECT DeviceObject
,
688 PIO_STACK_LOCATION IoStack
;
689 PHIDCLASS_FILEOP_CONTEXT Context
;
693 PHIDCLASS_IRP_CONTEXT NewIrpContext
;
694 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
697 // get current stack location
699 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
702 // get device extension
704 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
705 ASSERT(CommonDeviceExtension
->IsFDO
== FALSE
);
710 ASSERT(IoStack
->FileObject
);
711 ASSERT(IoStack
->FileObject
->FsContext
);
716 Context
= IoStack
->FileObject
->FsContext
;
720 // FIXME support polled devices
722 ASSERT(Context
->DeviceExtension
->Common
.DriverExtension
->DevicesArePolled
== FALSE
);
724 if (Context
->StopInProgress
)
729 DPRINT1("[HIDCLASS] Stop In Progress\n");
730 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
731 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
732 return STATUS_CANCELLED
;
738 Status
= HidClass_BuildIrp(DeviceObject
,
741 IOCTL_HID_READ_REPORT
,
742 IoStack
->Parameters
.Read
.Length
,
745 if (!NT_SUCCESS(Status
))
750 DPRINT1("HidClass_BuildIrp failed with %x\n", Status
);
751 Irp
->IoStatus
.Status
= Status
;
752 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
759 KeAcquireSpinLock(&Context
->Lock
, &OldLevel
);
762 // insert irp into pending list
764 InsertTailList(&Context
->ReadPendingIrpListHead
, &NewIrp
->Tail
.Overlay
.ListEntry
);
767 // set completion routine
769 IoSetCompletionRoutine(NewIrp
, HidClass_ReadCompleteIrp
, NewIrpContext
, TRUE
, TRUE
, TRUE
);
772 // make next location current
774 IoSetNextIrpStackLocation(NewIrp
);
779 KeReleaseSpinLock(&Context
->Lock
, OldLevel
);
784 IoMarkIrpPending(Irp
);
787 // let's dispatch the request
789 ASSERT(Context
->DeviceExtension
);
790 Status
= Context
->DeviceExtension
->Common
.DriverExtension
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
](Context
->DeviceExtension
->FDODeviceObject
, NewIrp
);
795 return STATUS_PENDING
;
801 IN PDEVICE_OBJECT DeviceObject
,
804 PIO_STACK_LOCATION IoStack
;
805 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
808 IO_STATUS_BLOCK IoStatusBlock
;
809 HID_XFER_PACKET XferPacket
;
813 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
814 Length
= IoStack
->Parameters
.Write
.Length
;
817 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
818 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
819 return STATUS_INVALID_PARAMETER
;
822 RtlZeroMemory(&XferPacket
, sizeof(XferPacket
));
823 XferPacket
.reportBufferLen
= Length
;
824 XferPacket
.reportBuffer
= Irp
->UserBuffer
;
825 XferPacket
.reportId
= XferPacket
.reportBuffer
[0];
827 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
828 SubIrp
= IoBuildDeviceIoControlRequest(
829 IOCTL_HID_WRITE_REPORT
,
830 CommonDeviceExtension
->HidDeviceExtension
.NextDeviceObject
,
838 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
839 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
840 return STATUS_NOT_IMPLEMENTED
;
842 SubIrp
->UserBuffer
= &XferPacket
;
843 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
844 Status
= IoCallDriver(CommonDeviceExtension
->HidDeviceExtension
.NextDeviceObject
, SubIrp
);
845 if (Status
== STATUS_PENDING
)
847 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
848 Status
= IoStatusBlock
.Status
;
850 Irp
->IoStatus
.Status
= Status
;
851 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
857 HidClass_DeviceControl(
858 IN PDEVICE_OBJECT DeviceObject
,
861 PIO_STACK_LOCATION IoStack
;
862 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
863 PHID_COLLECTION_INFORMATION CollectionInformation
;
864 PHIDP_COLLECTION_DESC CollectionDescription
;
865 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension
;
868 // get device extension
870 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
873 // only PDO are supported
875 if (CommonDeviceExtension
->IsFDO
)
880 DPRINT1("[HIDCLASS] DeviceControl Irp for FDO arrived\n");
881 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER_1
;
882 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
883 return STATUS_INVALID_PARAMETER_1
;
886 ASSERT(CommonDeviceExtension
->IsFDO
== FALSE
);
889 // get pdo device extension
891 PDODeviceExtension
= DeviceObject
->DeviceExtension
;
894 // get stack location
896 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
898 switch (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
)
900 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
903 // check if output buffer is big enough
905 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
908 // invalid buffer size
910 Irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
911 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
912 return STATUS_INVALID_BUFFER_SIZE
;
918 CollectionInformation
= Irp
->AssociatedIrp
.SystemBuffer
;
919 ASSERT(CollectionInformation
);
922 // get collection description
924 CollectionDescription
= HidClassPDO_GetCollectionDescription(&CommonDeviceExtension
->DeviceDescription
,
925 PDODeviceExtension
->CollectionNumber
);
926 ASSERT(CollectionDescription
);
929 // init result buffer
931 CollectionInformation
->DescriptorSize
= CollectionDescription
->PreparsedDataLength
;
932 CollectionInformation
->Polled
= CommonDeviceExtension
->DriverExtension
->DevicesArePolled
;
933 CollectionInformation
->VendorID
= CommonDeviceExtension
->Attributes
.VendorID
;
934 CollectionInformation
->ProductID
= CommonDeviceExtension
->Attributes
.ProductID
;
935 CollectionInformation
->VersionNumber
= CommonDeviceExtension
->Attributes
.VersionNumber
;
940 Irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
941 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
942 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
943 return STATUS_SUCCESS
;
945 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
948 // get collection description
950 CollectionDescription
= HidClassPDO_GetCollectionDescription(&CommonDeviceExtension
->DeviceDescription
,
951 PDODeviceExtension
->CollectionNumber
);
952 ASSERT(CollectionDescription
);
955 // check if output buffer is big enough
957 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< CollectionDescription
->PreparsedDataLength
)
960 // invalid buffer size
962 Irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
963 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
964 return STATUS_INVALID_BUFFER_SIZE
;
970 ASSERT(Irp
->UserBuffer
);
971 RtlCopyMemory(Irp
->UserBuffer
, CollectionDescription
->PreparsedData
, CollectionDescription
->PreparsedDataLength
);
976 Irp
->IoStatus
.Information
= CollectionDescription
->PreparsedDataLength
;
977 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
978 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
979 return STATUS_SUCCESS
;
981 case IOCTL_HID_GET_FEATURE
:
985 IO_STATUS_BLOCK IoStatusBlock
;
986 HID_XFER_PACKET XferPacket
;
988 PHIDP_REPORT_IDS ReportDescription
;
990 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< 1)
992 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
993 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
994 return STATUS_INVALID_PARAMETER
;
996 ReportDescription
= HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension
->Common
.DeviceDescription
, ((PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
)[0]);
997 if (!ReportDescription
|| IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< ReportDescription
->FeatureLength
)
999 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1000 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1001 return STATUS_INVALID_PARAMETER
;
1004 RtlZeroMemory(&XferPacket
, sizeof(XferPacket
));
1005 XferPacket
.reportBufferLen
= ReportDescription
->FeatureLength
;
1006 XferPacket
.reportBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
1007 XferPacket
.reportId
= ((PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
)[0];
1008 if (!XferPacket
.reportBuffer
)
1010 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1011 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1012 return STATUS_INSUFFICIENT_RESOURCES
;
1015 SubIrp
= IoBuildDeviceIoControlRequest(
1016 IOCTL_HID_GET_FEATURE
,
1017 CommonDeviceExtension
->HidDeviceExtension
.NextDeviceObject
,
1025 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
1026 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1027 return STATUS_NOT_IMPLEMENTED
;
1029 SubIrp
->UserBuffer
= &XferPacket
;
1030 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1031 Status
= IoCallDriver(CommonDeviceExtension
->HidDeviceExtension
.NextDeviceObject
, SubIrp
);
1032 if (Status
== STATUS_PENDING
)
1034 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1035 Status
= IoStatusBlock
.Status
;
1037 Irp
->IoStatus
.Status
= Status
;
1038 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1041 case IOCTL_HID_SET_FEATURE
:
1045 IO_STATUS_BLOCK IoStatusBlock
;
1046 HID_XFER_PACKET XferPacket
;
1048 PHIDP_REPORT_IDS ReportDescription
;
1050 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< 1)
1052 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1053 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1054 return STATUS_INVALID_PARAMETER
;
1056 ReportDescription
= HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension
->Common
.DeviceDescription
, ((PUCHAR
)Irp
->AssociatedIrp
.SystemBuffer
)[0]);
1057 if (!ReportDescription
|| IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< ReportDescription
->FeatureLength
)
1059 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1060 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1061 return STATUS_INVALID_PARAMETER
;
1064 RtlZeroMemory(&XferPacket
, sizeof(XferPacket
));
1065 XferPacket
.reportBufferLen
= ReportDescription
->FeatureLength
;
1066 XferPacket
.reportBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
1067 XferPacket
.reportId
= XferPacket
.reportBuffer
[0];
1069 SubIrp
= IoBuildDeviceIoControlRequest(
1070 IOCTL_HID_SET_FEATURE
,
1071 CommonDeviceExtension
->HidDeviceExtension
.NextDeviceObject
,
1079 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
1080 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1081 return STATUS_NOT_IMPLEMENTED
;
1083 SubIrp
->UserBuffer
= &XferPacket
;
1084 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1085 Status
= IoCallDriver(CommonDeviceExtension
->HidDeviceExtension
.NextDeviceObject
, SubIrp
);
1086 if (Status
== STATUS_PENDING
)
1088 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1089 Status
= IoStatusBlock
.Status
;
1091 Irp
->IoStatus
.Status
= Status
;
1092 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1097 DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
1098 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
1099 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1100 return STATUS_NOT_IMPLEMENTED
;
1107 HidClass_InternalDeviceControl(
1108 IN PDEVICE_OBJECT DeviceObject
,
1113 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
1114 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1115 return STATUS_NOT_IMPLEMENTED
;
1121 IN PDEVICE_OBJECT DeviceObject
,
1124 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
1125 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
1127 if (CommonDeviceExtension
->IsFDO
)
1129 IoCopyCurrentIrpStackLocationToNext(Irp
);
1130 return HidClassFDO_DispatchRequest(DeviceObject
, Irp
);
1134 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1135 PoStartNextPowerIrp(Irp
);
1136 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1137 return STATUS_SUCCESS
;
1144 IN PDEVICE_OBJECT DeviceObject
,
1147 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
1150 // get common device extension
1152 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
1155 // check type of device object
1157 if (CommonDeviceExtension
->IsFDO
)
1162 return HidClassFDO_PnP(DeviceObject
, Irp
);
1169 return HidClassPDO_PnP(DeviceObject
, Irp
);
1175 HidClass_DispatchDefault(
1176 IN PDEVICE_OBJECT DeviceObject
,
1179 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension
;
1182 // get common device extension
1184 CommonDeviceExtension
= DeviceObject
->DeviceExtension
;
1187 // FIXME: support PDO
1189 ASSERT(CommonDeviceExtension
->IsFDO
== TRUE
);
1192 // skip current irp stack location
1194 IoSkipCurrentIrpStackLocation(Irp
);
1197 // dispatch to lower device object
1199 return IoCallDriver(CommonDeviceExtension
->HidDeviceExtension
.NextDeviceObject
, Irp
);
1205 IN PDEVICE_OBJECT DeviceObject
,
1208 PIO_STACK_LOCATION IoStack
;
1211 // get current stack location
1213 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
1214 DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack
->MajorFunction
, IoStack
->MinorFunction
);
1217 // dispatch request based on major function
1219 switch (IoStack
->MajorFunction
)
1222 return HidClass_Create(DeviceObject
, Irp
);
1224 return HidClass_Close(DeviceObject
, Irp
);
1226 return HidClass_Read(DeviceObject
, Irp
);
1228 return HidClass_Write(DeviceObject
, Irp
);
1229 case IRP_MJ_DEVICE_CONTROL
:
1230 return HidClass_DeviceControl(DeviceObject
, Irp
);
1231 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
1232 return HidClass_InternalDeviceControl(DeviceObject
, Irp
);
1234 return HidClass_Power(DeviceObject
, Irp
);
1236 return HidClass_PnP(DeviceObject
, Irp
);
1238 return HidClass_DispatchDefault(DeviceObject
, Irp
);
1244 HidRegisterMinidriver(
1245 IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration
)
1248 PHIDCLASS_DRIVER_EXTENSION DriverExtension
;
1250 /* check if the version matches */
1251 if (MinidriverRegistration
->Revision
> HID_REVISION
)
1253 /* revision mismatch */
1255 return STATUS_REVISION_MISMATCH
;
1258 /* now allocate the driver object extension */
1259 Status
= IoAllocateDriverObjectExtension(MinidriverRegistration
->DriverObject
,
1260 ClientIdentificationAddress
,
1261 sizeof(HIDCLASS_DRIVER_EXTENSION
),
1262 (PVOID
*)&DriverExtension
);
1263 if (!NT_SUCCESS(Status
))
1265 /* failed to allocate driver extension */
1270 /* zero driver extension */
1271 RtlZeroMemory(DriverExtension
, sizeof(HIDCLASS_DRIVER_EXTENSION
));
1273 /* init driver extension */
1274 DriverExtension
->DriverObject
= MinidriverRegistration
->DriverObject
;
1275 DriverExtension
->DeviceExtensionSize
= MinidriverRegistration
->DeviceExtensionSize
;
1276 DriverExtension
->DevicesArePolled
= MinidriverRegistration
->DevicesArePolled
;
1277 DriverExtension
->AddDevice
= MinidriverRegistration
->DriverObject
->DriverExtension
->AddDevice
;
1278 DriverExtension
->DriverUnload
= MinidriverRegistration
->DriverObject
->DriverUnload
;
1280 /* copy driver dispatch routines */
1281 RtlCopyMemory(DriverExtension
->MajorFunction
,
1282 MinidriverRegistration
->DriverObject
->MajorFunction
,
1283 sizeof(PDRIVER_DISPATCH
) * (IRP_MJ_MAXIMUM_FUNCTION
+ 1));
1285 /* initialize lock */
1286 KeInitializeSpinLock(&DriverExtension
->Lock
);
1288 /* now replace dispatch routines */
1289 DriverExtension
->DriverObject
->DriverExtension
->AddDevice
= HidClassAddDevice
;
1290 DriverExtension
->DriverObject
->DriverUnload
= HidClassDriverUnload
;
1291 DriverExtension
->DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = HidClassDispatch
;
1292 DriverExtension
->DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = HidClassDispatch
;
1293 DriverExtension
->DriverObject
->MajorFunction
[IRP_MJ_READ
] = HidClassDispatch
;
1294 DriverExtension
->DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = HidClassDispatch
;
1295 DriverExtension
->DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = HidClassDispatch
;
1296 DriverExtension
->DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = HidClassDispatch
;
1297 DriverExtension
->DriverObject
->MajorFunction
[IRP_MJ_POWER
] = HidClassDispatch
;
1298 DriverExtension
->DriverObject
->MajorFunction
[IRP_MJ_PNP
] = HidClassDispatch
;
1301 return STATUS_SUCCESS
;