[HID]
[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 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 // call driver
186 //
187 DPRINT("IoStack MajorFunction %x MinorFunction %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
188 Status = CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction](DeviceObject, Irp);
189
190 //
191 // wait for the request to finish
192 //
193 if (Status == STATUS_PENDING)
194 {
195 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
196
197 //
198 // update status
199 //
200 Status = Irp->IoStatus.Status;
201 }
202
203 //
204 // done
205 //
206 return Status;
207 }
208
209 NTSTATUS
210 HidClassFDO_GetDescriptors(
211 IN PDEVICE_OBJECT DeviceObject)
212 {
213 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
214 PIRP Irp;
215 PIO_STACK_LOCATION IoStack;
216 NTSTATUS Status;
217
218 //
219 // get device extension
220 //
221 FDODeviceExtension = DeviceObject->DeviceExtension;
222 ASSERT(FDODeviceExtension->Common.IsFDO);
223
224 //
225 // let's allocate irp
226 //
227 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
228 if (!Irp)
229 {
230 //
231 // no memory
232 //
233 return STATUS_INSUFFICIENT_RESOURCES;
234 }
235
236 //
237 // get stack location
238 //
239 IoStack = IoGetNextIrpStackLocation(Irp);
240
241 //
242 // init stack location
243 //
244 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
245 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_DESCRIPTOR;
246 IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DESCRIPTOR);
247 IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
248 IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
249 Irp->UserBuffer = &FDODeviceExtension->HidDescriptor;
250
251 //
252 // send request
253 //
254 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
255 if (!NT_SUCCESS(Status))
256 {
257 //
258 // failed to get device descriptor
259 //
260 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status);
261 IoFreeIrp(Irp);
262 return Status;
263 }
264
265 //
266 // let's get device attributes
267 //
268 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_ATTRIBUTES;
269 IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DEVICE_ATTRIBUTES);
270 Irp->UserBuffer = &FDODeviceExtension->Common.Attributes;
271
272 //
273 // send request
274 //
275 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
276 if (!NT_SUCCESS(Status))
277 {
278 //
279 // failed to get device descriptor
280 //
281 DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status);
282 IoFreeIrp(Irp);
283 return Status;
284 }
285
286 //
287 // sanity checks
288 //
289 ASSERT(FDODeviceExtension->HidDescriptor.bLength == sizeof(HID_DESCRIPTOR));
290 ASSERT(FDODeviceExtension->HidDescriptor.bNumDescriptors > 0);
291 ASSERT(FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength > 0);
292 ASSERT(FDODeviceExtension->HidDescriptor.DescriptorList[0].bReportType == HID_REPORT_DESCRIPTOR_TYPE);
293
294 //
295 // now allocate space for the report descriptor
296 //
297 FDODeviceExtension->ReportDescriptor = ExAllocatePoolWithTag(NonPagedPool,
298 FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength,
299 HIDCLASS_TAG);
300 if (!FDODeviceExtension->ReportDescriptor)
301 {
302 //
303 // not enough memory
304 //
305 IoFreeIrp(Irp);
306 return STATUS_INSUFFICIENT_RESOURCES;
307 }
308
309 //
310 // init stack location
311 //
312 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_REPORT_DESCRIPTOR;
313 IoStack->Parameters.DeviceIoControl.OutputBufferLength = FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength;
314 Irp->UserBuffer = FDODeviceExtension->ReportDescriptor;
315
316 //
317 // send request
318 //
319 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
320 if (!NT_SUCCESS(Status))
321 {
322 //
323 // failed to get device descriptor
324 //
325 DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status);
326 IoFreeIrp(Irp);
327 return Status;
328 }
329
330 //
331 // completed successfully
332 //
333 return STATUS_SUCCESS;
334 }
335
336
337 NTSTATUS
338 HidClassFDO_StartDevice(
339 IN PDEVICE_OBJECT DeviceObject,
340 IN PIRP Irp)
341 {
342 NTSTATUS Status;
343 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
344
345 //
346 // get device extension
347 //
348 FDODeviceExtension = DeviceObject->DeviceExtension;
349 ASSERT(FDODeviceExtension->Common.IsFDO);
350
351 //
352 // query capabilities
353 //
354 Status = HidClassFDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities);
355 if (!NT_SUCCESS(Status))
356 {
357 DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status);
358 Irp->IoStatus.Status = Status;
359 IoCompleteRequest(Irp, IO_NO_INCREMENT);
360 return Status;
361 }
362
363 //
364 // let's start the lower device too
365 //
366 IoSkipCurrentIrpStackLocation(Irp);
367 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
368 if (!NT_SUCCESS(Status))
369 {
370 DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status);
371 Irp->IoStatus.Status = Status;
372 IoCompleteRequest(Irp, IO_NO_INCREMENT);
373 return Status;
374 }
375
376 //
377 // let's get the descriptors
378 //
379 Status = HidClassFDO_GetDescriptors(DeviceObject);
380 if (!NT_SUCCESS(Status))
381 {
382 DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status);
383 Irp->IoStatus.Status = Status;
384 IoCompleteRequest(Irp, IO_NO_INCREMENT);
385 return Status;
386 }
387
388 //
389 // now get the the collection description
390 //
391 Status = HidP_GetCollectionDescription(FDODeviceExtension->ReportDescriptor, FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, NonPagedPool, &FDODeviceExtension->Common.DeviceDescription);
392 if (!NT_SUCCESS(Status))
393 {
394 DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status);
395 Irp->IoStatus.Status = Status;
396 IoCompleteRequest(Irp, IO_NO_INCREMENT);
397 return Status;
398 }
399
400 //
401 // complete request
402 //
403 Irp->IoStatus.Status = Status;
404 IoCompleteRequest(Irp, IO_NO_INCREMENT);
405 return Status;
406 }
407
408 NTSTATUS
409 HidClassFDO_RemoveDevice(
410 IN PDEVICE_OBJECT DeviceObject,
411 IN PIRP Irp)
412 {
413 NTSTATUS Status;
414 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
415
416 //
417 // get device extension
418 //
419 FDODeviceExtension = DeviceObject->DeviceExtension;
420 ASSERT(FDODeviceExtension->Common.IsFDO);
421
422 /* FIXME cleanup */
423
424 //
425 // dispatch to minidriver
426 //
427 IoSkipCurrentIrpStackLocation(Irp);
428 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
429
430 //
431 // complete request
432 //
433 Irp->IoStatus.Status = Status;
434 IoCompleteRequest(Irp, IO_NO_INCREMENT);
435
436 //
437 // detach and delete device
438 //
439 IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
440 IoDeleteDevice(DeviceObject);
441
442 return Status;
443 }
444
445 NTSTATUS
446 HidClassFDO_CopyDeviceRelations(
447 IN PDEVICE_OBJECT DeviceObject,
448 OUT PDEVICE_RELATIONS *OutRelations)
449 {
450 PDEVICE_RELATIONS DeviceRelations;
451 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
452 ULONG Index;
453
454 //
455 // get device extension
456 //
457 FDODeviceExtension = DeviceObject->DeviceExtension;
458 ASSERT(FDODeviceExtension->Common.IsFDO);
459
460 //
461 // allocate result
462 //
463 DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
464 sizeof(DEVICE_RELATIONS) + (FDODeviceExtension->DeviceRelations->Count - 1) * sizeof(PDEVICE_OBJECT),
465 HIDCLASS_TAG);
466 if (!DeviceRelations)
467 {
468 //
469 // no memory
470 //
471 *OutRelations = NULL;
472 return STATUS_INSUFFICIENT_RESOURCES;
473 }
474
475 //
476 // copy device objects
477 //
478 for (Index = 0; Index < FDODeviceExtension->DeviceRelations->Count; Index++)
479 {
480 //
481 // reference pdo
482 //
483 ObReferenceObject(FDODeviceExtension->DeviceRelations->Objects[Index]);
484
485 //
486 // store object
487 //
488 DeviceRelations->Objects[Index] = FDODeviceExtension->DeviceRelations->Objects[Index];
489 }
490
491 //
492 // set object count
493 //
494 DeviceRelations->Count = FDODeviceExtension->DeviceRelations->Count;
495
496 //
497 // store result
498 //
499 *OutRelations = DeviceRelations;
500 return STATUS_SUCCESS;
501 }
502
503 NTSTATUS
504 HidClassFDO_DeviceRelations(
505 IN PDEVICE_OBJECT DeviceObject,
506 IN PIRP Irp)
507 {
508 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
509 PIO_STACK_LOCATION IoStack;
510 NTSTATUS Status;
511 PDEVICE_RELATIONS DeviceRelations;
512
513 //
514 // get device extension
515 //
516 FDODeviceExtension = DeviceObject->DeviceExtension;
517 ASSERT(FDODeviceExtension->Common.IsFDO);
518
519 //
520 // get current irp stack location
521 //
522 IoStack = IoGetCurrentIrpStackLocation(Irp);
523
524 //
525 // check relations type
526 //
527 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
528 {
529 //
530 // only bus relations are handled
531 //
532 IoSkipCurrentIrpStackLocation(Irp);
533 return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
534 }
535
536 if (FDODeviceExtension->DeviceRelations == NULL)
537 {
538 //
539 // time to create the pdos
540 //
541 Status = HidClassPDO_CreatePDO(DeviceObject, &FDODeviceExtension->DeviceRelations);
542 if (!NT_SUCCESS(Status))
543 {
544 //
545 // failed
546 //
547 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status);
548 Irp->IoStatus.Status = Status;
549 IoCompleteRequest(Irp, IO_NO_INCREMENT);
550 return STATUS_SUCCESS;
551 }
552 //
553 // sanity check
554 //
555 ASSERT(FDODeviceExtension->DeviceRelations->Count > 0);
556 }
557
558 //
559 // now copy device relations
560 //
561 Status = HidClassFDO_CopyDeviceRelations(DeviceObject, &DeviceRelations);
562 //
563 // store result
564 //
565 Irp->IoStatus.Status = Status;
566 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
567
568 //
569 // complete request
570 //
571 IoCompleteRequest(Irp, IO_NO_INCREMENT);
572 return Status;
573 }
574
575 NTSTATUS
576 HidClassFDO_PnP(
577 IN PDEVICE_OBJECT DeviceObject,
578 IN PIRP Irp)
579 {
580 PIO_STACK_LOCATION IoStack;
581 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
582 NTSTATUS Status;
583
584 //
585 // get device extension
586 //
587 FDODeviceExtension = DeviceObject->DeviceExtension;
588 ASSERT(FDODeviceExtension->Common.IsFDO);
589
590 //
591 // get current irp stack location
592 //
593 IoStack = IoGetCurrentIrpStackLocation(Irp);
594 switch (IoStack->MinorFunction)
595 {
596 case IRP_MN_START_DEVICE:
597 {
598 return HidClassFDO_StartDevice(DeviceObject, Irp);
599 }
600 case IRP_MN_REMOVE_DEVICE:
601 {
602 return HidClassFDO_RemoveDevice(DeviceObject, Irp);
603 }
604 case IRP_MN_QUERY_DEVICE_RELATIONS:
605 {
606 return HidClassFDO_DeviceRelations(DeviceObject, Irp);
607 }
608 case IRP_MN_QUERY_REMOVE_DEVICE:
609 case IRP_MN_QUERY_STOP_DEVICE:
610 case IRP_MN_CANCEL_REMOVE_DEVICE:
611 case IRP_MN_CANCEL_STOP_DEVICE:
612 {
613 //
614 // set status to success and fall through
615 //
616 Irp->IoStatus.Status = STATUS_SUCCESS;
617 }
618 default:
619 {
620 //
621 // dispatch to mini driver
622 //
623 IoSkipCurrentIrpStackLocation(Irp);
624 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
625
626 //
627 // complete request
628 //
629 Irp->IoStatus.Status = Status;
630 IoCompleteRequest(Irp, IO_NO_INCREMENT);
631 return Status;
632 }
633 }
634 }