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