helloxieyu
驱动牛犊
驱动牛犊
  • 注册日期2005-04-10
  • 最后登录2011-05-25
  • 粉丝0
  • 关注0
  • 积分820分
  • 威望83点
  • 贡献值0点
  • 好评度83点
  • 原创分0分
  • 专家分0分
阅读:3013回复:10

--------把ezusb改为异步驱动,请大侠们指点!---------

楼主#
更多 发布于:2007-06-20 16:14
      好不容易在网上找到一段把ezusb改为异步驱动的代码,运行后出现“蓝屏”。
恳请各位大侠看后踊跃发言,给菜鸟们打造一个异步驱动的入门平台。
rayyang2000, Shentu , jinghuiren兄:请指点一下,小弟实在搞不定啊!

以下的异步读写代码摘自“见贤思齐”的博客:

//--------------------------------------------------------
//--------------以下是ezusb.h的改动----------------------------
//--------------------------------------------------------
typedef struct _BULKUSB_RW_CONTEXT {
    PURB Urb;
    PDEVICE_OBJECT DeviceObject;
    PIRP  Irp;
    PMDL  Mdl;
    //-------以下为新增加的成员变量--------
    int    Length;
    int    Numxfer;
    ULONG_PTR VirtualAddress;
    PDEVICE_EXTENSION DeviceExtension;
    
} BULKUSB_RW_CONTEXT, *PBULKUSB_RW_CONTEXT;
#define EZUSB_MAXIMUM_TRANSTER_SIZE    1024    //这个我随便定的
#define BULKUSB_MAX_TRANSFER_SIZE      1024    //这个我随便定的

