PLX 9x5x PCI 驱动程序执行流程详解(Qoder生成)

PLX 9x5x PCI 驱动程序执行流程详解(Qoder生成)

为了些PCI9054驱动,先要阅读官方示例程序,让Qoder先出个流程文件方便后续阅读程序。
大家想要尝试Qoder进行AI编程,可以在官网下载,也可以通过下面链接注册后下载安装:
Qoder下载链接

以下为Qoder自动生成部分:

概述

这是一个基于 Windows WDF(Windows Driver Framework)的 PLX PCI9656RDK-Lite 参考适配器驱动程序。主要功能是通过 PCI 接口进行 Scatter/Gather DMA 操作,支持读写操作和中断处理。


文件结构

文件 功能
Pci9656.c 驱动入口、设备初始化、电源管理
Init.c 设备初始化、硬件资源映射、DMA 配置
IsrDpc.c 中断服务例程(ISR)和延迟过程调用(DPC)
Read.c 读操作处理和 DMA 编程
Write.c 写操作处理和 DMA 编程
Control.c 设备控制(IOCTL)处理
Pci9656.h / Public.h / Private.h 头文件定义
Reg9656.h PLX 9656 芯片寄存器定义
trace.h WPP 跟踪配置

初始化流程

1. DriverEntry(驱动程序入口)

文件: Pci9656.c

NTSTATUS DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING RegistryPath
)

执行流程:

DriverEntry
  ├─ WPP_INIT_TRACING()              // 初始化 WPP 跟踪
  ├─ WDF_DRIVER_CONFIG_INIT()        // 初始化驱动配置
  ├─ 设置 EvtDeviceAdd 回调          // 设置设备添加事件
  ├─ 设置 EvtCleanupCallback         // 设置驱动清理事件
  └─ WdfDriverCreate()               // 创建 WDF 驱动对象

关键点:

  • 初始化 WPP 跟踪系统用于调试输出
  • 注册 PLxEvtDeviceAdd 作为设备检测回调
  • 注册 PlxEvtDriverContextCleanup 作为驱动卸载清理回调
  • 返回 STATUS_SUCCESS 表示驱动加载成功

2. PLxEvtDeviceAdd(设备添加事件)

文件: Pci9656.c

NTSTATUS PLxEvtDeviceAdd(
    IN WDFDRIVER        Driver,
    IN PWDFDEVICE_INIT  DeviceInit
)

执行流程:

PLxEvtDeviceAdd
  ├─ WdfDeviceInitSetIoType()        // 设置 I/O 类型为直接访问
  ├─ 初始化 PnP/电源回调
  │  ├─ EvtDevicePrepareHardware    // 硬件准备
  │  ├─ EvtDeviceReleaseHardware    // 硬件释放
  │  ├─ EvtDeviceD0Entry            // 进入 D0 状态
  │  └─ EvtDeviceD0Exit             // 离开 D0 状态
  ├─ WdfDeviceCreate()              // 创建设备对象
  ├─ 获取设备上下文 (DeviceExtension)
  ├─ WdfDeviceCreateDeviceInterface() // 创建设备接口
  ├─ PLxSetIdleAndWakeSettings()    // 设置空闲和唤醒策略
  └─ PLxInitializeDeviceExtension() // 初始化设备扩展

关键点:

  • 设置 I/O 直接访问模式以提高 DMA 性能
  • 创建 WDFDEVICE 对象并获取其上下文(DEVICE_EXTENSION)
  • 注册 PnP 和电源管理回调
  • 创建设备接口以供应用程序通过 GUID 访问

3. PLxInitializeDeviceExtension(设备扩展初始化)

文件: Init.c

NTSTATUS PLxInitializeDeviceExtension(
    IN PDEVICE_EXTENSION DevExt
)

执行流程:

