阅读:3013回复:10
--------把ezusb改为异步驱动,请大侠们指点!---------
好不容易在网上找到一段把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兄指导下调通的”,为何我一运行就不行啊? |
|
沙发#
发布于:2007-06-21 11:13
怎么不行?问题在哪?其实你就把XP版本的DDK的例子BULKUSB的那几个函数移植过去就行了。
|
|
板凳#
发布于:2007-06-21 14:24
jinghuiren兄:
驱动一执行读写操作就蓝屏,提示: KMODE_EXCEPTION_NOT_HANDLED ***Address 80531D0F base at 804B5000,DateStamp 3ee6c002-ntoskrnl.exe 或者提示: MULTIPLE_IRP_COMPLETE_REQUESTS 还有,我是在Windows2000上编译并运行的! |
|
地板#
发布于:2007-06-22 07:22
不要沉啊!顶一顶。
|
|
地下室#
发布于:2007-06-23 09:49
给你贴个bulkusb的源代码,你比较一下吧
|
|
|
5楼#
发布于:2009-03-20 10:01
请教下楼主最后改成功了吗
|
|
6楼#
发布于:2009-03-24 00:01
有没有修改成功的TX,能不能共享下源代码啊,学习下怎样修改的
|
|
7楼#
发布于:2009-03-30 10:41
顶……………………
|
|
8楼#
发布于:2009-04-07 15:18
我这也蓝屏,出现DRIVER_IRQ_NOT_LESS_OR_EQUAL
|
|
9楼#
发布于:2009-12-17 15:57
上位机是不是也要改啊?哪儿能找到例子啊?
|
|
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. 以上意见纯属按图索骥,书上点兵,仅作参考。 |
|