阅读:4149回复:20
请助:PCI驱动程序莫名死机--急!!!
最近由于调试板子需要,自己照着书用DS 2.7写了个PCI驱动程序,其工作原理是:当PCI卡上有数据要求传送时向主机发出中断请求,驱动程序的ISR接收到之后,向应用程序发送一个事件通知,然后由应用程序调用DeviceIoControl(),启动DMA传送数据,将数据传送到主机内存。
现在ISR等正常了,应用程序能够收到驱动程序发出的事件通知,但是当应用在收到事件通知之后去调用DeviceIoControl时,机器会出现重新启动的现象。 用SoftICE在DMA_READ分发例程上设断点,发现在执行KDmaTransfer.Initiate()时,驱动程序出错了,它进入了KIrp.h中的KIrp类定义处,(如①所示)SoftICE会出现如下提示:“Break due to page Fault. Fault=0000”。然后如果此时在SoftICE中按<F10>,计算机就会出现重启,如果按<F5>,则SoftICE中会反复出现 “Break due to page Fault. Fault=0000”的信息。 我怀疑是因为I.Mdl()的问题,有可能是因为在用户层上的指针在内核下出错。但是该段代码我放在Serail Read例程中调试通过了的。现在放在DMA_READ例程中就出问题了。 DMA_READ 在ioctl.h文件中的定义如下: #define My_DMA_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80C, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 一个多星期了,我试了很多种方法,在应用程序中开个线程也试了,也是不行。 查了Windows 2000DDK文档和DriverWorks帮助文档,所讲的都是和武安河主编的《Windows 2000/XP WDM设备驱动程序开发》书上说的一样,驱动程序通过KIrp::IoctlBuffer访问这个缓冲区,但是现在就是不行。可能我的思维已陷入了一个死胡同,请各位大侠们帮忙看看,指点小弟一把,不甚感激! 下面给出部分程序代码: //--------------------------------------------------------- =====App中调用DMA_READ方法: //--------------------------------------------------------- UCHAR *pBuffer; ULONG bufSize; ULONG tmp; pBuffer = NULL; bufSize = 0x200000; pBuffer = new UCHAR[bufSize]; if(pBuffer == NULL) return -1; DeviceIoControl(hDevice, //设备句柄,在前面已用同步方式打开 My_DMA_READ, NULL, 0, pBuffer;, bufSize, &tmp, NULL); ... //--------------------------------------------------------- =====DMA_READ分发例程如下: //--------------------------------------------------------- NTSTATUS MyDevice::My_DMA_READ_Handler(KIrp I) { NTSTATUS status = STATUS_SUCCESS; // 为当前IRP创建一DMATransfer对象 m_CurrentTransfer = new(NonPagedPool) KDmaTransfer(this, &m_Dma); //m_CurrentTransfer 在MyDevice类的Public:中已申明为指针 if ( m_CurrentTransfer == NULL ) { status = STATUS_INSUFFICIENT_RESOURCES; DbgPrint(\"unable to allocate transfer object: %x\\n\", status); I.Information() = 0; I.Status() = status; } //采用应用程序的数据缓冲区作为DMA数据区 status = m_CurrentTransfer->Initiate( <-- 驱动程序出错位置 I.Mdl(), FromDeviceToMemory, LinkTo(OnDmaReady) ); // 初始化失败,则返回错误状态 if ( ! NT_SUCCESS(status) ) { DbgPrint(\"unable to initiate transfer: %x\\n\", status); delete m_CurrentTransfer; m_CurrentTransfer = NULL; I.Information() = 0; I.Status() = status; } return status; } //--------------------------------------------------------- =====进入KIrp.h中光标停留位置: Class KIrp { public: … #if DBG VOID ValidateStackLocation(EStackLocation loc) { if(loc == CURRENT) { ASSERT (m_Irp->CurrentLocation <= m_Irp->StackCount); } else // loc == NEXT <--① (进入时光标停留位置) { ASSERT (m_Irp->CurrentLocation > 1); } } #else VOID ValidateStackLocation(EStackLocation loc) { UNREFERENCED_PARAMETER(loc) } #endif // Data public : PIRP m_Irp; } //--------------------------------------------------------- 现在我被卡在这里了,也不知该如何下手。真的很着急,还请各位高手多加指点,先谢了! [编辑 - 8/19/03 by flying] |
|
最新喜欢:mapofl |
沙发#
发布于:2003-08-20 11:02
怎么没人回啊?
我都快急疯了!!! |
|
板凳#
发布于:2003-08-20 12:53
不用DS,猜一下 :D
#define My_DMA_READ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80C, METHOD_IN_DIRECT, FILE_ANY_ACCESS) 不是METHOD_IN_DIRECT吗?,怎么 DeviceIoControl(hDevice, //设备句柄,在前面已用同步方式打开 My_DMA_READ, NULL, 0, pBuffer;, bufSize, &tmp, NULL); 的in buffer是NULL? |
|
地板#
发布于:2003-08-20 13:34
可是我用METHOD_OUT_DIRECT也试过了,一样的结果
还有没有别的招? |
|
地下室#
发布于:2003-08-26 13:56
一定给分,如果分不够,还可以再加!
版主,znsoft,快帮帮忙! 还有哪位遇到过类似问题的“前辈”高手们! :( |
|
5楼#
发布于:2003-09-14 15:38
1、应该是METHOD_OUT_DIRECT
2、把in buffer和in buffer size加上,随便传个数给驱动,反正不让他们为空 |
|
|
6楼#
发布于:2003-09-15 21:32
谢谢你AthlonXP兄!
你的意思是在应用程序中的DeviceIocontrol()中把In buffer和In buffer size参数加进去? |
|
7楼#
发布于:2003-09-17 10:32
不用吧,如果你只想要驱动程序返回的数据而不给驱动程序送数据的话,inbuffer和inbuffersize可以为空。
我一般都是用METHOD_BUFFERED方式DeviceIoControl,你可以试一下啊 |
|
|
8楼#
发布于:2003-09-17 12:21
谢谢你AthlonXP兄! 是的 |
|
|
9楼#
发布于:2003-09-17 12:22
不用吧,如果你只想要驱动程序返回的数据而不给驱动程序送数据的话,inbuffer和inbuffersize可以为空。 呵呵,测试一下嘛,这方法不行再找其他方法试试 |
|
|
10楼#
发布于:2003-09-18 16:20
你是采用基于包的总线主DMA模式吧?你在CREATEDEVICE 的时候应当把FLAG定义成DIRECT。
|
|
|
11楼#
发布于:2003-09-25 09:23
先谢谢大家了, 我现在在用PLX提供的驱动调试, 等过几天再试试看
|
|
12楼#
发布于:2003-09-25 09:25
我怎么给不了分啊?
看不到给分的那个按钮啊 |
|
13楼#
发布于:2004-04-02 14:42
请问flying,最后是如何解决的?
|
|
|
14楼#
发布于:2004-04-14 03:32
问题是出在回调例程ondmaready()
:D :D :D |
|
|
15楼#
发布于:2004-04-19 15:54
这个问题最后怎么解决的啊?
我现在也碰到这样的问题了 :( |
|
16楼#
发布于:2004-04-21 09:57
这个问题我一直没有去解决它,因为我用另一种方法了
但是我想问题的原因是由于用户空间的虚拟内存不能在内核空间使用而引起的,写出来大家一起参考分析: 由于X86系统的特点,在OS下虚拟内存地址通过分段、分页等机制被转换成物理地址。 在系统执行DMA时,需要的是物理地址,它不能将数据直接传送至虚拟地址中(因为这个虚拟地址和可能就不在真正的内存中,或已被系统交换到硬盘上),而需要将该虚拟地址转换成物理地址,当然,这个物理地址就很有可能是被分配在不连续的物理内存分页中。你可以通过DDK提供的一些函数取得这些信息,比如说:MmGetPhysicalAddress()等,具体的你可以看DDK文档。当你取得了这些物理地址之后,就可以在驱动程序中使用它们了。 因为我的硬件中就需要这些信息,所以到这里就可以了,我不知道你的是否和我相同,不过我想可能会对你有所帮助吧。 |
|
17楼#
发布于:2004-04-21 16:14
hoho
按照你的程序,我用逻辑分析看了,dma传输是完成了的 也就是说,取得的物理地址是没有问题的 |
|
|
18楼#
发布于:2004-04-25 22:27
你是怎么确定DMA传输完成了的?
如果如你所说的物理地址没有问题,9054完成了DMA,那么为什么还会Crash? 能否说说你的想法? |
|
19楼#
发布于:2004-04-25 22:37
程序到这里应该还没有启动DMA吧
|
|
上一页
下一页