PLxInitializeDeviceExtension
  ├─ 初始化最大传输长度
  │  └─ MaximumTransferLength = min(8KB, SRAM_SIZE)
  ├─ 计算 DMA_TRANSFER_ELEMENTS (DTE) 数量
  ├─ 创建顺序分发队列(Sequential Dispatch Queue)
  │  ├─ 创建写队列 (WriteQueue)
  │  │  └─ 设置 EvtIoWrite 回调
  │  ├─ 创建读队列 (ReadQueue)
  │  │  └─ 设置 EvtIoRead 回调
  │  └─ 创建控制队列 (ControlQueue)
  │     └─ 设置 EvtIoDeviceControl 回调
  ├─ PLxInterruptCreate()            // 创建中断对象
  └─ PLxInitializeDMA()              // 初始化 DMA

数据结构 (DEVICE_EXTENSION):

typedef struct _DEVICE_EXTENSION {
    WDFDEVICE Device;                    // WDF 设备对象
    
    // 硬件资源
    PPCI9656_REGS Regs;                 // 寄存器地址指针
    PUCHAR RegsBase;                    // 寄存器基地址
    ULONG RegsLength;                   // 寄存器长度
    
    PUCHAR SRAMBase;                    // SRAM 基地址
    ULONG SRAMLength;                   // SRAM 长度
    
    // 中断和 DMA
    WDFINTERRUPT Interrupt;             // 中断对象
    WDFDMAENABLER DmaEnabler;           // DMA 启用器
    
    // 读写队列
    WDFQUEUE ReadQueue, WriteQueue;     // 读写请求队列
    WDFQUEUE ControlQueue;              // 控制请求队列
    
    // 读写 DMA 事务
    WDFDMATRANSACTION ReadDmaTransaction;
    WDFDMATRANSACTION WriteDmaTransaction;
    
    // 公共缓冲区(用于 DTE 列表)
    WDFCOMMONBUFFER ReadCommonBuffer;   // 读 DTE 列表缓冲
    WDFCOMMONBUFFER WriteCommonBuffer;  // 写 DTE 列表缓冲
    PUCHAR ReadCommonBufferBase;
    PUCHAR WriteCommonBufferBase;
} DEVICE_EXTENSION;

4. PLxInterruptCreate(中断创建)

文件: IsrDpc.c

NTSTATUS PLxInterruptCreate(
    IN PDEVICE_EXTENSION DevExt
)

执行流程:

PLxInterruptCreate
  ├─ WDF_INTERRUPT_CONFIG_INIT()
  │  ├─ 设置 ISR 回调: PLxEvtInterruptIsr
  │  ├─ 设置 DPC 回调: PLxEvtInterruptDpc
  │  ├─ 设置 Enable 回调: PLxEvtInterruptEnable
  │  ├─ 设置 Disable 回调: PLxEvtInterruptDisable
  │  └─ AutomaticSerialization = TRUE
  └─ WdfInterruptCreate()

关键点:

  • ISR 在 DIRQL 级别执行(中断级)
  • DPC 用于处理非时间关键的中断处理
  • 自动串行化确保 ISR 和 DPC 不会并发执行

5. PLxInitializeDMA(DMA 初始化)

文件: Init.c

NTSTATUS PLxInitializeDMA(
    IN PDEVICE_EXTENSION DevExt
)

执行流程:

PLxInitializeDMA
  ├─ WdfDeviceSetAlignmentRequirement(16字节对齐)
  ├─ 创建 DMA 启用器
  │  ├─ 配置: WdfDmaProfileScatterGather64Duplex
  │  │         支持双工 Scatter/Gather DMA,64位地址
  │  ├─ 最大传输长度: 8KB
  │  └─ DMA 版本 3(支持单次传输限制)
  ├─ 为读操作创建公共缓冲区
  │  ├─ 大小: sizeof(DMA_TRANSFER_ELEMENT) × ReadTransferElements
  │  ├─ 获取虚拟地址: ReadCommonBufferBase
  │  └─ 获取逻辑地址: ReadCommonBufferBaseLA
  ├─ 为写操作创建公共缓冲区
  │  └─ 类似读缓冲区
  ├─ 创建读 DMA 事务对象
  │  └─ WdfDmaTransactionCreate()
  └─ 创建写 DMA 事务对象
     └─ WdfDmaTransactionCreate()

DMA_TRANSFER_ELEMENT 结构 (Reg9656.h):

