[ISAPNP] Implement the Read Port resource management

Currently disabled until the kernel is ready
This commit is contained in:
Dmitry Borisov 2021-03-28 23:29:02 +06:00
parent f15de15554
commit c4b6330b14
3 changed files with 243 additions and 59 deletions

View file

@ -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;

View file

@ -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(

View file

@ -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;
}