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