typedef struct _DMA_TRANSFER_ELEMENT {
    unsigned int PciAddressLow;      // PCI 地址低32位
    unsigned int LocalAddress;       // 本地 SRAM 地址
    unsigned int TransferSize;       // 传输字节数
    DESC_PTR DescPtr;                // 描述符指针(含控制位)
    unsigned int PciAddressHigh;     // PCI 地址高32位
    unsigned int pad[3];             // 对齐填充
} DMA_TRANSFER_ELEMENT;

6. PLxEvtDevicePrepareHardware(硬件准备)

文件: Pci9656.c

NTSTATUS PLxEvtDevicePrepareHardware(
    WDFDEVICE Device,
    WDFCMRESLIST Resources,
    WDFCMRESLIST ResourcesTranslated
)

执行流程:

PLxEvtDevicePrepareHardware
  └─ PLxPrepareHardware()
      ├─ 遍历资源列表
      │  ├─ 查找 BAR0 (寄存器, 0x200 字节)
      │  ├─ 查找 BAR2 (SRAM, 128KB)
      │  └─ 可选: BAR3 (备用 SRAM)
      ├─ 映射寄存器内存到系统地址空间
      │  └─ LocalMmMapIoSpace() / MmMapIoSpace()
      └─ 映射 SRAM 内存到系统地址空间

PCI 资源分配:

BAR 类型 大小 用途
BAR0 Memory 0x200 PCI9656 寄存器
BAR1 I/O Port 0x100+ I/O 端口(未使用)
BAR2 Memory 128KB SRAM(读写缓冲)
BAR3 Memory 128KB 备用 SRAM

7. PLxEvtDeviceD0Entry(进入 D0 电源状态)

文件: Pci9656.c

NTSTATUS PLxEvtDeviceD0Entry(
    IN WDFDEVICE Device,
    IN WDF_POWER_DEVICE_STATE PreviousState
)

执行流程:

PLxEvtDeviceD0Entry
  ├─ PLxInitWrite()
  │  ├─ 清零 DMA0 DAC 寄存器
  │  └─ 清零 Dma0Csr 副本
  └─ PLxInitRead()
     ├─ 清零 DMA1 DAC 寄存器
     └─ 清零 Dma1Csr 副本

关键点:

  • 在设备进入 D0(工作状态)时调用
  • 初始化 DMA 通道 0(写)和通道 1(读)
  • 中断尚未启用,将在此函数后由框架启用

读写操作流程

写操作流程

1. PLxEvtIoWrite(写请求处理)

文件: Write.c

VOID PLxEvtIoWrite(
    IN WDFQUEUE Queue,
    IN WDFREQUEST Request,
    IN size_t Length
)

执行流程:

PLxEvtIoWrite
  ├─ 验证数据长度
  │  └─ if (Length > SRAM_SIZE) 返回 STATUS_INVALID_BUFFER_SIZE
  ├─ 设置单次传输要求
  │  └─ WdfDmaTransactionSetSingleTransferRequirement()
  ├─ 初始化 DMA 事务
  │  └─ WdfDmaTransactionInitializeUsingRequest()
  │     或 WdfDmaTransactionInitialize()(如果使用 MDL)
  ├─ 执行 DMA 事务
  │  └─ WdfDmaTransactionExecute(WriteDmaTransaction)
  │     // 触发 PLxEvtProgramWriteDma 调用
  └─ 错误处理
     ├─ WdfDmaTransactionRelease()
     └─ WdfRequestComplete()

关键点:

  • 在顺序队列中执行,一次处理一个请求
  • DMA 事务的初始化可绑定到 WDF 请求
  • 执行后立即返回,完成由 DPC 处理

2. PLxEvtProgramWriteDma(写 DMA 编程)

文件: Write.c

BOOLEAN PLxEvtProgramWriteDma(
    IN WDFDMATRANSACTION Transaction,
    IN WDFDEVICE Device,
    IN PVOID Context,
    IN WDF_DMA_DIRECTION Direction,
    IN PSCATTER_GATHER_LIST SgList
)

执行流程:

