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