资源配置

来源:互联网 发布:app软件排名 编辑:程序博客网 时间:2024/05/16 15:50

PCI的配置空间为4KB,具体格式如下表。

0x030x020x010x00AddressDevice IDVendor ID0x000x070x060x050x04 Cmd RegStatus Reg0x040x0B0x0A0x090x08 Class Code 0x080x0F0x0E0x0D0x0C BISTLatency0x0C0x130x120x110x10 Base0 0x100x170x160x150x14 Base1 0x140x1B0x1A0x190x18 Base2 0x180x1F0x1E0x1D0x1C Base3 0x1C0x230x220x210x20 Base4 0x200x270x260x250x24 Base5 0x240x2B0x2A0x290x28 Card Bus CIS Pointer 0x280x2F0x2E0x2D0x2C Sub Device IDSub VID0x2C0x330x320x310x30 Expansion ROM Base Address 0x300x370x360x350x34 Reserved 0x340x3B0x3A0x390x38 Reserved 0x380x3F0x3E0x3D0x3C Max_LatIRQ Pin0x3C
PCI配置空间的前256个Byte是兼容PCI的配置寄存器,可采用PCI或PCIe配置访问机制 ;后3840Byte是PCIe的扩展配置空间,用于实现可选的PCIe扩展功能寄存器。


在x86体系中,要读取设备配置空间,需要访问2个32bit的register,首先在0xCF8中,写入Bus Number,DeviceNumver,Function Number, Register Number;再从0xCFC中读取设备信息。

765432100xCF8Register Number (0 ~ 255) 15141312111098 Device Numver (0 ~ 31) 2322212019181716 Bus Number  3130292827262524 EffectReserved 
==================================================================================================================

    KMDF驱动程序将硬件资源映射成为EvtDevicePrepareHardware回调函数的一部分;最后在EvtDeviceReleaseHardware函数中取消资源映射。在设备枚举时和资源均衡后,KMDF会在调用EvtDeviceDOEntry之前,调用EvtDevicePrepareHardware函数来映射设备资源。在这个函数中,驱动程序不要访问硬件设备。在EvtDevicePrepareHardware函数内,驱动程序调用WdfCmResourceListGetCount来获得设备资源的数量,然后在调用WdfCmResourceListGetDesctiptor获得指定资源的细节。

    硬件资源可以映射到IO或者Memory,要实现与平台无关,需要对IO和Memory两种映射都支持。

映射IO:CmResourceTypePort,保存Base地址和资源的映射范围;保存*_PORT_*函数的指针,用来访问资源。

映射Memory:CmResourceTypeMemory,需要确保分配的大小足够,然后调用MmMapIoSpace,把返回的物理地址映射到虚拟地址,保存*_PORT_*函数的指针,用来访问资源。

