xref: /reactos/drivers/hid/hidclass/fdo.c (revision 1734f297)
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/fdo.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 NTSTATUS
17 NTAPI
18 HidClassFDO_QueryCapabilitiesCompletionRoutine(
19     IN PDEVICE_OBJECT DeviceObject,
20     IN PIRP Irp,
21     IN PVOID Context)
22 {
23     //
24     // set event
25     //
26     KeSetEvent(Context, 0, FALSE);
27 
28     //
29     // completion is done in the HidClassFDO_QueryCapabilities routine
30     //
31     return STATUS_MORE_PROCESSING_REQUIRED;
32 }
33 
34 NTSTATUS
35 HidClassFDO_QueryCapabilities(
36     IN PDEVICE_OBJECT DeviceObject,
37     IN OUT PDEVICE_CAPABILITIES Capabilities)
38 {
39     PIRP Irp;
40     KEVENT Event;
41     NTSTATUS Status;
42     PIO_STACK_LOCATION IoStack;
43     PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
44 
45     //
46     // get device extension
47     //
48     FDODeviceExtension = DeviceObject->DeviceExtension;
49     ASSERT(FDODeviceExtension->Common.IsFDO);
50 
51     //
52     // init event
53     //
54     KeInitializeEvent(&Event, NotificationEvent, FALSE);
55 
56     //
57     // now allocate the irp
58     //
59     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
60     if (!Irp)
61     {
62         //
63         // no memory
64         //
65         return STATUS_INSUFFICIENT_RESOURCES;
66     }
67 
68     //
69     // get next stack location
70     //
71     IoStack = IoGetNextIrpStackLocation(Irp);
72 
73     //
74     // init stack location
75     //
76     IoStack->MajorFunction = IRP_MJ_PNP;
77     IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
78     IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities;
79 
80     //
81     // set completion routine
82     //
83     IoSetCompletionRoutine(Irp, HidClassFDO_QueryCapabilitiesCompletionRoutine, &Event, TRUE, TRUE, TRUE);
84 
85     //
86     // init capabilities
87     //
88     RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
89     Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
90     Capabilities->Version = 1; // FIXME hardcoded constant
91     Capabilities->Address = MAXULONG;
92     Capabilities->UINumber = MAXULONG;
93 
94     //
95     // pnp irps have default completion code
96     //
97     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
98 
99     //
100     // call lower  device
101     //
102     Status = IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
103     if (Status == STATUS_PENDING)
104     {
105         //
106         // wait for completion
107         //
108         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
109     }
110 
111     //
112     // get status
113     //
114     Status = Irp->IoStatus.Status;
115 
116     //
117     // complete request
118     //
119     IoFreeIrp(Irp);
120 
121     //
122     // done
123     //
124     return Status;
125 }
126 
127 NTSTATUS
128 NTAPI
129 HidClassFDO_DispatchRequestSynchronousCompletion(
130     IN PDEVICE_OBJECT DeviceObject,
131     IN PIRP Irp,
132     IN PVOID Context)
133 {
134     //
135     // signal event
136     //
137     KeSetEvent(Context, 0, FALSE);
138 
139     //
140     // done
141     //
142     return STATUS_MORE_PROCESSING_REQUIRED;
143 }
144 
145 
146 NTSTATUS
147 HidClassFDO_DispatchRequestSynchronous(
148     IN PDEVICE_OBJECT DeviceObject,
149     IN PIRP Irp)
150 {
151     KEVENT Event;
152     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
153     NTSTATUS Status;
154     PIO_STACK_LOCATION IoStack;
155 
156     //
157     // init event
158     //
159     KeInitializeEvent(&Event, NotificationEvent, FALSE);
160 
161     //
162     // get device extension
163     //
164     CommonDeviceExtension = DeviceObject->DeviceExtension;
165 
166     //
167     // set completion routine
168     //
169     IoSetCompletionRoutine(Irp, HidClassFDO_DispatchRequestSynchronousCompletion, &Event, TRUE, TRUE, TRUE);
170 
171     ASSERT(Irp->CurrentLocation > 0);
172     //
173     // create stack location
174     //
175     IoSetNextIrpStackLocation(Irp);
176 
177     //
178     // get next stack location
179     //
180     IoStack = IoGetCurrentIrpStackLocation(Irp);
181 
182     //
183     // store device object
184     //
185     IoStack->DeviceObject = DeviceObject;
186 
187     //
188     // sanity check
189     //
190     ASSERT(CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction] != NULL);
191 
192     //
193     // call minidriver (hidusb)
194     //
195     Status = CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction](DeviceObject, Irp);
196 
197     //
198     // wait for the request to finish
199     //
200     if (Status == STATUS_PENDING)
201     {
202         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
203 
204         //
205         // update status
206         //
207         Status = Irp->IoStatus.Status;
208     }
209 
210     //
211     // done
212     //
213     return Status;
214 }
215 
216 NTSTATUS
217 HidClassFDO_DispatchRequest(
218     IN PDEVICE_OBJECT DeviceObject,
219     IN PIRP Irp)
220 {
221     PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
222     NTSTATUS Status;
223     PIO_STACK_LOCATION IoStack;
224 
225     //
226     // get device extension
227     //
228     CommonDeviceExtension = DeviceObject->DeviceExtension;
229 
230     ASSERT(Irp->CurrentLocation > 0);
231 
232     //
233     // create stack location
234     //
235     IoSetNextIrpStackLocation(Irp);
236 
237     //
238     // get next stack location
239     //
240     IoStack = IoGetCurrentIrpStackLocation(Irp);
241 
242     //
243     // store device object
244     //
245     IoStack->DeviceObject = DeviceObject;
246 
247     //
248     // sanity check
249     //
250     ASSERT(CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction] != NULL);
251 
252     //
253     // call driver
254     //
255     Status = CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction](DeviceObject, Irp);
256 
257     //
258     // done
259     //
260     return Status;
261 }
262 
263 NTSTATUS
264 HidClassFDO_GetDescriptors(
265     IN PDEVICE_OBJECT DeviceObject)
266 {
267     PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
268     PIRP Irp;
269     PIO_STACK_LOCATION IoStack;
270     NTSTATUS Status;
271 
272     //
273     // get device extension
274     //
275     FDODeviceExtension = DeviceObject->DeviceExtension;
276     ASSERT(FDODeviceExtension->Common.IsFDO);
277 
278     //
279     // let's allocate irp
280     //
281     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
282     if (!Irp)
283     {
284         //
285         // no memory
286         //
287         return STATUS_INSUFFICIENT_RESOURCES;
288     }
289 
290     //
291     // get stack location
292     //
293     IoStack = IoGetNextIrpStackLocation(Irp);
294 
295     //
296     // init stack location
297     //
298     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
299     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_DESCRIPTOR;
300     IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DESCRIPTOR);
301     IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
302     IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
303     Irp->UserBuffer = &FDODeviceExtension->HidDescriptor;
304 
305     //
306     // send request
307     //
308     Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
309     if (!NT_SUCCESS(Status))
310     {
311         //
312         // failed to get device descriptor
313         //
314         DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status);
315         IoFreeIrp(Irp);
316         return Status;
317     }
318 
319     //
320     // let's get device attributes
321     //
322     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_ATTRIBUTES;
323     IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DEVICE_ATTRIBUTES);
324     Irp->UserBuffer = &FDODeviceExtension->Common.Attributes;
325 
326     //
327     // send request
328     //
329     Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
330     if (!NT_SUCCESS(Status))
331     {
332         //
333         // failed to get device descriptor
334         //
335         DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status);
336         IoFreeIrp(Irp);
337         return Status;
338     }
339 
340     //
341     // sanity checks
342     //
343     ASSERT(FDODeviceExtension->HidDescriptor.bLength == sizeof(HID_DESCRIPTOR));
344     ASSERT(FDODeviceExtension->HidDescriptor.bNumDescriptors > 0);
345     ASSERT(FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength > 0);
346     ASSERT(FDODeviceExtension->HidDescriptor.DescriptorList[0].bReportType == HID_REPORT_DESCRIPTOR_TYPE);
347 
348     //
349     // now allocate space for the report descriptor
350     //
351     FDODeviceExtension->ReportDescriptor = ExAllocatePoolWithTag(NonPagedPool,
352                                                                  FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength,
353                                                                  HIDCLASS_TAG);
354     if (!FDODeviceExtension->ReportDescriptor)
355     {
356         //
357         // not enough memory
358         //
359         IoFreeIrp(Irp);
360         return STATUS_INSUFFICIENT_RESOURCES;
361     }
362 
363     //
364     // init stack location
365     //
366     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_REPORT_DESCRIPTOR;
367     IoStack->Parameters.DeviceIoControl.OutputBufferLength = FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength;
368     Irp->UserBuffer = FDODeviceExtension->ReportDescriptor;
369 
370     //
371     // send request
372     //
373     Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
374     if (!NT_SUCCESS(Status))
375     {
376         //
377         // failed to get device descriptor
378         //
379         DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status);
380         IoFreeIrp(Irp);
381         return Status;
382     }
383 
384     //
385     // completed successfully
386     //
387     IoFreeIrp(Irp);
388     return STATUS_SUCCESS;
389 }
390 
391 
392 NTSTATUS
393 HidClassFDO_StartDevice(
394     IN PDEVICE_OBJECT DeviceObject,
395     IN PIRP Irp)
396 {
397     NTSTATUS Status;
398     PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
399 
400     //
401     // get device extension
402     //
403     FDODeviceExtension = DeviceObject->DeviceExtension;
404     ASSERT(FDODeviceExtension->Common.IsFDO);
405 
406     //
407     // query capabilities
408     //
409     Status = HidClassFDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities);
410     if (!NT_SUCCESS(Status))
411     {
412         DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status);
413         Irp->IoStatus.Status = Status;
414         IoCompleteRequest(Irp, IO_NO_INCREMENT);
415         return Status;
416     }
417 
418     //
419     // let's start the lower device too
420     //
421     IoSkipCurrentIrpStackLocation(Irp);
422     Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
423     if (!NT_SUCCESS(Status))
424     {
425         DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status);
426         Irp->IoStatus.Status = Status;
427         IoCompleteRequest(Irp, IO_NO_INCREMENT);
428         return Status;
429     }
430 
431     //
432     // let's get the descriptors
433     //
434     Status = HidClassFDO_GetDescriptors(DeviceObject);
435     if (!NT_SUCCESS(Status))
436     {
437         DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status);
438         Irp->IoStatus.Status = Status;
439         IoCompleteRequest(Irp, IO_NO_INCREMENT);
440         return Status;
441     }
442 
443     //
444     // now get the the collection description
445     //
446     Status = HidP_GetCollectionDescription(FDODeviceExtension->ReportDescriptor, FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, NonPagedPool, &FDODeviceExtension->Common.DeviceDescription);
447     if (!NT_SUCCESS(Status))
448     {
449         DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status);
450         Irp->IoStatus.Status = Status;
451         IoCompleteRequest(Irp, IO_NO_INCREMENT);
452         return Status;
453     }
454 
455     //
456     // complete request
457     //
458     Irp->IoStatus.Status = Status;
459     IoCompleteRequest(Irp, IO_NO_INCREMENT);
460     return Status;
461 }
462 
463 NTSTATUS
464 HidClassFDO_RemoveDevice(
465     IN PDEVICE_OBJECT DeviceObject,
466     IN PIRP Irp)
467 {
468     NTSTATUS Status;
469     PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
470 
471     //
472     // get device extension
473     //
474     FDODeviceExtension = DeviceObject->DeviceExtension;
475     ASSERT(FDODeviceExtension->Common.IsFDO);
476 
477     /* FIXME cleanup */
478 
479     //
480     // dispatch to minidriver
481     //
482     IoSkipCurrentIrpStackLocation(Irp);
483     Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
484 
485     //
486     // complete request
487     //
488     Irp->IoStatus.Status = Status;
489     IoCompleteRequest(Irp, IO_NO_INCREMENT);
490 
491     //
492     // detach and delete device
493     //
494     IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
495     IoDeleteDevice(DeviceObject);
496 
497     return Status;
498 }
499 
500 NTSTATUS
501 HidClassFDO_CopyDeviceRelations(
502     IN PDEVICE_OBJECT DeviceObject,
503     OUT PDEVICE_RELATIONS *OutRelations)
504 {
505     PDEVICE_RELATIONS DeviceRelations;
506     PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
507     ULONG Index;
508 
509     //
510     // get device extension
511     //
512     FDODeviceExtension = DeviceObject->DeviceExtension;
513     ASSERT(FDODeviceExtension->Common.IsFDO);
514 
515     //
516     // allocate result
517     //
518     DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
519                                             sizeof(DEVICE_RELATIONS) + (FDODeviceExtension->DeviceRelations->Count - 1) * sizeof(PDEVICE_OBJECT),
520                                             HIDCLASS_TAG);
521     if (!DeviceRelations)
522     {
523         //
524         // no memory
525         //
526         *OutRelations = NULL;
527         return STATUS_INSUFFICIENT_RESOURCES;
528     }
529 
530     //
531     // copy device objects
532     //
533     for (Index = 0; Index < FDODeviceExtension->DeviceRelations->Count; Index++)
534     {
535         //
536         // reference pdo
537         //
538         ObReferenceObject(FDODeviceExtension->DeviceRelations->Objects[Index]);
539 
540         //
541         // store object
542         //
543         DeviceRelations->Objects[Index] = FDODeviceExtension->DeviceRelations->Objects[Index];
544     }
545 
546     //
547     // set object count
548     //
549     DeviceRelations->Count = FDODeviceExtension->DeviceRelations->Count;
550 
551     //
552     // store result
553     //
554     *OutRelations = DeviceRelations;
555     return STATUS_SUCCESS;
556 }
557 
558 NTSTATUS
559 HidClassFDO_DeviceRelations(
560     IN PDEVICE_OBJECT DeviceObject,
561     IN PIRP Irp)
562 {
563     PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
564     PIO_STACK_LOCATION IoStack;
565     NTSTATUS Status;
566     PDEVICE_RELATIONS DeviceRelations;
567 
568     //
569     // get device extension
570     //
571     FDODeviceExtension = DeviceObject->DeviceExtension;
572     ASSERT(FDODeviceExtension->Common.IsFDO);
573 
574     //
575     // get current irp stack location
576     //
577     IoStack = IoGetCurrentIrpStackLocation(Irp);
578 
579     //
580     // check relations type
581     //
582     if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
583     {
584         //
585         // only bus relations are handled
586         //
587         IoSkipCurrentIrpStackLocation(Irp);
588         return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
589     }
590 
591     if (FDODeviceExtension->DeviceRelations == NULL)
592     {
593         //
594         // time to create the pdos
595         //
596         Status = HidClassPDO_CreatePDO(DeviceObject, &FDODeviceExtension->DeviceRelations);
597         if (!NT_SUCCESS(Status))
598         {
599             //
600             // failed
601             //
602             DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status);
603             Irp->IoStatus.Status = Status;
604             IoCompleteRequest(Irp, IO_NO_INCREMENT);
605             return STATUS_SUCCESS;
606         }
607         //
608         // sanity check
609         //
610         ASSERT(FDODeviceExtension->DeviceRelations->Count > 0);
611     }
612 
613     //
614     // now copy device relations
615     //
616     Status = HidClassFDO_CopyDeviceRelations(DeviceObject, &DeviceRelations);
617     //
618     // store result
619     //
620     Irp->IoStatus.Status = Status;
621     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
622 
623     //
624     // complete request
625     //
626     IoCompleteRequest(Irp, IO_NO_INCREMENT);
627     return Status;
628 }
629 
630 NTSTATUS
631 HidClassFDO_PnP(
632     IN PDEVICE_OBJECT DeviceObject,
633     IN PIRP Irp)
634 {
635     PIO_STACK_LOCATION IoStack;
636     PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
637     NTSTATUS Status;
638 
639     //
640     // get device extension
641     //
642     FDODeviceExtension = DeviceObject->DeviceExtension;
643     ASSERT(FDODeviceExtension->Common.IsFDO);
644 
645     //
646     // get current irp stack location
647     //
648     IoStack = IoGetCurrentIrpStackLocation(Irp);
649     switch (IoStack->MinorFunction)
650     {
651         case IRP_MN_START_DEVICE:
652         {
653              return HidClassFDO_StartDevice(DeviceObject, Irp);
654         }
655         case IRP_MN_REMOVE_DEVICE:
656         {
657              return HidClassFDO_RemoveDevice(DeviceObject, Irp);
658         }
659         case IRP_MN_QUERY_DEVICE_RELATIONS:
660         {
661              return HidClassFDO_DeviceRelations(DeviceObject, Irp);
662         }
663         case IRP_MN_QUERY_REMOVE_DEVICE:
664         case IRP_MN_QUERY_STOP_DEVICE:
665         case IRP_MN_CANCEL_REMOVE_DEVICE:
666         case IRP_MN_CANCEL_STOP_DEVICE:
667         {
668             //
669             // set status to success and fall through
670             //
671             Irp->IoStatus.Status = STATUS_SUCCESS;
672         }
673         default:
674         {
675             //
676             // dispatch to mini driver
677             //
678            IoCopyCurrentIrpStackLocationToNext(Irp);
679            Status = HidClassFDO_DispatchRequest(DeviceObject, Irp);
680            return Status;
681         }
682     }
683 }
684