chinanier 2018-09-18 05:36 采纳率: 0%
浏览 912

windows PCI驱动Block DMA使用问题

最近在修改一份基于DriverStudio的PCI视频采集卡驱动代码,遇到了关于DMA的使用上的疑惑。
其OnStartDevice初始化了相关资源,代码如下:

    PCM_RESOURCE_LIST pResListRaw = I.AllocatedResources();
    // Get the list of translated resources from the IRP
    PCM_RESOURCE_LIST pResListTranslated = I.TranslatedResources();
    // Initialize the device descriptor for the DMA object using the assigned resource
    DEVICE_DESCRIPTION dd;
    RtlZeroMemory(&dd, sizeof(dd));
    dd.Version = DEVICE_DESCRIPTION_VERSION;
    dd.Master = TRUE;
    dd.ScatterGather = FALSE;
    dd.DemandMode = TRUE;
    dd.AutoInitialize = FALSE;
    dd.Dma32BitAddresses = TRUE;
    dd.IgnoreCount = FALSE;
    dd.DmaChannel = 3;
    dd.InterfaceType = PCIBus;
    dd.DmaWidth = Width32Bits;  // PCI default width
    dd.DmaSpeed = MaximumDmaSpeed;
    dd.MaximumLength = m_nDmaBufferSize;

    // Initialize the DMA adapter object
    m_Dma.Initialize(&dd, m_Lower.TopOfStack());
    m_DmaBuffer.Initialize(&m_Dma,m_nDmaBufferSize,true);

    // Create an instance of KPciConfiguration so we can map Base Address
    // Register indicies to ordinals for memory or I/O port ranges.
    KPciConfiguration PciConfig(m_Lower.TopOfStack());

    // For each I/O port mapped region, initialize the I/O port range using
    // the resources provided by NT. Once initialized, use member functions such as
    // inb/outb, or the array element operator to access the ports range.
    status = m_IoPortRange0.Initialize(
        pResListTranslated,
        pResListRaw,
        PciConfig.BaseAddressIndexToOrdinal(0)
        );

    status = m_Irq.InitializeAndConnect(
    pResListTranslated, 
    LinkTo(Isr_Irq), 
    this
    );

    if (!NT_SUCCESS(status))
    {
        Invalidate();
        return status;      
    }

    // Setup the DPC to be used for interrupt processing
    m_DpcFor_Irq.Setup(LinkTo(DpcFor_Irq), this);

这里初始化了DMA,但是没有绑定PCI设备物理地址与驱动空间地址的相关代码。然而在IoControl中却有以下操作

//写
 UCHAR* pDMA = (UCHAR*)m_DmaBuffer.pVirtualAddress() + pCapInfo->nCode*pCapInfo->nSize + pCapInfo->nOffset;
        memcpy(pDMA,pCapInfo->pData,pCapInfo->nSize);
//读
UCHAR* pDMA = (UCHAR*)m_DmaBuffer.pVirtualAddress() + pCapInfo->nCode*pCapInfo->nSize + pCapInfo->nOffset;
        memcpy(pCapInfo->pData,pDMA,pCapInfo->nSize);

从代码可以看出,直接将m_DmaBuffer当做PCI的内存进行了访问。简单阅读了DriverStudio的封装源代码,初始化过程实际上调用了IoGetDmaAdapter与AllocateCommonBuffer,也就是说m_DmaBuffer.pVirtualAddress()实际上是AllocateCommonBuffer分配的公用缓冲区,而实际上并没有任何地方将该地址与PCI实际的物理地址进行绑定。查阅相关资料,AllocateCommonBuffer一般用于ScatterGather模式,这里使用的是block DMA模式。难道是IoGetDmaAdapter或者AllocateCommonBuffer自动将pVirtualAddress()与PCI的物理地址空间进行了绑定?查询相关资料,也没有这种解释。那究竟为什么能直接通过m_DmaBuffer.pVirtualAddress()操作PCI的物理地址空间呢?

求各位大神解答。

  • 写回答

2条回答

  • casperyjy 2020-12-25 16:52
    关注

    貌似KCommonDmaBuffer的物理地址通过IO传输给PCI采集卡DMA控制器做主动DMA目标地址后就是能用。与PCI采集卡内存空间分配的地址大小等完全无关

    评论

报告相同问题?

悬赏问题

  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能