Branching for 0.3.15 release after two days of no response from a certain sphere...
[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 #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 if (!NT_SUCCESS(Status))
354 {
355 DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status);
356 Irp->IoStatus.Status = Status;
357 IoCompleteRequest(Irp, IO_NO_INCREMENT);
358 return Status;
359 }
360
361 //
362 // lets start the lower device too
363 //
364 IoSkipCurrentIrpStackLocation(Irp);
365 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
366 if (!NT_SUCCESS(Status))
367 {
368 DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status);
369 Irp->IoStatus.Status = Status;
370 IoCompleteRequest(Irp, IO_NO_INCREMENT);
371 return Status;
372 }
373
374 //
375 // lets get the descriptors
376 //
377 Status = HidClassFDO_GetDescriptors(DeviceObject);
378 if (!NT_SUCCESS(Status))
379 {
380 DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status);
381 Irp->IoStatus.Status = Status;
382 IoCompleteRequest(Irp, IO_NO_INCREMENT);
383 return Status;
384 }
385
386 //
387 // now get the the collection description
388 //
389 Status = HidP_GetCollectionDescription(FDODeviceExtension->ReportDescriptor, FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, NonPagedPool, &FDODeviceExtension->Common.DeviceDescription);
390 if (!NT_SUCCESS(Status))
391 {
392 DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status);
393 Irp->IoStatus.Status = Status;
394 IoCompleteRequest(Irp, IO_NO_INCREMENT);
395 return Status;
396 }
397
398 //
399 // complete request
400 //
401 Irp->IoStatus.Status = Status;
402 IoCompleteRequest(Irp, IO_NO_INCREMENT);
403 return Status;
404 }
405
406 NTSTATUS
407 HidClassFDO_RemoveDevice(
408 IN PDEVICE_OBJECT DeviceObject,
409 IN PIRP Irp)
410 {
411 NTSTATUS Status;
412
413 /* FIXME cleanup */
414
415 //
416 // dispatch to minidriver
417 //
418 IoSkipCurrentIrpStackLocation(Irp);
419 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
420
421 //
422 // complete request
423 //
424 Irp->IoStatus.Status = Status;
425 IoCompleteRequest(Irp, IO_NO_INCREMENT);
426 return Status;
427 }
428
429 NTSTATUS
430 HidClassFDO_CopyDeviceRelations(
431 IN PDEVICE_OBJECT DeviceObject,
432 OUT PDEVICE_RELATIONS *OutRelations)
433 {
434 PDEVICE_RELATIONS DeviceRelations;
435 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
436 ULONG Index;
437
438 //
439 // get device extension
440 //
441 FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
442 ASSERT(FDODeviceExtension->Common.IsFDO);
443
444 //
445 // allocate result
446 //
447 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, sizeof(DEVICE_RELATIONS) + (FDODeviceExtension->DeviceRelations->Count-1) * sizeof(PDEVICE_OBJECT));
448 if (!DeviceRelations)
449 {
450 //
451 // no memory
452 //
453 *OutRelations = NULL;
454 return STATUS_INSUFFICIENT_RESOURCES;
455 }
456
457 //
458 // copy device objects
459 //
460 for(Index = 0; Index < FDODeviceExtension->DeviceRelations->Count; Index++)
461 {
462 //
463 // reference pdo
464 //
465 ObReferenceObject(FDODeviceExtension->DeviceRelations->Objects[Index]);
466
467 //
468 // store object
469 //
470 DeviceRelations->Objects[Index] = FDODeviceExtension->DeviceRelations->Objects[Index];
471 }
472
473 //
474 // set object count
475 //
476 DeviceRelations->Count = FDODeviceExtension->DeviceRelations->Count;
477
478 //
479 // store result
480 //
481 *OutRelations = DeviceRelations;
482 return STATUS_SUCCESS;
483 }
484
485 NTSTATUS
486 HidClassFDO_DeviceRelations(
487 IN PDEVICE_OBJECT DeviceObject,
488 IN PIRP Irp)
489 {
490 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
491 PIO_STACK_LOCATION IoStack;
492 NTSTATUS Status;
493 PDEVICE_RELATIONS DeviceRelations;
494
495 //
496 // get device extension
497 //
498 FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
499 ASSERT(FDODeviceExtension->Common.IsFDO);
500
501 //
502 // get current irp stack location
503 //
504 IoStack = IoGetCurrentIrpStackLocation(Irp);
505
506 //
507 // check relations type
508 //
509 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
510 {
511 //
512 // only bus relations are handled
513 //
514 IoSkipCurrentIrpStackLocation(Irp);
515 return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
516 }
517
518 if (FDODeviceExtension->DeviceRelations == NULL)
519 {
520 //
521 // time to create the pdos
522 //
523 Status = HidClassPDO_CreatePDO(DeviceObject, &FDODeviceExtension->DeviceRelations);
524 if (!NT_SUCCESS(Status))
525 {
526 //
527 // failed
528 //
529 DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status);
530 Irp->IoStatus.Status = Status;
531 IoCompleteRequest(Irp, IO_NO_INCREMENT);
532 return STATUS_SUCCESS;
533 }
534 //
535 // sanity check
536 //
537 ASSERT(FDODeviceExtension->DeviceRelations->Count > 0);
538 }
539
540 //
541 // now copy device relations
542 //
543 Status = HidClassFDO_CopyDeviceRelations(DeviceObject, &DeviceRelations);
544 //
545 // store result
546 //
547 Irp->IoStatus.Status = Status;
548 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
549
550 //
551 // complete request
552 //
553 IoCompleteRequest(Irp, IO_NO_INCREMENT);
554 return Status;
555 }
556
557 NTSTATUS
558 HidClassFDO_PnP(
559 IN PDEVICE_OBJECT DeviceObject,
560 IN PIRP Irp)
561 {
562 PIO_STACK_LOCATION IoStack;
563 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
564 NTSTATUS Status;
565
566 //
567 // get device extension
568 //
569 FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
570 ASSERT(FDODeviceExtension->Common.IsFDO);
571
572 //
573 // get current irp stack location
574 //
575 IoStack = IoGetCurrentIrpStackLocation(Irp);
576 switch(IoStack->MinorFunction)
577 {
578 case IRP_MN_START_DEVICE:
579 {
580 return HidClassFDO_StartDevice(DeviceObject, Irp);
581 }
582 case IRP_MN_REMOVE_DEVICE:
583 {
584 return HidClassFDO_RemoveDevice(DeviceObject, Irp);
585 }
586 case IRP_MN_QUERY_DEVICE_RELATIONS:
587 {
588 return HidClassFDO_DeviceRelations(DeviceObject, Irp);
589 }
590 case IRP_MN_QUERY_REMOVE_DEVICE:
591 case IRP_MN_QUERY_STOP_DEVICE:
592 case IRP_MN_CANCEL_REMOVE_DEVICE:
593 case IRP_MN_CANCEL_STOP_DEVICE:
594 {
595 //
596 // set status to success and fall through
597 //
598 Irp->IoStatus.Status = STATUS_SUCCESS;
599 }
600 default:
601 {
602 //
603 // dispatch to mini driver
604 //
605 IoSkipCurrentIrpStackLocation(Irp);
606 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
607
608 //
609 // complete request
610 //
611 Irp->IoStatus.Status = Status;
612 IoCompleteRequest(Irp, IO_NO_INCREMENT);
613 return Status;
614 }
615 }
616 }