[HIDCLASS] Implement IOCTL_HID_GET_FEATURE/IOCTL_HID_SET_FEATURE
[reactos.git] / drivers / hid / hidclass / pdo.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 #include <wdmguid.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 PHIDP_COLLECTION_DESC
19 HidClassPDO_GetCollectionDescription(
20 PHIDP_DEVICE_DESC DeviceDescription,
21 ULONG CollectionNumber)
22 {
23 ULONG Index;
24
25 for(Index = 0; Index < DeviceDescription->CollectionDescLength; Index++)
26 {
27 if (DeviceDescription->CollectionDesc[Index].CollectionNumber == CollectionNumber)
28 {
29 //
30 // found collection
31 //
32 return &DeviceDescription->CollectionDesc[Index];
33 }
34 }
35
36 //
37 // failed to find collection
38 //
39 DPRINT1("[HIDCLASS] GetCollectionDescription CollectionNumber %x not found\n", CollectionNumber);
40 ASSERT(FALSE);
41 return NULL;
42 }
43
44 PHIDP_REPORT_IDS
45 HidClassPDO_GetReportDescription(
46 PHIDP_DEVICE_DESC DeviceDescription,
47 ULONG CollectionNumber)
48 {
49 ULONG Index;
50
51 for (Index = 0; Index < DeviceDescription->ReportIDsLength; Index++)
52 {
53 if (DeviceDescription->ReportIDs[Index].CollectionNumber == CollectionNumber)
54 {
55 //
56 // found collection
57 //
58 return &DeviceDescription->ReportIDs[Index];
59 }
60 }
61
62 //
63 // failed to find collection
64 //
65 DPRINT1("[HIDCLASS] GetReportDescription CollectionNumber %x not found\n", CollectionNumber);
66 ASSERT(FALSE);
67 return NULL;
68 }
69
70 PHIDP_REPORT_IDS
71 HidClassPDO_GetReportDescriptionByReportID(
72 PHIDP_DEVICE_DESC DeviceDescription,
73 UCHAR ReportID)
74 {
75 ULONG Index;
76
77 for (Index = 0; Index < DeviceDescription->ReportIDsLength; Index++)
78 {
79 if (DeviceDescription->ReportIDs[Index].ReportID == ReportID)
80 {
81 //
82 // found report id
83 //
84 return &DeviceDescription->ReportIDs[Index];
85 }
86 }
87
88 //
89 // failed to find report id
90 //
91 DPRINT1("[HIDCLASS] GetReportDescriptionByReportID ReportID %x not found\n", ReportID);
92 ASSERT(FALSE);
93 return NULL;
94 }
95
96 NTSTATUS
97 HidClassPDO_HandleQueryDeviceId(
98 IN PDEVICE_OBJECT DeviceObject,
99 IN PIRP Irp)
100 {
101 NTSTATUS Status;
102 LPWSTR Buffer;
103 LPWSTR NewBuffer, Ptr;
104 ULONG Length;
105
106 //
107 // copy current stack location
108 //
109 IoCopyCurrentIrpStackLocationToNext(Irp);
110
111 //
112 // call mini-driver
113 //
114 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
115 if (!NT_SUCCESS(Status))
116 {
117 //
118 // failed
119 //
120 return Status;
121 }
122
123 //
124 // get buffer
125 //
126 Buffer = (LPWSTR)Irp->IoStatus.Information;
127 Length = wcslen(Buffer);
128
129 //
130 // allocate new buffer
131 //
132 NewBuffer = ExAllocatePoolWithTag(NonPagedPool, (Length + 1) * sizeof(WCHAR), HIDCLASS_TAG);
133 if (!NewBuffer)
134 {
135 //
136 // failed to allocate buffer
137 //
138 return STATUS_INSUFFICIENT_RESOURCES;
139 }
140
141 //
142 // replace bus
143 //
144 wcscpy(NewBuffer, L"HID\\");
145
146 //
147 // get offset to first '\\'
148 //
149 Ptr = wcschr(Buffer, L'\\');
150 if (Ptr)
151 {
152 //
153 // append result
154 //
155 wcscat(NewBuffer, Ptr + 1);
156 }
157
158 //
159 // free old buffer
160 //
161 ExFreePoolWithTag(Buffer, 0);
162
163 //
164 // store result
165 //
166 DPRINT("NewBuffer %S\n", NewBuffer);
167 Irp->IoStatus.Information = (ULONG_PTR)NewBuffer;
168 return STATUS_SUCCESS;
169 }
170
171 NTSTATUS
172 HidClassPDO_HandleQueryHardwareId(
173 IN PDEVICE_OBJECT DeviceObject,
174 IN PIRP Irp)
175 {
176 NTSTATUS Status;
177 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
178 WCHAR Buffer[200];
179 ULONG Offset = 0;
180 LPWSTR Ptr;
181 PHIDP_COLLECTION_DESC CollectionDescription;
182
183 //
184 // get device extension
185 //
186 PDODeviceExtension = DeviceObject->DeviceExtension;
187 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
188
189 //
190 // copy current stack location
191 //
192 IoCopyCurrentIrpStackLocationToNext(Irp);
193
194 //
195 // call mini-driver
196 //
197 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
198 if (!NT_SUCCESS(Status))
199 {
200 //
201 // failed
202 //
203 return Status;
204 }
205
206 if (PDODeviceExtension->Common.DeviceDescription.CollectionDescLength > 1)
207 {
208 //
209 // multi-tlc device
210 //
211 Offset = swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Rev_%04x&Col%02x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->Common.Attributes.VersionNumber, PDODeviceExtension->CollectionNumber) + 1;
212 Offset += swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Col%02x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->CollectionNumber) + 1;
213 }
214 else
215 {
216 //
217 // single tlc device
218 //
219 Offset = swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Rev_%04x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->Common.Attributes.VersionNumber) + 1;
220 Offset += swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID) + 1;
221 }
222
223 //
224 // get collection description
225 //
226 CollectionDescription = HidClassPDO_GetCollectionDescription(&PDODeviceExtension->Common.DeviceDescription, PDODeviceExtension->CollectionNumber);
227 ASSERT(CollectionDescription);
228
229 if (CollectionDescription->UsagePage == HID_USAGE_PAGE_GENERIC)
230 {
231 switch (CollectionDescription->Usage)
232 {
233 case HID_USAGE_GENERIC_POINTER:
234 case HID_USAGE_GENERIC_MOUSE:
235 //
236 // Pointer / Mouse
237 //
238 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_MOUSE") + 1;
239 break;
240 case HID_USAGE_GENERIC_GAMEPAD:
241 case HID_USAGE_GENERIC_JOYSTICK:
242 //
243 // Joystick / Gamepad
244 //
245 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_GAME") + 1;
246 break;
247 case HID_USAGE_GENERIC_KEYBOARD:
248 case HID_USAGE_GENERIC_KEYPAD:
249 //
250 // Keyboard / Keypad
251 //
252 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_KEYBOARD") + 1;
253 break;
254 case HID_USAGE_GENERIC_SYSTEM_CTL:
255 //
256 // System Control
257 //
258 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_CONTROL") + 1;
259 break;
260 }
261 }
262 else if (CollectionDescription->UsagePage == HID_USAGE_PAGE_CONSUMER && CollectionDescription->Usage == HID_USAGE_CONSUMERCTRL)
263 {
264 //
265 // Consumer Audio Control
266 //
267 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_CONSUMER") + 1;
268 }
269
270 //
271 // add HID_DEVICE_UP:0001_U:0002'
272 //
273 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_UP:%04x_U:%04x", CollectionDescription->UsagePage, CollectionDescription->Usage) + 1;
274
275 //
276 // add HID
277 //
278 Offset +=swprintf(&Buffer[Offset], L"HID_DEVICE") + 1;
279
280 //
281 // free old buffer
282 //
283 ExFreePoolWithTag((PVOID)Irp->IoStatus.Information, 0);
284
285 //
286 // allocate buffer
287 //
288 Ptr = ExAllocatePoolWithTag(NonPagedPool, (Offset + 1) * sizeof(WCHAR), HIDCLASS_TAG);
289 if (!Ptr)
290 {
291 //
292 // no memory
293 //
294 Irp->IoStatus.Information = 0;
295 return STATUS_INSUFFICIENT_RESOURCES;
296 }
297
298 //
299 // copy buffer
300 //
301 RtlCopyMemory(Ptr, Buffer, Offset * sizeof(WCHAR));
302 Ptr[Offset] = UNICODE_NULL;
303
304 //
305 // store result
306 //
307 Irp->IoStatus.Information = (ULONG_PTR)Ptr;
308 return STATUS_SUCCESS;
309 }
310
311 NTSTATUS
312 HidClassPDO_HandleQueryInstanceId(
313 IN PDEVICE_OBJECT DeviceObject,
314 IN PIRP Irp)
315 {
316 LPWSTR Buffer;
317 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
318
319 //
320 // get device extension
321 //
322 PDODeviceExtension = DeviceObject->DeviceExtension;
323 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
324
325 //
326 // allocate buffer
327 //
328 Buffer = ExAllocatePoolWithTag(NonPagedPool, 5 * sizeof(WCHAR), HIDCLASS_TAG);
329 if (!Buffer)
330 {
331 //
332 // failed
333 //
334 return STATUS_INSUFFICIENT_RESOURCES;
335 }
336
337 //
338 // write device id
339 //
340 swprintf(Buffer, L"%04x", PDODeviceExtension->CollectionNumber);
341 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
342
343 //
344 // done
345 //
346 return STATUS_SUCCESS;
347 }
348
349 NTSTATUS
350 HidClassPDO_HandleQueryCompatibleId(
351 IN PDEVICE_OBJECT DeviceObject,
352 IN PIRP Irp)
353 {
354 LPWSTR Buffer;
355
356 Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), HIDCLASS_TAG);
357 if (!Buffer)
358 {
359 //
360 // no memory
361 //
362 return STATUS_INSUFFICIENT_RESOURCES;
363 }
364
365 //
366 // zero buffer
367 //
368 Buffer[0] = 0;
369 Buffer[1] = 0;
370
371 //
372 // store result
373 //
374 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
375 return STATUS_SUCCESS;
376 }
377
378 NTSTATUS
379 HidClassPDO_PnP(
380 IN PDEVICE_OBJECT DeviceObject,
381 IN PIRP Irp)
382 {
383 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
384 PIO_STACK_LOCATION IoStack;
385 NTSTATUS Status;
386 PPNP_BUS_INFORMATION BusInformation;
387 PDEVICE_RELATIONS DeviceRelation;
388 ULONG Index, bFound;
389
390 //
391 // get device extension
392 //
393 PDODeviceExtension = DeviceObject->DeviceExtension;
394 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
395
396 //
397 // get current irp stack location
398 //
399 IoStack = IoGetCurrentIrpStackLocation(Irp);
400
401 //
402 // handle request
403 //
404 switch (IoStack->MinorFunction)
405 {
406 case IRP_MN_QUERY_ID:
407 {
408 if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
409 {
410 //
411 // handle query device id
412 //
413 Status = HidClassPDO_HandleQueryDeviceId(DeviceObject, Irp);
414 break;
415 }
416 else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
417 {
418 //
419 // handle instance id
420 //
421 Status = HidClassPDO_HandleQueryHardwareId(DeviceObject, Irp);
422 break;
423 }
424 else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
425 {
426 //
427 // handle instance id
428 //
429 Status = HidClassPDO_HandleQueryInstanceId(DeviceObject, Irp);
430 break;
431 }
432 else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
433 {
434 //
435 // handle instance id
436 //
437 Status = HidClassPDO_HandleQueryCompatibleId(DeviceObject, Irp);
438 break;
439 }
440
441 DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
442 Status = STATUS_NOT_SUPPORTED;
443 Irp->IoStatus.Information = 0;
444 break;
445 }
446 case IRP_MN_QUERY_CAPABILITIES:
447 {
448 if (IoStack->Parameters.DeviceCapabilities.Capabilities == NULL)
449 {
450 //
451 // invalid request
452 //
453 Status = STATUS_DEVICE_CONFIGURATION_ERROR;
454 break;
455 }
456
457 //
458 // copy capabilities
459 //
460 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities,
461 &PDODeviceExtension->Capabilities,
462 sizeof(DEVICE_CAPABILITIES));
463 Status = STATUS_SUCCESS;
464 break;
465 }
466 case IRP_MN_QUERY_BUS_INFORMATION:
467 {
468 //
469 //
470 //
471 BusInformation = ExAllocatePoolWithTag(NonPagedPool, sizeof(PNP_BUS_INFORMATION), HIDCLASS_TAG);
472
473 //
474 // fill in result
475 //
476 RtlCopyMemory(&BusInformation->BusTypeGuid, &GUID_BUS_TYPE_HID, sizeof(GUID));
477 BusInformation->LegacyBusType = PNPBus;
478 BusInformation->BusNumber = 0; //FIXME
479
480 //
481 // store result
482 //
483 Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
484 Status = STATUS_SUCCESS;
485 break;
486 }
487 case IRP_MN_QUERY_PNP_DEVICE_STATE:
488 {
489 //
490 // FIXME set flags when driver fails / disabled
491 //
492 Status = STATUS_SUCCESS;
493 break;
494 }
495 case IRP_MN_QUERY_DEVICE_RELATIONS:
496 {
497 //
498 // only target relations are supported
499 //
500 if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
501 {
502 //
503 // not supported
504 //
505 Status = Irp->IoStatus.Status;
506 break;
507 }
508
509 //
510 // allocate device relations
511 //
512 DeviceRelation = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_RELATIONS), HIDCLASS_TAG);
513 if (!DeviceRelation)
514 {
515 //
516 // no memory
517 //
518 Status = STATUS_INSUFFICIENT_RESOURCES;
519 break;
520 }
521
522 //
523 // init device relation
524 //
525 DeviceRelation->Count = 1;
526 DeviceRelation->Objects[0] = DeviceObject;
527 ObReferenceObject(DeviceRelation->Objects[0]);
528
529 //
530 // store result
531 //
532 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
533 Status = STATUS_SUCCESS;
534 break;
535 }
536 case IRP_MN_START_DEVICE:
537 {
538 //
539 // FIXME: support polled devices
540 //
541 ASSERT(PDODeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE);
542
543 //
544 // now register the device interface
545 //
546 Status = IoRegisterDeviceInterface(PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject,
547 &GUID_DEVINTERFACE_HID,
548 NULL,
549 &PDODeviceExtension->DeviceInterface);
550 DPRINT("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status);
551 if (NT_SUCCESS(Status))
552 {
553 //
554 // enable device interface
555 //
556 Status = IoSetDeviceInterfaceState(&PDODeviceExtension->DeviceInterface, TRUE);
557 DPRINT("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status);
558 }
559
560 //
561 // done
562 //
563 Status = STATUS_SUCCESS;
564 break;
565 }
566 case IRP_MN_REMOVE_DEVICE:
567 {
568 /* Disable the device interface */
569 if (PDODeviceExtension->DeviceInterface.Length != 0)
570 IoSetDeviceInterfaceState(&PDODeviceExtension->DeviceInterface, FALSE);
571
572 //
573 // remove us from the fdo's pdo list
574 //
575 bFound = FALSE;
576 for (Index = 0; Index < PDODeviceExtension->FDODeviceExtension->DeviceRelations->Count; Index++)
577 {
578 if (PDODeviceExtension->FDODeviceExtension->DeviceRelations->Objects[Index] == DeviceObject)
579 {
580 //
581 // remove us
582 //
583 bFound = TRUE;
584 PDODeviceExtension->FDODeviceExtension->DeviceRelations->Objects[Index] = NULL;
585 break;
586 }
587 }
588
589 /* Complete the IRP */
590 Irp->IoStatus.Status = STATUS_SUCCESS;
591 IoCompleteRequest(Irp, IO_NO_INCREMENT);
592
593 if (bFound)
594 {
595 /* Delete our device object*/
596 IoDeleteDevice(DeviceObject);
597 }
598
599 return STATUS_SUCCESS;
600 }
601 case IRP_MN_QUERY_INTERFACE:
602 {
603 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
604
605 //
606 // do nothing
607 //
608 Status = Irp->IoStatus.Status;
609 break;
610 }
611 case IRP_MN_QUERY_REMOVE_DEVICE:
612 case IRP_MN_CANCEL_STOP_DEVICE:
613 case IRP_MN_QUERY_STOP_DEVICE:
614 case IRP_MN_CANCEL_REMOVE_DEVICE:
615 {
616 //
617 // no/op
618 //
619 #if 0
620 Status = STATUS_SUCCESS;
621 #else
622 DPRINT1("Denying removal of HID device due to IRP cancellation bugs\n");
623 Status = STATUS_UNSUCCESSFUL;
624 #endif
625 break;
626 }
627 default:
628 {
629 //
630 // do nothing
631 //
632 Status = Irp->IoStatus.Status;
633 break;
634 }
635 }
636
637 //
638 // complete request
639 //
640 if (Status != STATUS_PENDING)
641 {
642 //
643 // store result
644 //
645 Irp->IoStatus.Status = Status;
646
647 //
648 // complete request
649 //
650 IoCompleteRequest(Irp, IO_NO_INCREMENT);
651 }
652
653 //
654 // done processing
655 //
656 return Status;
657 }
658
659 NTSTATUS
660 HidClassPDO_CreatePDO(
661 IN PDEVICE_OBJECT DeviceObject,
662 OUT PDEVICE_RELATIONS *OutDeviceRelations)
663 {
664 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
665 NTSTATUS Status = STATUS_SUCCESS;
666 PDEVICE_OBJECT PDODeviceObject;
667 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
668 ULONG Index;
669 PDEVICE_RELATIONS DeviceRelations;
670 ULONG Length;
671
672 //
673 // get device extension
674 //
675 FDODeviceExtension = DeviceObject->DeviceExtension;
676 ASSERT(FDODeviceExtension->Common.IsFDO);
677
678 //
679 // first allocate device relations
680 //
681 Length = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * FDODeviceExtension->Common.DeviceDescription.CollectionDescLength;
682 DeviceRelations = ExAllocatePoolWithTag(PagedPool, Length, HIDCLASS_TAG);
683 if (!DeviceRelations)
684 {
685 //
686 // no memory
687 //
688 return STATUS_INSUFFICIENT_RESOURCES;
689 }
690
691 //
692 // zero device relations
693 //
694 RtlZeroMemory(DeviceRelations, Length);
695
696 //
697 // let's create a PDO for top level collection
698 //
699 Index = 0;
700 while (Index < FDODeviceExtension->Common.DeviceDescription.CollectionDescLength)
701 {
702 //
703 // let's create the device object
704 //
705 Status = IoCreateDevice(FDODeviceExtension->Common.DriverExtension->DriverObject,
706 sizeof(HIDCLASS_PDO_DEVICE_EXTENSION),
707 NULL,
708 FILE_DEVICE_UNKNOWN,
709 FILE_AUTOGENERATED_DEVICE_NAME,
710 FALSE,
711 &PDODeviceObject);
712 if (!NT_SUCCESS(Status))
713 {
714 //
715 // failed to create device
716 //
717 DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status);
718 break;
719 }
720
721 //
722 // patch stack size
723 //
724 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
725
726 //
727 // get device extension
728 //
729 PDODeviceExtension = PDODeviceObject->DeviceExtension;
730
731 //
732 // init device extension
733 //
734 PDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension;
735 PDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject;
736 PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject;
737 PDODeviceExtension->Common.IsFDO = FALSE;
738 PDODeviceExtension->FDODeviceExtension = FDODeviceExtension;
739 PDODeviceExtension->FDODeviceObject = DeviceObject;
740 PDODeviceExtension->Common.DriverExtension = FDODeviceExtension->Common.DriverExtension;
741 PDODeviceExtension->CollectionNumber = FDODeviceExtension->Common.DeviceDescription.CollectionDesc[Index].CollectionNumber;
742
743 //
744 // copy device data
745 //
746 RtlCopyMemory(&PDODeviceExtension->Common.Attributes, &FDODeviceExtension->Common.Attributes, sizeof(HID_DEVICE_ATTRIBUTES));
747 RtlCopyMemory(&PDODeviceExtension->Common.DeviceDescription, &FDODeviceExtension->Common.DeviceDescription, sizeof(HIDP_DEVICE_DESC));
748 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
749
750 //
751 // set device flags
752 //
753 PDODeviceObject->Flags |= DO_MAP_IO_BUFFER;
754
755 //
756 // device is initialized
757 //
758 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
759
760 //
761 // store device object in device relations
762 //
763 DeviceRelations->Objects[Index] = PDODeviceObject;
764 DeviceRelations->Count++;
765
766 //
767 // move to next
768 //
769 Index++;
770
771 }
772
773
774 //
775 // check if creating succeeded
776 //
777 if (!NT_SUCCESS(Status))
778 {
779 //
780 // failed
781 //
782 for (Index = 0; Index < DeviceRelations->Count; Index++)
783 {
784 //
785 // delete device
786 //
787 IoDeleteDevice(DeviceRelations->Objects[Index]);
788 }
789
790 //
791 // free device relations
792 //
793 ExFreePoolWithTag(DeviceRelations, HIDCLASS_TAG);
794 return Status;
795 }
796
797 //
798 // store device relations
799 //
800 *OutDeviceRelations = DeviceRelations;
801
802 //
803 // done
804 //
805 return STATUS_SUCCESS;
806 }