/* * PROJECT: ReactOS ISA PnP Bus driver * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: PDO-specific code * COPYRIGHT: Copyright 2010 Cameron Gutman * Copyright 2020 Hervé Poussineau * Copyright 2021 Dmitry Borisov */ #include "isapnp.h" #define NDEBUG #include static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryDeviceRelations( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { PDEVICE_RELATIONS DeviceRelations; PAGED_CODE(); if (IrpSp->Parameters.QueryDeviceRelations.Type == RemovalRelations && PdoExt->Common.Signature == IsaPnpReadDataPort) { return IsaPnpFillDeviceRelations(PdoExt->FdoExt, Irp, FALSE); } if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) return Irp->IoStatus.Status; DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(*DeviceRelations), TAG_ISAPNP); if (!DeviceRelations) return STATUS_NO_MEMORY; DeviceRelations->Count = 1; DeviceRelations->Objects[0] = PdoExt->Common.Self; ObReferenceObject(PdoExt->Common.Self); Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryCapabilities( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { PDEVICE_CAPABILITIES DeviceCapabilities; ULONG i; UNREFERENCED_PARAMETER(Irp); PAGED_CODE(); DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities; if (DeviceCapabilities->Version != 1) return STATUS_REVISION_MISMATCH; DeviceCapabilities->LockSupported = DeviceCapabilities->EjectSupported = DeviceCapabilities->Removable = DeviceCapabilities->DockDevice = FALSE; DeviceCapabilities->UniqueID = TRUE; if (PdoExt->Common.Signature == IsaPnpReadDataPort) { DeviceCapabilities->RawDeviceOK = TRUE; DeviceCapabilities->SilentInstall = TRUE; } for (i = 0; i < POWER_SYSTEM_MAXIMUM; i++) DeviceCapabilities->DeviceState[i] = PowerDeviceD3; DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0; return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryPnpDeviceState( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp) { PAGED_CODE(); if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE) { Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE | PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED | PNP_DEVICE_FAILED; return STATUS_SUCCESS; } else if (PdoExt->SpecialFiles > 0) { Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; return STATUS_SUCCESS; } return Irp->IoStatus.Status; } static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryId( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; NTSTATUS Status; PWCHAR Buffer, End, IdStart; size_t CharCount, Remaining; PAGED_CODE(); switch (IrpSp->Parameters.QueryId.IdType) { case BusQueryDeviceID: { CharCount = sizeof("ISAPNP\\XXXFFFF"); if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS) { CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL); } Buffer = ExAllocatePoolWithTag(PagedPool, CharCount * sizeof(WCHAR), TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; Status = RtlStringCchPrintfExW(Buffer, CharCount, &End, &Remaining, 0, L"ISAPNP\\%.3S%04X", LogDev->VendorId, LogDev->ProdId); if (!NT_VERIFY(NT_SUCCESS(Status))) goto Failure; if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS) { Status = RtlStringCchPrintfExW(End, Remaining, NULL, NULL, 0, L"_DEV%04X", LogDev->LDN); if (!NT_VERIFY(NT_SUCCESS(Status))) goto Failure; } DPRINT("Device ID: '%S'\n", Buffer); break; } case BusQueryHardwareIDs: { CharCount = sizeof("ISAPNP\\XXXFFFF") + sizeof("*PNPxxxx") + sizeof(ANSI_NULL); /* multi-string */ if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS) { CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL); } Buffer = ExAllocatePoolWithTag(PagedPool, CharCount * sizeof(WCHAR), TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; DPRINT("Hardware IDs:\n"); /* 1 */ Status = RtlStringCchPrintfExW(Buffer, CharCount, &End, &Remaining, 0, L"ISAPNP\\%.3S%04X", LogDev->VendorId, LogDev->ProdId); if (!NT_VERIFY(NT_SUCCESS(Status))) goto Failure; if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS) { Status = RtlStringCchPrintfExW(End, Remaining, &End, &Remaining, 0, L"_DEV%04X", LogDev->LDN); if (!NT_VERIFY(NT_SUCCESS(Status))) goto Failure; } DPRINT(" '%S'\n", Buffer); ++End; --Remaining; /* 2 */ IdStart = End; Status = RtlStringCchPrintfExW(End, Remaining, &End, &Remaining, 0, L"*%.3S%04X", LogDev->LogVendorId, LogDev->LogProdId); if (!NT_VERIFY(NT_SUCCESS(Status))) goto Failure; DPRINT(" '%S'\n", IdStart); *++End = UNICODE_NULL; --Remaining; break; } case BusQueryCompatibleIDs: { PLIST_ENTRY Entry; for (Entry = LogDev->CompatibleIdList.Flink, CharCount = 0; Entry != &LogDev->CompatibleIdList; Entry = Entry->Flink) { CharCount += sizeof("*PNPxxxx"); } CharCount += sizeof(ANSI_NULL); /* multi-string */ if (CharCount == sizeof(ANSI_NULL)) return Irp->IoStatus.Status; Buffer = ExAllocatePoolWithTag(PagedPool, CharCount * sizeof(WCHAR), TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; DPRINT("Compatible IDs:\n"); for (Entry = LogDev->CompatibleIdList.Flink, End = Buffer, Remaining = CharCount; Entry != &LogDev->CompatibleIdList; Entry = Entry->Flink) { PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId = CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink); IdStart = End; Status = RtlStringCchPrintfExW(End, Remaining, &End, &Remaining, 0, L"*%.3S%04X", CompatibleId->VendorId, CompatibleId->ProdId); if (!NT_VERIFY(NT_SUCCESS(Status))) goto Failure; DPRINT(" '%S'\n", IdStart); ++End; --Remaining; } *End = UNICODE_NULL; break; } case BusQueryInstanceID: { CharCount = sizeof(LogDev->SerialNumber) * 2 + sizeof(ANSI_NULL); Buffer = ExAllocatePoolWithTag(PagedPool, CharCount * sizeof(WCHAR), TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; Status = RtlStringCchPrintfExW(Buffer, CharCount, NULL, NULL, 0, L"%X", LogDev->SerialNumber); if (!NT_VERIFY(NT_SUCCESS(Status))) goto Failure; DPRINT("Instance ID: '%S'\n", Buffer); break; } default: return Irp->IoStatus.Status; } Irp->IoStatus.Information = (ULONG_PTR)Buffer; return STATUS_SUCCESS; Failure: ExFreePoolWithTag(Buffer, TAG_ISAPNP); return Status; } static CODE_SEG("PAGE") NTSTATUS IsaReadPortQueryId( _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { PWCHAR Buffer; static const WCHAR ReadPortId[] = L"ISAPNP\\ReadDataPort"; PAGED_CODE(); switch (IrpSp->Parameters.QueryId.IdType) { case BusQueryDeviceID: { Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(ReadPortId), TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; RtlCopyMemory(Buffer, ReadPortId, sizeof(ReadPortId)); DPRINT("Device ID: '%S'\n", Buffer); break; } case BusQueryHardwareIDs: { Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(ReadPortId) + sizeof(UNICODE_NULL), TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; RtlCopyMemory(Buffer, ReadPortId, sizeof(ReadPortId)); Buffer[sizeof(ReadPortId) / sizeof(WCHAR)] = UNICODE_NULL; /* multi-string */ DPRINT("Hardware ID: '%S'\n", Buffer); break; } case BusQueryCompatibleIDs: { /* Empty multi-string */ Buffer = ExAllocatePoolZero(PagedPool, sizeof(UNICODE_NULL) * 2, TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; DPRINT("Compatible ID: '%S'\n", Buffer); break; } case BusQueryInstanceID: { /* Even if there are multiple ISA buses, the driver has only one Read Port */ static const WCHAR InstanceId[] = L"0"; Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(InstanceId), TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; RtlCopyMemory(Buffer, InstanceId, sizeof(InstanceId)); DPRINT("Instance ID: '%S'\n", Buffer); break; } default: return Irp->IoStatus.Status; } Irp->IoStatus.Information = (ULONG_PTR)Buffer; return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryDeviceText( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { NTSTATUS Status; PWCHAR Buffer; size_t CharCount; PAGED_CODE(); switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType) { case DeviceTextDescription: { if (!PdoExt->IsaPnpDevice->FriendlyName) return Irp->IoStatus.Status; CharCount = strlen(PdoExt->IsaPnpDevice->FriendlyName) + sizeof(ANSI_NULL); if (CharCount == sizeof(ANSI_NULL)) return Irp->IoStatus.Status; Buffer = ExAllocatePoolWithTag(PagedPool, CharCount * sizeof(WCHAR), TAG_ISAPNP); if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; Status = RtlStringCchPrintfExW(Buffer, CharCount, NULL, NULL, 0, L"%hs", PdoExt->IsaPnpDevice->FriendlyName); if (!NT_VERIFY(NT_SUCCESS(Status))) { ExFreePoolWithTag(Buffer, TAG_ISAPNP); return Status; } DPRINT("TextDescription: '%S'\n", Buffer); break; } default: return Irp->IoStatus.Status; } Irp->IoStatus.Information = (ULONG_PTR)Buffer; return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryResources( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { ULONG ListSize; PCM_RESOURCE_LIST ResourceList; UNREFERENCED_PARAMETER(IrpSp); PAGED_CODE(); if (PdoExt->Common.Signature == IsaPnpReadDataPort) { ResourceList = IsaPnpCreateReadPortDOResources(); if (!ResourceList) return STATUS_NO_MEMORY; Irp->IoStatus.Information = (ULONG_PTR)ResourceList; return STATUS_SUCCESS; } if (!(PdoExt->IsaPnpDevice->Flags & ISAPNP_HAS_RESOURCES)) { Irp->IoStatus.Information = 0; return STATUS_SUCCESS; } if (!PdoExt->ResourceList) return Irp->IoStatus.Status; ListSize = PdoExt->ResourceListSize; ResourceList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_ISAPNP); if (!ResourceList) return STATUS_NO_MEMORY; RtlCopyMemory(ResourceList, PdoExt->ResourceList, ListSize); Irp->IoStatus.Information = (ULONG_PTR)ResourceList; return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryResourceRequirements( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { ULONG ListSize; PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; UNREFERENCED_PARAMETER(IrpSp); PAGED_CODE(); if (PdoExt->Common.Signature == IsaPnpReadDataPort) { RequirementsList = IsaPnpCreateReadPortDORequirements(PdoExt->SelectedPort); if (!RequirementsList) return STATUS_NO_MEMORY; Irp->IoStatus.Information = (ULONG_PTR)RequirementsList; return STATUS_SUCCESS; } if (!PdoExt->RequirementsList) return Irp->IoStatus.Status; ListSize = PdoExt->RequirementsList->ListSize; RequirementsList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_ISAPNP); if (!RequirementsList) return STATUS_NO_MEMORY; RtlCopyMemory(RequirementsList, PdoExt->RequirementsList, ListSize); Irp->IoStatus.Information = (ULONG_PTR)RequirementsList; return STATUS_SUCCESS; } #define IS_READ_PORT(_d) ((_d)->Type == CmResourceTypePort && (_d)->u.Port.Length > 1) static CODE_SEG("PAGE") NTSTATUS IsaPdoStartReadPort( _In_ PISAPNP_PDO_EXTENSION PdoExt, _In_ PCM_RESOURCE_LIST ResourceList) { PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; NTSTATUS Status; ULONG i; PAGED_CODE(); if (!ResourceList) { DPRINT1("No resource list\n"); return STATUS_INSUFFICIENT_RESOURCES; } if (ResourceList->List[0].PartialResourceList.Version != 1 || ResourceList->List[0].PartialResourceList.Revision != 1) { DPRINT1("Bad resource list version (%u.%u)\n", ResourceList->List[0].PartialResourceList.Version, ResourceList->List[0].PartialResourceList.Revision); return STATUS_REVISION_MISMATCH; } #if 0 /* Try various Read Ports from the list */ if (ResourceList->List[0].PartialResourceList.Count > 3) { ULONG SelectedPort = 0; for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; if (IS_READ_PORT(PartialDescriptor)) { PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); ULONG Cards; /* * Remember the first Read Port in the resource list. * It will be selected by default even if no card has been detected. */ if (!SelectedPort) SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; Cards = IsaHwTryReadDataPort(ReadDataPort); IsaHwWaitForKey(); /* We detected some ISAPNP cards */ if (Cards > 0) { SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; break; } } } ASSERT(SelectedPort != 0); /* Discard the Read Ports at conflicting locations */ PdoExt->SelectedPort = SelectedPort; PdoExt->Flags |= ISAPNP_READ_PORT_NEED_REBALANCE; IoInvalidateDeviceState(PdoExt->Common.Self); return STATUS_SUCCESS; } /* Set the Read Port */ else if (ResourceList->List[0].PartialResourceList.Count == 3) #else if (ResourceList->List[0].PartialResourceList.Count > 3) /* Temporary HACK */ #endif { PdoExt->Flags &= ~ISAPNP_READ_PORT_NEED_REBALANCE; for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; if (IS_READ_PORT(PartialDescriptor)) { PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); /* Run the isolation protocol */ FdoExt->Cards = IsaHwTryReadDataPort(ReadDataPort); if (FdoExt->Cards > 0) { FdoExt->ReadDataPort = ReadDataPort; IsaPnpAcquireDeviceDataLock(FdoExt); /* Card identification */ Status = IsaHwFillDeviceList(FdoExt); IsaHwWaitForKey(); IsaPnpReleaseDeviceDataLock(FdoExt); PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN | ISAPNP_SCANNED_BY_READ_PORT; IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations); return Status; } else { IsaHwWaitForKey(); #if 0 /* See the 'if 0' above */ break; #endif } } } } else { return STATUS_DEVICE_CONFIGURATION_ERROR; } /* Mark Read Port as started, even if no card has been detected */ return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaPdoFilterResourceRequirements( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); /* TODO: Handle */ UNREFERENCED_PARAMETER(PdoExt); UNREFERENCED_PARAMETER(IrpSp); return Irp->IoStatus.Status; } static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryBusInformation( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp) { PPNP_BUS_INFORMATION BusInformation; PAGED_CODE(); BusInformation = ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_ISAPNP); if (!BusInformation) return STATUS_INSUFFICIENT_RESOURCES; BusInformation->BusTypeGuid = GUID_BUS_TYPE_ISAPNP; BusInformation->LegacyBusType = Isa; BusInformation->BusNumber = PdoExt->FdoExt->BusNumber; Irp->IoStatus.Information = (ULONG_PTR)BusInformation; return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaPdoQueryDeviceUsageNotification( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { BOOLEAN InPath = IrpSp->Parameters.UsageNotification.InPath; PAGED_CODE(); switch (IrpSp->Parameters.UsageNotification.Type) { case DeviceUsageTypePaging: case DeviceUsageTypeHibernation: case DeviceUsageTypeDumpFile: IoAdjustPagingPathCount(&PdoExt->SpecialFiles, InPath); IoInvalidateDeviceState(PdoExt->Common.Self); break; default: return Irp->IoStatus.Status; } /* Do not send it to FDO for compatibility */ return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaPdoRemoveDevice( _In_ PISAPNP_PDO_EXTENSION PdoExt, _In_ BOOLEAN FinalRemove) { PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; PAGED_CODE(); /* Deactivate the device if previously activated */ if (PdoExt->Common.State == dsStarted) { IsaHwWakeDevice(PdoExt->IsaPnpDevice); IsaHwDeactivateDevice(PdoExt->IsaPnpDevice); IsaHwWaitForKey(); PdoExt->Common.State = dsStopped; } if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED)) { IsaPnpAcquireDeviceDataLock(FdoExt); RemoveEntryList(&PdoExt->IsaPnpDevice->DeviceLink); --FdoExt->DeviceCount; IsaPnpReleaseDeviceDataLock(FdoExt); IsaPnpRemoveLogicalDeviceDO(PdoExt->Common.Self); } return STATUS_SUCCESS; } static CODE_SEG("PAGE") NTSTATUS IsaReadPortRemoveDevice( _In_ PISAPNP_PDO_EXTENSION PdoExt, _In_ BOOLEAN FinalRemove) { PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; PLIST_ENTRY Entry; PAGED_CODE(); IsaPnpAcquireDeviceDataLock(FdoExt); /* Logical devices will receive a remove request afterwards */ for (Entry = FdoExt->DeviceListHead.Flink; Entry != &FdoExt->DeviceListHead; Entry = Entry->Flink) { PISAPNP_LOGICAL_DEVICE LogDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, DeviceLink); LogDevice->Flags &= ~ISAPNP_PRESENT; } IsaPnpReleaseDeviceDataLock(FdoExt); PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN; IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED)) { IsaPnpRemoveReadPortDO(PdoExt->Common.Self); } return STATUS_SUCCESS; } CODE_SEG("PAGE") VOID IsaPnpRemoveLogicalDeviceDO( _In_ PDEVICE_OBJECT Pdo) { PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension; PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; PLIST_ENTRY Entry; PAGED_CODE(); ASSERT(LogDev); DPRINT("Removing CSN %u, LDN %u\n", LogDev->CSN, LogDev->LDN); if (PdoExt->RequirementsList) ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP); if (PdoExt->ResourceList) ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP); if (LogDev->FriendlyName) ExFreePoolWithTag(LogDev->FriendlyName, TAG_ISAPNP); if (LogDev->Alternatives) ExFreePoolWithTag(LogDev->Alternatives, TAG_ISAPNP); Entry = LogDev->CompatibleIdList.Flink; while (Entry != &LogDev->CompatibleIdList) { PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId = CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink); RemoveEntryList(&CompatibleId->IdLink); Entry = Entry->Flink; ExFreePoolWithTag(CompatibleId, TAG_ISAPNP); } ExFreePoolWithTag(LogDev, TAG_ISAPNP); IoDeleteDevice(PdoExt->Common.Self); } CODE_SEG("PAGE") NTSTATUS IsaPdoPnp( _In_ PISAPNP_PDO_EXTENSION PdoExt, _Inout_ PIRP Irp, _In_ PIO_STACK_LOCATION IrpSp) { NTSTATUS Status = Irp->IoStatus.Status; PAGED_CODE(); if (PdoExt->Common.Signature == IsaPnpLogicalDevice) { DPRINT("%s(%p, %p) CSN %u, LDN %u, Minor - %X\n", __FUNCTION__, PdoExt, Irp, PdoExt->IsaPnpDevice->CSN, PdoExt->IsaPnpDevice->LDN, IrpSp->MinorFunction); } else { DPRINT("%s(%p, %p) ReadPort, Minor - %X\n", __FUNCTION__, PdoExt, Irp, IrpSp->MinorFunction); } switch (IrpSp->MinorFunction) { case IRP_MN_START_DEVICE: { if (PdoExt->Common.Signature == IsaPnpLogicalDevice) { IsaHwWakeDevice(PdoExt->IsaPnpDevice); Status = IsaHwConfigureDevice(PdoExt->FdoExt, PdoExt->IsaPnpDevice, IrpSp->Parameters.StartDevice.AllocatedResources); if (NT_SUCCESS(Status)) { IsaHwActivateDevice(PdoExt->FdoExt, PdoExt->IsaPnpDevice); } else { DPRINT1("Failed to configure CSN %u, LDN %u with status 0x%08lx\n", PdoExt->IsaPnpDevice->CSN, PdoExt->IsaPnpDevice->LDN, Status); } IsaHwWaitForKey(); } else { Status = IsaPdoStartReadPort(PdoExt, IrpSp->Parameters.StartDevice.AllocatedResources); } if (NT_SUCCESS(Status)) PdoExt->Common.State = dsStarted; break; } case IRP_MN_STOP_DEVICE: { if (PdoExt->Common.Signature == IsaPnpLogicalDevice) { IsaHwWakeDevice(PdoExt->IsaPnpDevice); IsaHwDeactivateDevice(PdoExt->IsaPnpDevice); IsaHwWaitForKey(); } else { PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN; } Status = STATUS_SUCCESS; if (NT_SUCCESS(Status)) PdoExt->Common.State = dsStopped; break; } case IRP_MN_QUERY_STOP_DEVICE: { if (PdoExt->SpecialFiles > 0) Status = STATUS_DEVICE_BUSY; else if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE) Status = STATUS_RESOURCE_REQUIREMENTS_CHANGED; else Status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_REMOVE_DEVICE: { if (PdoExt->SpecialFiles > 0) Status = STATUS_DEVICE_BUSY; else Status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_DEVICE_RELATIONS: Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp); break; case IRP_MN_QUERY_CAPABILITIES: Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp); break; case IRP_MN_SURPRISE_REMOVAL: if (PdoExt->Common.Signature == IsaPnpLogicalDevice) Status = IsaPdoRemoveDevice(PdoExt, FALSE); else Status = IsaReadPortRemoveDevice(PdoExt, FALSE); break; case IRP_MN_REMOVE_DEVICE: if (PdoExt->Common.Signature == IsaPnpLogicalDevice) Status = IsaPdoRemoveDevice(PdoExt, TRUE); else Status = IsaReadPortRemoveDevice(PdoExt, TRUE); break; case IRP_MN_QUERY_PNP_DEVICE_STATE: Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp); break; case IRP_MN_QUERY_RESOURCES: Status = IsaPdoQueryResources(PdoExt, Irp, IrpSp); break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: Status = IsaPdoQueryResourceRequirements(PdoExt, Irp, IrpSp); break; case IRP_MN_QUERY_ID: if (PdoExt->Common.Signature == IsaPnpLogicalDevice) Status = IsaPdoQueryId(PdoExt, Irp, IrpSp); else Status = IsaReadPortQueryId(Irp, IrpSp); break; case IRP_MN_QUERY_DEVICE_TEXT: if (PdoExt->Common.Signature == IsaPnpLogicalDevice) Status = IsaPdoQueryDeviceText(PdoExt, Irp, IrpSp); break; case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp); break; case IRP_MN_QUERY_BUS_INFORMATION: Status = IsaPdoQueryBusInformation(PdoExt, Irp); break; case IRP_MN_DEVICE_USAGE_NOTIFICATION: Status = IsaPdoQueryDeviceUsageNotification(PdoExt, Irp, IrpSp); break; case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_CANCEL_STOP_DEVICE: Status = STATUS_SUCCESS; break; default: DPRINT("Unknown PnP code: %X\n", IrpSp->MinorFunction); break; } Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }