阅读:1997回复:11
棘手的问题...
我在做BULK驱动,BULK-OUT是正常的,但BULK-IN没有数据然后卡在WaitForSingleObject,加了超时,调用IOCancellIRP,但是从此以后整个驱动就再也发不出USB信息了,Control命令也发不出去,可有解决之道?谢谢!
|
|
沙发#
发布于:2010-03-02 23:44
大概与调用IoCancellrp时没有考虑到怎样应对将出现一系列比较复杂的逻辑(与完成请求、IoFreeIrp有关),一般是代码写的过于简单,把有关的代码贴出来,才好让大家出主意。
|
|
板凳#
发布于:2010-03-03 13:25
NTSTATUS CallUSBDI( IN PUSBPS_DEVICE_EXTENSION dx, IN PVOID UrbEtc,
IN ULONG IoControlCode/*=IOCTL_INTERNAL_USB_SUBMIT_URB*/, IN ULONG Arg2/*=0*/) { IO_STATUS_BLOCK IoStatus; KEVENT event; // Initialise IRP completion event KeInitializeEvent(&event, NotificationEvent, FALSE); // Build Internal IOCTL IRP PIRP Irp = IoBuildDeviceIoControlRequest( IoControlCode, dx->NextStackDevice, NULL, 0, // Input buffer NULL, 0, // Output buffer TRUE, &event, &IoStatus); // Get IRP stack location for next driver down (already set up) PIO_STACK_LOCATION NextIrpStack = IoGetNextIrpStackLocation(Irp); // Store pointer to the URB etc NextIrpStack->Parameters.Others.Argument1 = UrbEtc; NextIrpStack->Parameters.Others.Argument2 = (PVOID)Arg2; IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)USBDCompletionRoutine, (PVOID)&event, TRUE, TRUE, TRUE); // Call the driver and wait for completion if necessary //dx -> TimerHandledEvent = &event; //IoStartTimer(dx->fdo); DebugPrint("Usb Waiting\n"); LARGE_INTEGER TimeoutInt; TimeoutInt.QuadPart = -1000000; NTSTATUS status = IoCallDriver( dx->NextStackDevice, Irp); DebugPrint("Usb Waiting 1\n"); if (status == STATUS_PENDING) { DebugPrint("CallUSBDI: waiting for URB completion"); DebugPrint("Usb Waiting a\n"); status = KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, &TimeoutInt); //status = KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL); DebugPrint("Usb Waiting b\n"); if( status == STATUS_TIMEOUT ) { DebugPrint (" Wait for single object, returned STATUS_TIMEOUT\n"); // we timed out - cancel the IRP status = IoCancelIrp( Irp ); DebugPrint (" Canceling IRP %x\n",status); KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,NULL); } else { status = IoStatus.Status; } } // return IRP completion status // DebugPrint("CallUSBDI returned %x",status); return status; } NTSTATUS USBDCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PKEVENT pEvent = (PKEVENT)Context; KeSetEvent(pEvent, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS UsbGetData( IN PUSBPS_DEVICE_EXTENSION dx) { // Allocate memory for URB UCHAR retryCount = 0; USHORT UrbSize = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER); PURB urb = (PURB)ExAllocatePool(NonPagedPool, UrbSize); if( urb==NULL) { DebugPrint("No URB memory"); return STATUS_INSUFFICIENT_RESOURCES; } ULONG sizeBuffer; PUCHAR dataBuffer; sizeBuffer = 64; dataBuffer = (PUCHAR)ExAllocatePool(NonPagedPool, sizeBuffer); if( dataBuffer==NULL) { ExFreePool(urb); DebugPrint("No buffer memory"); return STATUS_INSUFFICIENT_RESOURCES; } // Build the Get Descriptor URB checkSendData: UsbBuildInterruptOrBulkTransferRequest( urb, UrbSize, dx->UsbDataInHandle, //Pipe Handler dataBuffer, //buffer NULL, //MDL sizeBuffer, //size USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK ,//TransferFlags NULL // link ); // Call the USB driver NTSTATUS status = CallUSBDI( dx, urb ); // Check statuses if( !USBD_SUCCESS( urb->UrbHeader.Status)) { DebugPrint("status %x URB status %x", status, urb->UrbHeader.Status); status = STATUS_UNSUCCESSFUL; if ( retryCount < 3 ) { DebugPrint("USB get data failed:retry"); retryCount ++; goto checkSendData; } } ExFreePool(urb); ExFreePool(dataBuffer ); return status; } |
|
地板#
发布于:2010-03-04 13:25
帮一下忙,谢谢!
|
|
地下室#
发布于:2010-03-04 21:45
你似乎在CallUSBDI函数结束return status;前加上一句:IoCompleteRequest(Irp, IO_NO_INCREMENT);
你在正常工作时候,底层驱动调用了完成请求IoCompleteRequest ,将执行你的完成例程USBDCompletionRoutine,该函数中你返回了STATUS_INSUFFICIENT_RESOURCES,中止了完成请求的执行,因此这个IRP也不会得到释放。所以你要加IoCompleteRequest这一句接着处理,重新触发后,继续进行后续的清理,比如调用IoFreeIrp把这个Irp给释放了。所以,这个问题简单可认为是没有把Irp释放掉。 你这个问题可参考《Programming the Microsoft Windows Driver Model(2nd)》里面有比较详细的解释,这本书写的非常好。还有这段代码里有个小概率发生的竞争事件,你可以仔细读读这里面的研究。 |
|
5楼#
发布于:2010-03-05 20:54
请问除了IoFreeIrp还有什么吗?我只用了IoFreeIrp,然后系统就死机了,也没有蓝屏
|
|
6楼#
发布于:2010-03-06 15:26
看了那本书,不过我自己还是搞不定啊,帮下忙....
|
|
7楼#
发布于:2010-03-07 01:00
NTSTATUS
USBDCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { if (Irp->PendingReturned) {PKEVENT pEvent = (PKEVENT)Context; KeSetEvent(pEvent, 0, FALSE); } return STATUS_MORE_PROCESSING_REQUIRED; } 你贴出的代码中没看见你调用IoFreeIrp啊,你说“我只用了IoFreeIrp,然后系统就死机了”,那是你过早地释放了IRP吧。 你增加IoCompleteRequest(Irp, IO_NO_INCREMENT)这条语句如果不能解决问题,那我也没有办法,请高手露面吧。 |
|
9楼#
发布于:2010-03-09 19:46
哦,原来我是没加的,就是因为Bulk-In不成功卡死在那,我才又加了这个,设置完成例程是因为当超时发生而一路跑下去不管的话CallUSBDI会引起蓝屏
|
|
10楼#
发布于:2010-03-11 19:16
大家过帖留留名,是不是我的问题太低级了...不管怎样,帮一下吧,谢谢了。
|
|
11楼#
发布于:2010-03-12 10:58
Bulk-in不成功,卡死,我怀疑是设备端存在问题,导致数据包一直不结束,总线这边就没法完成。
另外,你要加完成例程,用IoAllocateIrp,然后再自己来填IRP STACK 参数,IoCallDriver, KeWaitForSingleObject,最后IoFreeIrp -- 这一套机制也不复杂。 |
|