PLxEvtProgramWriteDma
  ├─ 获取字节偏移量
  │  └─ offset = WdfDmaTransactionGetBytesTransferred()
  ├─ 设置 DTE 指针
  │  ├─ dteVA: 虚拟地址
  │  └─ dteLA: 逻辑地址
  ├─ 遍历 Scatter/Gather 列表
  │  └─ for (i=0; i < SgList->NumberOfElements; i++)
  │     ├─ dteVA->PciAddressLow = SgList[i].Address.LowPart
  │     ├─ dteVA->PciAddressHigh = SgList[i].Address.HighPart
  │     ├─ dteVA->TransferSize = SgList[i].Length
  │     ├─ dteVA->LocalAddress = offset  // SRAM 偏移
  │     ├─ dteVA->DescPtr.DirOfTransfer = TO_DEVICE
  │     └─ 设置 LastElement 标志(最后一个元素)
  ├─ 锁定中断自旋锁
  │  └─ WdfInterruptAcquireLock()
  ├─ 配置硬件寄存器
  │  ├─ DMA0_Mode: 启用 S/G、中断、路由到 PCI
  │  ├─ Int_Csr: 启用 PCI 中断和 DMA0 通道中断
  │  ├─ DMA0_Desc_Ptr: 设置 DTE 列表地址
  │  └─ DMA0_Csr: 启动 DMA (Enable + Start)
  ├─ 释放中断自旋锁
  │  └─ WdfInterruptReleaseLock()
  └─ 返回 TRUE(成功)

硬件寄存器配置:

// DMA0_Mode (0x080)
dmaMode.bits.SgModeEnable = TRUE;    // 启用 Scatter/Gather
dmaMode.bits.DoneIntEnable = TRUE;   // 传输完成时中断
dmaMode.bits.IntToPci = TRUE;        // 中断路由到 PCI

// Int_Csr (0x068)
intCSR.bits.PciIntEnable = TRUE;      // 启用 PCI 中断
intCSR.bits.DmaChan0IntEnable = TRUE; // 启用 DMA0 中断

// DMA0_Desc_Ptr (0x090)
ptr.bits.DescLocation = PCI;          // DTE 在 PCI 内存中
ptr.bits.TermCountInt = TRUE;         // 终端计数中断
ptr.bits.Address = DTE_BASE_ADDRESS;  // DTE 列表基地址

// DMA0_Csr (0x0A8)
dmaCSR.bits.Enable = TRUE;            // 启用 DMA 通道
dmaCSR.bits.Start = TRUE;             // 启动 DMA 操作

关键点:

  • 构建 Scatter/Gather DMA 传输元素列表
  • 在临界区内(中断锁定下)配置硬件
  • 保持 DTE 列表 16 字节对齐
  • 最后一个 DTE 需设置 LastElement 标志

3. PLxWriteRequestComplete(写请求完成)

文件: Write.c

VOID PLxWriteRequestComplete(
    IN WDFDMATRANSACTION DmaTransaction,
    IN NTSTATUS Status
)

执行流程:

PLxWriteRequestComplete
  ├─ 获取关联的 WDF 请求
  │  └─ request = WdfDmaTransactionGetRequest()
  ├─ 获取已传输字节数
  │  └─ bytesTransferred = WdfDmaTransactionGetBytesTransferred()
  ├─ 释放 DMA 事务
  │  └─ WdfDmaTransactionRelease()
  └─ 完成请求
     └─ WdfRequestCompleteWithInformation(request, Status, bytesTransferred)

读操作流程

1. PLxEvtIoRead(读请求处理)

文件: Read.c

VOID PLxEvtIoRead(
    IN WDFQUEUE Queue,
    IN WDFREQUEST Request,
    IN size_t Length
)

执行流程 (类似写操作):

PLxEvtIoRead
  ├─ 验证数据长度
  ├─ 设置单次传输要求
  ├─ 初始化 DMA 事务(ReadFromDevice 方向)
  ├─ 执行 DMA 事务
  │  └─ 触发 PLxEvtProgramReadDma
  └─ 错误处理

2. PLxEvtProgramReadDma(读 DMA 编程)

