diff --git a/drivers/bus/isapnp/isapnp.c b/drivers/bus/isapnp/isapnp.c index 148dfb6b090..41f52c9aed6 100644 --- a/drivers/bus/isapnp/isapnp.c +++ b/drivers/bus/isapnp/isapnp.c @@ -370,22 +370,54 @@ IsaForwardOrIgnore( } } -static CODE_SEG("PAGE") NTSTATUS IsaPnpCreateReadPortDORequirements( - _In_ PISAPNP_PDO_EXTENSION PdoExt) + _In_ PISAPNP_PDO_EXTENSION PdoExt, + _In_opt_ ULONG SelectedReadPort) { - ULONG ListSize, i; + ULONG ResourceCount, ListSize, i; PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; PIO_RESOURCE_DESCRIPTOR Descriptor; - const ULONG Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS, - 0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 }; + const ULONG Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS }; + const ULONG ReadPorts[] = { 0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 }; PAGED_CODE(); - ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) - + 2 * RTL_NUMBER_OF(Ports) * sizeof(IO_RESOURCE_DESCRIPTOR); + if (SelectedReadPort) + { + /* + * [IO descriptor: ISAPNP_WRITE_DATA, required] + * [IO descriptor: ISAPNP_WRITE_DATA, optional] + * [IO descriptor: ISAPNP_ADDRESS, required] + * [IO descriptor: ISAPNP_ADDRESS, optional] + * [IO descriptor: Selected Read Port, required] + * [IO descriptor: Read Port 1, optional] + * [IO descriptor: Read Port 2, optional] + * [...] + * [IO descriptor: Read Port X - 1, optional] + */ + ResourceCount = RTL_NUMBER_OF(Ports) * 2 + RTL_NUMBER_OF(ReadPorts); + } + else + { + /* + * [IO descriptor: ISAPNP_WRITE_DATA, required] + * [IO descriptor: ISAPNP_WRITE_DATA, optional] + * [IO descriptor: ISAPNP_ADDRESS, required] + * [IO descriptor: ISAPNP_ADDRESS, optional] + * [IO descriptor: Read Port 1, required] + * [IO descriptor: Read Port 1, optional] + * [IO descriptor: Read Port 2, required] + * [IO descriptor: Read Port 2, optional] + * [...] + * [IO descriptor: Read Port X, required] + * [IO descriptor: Read Port X, optional] + */ + ResourceCount = (RTL_NUMBER_OF(Ports) + RTL_NUMBER_OF(ReadPorts)) * 2; + } + ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof(IO_RESOURCE_DESCRIPTOR) * (ResourceCount - 1); RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP); if (!RequirementsList) return STATUS_NO_MEMORY; @@ -395,27 +427,92 @@ IsaPnpCreateReadPortDORequirements( RequirementsList->List[0].Version = 1; RequirementsList->List[0].Revision = 1; - RequirementsList->List[0].Count = 2 * RTL_NUMBER_OF(Ports); + RequirementsList->List[0].Count = ResourceCount; - for (i = 0; i < 2 * RTL_NUMBER_OF(Ports); i += 2) + Descriptor = &RequirementsList->List[0].Descriptors[0]; + + /* Store the Data port and the Address port */ + for (i = 0; i < RTL_NUMBER_OF(Ports) * 2; i++) { - Descriptor = &RequirementsList->List[0].Descriptors[i]; + if ((i % 2) == 0) + { + /* Expected port */ + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; + Descriptor->u.Port.Length = 0x01; + Descriptor->u.Port.Alignment = 0x01; + Descriptor->u.Port.MinimumAddress.LowPart = + Descriptor->u.Port.MaximumAddress.LowPart = Ports[i / 2]; + } + else + { + /* ... but mark it as optional */ + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; + Descriptor->u.Port.Alignment = 0x01; + } - /* Expected port */ - Descriptor[0].Type = CmResourceTypePort; - Descriptor[0].ShareDisposition = CmResourceShareDeviceExclusive; - Descriptor[0].Flags = CM_RESOURCE_PORT_16_BIT_DECODE; - Descriptor[0].u.Port.Length = Ports[i / 2] & 1 ? 0x01 : 0x04; - Descriptor[0].u.Port.Alignment = 0x01; - Descriptor[0].u.Port.MinimumAddress.LowPart = Ports[i / 2]; - Descriptor[0].u.Port.MaximumAddress.LowPart = Ports[i / 2] + Descriptor[0].u.Port.Length - 1; + Descriptor++; + } - /* ... but mark it as optional */ - Descriptor[1].Option = IO_RESOURCE_ALTERNATIVE; - Descriptor[1].Type = CmResourceTypePort; - Descriptor[1].ShareDisposition = CmResourceShareDeviceExclusive; - Descriptor[1].Flags = CM_RESOURCE_PORT_16_BIT_DECODE; - Descriptor[1].u.Port.Alignment = 0x01; + /* Store the Read Ports */ + if (SelectedReadPort) + { + BOOLEAN Selected = FALSE; + + DBG_UNREFERENCED_LOCAL_VARIABLE(Selected); + + for (i = 0; i < RTL_NUMBER_OF(ReadPorts); i++) + { + if (ReadPorts[i] != SelectedReadPort) + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + else + Selected = TRUE; + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; + Descriptor->u.Port.Length = 0x04; + Descriptor->u.Port.Alignment = 0x01; + Descriptor->u.Port.MinimumAddress.LowPart = ReadPorts[i]; + Descriptor->u.Port.MaximumAddress.LowPart = ReadPorts[i] + + Descriptor->u.Port.Length - 1; + + Descriptor++; + } + + ASSERT(Selected == TRUE); + } + else + { + for (i = 0; i < RTL_NUMBER_OF(ReadPorts) * 2; i++) + { + if ((i % 2) == 0) + { + /* Expected port */ + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; + Descriptor->u.Port.Length = 0x04; + Descriptor->u.Port.Alignment = 0x01; + Descriptor->u.Port.MinimumAddress.LowPart = ReadPorts[i / 2]; + Descriptor->u.Port.MaximumAddress.LowPart = ReadPorts[i / 2] + + Descriptor->u.Port.Length - 1; + } + else + { + /* ... but mark it as optional */ + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; + Descriptor->u.Port.Alignment = 0x01; + } + + Descriptor++; + } } PdoExt->RequirementsList = RequirementsList; @@ -493,7 +590,7 @@ IsaPnpCreateReadPortDO( PdoExt->Common.State = dsStopped; PdoExt->FdoExt = FdoExt; - Status = IsaPnpCreateReadPortDORequirements(PdoExt); + Status = IsaPnpCreateReadPortDORequirements(PdoExt, 0); if (!NT_SUCCESS(Status)) goto Failure; diff --git a/drivers/bus/isapnp/isapnp.h b/drivers/bus/isapnp/isapnp.h index e476f9737b0..ed4a6027a9b 100644 --- a/drivers/bus/isapnp/isapnp.h +++ b/drivers/bus/isapnp/isapnp.h @@ -115,6 +115,7 @@ typedef struct _ISAPNP_PDO_EXTENSION #define ISAPNP_ENUMERATED 0x00000001 /**< @brief Whether the device has been reported to the PnP manager. */ #define ISAPNP_SCANNED_BY_READ_PORT 0x00000002 /**< @brief The bus has been scanned by Read Port PDO. */ #define ISAPNP_READ_PORT_ALLOW_FDO_SCAN 0x00000004 /**< @brief Allows the active FDO to scan the bus. */ +#define ISAPNP_READ_PORT_NEED_REBALANCE 0x00000008 /**< @brief The I/O resource requirements have changed. */ _Write_guarded_by_(_Global_interlock_) volatile LONG SpecialFiles; @@ -166,6 +167,12 @@ IsaPnpReleaseDeviceDataLock( /* isapnp.c */ +CODE_SEG("PAGE") +NTSTATUS +IsaPnpCreateReadPortDORequirements( + _In_ PISAPNP_PDO_EXTENSION PdoExt, + _In_opt_ ULONG SelectedReadPort); + CODE_SEG("PAGE") VOID IsaPnpRemoveReadPortDO( diff --git a/drivers/bus/isapnp/pdo.c b/drivers/bus/isapnp/pdo.c index 27aedff6c6f..6e3676a01cc 100644 --- a/drivers/bus/isapnp/pdo.c +++ b/drivers/bus/isapnp/pdo.c @@ -93,7 +93,14 @@ IsaPdoQueryPnpDeviceState( { PAGED_CODE(); - if (PdoExt->SpecialFiles > 0) + 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; @@ -368,24 +375,24 @@ IsaPdoQueryResourceRequirements( return STATUS_SUCCESS; } +#define IS_READ_PORT(_d) ((_d)->Type == CmResourceTypePort && (_d)->u.Port.Length > 1) + static CODE_SEG("PAGE") NTSTATUS IsaPdoStartReadPort( - _In_ PISAPNP_FDO_EXTENSION FdoExt, - _In_ PIO_STACK_LOCATION IrpSp) + _In_ PISAPNP_PDO_EXTENSION PdoExt, + _In_ PCM_RESOURCE_LIST ResourceList) { - PISAPNP_PDO_EXTENSION PdoExt = FdoExt->ReadPortPdo->DeviceExtension; - PCM_RESOURCE_LIST ResourceList = IrpSp->Parameters.StartDevice.AllocatedResources; - NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; + PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt; + NTSTATUS Status; ULONG i; PAGED_CODE(); - if (!ResourceList || ResourceList->Count != 1) + if (!ResourceList) { - DPRINT1("No resource list (%p) or bad count (%d)\n", - ResourceList, ResourceList ? ResourceList->Count : 0); + DPRINT1("No resource list\n"); return STATUS_INSUFFICIENT_RESOURCES; } @@ -398,43 +405,110 @@ IsaPdoStartReadPort( return STATUS_REVISION_MISMATCH; } - for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) +#if 0 + /* Try various Read Ports from the list */ + if (ResourceList->List[0].PartialResourceList.Count > 3) { - PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = - &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; + ULONG SelectedPort = 0; - if (PartialDescriptor->Type == CmResourceTypePort && - PartialDescriptor->u.Port.Length > 1 && !FdoExt->ReadDataPort) + for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) { - PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); - if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort))) + 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); + + /* + * 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; + /* We detected some ISAPNP cards */ - - FdoExt->ReadDataPort = ReadDataPort; - - IsaPnpAcquireDeviceDataLock(FdoExt); - Status = IsaHwFillDeviceList(FdoExt); - IsaPnpReleaseDeviceDataLock(FdoExt); - - if (FdoExt->DeviceCount > 0) + if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort))) { - PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN | - ISAPNP_SCANNED_BY_READ_PORT; - - IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); - IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations); + SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; + break; } } - else + } + + ASSERT(SelectedPort != 0); + + if (PdoExt->RequirementsList) + { + ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP); + PdoExt->RequirementsList = NULL; + } + + /* Discard the Read Ports at conflicting locations */ + Status = IsaPnpCreateReadPortDORequirements(PdoExt, SelectedPort); + if (!NT_SUCCESS(Status)) + return Status; + + 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)) { - /* Mark read data port as started, even if no card has been detected */ - Status = STATUS_SUCCESS; + PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); + + /* Run the isolation protocol */ + if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort))) + { + FdoExt->ReadDataPort = ReadDataPort; + + IsaPnpAcquireDeviceDataLock(FdoExt); + + /* Card identification */ + Status = IsaHwFillDeviceList(FdoExt); + + if (FdoExt->DeviceCount > 0) + { + PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN | + ISAPNP_SCANNED_BY_READ_PORT; + + IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); + IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations); + } + + IsaPnpReleaseDeviceDataLock(FdoExt); + + return Status; + } + else + { + break; + } } } } + else + { + return STATUS_DEVICE_CONFIGURATION_ERROR; + } - return Status; + /* Mark Read Port as started, even if no card has been detected */ + return STATUS_SUCCESS; } static @@ -632,7 +706,10 @@ IsaPdoPnp( if (PdoExt->Common.Signature == IsaPnpLogicalDevice) Status = IsaHwActivateDevice(PdoExt->IsaPnpDevice); else - Status = IsaPdoStartReadPort(PdoExt->FdoExt, IrpSp); + { + Status = IsaPdoStartReadPort(PdoExt, + IrpSp->Parameters.StartDevice.AllocatedResources); + } if (NT_SUCCESS(Status)) PdoExt->Common.State = dsStarted; @@ -655,8 +732,11 @@ IsaPdoPnp( { 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; }