驱动调试记录

这是前段时间做驱动时碰到的一些问题,总结了下,供以后参考。

1、调试时当断点找不到相对应的源文件时,
     1、在DriverEntry开头中加入_asm{int 3};即可
     2、在windbg中设置符号文件、源文件和镜像文件的路径
     3、注意inf文件中的名字和sys文件名是否一致(这个不太清楚)
     4、注意系统加载的驱动是否就是我们自己的驱动,最好每次加载新的驱动时,删除所有以前的驱动,确保系统 找不到,弹出手动加载驱动。
备注:当原因是第四点时,很有可能会出现蓝屏的情况,下午再试试。
2、返回状态值在wdk中的ntstatus.h中查找。

3、#define STOP_HERE(void) /
_asm{int 3};

4、当卸载驱动时,先触发一个IRP_MN_QUERY_REMOVE_DEVICE请求,暂停设备堆栈中所有的I/O请求并更新PNP的状态,使用一个循环来完成这个处理;再这个请求处理完成后又产生一个IRP_MN_REMOVE_DEVICE请求,在这个请求处理里面完成对设备资源的删除,(请求队列清空、设备堆栈的删除、电源管理、设备对象、设备接口、符号链接等等);最后进入UNLOAD函数,其实经过了IRP_MN_QUERY_REMOVE_DEVICE和IRP_MN_REMOVE_DEVICE处理,这个里面就完成了对全局变量中使用到内存的地方进行安全释放。备注:如果在IRP_MN_REMOVE_DEVICE中不删除符号链接,则在你执行完卸载操作后再为设备安装驱动时系统会蓝屏,信息为

IRP_CANCEL_WITHOUT_UNCOMPLETED_OPERATION,大概是这么写的,意思是为取消之前还有没有做完的操作。

5、读写card配置信息,在DS生成的框架中提供了获得配置空间信息的函数XXXAccessConfigSpace,具体用法如下:

PCI_COMMON_CONFIG pci_config = {0};
ULONG ReadWrittenSize = 0;
status = HK6802VAccessConfigSpace(&deviceExtension, TRUE, &pci_config,     0, sizeof(PCI_COMMON_CONFIG),&ReadWrittenSize);

6、关于配置空间。配置空间在系统启动时就已经配置好了,我们所要做的只是在AddDevice中根据配置空间的设置来对I/O端口、Memory等等进行初始化。当然每次启动时都会进行这个操作的,可以用windbg跟踪下系统启动的过程,在AddDevice中打上断点。

7、BUFFER NONE 与 BUFFER QUEUE的比较从函数结构上看DVR6805_NONEReadDispatch步骤:1、检查请求是否可以继续,主要是通过检查DVR6805_NONE_IO_LOCK 这个结构,如果不可以或者挂起就返回status值;2、获得当前IRP堆栈信息和读缓冲区长度;3、获得缓冲区区首地址并且立即执行IoCompleteRequest (Irp, IO_NO_INCREMENT),并且设置自旋锁保证处理过程不被外部干扰KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);4、处理完毕释放自旋锁KeReleaseSpinLock(&IoLock->IoLock, oldIrql)。

DVR6805ReadDispatch步骤:1、将读请求IRP直接放入读队列DVR6805QueueIrp;2、如果当前队列中没有请求,则立即跳转到相应的StartIo回调函数DVR6805ReadQueueStartIo中执行。该回调函数和队列的初始化是在AddDevice中完成的DVR6805InitializeQueue(
        &deviceExtension->ReadQueue,
        DVR6805ReadQueueStartIo,
        deviceExtension->DeviceObject,
        TRUE
        );


