guaiguaiguan
驱动中牛
驱动中牛
  • 注册日期2003-10-11
  • 最后登录2011-01-12
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望556点
  • 贡献值0点
  • 好评度490点
  • 原创分0分
  • 专家分0分
阅读:1576回复:2

如何解决uSB丢包的问题?

楼主#
更多 发布于:2008-09-27 17:12
开发一个USB项目,刚开始的时候着眼于应用层,双线程、环形队列缓冲区,结果仍然存在丢包的现象,在进程切换时比较明显。于是开始在驱动中做文章,参考了驱动开发网的一个帖子。尝试自己创建irp,发送urb请求,结果在调用IocallDriver函数时,出现指针错误,导致IocallDriver没有返回,直接bsod,下面的代码有问题吗?我怎么才能自己创建IRP发送urb请求。

NTSTATUS
My_BulkUsb_DispatchReadWrite(
    IN PDEVICE_OBJECT DeviceObject
)
{
         PMDL                   mdl;
    PURB                   urb;
    ULONG                  totalLength;
    ULONG                  stageLength;
    ULONG                  urbFlags;
    BOOLEAN                read;
    NTSTATUS               ntStatus;
    ULONG_PTR              virtualAddress;
    PFILE_OBJECT           fileObject;
    PDEVICE_EXTENSION      deviceExtension;
    PIO_STACK_LOCATION     irpStack;
    PIO_STACK_LOCATION     nextStack;
    PBULKUSB_RW_CONTEXT    rwContext;
    PUSBD_PIPE_INFORMATION pipeInformation;
         //IO_STATUS_BLOCK    ioStatus;
        PIRP               Irp;
    KEVENT             event;

        
        
    //
    // initialize variables
    //
    urb = NULL;
    mdl = NULL;
    rwContext = NULL;
    totalLength = 0;
    deviceExtension = DeviceObject->DeviceExtension;
    //KeInitializeEvent(&event, NotificationEvent, FALSE);
    Irp = IoAllocateIrp(DeviceObject->StackSize+1,
                            FALSE);/* IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
                                           deviceExtension->TopOfStackDeviceObject,
                                           NULL,
                                           0,
                                           NULL,  
                                           0,
                                           TRUE,
                                           &event,
                                           &ioStatus);*/

         if(!Irp) {
    //如果IRP创建失败则返回
        BulkUsb_DbgPrint(1, ("IoBuildDeviceIoControlRequest failed\n"));
        return STATUS_INSUFFICIENT_RESOURCES;
      }
    irpStack = IoGetCurrentIrpStackLocation(Irp);
    if(!irpStack->FileObject)
    {
        irpStack->FileObject = deviceExtension->fileObject;
        fileObject = irpStack->FileObject;
    }
    else
        fileObject = irpStack->FileObject;
    read = TRUE ;
  

    BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite - begins\n"));

    if(deviceExtension->DeviceState != Working) {

        BulkUsb_DbgPrint(1, ("Invalid device state\n"));

        ntStatus = STATUS_INVALID_DEVICE_STATE;
        goto BulkUsb_DispatchReadWrite_Exit;
    }

    //
    // It is true that the client driver cancelled the selective suspend
    // request in the dispatch routine for create Irps.
    // But there is no guarantee that it has indeed completed.
    // so wait on the NoIdleReqPendEvent and proceed only if this event
    // is signalled.
    //
    BulkUsb_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n"));
    
    //
    // make sure that the selective suspend request has been completed.
    //

    if(deviceExtension->SSEnable) {

        KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
                              Executive,
                              KernelMode,
                              FALSE,
                              NULL);
    }

    if(fileObject && fileObject->FsContext) {

        pipeInformation = fileObject->FsContext;

        if((UsbdPipeTypeBulk != pipeInformation->PipeType) &&
           (UsbdPipeTypeInterrupt != pipeInformation->PipeType)) {
            
            BulkUsb_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt\n"));

            ntStatus = STATUS_INVALID_HANDLE;
            goto BulkUsb_DispatchReadWrite_Exit;
        }
    }
    else {

        BulkUsb_DbgPrint(1, ("Invalid handle\n"));

        ntStatus = STATUS_INVALID_HANDLE;
        goto BulkUsb_DispatchReadWrite_Exit;
    }

    rwContext = (PBULKUSB_RW_CONTEXT)
                ExAllocatePool(NonPagedPool,
                               sizeof(BULKUSB_RW_CONTEXT));

    if(rwContext == NULL) {
        
        BulkUsb_DbgPrint(1, ("Failed to alloc mem for rwContext\n"));

        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        goto BulkUsb_DispatchReadWrite_Exit;
    }
        if(!Irp->MdlAddress)
        {
            Irp->MdlAddress = IoAllocateMdl((PVOID) cBuffer,
                        sizeof(cBuffer),
                        FALSE,
                        FALSE,
                        NULL);
      if(!Irp->MdlAddress)
      {
          BulkUsb_DbgPrint(1, ("Failed to alloc mem for Irp->MdlAddress\n"));

        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        goto BulkUsb_DispatchReadWrite_Exit;
        
      }
        }
    if(Irp->MdlAddress) {

        totalLength = MmGetMdlByteCount(Irp->MdlAddress);
    }

    if(totalLength > BULKUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE) {

        BulkUsb_DbgPrint(1, ("Transfer length > circular buffer\n"));

        ntStatus = STATUS_INVALID_PARAMETER;

        ExFreePool(rwContext);

        goto BulkUsb_DispatchReadWrite_Exit;
    }

    if(totalLength == 0) {

        BulkUsb_DbgPrint(1, ("Transfer data length = 0\n"));

        ntStatus = STATUS_SUCCESS;

        ExFreePool(rwContext);
                
                IoFreeMdl(Irp->MdlAddress);
        goto BulkUsb_DispatchReadWrite_Exit;
    }

    urbFlags = USBD_SHORT_TRANSFER_OK;
    virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);

    if(read) {

        urbFlags |= USBD_TRANSFER_DIRECTION_IN;
        BulkUsb_DbgPrint(3, ("Read operation\n"));
    }
    else {

        urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
        BulkUsb_DbgPrint(3, ("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) {
    
        BulkUsb_DbgPrint(1, ("Failed to alloc mem for mdl\n"));

        ntStatus = STATUS_INSUFFICIENT_RESOURCES;

        ExFreePool(rwContext);
                IoFreeMdl(Irp->MdlAddress);
        goto BulkUsb_DispatchReadWrite_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) {

        BulkUsb_DbgPrint(1, ("Failed to alloc mem for urb\n"));

        ntStatus = STATUS_INSUFFICIENT_RESOURCES;

        ExFreePool(rwContext);
        IoFreeMdl(mdl);
                IoFreeMdl(Irp->MdlAddress);
        goto BulkUsb_DispatchReadWrite_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;

        rwContext->IrpMDL = Irp->MdlAddress;
    //
    // 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)BulkUsb_ReadWriteCompletion,
                           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);

    BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite::"));
    BulkUsb_IoIncrement(deviceExtension);

    ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
                            Irp);

    if(!NT_SUCCESS(ntStatus)) {

        BulkUsb_DbgPrint(1, ("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 = BulkUsb_ResetPipe(DeviceObject,
                                     pipeInformation);
    
            if(!NT_SUCCESS(ntStatus)) {

                BulkUsb_DbgPrint(1, ("BulkUsb_ResetPipe failed\n"));

                ntStatus = BulkUsb_ResetDevice(DeviceObject);
            }
        }
        else {

            BulkUsb_DbgPrint(3, ("ntStatus is STATUS_CANCELLED or "
                                 "STATUS_DEVICE_NOT_CONNECTED\n"));
        }
    }
    /*
         KeInsertQueueDpc(
                                &deviceExtension->DeferredProcCallSendIRP,
                                (PVOID)1,
                                (PVOID)2
                                );
        */
    //
    // we return STATUS_PENDING and not the status returned by the lower layer.
    //
    return STATUS_PENDING;

BulkUsb_DispatchReadWrite_Exit:
#if 0
    Irp->IoStatus.Status = ntStatus;
    Irp->IoStatus.Information = 0;
#endif    
        IoFreeIrp(Irp);
    //IoCompleteRequest(Irp, IO_NO_INCREMENT);

    BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite - ends\n"));

    return ntStatus;
}
guaiguaiguan
驱动中牛
驱动中牛
  • 注册日期2003-10-11
  • 最后登录2011-01-12
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望556点
  • 贡献值0点
  • 好评度490点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2008-09-27 17:18
我的思路是在添加设备时,初始化一个DPC对象,设置DPC调用例程,通过定时器或者手工触发DPC过程调用,在这个调用中发送urb请求,这需要自己分配一个irp,具体初始化参数过程如上面代码所示。在发送这个URB请求时,设置IoSetCompletionRoutine完成例程。在例程中接收usb数据,并再调用KeInsertQueueDpc,再次触发DPC过程调用,以便继续读取uSB设备数据。
现在是每执行到IOCallDriver就死掉了。不知道上面的逻辑上是否行得通,代码有没有问题,高手帮俺想想办法?谁又更简单的实现代码,帮俺贴一段也可。
xgy893
驱动牛犊
驱动牛犊
  • 注册日期2007-07-15
  • 最后登录2008-12-04
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望20点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2008-09-28 19:13
刚刚入门啊,看不大懂
游客

返回顶部