3eab30d27862f2aefaccb178116182a05dd0d481
[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 return STATUS_SUCCESS;
388 }
389
390
391 NTSTATUS
392 HidClassFDO_StartDevice(
393 IN PDEVICE_OBJECT DeviceObject,
394 IN PIRP Irp)
395 {
396 NTSTATUS Status;
397 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
398
399 //
400 // get device extension
401 //
402 FDODeviceExtension = DeviceObject->DeviceExtension;
403 ASSERT(FDODeviceExtension->Common.IsFDO);
404
405 //
406 // query capabilities
407 //
408 Status = HidClassFDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities);
409 if (!NT_SUCCESS(Status))
410 {
411 DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status);
412 Irp->IoStatus.Status = Status;
413 IoCompleteRequest(Irp, IO_NO_INCREMENT);
414 return Status;
415 }
416
417 //
418 // let's start the lower device too
419 //
420 IoSkipCurrentIrpStackLocation(Irp);
421 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
422 if (!NT_SUCCESS(Status))
423 {
424 DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status);
425 Irp->IoStatus.Status = Status;
426 IoCompleteRequest(Irp, IO_NO_INCREMENT);
427 return Status;
428 }
429
430 //
431 // let's get the descriptors
432 //
433 Status = HidClassFDO_GetDescriptors(DeviceObject);
434 if (!NT_SUCCESS(Status))
435 {
436 DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status);
437 Irp->IoStatus.Status = Status;
438 IoCompleteRequest(Irp, IO_NO_INCREMENT);
439 return Status;
440 }
441
442 //
443 // now get the the collection description
444 //
445 Status = HidP_GetCollectionDescription(FDODeviceExtension->ReportDescriptor, FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, NonPagedPool, &FDODeviceExtension->Common.DeviceDescription);
446 if (!NT_SUCCESS(Status))
447 {
448 DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status);
449 Irp->IoStatus.Status = Status;
450 IoCompleteRequest(Irp, IO_NO_INCREMENT);
451 return Status;
452 }
453
454 //
455 // complete request
456 //
457 Irp->IoStatus.Status = Status;
458 IoCompleteRequest(Irp, IO_NO_INCREMENT);
459 return Status;
460 }
461
462 NTSTATUS
463 HidClassFDO_RemoveDevice(
464 IN PDEVICE_OBJECT DeviceObject,
465 IN PIRP Irp)
466 {
467 NTSTATUS Status;
468 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
469
470 //
471 // get device extension
472 //
473 FDODeviceExtension = DeviceObject->DeviceExtension;
474 ASSERT(FDODeviceExtension->Common.IsFDO);
475
476 /* FIXME cleanup */
477
478 //
479 // dispatch to minidriver
480 //
481 IoSkipCurrentIrpStackLocation(Irp);
482 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
483
484 //
485 // complete request
486 //
487 Irp->IoStatus.Status = Status;
488 IoCompleteRequest(Irp, IO_NO_INCREMENT);
489
490 //
491 // detach and delete device
492 //
493 IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
494 IoDeleteDevice(DeviceObject);
495
496 return Status;
497 }
498
499 NTSTATUS
500 HidClassFDO_CopyDeviceRelations(
501 IN PDEVICE_OBJECT DeviceObject,
502 OUT PDEVICE_RELATIONS *OutRelations)
503 {
504 PDEVICE_RELATIONS DeviceRelations;
505 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
506 ULONG Index;
507
508 //
509 // get device extension
510 //
511 FDODeviceExtension = DeviceObject->DeviceExtension;
512 ASSERT(FDODeviceExtension->Common.IsFDO);
513
514 //
515 // allocate result
516 //
517 DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
518 sizeof(DEVICE_RELATIONS) + (FDODeviceExtension->DeviceRelations->Count - 1) * sizeof(PDEVICE_OBJECT),
519 HIDCLASS_TAG);
520 if (!DeviceRelations)
521 {
522 //
523 // no memory
524 //
525 *OutRelations = NULL;
526 return STATUS_INSUFFICIENT_RESOURCES;
527 }
528
529 //
530 // copy device objects
531 //
532 for (Index = 0; Index < FDODeviceExtension->DeviceRelations->Count; Index++)
533 {
534 //
535 // reference pdo
536 //
537 ObReferenceObject(FDODeviceExtension->DeviceRelations->Objects[Index]);
538
539 //
540 // store object
541 //
542 DeviceRelations->Objects[Index] = FDODeviceExtension->DeviceRelations->Objects[Index];
543 }
544
545 //
546 // set object count
547 //
548 DeviceRelations->Count = FDODeviceExtension->DeviceRelations->Count;
549
550 //
551 // store result
552 //
553 *OutRelations = DeviceRelations;
554 return STATUS_SUCCESS;
555 }
556
557 NTSTATUS
558 HidClassFDO_DeviceRelations(
559 IN PDEVICE_OBJECT DeviceObject,
560 IN PIRP Irp)
561 {
562 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
563 PIO_STACK_LOCATION IoStack;
564 NTSTATUS Status;
565 PDEVICE_RELATIONS DeviceRelations;
566
567 //
568 // get device extension
569 //
570 FDODeviceExtension = DeviceObject->DeviceExtension;
571 ASSERT(FDODeviceExtension->Common.IsFDO);
572
573 //
574 // get current irp stack location
575 //
576 IoStack = IoGetCurrentIrpStackLocation(Irp);
577
578 //
579 // check relations type
580 //
581 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
582 {
583 //
584 // only bus relations are handled
585 //
586 IoSkipCurrentIrpStackLocation(Irp);
587 return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
588 }
589
590 if (FDODeviceExtension->DeviceRelations == NULL)
591 {
592 //
593 // time to create the pdos
594 //
595 Status = HidClassPDO_CreatePDO(DeviceObject, &FDODeviceExtension->DeviceRelations);
596 if (!NT_SUCCESS(Status))
597 {
598 //
599 // failed
600 //
601 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status);
602 Irp->IoStatus.Status = Status;
603 IoCompleteRequest(Irp, IO_NO_INCREMENT);
604 return STATUS_SUCCESS;
605 }
606 //
607 // sanity check
608 //
609 ASSERT(FDODeviceExtension->DeviceRelations->Count > 0);
610 }
611
612 //
613 // now copy device relations
614 //
615 Status = HidClassFDO_CopyDeviceRelations(DeviceObject, &DeviceRelations);
616 //
617 // store result
618 //
619 Irp->IoStatus.Status = Status;
620 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
621
622 //
623 // complete request
624 //
625 IoCompleteRequest(Irp, IO_NO_INCREMENT);
626 return Status;
627 }
628
629 NTSTATUS
630 HidClassFDO_PnP(
631 IN PDEVICE_OBJECT DeviceObject,
632 IN PIRP Irp)
633 {
634 PIO_STACK_LOCATION IoStack;
635 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
636 NTSTATUS Status;
637
638 //
639 // get device extension
640 //
641 FDODeviceExtension = DeviceObject->DeviceExtension;
642 ASSERT(FDODeviceExtension->Common.IsFDO);
643
644 //
645 // get current irp stack location
646 //
647 IoStack = IoGetCurrentIrpStackLocation(Irp);
648 switch (IoStack->MinorFunction)
649 {
650 case IRP_MN_START_DEVICE:
651 {
652 return HidClassFDO_StartDevice(DeviceObject, Irp);
653 }
654 case IRP_MN_REMOVE_DEVICE:
655 {
656 return HidClassFDO_RemoveDevice(DeviceObject, Irp);
657 }
658 case IRP_MN_QUERY_DEVICE_RELATIONS:
659 {
660 return HidClassFDO_DeviceRelations(DeviceObject, Irp);
661 }
662 case IRP_MN_QUERY_REMOVE_DEVICE:
663 case IRP_MN_QUERY_STOP_DEVICE:
664 case IRP_MN_CANCEL_REMOVE_DEVICE:
665 case IRP_MN_CANCEL_STOP_DEVICE:
666 {
667 //
668 // set status to success and fall through
669 //
670 Irp->IoStatus.Status = STATUS_SUCCESS;
671 }
672 default:
673 {
674 //
675 // dispatch to mini driver
676 //
677 IoCopyCurrentIrpStackLocationToNext(Irp);
678 Status = HidClassFDO_DispatchRequest(DeviceObject, Irp);
679 return Status;
680 }
681 }
682 }