阅读:1923回复:7
9052中断蓝屏的问题请教[50分](急)
大概原来也有朋友遇到同样的问题,请指点一下。感觉就差一层
窗户纸,但是不得其入。为了以后也方便别人解决类似问题,我把 我的问题描述的详细些。请有经验的朋友耐心帮我看一下,不胜 感激。 1,问题的现象: 对pld片子编程产生时钟中断(大约每两秒一次)后,机器重启并蓝屏显示 STOP:0X00000D1(0X00000004,0X00000002,0X00000000,0XBFE476F2) DRIVER_IRQL_NOT_LESS_OR_EQUAL 2,硬件连接:32MHz晶振时钟输入到PLD芯片中,在内部分频后将2Hz的时钟输出连接到9052的LINTi1引脚上作为外部中断输入。 EEPROM中把INTCSR寄存器的值设为0。 3,主要想做的事情:中断到达的时候,INTCSR的第2位status位应该会从0变作1,想把这时候的INTCSR寄存器的值读出并保存,返回给应用程序。 4,软件功能描述:应用程序分两个线程,主线程创建事件对象,并把句柄hEvent通过DeviceIoControl()函数传给驱动程序,之后主线程创建系统服务线程ServiceThread,等待键盘输入Enter后退出。 ServiceThread等待驱动把事件对象设为已通知状态后,通readfile()读取中断来临时INTCSR的值。 5,应用程序的部分代码: ... DWORD WINAPI ServiceThread(PVOID hEvent) { while (TRUE) { WaitForSingleObject(hEvent, INFINITE); printf("New event:\n"); doRead(); //从驱动中读取INTCSR的值 } return 0; } int __cdecl main(int argc, char *argv[]) { ... // 创建一个事件对象,把句柄传给驱动 hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (! DeviceIoControl( hDevice, IOCTL_SET_NOTIFICATION_EVENT, &hEvent, sizeof(hEvent), NULL, 0, &nRet, NULL ) ) { printf("Ioctl failed: %x\n", GetLastError()); exit(1); } // 创建一个线程等待事件对象 CreateThread(0, 0x1000, ServiceThread,(PVOID) hEvent, 0, &Tid); //当键盘输入Enter后退出 printf("press return to exit . . .\n"); while (TRUE) if (_getche() == 0xd) break; CloseHandle(hEvent); CloseHandle(hDevice); return 0; } 6,驱动程序的部分代码: class Pci9052Device : public KPnpDevice {... protected: ULONG m_InterruptValue; //用来保存INTCSR的值 KEvent* m_pEvent; ... } Pci9052Device::Pci9052Device(PDEVICE_OBJECT Pdo, ULONG Unit) :KPnpDevice(Pdo, &Pci9052Device_Guid) {... #define INTCSR 0x4C//定义INTCSR偏移量 m_InterruptValue = 0; //初始化变量 ... } NTSTATUS Pci9052Device::OnStartDevice(KIrp I) {... m_pEvent = NULL; m_DpcFor_Irq.Setup(LinkTo(DpcFor_Irq), this); //允许PCI中断,使能lint1,active状态为高电平,边缘触发中断. m_IoPortRange0.outd(INTCSR,0x143); ... } NTSTATUS Pci9052Device::OnStopDevice(KIrp I) {... m_IoPortRange0.outd(INTCSR,0); //禁止PCI中断和LINTi1中断 m_Irq.Disconnect(); Invalidate(); ... } NTSTATUS Pci9052Device::OnRemoveDevice(KIrp I) {... m_IoPortRange0.outd(INTCSR,0); m_Irq.Disconnect(); Invalidate(); ... } NTSTATUS Pci9052Device::DeviceControl(KIrp I) { I.Information() = 0; switch (I.IoctlCode()) { case IOCTL_SET_NOTIFICATION_EVENT: { HANDLE hEvent = *(HANDLE*I.IoctlBuffer(); if (m_pEvent) delete m_pEvent; m_pEvent = new (NonPagedPool) KEvent(hEvent, OBJECT_TYPE_ALL_ACCESS); return I.Complete(STATUS_SUCCESS); } break; default: return I.Complete(STATUS_INVALID_PARAMETER); } } BOOLEAN Pci9052Device::Isr_Irq(void) { ULONG status; status = m_IoPortRange0.ind(INTCSR); //判断INTCSR的第2位是否变为1,如果是,说明是来自9052的中断 if ((status & 0x4) == 0) { return FALSE; } m_InterruptValue = status;//保存此时INTCSR的值 //禁止LINTi1中断 m_IoPortRange0.outd(INTCSR, 0x140); //清除LINTi1中断 m_IoPortRange0.outd(INTCSR, 0x543); //调用DPC例程 if (!m_DpcFor_Irq.Request(NULL, NULL)) { } return TRUE; } VOID Pci9052Device::DpcFor_Irq(PVOID Arg1, PVOID Arg2) { //把事件设为已通知状态 m_pEvent->Set(); //重新使能LINTi1中断 m_IoPortRange0.outd(INTCSR, 0x143); ... } NTSTATUS Pci9052Device::Read(KIrp I) { ... NTSTATUS status = STATUS_SUCCESS; ULONG INTStatus = m_InterruptValue; //下面把INTCSR的值返回给应用程序的ServiceThread线程 KMemory Mem(I.Mdl()); PULONG pBuffer = (PULONG) Mem.MapToSystemSpace(); *pBuffer = INTStatus; ULONG dwTotalSize = I.ReadSize(CURRENT); ULONG dwBytesRead = dwTotalSize; I.Information() = dwBytesRead; //重新把事件设为未通知状态 m_pEvent->Reset(); return I.PnpComplete(this, status); } 我的邮箱:superrobust@hotmail.com |
|
最新喜欢:mapofl
|
沙发#
发布于:2004-03-28 11:06
好像在你初始化m_pEvent之前,就已经有中断过来,使用了m_pEvent,从而引起死机。
|
|
板凳#
发布于:2004-03-28 13:13
mydrive兄
是不是CPU接收到中断后直接把控制交给了驱动中的ISR例程。 我设计的硬件中,外部时钟中断一直是在产生的。 那这样是否意味着要在ISR中对m_pEvent进行初始化 |
|
|
地板#
发布于:2004-03-28 13:47
你可以初始化m_pEvent以后,再打开中断屏蔽。
|
|
地下室#
发布于:2004-03-28 13:55
具体怎么做?
我是在OnStartdevice()例程中先把m_pEvent初始化为NULL, 然后开中断的。 但就是这样出的问题 |
|
|
5楼#
发布于:2004-03-28 14:11
在你的IOCTL_SET_NOTIFICATION_EVENT的处理程序中,先初始化m_pEvent,然后开中断。不要在OnStartdevice()中开中断。
|
|
6楼#
发布于:2004-03-28 15:24
谢谢mydriver兄
我准备再试试 还有一个问题: 我发现9052自动把INTCSR中LINTi1和LINTi2的status位设成了 active,这两位是不可写的。 那么中断来的时候我该如何判断是否为LINTi1的中断? |
|
|
7楼#
发布于:2004-03-28 20:20
再次感谢mydrive,问题算是解决了。
但是我发现在INTCSR中disable LINTi1的话,status位总是active 的。LINTi2也是一样。 但是如果Enable LINTi1,status位会变为 0。不知道别人做的是不是一样。 |
|
|