文件: Read.c

BOOLEAN PLxEvtProgramReadDma(
    IN WDFDMATRANSACTION Transaction,
    IN WDFDEVICE Device,
    IN WDFCONTEXT Context,
    IN WDF_DMA_DIRECTION Direction,
    IN PSCATTER_GATHER_LIST SgList
)

主要区别:

// 写操作使用 DMA 通道 0,读操作使用 DMA 通道 1

// 读方向(从设备读取)
dteVA->DescPtr.DirOfTransfer = FROM_DEVICE;

// 配置的寄存器
// DMA1_Mode (0x094)
// Int_Csr: DmaChan1IntEnable
// DMA1_Desc_Ptr (0x0A4)
// DMA1_Csr (0x0A9)

// 清空计数模式(读操作特有)
dmaMode.bits.ClearCountMode = TRUE;

中断处理流程

1. PLxEvtInterruptIsr(中断服务例程)

文件: IsrDpc.c

BOOLEAN PLxEvtInterruptIsr(
    IN WDFINTERRUPT Interrupt,
    IN ULONG MessageID
)

执行流程:

PLxEvtInterruptIsr (在 DIRQL 执行)
  ├─ 读取中断 CSR 寄存器
  │  └─ intCsr.ulong = READ_REGISTER_ULONG(&Regs->Int_Csr)
  ├─ 检查 DMA0 中断(写完成)
  │  ├─ if (intCsr.bits.DmaChan0IntActive)
  │  ├─ 标记: devExt->IntCsr.bits.DmaChan0IntActive = TRUE
  │  ├─ 读取并清除 DMA0_Csr
  │  │  └─ dmaCSR.bits.Clear = TRUE
  │  └─ isRecognized = TRUE
  ├─ 检查 DMA1 中断(读完成)
  │  ├─ if (intCsr.bits.DmaChan1IntActive)
  │  ├─ 标记: devExt->IntCsr.bits.DmaChan1IntActive = TRUE
  │  ├─ 读取并清除 DMA1_Csr
  │  └─ isRecognized = TRUE
  ├─ 如果有中断且 DMA 完成
  │  └─ if (isRecognized && (Dma0Done || Dma1Done))
  │     └─ WdfInterruptQueueDpcForIsr()  // 队列 DPC
  └─ 返回 isRecognized

关键点:

  • 快速确定中断来源,避免处理不相关中断
  • 清除硬件中断标志防止重复
  • 如果有数据完成,队列 DPC 进行后续处理
  • 应尽快返回以提高系统响应性

2. PLxEvtInterruptDpc(延迟过程调用)

文件: IsrDpc.c

VOID PLxEvtInterruptDpc(
    WDFINTERRUPT Interrupt,
    WDFOBJECT Device
)

执行流程:

PLxEvtInterruptDpc (在较低 IRQL 执行,可分页)
  ├─ 锁定中断自旋锁
  │  └─ WdfInterruptAcquireLock()
  ├─ 检查写中断(DMA0)
  │  ├─ if (DmaChan0IntActive && Dma0Done)
  │  ├─ 清除标志
  │  └─ writeInterrupt = TRUE
  ├─ 检查读中断(DMA1)
  │  ├─ if (DmaChan1IntActive && Dma1Done)
  │  ├─ 清除标志
  │  └─ readInterrupt = TRUE
  ├─ 释放中断自旋锁
  │  └─ WdfInterruptReleaseLock()
  ├─ 处理写中断
  │  ├─ if (writeInterrupt)
  │  ├─ dmaTransaction = WriteDmaTransaction
  │  ├─ transactionComplete = WdfDmaTransactionDmaCompleted()
  │  │  // 检查是否有更多数据需传输
  │  └─ if (transactionComplete)
  │     └─ PLxWriteRequestComplete()  // 完成请求
  ├─ 处理读中断
  │  ├─ if (readInterrupt)
  │  ├─ 计算传输的实际字节数
  │  │  └─ 遍历 DTE 列表,从 TransferSize 中减去
  │  ├─ transactionComplete = 
  │  │   WdfDmaTransactionDmaCompletedWithLength()
  │  └─ if (transactionComplete)
  │     └─ PLxReadRequestComplete()  // 完成请求
  └─ 返回

