阅读:2206回复:2
请各位帮忙,多谢了。
RY斑竹以及各位大虾:
在前面的帖子里我提到过BULK传输时在一些错误的情况下会永远不结束,不能继续对设备操作,有几位都说弄个超时退出,我对wdm一窍不通,只好依葫芦画瓢,如下面所示,但结果更糟糕,一旦插上设备就蓝屏重启。 源程序是 cypress ezusb development board 的原装驱动程序,没有作其他的任何改动,为什么会死机呢?请指点。 各位想写驱动的朋友,如果只写bulk传输,也可以看看,这是最主要的部分,除了容错能力差了点,这个驱动倒没有什么不好的地方。 // Copyright (C) Cypress 2000 Rev // File: ezusbsys.c // $Archive: /USB/Drivers/ezusbdrv/ezusbsys.c $ // // Purpose: // General purpose USB device driver // // $Author: Mdn $ NTSTATUS Ezusb_CallUSBD( IN PDEVICE_OBJECT fdo, IN PURB Urb ) /*++ Routine Description: Passes a Usb Request Block (URB) to the USB class driver (USBD) Note that we create our own IRP here and use it to send the request to the USB software subsystem. This means that this routine is essentially independent of the IRP that caused this driver to be called in the first place. The IRP for this transfer is created, used, and then destroyed in this routine. However, note that this routine uses the Usb Request Block (urb) passed in by the caller as the request block for the USB software stack. Implementation of this routine may be changed depending on the specific requirements of your driver. For example, while this routine issues a synchronous request to the USB stack, you may wish to implement this as an asynchronous request in which you set an IoCompletionRoutine to be called when the request is complete. Arguments: fdo - pointer to the device object for this instance of an Ezusb Device Urb - pointer to Urb request block Return Value: STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise --*/ { NTSTATUS ntStatus, status = STATUS_SUCCESS; PDEVICE_EXTENSION pdx; PIRP irp; KEVENT event; IO_STATUS_BLOCK ioStatus; PIO_STACK_LOCATION nextStack; Ezusb_KdPrint (("enter Ezusb_CallUSBD\n")); pdx = fdo->DeviceExtension; // issue a synchronous request (see notes above) KeInitializeEvent(&event, NotificationEvent, FALSE); irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_SUBMIT_URB, pdx->StackDeviceObject, NULL, 0, NULL, 0, TRUE, /* INTERNAL */ &event, &ioStatus); // Prepare for calling the USB driver stack nextStack = IoGetNextIrpStackLocation(irp); ASSERT(nextStack != NULL); // Set up the URB ptr to pass to the USB driver stack nextStack->Parameters.Others.Argument1 = Urb; Ezusb_KdPrint (("Calling USB Driver Stack\n")); // // Call the USB class driver to perform the operation. If the returned status // is PENDING, wait for the request to complete. // ntStatus = IoCallDriver(pdx->StackDeviceObject, irp); Ezusb_KdPrint (("return from IoCallDriver USBD %x\n", ntStatus)); if (ntStatus == STATUS_PENDING) { Ezusb_KdPrint (("Wait for single object\n")); /* 原来的代码 status = KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL); */ //************************************************ //下面几句代替上面的注释部分,改变了最后一个参数 LARGE_INTEGER Timeout; Timeout.QuadPart=30*1000000; //3seconds,units of 100 nanoseconds status = KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, &Timeout); //// 3s 超时 //************************************************ Ezusb_KdPrint (("Wait for single object, returned %x\n", status)); } else { ioStatus.Status = ntStatus; } Ezusb_KdPrint (("URB status = %x status = %x irp status %x\n", Urb->UrbHeader.Status, status, ioStatus.Status)); // // USBD maps the error code for us. USBD uses error codes in its URB // structure that are more insightful into USB behavior. In order to // match the NT Status codes, USBD maps its error codes into more general NT // error categories so higher level drivers can decipher the error codes // based on standard NT error code definitions. // ntStatus = ioStatus.Status; // // If the URB status was not USBD_STATUS_SUCCESS, we save a copy of the // URB status in the device extension. After a failure, another IOCTL, // IOCTL_EZUSB_GET_LAST_ERROR can be used to retrieve the URB status // for the most recently failed URB. Of course, this status gets // overwritten by subsequent failures, but it's better than nothing. // if (!(USBD_SUCCESS(Urb->UrbHeader.Status))) pdx->LastFailedUrbStatus = Urb->UrbHeader.Status; // // if ioStatus.Status indicates an error (ie. the IRP failed) then return that. // If ioStatus.Status indicates success, it is still possible that what we were // trying to do failed. For example, if the IRP is cancelled, the status returned // by the I/O manager for the IRP will not indicate an error. In that case, we // should check the URB status. If it indicates anything other than // USBD_SUCCESS, then we should return STATUS_UNSUCCESSFUL. // if (NT_SUCCESS(ntStatus)) { if (!(USBD_SUCCESS(Urb->UrbHeader.Status))) ntStatus = STATUS_UNSUCCESSFUL; } Ezusb_KdPrint(("exit Ezusb_CallUSBD (%x)\n", ntStatus)); return ntStatus; } //上面函数的调用处 NTSTATUS Ezusb_Read_Write( IN PDEVICE_OBJECT fdo, 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 --*/ { PDEVICE_EXTENSION pdx = fdo->DeviceExtension; NTSTATUS ntStatus; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp); PBULK_TRANSFER_CONTROL bulkControl = (PBULK_TRANSFER_CONTROL)Irp->AssociatedIrp.SystemBuffer; ULONG bufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; PURB urb = NULL; ULONG urbSize = 0; ULONG transferFlags = 0; PUSBD_INTERFACE_INFORMATION interfaceInfo = NULL; PUSBD_PIPE_INFORMATION pipeInfo = NULL; USBD_PIPE_HANDLE pipeHandle = NULL; Ezusb_KdPrint(("enter Ezusb_Read_Write()\n")); // // verify that the selected pipe is valid, and get a handle to it. If anything // is wrong, return an error // interfaceInfo = pdx->Interface; if (!interfaceInfo) { Ezusb_KdPrint(("Ezusb_Read_Write() no interface info - Exiting\n")); return STATUS_UNSUCCESSFUL; } if (bulkControl->pipeNum > interfaceInfo->NumberOfPipes) { Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n")); return STATUS_INVALID_PARAMETER; } pipeInfo = &(interfaceInfo->Pipes[bulkControl->pipeNum]); if (!((pipeInfo->PipeType == UsbdPipeTypeBulk) || (pipeInfo->PipeType == UsbdPipeTypeInterrupt))) { Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n")); return STATUS_INVALID_PARAMETER; } pipeHandle = pipeInfo->PipeHandle; if (!pipeHandle) { Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n")); return STATUS_UNSUCCESSFUL; } if (bufferLength > pipeInfo->MaximumTransferSize) { Ezusb_KdPrint(("Ezusb_Read_Write() invalid transfer size - Exiting\n")); return STATUS_INVALID_PARAMETER; } // // allocate and fill in the Usb request (URB) // urbSize = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER); urb = ExAllocatePool(NonPagedPool,urbSize); if (!urb) { Ezusb_KdPrint(("Ezusb_Read_Write() unable to alloc URB - Exiting\n")); return STATUS_NO_MEMORY; } transferFlags = USBD_SHORT_TRANSFER_OK; // // get direction info from the endpoint address // if (USB_ENDPOINT_DIRECTION_IN(pipeInfo->EndpointAddress)) transferFlags |= USBD_TRANSFER_DIRECTION_IN; UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb (USHORT) urbSize, //size of urb pipeHandle, //usbd pipe handle NULL, //TransferBuffer Irp->MdlAddress, //mdl bufferLength, //bufferlength transferFlags, //flags NULL); //link // // Call the USB Stack. //!!!!!!!!!!!!!!!!!!!!!!!!! ntStatus = Ezusb_CallUSBD(fdo, urb); //!!!!!!!!!!!!!!!!!!!!!!!!! // // If the transfer was successful, report the length of the transfer to the // caller by setting IoStatus.Information // if (NT_SUCCESS(ntStatus)) { Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; Ezusb_KdPrint(("Successfully transfered 0x%x bytes\n",Irp->IoStatus.Information)); } // // free the URB // ExFreePool(urb); return ntStatus; } [sunkai 编辑于 2001-10-03 17:32] |
|
最新喜欢:![]() |
沙发#
发布于:2001-10-09 11:12
我认为你不能只是简单的作一个超时。因为你的代码如果不等到lower device返回而因为超时而返回的话,lower device在返回那个irp的时候会出错了:因为这个irp已经没有了。
我记得DW是自己做了很多工作来实现这个超时的。你可以参考一下它的代码。 |
|
|
板凳#
发布于:2001-10-10 00:33
呵呵,谢谢,你看得出源程序是C写的,现在要看C++的,要命。
|
|