阅读:5974回复:17
300分相送!再论ezusb的“超时”问题!请解决这个问题的前辈们指教!
查看以前的帖,讨论ezusb驱动的“超时”问题的大有人在,很多都是02年03年的帖,我想过了那么久,一定有很多人把问题解决了把。可是没人愿意贴出比较完整可行的代码,我试了几个从旧帖里抄下来的代码,编译运行后除了蓝屏还是蓝屏。
那位高人愿意站出来,把解决“超时”问题的相关代码帖出来,小弟们不胜感激啊! 哪位前辈愿意把Walter Oney解决“超时”问题的相关代码帖出来啊? |
|
沙发#
发布于:2007-05-31 11:02
"rayyang2000"大侠在旧帖里说过:"去把driverworks里面对应的代码,拿过来不就行了!"
可是Compuware\SoftICE Driver Suite\DriverWorks\Examples\wdm 目录下 的例子根本没有KeWaitForSingleObject这个函数! 以下是在老帖子里找到的用Walter Oney实现的超时问题的代码,可是仍然会出现“蓝屏”现象, 请高手们指出代码中的错误! NTSTATUS Ezusb_CallUSBD(IN PDEVICE_OBJECT fdo, IN PURB urb) { NTSTATUS ntStatus,status=STATUS_SUCCESS; PDEVICE_EXTENSION pdx; PIRP irp; IO_STATUS_BLOCK ioStatus; PIO_STACK_LOCATION nextStack; KEVENT event; pdx=fdo->DeviceExtension; //issue a synchronous request(同步请求) KeInitializeEvent(&event,NotificationEvent,FALSE); //build irp which will be send to bus driver irp=IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, pdx->StackDeviceObject, NULL, 0, NULL, 0, TRUE, //internal &event, &ioStatus); //newly added for timeout IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE)HUSBDCompletionRoutine, (PVOID)&event, TRUE, TRUE, TRUE); //prepare for calling the usb bus driver nextStack=IoGetNextIrpStackLocation(irp); ASSERT(nextStack!=NULL); nextStack->Parameters.Others.Argument1=urb; //call the USB driver stack to perform the operation.if the return value is //PENDING ,wait for request to complete ntStatus=IoCallDriver(pdx->StackDeviceObject,irp); //STATUS_PENDING means the lower driver have not finished processing the IRP, //yet.we must wait. if(ntStatus==STATUS_PENDING) { LARGE_INTEGER timeout5second; timeout5second.QuadPart=-5*10000000; //5秒 status=KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, &timeout5second); if(status==STATUS_TIMEOUT) { IoCancelIrp(irp); KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,NULL); } } else { ioStatus.Status=ntStatus; //added here KeClearEvent(&event); IoCompleteRequest(irp,IO_NO_INCREMENT); KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,NULL); } //USBD maps the error code for us,USBD uses error codes in its URB structure, //that are more insightful into USB behavior.in order to match the //NT status code,USBD maps its error codes into more general NT // error categories so higher level drivers can decipher the error codes // based on standard NT error code definitions. // ntStatus=ioStatus.Status; // // If the URB status was not USBD_STATUS_SUCCESS, we save a copy of the // URB status in the device extension. After a failure, another IOCTL, // IOCTL_EVK_GET_LAST_ERROR can be used to retrieve the URB status // for the most recently failed URB. Of course, this status gets // overwritten by subsequent failures, but it\'s better than nothing. // if(NT_SUCCESS(ntStatus)) { if(!USBD_SUCCESS(urb->UrbHeader.Status)) ntStatus=STATUS_UNSUCCESSFUL; } return ntStatus; } //-------------HUSBDCompletionRoutine--------- NTSTATUS HUSBDCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PKEVENT pEvent = (PKEVENT)Context; KeSetEvent(pEvent, 0, TRUE); return STATUS_MORE_PROCESSING_REQUIRED; } |
|
板凳#
发布于:2007-06-01 16:20
我每天顶一次,直到有大侠出来相救!
|
|
地板#
发布于:2007-06-02 08:17
今天还没人来相救!我再顶!
|
|
地下室#
发布于:2007-06-03 23:31
今天星期天,没人回,再顶!
|
|
5楼#
发布于:2007-06-04 00:51
"rayyang2000"大侠在旧帖里说过:"去把driverworks里面对应的代码,拿过来不就行了!"
可是Compuware\SoftICE Driver Suite\DriverWorks\Examples\wdm 目录下 的例子根本没有KeWaitForSingleObject这个函数! 1, DriverStudio把DDK的函数都经过自己重新包装了,所以直接搜索是有可能找不到的,不如自己通读一遍咯,花个把小时就可以的... 2, 蓝屏的问题有很多可能了,最好用windbg跟踪调试一下。。我有个想法是可能在处理Pending的那段代码里,在额外等5s?中的时候正好这个IRP被下层驱动完成了,但是我们不知道就继续调用cancel导致的.....好久没有看驱动这块了,忘记了好多,手头资料也少,说的不对请大家批评!! |
|
6楼#
发布于:2007-06-04 12:13
不知道你说的超时是什么现象。是指read的urb没有在指定时间内得到回应吗?如果是这样,基本上是你的firmware的问题,不需要怀疑driver部分。至于bsod,那就是你的driver了,但不太会是cancel,解决方法也很简单,只要三板斧:
1 prefast + Static Driver Verifier, 2 Driver Verifier + HCT/DTM, 3 WinDbg + Memory Dump File |
|
|
7楼#
发布于:2007-06-04 21:01
恩,再看了一下代码,因为用的是同一个event,同意rayyang2000的观点,cancel那段代码不会导致BSOD...
BTW,超级喜欢prefast,在WDK里面非常好的工具... |
|
8楼#
发布于:2007-06-05 12:58
引用第7楼Shentu于2007-06-04 23:01发表的 : 没错~~~经常会发现一些自己写的很小白的代码~~~ ![]() ![]() |
|
|
9楼#
发布于:2007-06-05 14:53
能得到rayyang2000 ,Shentu两位元老级人物的回帖,小弟兴奋了一早上!
我指的超时现象是指KeWaitForSingleObject()函数死等,不返回的情况: 1:68013固件是同步slavefifo模式EP6 auto in,应用程序读端点EP6,达到28M/byte,连续几十秒后死掉,需要拔掉usb口才能关闭应用程序。 2:跟踪68013驱动ezusb,发现进入Ezusb_CallUSBD(fdo, urb)函数里的KeWaitForSingleObject()函数就死掉!这个函数一直没有返回!! 问题: 1:两位大侠有没有用过68013做高速的数据采集? 2:两位大侠用68013的驱动程序ezusb时有没有遇到上述问题?你们是如何解决的? 3:我再次修改walter oney的上述代码后只要KeWaitForSingleObject(...&timeout5second)函数等待5秒后没回应就返回,继续网下走。 上面的代码片断: else { ioStatus.Status=ntStatus; //added here KeClearEvent(&event); IoCompleteRequest(irp,IO_NO_INCREMENT); KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,NULL); } 改为: // else //去掉else就不会“蓝屏”了! // { ioStatus.Status=ntStatus; //added here KeClearEvent(&event); IoCompleteRequest(irp,IO_NO_INCREMENT); KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,NULL); // } 就可以了 4:经过上述修改后KeWaitForSingleObject(&event,Suspended,KernelMode,false,&timeout5second)函数在等待5秒没 响应后能正常返回STATUS_TIMEOUT了,驱动程序能继续网下走。可是第2次进入Ezusb_CallUSBD()函数时再也读不到数据 了,是不是KeWaitForSingleObject()超时返回后就在也读不出68013的数据了,需要“硬件复位”才能恢复正常? 我试过重新下载固件后又可以连续读个几十秒,不过这样的方法太笨了。 其他讨论: rayyang2000说是我的“firmware的问题,不需要怀疑driver部分”,可是“firmware”对于slavefifo模式EP6 auto in的 方式只需改动几个相关的寄存器,其他的都是68013内核自动完成,我们根本就干涉不了啊?至于驱动读EP6的fifo时, 68013偶尔出现不能及时返回数据的原因我也不清楚,希望大侠解答! 网上还有讨论用异步读的方法:请问异步是不是只在驱动程序中的异步,相对于驱动程序中的同步,速度上怎样? 在驱动中异步读会不会遇到68013不能及时返回数据而驱动程序死等的现象? |
|
10楼#
发布于:2007-06-05 17:49
异步读是一个不错的选择,一般是用IoCompletion Routine来实现异步读的,就不会有你说的死等导致应用程序死掉的问题。具体实现方法参看WDK文档和例子,或者搜索论坛。
|
|
11楼#
发布于:2007-06-06 11:46
老大,有没有现成的驱动异步读的.sys文件啊?驱动的异步读是不是比同步读慢啊?速度是多少啊?驱动的同步读就没有比较有效的解决办法了么?
还有,驱动的同步读造成的死等现象谱遍么?是不是很少人会遇到这种情况? |
|
12楼#
发布于:2007-06-06 13:06
1. 需要例子就参考WDK的例子或者DriverStudio的例子,在USB下面有很多的
2. 根本不会有速度慢的问题,如果你试着看看代码,理解它的工作原理的话,采用异步读的话系统效率会更高。 3. 同步读死等的解决办法是有的,最简单的就是修改应用程序,但是,并不是所有的应用程序都可以修改的,有的时候编写驱动就是“带着镣铐跳舞”,没有很多的选择。 |
|
13楼#
发布于:2007-06-06 18:50
谢谢Shentu,
谢谢rayyang2000, 还有谢谢jinghuiren的热心帮助! boss不会给我很多时间学驱动的,这个问题先放一边,我要做PCB了,等画完板子交给厂家做 板的那段时间我才来看驱动. 死了,看了半天也不知道怎么给分啊??? |
|
14楼#
发布于:2007-06-07 09:08
helloxieyu:
看到现在,我更能确定是你的firmware的问题。而且是时序逻辑上的问题。你也提到不是一直没有读到数据,只是有时候读不到,这说明你的firmware程序在某个时候没有把数据放到IN FIFO中,这种问题,你可以用firmware的debugger来调试,看看是什么原因造成的。 |
|
|
15楼#
发布于:2007-06-07 10:27
我觉得他应该是这样的情况:
1,在他下发read请求的时候并不知道firmware那里有没有数据,如果有数据,那么read请求能够正常返回,如果没有数据,那么就会进入超时等待了,楼主的意思是想在这个时候让驱动能够返回而不是死等在那里。所以有了5秒超时返回的问题,不过他虽然时间了,但是附带出现一个问题就是,超时返回后再发read请求无论如何也得不到数据了!这个现象很是奇怪。按说如果设备挂起或者被移出才需要复位来激活设备的。 2,第2种情况是read请求下发了,也确实读到了一些数据,但过了一会发现数据没有了,于是read就在一只等待数据返回,也就是死在那里了,这个肯定是firmware的问题,主机端和firmware端没有协商好数据的数量和出现时机。 对于情况1,建议你在超时返回后下发一个reset pipe的命令试一下,另外就是如果你不能确定设备端有没有数据,最好用vendor request先查询一下然后再发读数据的命令。 对于情况2,建议修改固件程序,使之与应用程序相匹配。另外就是要利用pktend管脚,如果主机要求的数据量较多,而firmware方没有那么多数据,那么在最后一个数据包时使用pktend管脚告诉主机说数据已经传输完成,这样驱动也能正常返回,而不会死在那里。 个人建议,仅供参考,呵呵 |
|
16楼#
发布于:2007-06-08 13:27
呵呵,我以为此帖就此结束了,没想到jinghuiren 兄跟rayyang2000还那么认真的帮我解决问题,特别是jinghuiren ,
分析得很细致,再次感谢你!大侠们有空到汕头来小弟一定会热情款待的! 连接68013的电路或逻辑(vhdl)如下: -------------------Synchronous FIFO Writes--------------------- IFCLK<=CLK_25M; --外部提供25M时钟 SLRD<='1'; fifoadd<="10"; --写入EP6 FIFOADR0<=fifoadd(0); FIFOADR1<=fifoadd(1); SLOE<='1' ; PKTEND<='1'; SLWR<=not FLAGB when "符合写入的时候" else --伪代码 '1'; 以下是部分固件代码,用的是外部25M的同步时钟 //-------------------------------------部分固件如下----------------------------------------------------- void TD_Init( void ) { CPUCS = 0x02; // CLKSPD[1:0]=10, for 48MHz operation CLKOE=0 IFCONFIG = 0x03; //外部给出时钟25M时钟 // IFCONFIG = 0xE3; //内部48M时钟 // IFCLKSRC=1 , FIFOs executes on internal clk source // xMHz=1 , 48MHz internal clk rate // IFCLKOE=1 , 输出IFCLK给外部逻辑用,Don't drive IFCLK pin signal at 48MHz // IFCLKPOL=0 , Don't invert IFCLK pin signal from internal clk // ASYNC=0 , 改成同步FIFO // GSTATE=0 , Don't drive GPIF states out on PORTE[2:0], debug WF // IFCFG[1:0]=11, FX2 in slave FIFO mode // Registers which require a synchronization delay, see section 15.14 // FIFORESET FIFOPINPOLAR // INPKTEND OUTPKTEND // EPxBCH:L REVCTL // GPIFTCB3 GPIFTCB2 // GPIFTCB1 GPIFTCB0 // EPxFIFOPFH:L EPxAUTOINLENH:L // EPxFIFOCFG EPxGPIFFLGSEL // PINFLAGSxx EPxFIFOIRQ // EPxFIFOIE GPIFIRQ // GPIFIE GPIFADRH:L // UDMACRCH:L EPxGPIFTRIG // GPIFTRIG // Note: The pre-REVE EPxGPIFTCH/L register are affected, as well... // ...these have been replaced by GPIFTC[B3:B0] registers SYNCDELAY; // see TRM section 15.14 REVCTL = 0x01; // use enhanced packet handling // NOTE: when using "enhanced packet handling" feature (REVCTL.0=1) // ...the core functions as follows: // - OUTPKTEND is used to skip/commit OUT pkt. // - INPKTEND is used to skip/commit IN pkt. // - EPxBCH/L is used to // - commit cpu sourced pkt. // - modify length of an OUT pkt. // - cpu can not source an OUT pkt in "AUTOOUT" mode // - see cpu source out pkt method in BOOL DR_VendorCmnd(); ... SYNCDELAY; // //EP2CFG Endpoint 2 Configuration VALID DIR TYPE1 TYPE0 SIZE 0 BUF1 BUF0 // EP2 512 BULK OUT 4x EP2CFG = 0xA0; // BUF[1:0]=00 for 4x buffering // EP6 512 BULK IN 4x SYNCDELAY; // EP6CFG = 0xE0; // SIZE=0 512 BYTE BUF[1:0]=00 for 4x buffering 1110 0000 // EP4 and EP8 are not used in this implementation... SYNCDELAY; // EP4CFG = 0x20; // clear valid bit SYNCDELAY; // EP8CFG = 0x60; // clear valid bit SYNCDELAY; // FIFORESET = 0x80; // activate NAK-ALL to avoid race conditions SYNCDELAY; // FIFORESET = 0x02; // reset, FIFO 2 SYNCDELAY; // FIFORESET = 0x04; // reset, FIFO 4 SYNCDELAY; // FIFORESET = 0x06; // reset, FIFO 6 SYNCDELAY; // FIFORESET = 0x08; // reset, FIFO 8 SYNCDELAY; // FIFORESET = 0x00; // deactivate NAK-ALL SYNCDELAY; // // 8-bit bus (WORDWIDE=0)... EP2FIFOCFG = 0x10; // AUTOOUT=1, WORDWIDE=0 修改AUTOOUT=1,自动提交输出给FIFO SYNCDELAY; // // use auto in mode EP6FIFOCFG = 0x0C; // AUTOIN=1, ZEROLENIN=1, WORDWIDE=0 SYNCDELAY; // EP4FIFOCFG = 0x00; //WORDWIDE=0 SYNCDELAY; // EP8FIFOCFG = 0x00; //WORDWIDE=0 SYNCDELAY; OED = 0xff; IOD = 0x80; OEE = 0xff; IOE = 0x80; EZUSB_InitI2C(); // Initialize I2C Bus EZUSB_WriteI2C(LED_ADDR, 0x01, &(Digit[0])); EZUSB_WaitForEEPROMWrite(LED_ADDR); } //------------------------------应用程序部分代码如下--------------------------------------------------------- void CBitMapView::ResetFifo() //读fifo数据函数 { //一些初始化,声明等...... status = DeviceIoControl (hInDevice, IOCTL_EZUSB_BULK_READ, (PVOID)&inBulkControl, sizeof(BULK_TRANSFER_CONTROL), outBuffer,//输出缓冲区 32768,//字节数, 32768 &BytesReturned,//返回字节数据 NULL); } //-------------------------------------------------------- void CBitMapView::ResetFifo() //复位fifo函数 { //一些初始化,声明等...... inBulkControl.pipeNum=1;//端点选择EP6 bResult=DeviceIoControl (hInDevice, IOCTL_Ezusb_RESETPIPE, //复位fifo,好像不顶用哦! //IOCTL_Ezusb_RESET, //这个也不顶用的! (PVOID)&inBulkControl, sizeof(BULK_TRANSFER_CONTROL), outBuffer, 10, &BytesReturned, NULL); } //---------------------------------------------------------------------------------------------------------- 回jinghuiren兄: 1: 超时返回后下发一个reset pipe的命令,还是再也读不到数据了,用“control panel” 或用上述的 ResetFifo()函数都 不顶用!用“control panel”从新下载固件才起作用! 2: 您建议我修改固件程序,可是固件里跟slavefifo auto in相关的就只有TD_Init()函数的几个寄存器的修改,其他都是 68013内核自动完成的,我好像没什么可修改的地方。 3: 您建议的“利用pktend管脚”,当然,我对pktend管脚的应用不熟悉,而且固件端怎么知道主机要求的数据量(有没有相关的固件代码啊)? 其他问题: 昨天,代理商告诉我,我用的"the chip you are using is a EOL part. You are impossible to buy it anymore. Please change CY7C68013A-128AXC." 我用的是CY7C68013A-128AC,现在没有了,换成CY7C68013A-128AXC,不知两个器件有何区别?驱动有何区别? 我的电路图已经做好了,不知换成CY7C68013A-128AXC要不要修改。 汕头的牛肉丸n好吃哦,美女也挺多的!呵呵... |
|
17楼#
发布于:2008-01-09 11:16
学习了,大大受益!对前辈表示感谢!
|
|