关键点:

  • 读操作需要计算实际传输字节数(因为 ClearCountMode)
  • 如果 DMA 事务未完成,框架将自动重新启动 DMA
  • DMA 事务完成时,执行完成回调完成用户请求

控制和电源管理

IOCTL 处理

文件: Control.c

VOID PLxEvtIoDeviceControl(
    _In_ WDFQUEUE Queue,
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength,
    _In_ ULONG IoControlCode
)

支持的 IOCTL:

  • IOCTL_PLX9X5X_TOGGLE_SINGLE_TRANSFER: 切换单次传输模式

电源状态管理

D0 状态 (工作)

  • 设备初始化完成
  • 中断已启用
  • DMA 可用

D0 -> Dx 转换

  • PLxEvtDeviceD0Exit 被调用
  • 根据目标状态执行相应操作

D3 状态 (关闭)

  • PLxShutdown(): 执行硬件复位
  • PLxHardwareReset(): 软件复位流程
    // 进入复位
    EEPROM_Ctrl_Stat.SoftwareReset = TRUE
    WRITE_REGISTER_ULONG(&Regs->EEPROM_Ctrl_Stat)
    
    // 延迟 100 毫秒
    KeDelayExecutionThread()
    
    // 退出复位
    EEPROM_Ctrl_Stat.SoftwareReset = FALSE
    WRITE_REGISTER_ULONG(&Regs->EEPROM_Ctrl_Stat)
    

内存管理

公共缓冲区 (Common Buffer)

用于存储 DMA 传输元素列表,必须满足以下条件:

  • 物理上连续
  • 非缓存(适用于 DMA)
  • 16 字节对齐
// 创建公共缓冲区
WdfCommonBufferCreate(
    DmaEnabler,
    sizeof(DMA_TRANSFER_ELEMENT) * NumElements,
    ...
)

// 获取虚拟地址(用于 CPU 访问)
PUCHAR virtAddr = WdfCommonBufferGetAlignedVirtualAddress()

// 获取逻辑地址(用于 DMA/硬件)
PHYSICAL_ADDRESS logAddr = WdfCommonBufferGetAlignedLogicalAddress()

Scatter/Gather 列表

由 WDF DMA 框架自动从用户 I/O 请求生成,描述用户缓冲区的物理分段。


驱动清理和卸载

PlxEvtDriverContextCleanup(驱动清理)

文件: Pci9656.c

VOID PlxEvtDriverContextCleanup(
    WDFOBJECT Driver
)

执行流程:

PlxEvtDriverContextCleanup
  └─ WPP_CLEANUP()  // 清理 WPP 跟踪

PLxEvtDeviceReleaseHardware(硬件释放)

文件: Pci9656.c

NTSTATUS PLxEvtDeviceReleaseHardware(
    IN WDFDEVICE Device,
    IN WDFCMRESLIST ResourcesTranslated
)

执行流程:

PLxEvtDeviceReleaseHardware
  ├─ 取消映射寄存器内存
  │  └─ MmUnmapIoSpace(RegsBase, RegsLength)
  └─ 取消映射 SRAM 内存
     └─ MmUnmapIoSpace(SRAMBase, SRAMLength)

关键数据结构

INT_CSR (Interrupt Control Status Register) - 0x068

typedef struct _INT_CSR_ {
    unsigned int EnableIntSources : 2;       // 位 0-1
    unsigned int GenPciBusSerrInt : 1;       // 位 2
    unsigned int DmaChan0IntActive : 1;      // 位 21 - DMA 通道 0 中断活跃
    unsigned int DmaChan1IntActive : 1;      // 位 22 - DMA 通道 1 中断活跃
    unsigned int DmaChan0IntEnable : 1;      // 位 18 - 启用 DMA0 中断
    unsigned int DmaChan1IntEnable : 1;      // 位 19 - 启用 DMA1 中断
    unsigned int PciIntEnable : 1;           // 位 8 - PCI 中断启用
    // ... 其他字段
} INT_CSR;

