https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c4b6330b14043add278ef…
commit c4b6330b14043add278ef4b74ca6a7566d667737
Author: Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Sun Mar 28 23:29:02 2021 +0600
Commit: Dmitry Borisov <di.sean(a)protonmail.com>
CommitDate: Sun Jun 20 19:24:31 2021 +0600
[ISAPNP] Implement the Read Port resource management
Currently disabled until the kernel is ready
---
drivers/bus/isapnp/isapnp.c | 151 ++++++++++++++++++++++++++++++++++++--------
drivers/bus/isapnp/isapnp.h | 7 ++
drivers/bus/isapnp/pdo.c | 144 ++++++++++++++++++++++++++++++++----------
3 files changed, 243 insertions(+), 59 deletions(-)
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;
+
+ Descriptor = &RequirementsList->List[0].Descriptors[0];
+
+ /* Store the Data port and the Address port */
+ for (i = 0; i < RTL_NUMBER_OF(Ports) * 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 = 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;
+ }
+
+ Descriptor++;
+ }
- for (i = 0; i < 2 * RTL_NUMBER_OF(Ports); i += 2)
+ /* Store the Read Ports */
+ if (SelectedReadPort)
{
- Descriptor = &RequirementsList->List[0].Descriptors[i];
-
- /* 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;
-
- /* ... 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;
+ 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 */
+ if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
+ {
+ SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
+ break;
+ }
+ }
+ }
+
+ 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;
- FdoExt->ReadDataPort = ReadDataPort;
+ for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
+ {
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor =
+ &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
- IsaPnpAcquireDeviceDataLock(FdoExt);
- Status = IsaHwFillDeviceList(FdoExt);
- IsaPnpReleaseDeviceDataLock(FdoExt);
+ if (IS_READ_PORT(PartialDescriptor))
+ {
+ PUCHAR ReadDataPort =
ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
- if (FdoExt->DeviceCount > 0)
+ /* Run the isolation protocol */
+ if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
{
- PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
- ISAPNP_SCANNED_BY_READ_PORT;
+ FdoExt->ReadDataPort = ReadDataPort;
+
+ IsaPnpAcquireDeviceDataLock(FdoExt);
- IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
- IoInvalidateDeviceRelations(FdoExt->ReadPortPdo,
RemovalRelations);
+ /* 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
- {
- /* Mark read data port as started, even if no card has been detected */
- Status = STATUS_SUCCESS;
}
}
}
+ 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;
}