NTSTATUS NICMapHWResources(IN OUT PFDO_DATA FdoData,IN WDFCMRESLIST  ResourcesRaw,IN WDFCMRESLIST  ResourcesTranslated )Routine Description:    Gets the HW resources assigned by the bus driver and:    1) Maps them to system address space.     2) If PCIDRV_CREATE_INTERRUPT_IN_PREPARE_HARDWARE is defined,         it creates a WDFINTERRUPT object.    Called during EvtDevicePrepareHardware callback.    Three base address registers are supported by the 8255x:    1) CSR Memory Mapped Base Address Register (BAR 0 at offset 10)    2) CSR I/O Mapped Base Address Register (BAR 1 at offset 14)    3) Flash Memory Mapped Base Address Register (BAR 2 at offset 18)    The 8255x requires one BAR for I/O mapping and one BAR for memory    mapping of these registers anywhere within the 32-bit memory address space.    The driver determines which BAR (I/O or Memory) is used to access the    Control/Status Registers.    Just for illustration, this driver maps both memory and I/O registers and    shows how to use READ_PORT_xxx or READ_REGISTER_xxx functions to perform    I/O in a platform independent basis. On some platforms, the I/O registers    can get mapped into memory space and your driver should be able to handle    this transparently.    One BAR is also required to map the accesses to an optional Flash memory.    The 82557 implements this register regardless of the presence or absence    of a Flash chip on the adapter. The 82558 and 82559 implement this    register only if a bit is set in the EEPROM. The size of the space requested    by this register is 1Mbyte, and it is always mapped anywhere in the 32-bit    memory address space.    Note: Although the 82558 only supports up to 64 Kbytes of Flash memory    and the 82559 only supports 128 Kbytes of Flash memory, the driver    requests 1 Mbyte of address space. Software should not access Flash    addresses above 64 Kbytes for the 82558 or 128 Kbytes for the 82559    because Flash accesses above the limits are aliased to lower addresses.Arguments:    FdoData     Pointer to our FdoData    ResourcesRaw - Pointer to list of raw resources passed to                         EvtDevicePrepareHardware callback    ResourcesTranslated - Pointer to list of translated resources passed to                        EvtDevicePrepareHardware callbackReturn Value:    NTSTATUS--*/{    PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;    ULONG       i;    NTSTATUS    status = STATUS_SUCCESS;    BOOLEAN     bResPort      = FALSE;    BOOLEAN     bResInterrupt = FALSE;    BOOLEAN     bResMemory    = FALSE;    ULONG       numberOfBARs  = 0;    UNREFERENCED_PARAMETER(ResourcesRaw);    PAGED_CODE();    for (i=0; i<WdfCmResourceListGetCount(ResourcesTranslated); i++) {        descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);        if(!descriptor){            TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfResourceCmGetDescriptor");            return STATUS_DEVICE_CONFIGURATION_ERROR;        }        switch (descriptor->Type) {        case CmResourceTypePort:            //            // We will increment the BAR count only for valid resources. We will            // not count the private device types added by the PCI bus driver.            //            numberOfBARs++;            TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,                "I/O mapped CSR: (%x) Length: (%d)\n",                descriptor->u.Port.Start.LowPart,                descriptor->u.Port.Length);            //            // The resources are listed in the same order the as            // BARs in the config space, so this should be the second one.            //            if(numberOfBARs != 2) {                TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "I/O mapped CSR is not in the right order\n");                status = STATUS_DEVICE_CONFIGURATION_ERROR;                return status;            }            //            // The port is in I/O space on this machine.            // We should use READ_PORT_Xxx, and WRITE_PORT_Xxx routines            // to read or write to the port.            //            FdoData->IoBaseAddress = ULongToPtr(descriptor->u.Port.Start.LowPart);            FdoData->IoRange = descriptor->u.Port.Length;            //            // Since all our accesses are USHORT wide, we will create an accessor            // table just for these two functions.            //            FdoData->ReadPort = NICReadPortUShort;            FdoData->WritePort = NICWritePortUShort;            bResPort = TRUE;            FdoData->MappedPorts = FALSE;            break;        case CmResourceTypeMemory:            numberOfBARs++;            if(numberOfBARs == 1) {                TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Memory mapped CSR:(%x:%x) Length:(%d)\n",                                        descriptor->u.Memory.Start.LowPart,                                        descriptor->u.Memory.Start.HighPart,                                        descriptor->u.Memory.Length);                //                // Our CSR memory space should be 0x1000 in size.                //                ASSERT(descriptor->u.Memory.Length == 0x1000);                FdoData->MemPhysAddress = descriptor->u.Memory.Start;                FdoData->CSRAddress = MmMapIoSpace(                                                descriptor->u.Memory.Start,                                                NIC_MAP_IOSPACE_LENGTH,                                                MmNonCached);                TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "CSRAddress=%p\n", FdoData->CSRAddress);                bResMemory = TRUE;            } else if(numberOfBARs == 2){                TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,                    "I/O mapped CSR in Memory Space: (%x) Length: (%d)\n",                    descriptor->u.Memory.Start.LowPart,                    descriptor->u.Memory.Length);                //                // The port is in memory space on this machine.                // We should call MmMapIoSpace to map the physical to virtual                // address, and also use the READ/WRITE_REGISTER_xxx function                // to read or write to the port.                //                FdoData->IoBaseAddress = MmMapIoSpace(                                                descriptor->u.Memory.Start,                                                descriptor->u.Memory.Length,                                                MmNonCached);                FdoData->ReadPort = NICReadRegisterUShort;                FdoData->WritePort = NICWriteRegisterUShort;                FdoData->MappedPorts = TRUE;                bResPort = TRUE;            } else if(numberOfBARs == 3){                TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Flash memory:(%x:%x) Length:(%d)\n",                                        descriptor->u.Memory.Start.LowPart,                                        descriptor->u.Memory.Start.HighPart,                                        descriptor->u.Memory.Length);                //                // Our flash memory should be 1MB in size. Since we don't                // access the memory, let us not bother mapping it.                //                //ASSERT(descriptor->u.Memory.Length == 0x100000);            } else {                TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,                            "Memory Resources are not in the right order\n");                status = STATUS_DEVICE_CONFIGURATION_ERROR;                return status;            }            break;        case CmResourceTypeInterrupt:            ASSERT(!bResInterrupt);            #ifdef PCIDRV_CREATE_INTERRUPT_IN_PREPARE_HARDWARE            {                WDF_INTERRUPT_CONFIG interruptConfig;                                //                // Create WDFINTERRUPT object.                //                WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,                                          NICEvtInterruptIsr,                                          NICEvtInterruptDpc);                //                // These first two callbacks will be called at DIRQL.  Their job is to                // enable and disable interrupts.                //                interruptConfig.EvtInterruptEnable  = NICEvtInterruptEnable;                interruptConfig.EvtInterruptDisable = NICEvtInterruptDisable;                interruptConfig.InterruptTranslated = descriptor;                interruptConfig.InterruptRaw =                        WdfCmResourceListGetDescriptor(ResourcesRaw, i);                  status = WdfInterruptCreate(FdoData->WdfDevice,                                    &interruptConfig,                                    WDF_NO_OBJECT_ATTRIBUTES,                                    &FdoData->WdfInterrupt);                if (!NT_SUCCESS (status))                {                    TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,                                "WdfInterruptCreate failed: %!STATUS!\n", status);                    return status;                }            }#endif            bResInterrupt = TRUE;            TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,                "Interrupt level: 0x%0x, Vector: 0x%0x\n",                descriptor->u.Interrupt.Level,                descriptor->u.Interrupt.Vector);            break;        default:            //            // This could be device-private type added by the PCI bus driver. We            // shouldn't filter this or change the information contained in it.            //            TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Unhandled resource type (0x%x)\n",                                        descriptor->Type);            break;        }    }    //    // Make sure we got all the 3 resources to work with.    //    if (!(bResPort && bResInterrupt && bResMemory)) {        status = STATUS_DEVICE_CONFIGURATION_ERROR;        return status;    }    //    // Read additional info from NIC such as MAC address    //    status = NICReadAdapterInfo(FdoData);    if (status != STATUS_SUCCESS)    {        return status;    }    //    // Test our adapter hardware    //    status = NICSelfTest(FdoData);    if (status != STATUS_SUCCESS)    {        return status;    }    return status;}

NTSTATUSNICUnmapHWResources(    IN OUT PFDO_DATA FdoData    )/*++Routine Description:    Disconnect the interrupt and unmap all the memory and I/O resources.Arguments:    FdoData     Pointer to our FdoDataReturn Value:     None--*/{    PAGED_CODE();    //    // Free hardware resources    //    if (FdoData->CSRAddress)    {        MmUnmapIoSpace(FdoData->CSRAddress, NIC_MAP_IOSPACE_LENGTH);        FdoData->CSRAddress = NULL;    }    if(FdoData->MappedPorts){        MmUnmapIoSpace(FdoData->IoBaseAddress, FdoData->IoRange);        FdoData->IoBaseAddress = NULL;    }    return STATUS_SUCCESS;}


0 0