[HIDCLASS][USBHUB]
[reactos.git] / reactos / drivers / hid / hidclass / fdo.c
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 allocte 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 }