zhenchuan9r
驱动牛犊
驱动牛犊
  • 注册日期2009-09-04
  • 最后登录2010-03-11
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望101点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1997回复:11

棘手的问题...

楼主#
更多 发布于:2010-03-02 12:55
我在做BULK驱动,BULK-OUT是正常的,但BULK-IN没有数据然后卡在WaitForSingleObject,加了超时,调用IOCancellIRP,但是从此以后整个驱动就再也发不出USB信息了,Control命令也发不出去,可有解决之道?谢谢!
xzyee
驱动牛犊
驱动牛犊
  • 注册日期2005-08-08
  • 最后登录2010-07-01
  • 粉丝0
  • 关注0
  • 积分48分
  • 威望185点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2010-03-02 23:44
大概与调用IoCancellrp时没有考虑到怎样应对将出现一系列比较复杂的逻辑(与完成请求、IoFreeIrp有关),一般是代码写的过于简单,把有关的代码贴出来,才好让大家出主意。
zhenchuan9r
驱动牛犊
驱动牛犊
  • 注册日期2009-09-04
  • 最后登录2010-03-11
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望101点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于: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;
}

zhenchuan9r
驱动牛犊
驱动牛犊
  • 注册日期2009-09-04
  • 最后登录2010-03-11
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望101点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2010-03-04 13:25
帮一下忙,谢谢!
xzyee
驱动牛犊
驱动牛犊
  • 注册日期2005-08-08
  • 最后登录2010-07-01
  • 粉丝0
  • 关注0
  • 积分48分
  • 威望185点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
地下室#
发布于: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)》里面有比较详细的解释,这本书写的非常好。还有这段代码里有个小概率发生的竞争事件,你可以仔细读读这里面的研究。
zhenchuan9r
驱动牛犊
驱动牛犊
  • 注册日期2009-09-04
  • 最后登录2010-03-11
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望101点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2010-03-05 20:54
请问除了IoFreeIrp还有什么吗?我只用了IoFreeIrp,然后系统就死机了,也没有蓝屏
zhenchuan9r
驱动牛犊
驱动牛犊
  • 注册日期2009-09-04
  • 最后登录2010-03-11
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望101点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2010-03-06 15:26
看了那本书,不过我自己还是搞不定啊,帮下忙....
xzyee
驱动牛犊
驱动牛犊
  • 注册日期2005-08-08
  • 最后登录2010-07-01
  • 粉丝0
  • 关注0
  • 积分48分
  • 威望185点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
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)这条语句如果不能解决问题,那我也没有办法,请高手露面吧。
jally76
驱动牛犊
驱动牛犊
  • 注册日期2005-04-28
  • 最后登录2010-11-23
  • 粉丝0
  • 关注0
  • 积分59分
  • 威望590点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2010-03-09 14:48
引用第4楼xzyee于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)》里面有比较详细的解释,这本书写的非常好。还有这段代码里有个小概率发生的竞争事件,你可以仔细读读这里面的研究。


他这里用的是IoBuildDeviceIoControlRequest,不用在本过程中再调用IoFreeIrp或IoCompleteRequest,因为I/O管理器在请求完成后会自动地回收IRP资源。

这个CallUSBDI过程存在着一个问题:就是不用自己再设置一个完成例程USBDCompletionRoutine,完全多此一举,而且容易出错。既然在IoBuildDeviceIoControlRequest中已经将event传递进去了,又在USBDCompletionRoutine中再用一次event对象,根本没有必要。在IoCallDriver之后,直接等待这个event就可以了。

至于卡住是不是由这个引起的,还不能断定,先将这个问题解决了吧。
zhenchuan9r
驱动牛犊
驱动牛犊
  • 注册日期2009-09-04
  • 最后登录2010-03-11
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望101点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2010-03-09 19:46
哦,原来我是没加的,就是因为Bulk-In不成功卡死在那,我才又加了这个,设置完成例程是因为当超时发生而一路跑下去不管的话CallUSBDI会引起蓝屏
zhenchuan9r
驱动牛犊
驱动牛犊
  • 注册日期2009-09-04
  • 最后登录2010-03-11
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望101点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2010-03-11 19:16
大家过帖留留名,是不是我的问题太低级了...不管怎样,帮一下吧,谢谢了。
jally76
驱动牛犊
驱动牛犊
  • 注册日期2005-04-28
  • 最后登录2010-11-23
  • 粉丝0
  • 关注0
  • 积分59分
  • 威望590点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2010-03-12 10:58
Bulk-in不成功,卡死,我怀疑是设备端存在问题,导致数据包一直不结束,总线这边就没法完成。

另外,你要加完成例程,用IoAllocateIrp,然后再自己来填IRP STACK 参数,IoCallDriver, KeWaitForSingleObject,最后IoFreeIrp -- 这一套机制也不复杂。
游客

返回顶部