8、应用层异步读、驱动层队列处理IRP

     在生成的代码中,当驱动层使用队列方式来处理读的IRP时,应用层如果使用同步读的话,将不会调到IRP_MJ_READ对应的派遣函数,也就是不会响应读这个动作,ReadFile这个操作返回0,错误码为87,代表参数错误,个人理解为应用层和驱动层读方式不一致导致的。

    当应用层使用异步事件来读设备,程序中如果队列空闲,则立即处理当前IRP,如果队列繁忙,则插入队列尾部并返回状态值PENDING,错误码为103。在程序中,由于调试队列繁忙不容易或者因为我没有好的方法,我就在程序处理完成第一个IRP代码之后将Queue->StallCount = 1(改变过队列的irp状态,在检查队列状态之前Queue->CurrentIrp = irp,结果蓝屏IRQL_NOT_LESS_OR_EQUAL,意思是在高级别中使用了分页内存,估计是这个赋值动作完成在分页内存中,但是在判断后首先调用IoMarkIrpPending(Irp),紧接着就Queue->CurrentIrp = irp,这里不解!),表示队列中仍然存在一个IRP请求,其实是为空的。这样,当应用层循环读的时候,第一次OK,第二次进来时检查队列时发现队列IRP数为1,说明队列繁忙,这时会执行插入队列的操作。当然除了第一次,后面的均阻塞了,队列头部的假信息导致之后的IRP都不能得到处理,应用层WaitForSingleObject等待事件结束也一直被阻塞,应用程序陷入无限等待。

9、中断处理
在Isr中要做的几件事
(1)判断是否掉电,如果掉电了就啥都不用做了,返回FALSE。
if ( PowerDeviceD0 != deviceExtension->DevicePowerState )
{
 return FALSE;
}
(2)读卡寄存器,看看是否是我们的卡来了中断
IntStatus = READ_REGISTER_ULONG((PULONG)(deviceExtension->MemoryBase + INTSTAT));
if (!IntStatus)
{
 return FALSE;
}
(3)没有irp请求,就是我们的卡来了中断,也不用理睬
if (!deviceExtension->QueueArray[0]->CurrentIrp)
{
 WRITE_REGISTER_ULONG((PULONG)(deviceExtension->MemoryBase + INTSTAT), 0xffffffff);  
 return TRUE;
}
(4)我们的卡产生了中断并且也传来了一个待处理的IRP,接下来的操作就是清掉中断位和进入DPC处理
//将中断清掉,以便下一次能够响应该中断
WRITE_REGISTER_ULONG((PULONG)(deviceExtension->MemoryBase + INTSTAT), 0xffffffff);
 
//调用DPC例程处理剩下的操作
KeInsertQueueDpc(&deviceExtension->GHIsrDpc, NULL, NULL);

 

10、ReadFile、WriteFile操作(下以ReadFile后驱动操作为例)、如

果要进队列,这里的操作就放在StartIo中做就可以了。

