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 } 807