20楼#
发布于:2004-11-16 21:55
最后,我想在讲讲使用向导来生成驱动程序:
可以使用的向导有两种: 1. DriverWorks的PCI向导。 2. WinDriver的向导。 这两个都很好用,以下就这两个工具进行一些浅陋的说明。 一.DriverWorks的Wizard 在用DriverWorks生成PCI模板的初期,要求输入Vendor ID(对于9054,默认为0x10B5),DeviceID(9054默认为0x9054),SubsystemID(9054默认为0x9054),和RevisionID。这些信息都用于inf文件的生成,当查阅INF时,可以看见以下的键值: %DeviceDesc% = MyPciTest_DDI, PCIVEN_10B5&DEV_9054&SUBSYS_00009054&REV_00 我们从中可以看到这些值在生成驱动的位置。 当将PCI卡插入插槽时,Pnp Manager会检查注册表,看有无与这个设备相应的记录。其实,VendorID,DeviceID,SubsystemID和RevisionID就是用于标识这个注册表的相应记录的。如果是已经安装INF和SYS,则系统会自己完成所以的任务,它的工作应该是AddDevice(此处我不敢肯定,希望高手指点)。若未安装此驱动时,会启动硬件向导,要求用户提供inf,由inf完成注册表的更新,并安装sys文件。 由DriverWorks的向导生成的PCI驱动,和《武》提供的9054驱动的框架是一样的。再加一些补充的硬件操作就可以完成一个驱动的编写了。但如果希望驱动能完成更复杂的特定工作,恐怕还需理解DDK的基本工作原理。 二.使用WinDriver的Wizard 通过阅读WinDriver的快速生成PCI驱动程序的帮助就可以在10分钟内做一个驱动。我在亲历过后,不得不佩服,大洋彼岸的同僚,他们可以将开发平台做得如此简便,实用,可谓一绝。我觉得,在驱动开发的初期,使用它,一定是很好的,可以很快地检查硬件的工作情况,并执行简单的调试任务。WinDriver的最大的特点是,即时生成程序,在用户模式下进行调试。光这两点,就值得我们好好学习的了。我在这里就将生成PCI驱动的8个步骤简译如下: 1. 插入PCI硬件。(这个硬件就是我们做的PCI卡。) 2. 打开Wizard。 3. 选择你的硬件(在Wizard的列表中,会出现所有安装在PC机上的硬件,如果我们把9054插入,那么它会显示出来)。 4. 生成INF文件 5. 探测硬件 a) Wizard会自动探测你硬件的硬件资源(I/O ranges, Memory ranges and Interrupt) b) 如果不是PNP的,你可以手工进行定义。 6. 测试硬件 a) 在写你的驱动时,这个时很重要的,它可以保证你的硬件入你所愿地工作。 b) 读、写I/O Port, Memory space 和 你定义的寄存器。 c) “Listen”硬件的中断。 7. 生成Driver Code 8. 生成INF文件。 这种生成驱动的方法,很直观,而且更妙的是可以什么都不做,就可以检测硬件了,这些都要归功于WinDriver的底层驱动,这使得,通过WinDriver取得的驱动是不能独立运行的,必须要WinDriver的支持。但这点小瑕疵,并不影响我们去使用它。如果它不是太贵的话,真应该去买正版的,我想他们也需要“顶顶”的支持。 |
|
21楼#
发布于:2004-12-08 21:39
dengyih老哥:
你太强了! 我能问你一下continue()式传输什么的阿,看完了帮助很糊涂, a segment of transfer 指的是什么阿?是一次DMA需要好几次才能传输完成吗?还是指的下一次传输的需要设置的东西? 我对continue()很迷茫? 假如我用ReadFile来读一次DMA,那么会执行到OnDmaReady,然后StartDMA,它是一个判断语句 if ((ULONG) pXfer->BytesRemaining() == I.ReadSize()) StartDMA(ptd->td_PhysAddr.LowPart,ptd->td_Length) 可是第一次没传完,再传会再次调用StartDMA(?),但是 pXfer->BytesRemaining() 不== I.ReadSize(),那还怎么办?是不是我的理解有错误? pXfer->SequenceTransferDescriptors()传输一次DMA为什么要获得好几次TransferDescriptors? 请你给我强一下这个流程? 谢!!!! |
|
22楼#
发布于:2004-12-09 19:37
在这些工具中DDK是Microsoft提供的,是整个驱动程序开发的基础,DriverStudio就是建立在此基础之上的,因没用过DriverWork所以不知DW能否独立地编写驱动。有人说,DDK是驱程的汇编,而DS是驱程的C语音,那么DW,我理解就是驱程的VB了。比较过DDK和DS和DW,DW确实是最简单的,甚至它已经为PLX9054写了模板,还提供了实例,因为它是PLX的合作伙伴。但在DW里基本看不见DDK的影子。和DW比较,DS就复杂一些了,它的许多功能歧视是DDK例程的打包,它通过类的方法将DDK的功能包装在一起。要了解驱动程序的设计,最后还是要了解DDK的。
不能理解:DriverStudio中编写WDM驱动程序的工具就是driverwork,所以DS和DW应该是一个冬冬才对,我觉得是不是将windriver错写成了driverwork了,不知我理解的对不对? [编辑 - 12/9/04 by imagewxg] |
|
23楼#
发布于:2005-03-17 16:13
好帖啊 !!!好佩服各位大虾
|
|
24楼#
发布于:2005-03-18 11:39
绝对好贴!!
|
|
25楼#
发布于:2005-03-31 09:45
好贴,支持
|
|
26楼#
发布于:2005-04-04 14:45
应该整理一下上传呀!
|
|
|
27楼#
发布于:2005-04-08 22:05
受益匪浅啊
|
|
28楼#
发布于:2005-06-08 15:05
好贴!顶……
|
|
29楼#
发布于:2005-07-07 20:06
下面是引用imagewxg于2004-12-09 19:37发表的: 我也觉的楼主在这一点上是不是不小心给弄错了。 不过从楼主那里还是可以学到很多东东,谢了!!!! |
|
|
30楼#
发布于:2005-07-07 20:07
下面是引用imagewxg于2004-12-09 19:37发表的: 我也觉的楼主在这一点上是不是不小心给弄错了。 不过从楼主那里还是可以学到很多东东,谢了!!!! |
|
|
31楼#
发布于:2005-07-07 20:07
下面是引用imagewxg于2004-12-09 19:37发表的: 我也觉的楼主在这一点上是不是不小心给弄错了。 不过从楼主那里还是可以学到很多东东,谢了!!!! |
|
|
32楼#
发布于:2007-02-02 14:29
在驱动程序中,我写了一个Dma传输的程序,并没有涉及任何的硬件操作,在serialread调用定回调函数,回调函数然后,触发OnDmaReady()函数调用,
但是在程序运行时,在 sofitice中出现如下的错误: Break Due to KeBufCheckEx(unhandle kernel mode exception) Error = A (IROQL_NOT_Less_or_EQAOL) P1=60 D2=2 P3=0 P4=F47A0EC0 然后机器自动重新启动了。当屏蔽掉OnDmaReady()中的(ULONG) pXfer->BytesRemaining() == I.ReadSize()这段代码时 程序就不会出现任何的错误。我实在是弄不清这是什么的原因,请大家帮我检查一下我的程序错在那里? 后来发现VOIDOnDmaReady(KDmaTransfer *pXfer, KIrp I)中没有传递参数KIrp I,请问怎样修改 代码如下,版本为DS3.1 VOID P5064Device::OnDmaReady(KDmaTransfer *pXfer, KIrp I) { // All KDmaTransfer callbacks must first check to see if there are any bytes // left to transfer. //DMA 结束处理 t << "start ondmaready" << EOL; t << "IRP:" << I << EOL; if (pXfer->BytesRemaining() == 0) { // If there are no bytes left to transfer, the callback must call // Terminate(). Then it completes the IRP with STATUS_SUCCESS. pXfer->Terminate(); I.Information() = I.ReadSize(CURRENT); I.Status() = STATUS_SUCCESS; PnpNextIrp(I); m_CurrentTransfer = NULL; delete pXfer; return; } // We must get the descriptor for the physical memory location for // the DMA transfer. PTRANSFER_DESCRIPTOR ptd; //DMA 处理 while (pXfer->SequenceTransferDescriptors(&ptd)) { // program the h/w using ppTD t << " Physical address 0x" << ptd->td_PhysAddr.LowPart << ". Length is 0x" << ptd->td_Length << "." << EOL; } // If this is the first time through, then start the DMA going. // We only want to do this ONCE for a given Read transfer. That // way, our data will be collected smoothly, without interruptions // or dropouts. //DMA 开始 -》进入startDMA进行配置和启动DMA if ((ULONG) pXfer-BytesRemaining() == I.ReadSize()) { t << "GOTO StartDMA " << EOL; }> // StartDMA(ptd->td_PhysAddr.LowPart,ptd->td_Length,(I.MajorFunction() == IRP_MJ_READ) ? FromDeviceToMemory : FromMemoryToDevice); } void P5064Device::SerialRead(KIrp I) { t << "Entering SerialRead, " << I << EOL; NTSTATUS status = STATUS_SUCCESS; // KMemory Mem(m_Buffer.Mdl()); // m_IoPortRange1.outd(INTCSR,0x40000);//DMA通道0中断 // Create a new DMA transfer object for this IRP m_CurrentTransfer = new(NonPagedPool) KDmaTransfer(this, &m_Dma); RtlZeroMemory(m_Buffer.VirtualAddress(), MAX_DMA_LENGTH); if ( m_CurrentTransfer == NULL ) { status = STATUS_INSUFFICIENT_RESOURCES; //DbgPrint("BMDmaTstDevice: unable to allocate transfer object: %x\n", status); t <<"unable to allocate transfer object" <<EOL; I.Information() = 0; I.Status() = status; NextIrp(I); } status = m_CurrentTransfer->Initiate( this, &m_Dma, I.Mdl(), (I.MajorFunction() == IRP_MJ_READ) ? FromDeviceToMemory : FromMemoryToDevice, LinkTo(OnDmaReady), &m_Buffer ); // If the transfer cannot be initiated, complete it with an error status. if ( ! NT_SUCCESS(status) ) { t<<" unable to initiate transfer"<<EOL; delete m_CurrentTransfer; m_CurrentTransfer = NULL; I.Information() = 0; I.Status() = status; NextIrp(I); } } 谢谢众位大师指点帮忙 |
|
|
33楼#
发布于:2007-02-02 14:31
寻求大师高手帮助
在驱动程序中,我写了一个Dma传输的程序,并没有涉及任何的硬件操作,在serialread调用定回调函数,回调函数然后,触发OnDmaReady()函数调用, 但是在程序运行时,在 sofitice中出现如下的错误: Break Due to KeBufCheckEx(unhandle kernel mode exception) Error = A (IROQL_NOT_Less_or_EQAOL) P1=60 D2=2 P3=0 P4=F47A0EC0 然后机器自动重新启动了。当屏蔽掉OnDmaReady()中的(ULONG) pXfer->BytesRemaining() == I.ReadSize()这段代码时 程序就不会出现任何的错误。我实在是弄不清这是什么的原因,请大家帮我检查一下我的程序错在那里? 后来发现VOIDOnDmaReady(KDmaTransfer *pXfer, KIrp I)中没有传递参数KIrp I,请问怎样修改 代码如下,版本为DS3.1 VOID P5064Device::OnDmaReady(KDmaTransfer *pXfer, KIrp I) { // All KDmaTransfer callbacks must first check to see if there are any bytes // left to transfer. //DMA 结束处理 t << "start ondmaready" << EOL; t << "IRP:" << I << EOL; if (pXfer->BytesRemaining() == 0) { // If there are no bytes left to transfer, the callback must call // Terminate(). Then it completes the IRP with STATUS_SUCCESS. pXfer->Terminate(); I.Information() = I.ReadSize(CURRENT); I.Status() = STATUS_SUCCESS; PnpNextIrp(I); m_CurrentTransfer = NULL; delete pXfer; return; } // We must get the descriptor for the physical memory location for // the DMA transfer. PTRANSFER_DESCRIPTOR ptd; //DMA 处理 while (pXfer->SequenceTransferDescriptors(&ptd)) { // program the h/w using ppTD t << " Physical address 0x" << ptd->td_PhysAddr.LowPart << ". Length is 0x" << ptd->td_Length << "." << EOL; } // If this is the first time through, then start the DMA going. // We only want to do this ONCE for a given Read transfer. That // way, our data will be collected smoothly, without interruptions // or dropouts. //DMA 开始 -》进入startDMA进行配置和启动DMA if ((ULONG) pXfer-BytesRemaining() == I.ReadSize()) { t << "GOTO StartDMA " << EOL; }> // StartDMA(ptd->td_PhysAddr.LowPart,ptd->td_Length,(I.MajorFunction() == IRP_MJ_READ) ? FromDeviceToMemory : FromMemoryToDevice); } void P5064Device::SerialRead(KIrp I) { t << "Entering SerialRead, " << I << EOL; NTSTATUS status = STATUS_SUCCESS; // KMemory Mem(m_Buffer.Mdl()); // m_IoPortRange1.outd(INTCSR,0x40000);//DMA通道0中断 // Create a new DMA transfer object for this IRP m_CurrentTransfer = new(NonPagedPool) KDmaTransfer(this, &m_Dma); RtlZeroMemory(m_Buffer.VirtualAddress(), MAX_DMA_LENGTH); if ( m_CurrentTransfer == NULL ) { status = STATUS_INSUFFICIENT_RESOURCES; //DbgPrint("BMDmaTstDevice: unable to allocate transfer object: %x\n", status); t <<"unable to allocate transfer object" <<EOL; I.Information() = 0; I.Status() = status; NextIrp(I); } status = m_CurrentTransfer->Initiate( this, &m_Dma, I.Mdl(), (I.MajorFunction() == IRP_MJ_READ) ? FromDeviceToMemory : FromMemoryToDevice, LinkTo(OnDmaReady), &m_Buffer ); // If the transfer cannot be initiated, complete it with an error status. if ( ! NT_SUCCESS(status) ) { t<<" unable to initiate transfer"<<EOL; delete m_CurrentTransfer; m_CurrentTransfer = NULL; I.Information() = 0; I.Status() = status; NextIrp(I); } } 谢谢众位大师指点帮忙 |
|
|
34楼#
发布于:2007-02-03 16:40
好贴呀。一个字:顶!
|
|
35楼#
发布于:2007-02-05 14:04
楼主和各位高手帮忙解决一下小弟的困难呀,很急
|
|
|
36楼#
发布于:2007-03-06 16:58
虽然不是很懂,但也得到了不少启发,谢谢了
|
|
37楼#
发布于:2007-03-06 16:58
虽然不是很懂,但也得到了不少启发,谢谢了
|
|
38楼#
发布于:2007-03-07 17:49
找到原因了:在回调函数Ondmaready中参数Kirp I 没有返回数值,其为0。但不知道为什么出现这种错误。请问哪位高手知道,是否是版本的问题, 我用的版本是3.1。但用2.6版本生成的代码,在3.1版本编译后安装运行可以通过。没有重起的现象。Ondmaready函数中参数Kirp I 有数值
|
|
|
39楼#
发布于:2007-06-12 22:33
偶还没怎么入门,不过,帮助很大啊,谢谢了
|
|