Windows DMA驱动调试

        本文记录我调试微软官方提供的一个PCI驱动sample程序的过程。

一、开发环境和资源下载

1,在win10 X64操作系统下,安装VS2015+WDK10。(参考我前面的驱动开发入门篇)

2,使用TI6655 DSP开发板,点击打开链接。

3,下载微软官方发布在github上的驱动samples,点击打开链接,选择其中的“General/PLX9x5x”这个工程。

4,参考微软关于windows dma技术的文档,点击打开链接,该文档即以上面的工程代码为实例。


二、调试过程

1,使用VS2015直接编译PLX9x5x工程,需选择debug模式和X64环境。

        该工程分为sys和test两个模块,前者是驱动代码,后者是一个应用程序。

2,该工程中的inf文件(实际工程中是“.inx”,编译后会生产inf),其GUID和代码的public.h中的不一致,需修改为一致。这是唯一需要修改的地方。

3,将DSP开发板的venID和devID修改与inf文件中一致,在DSP侧修改即可。修改后,可以在“Windows设备管理”中查看。

(windows键+R,打开CMD,然后输入“devmgmt.msc”即可打开设备管理器;右键目标设备,选择属性,可以看详细信息,其中“硬件ID”即inf中需要填写一致的内容)


执行完以上操作,即可安装驱动,但此时驱动安装后显示不正确。实际上是没有配置DSP的“配置空间”。

4,在驱动的各个Routine中添加"KdPrint“打印信息,使用debugview查看驱动加载过程中的函数调用。

5,在init.c文件中的preparehardware函数中,扫描到memory resource后的地方,添加DSP配置空间的配置操作(调用DDK提供的写寄存器函数)。

    //
    // Parse the resource list and save the resource information.
    //
    for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {

        desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );

        if(!desc) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                        "WdfResourceCmGetDescriptor failed");
            return STATUS_DEVICE_CONFIGURATION_ERROR;
        }

        switch (desc->Type) {

            case CmResourceTypeMemory:

                bar = NULL;

                if (foundSRAM && !foundSRAM2 &&
                    desc->u.Memory.Length == 0x400000) {

                    SRAM2BasePA = desc->u.Memory.Start;
                    SRAM2Length = desc->u.Memory.Length;
                    foundSRAM2 = TRUE;
                    bar = "BAR3";
					KdPrint(("BAR3 found.\n"));
                }

                if (foundRegs && !foundSRAM &&
                    desc->u.Memory.Length == 0x100000) {

                    SRAMBasePA = desc->u.Memory.Start;
                    SRAMLength = desc->u.Memory.Length;
                    foundSRAM = TRUE;
                    bar = "BAR2";
					KdPrint(("BAR2 found.\n" ));
                }

                if (!foundRegs &&
                    desc->u.Memory.Length == 0x1000) {

                    regsBasePA = desc->u.Memory.Start;
                    regsLength = desc->u.Memory.Length;
                    foundRegs = TRUE;
                    bar = "BAR0";

					KdPrint(("BAR0 found.\n"));

                }

                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                            " - Memory Resource [%I64X-%I64X] %s",
                            desc->u.Memory.Start.QuadPart,
                            desc->u.Memory.Start.QuadPart +
                            desc->u.Memory.Length,
                            (bar) ? bar : "<unrecognized>" );


				KdPrint(("desc->u.Memory.Start is %x, desc->u.Memory.length is %x\n", desc->u.Memory.Start, desc->u.Memory.Length));



                break;

以上代码作用:扫描资源列表,获取windows操作系统为device分配的memory资源(可以再设备管理器的属性-》资源中看到)。保存系统分配的几块memory的基地址和长度。

6,将系统分配的空间基址和长度进行转换

    // Map in the Registers Memory resource: BAR0
    //
    DevExt->RegsBase = (PUCHAR) LocalMmMapIoSpace(regsBasePA,
                                                  regsLength);

    if (!DevExt->RegsBase) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    " - Unable to map Registers memory %08I64X, length %d",
                    regsBasePA.QuadPart, regsLength);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    DevExt->RegsLength = regsLength;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                " - Registers %p, length %d",
                DevExt->RegsBase, DevExt->RegsLength );

    //
    // Set seperated pointer to PCI9656_REGS structure.
    //
    DevExt->Regs = (PPCI9656_REGS) DevExt->RegsBase;
	DevExt->Bar0Regs = (PBAR0_REGS)DevExt->RegsBase;
	
    //
    // Map in the SRAM Memory Space resource: BAR1
    //
    DevExt->SRAMBase = (PUCHAR) LocalMmMapIoSpace(SRAMBasePA,
                                                  SRAMLength);

    if (!DevExt->SRAMBase) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    " - Unable to map SRAM memory %08I64X, length %d",
                    SRAMBasePA.QuadPart,  SRAMLength);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    DevExt->SRAMLength = SRAMLength;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                " - SRAM      %p, length %d",
                DevExt->SRAMBase, DevExt->SRAMLength );

7, DSP的“Configure空间”配置

	// configure dsp bar
 	{
		i = 0;
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_bar, i);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_lo, regsBasePA.u.LowPart);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_hi, regsBasePA.u.HighPart);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_offset, PCIE_BASE_ADDRESS);
	}

	{
		i = 1;
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_bar, i);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_lo, SRAMBasePA.u.LowPart);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_hi, SRAMBasePA.u.HighPart);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_offset, MSMC_START);
	}

	{
		i = 2;
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_bar, i);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_lo, SRAM2BasePA.u.LowPart);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_hi, SRAM2BasePA.u.HighPart);
		WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_offset, DDR_START);
	}

DSP配置正确,此时再加载驱动,即显示运行正常。(DSP的配置可以根据芯片资料配置)

6,测试DMA读操作,需先注释init.c中的中断调用部分代码和read.c中的DMA操作硬件部分的代码。

7,添加相关的打印。

8,将error的初始值由FALSE改为TRUE,从而可以执行后面的completerequest操作,推出该Routine。

执行完以上操作,可以运行test工程,来查看read过程的函数调用(debugview)。

暂时调试到该步骤。


四、DMA配置

其实际就是将CommonBuffer的物理地址告诉DSP


三、经验总结

1,在驱动工程中,不要放其他inf文件,VS会优先编译inf文件,而不编译inx文件,会反复报编译错误。

2,用F5运行test程序时,报”createfile“失败。查看getlasterror,返回值为5——拒绝访问,这是权限不够引起的。需要以管理员身份运行VS或改程序。(应用程序掉系统函数失败,查看getlasterror非常重要)

3,需要禁用数字签名,参考我之前的相关博客。



你可能感兴趣的:(Windows DMA驱动调试)