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 == IsaPnpReadDataPort) 482 { 483 ResourceList = IsaPnpCreateReadPortDOResources(); 484 if (!ResourceList) 485 return STATUS_NO_MEMORY; 486 487 Irp->IoStatus.Information = (ULONG_PTR)ResourceList; 488 return STATUS_SUCCESS; 489 } 490 491 if (!PdoExt->ResourceList) 492 return Irp->IoStatus.Status; 493 494 ListSize = PdoExt->ResourceListSize; 495 ResourceList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_ISAPNP); 496 if (!ResourceList) 497 return STATUS_NO_MEMORY; 498 499 RtlCopyMemory(ResourceList, PdoExt->ResourceList, ListSize); 500 Irp->IoStatus.Information = (ULONG_PTR)ResourceList; 501 return STATUS_SUCCESS; 502 } 503 504 static 505 CODE_SEG("PAGE") 506 NTSTATUS 507 IsaPdoQueryResourceRequirements( 508 _In_ PISAPNP_PDO_EXTENSION PdoExt, 509 _Inout_ PIRP Irp, 510 _In_ PIO_STACK_LOCATION IrpSp) 511 { 512 ULONG ListSize; 513 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; 514 515 UNREFERENCED_PARAMETER(IrpSp); 516 517 PAGED_CODE(); 518 519 if (PdoExt->Common.Signature == IsaPnpReadDataPort) 520 { 521 RequirementsList = IsaPnpCreateReadPortDORequirements(PdoExt->SelectedPort); 522 if (!RequirementsList) 523 return STATUS_NO_MEMORY; 524 525 Irp->IoStatus.Information = (ULONG_PTR)RequirementsList; 526 return STATUS_SUCCESS; 527 } 528 529 if (!PdoExt->RequirementsList) 530 return Irp->IoStatus.Status; 531 532 ListSize = PdoExt->RequirementsList->ListSize; 533 RequirementsList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_ISAPNP); 534 if (!RequirementsList) 535 return STATUS_NO_MEMORY; 536 537 RtlCopyMemory(RequirementsList, PdoExt->RequirementsList, ListSize); 538 Irp->IoStatus.Information = (ULONG_PTR)RequirementsList; 539 return STATUS_SUCCESS; 540 } 541 542 #define IS_READ_PORT(_d) ((_d)->Type == CmResourceTypePort && (_d)->u.Port.Length > 1) 543 544 static 545 CODE_SEG("PAGE") 546 NTSTATUS 547 IsaPdoStartReadPort( 548 _In_ PISAPNP_PDO_EXTENSION PdoExt, 549 _In_ PCM_RESOURCE_LIST ResourceList) 550 { 551 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; 552 NTSTATUS Status; 553 ULONG i; 554 555 PAGED_CODE(); 556 557 if (!ResourceList) 558 { 559 DPRINT1("No resource list\n"); 560 return STATUS_INSUFFICIENT_RESOURCES; 561 } 562 563 if (ResourceList->List[0].PartialResourceList.Version != 1 || 564 ResourceList->List[0].PartialResourceList.Revision != 1) 565 { 566 DPRINT1("Bad resource list version (%u.%u)\n", 567 ResourceList->List[0].PartialResourceList.Version, 568 ResourceList->List[0].PartialResourceList.Revision); 569 return STATUS_REVISION_MISMATCH; 570 } 571 572 #if 0 573 /* Try various Read Ports from the list */ 574 if (ResourceList->List[0].PartialResourceList.Count > 3) 575 { 576 ULONG SelectedPort = 0; 577 578 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) 579 { 580 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = 581 &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 582 583 if (IS_READ_PORT(PartialDescriptor)) 584 { 585 PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); 586 ULONG Cards; 587 588 /* 589 * Remember the first Read Port in the resource list. 590 * It will be selected by default even if no card has been detected. 591 */ 592 if (!SelectedPort) 593 SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; 594 595 Cards = IsaHwTryReadDataPort(ReadDataPort); 596 IsaHwWaitForKey(); 597 598 /* We detected some ISAPNP cards */ 599 if (Cards > 0) 600 { 601 SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; 602 break; 603 } 604 } 605 } 606 607 ASSERT(SelectedPort != 0); 608 609 /* Discard the Read Ports at conflicting locations */ 610 PdoExt->SelectedPort = SelectedPort; 611 PdoExt->Flags |= ISAPNP_READ_PORT_NEED_REBALANCE; 612 IoInvalidateDeviceState(PdoExt->Common.Self); 613 614 return STATUS_SUCCESS; 615 } 616 /* Set the Read Port */ 617 else if (ResourceList->List[0].PartialResourceList.Count == 3) 618 #else 619 if (ResourceList->List[0].PartialResourceList.Count > 3) /* Temporary HACK */ 620 #endif 621 { 622 PdoExt->Flags &= ~ISAPNP_READ_PORT_NEED_REBALANCE; 623 624 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) 625 { 626 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = 627 &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 628 629 if (IS_READ_PORT(PartialDescriptor)) 630 { 631 PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); 632 633 /* Run the isolation protocol */ 634 FdoExt->Cards = IsaHwTryReadDataPort(ReadDataPort); 635 636 if (FdoExt->Cards > 0) 637 { 638 FdoExt->ReadDataPort = ReadDataPort; 639 640 IsaPnpAcquireDeviceDataLock(FdoExt); 641 642 /* Card identification */ 643 Status = IsaHwFillDeviceList(FdoExt); 644 IsaHwWaitForKey(); 645 646 IsaPnpReleaseDeviceDataLock(FdoExt); 647 648 PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN | 649 ISAPNP_SCANNED_BY_READ_PORT; 650 651 IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); 652 IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations); 653 654 return Status; 655 } 656 else 657 { 658 IsaHwWaitForKey(); 659 #if 0 /* See the 'if 0' above */ 660 break; 661 #endif 662 } 663 } 664 } 665 } 666 else 667 { 668 return STATUS_DEVICE_CONFIGURATION_ERROR; 669 } 670 671 /* Mark Read Port as started, even if no card has been detected */ 672 return STATUS_SUCCESS; 673 } 674 675 static 676 CODE_SEG("PAGE") 677 NTSTATUS 678 IsaPdoFilterResourceRequirements( 679 _In_ PISAPNP_PDO_EXTENSION PdoExt, 680 _Inout_ PIRP Irp, 681 _In_ PIO_STACK_LOCATION IrpSp) 682 { 683 PAGED_CODE(); 684 685 /* TODO: Handle */ 686 UNREFERENCED_PARAMETER(PdoExt); 687 UNREFERENCED_PARAMETER(IrpSp); 688 return Irp->IoStatus.Status; 689 } 690 691 static 692 CODE_SEG("PAGE") 693 NTSTATUS 694 IsaPdoQueryBusInformation( 695 _In_ PISAPNP_PDO_EXTENSION PdoExt, 696 _Inout_ PIRP Irp) 697 { 698 PPNP_BUS_INFORMATION BusInformation; 699 700 PAGED_CODE(); 701 702 BusInformation = ExAllocatePoolWithTag(PagedPool, 703 sizeof(PNP_BUS_INFORMATION), 704 TAG_ISAPNP); 705 if (!BusInformation) 706 return STATUS_INSUFFICIENT_RESOURCES; 707 708 BusInformation->BusTypeGuid = GUID_BUS_TYPE_ISAPNP; 709 BusInformation->LegacyBusType = Isa; 710 BusInformation->BusNumber = PdoExt->FdoExt->BusNumber; 711 712 Irp->IoStatus.Information = (ULONG_PTR)BusInformation; 713 return STATUS_SUCCESS; 714 } 715 716 static 717 CODE_SEG("PAGE") 718 NTSTATUS 719 IsaPdoQueryDeviceUsageNotification( 720 _In_ PISAPNP_PDO_EXTENSION PdoExt, 721 _Inout_ PIRP Irp, 722 _In_ PIO_STACK_LOCATION IrpSp) 723 { 724 BOOLEAN InPath = IrpSp->Parameters.UsageNotification.InPath; 725 726 PAGED_CODE(); 727 728 switch (IrpSp->Parameters.UsageNotification.Type) 729 { 730 case DeviceUsageTypePaging: 731 case DeviceUsageTypeHibernation: 732 case DeviceUsageTypeDumpFile: 733 IoAdjustPagingPathCount(&PdoExt->SpecialFiles, InPath); 734 IoInvalidateDeviceState(PdoExt->Common.Self); 735 break; 736 737 default: 738 return Irp->IoStatus.Status; 739 } 740 741 /* Do not send it to FDO for compatibility */ 742 return STATUS_SUCCESS; 743 } 744 745 static 746 CODE_SEG("PAGE") 747 NTSTATUS 748 IsaPdoRemoveDevice( 749 _In_ PISAPNP_PDO_EXTENSION PdoExt, 750 _In_ BOOLEAN FinalRemove) 751 { 752 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; 753 754 PAGED_CODE(); 755 756 /* Deactivate the device if previously activated */ 757 if (PdoExt->Common.State == dsStarted) 758 { 759 IsaHwWakeDevice(PdoExt->IsaPnpDevice); 760 IsaHwDeactivateDevice(PdoExt->IsaPnpDevice); 761 762 IsaHwWaitForKey(); 763 764 PdoExt->Common.State = dsStopped; 765 } 766 767 if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED)) 768 { 769 IsaPnpAcquireDeviceDataLock(FdoExt); 770 771 RemoveEntryList(&PdoExt->IsaPnpDevice->DeviceLink); 772 --FdoExt->DeviceCount; 773 774 IsaPnpReleaseDeviceDataLock(FdoExt); 775 776 IsaPnpRemoveLogicalDeviceDO(PdoExt->Common.Self); 777 } 778 779 return STATUS_SUCCESS; 780 } 781 782 static 783 CODE_SEG("PAGE") 784 NTSTATUS 785 IsaReadPortRemoveDevice( 786 _In_ PISAPNP_PDO_EXTENSION PdoExt, 787 _In_ BOOLEAN FinalRemove) 788 { 789 PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; 790 PLIST_ENTRY Entry; 791 792 PAGED_CODE(); 793 794 IsaPnpAcquireDeviceDataLock(FdoExt); 795 796 /* Logical devices will receive a remove request afterwards */ 797 for (Entry = FdoExt->DeviceListHead.Flink; 798 Entry != &FdoExt->DeviceListHead; 799 Entry = Entry->Flink) 800 { 801 PISAPNP_LOGICAL_DEVICE LogDevice = CONTAINING_RECORD(Entry, 802 ISAPNP_LOGICAL_DEVICE, 803 DeviceLink); 804 805 LogDevice->Flags &= ~ISAPNP_PRESENT; 806 } 807 808 IsaPnpReleaseDeviceDataLock(FdoExt); 809 810 PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN; 811 IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); 812 813 if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED)) 814 { 815 IsaPnpRemoveReadPortDO(PdoExt->Common.Self); 816 } 817 818 return STATUS_SUCCESS; 819 } 820 821 CODE_SEG("PAGE") 822 VOID 823 IsaPnpRemoveLogicalDeviceDO( 824 _In_ PDEVICE_OBJECT Pdo) 825 { 826 PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension; 827 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; 828 PLIST_ENTRY Entry; 829 830 PAGED_CODE(); 831 ASSERT(LogDev); 832 833 DPRINT("Removing CSN %u, LDN %u\n", LogDev->CSN, LogDev->LDN); 834 835 if (PdoExt->RequirementsList) 836 ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP); 837 838 if (PdoExt->ResourceList) 839 ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP); 840 841 if (LogDev->FriendlyName) 842 ExFreePoolWithTag(LogDev->FriendlyName, TAG_ISAPNP); 843 844 if (LogDev->Resources) 845 ExFreePoolWithTag(LogDev->Resources, TAG_ISAPNP); 846 847 Entry = LogDev->CompatibleIdList.Flink; 848 while (Entry != &LogDev->CompatibleIdList) 849 { 850 PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId = 851 CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink); 852 853 RemoveEntryList(&CompatibleId->IdLink); 854 855 Entry = Entry->Flink; 856 857 ExFreePoolWithTag(CompatibleId, TAG_ISAPNP); 858 } 859 860 ExFreePoolWithTag(LogDev, TAG_ISAPNP); 861 862 IoDeleteDevice(PdoExt->Common.Self); 863 } 864 865 CODE_SEG("PAGE") 866 NTSTATUS 867 IsaPdoPnp( 868 _In_ PISAPNP_PDO_EXTENSION PdoExt, 869 _Inout_ PIRP Irp, 870 _In_ PIO_STACK_LOCATION IrpSp) 871 { 872 NTSTATUS Status = Irp->IoStatus.Status; 873 874 PAGED_CODE(); 875 876 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 877 { 878 DPRINT("%s(%p, %p) CSN %u, LDN %u, Minor - %X\n", 879 __FUNCTION__, 880 PdoExt, 881 Irp, 882 PdoExt->IsaPnpDevice->CSN, 883 PdoExt->IsaPnpDevice->LDN, 884 IrpSp->MinorFunction); 885 } 886 else 887 { 888 DPRINT("%s(%p, %p) ReadPort, Minor - %X\n", 889 __FUNCTION__, 890 PdoExt, 891 Irp, 892 IrpSp->MinorFunction); 893 } 894 895 switch (IrpSp->MinorFunction) 896 { 897 case IRP_MN_START_DEVICE: 898 { 899 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 900 { 901 IsaHwWakeDevice(PdoExt->IsaPnpDevice); 902 903 Status = IsaHwConfigureDevice(PdoExt->FdoExt, 904 PdoExt->IsaPnpDevice, 905 IrpSp->Parameters.StartDevice.AllocatedResources); 906 if (NT_SUCCESS(Status)) 907 { 908 IsaHwActivateDevice(PdoExt->FdoExt, PdoExt->IsaPnpDevice); 909 } 910 else 911 { 912 DPRINT1("Failed to configure CSN %u, LDN %u with status 0x%08lx\n", 913 PdoExt->IsaPnpDevice->CSN, PdoExt->IsaPnpDevice->LDN, Status); 914 } 915 916 IsaHwWaitForKey(); 917 } 918 else 919 { 920 Status = IsaPdoStartReadPort(PdoExt, 921 IrpSp->Parameters.StartDevice.AllocatedResources); 922 } 923 924 if (NT_SUCCESS(Status)) 925 PdoExt->Common.State = dsStarted; 926 break; 927 } 928 929 case IRP_MN_STOP_DEVICE: 930 { 931 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 932 { 933 IsaHwWakeDevice(PdoExt->IsaPnpDevice); 934 IsaHwDeactivateDevice(PdoExt->IsaPnpDevice); 935 936 IsaHwWaitForKey(); 937 } 938 else 939 { 940 PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN; 941 } 942 943 Status = STATUS_SUCCESS; 944 945 if (NT_SUCCESS(Status)) 946 PdoExt->Common.State = dsStopped; 947 break; 948 } 949 950 case IRP_MN_QUERY_STOP_DEVICE: 951 { 952 if (PdoExt->SpecialFiles > 0) 953 Status = STATUS_DEVICE_BUSY; 954 else if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE) 955 Status = STATUS_RESOURCE_REQUIREMENTS_CHANGED; 956 else 957 Status = STATUS_SUCCESS; 958 959 break; 960 } 961 962 case IRP_MN_QUERY_REMOVE_DEVICE: 963 { 964 if (PdoExt->SpecialFiles > 0) 965 Status = STATUS_DEVICE_BUSY; 966 else 967 Status = STATUS_SUCCESS; 968 break; 969 } 970 971 case IRP_MN_QUERY_DEVICE_RELATIONS: 972 Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp); 973 break; 974 975 case IRP_MN_QUERY_CAPABILITIES: 976 Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp); 977 break; 978 979 case IRP_MN_SURPRISE_REMOVAL: 980 case IRP_MN_REMOVE_DEVICE: 981 { 982 BOOLEAN FinalRemove = (IrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE); 983 984 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 985 Status = IsaPdoRemoveDevice(PdoExt, FinalRemove); 986 else 987 Status = IsaReadPortRemoveDevice(PdoExt, FinalRemove); 988 break; 989 } 990 991 case IRP_MN_QUERY_PNP_DEVICE_STATE: 992 Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp); 993 break; 994 995 case IRP_MN_QUERY_RESOURCES: 996 Status = IsaPdoQueryResources(PdoExt, Irp, IrpSp); 997 break; 998 999 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: 1000 Status = IsaPdoQueryResourceRequirements(PdoExt, Irp, IrpSp); 1001 break; 1002 1003 case IRP_MN_QUERY_ID: 1004 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 1005 Status = IsaPdoQueryId(PdoExt, Irp, IrpSp); 1006 else 1007 Status = IsaReadPortQueryId(Irp, IrpSp); 1008 break; 1009 1010 case IRP_MN_QUERY_DEVICE_TEXT: 1011 if (PdoExt->Common.Signature == IsaPnpLogicalDevice) 1012 Status = IsaPdoQueryDeviceText(PdoExt, Irp, IrpSp); 1013 break; 1014 1015 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 1016 Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp); 1017 break; 1018 1019 case IRP_MN_QUERY_BUS_INFORMATION: 1020 Status = IsaPdoQueryBusInformation(PdoExt, Irp); 1021 break; 1022 1023 case IRP_MN_DEVICE_USAGE_NOTIFICATION: 1024 Status = IsaPdoQueryDeviceUsageNotification(PdoExt, Irp, IrpSp); 1025 break; 1026 1027 case IRP_MN_CANCEL_REMOVE_DEVICE: 1028 case IRP_MN_CANCEL_STOP_DEVICE: 1029 Status = STATUS_SUCCESS; 1030 break; 1031 1032 default: 1033 DPRINT("Unknown PnP code: %X\n", IrpSp->MinorFunction); 1034 break; 1035 } 1036 1037 Irp->IoStatus.Status = Status; 1038 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1039 1040 return Status; 1041 } 1042