📄 pdo.c
字号:
/*
* PROJECT: ReactOS PCI bus driver
* FILE: pdo.c
* PURPOSE: Child device object dispatch routines
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* UPDATE HISTORY:
* 10-09-2001 CSH Created
*/
#include "pci.h"
#ifndef NDEBUG
#define NDEBUG
#endif
#include <debug.h>
/*** PRIVATE *****************************************************************/
static NTSTATUS
PdoQueryDeviceText(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
DPRINT("Called\n");
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
Status = STATUS_SUCCESS;
switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType)
{
case DeviceTextDescription:
DPRINT("DeviceTextDescription\n");
Irp->IoStatus.Information = (ULONG_PTR)DeviceExtension->DeviceDescription.Buffer;
break;
case DeviceTextLocationInformation:
DPRINT("DeviceTextLocationInformation\n");
Irp->IoStatus.Information = (ULONG_PTR)DeviceExtension->DeviceLocation.Buffer;
break;
default:
Irp->IoStatus.Information = 0;
Status = STATUS_INVALID_PARAMETER;
}
return Status;
}
static NTSTATUS
PdoQueryId(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
UNICODE_STRING String;
NTSTATUS Status;
DPRINT("Called\n");
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
// Irp->IoStatus.Information = 0;
Status = STATUS_SUCCESS;
RtlInitUnicodeString(&String, NULL);
switch (IrpSp->Parameters.QueryId.IdType) {
case BusQueryDeviceID:
Status = PciDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&DeviceExtension->DeviceID,
&String);
DPRINT("DeviceID: %S\n", String.Buffer);
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
break;
case BusQueryHardwareIDs:
Status = PciDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&DeviceExtension->HardwareIDs,
&String);
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
break;
case BusQueryCompatibleIDs:
Status = PciDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&DeviceExtension->CompatibleIDs,
&String);
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
break;
case BusQueryInstanceID:
Status = PciDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&DeviceExtension->InstanceID,
&String);
DPRINT("InstanceID: %S\n", String.Buffer);
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
break;
case BusQueryDeviceSerialNumber:
default:
Status = STATUS_NOT_IMPLEMENTED;
}
return Status;
}
static NTSTATUS
PdoQueryBusInformation(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
PPNP_BUS_INFORMATION BusInformation;
DPRINT("Called\n");
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->Fdo->DeviceExtension;
BusInformation = ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PCI);
Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
if (BusInformation != NULL)
{
BusInformation->BusTypeGuid = GUID_BUS_TYPE_PCI;
BusInformation->LegacyBusType = PCIBus;
BusInformation->BusNumber = DeviceExtension->PciDevice->BusNumber;
return STATUS_SUCCESS;
}
return STATUS_INSUFFICIENT_RESOURCES;
}
static NTSTATUS
PdoQueryCapabilities(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
PDEVICE_CAPABILITIES DeviceCapabilities;
ULONG DeviceNumber, FunctionNumber;
DPRINT("Called\n");
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
if (DeviceCapabilities->Version != 1)
return STATUS_UNSUCCESSFUL;
DeviceNumber = DeviceExtension->PciDevice->SlotNumber.u.bits.DeviceNumber;
FunctionNumber = DeviceExtension->PciDevice->SlotNumber.u.bits.FunctionNumber;
DeviceCapabilities->UniqueID = FALSE;
DeviceCapabilities->Address = ((DeviceNumber << 16) & 0xFFFF0000) + (FunctionNumber & 0xFFFF);
DeviceCapabilities->UINumber = (ULONG)-1; /* FIXME */
return STATUS_SUCCESS;
}
static BOOLEAN
PdoGetRangeLength(PPDO_DEVICE_EXTENSION DeviceExtension,
ULONG Offset,
PULONG Base,
PULONG Length,
PULONG Flags)
{
ULONG OrigValue;
ULONG BaseValue;
ULONG NewValue;
ULONG Size;
ULONG XLength;
/* Save original value */
Size= HalGetBusDataByOffset(PCIConfiguration,
DeviceExtension->PciDevice->BusNumber,
DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
&OrigValue,
Offset,
sizeof(ULONG));
if (Size != sizeof(ULONG))
{
DPRINT1("Wrong size %lu\n", Size);
return FALSE;
}
BaseValue = (OrigValue & 0x00000001) ? (OrigValue & ~0x3) : (OrigValue & ~0xF);
*Base = BaseValue;
/* Set magic value */
NewValue = (ULONG)-1;
Size= HalSetBusDataByOffset(PCIConfiguration,
DeviceExtension->PciDevice->BusNumber,
DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
&NewValue,
Offset,
sizeof(ULONG));
if (Size != sizeof(ULONG))
{
DPRINT1("Wrong size %lu\n", Size);
return FALSE;
}
/* Get the range length */
Size= HalGetBusDataByOffset(PCIConfiguration,
DeviceExtension->PciDevice->BusNumber,
DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
&NewValue,
Offset,
sizeof(ULONG));
if (Size != sizeof(ULONG))
{
DPRINT1("Wrong size %lu\n", Size);
return FALSE;
}
/* Restore original value */
Size= HalSetBusDataByOffset(PCIConfiguration,
DeviceExtension->PciDevice->BusNumber,
DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
&OrigValue,
Offset,
sizeof(ULONG));
if (Size != sizeof(ULONG))
{
DPRINT1("Wrong size %lu\n", Size);
return FALSE;
}
if (NewValue == 0)
{
DPRINT("Unused address register\n");
*Base = 0;
*Length = 0;
*Flags = 0;
return TRUE;
}
XLength = ~((NewValue & 0x00000001) ? (NewValue & ~0x3) : (NewValue & ~0xF)) + 1;
#if 0
DbgPrint("BaseAddress 0x%08lx Length 0x%08lx",
BaseValue, XLength);
if (NewValue & 0x00000001)
{
DbgPrint(" IO range");
}
else
{
DbgPrint(" Memory range");
if ((NewValue & 0x00000006) == 0)
{
DbgPrint(" in 32-Bit address space");
}
else if ((NewValue & 0x00000006) == 2)
{
DbgPrint(" below 1BM ");
}
else if ((NewValue & 0x00000006) == 4)
{
DbgPrint(" in 64-Bit address space");
}
if (NewValue & 0x00000008)
{
DbgPrint(" prefetchable");
}
}
DbgPrint("\n");
#endif
*Length = XLength;
*Flags = (NewValue & 0x00000001) ? (NewValue & 0x3) : (NewValue & 0xF);
return TRUE;
}
static NTSTATUS
PdoQueryResourceRequirements(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
PCI_COMMON_CONFIG PciConfig;
PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
PIO_RESOURCE_DESCRIPTOR Descriptor;
ULONG Size;
ULONG ResCount = 0;
ULONG ListSize;
ULONG i;
ULONG Base;
ULONG Length;
ULONG Flags;
DPRINT("PdoQueryResourceRequirements() called\n");
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* Get PCI configuration space */
Size= HalGetBusData(PCIConfiguration,
DeviceExtension->PciDevice->BusNumber,
DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
&PciConfig,
PCI_COMMON_HDR_LENGTH);
DPRINT("Size %lu\n", Size);
if (Size < PCI_COMMON_HDR_LENGTH)
{
Irp->IoStatus.Information = 0;
return STATUS_UNSUCCESSFUL;
}
DPRINT("Command register: 0x%04hx\n", PciConfig.Command);
/* Count required resource descriptors */
ResCount = 0;
if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
{
for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
{
if (!PdoGetRangeLength(DeviceExtension,
0x10 + i * 4,
&Base,
&Length,
&Flags))
break;
if (Length != 0)
ResCount += 2;
}
/* FIXME: Check ROM address */
if (PciConfig.u.type0.InterruptPin != 0)
ResCount++;
}
else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
{
for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
{
if (!PdoGetRangeLength(DeviceExtension,
0x10 + i * 4,
&Base,
&Length,
&Flags))
break;
if (Length != 0)
ResCount += 2;
}
if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
ResCount++;
}
else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
{
/* FIXME: Count Cardbus bridge resources */
}
else
{
DPRINT1("Unsupported header type %u\n", PCI_CONFIGURATION_TYPE(&PciConfig));
}
if (ResCount == 0)
{
Irp->IoStatus.Information = 0;
return STATUS_SUCCESS;
}
/* Calculate the resource list size */
ListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List->Descriptors)
+ ResCount * sizeof(IO_RESOURCE_DESCRIPTOR);
DPRINT("ListSize %lu (0x%lx)\n", ListSize, ListSize);
/* Allocate the resource requirements list */
ResourceList = ExAllocatePoolWithTag(PagedPool,
ListSize, TAG_PCI);
if (ResourceList == NULL)
{
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(ResourceList, ListSize);
ResourceList->ListSize = ListSize;
ResourceList->InterfaceType = PCIBus;
ResourceList->BusNumber = DeviceExtension->PciDevice->BusNumber;
ResourceList->SlotNumber = DeviceExtension->PciDevice->SlotNumber.u.AsULONG;
ResourceList->AlternativeLists = 1;
ResourceList->List[0].Version = 1;
ResourceList->List[0].Revision = 1;
ResourceList->List[0].Count = ResCount;
Descriptor = &ResourceList->List[0].Descriptors[0];
if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
{
for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
{
if (!PdoGetRangeLength(DeviceExtension,
0x10 + i * 4,
&Base,
&Length,
&Flags))
{
DPRINT1("PdoGetRangeLength() failed\n");
break;
}
if (Length == 0)
{
DPRINT("Unused address register\n");
continue;
}
/* Set preferred descriptor */
Descriptor->Option = IO_RESOURCE_PREFERRED;
if (Flags & PCI_ADDRESS_IO_SPACE)
{
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO |
CM_RESOURCE_PORT_16_BIT_DECODE |
CM_RESOURCE_PORT_POSITIVE_DECODE;
Descriptor->u.Port.Length = Length;
Descriptor->u.Port.Alignment = 1;
Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)Base;
Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
}
else
{
Descriptor->Type = CmResourceTypeMemory;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
Descriptor->u.Memory.Length = Length;
Descriptor->u.Memory.Alignment = 1;
Descriptor->u.Memory.MinimumAddress.QuadPart = (ULONGLONG)Base;
Descriptor->u.Memory.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
}
Descriptor++;
/* Set alternative descriptor */
Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
if (Flags & PCI_ADDRESS_IO_SPACE)
{
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO |
CM_RESOURCE_PORT_16_BIT_DECODE |
CM_RESOURCE_PORT_POSITIVE_DECODE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -