xref: /reactos/drivers/hid/hidclass/hidclass.c (revision 9393fc32)
1 /*
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
6  * PROGRAMMERS:
7  *              Michael Martin (michael.martin@reactos.org)
8  *              Johannes Anderwald (johannes.anderwald@reactos.org)
9  */
10 
11 #include "precomp.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 static LPWSTR ClientIdentificationAddress = L"HIDCLASS";
17 static ULONG HidClassDeviceNumber = 0;
18 
19 NTSTATUS
20 NTAPI
21 DllInitialize(
22     IN PUNICODE_STRING RegistryPath)
23 {
24     return STATUS_SUCCESS;
25 }
26 
27 NTSTATUS
28 NTAPI
29 DllUnload(VOID)
30 {
31     return STATUS_SUCCESS;
32 }
33 
34 NTSTATUS
35 NTAPI
36 HidClassAddDevice(
37     IN PDRIVER_OBJECT DriverObject,
38     IN PDEVICE_OBJECT PhysicalDeviceObject)
39 {
40     WCHAR CharDeviceName[64];
41     NTSTATUS Status;
42     UNICODE_STRING DeviceName;
43     PDEVICE_OBJECT NewDeviceObject;
44     PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
45     ULONG DeviceExtensionSize;
46     PHIDCLASS_DRIVER_EXTENSION DriverExtension;
47 
48     /* increment device number */
49     InterlockedIncrement((PLONG)&HidClassDeviceNumber);
50 
51     /* construct device name */
52     swprintf(CharDeviceName, L"\\Device\\_HID%08x", HidClassDeviceNumber);
53 
54     /* initialize device name */
55     RtlInitUnicodeString(&DeviceName, CharDeviceName);
56 
57     /* get driver object extension */
58     DriverExtension = IoGetDriverObjectExtension(DriverObject, ClientIdentificationAddress);
59     if (!DriverExtension)
60     {
61         /* device removed */
62         ASSERT(FALSE);
63         return STATUS_DEVICE_CONFIGURATION_ERROR;
64     }
65 
66     /* calculate device extension size */
67     DeviceExtensionSize = sizeof(HIDCLASS_FDO_EXTENSION) + DriverExtension->DeviceExtensionSize;
68 
69     /* now create the device */
70     Status = IoCreateDevice(DriverObject, DeviceExtensionSize, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &NewDeviceObject);
71     if (!NT_SUCCESS(Status))
72     {
73         /* failed to create device object */
74         ASSERT(FALSE);
75         return Status;
76     }
77 
78     /* get device extension */
79     FDODeviceExtension = NewDeviceObject->DeviceExtension;
80 
81     /* zero device extension */
82     RtlZeroMemory(FDODeviceExtension, sizeof(HIDCLASS_FDO_EXTENSION));
83 
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)
91     {
92         /* no PDO */
93         IoDeleteDevice(NewDeviceObject);
94         DPRINT1("[HIDCLASS] failed to attach to device stack\n");
95         return STATUS_DEVICE_REMOVED;
96     }
97 
98     /* sanity check */
99     ASSERT(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
100 
101     /* increment stack size */
102     NewDeviceObject->StackSize++;
103 
104     /* init device object */
105     NewDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
106     NewDeviceObject->Flags  &= ~DO_DEVICE_INITIALIZING;
107 
108     /* now call driver provided add device routine */
109     ASSERT(DriverExtension->AddDevice != 0);
110     Status = DriverExtension->AddDevice(DriverObject, NewDeviceObject);
111     if (!NT_SUCCESS(Status))
112     {
113         /* failed */
114         DPRINT1("HIDCLASS: AddDevice failed with %x\n", Status);
115         IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
116         IoDeleteDevice(NewDeviceObject);
117         return Status;
118     }
119 
120     /* succeeded */
121     return Status;
122 }
123 
124 VOID
125 NTAPI
126 HidClassDriverUnload(
127     IN PDRIVER_OBJECT DriverObject)
128 {
129     UNIMPLEMENTED;
130 }
131 
132 NTSTATUS
133 NTAPI
134 HidClass_Create(
135     IN PDEVICE_OBJECT DeviceObject,
136     IN PIRP Irp)
137 {
138     PIO_STACK_LOCATION IoStack;
139     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
140     PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
141     PHIDCLASS_FILEOP_CONTEXT Context;
142 
143     //
144     // get device extension
145     //
146     CommonDeviceExtension = DeviceObject->DeviceExtension;
147     if (CommonDeviceExtension->IsFDO)
148     {
149          //
150          // only supported for PDO
151          //
152          Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
153          IoCompleteRequest(Irp, IO_NO_INCREMENT);
154          return STATUS_UNSUCCESSFUL;
155     }
156 
157     //
158     // must be a PDO
159     //
160     ASSERT(CommonDeviceExtension->IsFDO == FALSE);
161 
162     //
163     // get device extension
164     //
165     PDODeviceExtension = DeviceObject->DeviceExtension;
166 
167     //
168     // get stack location
169     //
170     IoStack = IoGetCurrentIrpStackLocation(Irp);
171 
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);
175 
176     //
177     // allocate context
178     //
179     Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT), HIDCLASS_TAG);
180     if (!Context)
181     {
182         //
183         // no memory
184         //
185         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
186         IoCompleteRequest(Irp, IO_NO_INCREMENT);
187         return STATUS_INSUFFICIENT_RESOURCES;
188     }
189 
190     //
191     // init context
192     //
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);
199 
200     //
201     // store context
202     //
203     ASSERT(IoStack->FileObject);
204     IoStack->FileObject->FsContext = Context;
205 
206     //
207     // done
208     //
209     Irp->IoStatus.Status = STATUS_SUCCESS;
210     IoCompleteRequest(Irp, IO_NO_INCREMENT);
211     return STATUS_SUCCESS;
212 }
213 
214 NTSTATUS
215 NTAPI
216 HidClass_Close(
217     IN PDEVICE_OBJECT DeviceObject,
218     IN PIRP Irp)
219 {
220     PIO_STACK_LOCATION IoStack;
221     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
222     PHIDCLASS_FILEOP_CONTEXT IrpContext;
223     BOOLEAN IsRequestPending = FALSE;
224     KIRQL OldLevel;
225     PLIST_ENTRY Entry;
226     PIRP ListIrp;
227 
228     //
229     // get device extension
230     //
231     CommonDeviceExtension = DeviceObject->DeviceExtension;
232 
233     //
234     // is it a FDO request
235     //
236     if (CommonDeviceExtension->IsFDO)
237     {
238         //
239         // how did the request get there
240         //
241         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1;
242         IoCompleteRequest(Irp, IO_NO_INCREMENT);
243         return STATUS_INVALID_PARAMETER_1;
244     }
245 
246     //
247     // get stack location
248     //
249     IoStack = IoGetCurrentIrpStackLocation(Irp);
250 
251     //
252     // sanity checks
253     //
254     ASSERT(IoStack->FileObject);
255     ASSERT(IoStack->FileObject->FsContext);
256 
257     //
258     // get irp context
259     //
260     IrpContext = IoStack->FileObject->FsContext;
261     ASSERT(IrpContext);
262 
263     //
264     // acquire lock
265     //
266     KeAcquireSpinLock(&IrpContext->Lock, &OldLevel);
267 
268     if (!IsListEmpty(&IrpContext->ReadPendingIrpListHead))
269     {
270         //
271         // FIXME cancel irp
272         //
273         IsRequestPending = TRUE;
274     }
275 
276     //
277     // signal stop
278     //
279     IrpContext->StopInProgress = TRUE;
280 
281     //
282     // release lock
283     //
284     KeReleaseSpinLock(&IrpContext->Lock, OldLevel);
285 
286     if (IsRequestPending)
287     {
288         //
289         // wait for request to complete
290         //
291         DPRINT1("[HIDCLASS] Waiting for read irp completion...\n");
292         KeWaitForSingleObject(&IrpContext->IrpReadComplete, Executive, KernelMode, FALSE, NULL);
293     }
294 
295     //
296     // acquire lock
297     //
298     KeAcquireSpinLock(&IrpContext->Lock, &OldLevel);
299 
300     //
301     // sanity check
302     //
303     ASSERT(IsListEmpty(&IrpContext->ReadPendingIrpListHead));
304 
305     //
306     // now free all irps
307     //
308     while (!IsListEmpty(&IrpContext->IrpCompletedListHead))
309     {
310         //
311         // remove head irp
312         //
313         Entry = RemoveHeadList(&IrpContext->IrpCompletedListHead);
314 
315         //
316         // get irp
317         //
318         ListIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
319 
320         //
321         // free the irp
322         //
323         IoFreeIrp(ListIrp);
324     }
325 
326     //
327     // release lock
328     //
329     KeReleaseSpinLock(&IrpContext->Lock, OldLevel);
330 
331     //
332     // remove context
333     //
334     IoStack->FileObject->FsContext = NULL;
335 
336     //
337     // free context
338     //
339     ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
340 
341     //
342     // complete request
343     //
344     Irp->IoStatus.Status = STATUS_SUCCESS;
345     IoCompleteRequest(Irp, IO_NO_INCREMENT);
346     return STATUS_SUCCESS;
347 }
348 
349 NTSTATUS
350 NTAPI
351 HidClass_ReadCompleteIrp(
352     IN PDEVICE_OBJECT DeviceObject,
353     IN PIRP Irp,
354     IN PVOID Ctx)
355 {
356     PHIDCLASS_IRP_CONTEXT IrpContext;
357     KIRQL OldLevel;
358     PUCHAR Address;
359     ULONG Offset;
360     PHIDP_COLLECTION_DESC CollectionDescription;
361     PHIDP_REPORT_IDS ReportDescription;
362     BOOLEAN IsEmpty;
363 
364     //
365     // get irp context
366     //
367     IrpContext = Ctx;
368 
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);
376 
377     //
378     // copy result
379     //
380     if (Irp->IoStatus.Information)
381     {
382         //
383         // get address
384         //
385         Address = MmGetSystemAddressForMdlSafe(IrpContext->OriginalIrp->MdlAddress, NormalPagePriority);
386         if (Address)
387         {
388             //
389             // reports may have a report id prepended
390             //
391             Offset = 0;
392 
393             //
394             // get collection description
395             //
396             CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
397                                                                          IrpContext->FileOp->DeviceExtension->CollectionNumber);
398             ASSERT(CollectionDescription);
399 
400             //
401             // get report description
402             //
403             ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
404                                                                  IrpContext->FileOp->DeviceExtension->CollectionNumber);
405             ASSERT(ReportDescription);
406 
407             if (CollectionDescription && ReportDescription)
408             {
409                 //
410                 // calculate offset
411                 //
412                 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength);
413                 Offset = CollectionDescription->InputLength - ReportDescription->InputLength;
414             }
415 
416             //
417             // copy result
418             //
419             RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength);
420         }
421     }
422 
423     //
424     // copy result status
425     //
426     IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
427     IrpContext->OriginalIrp->IoStatus.Information = Irp->IoStatus.Information;
428 
429     //
430     // free input report buffer
431     //
432     ExFreePoolWithTag(IrpContext->InputReportBuffer, HIDCLASS_TAG);
433 
434     //
435     // remove us from pending list
436     //
437     KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel);
438 
439     //
440     // remove from pending list
441     //
442     RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
443 
444     //
445     // is list empty
446     //
447     IsEmpty = IsListEmpty(&IrpContext->FileOp->ReadPendingIrpListHead);
448 
449     //
450     // insert into completed list
451     //
452     InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry);
453 
454     //
455     // release lock
456     //
457     KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel);
458 
459     //
460     // complete original request
461     //
462     IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT);
463 
464 
465     DPRINT("StopInProgress %x IsEmpty %x\n", IrpContext->FileOp->StopInProgress, IsEmpty);
466     if (IrpContext->FileOp->StopInProgress && IsEmpty)
467     {
468         //
469         // last pending irp
470         //
471         DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
472         KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE);
473     }
474 
475     if (IrpContext->FileOp->StopInProgress && IsEmpty)
476     {
477         //
478         // last pending irp
479         //
480         DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
481         KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE);
482     }
483 
484     //
485     // free irp context
486     //
487     ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
488 
489     //
490     // done
491     //
492     return STATUS_MORE_PROCESSING_REQUIRED;
493 }
494 
495 PIRP
496 HidClass_GetIrp(
497     IN PHIDCLASS_FILEOP_CONTEXT Context)
498 {
499    KIRQL OldLevel;
500    PIRP Irp = NULL;
501    PLIST_ENTRY ListEntry;
502 
503     //
504     // acquire lock
505     //
506     KeAcquireSpinLock(&Context->Lock, &OldLevel);
507 
508     //
509     // is list empty?
510     //
511     if (!IsListEmpty(&Context->IrpCompletedListHead))
512     {
513         //
514         // grab first entry
515         //
516         ListEntry = RemoveHeadList(&Context->IrpCompletedListHead);
517 
518         //
519         // get irp
520         //
521         Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
522     }
523 
524     //
525     // release lock
526     //
527     KeReleaseSpinLock(&Context->Lock, OldLevel);
528 
529     //
530     // done
531     //
532     return Irp;
533 }
534 
535 NTSTATUS
536 HidClass_BuildIrp(
537     IN PDEVICE_OBJECT DeviceObject,
538     IN PIRP RequestIrp,
539     IN PHIDCLASS_FILEOP_CONTEXT Context,
540     IN ULONG DeviceIoControlCode,
541     IN ULONG BufferLength,
542     OUT PIRP *OutIrp,
543     OUT PHIDCLASS_IRP_CONTEXT *OutIrpContext)
544 {
545     PIRP Irp;
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;
551 
552     //
553     // get an irp from fresh list
554     //
555     Irp = HidClass_GetIrp(Context);
556     if (!Irp)
557     {
558         //
559         // build new irp
560         //
561         Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
562         if (!Irp)
563         {
564             //
565             // no memory
566             //
567             return STATUS_INSUFFICIENT_RESOURCES;
568         }
569     }
570     else
571     {
572         //
573         // re-use irp
574         //
575         IoReuseIrp(Irp, STATUS_SUCCESS);
576     }
577 
578     //
579     // allocate completion context
580     //
581     IrpContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT), HIDCLASS_TAG);
582     if (!IrpContext)
583     {
584         //
585         // no memory
586         //
587         IoFreeIrp(Irp);
588         return STATUS_INSUFFICIENT_RESOURCES;
589     }
590 
591     //
592     // get device extension
593     //
594     PDODeviceExtension = DeviceObject->DeviceExtension;
595     ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
596 
597     //
598     // init irp context
599     //
600     RtlZeroMemory(IrpContext, sizeof(HIDCLASS_IRP_CONTEXT));
601     IrpContext->OriginalIrp = RequestIrp;
602     IrpContext->FileOp = Context;
603 
604     //
605     // get collection description
606     //
607     CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
608                                                                  IrpContext->FileOp->DeviceExtension->CollectionNumber);
609     ASSERT(CollectionDescription);
610 
611     //
612     // get report description
613     //
614     ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
615                                                          IrpContext->FileOp->DeviceExtension->CollectionNumber);
616     ASSERT(ReportDescription);
617 
618     //
619     // sanity check
620     //
621     ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength);
622 
623     if (Context->StopInProgress)
624     {
625          //
626          // stop in progress
627          //
628          DPRINT1("[HIDCLASS] Stop In Progress\n");
629          Irp->IoStatus.Status = STATUS_CANCELLED;
630          IoCompleteRequest(Irp, IO_NO_INCREMENT);
631          return STATUS_CANCELLED;
632 
633     }
634 
635     //
636     // store report length
637     //
638     IrpContext->InputReportBufferLength = ReportDescription->InputLength;
639 
640     //
641     // allocate buffer
642     //
643     IrpContext->InputReportBuffer = ExAllocatePoolWithTag(NonPagedPool, IrpContext->InputReportBufferLength, HIDCLASS_TAG);
644     if (!IrpContext->InputReportBuffer)
645     {
646         //
647         // no memory
648         //
649         IoFreeIrp(Irp);
650         ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
651         return STATUS_INSUFFICIENT_RESOURCES;
652     }
653 
654     //
655     // get stack location
656     //
657     IoStack = IoGetNextIrpStackLocation(Irp);
658 
659     //
660     // init stack location
661     //
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;
669 
670     //
671     // store result
672     //
673     *OutIrp = Irp;
674     *OutIrpContext = IrpContext;
675 
676     //
677     // done
678     //
679     return STATUS_SUCCESS;
680 }
681 
682 NTSTATUS
683 NTAPI
684 HidClass_Read(
685     IN PDEVICE_OBJECT DeviceObject,
686     IN PIRP Irp)
687 {
688     PIO_STACK_LOCATION IoStack;
689     PHIDCLASS_FILEOP_CONTEXT Context;
690     KIRQL OldLevel;
691     NTSTATUS Status;
692     PIRP NewIrp;
693     PHIDCLASS_IRP_CONTEXT NewIrpContext;
694     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
695 
696     //
697     // get current stack location
698     //
699     IoStack = IoGetCurrentIrpStackLocation(Irp);
700 
701     //
702     // get device extension
703     //
704     CommonDeviceExtension = DeviceObject->DeviceExtension;
705     ASSERT(CommonDeviceExtension->IsFDO == FALSE);
706 
707     //
708     // sanity check
709     //
710     ASSERT(IoStack->FileObject);
711     ASSERT(IoStack->FileObject->FsContext);
712 
713     //
714     // get context
715     //
716     Context = IoStack->FileObject->FsContext;
717     ASSERT(Context);
718 
719     //
720     // FIXME support polled devices
721     //
722     ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE);
723 
724     if (Context->StopInProgress)
725     {
726         //
727         // stop in progress
728         //
729         DPRINT1("[HIDCLASS] Stop In Progress\n");
730         Irp->IoStatus.Status = STATUS_CANCELLED;
731         IoCompleteRequest(Irp, IO_NO_INCREMENT);
732         return STATUS_CANCELLED;
733     }
734 
735     //
736     // build irp request
737     //
738     Status = HidClass_BuildIrp(DeviceObject,
739                                Irp,
740                                Context,
741                                IOCTL_HID_READ_REPORT,
742                                IoStack->Parameters.Read.Length,
743                                &NewIrp,
744                                &NewIrpContext);
745     if (!NT_SUCCESS(Status))
746     {
747         //
748         // failed
749         //
750         DPRINT1("HidClass_BuildIrp failed with %x\n", Status);
751         Irp->IoStatus.Status = Status;
752         IoCompleteRequest(Irp, IO_NO_INCREMENT);
753         return Status;
754     }
755 
756     //
757     // acquire lock
758     //
759     KeAcquireSpinLock(&Context->Lock, &OldLevel);
760 
761     //
762     // insert irp into pending list
763     //
764     InsertTailList(&Context->ReadPendingIrpListHead, &NewIrp->Tail.Overlay.ListEntry);
765 
766     //
767     // set completion routine
768     //
769     IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE);
770 
771     //
772     // make next location current
773     //
774     IoSetNextIrpStackLocation(NewIrp);
775 
776     //
777     // release spin lock
778     //
779     KeReleaseSpinLock(&Context->Lock, OldLevel);
780 
781     //
782     // mark irp pending
783     //
784     IoMarkIrpPending(Irp);
785 
786     //
787     // let's dispatch the request
788     //
789     ASSERT(Context->DeviceExtension);
790     Status = Context->DeviceExtension->Common.DriverExtension->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](Context->DeviceExtension->FDODeviceObject, NewIrp);
791 
792     //
793     // complete
794     //
795     return STATUS_PENDING;
796 }
797 
798 NTSTATUS
799 NTAPI
800 HidClass_Write(
801     IN PDEVICE_OBJECT DeviceObject,
802     IN PIRP Irp)
803 {
804     PIO_STACK_LOCATION IoStack;
805     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
806     PIRP SubIrp;
807     KEVENT Event;
808     IO_STATUS_BLOCK IoStatusBlock;
809     HID_XFER_PACKET XferPacket;
810     NTSTATUS Status;
811     ULONG Length;
812 
813     IoStack = IoGetCurrentIrpStackLocation(Irp);
814     Length = IoStack->Parameters.Write.Length;
815     if (Length < 1)
816     {
817         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
818         IoCompleteRequest(Irp, IO_NO_INCREMENT);
819         return STATUS_INVALID_PARAMETER;
820     }
821 
822     RtlZeroMemory(&XferPacket, sizeof(XferPacket));
823     XferPacket.reportBufferLen = Length;
824     XferPacket.reportBuffer = Irp->UserBuffer;
825     XferPacket.reportId = XferPacket.reportBuffer[0];
826 
827     CommonDeviceExtension = DeviceObject->DeviceExtension;
828     SubIrp = IoBuildDeviceIoControlRequest(
829         IOCTL_HID_WRITE_REPORT,
830         CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
831         NULL, 0,
832         NULL, 0,
833         TRUE,
834         &Event,
835         &IoStatusBlock);
836     if (!SubIrp)
837     {
838         Irp->IoStatus.Status = STATUS_NO_MEMORY;
839         IoCompleteRequest(Irp, IO_NO_INCREMENT);
840         return STATUS_NOT_IMPLEMENTED;
841     }
842     SubIrp->UserBuffer = &XferPacket;
843     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
844     Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
845     if (Status == STATUS_PENDING)
846     {
847         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
848         Status = IoStatusBlock.Status;
849     }
850     Irp->IoStatus.Status = Status;
851     IoCompleteRequest(Irp, IO_NO_INCREMENT);
852     return Status;
853 }
854 
855 NTSTATUS
856 NTAPI
857 HidClass_DeviceControl(
858     IN PDEVICE_OBJECT DeviceObject,
859     IN PIRP Irp)
860 {
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;
866 
867     //
868     // get device extension
869     //
870     CommonDeviceExtension = DeviceObject->DeviceExtension;
871 
872     //
873     // only PDO are supported
874     //
875     if (CommonDeviceExtension->IsFDO)
876     {
877         //
878         // invalid request
879         //
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;
884     }
885 
886     ASSERT(CommonDeviceExtension->IsFDO == FALSE);
887 
888     //
889     // get pdo device extension
890     //
891     PDODeviceExtension = DeviceObject->DeviceExtension;
892 
893     //
894     // get stack location
895     //
896     IoStack = IoGetCurrentIrpStackLocation(Irp);
897 
898     switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
899     {
900         case IOCTL_HID_GET_COLLECTION_INFORMATION:
901         {
902             //
903             // check if output buffer is big enough
904             //
905             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
906             {
907                 //
908                 // invalid buffer size
909                 //
910                 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
911                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
912                 return STATUS_INVALID_BUFFER_SIZE;
913             }
914 
915             //
916             // get output buffer
917             //
918             CollectionInformation = Irp->AssociatedIrp.SystemBuffer;
919             ASSERT(CollectionInformation);
920 
921             //
922             // get collection description
923             //
924             CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
925                                                                          PDODeviceExtension->CollectionNumber);
926             ASSERT(CollectionDescription);
927 
928             //
929             // init result buffer
930             //
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;
936 
937             //
938             // complete request
939             //
940             Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
941             Irp->IoStatus.Status = STATUS_SUCCESS;
942             IoCompleteRequest(Irp, IO_NO_INCREMENT);
943             return STATUS_SUCCESS;
944         }
945         case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
946         {
947             //
948             // get collection description
949             //
950             CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
951                                                                          PDODeviceExtension->CollectionNumber);
952             ASSERT(CollectionDescription);
953 
954             //
955             // check if output buffer is big enough
956             //
957             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < CollectionDescription->PreparsedDataLength)
958             {
959                 //
960                 // invalid buffer size
961                 //
962                 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
963                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
964                 return STATUS_INVALID_BUFFER_SIZE;
965             }
966 
967             //
968             // copy result
969             //
970             ASSERT(Irp->UserBuffer);
971             RtlCopyMemory(Irp->UserBuffer, CollectionDescription->PreparsedData, CollectionDescription->PreparsedDataLength);
972 
973             //
974             // complete request
975             //
976             Irp->IoStatus.Information = CollectionDescription->PreparsedDataLength;
977             Irp->IoStatus.Status = STATUS_SUCCESS;
978             IoCompleteRequest(Irp, IO_NO_INCREMENT);
979             return STATUS_SUCCESS;
980         }
981         case IOCTL_HID_GET_FEATURE:
982         {
983             PIRP SubIrp;
984             KEVENT Event;
985             IO_STATUS_BLOCK IoStatusBlock;
986             HID_XFER_PACKET XferPacket;
987             NTSTATUS Status;
988             PHIDP_REPORT_IDS ReportDescription;
989 
990             if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1)
991             {
992                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
993                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
994                 return STATUS_INVALID_PARAMETER;
995             }
996             ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]);
997             if (!ReportDescription || IoStack->Parameters.DeviceIoControl.OutputBufferLength < ReportDescription->FeatureLength)
998             {
999                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1000                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1001                 return STATUS_INVALID_PARAMETER;
1002             }
1003 
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)
1009             {
1010                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1011                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1012                 return STATUS_INSUFFICIENT_RESOURCES;
1013             }
1014 
1015             SubIrp = IoBuildDeviceIoControlRequest(
1016                 IOCTL_HID_GET_FEATURE,
1017                 CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
1018                 NULL, 0,
1019                 NULL, 0,
1020                 TRUE,
1021                 &Event,
1022                 &IoStatusBlock);
1023             if (!SubIrp)
1024             {
1025                 Irp->IoStatus.Status = STATUS_NO_MEMORY;
1026                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1027                 return STATUS_NOT_IMPLEMENTED;
1028             }
1029             SubIrp->UserBuffer = &XferPacket;
1030             KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1031             Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
1032             if (Status == STATUS_PENDING)
1033             {
1034                 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1035                 Status = IoStatusBlock.Status;
1036             }
1037             Irp->IoStatus.Status = Status;
1038             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1039             return Status;
1040         }
1041         case IOCTL_HID_SET_FEATURE:
1042         {
1043             PIRP SubIrp;
1044             KEVENT Event;
1045             IO_STATUS_BLOCK IoStatusBlock;
1046             HID_XFER_PACKET XferPacket;
1047             NTSTATUS Status;
1048             PHIDP_REPORT_IDS ReportDescription;
1049 
1050             if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1)
1051             {
1052                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1053                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1054                 return STATUS_INVALID_PARAMETER;
1055             }
1056             ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]);
1057             if (!ReportDescription || IoStack->Parameters.DeviceIoControl.InputBufferLength < ReportDescription->FeatureLength)
1058             {
1059                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1060                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1061                 return STATUS_INVALID_PARAMETER;
1062             }
1063 
1064             RtlZeroMemory(&XferPacket, sizeof(XferPacket));
1065             XferPacket.reportBufferLen = ReportDescription->FeatureLength;
1066             XferPacket.reportBuffer = Irp->AssociatedIrp.SystemBuffer;
1067             XferPacket.reportId = XferPacket.reportBuffer[0];
1068 
1069             SubIrp = IoBuildDeviceIoControlRequest(
1070                 IOCTL_HID_SET_FEATURE,
1071                 CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
1072                 NULL, 0,
1073                 NULL, 0,
1074                 TRUE,
1075                 &Event,
1076                 &IoStatusBlock);
1077             if (!SubIrp)
1078             {
1079                 Irp->IoStatus.Status = STATUS_NO_MEMORY;
1080                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1081                 return STATUS_NOT_IMPLEMENTED;
1082             }
1083             SubIrp->UserBuffer = &XferPacket;
1084             KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1085             Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
1086             if (Status == STATUS_PENDING)
1087             {
1088                 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1089                 Status = IoStatusBlock.Status;
1090             }
1091             Irp->IoStatus.Status = Status;
1092             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1093             return Status;
1094         }
1095         default:
1096         {
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;
1101         }
1102     }
1103 }
1104 
1105 NTSTATUS
1106 NTAPI
1107 HidClass_InternalDeviceControl(
1108     IN PDEVICE_OBJECT DeviceObject,
1109     IN PIRP Irp)
1110 {
1111     UNIMPLEMENTED;
1112     ASSERT(FALSE);
1113     Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
1114     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1115     return STATUS_NOT_IMPLEMENTED;
1116 }
1117 
1118 NTSTATUS
1119 NTAPI
1120 HidClass_Power(
1121     IN PDEVICE_OBJECT DeviceObject,
1122     IN PIRP Irp)
1123 {
1124     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1125     CommonDeviceExtension = DeviceObject->DeviceExtension;
1126 
1127     if (CommonDeviceExtension->IsFDO)
1128     {
1129         IoCopyCurrentIrpStackLocationToNext(Irp);
1130         return HidClassFDO_DispatchRequest(DeviceObject, Irp);
1131     }
1132     else
1133     {
1134         Irp->IoStatus.Status = STATUS_SUCCESS;
1135         PoStartNextPowerIrp(Irp);
1136         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1137         return STATUS_SUCCESS;
1138     }
1139 }
1140 
1141 NTSTATUS
1142 NTAPI
1143 HidClass_PnP(
1144     IN PDEVICE_OBJECT DeviceObject,
1145     IN PIRP Irp)
1146 {
1147     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1148 
1149     //
1150     // get common device extension
1151     //
1152     CommonDeviceExtension = DeviceObject->DeviceExtension;
1153 
1154     //
1155     // check type of device object
1156     //
1157     if (CommonDeviceExtension->IsFDO)
1158     {
1159         //
1160         // handle request
1161         //
1162         return HidClassFDO_PnP(DeviceObject, Irp);
1163     }
1164     else
1165     {
1166         //
1167         // handle request
1168         //
1169         return HidClassPDO_PnP(DeviceObject, Irp);
1170     }
1171 }
1172 
1173 NTSTATUS
1174 NTAPI
1175 HidClass_DispatchDefault(
1176     IN PDEVICE_OBJECT DeviceObject,
1177     IN PIRP Irp)
1178 {
1179     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1180 
1181     //
1182     // get common device extension
1183     //
1184     CommonDeviceExtension = DeviceObject->DeviceExtension;
1185 
1186     //
1187     // FIXME: support PDO
1188     //
1189     ASSERT(CommonDeviceExtension->IsFDO == TRUE);
1190 
1191     //
1192     // skip current irp stack location
1193     //
1194     IoSkipCurrentIrpStackLocation(Irp);
1195 
1196     //
1197     // dispatch to lower device object
1198     //
1199     return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp);
1200 }
1201 
1202 NTSTATUS
1203 NTAPI
1204 HidClassDispatch(
1205     IN PDEVICE_OBJECT DeviceObject,
1206     IN PIRP Irp)
1207 {
1208     PIO_STACK_LOCATION IoStack;
1209 
1210     //
1211     // get current stack location
1212     //
1213     IoStack = IoGetCurrentIrpStackLocation(Irp);
1214     DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
1215 
1216     //
1217     // dispatch request based on major function
1218     //
1219     switch (IoStack->MajorFunction)
1220     {
1221         case IRP_MJ_CREATE:
1222             return HidClass_Create(DeviceObject, Irp);
1223         case IRP_MJ_CLOSE:
1224             return HidClass_Close(DeviceObject, Irp);
1225         case IRP_MJ_READ:
1226             return HidClass_Read(DeviceObject, Irp);
1227         case IRP_MJ_WRITE:
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);
1233         case IRP_MJ_POWER:
1234             return HidClass_Power(DeviceObject, Irp);
1235         case IRP_MJ_PNP:
1236             return HidClass_PnP(DeviceObject, Irp);
1237         default:
1238             return HidClass_DispatchDefault(DeviceObject, Irp);
1239     }
1240 }
1241 
1242 NTSTATUS
1243 NTAPI
1244 HidRegisterMinidriver(
1245     IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration)
1246 {
1247     NTSTATUS Status;
1248     PHIDCLASS_DRIVER_EXTENSION DriverExtension;
1249 
1250     /* check if the version matches */
1251     if (MinidriverRegistration->Revision > HID_REVISION)
1252     {
1253         /* revision mismatch */
1254         ASSERT(FALSE);
1255         return STATUS_REVISION_MISMATCH;
1256     }
1257 
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))
1264     {
1265         /* failed to allocate driver extension */
1266         ASSERT(FALSE);
1267         return Status;
1268     }
1269 
1270     /* zero driver extension */
1271     RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION));
1272 
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;
1279 
1280     /* copy driver dispatch routines */
1281     RtlCopyMemory(DriverExtension->MajorFunction,
1282                   MinidriverRegistration->DriverObject->MajorFunction,
1283                   sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1));
1284 
1285     /* initialize lock */
1286     KeInitializeSpinLock(&DriverExtension->Lock);
1287 
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;
1299 
1300     /* done */
1301     return STATUS_SUCCESS;
1302 }
1303