阅读:1583回复:2
如何解决uSB丢包的问题?
开发一个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; } |
|
沙发#
发布于:2008-09-27 17:18
我的思路是在添加设备时,初始化一个DPC对象,设置DPC调用例程,通过定时器或者手工触发DPC过程调用,在这个调用中发送urb请求,这需要自己分配一个irp,具体初始化参数过程如上面代码所示。在发送这个URB请求时,设置IoSetCompletionRoutine完成例程。在例程中接收usb数据,并再调用KeInsertQueueDpc,再次触发DPC过程调用,以便继续读取uSB设备数据。
现在是每执行到IOCallDriver就死掉了。不知道上面的逻辑上是否行得通,代码有没有问题,高手帮俺想想办法?谁又更简单的实现代码,帮俺贴一段也可。 |
|
板凳#
发布于:2008-09-28 19:13
刚刚入门啊,看不大懂
|
|