NTSTATUS GHReadDispatch(
    IN  PDEVICE_OBJECT  DeviceObject,
    IN  PIRP            Irp
    )
{
    PGH_DEVICE_EXTENSION    deviceExtension;
    NTSTATUS                        status;
    PIO_STACK_LOCATION irpStack;
    ULONG Loffset;
    ULONG Length;

    GHDebugPrint(DBG_IO, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp);

    deviceExtension = (PGH_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
    irpStack = IoGetCurrentIrpStackLocation(Irp);

    //偏移量
    Loffset = irpStack->Parameters.Read.ByteOffset.QuadPart;
 
    //长度
    Length = irpStack->Parameters.Read.Length;
 
    //模拟缓冲区内容
    memset((PUCHAR)deviceExtension->vaCommonBuffer, 0x99, 16 * PAGE_SIZE);
 
    RtlCopyMemory((PUCHAR)Irp->AssociatedIrp.SystemBuffer + Loffset, (PUCHAR)deviceExtension->vaCommonBuffer, Length);

    // put the read IRP in our read queue
//    status = GHQueueIrp(&deviceExtension->ReadQueue, Irp);

    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = Length;
    status = Irp->IoStatus.Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    GHDebugPrint(DBG_IO, DBG_TRACE, __FUNCTION__"--. IRP %p STATUS %x", Irp, status);

    return status;
}

11、FIFO调试
在6804中,我们设置VDAMTRIG为0x17,VDMAPEN为1,VFIFOEN为1,然后开FIFO溢出中断。接上摄像头之后,立马就响应了VFFOF(FIFO溢出)这个中断。我们可以发现,这个中断一直都在响应(就算你清掉了),原因是FIFO溢出后并没有将里面的数据搬移出来,会不停的触发这个中断,响应一段时间后蓝屏,提示陷入一个死循环了。dd watchdog!g_WdBugCheckData l5 ?查下这个命令 dds

12、DMA调试

昨晚出图像了,呵呵。令人高兴的是提前了一个月完成第一阶段目标,不过在解决问题时发现,导致最严重后果的并不是最关键的问题,反而是最易疏忽的细节,如果考虑问题再全面一点,大胆地去怀疑每一个步骤和细节,比起创造力更加重要。回头看看DMA传输这一块,大家都觉得很简单了,初始化、设置指令、开始传输、读取数据,流程很清晰。下面就这些步骤中出现的一些问题和一些考虑做一下总结。
(1) 初始化
    初始化的工作:DMA、FIFO去使能(也是清空FIFO的步骤),清除指令寄存器,关FIFO、DMA中断。这部分没有什么大的问题。
(2) 设置指令(我们调试时碰的最多的部分)
    首先是对指令的不熟悉,当时看DATASHEET并不清楚需要用到哪些指令,像同步、LINESTART、JUMP一无所知。最刚开始的想法是写一条LINESTART执行,看能不能读点什么东西出来,很显然是没有的。因为并不知道指令的格式是怎样组织的、指令中涉及到得地址是虚拟地址还是物理地址,为这个问题都搞了一天(当你的地址是给硬件用的时候肯定是物理地址,反之亦然)。确定物理地址后,每次取多少就是我们最关心的地方了,根据N制的标准,一行为720,那么我们一条LINESTART是否可以取720个点呢(与RGB格式有关,为RGB16时,一行为720 * 2点,为RGB24时,一行为720 * 3点)?当时并不知道,只能一步一步试。当把每行与RGB格式结合起来考虑还是过了蛮长的时间~~。
    指令的对与错
    当出现了指令错误中断时,第一反应这指令错了,但在查看DMA_EXE和DMA_PP时并不是指向那条错误的指令。指令错了DMA会停止吗?抑或继续?后来为了测试,加入JUMP后形成循环,指令错误消失,说明设置的指令并没有问题,而是没有JUMP后DMA一直在执行,而后面的内存并没有指令,当然出错。

    数据取出来之后,应用层也犯了些低级错误,在行和列的处理上写错了
 for (int i=0; i<HEIGTH; i++)
 {
  for (int j=0; j<WIDTH; j++)
  {
   UCHAR R = buff[i*WIDTH*COLORFORMAT + j*COLORFORMAT + 2];
   UCHAR G = buff[i*WIDTH*COLORFORMAT + j*COLORFORMAT + 1];
   UCHAR B = buff[i*WIDTH*COLORFORMAT + j*COLORFORMAT + 0];

   pDc->SetPixel(100 + j, 100 + i, RGB(R, G, B));
  }
 }
之前是将i * HEIGTH了,第一次写对了,第二次写错了,过了好久检查问题时才发现,悲剧中。。。。数据显示当然是有问题的,同步还没加。
    关于隔行的问题,当初考虑到隔行扫描的问题,以为里面数据已经是隔行的了,现在看来并非如此,这个设计是放在驱动中完成的,现在我们的驱动取出来的数据就是隔行的
 //创建奇场 LINESTART
 while( CmdIndex < CMD_NUM )
 {
  CrtOneDmaCmd(&cmd_co[CmdIndex], CMD_TYPE_LINESTART, Irq, DataType, StartingByte, ByteCount, O_Starting);
  CO_Starting += ByteCount * 2;//数据隔行
  CmdIndex++;
 }
你认为CO_Starting += ByteCount * 2是隔行呢还是CO_Starting += ByteCount隔行,越是细节问题越容易一闪而过,好的执行力更重要,细节远比创造力更有价值。

13、在中断调试时,在Isr中停留过多时间会死机,软件的滞留不代表硬件中断的停留,这是硬件还在运行,还有可能在产生新的中断。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值