DMA_CSR (DMA Control Status Register) - 0x0A8/0x0A9

typedef struct _DMA_CSR_ {
    unsigned char Enable : 1;  // 位 0 - DMA 启用
    unsigned char Start : 1;   // 位 1 - DMA 启动
    unsigned char Abort : 1;   // 位 2 - DMA 中止
    unsigned char Clear : 1;   // 位 3 - 清除中断
    unsigned char Done : 1;    // 位 4 - DMA 完成(只读)
} DMA_CSR;

DMA_MODE (DMA Mode Register) - 0x080/0x094

typedef struct _DMA_MODE_ {
    unsigned int SgModeEnable : 1;    // Scatter/Gather 模式
    unsigned int DoneIntEnable : 1;   // 完成时中断
    unsigned int IntToPci : 1;        // 中断路由到 PCI
    unsigned int ClearCountMode : 1;  // 清空计数模式(读操作)
    // ... 其他字段
} DMA_MODE;

执行时序图

写操作完整时序

应用程序
    │
    ├─> WriteFile()
    │
用户模式到内核模式转换
    │
    ├─> I/O Manager 队列请求到 WriteQueue
    │
框架处理
    │
    ├─> PLxEvtIoWrite()
    │   ├─ 初始化 WriteDmaTransaction
    │   ├─ WdfDmaTransactionExecute()
    │   │  ├─> 框架生成 Scatter/Gather 列表
    │   │  └─> 调用 PLxEvtProgramWriteDma()
    │   │      ├─ 构建 DTE 列表
    │   │      ├─ 配置硬件寄存器
    │   │      ├─ 启动 DMA
    │   │      └─ 返回
    │   └─ 返回(不等待完成)
    │
硬件执行
    │
    ├─> PLX 芯片执行 DMA 传输
    │   ├─ 读取 PCI 内存
    │   ├─ 写入 SRAM
    │   └─ 完成时产生中断
    │
中断处理
    │
    ├─> PLxEvtInterruptIsr() [DIRQL]
    │   ├─ 读取 Int_Csr
    │   ├─ 检测 DMA0 中断
    │   ├─ 清除中断标志
    │   └─ 队列 DPC
    │
    ├─> PLxEvtInterruptDpc() [IRQL < DIRQL]
    │   ├─ 标记中断处理完成
    │   ├─ PLxWriteRequestComplete()
    │   └─ WdfRequestCompleteWithInformation()
    │
    └─> 应用程序解除阻塞并获取完成状态

关键配置和参数

参数 说明
最大传输长度 8 KB 可根据需求调整
SRAM 大小 128 KB PLX 芯片配置
DTE 对齐 16 字节 PLX 硬件要求
DMA 通道 2 通道 0(写),通道 1(读)
传输方向 双工 支持并发读写
地址宽度 64 位 支持高地址

故障排查

常见问题

  1. 写入失败 (STATUS_INVALID_BUFFER_SIZE)

    • 原因: 请求大小超过 SRAM 大小
    • 解决: 分割大请求
  2. 中断未触发

    • 原因: 中断未启用或硬件故障
    • 检查:
      • Int_Csr.PciIntEnable
      • Int_Csr.DmaChanXIntEnable
  3. DMA 超时

    • 原因: DTE 配置错误或硬件故障
    • 检查:
      • DTE 地址对齐
      • 传输大小有效性
      • 硬件寄存器状态

总结

PLX 9x5x 驱动程序的核心机制:

  1. 初始化阶段: 映射硬件资源、创建 WDF 对象、配置中断和 DMA
  2. 读写操作: 构建 Scatter/Gather DTE 列表,配置硬件寄存器启动 DMA
  3. 中断处理: ISR 快速识别中断并队列 DPC,DPC 处理完成事务并完成请求
  4. 电源管理: 支持 D0/Dx 状态转换及硬件复位

此驱动展示了现代 Windows 驱动开发的最佳实践,包括 WDF 框架使用、DMA 操作、中断处理和设备管理。

posted @ 2026-01-17 16:16  自由的好好干活  阅读(0)  评论(0)    收藏  举报