1 /* 2 * PROJECT: ReactOS ISA PnP Bus driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: PDO-specific code 5 * COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org> 6 * Copyright 2020 Hervé Poussineau <hpoussin@reactos.org> 7 * Copyright 2021 Dmitry Borisov <di.sean@protonmail.com> 8 */ 9 10 #include "isapnp.h" 11 12 #define NDEBUG 13 #include <debug.h> 14 15 static 16 CODE_SEG("PAGE") 17 NTSTATUS 18 IsaPdoQueryDeviceRelations( 19 _In_ PISAPNP_PDO_EXTENSION PdoExt, 20 _Inout_ PIRP Irp, 21 _In_ PIO_STACK_LOCATION IrpSp) 22 { 23 PDEVICE_RELATIONS DeviceRelations; 24 25 PAGED_CODE(); 26 27 if (IrpSp->Parameters.QueryDeviceRelations.Type == RemovalRelations && 28 PdoExt->Common.Signature == IsaPnpReadDataPort) 29 { 30 return IsaPnpFillDeviceRelations(PdoExt->FdoExt, Irp, FALSE); 31 } 32 33 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) 34 return Irp->IoStatus.Status; 35 36 DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(*DeviceRelations), TAG_ISAPNP); 37 if (!DeviceRelations) 38 return STATUS_NO_MEMORY; 39 40 DeviceRelations->Count = 1; 41 DeviceRelations->Objects[0] = PdoExt->Common.Self; 42 ObReferenceObject(PdoExt->Common.Self); 43 44 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; 45 return STATUS_SUCCESS; 46 } 47 48 static 49 CODE_SEG("PAGE") 50 NTSTATUS 51 IsaPdoQueryCapabilities( 52 _In_ PISAPNP_PDO_EXTENSION PdoExt, 53 _Inout_ PIRP Irp, 54 _In_ PIO_STACK_LOCATION IrpSp) 55 { 56 PDEVICE_CAPABILITIES DeviceCapabilities; 57 ULONG i; 58 59 UNREFERENCED_PARAMETER(Irp); 60 61 PAGED_CODE(); 62 63 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities; 64 if (DeviceCapabilities->Version != 1) 65 return STATUS_REVISION_MISMATCH; 66 67 DeviceCapabilities->LockSupported = 68 DeviceCapabilities->EjectSupported = 69 DeviceCapabilities->Removable = 70 DeviceCapabilities->DockDevice = FALSE; 71 72 DeviceCapabilities->UniqueID = TRUE; 73 74 if (PdoExt->Common.Signature == IsaPnpReadDataPort) 75 { 76 DeviceCapabilities->RawDeviceOK = TRUE; 77 DeviceCapabilities->SilentInstall = TRUE; 78 } 79 80 for (i = 0; i < POWER_SYSTEM_MAXIMUM; i++) 81 DeviceCapabilities->DeviceState[i] = PowerDeviceD3; 82 DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0; 83 84 return STATUS_SUCCESS; 85 } 86 87 static 88 CODE_SEG("PAGE") 89 NTSTATUS 90 IsaPdoQueryPnpDeviceState( 91 _In_ PISAPNP_PDO_EXTENSION PdoExt, 92 _Inout_ PIRP Irp) 93 { 94 PAGED_CODE(); 95 96 if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE) 97 { 98 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE | 99 PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED | 100 PNP_DEVICE_FAILED; 101 return STATUS_SUCCESS; 102 } 103 else if (PdoExt->SpecialFiles > 0) 104 { 105 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; 106 return STATUS_SUCCESS; 107 } 108 109 return Irp->IoStatus.Status; 110 } 111 112 static 113 CODE_SEG("PAGE") 114 NTSTATUS 115 IsaPdoQueryId( 116 _In_ PISAPNP_PDO_EXTENSION PdoExt, 117 _Inout_ PIRP Irp, 118 _In_ PIO_STACK_LOCATION IrpSp) 119 { 120 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; 121 NTSTATUS Status; 122 PWCHAR Buffer, End, IdStart; 123 size_t CharCount, Remaining; 124 125 PAGED_CODE(); 126 127 switch (IrpSp->Parameters.QueryId.IdType) 128 { 129 case BusQueryDeviceID: 130 { 131 CharCount = sizeof("ISAPNP\\XXXFFFF"); 132 133 if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS) 134 { 135 CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL); 136 } 137 138 Buffer = ExAllocatePoolWithTag(PagedPool, 139 CharCount * sizeof(WCHAR), 140 TAG_ISAPNP); 141 if (!Buffer) 142 return STATUS_INSUFFICIENT_RESOURCES; 143 144 Status = RtlStringCchPrintfExW(Buffer, 145 CharCount, 146 &End, 147 &Remaining, 148 0, 149 L"ISAPNP\\%.3S%04X", 150 LogDev->VendorId, 151 LogDev->ProdId); 152 if (!NT_VERIFY(NT_SUCCESS(Status))) 153 goto Failure; 154 155 if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS) 156 { 157 Status = RtlStringCchPrintfExW(End, 158 Remaining, 159 NULL, 160 NULL, 161 0, 162 L"_DEV%04X", 163 LogDev->LDN); 164 if (!NT_VERIFY(NT_SUCCESS(Status))) 165 goto Failure; 166 } 167 168 DPRINT("Device ID: '%S'\n", Buffer); 169 break; 170 } 171 172 case BusQueryHardwareIDs: 173 { 174 CharCount = sizeof("ISAPNP\\XXXFFFF") + 175 sizeof("*PNPxxxx") + 176 sizeof(ANSI_NULL); /* multi-string */ 177 178 if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS) 179 { 180 CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL); 181 } 182 183 Buffer = ExAllocatePoolWithTag(PagedPool, 184 CharCount * sizeof(WCHAR), 185 TAG_ISAPNP); 186 if (!Buffer) 187 return STATUS_INSUFFICIENT_RESOURCES; 188 189 DPRINT("Hardware IDs:\n"); 190 191 /* 1 */ 192 Status = RtlStringCchPrintfExW(Buffer, 193 CharCount, 194 &End, 195 &Remaining, 196 0, 197 L"ISAPNP\\%.3S%04X", 198 LogDev->VendorId, 199 LogDev->ProdId); 200 if (!NT_VERIFY(NT_SUCCESS(Status))) 201 goto Failure; 202 203 if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS) 204 { 205 Status = RtlStringCchPrintfExW(End, 206 Remaining, 207 &End, 208 &Remaining, 209 0, 210 L"_DEV%04X", 211 LogDev->LDN); 212 if (!NT_VERIFY(NT_SUCCESS(Status))) 213 goto Failure; 214 } 215 216 DPRINT(" '%S'\n", Buffer); 217 218 ++End; 219 --Remaining; 220 221 /* 2 */ 222 IdStart = End; 223 Status = RtlStringCchPrintfExW(End, 224 Remaining, 225 &End, 226 &Remaining, 227 0, 228 L"*%.3S%04X", 229 LogDev->LogVendorId, 230 LogDev->LogProdId); 231 if (!NT_VERIFY(NT_SUCCESS(Status))) 232 goto Failure; 233 234 DPRINT(" '%S'\n", IdStart); 235 236 *++End = UNICODE_NULL; 237 --Remaining; 238 239 break; 240 } 241 242 case BusQueryCompatibleIDs: 243 { 244 PLIST_ENTRY Entry; 245 246 for (Entry = LogDev->CompatibleIdList.Flink, CharCount = 0; 247 Entry != &LogDev->CompatibleIdList; 248 Entry = Entry->Flink) 249 { 250 CharCount += sizeof("*PNPxxxx"); 251 } 252 CharCount += sizeof(ANSI_NULL); /* multi-string */ 253 254 if (CharCount == sizeof(ANSI_NULL)) 255 return Irp->IoStatus.Status; 256 257 Buffer = ExAllocatePoolWithTag(PagedPool, 258 CharCount * sizeof(WCHAR), 259 TAG_ISAPNP); 260 if (!Buffer) 261 return STATUS_INSUFFICIENT_RESOURCES; 262 263 DPRINT("Compatible IDs:\n"); 264 265 for (Entry = LogDev->CompatibleIdList.Flink, End = Buffer, Remaining = CharCount; 266 Entry != &LogDev->CompatibleIdList; 267 Entry = Entry->Flink) 268 { 269 PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId = 270 CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink); 271 272 IdStart = End; 273 Status = RtlStringCchPrintfExW(End, 274 Remaining, 275 &End, 276 &Remaining, 277 0, 278 L"*%.3S%04X", 279 CompatibleId->VendorId, 280 CompatibleId->ProdId); 281 if (!NT_VERIFY(NT_SUCCESS(Status))) 282 goto Failure; 283 284 DPRINT(" '%S'\n", IdStart); 285 286 ++End; 287 --Remaining; 288 } 289 290 *End = UNICODE_NULL; 291 292 break; 293 } 294 295 case BusQueryInstanceID: 296 { 297 CharCount = sizeof(LogDev->SerialNumber) * 2 + sizeof(ANSI_NULL); 298 299 Buffer = ExAllocatePoolWithTag(PagedPool, 300 CharCount * sizeof(WCHAR), 301 TAG_ISAPNP); 302 if (!Buffer) 303 return STATUS_INSUFFICIENT_RESOURCES; 304 305 Status = RtlStringCchPrintfExW(Buffer, 306 CharCount, 307 NULL, 308 NULL, 309 0, 310 L"%X", 311 LogDev->SerialNumber); 312 if (!NT_VERIFY(NT_SUCCESS(Status))) 313 goto Failure; 314 315 DPRINT("Instance ID: '%S'\n", Buffer); 316 break; 317 } 318 319 default: 320 return Irp->IoStatus.Status; 321 } 322 323 Irp->IoStatus.Information = (ULONG_PTR)Buffer; 324 return STATUS_SUCCESS; 325 326 Failure: 327 ExFreePoolWithTag(Buffer, TAG_ISAPNP); 328 329 return Status; 330 } 331 332 static 333 CODE_SEG("PAGE") 334 NTSTATUS 335 IsaReadPortQueryId( 336 _Inout_ PIRP Irp, 337 _In_ PIO_STACK_LOCATION IrpSp) 338 { 339 PWCHAR Buffer; 340 static const WCHAR ReadPortId[] = L"ISAPNP\\ReadDataPort"; 341 342 PAGED_CODE(); 343 344 switch (IrpSp->Parameters.QueryId.IdType) 345 { 346 case BusQueryDeviceID: 347 { 348 Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(ReadPortId), TAG_ISAPNP); 349 if (!Buffer) 350 return STATUS_INSUFFICIENT_RESOURCES; 351 352 RtlCopyMemory(Buffer, ReadPortId, sizeof(ReadPortId)); 353 354 DPRINT("Device ID: '%S'\n", Buffer); 355 break; 356 } 357 358 case BusQueryHardwareIDs: 359 { 360 Buffer = ExAllocatePoolWithTag(PagedPool, 361 sizeof(ReadPortId) + sizeof(UNICODE_NULL), 362 TAG_ISAPNP); 363 if (!Buffer) 364 return STATUS_INSUFFICIENT_RESOURCES; 365 366 RtlCopyMemory(Buffer, ReadPortId, sizeof(ReadPortId)); 367 368 Buffer[sizeof(ReadPortId) / sizeof(WCHAR)] = UNICODE_NULL; /* multi-string */ 369 370 DPRINT("Hardware ID: '%S'\n", Buffer); 371 break; 372 } 373 374 case BusQueryCompatibleIDs: 375 { 376 /* Empty multi-string */ 377 Buffer = ExAllocatePoolZero(PagedPool, sizeof(UNICODE_NULL) * 2, TAG_ISAPNP); 378 if (!Buffer) 379 return STATUS_INSUFFICIENT_RESOURCES; 380 381 DPRINT("Compatible ID: '%S'\n", Buffer); 382 break; 383 } 384 385 case BusQueryInstanceID: 386 { 387 /* Even if there are multiple ISA buses, the driver has only one Read Port */ 388 static const WCHAR InstanceId[] = L"0"; 389 390 Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(InstanceId), TAG_ISAPNP); 391 if (!Buffer) 392 return STATUS_INSUFFICIENT_RESOURCES; 393 394 RtlCopyMemory(Buffer, InstanceId, sizeof(InstanceId)); 395 396 DPRINT("Instance ID: '%S'\n", Buffer); 397 break; 398 } 399 400 default: 401 return Irp->IoStatus.Status; 402 } 403 404 Irp->IoStatus.Information = (ULONG_PTR)Buffer; 405 return STATUS_SUCCESS; 406 } 407 408 static 409 CODE_SEG("PAGE") 410 NTSTATUS 411 IsaPdoQueryDeviceText( 412 _In_ PISAPNP_PDO_EXTENSION PdoExt, 413 _Inout_ PIRP Irp, 414 _In_ PIO_STACK_LOCATION IrpSp) 415 { 416 NTSTATUS Status; 417 PWCHAR Buffer; 418 size_t CharCount; 419 420 PAGED_CODE(); 421 422 switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType) 423 { 424 case DeviceTextDescription: 425 { 426 if (!PdoExt->IsaPnpDevice->FriendlyName) 427 return Irp->IoStatus.Status; 428 429 CharCount = strlen(PdoExt->IsaPnpDevice->FriendlyName) + 430 sizeof(ANSI_NULL); 431 432 if (CharCount == sizeof(ANSI_NULL)) 433 return Irp->IoStatus.Status; 434 435 Buffer = ExAllocatePoolWithTag(PagedPool, 436 CharCount * sizeof(WCHAR), 437 TAG_ISAPNP); 438 if (!Buffer) 439 return STATUS_INSUFFICIENT_RESOURCES; 440 441 Status = RtlStringCchPrintfExW(Buffer, 442 CharCount, 443 NULL, 444 NULL, 445 0, 446 L"%hs", 447 PdoExt->IsaPnpDevice->FriendlyName); 448 if (!NT_VERIFY(NT_SUCCESS(Status))) 449 { 450 ExFreePoolWithTag(Buffer, TAG_ISAPNP); 451 return Status; 452 } 453 454 DPRINT("TextDescription: '%S'\n", Buffer); 455 break; 456 } 457 458 default: 459 return Irp->IoStatus.Status; 460 } 461 462 Irp->IoStatus.Information = (ULONG_PTR)Buffer; 463 return STATUS_SUCCESS; 464 } 465 466 static 467 CODE_SEG("PAGE") 468 NTSTATUS 469 IsaPdoQueryResources( 470 _In_ PISAPNP_PDO_EXTENSION PdoExt, 471 _Inout_ PIRP Irp, 472 _In_ PIO_STACK_LOCATION IrpSp) 473 { 474 ULONG ListSize; 475 PCM_RESOURCE_LIST ResourceList; 476 477 UNREFERENCED_PARAMETER(IrpSp); 478 479 PAGED_CODE(); 480 481 if (PdoExt->Common.Signature == IsaPnpLogicalDevice && 482 !(PdoExt->IsaPnpDevice->Flags & ISAPNP_HAS_RESOURCES)) 483 { 484 Irp->IoStatus.Information = 0; 485 return STATUS_SUCCESS; 486 } 487 488 if (!PdoExt->ResourceList) 489 return Irp->IoStatus.Status; 490 491 ListSize = PdoExt->ResourceListSize; 492 ResourceList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_ISAPNP); 493 if (!ResourceList) 494 return STATUS_NO_MEMORY; 495 496 RtlCopyMemory(ResourceList, PdoExt->ResourceList, ListSize); 497 Irp->IoStatus.Information = (ULONG_PTR)ResourceList; 498 return STATUS_SUCCESS; 499 } 500 501 static 502 CODE_SEG("PAGE") 503 NTSTATUS 504 IsaPdoQueryResourceRequirements( 505 _In_ PISAPNP_PDO_EXTENSION PdoExt, 506 _Inout_ PIRP Irp, 507 _In_ PIO_STACK_LOCATION IrpSp) 508 { 509 ULONG ListSize; 510 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; 511 512 UNREFERENCED_PARAMETER(IrpSp); 513 514 PAGED_CODE(); 515 516 if (!PdoExt->RequirementsList) 517 return Irp->IoStatus.Status; 518 519 ListSize = PdoExt->RequirementsList->ListSize; 520 RequirementsList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_ISAPNP); 521 if (!RequirementsList) 522 return STATUS_NO_MEMORY; 523 524 RtlCopyMemory(RequirementsList, PdoExt->RequirementsList, ListSize); 525 Irp->IoStatus.Information = (ULONG_PTR)RequirementsList; 526 return STATUS_SUCCESS; 527 } 528 529 #define IS_READ_PORT(_d) ((_d)->Type == CmResourceTypePort && (_d)->u.Port.Length > 1) 530 531 static 532 CODE_SEG("PAGE") 533 NTSTATUS 534 IsaPdoStartReadPort( 535 _In_ PISAPNP_PDO_EXTENSION PdoExt, 536 _In_ PCM_RESOURCE_LIST ResourceList) 537 { 538 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; 539 NTSTATUS Status; 540 ULONG i; 541 542 PAGED_CODE(); 543 544 if (!ResourceList) 545 { 546 DPRINT1("No resource list\n"); 547 return STATUS_INSUFFICIENT_RESOURCES; 548 } 549 550 if (ResourceList->List[0].PartialResourceList.Version != 1 || 551 ResourceList->List[0].PartialResourceList.Revision != 1) 552 { 553 DPRINT1("Bad resource list version (%u.%u)\n", 554 ResourceList->List[0].PartialResourceList.Version, 555 ResourceList->List[0].PartialResourceList.Revision); 556 return STATUS_REVISION_MISMATCH; 557 } 558 559 #if 0 560 /* Try various Read Ports from the list */ 561 if (ResourceList->List[0].PartialResourceList.Count > 3) 562 { 563 ULONG SelectedPort = 0; 564 565 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) 566 { 567 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = 568 &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 569 570 if (IS_READ_PORT(PartialDescriptor)) 571 { 572 PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); 573 ULONG Cards; 574 575 /* 576 * Remember the first Read Port in the resource list. 577 * It will be selected by default even if no card has been detected. 578 */ 579 if (!SelectedPort) 580 SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; 581 582 Cards = IsaHwTryReadDataPort(ReadDataPort); 583 IsaHwWaitForKey(); 584 585 /* We detected some ISAPNP cards */ 586 if (Cards > 0) 587 { 588 SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; 589 break; 590 } 591 } 592 } 593 594 ASSERT(SelectedPort != 0); 595 596 if (PdoExt->RequirementsList) 597 { 598 ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP); 599 PdoExt->RequirementsList = NULL; 600 } 601 602 /* Discard the Read Ports at conflicting locations */ 603 Status = IsaPnpCreateReadPortDORequirements(PdoExt, SelectedPort); 604 if (!NT_SUCCESS(Status)) 605 return Status; 606 607 PdoExt->Flags |= ISAPNP_READ_PORT_NEED_REBALANCE; 608 609 IoInvalidateDeviceState(PdoExt->Common.Self); 610 611 return STATUS_SUCCESS; 612 } 613 /* Set the Read Port */ 614 else if (ResourceList->List[0].PartialResourceList.Count == 3) 615 #else 616 if (ResourceList->List[0].PartialResourceList.Count > 3) /* Temporary HACK */ 617 #endif 618 { 619 PdoExt->Flags &= ~ISAPNP_READ_PORT_NEED_REBALANCE; 620 621 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) 622 { 623 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = 624 &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 625 626 if (IS_READ_PORT(PartialDescriptor)) 627 { 628 PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); 629 630 /* Run the isolation protocol */ 631 FdoExt->Cards = IsaHwTryReadDataPort(ReadDataPort); 632 633 if (FdoExt->Cards > 0) 634 { 635 FdoExt->ReadDataPort = ReadDataPort; 636 637 IsaPnpAcquireDeviceDataLock(FdoExt); 638 639 /* Card identification */ 640 Status = IsaHwFillDeviceList(FdoExt); 641 IsaHwWaitForKey(); 642 643 IsaPnpReleaseDeviceDataLock(FdoExt); 644 645 PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN | 646 ISAPNP_SCANNED_BY_READ_PORT; 647 648 IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); 649 IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations); 650 651 return Status; 652 } 653 else 654 { 655 IsaHwWaitForKey(); 656 #if 0 /* See the 'if 0' above */ 657 break; 658 #endif 659 } 660 } 661 } 662 } 663 else 664 { 665 return STATUS_DEVICE_CONFIGURATION_ERROR; 666 } 667 668 /* Mark Read Port as started, even if no card has been detected */ 669 return STATUS_SUCCESS; 670 } 671 672 static 673 CODE_SEG("PAGE") 674 NTSTATUS 675 IsaPdoFilterResourceRequirements( 676 _In_ PISAPNP_PDO_EXTENSION PdoExt, 677 _Inout_ PIRP Irp, 678 _In_ PIO_STACK_LOCATION IrpSp) 679 { 680 PAGED_CODE(); 681 682 /* TODO: Handle */ 683 UNREFERENCED_PARAMETER(PdoExt); 684 UNREFERENCED_PARAMETER(IrpSp); 685 return Irp->IoStatus.Status; 686 } 687 688 static 689 CODE_SEG("PAGE") 690 NTSTATUS 691 IsaPdoQueryBusInformation( 692 _In_ PISAPNP_PDO_EXTENSION PdoExt, 693 _Inout_ PIRP Irp) 694 { 695 PPNP_BUS_INFORMATION BusInformation; 696 697 PAGED_CODE(); 698 699 BusInformation = ExAllocatePoolWithTag(PagedPool, 700 sizeof(PNP_BUS_INFORMATION), 701 TAG_ISAPNP); 702 if (!BusInformation) 703 return STATUS_INSUFFICIENT_RESOURCES; 704 705 BusInformation->BusTypeGuid = GUID_BUS_TYPE_ISAPNP; 706 BusInformation->LegacyBusType = Isa; 707 BusInformation->BusNumber = PdoExt->FdoExt->BusNumber; 708 709 Irp->IoStatus.Information = (ULONG_PTR)BusInformation; 710 return STATUS_SUCCESS; 711 } 712 713 static 714 CODE_SEG("PAGE") 715 NTSTATUS 716 IsaPdoQueryDeviceUsageNotification( 717 _In_ PISAPNP_PDO_EXTENSION PdoExt, 718 _Inout_ PIRP Irp, 719 _In_ PIO_STACK_LOCATION IrpSp) 720 { 721 BOOLEAN InPath = IrpSp->Parameters.UsageNotification.InPath; 722 723 PAGED_CODE(); 724 725 switch (IrpSp->Parameters.UsageNotification.Type) 726 { 727 case DeviceUsageTypePaging: 728 case DeviceUsageTypeHibernation: 729 case DeviceUsageTypeDumpFile: 730 IoAdjustPagingPathCount(&PdoExt->SpecialFiles, InPath); 731 IoInvalidateDeviceState(PdoExt->Common.Self); 732 break; 733 734 default: 735 return Irp->IoStatus.Status; 736 } 737 738 /* Do not send it to FDO for compatibility */ 739 return STATUS_SUCCESS; 740 } 741 742 static 743 CODE_SEG("PAGE") 744 NTSTATUS 745 IsaPdoRemoveDevice( 746 _In_ PISAPNP_PDO_EXTENSION PdoExt, 747 _In_ BOOLEAN FinalRemove) 748 { 749 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; 750 751 PAGED_CODE(); 752 753 /* Deactivate the device if previously activated */ 754 if (PdoExt->Common.State == dsStarted) 755 { 756 IsaHwWakeDevice(PdoExt->IsaPnpDevice); 757 IsaHwDeactivateDevice(PdoExt->IsaPnpDevice); 758 759 IsaHwWaitForKey(); 760 761 PdoExt->Common.State = dsStopped; 762 } 763 764 if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED)) 765 { 766 IsaPnpAcquireDeviceDataLock(FdoExt); 767 768 RemoveEntryList(&PdoExt->IsaPnpDevice->DeviceLink); 769 --FdoExt->DeviceCount; 770 771 IsaPnpReleaseDeviceDataLock(FdoExt); 772 773 IsaPnpRemoveLogicalDeviceDO(PdoExt->Common.Self); 774 } 775 776 return STATUS_SUCCESS; 777 } 778 779 static 780 CODE_SEG("PAGE") 781 NTSTATUS 782 IsaReadPortRemoveDevice( 783 _In_ PISAPNP_PDO_EXTENSION PdoExt, 784 _In_ BOOLEAN FinalRemove) 785 { 786 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; 787 PLIST_ENTRY Entry; 788 789 PAGED_CODE(); 790 791 IsaPnpAcquireDeviceDataLock(FdoExt); 792 793 /* Logical devices will receive a remove request afterwards */ 794 for (Entry = FdoExt->DeviceListHead.Flink; 795 Entry != &FdoExt->DeviceListHead; 796 Entry = Entry->Flink) 797 { 798 PISAPNP_LOGICAL_DEVICE LogDevice = CONTAINING_RECORD(Entry, 799 ISAPNP_LOGICAL_DEVICE, 800 DeviceLink); 801 802 LogDevice->Flags &= ~ISAPNP_PRESENT; 803 } 804 805 IsaPnpReleaseDeviceDataLock(FdoExt); 806 807 PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN; 808 IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); 809 810 if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED)) 811 { 812 IsaPnpRemoveReadPortDO(PdoExt->Common.Self); 813 } 814 815 return STATUS_SUCCESS; 816 } 817 818 CODE_SEG("PAGE") 819 VOID 820 IsaPnpRemoveLogicalDeviceDO( 821 _In_ PDEVICE_OBJECT Pdo) 822 { 823 PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension; 824 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; 825 PLIST_ENTRY Entry; 826 827 PAGED_CODE(); 828 ASSERT(LogDev); 829 830 DPRINT("Removing CSN %u, LDN %u\n", LogDev->CSN, LogDev->LDN); 831 832 if (PdoExt->RequirementsList) 833 ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP); 834 835 if (PdoExt->ResourceList) 836 ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP); 837 838 if (LogDev->FriendlyName) 839 ExFreePoolWithTag(LogDev->FriendlyName, TAG_ISAPNP); 840 841 if (LogDev->Alternatives) 842 ExFreePoolWithTag(LogDev->Alternatives, TAG_ISAPNP); 843 844 Entry = LogDev->CompatibleIdList.Flink; 845 while (Entry != &LogDev->CompatibleIdList) 846 { 847 PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId = 848 CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink); 849 850 RemoveEntryList(&CompatibleId->IdLink); 851 852 Entry = Entry->Flink; 853 854 ExFreePoolWithTag(CompatibleId, TAG_ISAPNP); 855 } 856 857 ExFreePoolWithTag(LogDev, TAG_ISAPNP); 858 859 IoDeleteDevice(PdoExt->Common.Self); 860 } 861 862 CODE_SEG("PAGE") 863 NTSTATUS 864 IsaPdoPnp( 865 _In_ PISAPNP_PDO_EXTENSION PdoExt, 866 _Inout_ PIRP Irp, 867 _In_ PIO_STACK_LOCATION IrpSp) 868 { 869 NTSTATUS Status = Irp->IoStatus.Status; 870 871 PAGED_CODE(); 872 873 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 874 { 875 DPRINT("%s(%p, %p) CSN %u, LDN %u, Minor - %X\n", 876 __FUNCTION__, 877 PdoExt, 878 Irp, 879 PdoExt->IsaPnpDevice->CSN, 880 PdoExt->IsaPnpDevice->LDN, 881 IrpSp->MinorFunction); 882 } 883 else 884 { 885 DPRINT("%s(%p, %p) ReadPort, Minor - %X\n", 886 __FUNCTION__, 887 PdoExt, 888 Irp, 889 IrpSp->MinorFunction); 890 } 891 892 switch (IrpSp->MinorFunction) 893 { 894 case IRP_MN_START_DEVICE: 895 { 896 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 897 { 898 IsaHwWakeDevice(PdoExt->IsaPnpDevice); 899 900 Status = IsaHwConfigureDevice(PdoExt->FdoExt, 901 PdoExt->IsaPnpDevice, 902 IrpSp->Parameters.StartDevice.AllocatedResources); 903 if (NT_SUCCESS(Status)) 904 { 905 IsaHwActivateDevice(PdoExt->FdoExt, PdoExt->IsaPnpDevice); 906 } 907 else 908 { 909 DPRINT1("Failed to configure CSN %u, LDN %u with status 0x%08lx\n", 910 PdoExt->IsaPnpDevice->CSN, PdoExt->IsaPnpDevice->LDN, Status); 911 } 912 913 IsaHwWaitForKey(); 914 } 915 else 916 { 917 Status = IsaPdoStartReadPort(PdoExt, 918 IrpSp->Parameters.StartDevice.AllocatedResources); 919 } 920 921 if (NT_SUCCESS(Status)) 922 PdoExt->Common.State = dsStarted; 923 break; 924 } 925 926 case IRP_MN_STOP_DEVICE: 927 { 928 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 929 { 930 IsaHwWakeDevice(PdoExt->IsaPnpDevice); 931 IsaHwDeactivateDevice(PdoExt->IsaPnpDevice); 932 933 IsaHwWaitForKey(); 934 } 935 else 936 { 937 PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN; 938 } 939 940 Status = STATUS_SUCCESS; 941 942 if (NT_SUCCESS(Status)) 943 PdoExt->Common.State = dsStopped; 944 break; 945 } 946 947 case IRP_MN_QUERY_STOP_DEVICE: 948 { 949 if (PdoExt->SpecialFiles > 0) 950 Status = STATUS_DEVICE_BUSY; 951 else if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE) 952 Status = STATUS_RESOURCE_REQUIREMENTS_CHANGED; 953 else 954 Status = STATUS_SUCCESS; 955 956 break; 957 } 958 959 case IRP_MN_QUERY_REMOVE_DEVICE: 960 { 961 if (PdoExt->SpecialFiles > 0) 962 Status = STATUS_DEVICE_BUSY; 963 else 964 Status = STATUS_SUCCESS; 965 break; 966 } 967 968 case IRP_MN_QUERY_DEVICE_RELATIONS: 969 Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp); 970 break; 971 972 case IRP_MN_QUERY_CAPABILITIES: 973 Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp); 974 break; 975 976 case IRP_MN_SURPRISE_REMOVAL: 977 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 978 Status = IsaPdoRemoveDevice(PdoExt, FALSE); 979 else 980 Status = IsaReadPortRemoveDevice(PdoExt, FALSE); 981 break; 982 983 case IRP_MN_REMOVE_DEVICE: 984 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 985 Status = IsaPdoRemoveDevice(PdoExt, TRUE); 986 else 987 Status = IsaReadPortRemoveDevice(PdoExt, TRUE); 988 break; 989 990 case IRP_MN_QUERY_PNP_DEVICE_STATE: 991 Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp); 992 break; 993 994 case IRP_MN_QUERY_RESOURCES: 995 Status = IsaPdoQueryResources(PdoExt, Irp, IrpSp); 996 break; 997 998 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: 999 Status = IsaPdoQueryResourceRequirements(PdoExt, Irp, IrpSp); 1000 break; 1001 1002 case IRP_MN_QUERY_ID: 1003 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 1004 Status = IsaPdoQueryId(PdoExt, Irp, IrpSp); 1005 else 1006 Status = IsaReadPortQueryId(Irp, IrpSp); 1007 break; 1008 1009 case IRP_MN_QUERY_DEVICE_TEXT: 1010 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 1011 Status = IsaPdoQueryDeviceText(PdoExt, Irp, IrpSp); 1012 break; 1013 1014 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 1015 Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp); 1016 break; 1017 1018 case IRP_MN_QUERY_BUS_INFORMATION: 1019 Status = IsaPdoQueryBusInformation(PdoExt, Irp); 1020 break; 1021 1022 case IRP_MN_DEVICE_USAGE_NOTIFICATION: 1023 Status = IsaPdoQueryDeviceUsageNotification(PdoExt, Irp, IrpSp); 1024 break; 1025 1026 case IRP_MN_CANCEL_REMOVE_DEVICE: 1027 case IRP_MN_CANCEL_STOP_DEVICE: 1028 Status = STATUS_SUCCESS; 1029 break; 1030 1031 default: 1032 DPRINT("Unknown PnP code: %X\n", IrpSp->MinorFunction); 1033 break; 1034 } 1035 1036 Irp->IoStatus.Status = Status; 1037 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1038 1039 return Status; 1040 } 1041