阅读:1393回复:3
USB驱动程序造成关机不正常
我的USB设备可以正常工作,但是在关机时却无法正常关机,请各位大大帮忙看看。
环境是XP,USB驱动采用DS中的一个例子,等时传输的例子。 关机时,屏幕一直停留在“Windows正在关机...”,如果这时把USB拔掉,马上就可以正常关机了。 USB设备采用的是外部供电。 驱动程序源码如下:(其实就是DS的例子) #include <vdw.h> #include <kusb.h> #include "isochdev.h" #include "isocioct.h" extern KTrace Tracer; // Global driver trace object UsbIsocDevice::UsbIsocDevice(PDEVICE_OBJECT Pdo, ULONG Unit) : KPnpDevice( Pdo, KUnitizedName(L"UsbIsoc", Unit), FILE_DEVICE_UNKNOWN, KUnitizedName(L"UsbIsoc", Unit) ) { Tracer << "UsbIsocDevice::UsbIsocDevice() Entry\n"; m_pReadFifo = NULL; m_pReadContexts = NULL; m_readOverflow = 0; m_unitNum = Unit; m_Usb.Initialize(this, Pdo); // initialize the USB interface // initialize the USB interface m_Interface.Initialize( m_Usb, //KUsbLowerDevice 0, //Interface Number 1, //Configuration Value 0 //Initial Alternate Setting for the Interface ); // initialize description of data in pipe (In Bulk) m_Pipe0.Initialize( m_Usb, //KUsbLowerDevice 0x88 //Endpoint Address ); // initialize description of data out pipe (Out Bulk) m_Pipe1.Initialize( m_Usb, //KUsbLowerDevice 0x8 //Endpoint Address ); SetLowerDevice(&m_Usb); // inform PnP code of our Top-of-stack device SetPnpPolicy(); // use the default Pnp policy } UsbIsocDevice::~UsbIsocDevice() { Tracer << "UsbIsocDevice::~UsbIsocDevice() Entry\n"; DeleteAllReadContexts(); if ( m_pReadFifo ) { delete m_pReadFifo; m_pReadFifo = NULL; } } NTSTATUS UsbIsocDevice::DefaultPnp(KIrp I) { static char* minors[] = { "IRP_MN_START_DEVICE", "IRP_MN_QUERY_REMOVE_DEVICE", "IRP_MN_REMOVE_DEVICE", "IRP_MN_CANCEL_REMOVE_DEVICE", "IRP_MN_STOP_DEVICE", "IRP_MN_QUERY_STOP_DEVICE", "IRP_MN_CANCEL_STOP_DEVICE", "IRP_MN_QUERY_DEVICE_RELATIONS", "IRP_MN_QUERY_INTERFACE", "IRP_MN_QUERY_CAPABILITIES", "IRP_MN_QUERY_RESOURCES", "IRP_MN_QUERY_RESOURCE_REQUIREMENTS", "IRP_MN_QUERY_DEVICE_TEXT", "IRP_MN_FILTER_RESOURCE_REQUIREMENTS", "IRP_MN_undefined", "IRP_MN_READ_CONFIG", "IRP_MN_WRITE_CONFIG", "IRP_MN_EJECT", "IRP_MN_SET_LOCK", "IRP_MN_QUERY_ID", "IRP_MN_QUERY_PNP_DEVICE_STATE", "IRP_MN_QUERY_BUS_INFORMATION", "IRP_MN_DEVICE_USAGE_NOTIFICATION", "IRP_MN_SURPRISE_REMOVAL" }; ULONG Minor = I.MinorFunction(); CHAR* IrpName; if ( Minor < IRP_MN_SURPRISE_REMOVAL ) IrpName = minors[Minor]; else IrpName = "<unknown>"; DbgPrint("Pnp IRP minor function=%s\n", IrpName); I.ForceReuseOfCurrentStackLocationInCalldown(); return m_Usb.PnpCall(this, I); } NTSTATUS UsbIsocDevice::DefaultPower(KIrp I) { I.IndicatePowerIrpProcessed(); I.CopyParametersDown(); return m_Usb.PnpPowerCall(this, I); } NTSTATUS UsbIsocDevice::SystemControl(KIrp I) { I.ForceReuseOfCurrentStackLocationInCalldown(); return m_Usb.PnpCall(this, I); } NTSTATUS UsbIsocDevice::OnStartDevice(KIrp I) { NTSTATUS status = STATUS_UNSUCCESSFUL; AC_STATUS acStatus; Tracer << "UsbIsocDevice::OnStartDevice() Entry\n"; // The default Pnp policy has already cleared the IRP with the lower device // Now we initialize the device object acStatus = m_Usb.ActivateConfiguration(1); switch (acStatus) { case AC_SUCCESS: Tracer << "Configuration OK\n"; status = STATUS_SUCCESS; break; case AC_COULD_NOT_LOCATE_INTERFACE: Tracer << "Could not locate interface, endpoint address "; break; case AC_COULD_NOT_PRECONFIGURE_INTERFACE: Tracer << "Could not get configuration descriptor\n"; break; case AC_CONFIGURATION_REQUEST_FAILED: Tracer << "Board did not accept configuration URB\n"; break; case AC_FAILED_TO_INITIALIZE_INTERFACE_OBJECT: Tracer << "Failed to initialize interface for pipe[" ; break; case AC_FAILED_TO_LOCATE_ENDPOINT_ADDRESS: Tracer << "Failed to locate endpoint address for pipe[" ; break; } if ( !m_pReadFifo ) { m_pReadFifo = new (NonPagedPool) KLockableFifo<UCHAR>(ISOC_READ_FIFO_SIZE, NonPagedPool); if ( !m_pReadFifo ) { Tracer << "Allocation of Read FIFO failed!\n"; status = STATUS_INSUFFICIENT_RESOURCES; } } ASSERT( m_pReadFifo ); if ( NT_SUCCESS(status) ) status = StartIsocReads(); return status; // base class completes the IRP } NTSTATUS UsbIsocDevice::OnStopDevice(KIrp I) { Tracer << "UsbIsocDevice::OnStopDevice() Entry\n"; DeleteAllReadContexts(); if ( m_pReadFifo ) { delete m_pReadFifo; m_pReadFifo = NULL; } return m_Usb.Unconfigure(); // base class passes to lower device } NTSTATUS UsbIsocDevice::OnRemoveDevice(KIrp I) { Tracer << "UsbIsocDevice::OnRemoveDevice() Entry\n"; // Our PnP policy will take care of // (1) giving the IRP to USBD // (2) detaching the PDO // (3) deleting the device object return STATUS_SUCCESS; } NTSTATUS UsbIsocDevice::Create(KIrp I) { Tracer << "UsbIsocDevice::Create() Entry\n"; I.ForceReuseOfCurrentStackLocationInCalldown(); NTSTATUS status = m_Usb.PnpCall(this, I); Tracer << "UsbIsocDevice:Create Status " << (ULONG)status << "\n"; return status; } NTSTATUS UsbIsocDevice::Close(KIrp I) { Tracer << "UsbIsocDevice::Close() Entry\n"; I.ForceReuseOfCurrentStackLocationInCalldown(); NTSTATUS status = m_Usb.PnpCall(this, I); Tracer << "UsbIsocDevice:Close Status " << (ULONG)status << "\n"; return status; } NTSTATUS UsbIsocDevice::InternalDeviceControl(KIrp I) { Tracer << "UsbIsocDevice::InternalDeviceControl() Entry\n"; I.ForceReuseOfCurrentStackLocationInCalldown(); NTSTATUS status = m_Usb.PnpCall(this, I); Tracer << "UsbIsocDevice::InternalDeviceControl Status " << (ULONG)status << "\n"; return status; } NTSTATUS UsbIsocDevice::DeviceControl(KIrp I) { Tracer << "UsbIsocDevice::DeviceControl() Entry\n"; NTSTATUS status = STATUS_SUCCESS; switch (I.IoctlCode()) { // Placeholder for real IOCTL calls case ISOC_FIRST_IOCTL: return I.PnpComplete(this, STATUS_SUCCESS); default: Tracer << "UNKNOWN [ID=" << I.IoctlCode() << "] );\n"; I.Information() = 0; return I.PnpComplete(this, STATUS_INVALID_PARAMETER); } } VOID UsbIsocDevice::DeleteAllReadContexts() { while ( m_pReadContexts ) { PISOC_CONTEXT pContext = m_pReadContexts; m_pReadContexts = pContext->pNext; ASSERT( !pContext->bUsed ); if ( !pContext->bUsed ) { if ( pContext->pIrp ) delete pContext->pIrp; if ( pContext->pUrb ) delete pContext->pUrb; if ( pContext->pData ) delete pContext->pData; delete pContext; } } } // iread.cpp - read operation for USB Isoc Sample Driver //============================================================================= // // Compuware Corporation // NuMega Lab // 9 Townsend West // Nashua, NH 03060 USA // // Copyright (c) 1998 Compuware Corporation. All Rights Reserved. // Unpublished - rights reserved under the Copyright laws of the // United States. // //============================================================================= #include <vdw.h> #include <kusb.h> #include "isochdev.h" #include "isocioct.h" extern KTrace Tracer; // Global driver trace object //////////////////////////////////////////////////////////////////////////////// // Default handler for IRP_MJ_READ - Using USB Isoc Pipe // // This routine is the default handler for IRP_MJ_READ. // Incoming IRPs read from a FIFO, filled by constantly // running Isoc URBs. When FIFO fills, it is emptied // enough to put the new data into it! // // The KPnpDevice class handles restricting IRP flow // if the device is stopping or being removed. // NTSTATUS UsbIsocDevice::Read(KIrp I) { NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; Tracer << "UsbIsocDevice::Read() Entry\n"; PUCHAR pBuffer = (PUCHAR)I.BufferedReadDest(); ULONG dwTotalSize = I.ReadSize(CURRENT); ULONG dwBytesRead = 0; if ( !m_pReadFifo ) { I.Information() = 0; I.PnpComplete(this, STATUS_UNSUCCESSFUL, IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; } // Get all data waiting in m_pReadFifo status = STATUS_SUCCESS; m_pReadFifo->Lock(); if ( m_pReadFifo->NumberOfItemsAvailableForRead() == 0 ) { m_pReadFifo->Unlock(); I.Information() = 0; I.PnpComplete(this, status, IO_NO_INCREMENT); return status; } dwBytesRead = m_pReadFifo->Read(pBuffer, dwTotalSize); m_pReadFifo->Unlock(); if ( dwBytesRead != dwTotalSize ) { Tracer << "Read FIFO Read of " << dwBytesRead << "/" << dwTotalSize << " Bytes\n"; } else { Tracer << "Read FIFO Read of " << dwBytesRead << " Bytes\n"; } I.Information() = dwBytesRead; I.PnpComplete(this, status, IO_NO_INCREMENT); return status; } //////////////////////////////////////////////////////////////////////////////// // Starts a single ISOC read - allocating structures and submitting URB // NTSTATUS UsbIsocDevice::StartIsocReads() { NTSTATUS status; for (int i=0; i<ISOC_NUM_READ_URBS; i++) { UCHAR *p = new (NonPagedPool) UCHAR[ISOC_URB_DATA_SIZE]; ASSERT(p); if ( !p ) break; PURB pUrb = m_Pipe0.BuildIsochronousTransfer( ISOC_NUM_PACKETS_PER_URB, // # packets ISOC_PACKET_SIZE, // packet size TRUE, // bIn TRUE, // bASAP USBD_ISO_START_FRAME_RANGE,// Start Frame p, // pBuffer ISOC_URB_DATA_SIZE // Length ); ASSERT(pUrb); if ( !pUrb ) { delete p; break; } // Do not get an error on short or zero length packets pUrb->UrbIsochronousTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; PISOC_CONTEXT pContext = new (NonPagedPool) ISOC_CONTEXT; ASSERT(pContext); if ( !pContext ) { delete pUrb; delete p; break; } // Create the accompanying IRP once, since the kernel // does not like us deleting and allocating IRPs // on every completion routine. CCHAR stackSize = m_Usb.StackRequirement() + 1; PIRP pIrp = IoAllocateIrp(stackSize, FALSE); pContext->pNext = m_pReadContexts; pContext->bUsed = TRUE; pContext->pDev = this; pContext->pIrp = pIrp; pContext->pUrb = pUrb; pContext->pData = p; pContext->pMdl = NULL; m_pReadContexts = pContext; IncrementOutstandingRequestCount(); status = QueueIsocRead(pContext); if ( !NT_SUCCESS(status) ) break; } if ( i != ISOC_NUM_READ_URBS ) { Tracer << "StartReads() allocation FAILURE!\n"; return STATUS_INSUFFICIENT_RESOURCES; } return STATUS_SUCCESS; } NTSTATUS UsbIsocDevice::QueueIsocRead(PISOC_CONTEXT pContext) { NTSTATUS status; _URB_HEADER *pUHdr = (_URB_HEADER *)pContext->pUrb; _URB_ISOCH_TRANSFER *pIsoc = &pContext->pUrb->UrbIsochronousTransfer; pUHdr->UsbdDeviceHandle = NULL; pUHdr->UsbdFlags = 0; pIsoc->TransferBufferLength = ISOC_URB_DATA_SIZE; pIsoc->TransferBufferMDL = NULL; pIsoc->StartFrame = 0; memset(&pIsoc->hca, 0, sizeof(_URB_HCD_AREA)); status = m_Pipe0.SubmitUrb( pContext->pIrp, pContext->pUrb, LinkTo(UsbIsocReadComplete), pContext ); if ( !NT_SUCCESS(status) ) { Tracer << "Submission of Isoc Read URB FAILED (status=" << (ULONG)status << ")!\n"; } return status; } NTSTATUS UsbIsocDevice::UsbIsocReadComplete(KIrp I, PISOC_CONTEXT pContext) { NTSTATUS status; if ( m_State.m_StopPending || m_State.m_RemovePending || m_State.m_Removed || m_State.m_SurpriseRemoval ) { // Do not re-submit this URB pContext->bUsed = FALSE; DecrementOutstandingRequestCount(); return STATUS_MORE_PROCESSING_REQUIRED; } if ( !NT_SUCCESS(I.Status()) ) { // URB submission FAILED! Tracer << "Isoc Read IRP FAILED (status="<< (ULONG)I.Status() << ")!\n"; pContext->bUsed = FALSE; DecrementOutstandingRequestCount(); return STATUS_MORE_PROCESSING_REQUIRED; } // If we have nowhere to put its data, just re-cycle this buffer. if ( !m_pReadFifo ) { status = QueueIsocRead(pContext); return STATUS_MORE_PROCESSING_REQUIRED; } _URB_ISOCH_TRANSFER *pIsoc = &pContext->pUrb->UrbIsochronousTransfer; PUSBD_ISO_PACKET_DESCRIPTOR ppd; UCHAR temp[ISOC_PACKET_SIZE]; BOOLEAN bOverflow = FALSE; ULONG dwDataCount = 0; // Take data from URB completion, and copy it into our FIFO // If our FIFO fills up, then clear out enough for the new data! for (int i=0; i<ISOC_NUM_PACKETS_PER_URB; i++) { ppd = &pIsoc->IsoPacket; // We ignore zero length packets in the data stream for now. // You might want to have a zero length packet signal the // end of a large block of data. If so, then you need to // handle a zero length packet arriving at any time! if ( USBD_SUCCESS(ppd->Status) && (ppd->Length > 0) ) { PUCHAR p = ((UCHAR *)pIsoc->TransferBuffer) + ppd->Offset; m_pReadFifo->Lock(); if ( ISOC_PACKET_SIZE > m_pReadFifo->NumberOfItemsAvailableForWrite() ) { bOverflow = TRUE; // Discard oldest data from the Read FIFO m_pReadFifo->Read(temp, ppd->Length); } m_pReadFifo->Write(p, ppd->Length); m_pReadFifo->Unlock(); dwDataCount += ppd->Length; } } if ( bOverflow ) { Tracer << "Read FIFO overflow!\n"; m_readOverflow++; } if ( (dwDataCount > 0)) Tracer << "Isoc Read received " << dwDataCount << " bytes\n"; // Resubmit this URB. status = QueueIsocRead(pContext); return STATUS_MORE_PROCESSING_REQUIRED; } // iwrite.cpp - device class implementation for USB Isoc Sample Driver //============================================================================= // // Compuware Corporation // NuMega Lab // 9 Townsend West // Nashua, NH 03060 USA // // Copyright (c) 1998 Compuware Corporation. All Rights Reserved. // Unpublished - rights reserved under the Copyright laws of the // United States. // //============================================================================= #include <vdw.h> #include <kusb.h> #include "isochdev.h" #include "isocioct.h" extern KTrace Tracer; // Global driver trace object //////////////////////////////////////////////////////////////////////////////// // Default handler for IRP_MJ_WRITE - Using USB Isoc Pipe // // This routine is the default handler for IRP_MJ_WRITE. // Incoming IRPs just send data down to the USB device, synchronously. // // The KPnpDevice class handles restricting IRP flow // if the device is stopping or being removed. // // The application doing these writes MUST limit the amount of // data being written to ISOC_NUM_PACKETS_PER_URB * ISOC_PACKET_SIZE, // or 2048 bytes - to be compatible with all Host Controller drivers // in Win95 and Win98. // // If you want to write more data at once, consider creating multiple // URBs and IRPs that would span the entire data block you wish to // write. Care must be taken that the original IRP is not completed // until all of the URBs are done. // NTSTATUS UsbIsocDevice::Write(KIrp I) { NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; I.Information() = 0; Tracer << "UsbIsocDevice::Write() Entry\n"; // Send down a Pipe Reset. // // Since these writes are queued from Ring 3, assume // that the previous write has finished, and the // pipe did not have more data queued up to it in time! m_Pipe1.Reset(); PVOID pBuffer = I.BufferedWriteSource(); ULONG dwTotalSize = I.WriteSize(CURRENT); ULONG dwBytesSent = 0; // Create an URB to do actual Bulk read from Pipe0 KMemory *pMdl = new (NonPagedPool) KMemory(pBuffer, dwTotalSize); if ( !pMdl ) { ASSERT( pMdl != 0 ); return I.PnpComplete(STATUS_INSUFFICIENT_RESOURCES, IO_NO_INCREMENT); } pMdl->SetPageArray(); // tells system to set phys page addrs inside MDL PISOC_CONTEXT pContext = new (NonPagedPool) ISOC_CONTEXT; if ( !pContext ) { ASSERT ( pContext != 0 ); delete pMdl; return I.PnpComplete(STATUS_INSUFFICIENT_RESOURCES, IO_NO_INCREMENT); } memset(pContext, 0, sizeof(ISOC_CONTEXT)); // NOTE: This assumes you are passing a total size that is // an even multiple of the hard-coded packet size (now // 64), is 2048 bytes or less. Packet size is hardware // dependent. // // If USBD gets a "short" packet for transfer, your // pipe will be shut down. // ULONG numPackets = dwTotalSize / ISOC_PACKET_SIZE; if ( (numPackets * ISOC_PACKET_SIZE) != dwTotalSize ) numPackets++; ASSERT( numPackets <= ISOC_NUM_PACKETS_PER_URB ); PURB pUrb = m_Pipe1.BuildIsochronousTransfer( numPackets, // # of Packets ISOC_PACKET_SIZE, // Packet Size FALSE, // Output, not in TRUE, // send ASAP 0, // Start frame (unused if ASAP) pMdl, dwTotalSize ); // Submit the URB to our USB device, asynchronously if ( pUrb != 0 ) { // Fill in the USBD_ISO_PACKET_DESCRIPTORs for (ULONG i=0; i<numPackets; i++) pUrb->UrbIsochronousTransfer.IsoPacket.Offset = i*ISOC_PACKET_SIZE; pContext->pDev = this; pContext->pIrp = I; pContext->pUrb = pUrb; pContext->pMdl = pMdl; // clean up is always done in UsbIsocWriteComplete if SubmitUrb is called NTSTATUS status = m_Pipe1.SubmitUrb(pUrb, LinkTo(UsbIsocWriteComplete), pContext); if(status == STATUS_PENDING) I.MarkPending(); //This is the normal case. else if(!NT_SUCCESS(status)) I.PnpComplete(status); return status; } else { ASSERT ( pUrb != 0 ); delete pMdl; delete pContext; return I.PnpComplete(STATUS_INSUFFICIENT_RESOURCES, IO_NO_INCREMENT); } } NTSTATUS UsbIsocDevice::UsbIsocWriteComplete(KIrp I, PISOC_CONTEXT pContext) { // The only field in the IRP that this routine may examine is the status. NTSTATUS status = I.Status(); // NOTE: We created this IRP. We do not have to mark it pending // because we are also the last driver to deal with this IRP! // if ( I->PendingReturned ) // I.MarkPending(); ASSERT ( pContext != NULL ); ULONG dwBytesSent = pContext->pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength; if ( dwBytesSent > 0 ) { Tracer << "Write() sent " << dwBytesSent << " bytes to USB (status=" << (ULONG)status << ")!\n"; } KIrp origI(pContext->pIrp); // Clean up all the allocations we did if ( pContext->pUrb ) delete pContext->pUrb; if ( pContext->pMdl ) delete pContext->pMdl; delete pContext; // Now complete the IRP that started this write origI.Information() = dwBytesSent; if (origI->PendingReturned) origI.MarkPending(); origI.PnpComplete(status, IO_NO_INCREMENT); return STATUS_SUCCESS; } 采用WinDbg调试时,发现在调试模式下只要在Read的完成例程里所有的URB都提交失败后,就可以正常关机了。 这个例子中的URB数目最多是4个。 也就是说如果输出了4次的 // URB submission FAILED! Tracer << "Isoc Read IRP FAILED (status="<< (ULONG)I.Status() << ")!\n"; 之后,就可以正常关机了。 如果只输出3次或者更少,就不能正常关机了,就会出现文章开头描述的问题了。 麻烦各位大大了。 我都不知道该如何下手了。 谢谢谢谢!! |
|
沙发#
发布于:2007-11-06 09:40
大大们有没有遇到这种问题呢???
谢谢大家啊 |
|
板凳#
发布于:2007-11-06 15:45
大家不要责怪我,我实在没办法啊
沉得好快,所以只好自己顶了 请大家帮帮忙,谢谢! |
|
地板#
发布于:2007-11-07 12:17
。。。。
郁闷了 |
|