//-----------------------------------------------------
//-----------以下是ezusb.c的改动----------------------------
//-------------------------------------------------------
NTSTATUS
Ezusb_Read_Write(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:

Arguments:

Return Value:
NT status code
STATUS_SUCCESS: Read was done successfully
STATUS_INVALID_PARAMETER_3: The Endpoint Index does not specify an IN pipe
STATUS_NO_MEMORY: Insufficient data memory was supplied to perform the READ

This routine fills the status code into the Irp

--*/
{    
// define veriable
      
      PMDL mdl;
      PURB urb;
      ULONG totalLength;
      ULONG stageLength;
      ULONG urbFlags;
      BOOLEAN read;
      NTSTATUS ntStatus;
      ULONG_PTR virtualAddress;
      PDEVICE_EXTENSION deviceExtension;
      PIO_STACK_LOCATION irpStack;
      PIO_STACK_LOCATION nextStack;
      PBULKUSB_RW_CONTEXT rwContext;
      PUSBD_PIPE_INFORMATION pipeInformation = NULL;
      PUSBD_INTERFACE_INFORMATION interfaceInfo = NULL;
      USBD_PIPE_HANDLE pipeHandle = NULL;
      PBULK_TRANSFER_CONTROL bulkControl = (PBULK_TRANSFER_CONTROL)Irp->AssociatedIrp.SystemBuffer;
      
      DbgPrint("xieyu-----------------Ezusb_Read_Write()\n");
      //
      // initialize variables
      //
      urb = NULL;
      mdl = NULL;
      rwContext = NULL;
      totalLength = 0;
      irpStack = IoGetCurrentIrpStackLocation(Irp);
      read = (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ? TRUE : FALSE;
      deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
      interfaceInfo = deviceExtension->Interface;
      
      
      //
      // verify that the selected pipe is valid, and get a handle to it. If anything
      // is wrong, return an error
      //
      interfaceInfo = deviceExtension->Interface;
      
      if (!interfaceInfo)
      {
          DbgPrint(("Ezusb_Read_Write() no interface info - Exiting\n"));
          return STATUS_UNSUCCESSFUL;
      }
      
      if (bulkControl->pipeNum > interfaceInfo->NumberOfPipes)
      {
          DbgPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
          return STATUS_INVALID_PARAMETER;
      }
      
      pipeInformation = &(interfaceInfo->Pipes[bulkControl->pipeNum]);
      
      if (!((pipeInformation->PipeType == UsbdPipeTypeBulk) ||(pipeInformation->PipeType == UsbdPipeTypeInterrupt)))
      {
          DbgPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
          return STATUS_INVALID_PARAMETER;
      }
      
      pipeHandle = pipeInformation->PipeHandle;
      
      if (!pipeHandle)  
      {
          DbgPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
          return STATUS_UNSUCCESSFUL;
      }
      
      rwContext = (PBULKUSB_RW_CONTEXT)
      ExAllocatePool(NonPagedPool,
      sizeof(BULKUSB_RW_CONTEXT));
      
      if(rwContext == NULL)
      {      
            DbgPrint(("Failed to alloc mem for rwContext\n"));
            
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            goto Ezusb_read_write_exit;
      }
      
      if(Irp->MdlAddress)
      {      
          totalLength = MmGetMdlByteCount(Irp->MdlAddress);
      }
      
      if(totalLength > EZUSB_MAXIMUM_TRANSTER_SIZE) {
      
            DbgPrint(("Transfer length > circular buffer\n"));
            
            ntStatus = STATUS_INVALID_PARAMETER;
            
            ExFreePool(rwContext);
            
            goto Ezusb_read_write_exit;
      }
      
      if(totalLength == 0)
      {
      
             DbgPrint(("Transfer data length = 0\n"));
            
             ntStatus = STATUS_SUCCESS;
            
             ExFreePool(rwContext);
            
             goto Ezusb_read_write_exit;
      }
      
      urbFlags = USBD_SHORT_TRANSFER_OK;
      virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
      
      if(read)
      {      
            urbFlags |= USBD_TRANSFER_DIRECTION_IN;
            DbgPrint(("Read operation\n"));
      }
      else
      {      
            urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
            DbgPrint(("Write operation\n"));
      }
      
      //
      // the transfer request is for totalLength.
      // we can perform a max of BULKUSB_MAX_TRANSFER_SIZE
      // in each stage.
      //
      if(totalLength > BULKUSB_MAX_TRANSFER_SIZE) {
      
            stageLength = BULKUSB_MAX_TRANSFER_SIZE;
      }
      else
      {      
            stageLength = totalLength;
      }
      
      mdl = IoAllocateMdl((PVOID) virtualAddress,
      totalLength,
      FALSE,
      FALSE,
      NULL);
      
      if(mdl == NULL)
      {      
            DbgPrint(("Failed to alloc mem for mdl\n"));
            
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            
            ExFreePool(rwContext);
            
            goto Ezusb_read_write_exit;
      }  
      //
      // map the portion of user-buffer described by an mdl to another mdl
      //
      IoBuildPartialMdl(Irp->MdlAddress,
      mdl,
      (PVOID) virtualAddress,
      stageLength);
      
      urb = ExAllocatePool(NonPagedPool,
      sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
      
      if(urb == NULL)
      {      
            DbgPrint(("Failed to alloc mem for urb\n"));
            
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            
            ExFreePool(rwContext);
            IoFreeMdl(mdl);
            
            goto Ezusb_read_write_exit;
      }
      
      UsbBuildInterruptOrBulkTransferRequest(
                                              urb,
                                              sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                                              pipeInformation->PipeHandle,
                                              NULL,
                                              mdl,
                                              stageLength,
                                              urbFlags,
                                              NULL);
      
      //
      // set BULKUSB_RW_CONTEXT parameters.
      //
      
      rwContext->Urb = urb;
      rwContext->Mdl = mdl;
      rwContext->Length = totalLength - stageLength;
      rwContext->Numxfer = 0;
      rwContext->VirtualAddress = virtualAddress + stageLength;
      rwContext->DeviceExtension = deviceExtension;
      
      //
      // use the original read/write irp as an internal device control irp
      //
          
      nextStack = IoGetNextIrpStackLocation(Irp);
      nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
      nextStack->Parameters.Others.Argument1 = (PVOID) urb;
      nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;

      IoSetCompletionRoutine(Irp,
                            (PIO_COMPLETION_ROUTINE)Ezusb_ReadCompletion,
                            rwContext,
                            TRUE,
                            TRUE,
                            TRUE);
                              
      //
      // since we return STATUS_PENDING call IoMarkIrpPending.
      // This is the boiler plate code.
      // This may cause extra overhead of an APC for the Irp completion
      // but this is the correct thing to do.
      //
      
      IoMarkIrpPending(Irp);
      DbgPrint(("BulkUsb_DispatchReadWrite\n"));
      // to cancel this lock, other increment to much!
      //LockDevice(DeviceObject);
      
      ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,Irp);      
      if(!NT_SUCCESS(ntStatus))
      {      
            DbgPrint(("IoCallDriver fails with status %X\n", ntStatus));
            
            //
            // if the device was yanked out, then the pipeInformation
            // field is invalid.
            // similarly if the request was cancelled, then we need not
            // invoked reset pipe/device.
            //
            if((ntStatus != STATUS_CANCELLED) &&
            (ntStatus != STATUS_DEVICE_NOT_CONNECTED))
            {            
                  ntStatus = Ezusb_ResetPipe(DeviceObject, 0);            
            }
      }
      
      //
      // we return STATUS_PENDING and not the status returned by the lower layer.
      //
      return STATUS_PENDING;
      
      Ezusb_read_write_exit:
      
      Irp->IoStatus.Status = ntStatus;
      Irp->IoStatus.Information = 0;
      
      IoCompleteRequest(Irp, IO_NO_INCREMENT);
      
      DbgPrint(("BulkUsb_DispatchReadWrite - ends\n"));
      
      return ntStatus;
      
///////////////////
}
//-----------------------------------------------------------
//---------------------Ezusb_ReadCompletion-------------------
//-----------------------------------------------------------
NTSTATUS
Ezusb_ReadCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++

Routine Description:

This is the completion routine for reads/writes
If the irp completes with success, we check if we
need to recirculate this irp for another stage of
transfer. In this case return STATUS_MORE_PROCESSING_REQUIRED.
if the irp completes in error, free all memory allocs and
return the status.

Arguments:

DeviceObject - pointer to device object
Irp - I/O request packet
Context - context passed to the completion routine.

Return Value:

NT status value

--*/
{
    ULONG stageLength;
    NTSTATUS ntStatus;
    PIO_STACK_LOCATION nextStack;
    PBULKUSB_RW_CONTEXT rwContext;
    
    //
    // initialize variables
    //
    rwContext = (PBULKUSB_RW_CONTEXT) Context;
    ntStatus = Irp->IoStatus.Status;
    
    UNREFERENCED_PARAMETER(DeviceObject);
    Ezusb_KdPrint(("BulkUsb_ReadWriteCompletion - begins\n"));
    
    //
    // successfully performed a stageLength of transfer.
    // check if we need to recirculate the irp.
    //
    if(NT_SUCCESS(ntStatus))
    {    
            if(rwContext)
            {            
                  rwContext->Numxfer +=
                  rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
                  
                  if(rwContext->Length)
                    {                  
                          //
                          // another stage transfer
                          //
                          Ezusb_KdPrint(("Another stage transfer...\n"));
                          
                          if(rwContext->Length > BULKUSB_MAX_TRANSFER_SIZE)
                          {
                          
                                  stageLength = BULKUSB_MAX_TRANSFER_SIZE;
                          }
                          else
                          {                          
                                  stageLength = rwContext->Length;
                          }
                          
                          IoBuildPartialMdl(Irp->MdlAddress,
                                            rwContext->Mdl,
                                            (PVOID) rwContext->VirtualAddress,
                                            stageLength);
                          
                          //
                          // reinitialize the urb
                          //
                          rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength
                          = stageLength;
                          rwContext->VirtualAddress += stageLength;
                          rwContext->Length -= stageLength;
                          
                          nextStack = IoGetNextIrpStackLocation(Irp);
                          nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
                          nextStack->Parameters.Others.Argument1 = rwContext->Urb;
                          nextStack->Parameters.DeviceIoControl.IoControlCode =
                          IOCTL_INTERNAL_USB_SUBMIT_URB;
                          
                          IoSetCompletionRoutine(Irp,
                                                 Ezusb_ReadCompletion,
                                                 rwContext,
                                                 TRUE,
                                                 TRUE,
                                                 TRUE);
                          
                          IoCallDriver(rwContext->DeviceExtension->StackDeviceObject, Irp);
                          
                          return STATUS_MORE_PROCESSING_REQUIRED;
                    }
                  else
                  {                          
                            //
                            // this is the last transfer
                            //
                            UnlockDevice(DeviceObject);
                            Irp->IoStatus.Information = rwContext->Numxfer;
                            //IoCompleteRequest(Irp, IO_NO_INCREMENT);
                  }
            }
    }
    else
    {
    
          Ezusb_KdPrint(("ReadWriteCompletion - failed with status = %X\n", ntStatus));
    }
    
    if(rwContext)
    {    
          //
          // dump rwContext
          //
          Ezusb_KdPrint(("rwContext->Urb = %X\n",
          rwContext->Urb));
          Ezusb_KdPrint(("rwContext->Mdl = %X\n",
          rwContext->Mdl));
          Ezusb_KdPrint(("rwContext->Length = %d\n",
          rwContext->Length));
          Ezusb_KdPrint(("rwContext->Numxfer = %d\n",
          rwContext->Numxfer));
          Ezusb_KdPrint(("rwContext->VirtualAddress = %X\n",
          rwContext->VirtualAddress));
          Ezusb_KdPrint(("rwContext->DeviceExtension = %X\n",
          rwContext->DeviceExtension));
          
          Ezusb_KdPrint(("BulkUsb_ReadWriteCompletion::"));
          //LockDevice(DeviceObject);
          
          ExFreePool(rwContext->Urb);
          IoFreeMdl(rwContext->Mdl);
          ExFreePool(rwContext);
    }
    
    Ezusb_KdPrint(("BulkUsb_ReadWriteCompletion - ends\n"));
    
    return ntStatus;
}
        
注:原作者说“以上这些代码当时是在jinghuiren兄指导下调通的”,为何我一运行就不行啊?
jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-06-21 11:13
怎么不行?问题在哪?其实你就把XP版本的DDK的例子BULKUSB的那几个函数移植过去就行了。
helloxieyu
驱动牛犊
驱动牛犊
  • 注册日期2005-04-10
  • 最后登录2011-05-25
  • 粉丝0
  • 关注0
  • 积分820分
  • 威望83点
  • 贡献值0点
  • 好评度83点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-06-21 14:24
jinghuiren兄:
驱动一执行读写操作就蓝屏,提示:
    KMODE_EXCEPTION_NOT_HANDLED
         ***Address 80531D0F base at 804B5000,DateStamp 3ee6c002-ntoskrnl.exe

或者提示: MULTIPLE_IRP_COMPLETE_REQUESTS

还有,我是在Windows2000上编译并运行的!
helloxieyu
驱动牛犊
驱动牛犊
  • 注册日期2005-04-10
  • 最后登录2011-05-25
  • 粉丝0
  • 关注0
  • 积分820分
  • 威望83点
  • 贡献值0点
  • 好评度83点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-06-22 07:22
不要沉啊!顶一顶。
jinghuiren
驱动巨牛
驱动巨牛
  • 注册日期2002-06-01
  • 最后登录2008-10-27
  • 粉丝0
  • 关注0
  • 积分291分
  • 威望460点
  • 贡献值0点
  • 好评度428点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2007-06-23 09:49
给你贴个bulkusb的源代码,你比较一下吧
附件名称/大小 下载次数 最后更新
bulkusb.rar (66KB)  74 2007-06-23 09:49
cadet1997
驱动牛犊
驱动牛犊
  • 注册日期2008-07-14
  • 最后登录2009-04-27
  • 粉丝0
  • 关注0
  • 积分15分
  • 威望132点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2009-03-20 10:01
请教下楼主最后改成功了吗
cadet1997
驱动牛犊
驱动牛犊
  • 注册日期2008-07-14
  • 最后登录2009-04-27
  • 粉丝0
  • 关注0
  • 积分15分
  • 威望132点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2009-03-24 00:01
有没有修改成功的TX,能不能共享下源代码啊,学习下怎样修改的  
sweep7758
驱动牛犊
驱动牛犊
  • 注册日期2007-12-05
  • 最后登录2013-06-03
  • 粉丝1
  • 关注0
  • 积分50分
  • 威望560点
  • 贡献值1点
  • 好评度13点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2009-03-30 10:41
顶……………………
cczlp
驱动小牛
驱动小牛
  • 注册日期2002-11-04
  • 最后登录2014-03-25
  • 粉丝0
  • 关注0
  • 积分15分
  • 威望154点
  • 贡献值0点
  • 好评度59点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2009-04-07 15:18
我这也蓝屏,出现DRIVER_IRQ_NOT_LESS_OR_EQUAL
yukun840101
驱动牛犊
驱动牛犊
  • 注册日期2009-07-29
  • 最后登录2016-05-23
  • 粉丝2
  • 关注2
  • 积分23分
  • 威望251点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2009-12-17 15:57
上位机是不是也要改啊?哪儿能找到例子啊?
xzyee
驱动牛犊
驱动牛犊
  • 注册日期2005-08-08
  • 最后登录2010-07-01
  • 粉丝0
  • 关注0
  • 积分48分
  • 威望185点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2010-02-19 01:39
从给出的代码上看,没看出什么不对:
1、把UnlockDevice(DeviceObject);这句话注释掉看看。
2、完成函数应当放在nonpaged memory中。似乎应当在NTSTATUS  Ezusb_ReadCompletion(...)前面加上#pragma LOCKEDCODE,同时在其后面加上#pragma PAGEDCODE,出现DRIVER_IRQ_NOT_LESS_OR_EQUAL错误有一个名字上很难判断的原因就是应当放在nonpaged memory中的函数被放在paged memory中,当碰巧完成函数在高IRQL级别上执行时,却页面内容不在那里,找不到到内存,但是他不说你放错了内存,而是出现DRIVER_IRQ_NOT_LESS_OR_EQUAL错误。因此可以猜测,这个蓝屏和同步改异步有很大的关系,因为同步调用的话,你完成函数工作在原来的线程里,而你改为异步后,完成函数不在原来线程里,在任意线程里面,这个任意线程可能碰巧IRQL级别比较高,所以有时候你就蓝屏了。
3、对于很大传输来说,这段代码缺乏对Cancellation的支持,因为用户传输大文件,随时可能取消IRP,但是取消IRP和完成IRP存在潜在的冲突,这个在《Programming the Microsoft Windows Driver Model(2nd)》书里第12章有详细描述,该章节也有这样的例子,楼主可参考其例子。
4、出现MULTIPLE_IRP_COMPLETE_REQUESTS错误的原因可能在下面这段话里面:
     Ezusb_read_write_exit:
      Irp->IoStatus.Status = ntStatus;
      Irp->IoStatus.Information = 0;
      IoCompleteRequest(Irp, IO_NO_INCREMENT);
      DbgPrint(("BulkUsb_DispatchReadWrite - ends\n"));
      return ntStatus;
      
原因是:非正常退出时,调用IoCompleteRequest(Irp, IO_NO_INCREMENT)来完成IRP,但是Ezusb_Read_Write函数最后又return ntStatus.大概Ezusb_Read_Write函数要被某个dispather函数调用,最后因为不是返回STATUS_PENDING,I/O Manager就会再次完成IRP,造成重复完成一个IRP.

以上意见纯属按图索骥,书上点兵,仅作参考。
游客

返回顶部