|
|
/**************************************************************************************************************************
* SEND.C SigmaTel STIR4200 packet send module ************************************************************************************************************************** * (C) Unpublished Copyright of Sigmatel, Inc. All Rights Reserved. * * * Created: 04/06/2000 * Version 0.9 * Edited: 04/27/2000 * Version 0.92 * Edited: 05/03/2000 * Version 0.93 * Edited: 05/12/2000 * Version 0.94 * Edited: 08/22/2000 * Version 1.02 * Edited: 09/25/2000 * Version 1.10 * Edited: 10/13/2000 * Version 1.11 * Edited: 11/09/2000 * Version 1.12 * Edited: 12/29/2000 * Version 1.13 * Edited: 01/16/2001 * Version 1.14 * * **************************************************************************************************************************/
#include <ndis.h>
#include <ntdef.h>
#include <windef.h>
#include "stdarg.h"
#include "stdio.h"
#include "debug.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "ircommon.h"
#include "irusb.h"
#include "irndis.h"
#include "stir4200.h"
/*****************************************************************************
* * Function: SendPacketPreprocess * * Synopsis: Prepares a packet in such a way that the polling thread can later send it * The only operations are initializing and queuing the context * * * Arguments: pThisDev - pointer to current ir device object * pPacketToSend - pointer to packet to send * * Returns: NDIS_STATUS_PENDING - This is generally what we should * return. We will call NdisMSendComplete * when the USB driver completes the * send. * NDIS_STATUS_RESOURCES - No descriptor was available. * * Unsupported returns: * NDIS_STATUS_SUCCESS - We should never return this since * packet has to be sent from the polling thread * * * *****************************************************************************/ NDIS_STATUS SendPacketPreprocess( IN OUT PIR_DEVICE pThisDev, IN PVOID pPacketToSend ) { NDIS_STATUS status = NDIS_STATUS_PENDING ; PIRUSB_CONTEXT pThisContext; PLIST_ENTRY pListEntry;
DEBUGMSG(DBG_FUNC, ("+SendPacketPreprocess\n"));
//
// See if there are available send contexts
//
if( pThisDev->SendAvailableCount<=2 ) { DEBUGMSG(DBG_ERR, (" SendPacketPreprocess not enough contexts\n"));
InterlockedIncrement( &pThisDev->packetsSentRejected ); status = NDIS_STATUS_RESOURCES; goto done; }
//
// Dequeue a context
//
pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
if( NULL == pListEntry ) { //
// This cannot happen
//
IRUSB_ASSERT( 0 ); DEBUGMSG(DBG_ERR, (" SendPacketPreprocess failed to find a free context struct\n"));
InterlockedIncrement( &pThisDev->packetsSentRejected ); status = NDIS_STATUS_RESOURCES; goto done; }
InterlockedDecrement( &pThisDev->SendAvailableCount ); pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry ); pThisContext->pPacket = pPacketToSend; pThisContext->ContextType = CONTEXT_NDIS_PACKET;
//
// Store the time the packet was handed by the protocol
//
KeQuerySystemTime( &pThisContext->TimeReceived );
//
// Queue so that the polling thread can later handle it
//
ExInterlockedInsertTailList( &pThisDev->SendBuiltQueue, &pThisContext->ListEntry, &pThisDev->SendLock ); InterlockedIncrement( &pThisDev->SendBuiltCount );
done: DEBUGMSG(DBG_FUNC, ("-SendPacketPreprocess\n")); return status; }
/*****************************************************************************
* * Function: SendPreprocessedPacketSend * * Synopsis: Send a packet to the USB driver and add the sent irp and io context to * To the pending send queue; this queue is really just needed for possible later error cancellation * * * Arguments: pThisDev - pointer to current ir device object * pContext - pointer to the context with the packet to send * * Returns: NDIS_STATUS_PENDING - This is generally what we should * return. We will call NdisMSendComplete * when the USB driver completes the * send. * STATUS_UNSUCCESSFUL - The packet was invalid. * * NDIS_STATUS_SUCCESS - When blocking send are employed * * *****************************************************************************/ NDIS_STATUS SendPreprocessedPacketSend( IN OUT PIR_DEVICE pThisDev, IN PVOID pContext ) { PIRP pIrp; UINT BytesToWrite; NDIS_STATUS status; BOOLEAN fConvertedPacket; ULONG Counter; PURB pUrb = NULL; PDEVICE_OBJECT pUrbTargetDev; PIO_STACK_LOCATION pNextStack; PVOID pPacketToSend; PIRUSB_CONTEXT pThisContext = pContext; LARGE_INTEGER CurrentTime, TimeDifference; PNDIS_IRDA_PACKET_INFO pPacketInfo;
DEBUGMSG(DBG_FUNC, ("+SendPreprocessedPacketSend\n"));
IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
IRUSB_ASSERT( NULL != pThisContext );
//
// Stop if a halt/reset/suspend is going on
//
if( pThisDev->fPendingWriteClearStall || pThisDev->fPendingHalt || pThisDev->fPendingReset || pThisDev->fPendingClearTotalStall || !pThisDev->fProcessing ) { DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend abort due to pending reset or halt\n")); status = NDIS_STATUS_RESET_IN_PROGRESS;
//
// Give the packet back to the protocol
//
NdisMSendComplete( pThisDev->hNdisAdapter, pThisContext->pPacket, status ); InterlockedIncrement( &pThisDev->packetsSentRejected );
//
// Back to the available queue
//
ExInterlockedInsertTailList( &pThisDev->SendAvailableQueue, &pThisContext->ListEntry, &pThisDev->SendLock ); InterlockedIncrement( &pThisDev->SendAvailableCount ); goto done; } pUrb = pThisDev->pUrb;
NdisZeroMemory( pUrb, pThisDev->UrbLen );
pPacketToSend = pThisContext->pPacket; IRUSB_ASSERT( NULL != pPacketToSend );
//
// Indicate that we are not receiving
//
InterlockedExchange( (PLONG)&pThisDev->fCurrentlyReceiving, FALSE );
//
// Convert the packet to an ir frame and copy into our buffer
// and send the irp.
//
if( pThisDev->currentSpeed<=MAX_SIR_SPEED ) { fConvertedPacket = NdisToSirPacket( pThisDev, pPacketToSend, (PUCHAR)pThisDev->pBuffer, MAX_IRDA_DATA_SIZE, pThisDev->pStagingBuffer, &BytesToWrite ); } else if( pThisDev->currentSpeed<=MAX_MIR_SPEED ) { fConvertedPacket = NdisToMirPacket( pThisDev, pPacketToSend, (PUCHAR)pThisDev->pBuffer, MAX_IRDA_DATA_SIZE, pThisDev->pStagingBuffer, &BytesToWrite ); } else { fConvertedPacket = NdisToFirPacket( pThisDev, pPacketToSend, (PUCHAR)pThisDev->pBuffer, MAX_IRDA_DATA_SIZE, pThisDev->pStagingBuffer, &BytesToWrite ); } #if defined(SEND_LOGGING)
if( pThisDev->SendFileHandle ) { IO_STATUS_BLOCK IoStatusBlock;
ZwWriteFile( pThisDev->SendFileHandle, NULL, NULL, NULL, &IoStatusBlock, pThisDev->Buffer, BytesToWrite, (PLARGE_INTEGER)&pThisDev->SendFilePosition, NULL );
pThisDev->SendFilePosition += BytesToWrite; } #endif
if( (fConvertedPacket == FALSE) || (BytesToWrite > NDIS_STATUS_INVALID_PACKET) ) { DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() NdisToIrPacket failed. Couldn't convert packet!\n")); status = NDIS_STATUS_INVALID_LENGTH;
//
// Give the packet back to the protocol
//
NdisMSendComplete( pThisDev->hNdisAdapter, pThisContext->pPacket, status ); InterlockedIncrement( &pThisDev->packetsSentInvalid );
//
// Back to the available queue
//
ExInterlockedInsertTailList( &pThisDev->SendAvailableQueue, &pThisContext->ListEntry, &pThisDev->SendLock ); InterlockedIncrement( &pThisDev->SendAvailableCount ); goto done; }
//
// Save the effective length
//
pThisDev->BufLen = BytesToWrite; #if !defined(ONLY_ERROR_MESSAGES)
DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() NdisToIrPacket success BytesToWrite = dec %d, \n", BytesToWrite)); #endif
//
// Verify the FIFO condition and possibly make sure we don't overflow
//
pThisDev->SendFifoCount += BytesToWrite; if( pThisDev->SendFifoCount >= (3*STIR4200_FIFO_SIZE/2) ) { DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() Completing, size: %d\n", pThisDev->SendFifoCount)); SendWaitCompletion( pThisDev ); pThisDev->SendFifoCount = BytesToWrite; }
#if defined( WORKAROUND_STUCK_AFTER_GEAR_DOWN )
if( pThisDev->GearedDown ) { #define SIZE_FAKE_SEND 5
UCHAR pData[SIZE_FAKE_SEND]={0x55,0xaa,SIZE_FAKE_SEND-4,0x00,0xff}; St4200FakeSend( pThisDev, pData, SIZE_FAKE_SEND ); St4200FakeSend( pThisDev, pData, SIZE_FAKE_SEND ); pThisDev->GearedDown = FALSE; } #endif
//
// Enforce turnaround time
//
pPacketInfo = GetPacketInfo( pPacketToSend ); if (pPacketInfo != NULL) { #if DBG
//
// See if we get a packet with 0 turnaround time specified
// when we think we need need a turnaround time
//
if( pPacketInfo->MinTurnAroundTime > 0 ) { pThisDev->NumPacketsSentRequiringTurnaroundTime++; } else { pThisDev->NumPacketsSentNotRequiringTurnaroundTime++; } #endif
//
// Deal with turnaroud time
//
KeQuerySystemTime( &CurrentTime ); TimeDifference = RtlLargeIntegerSubtract( CurrentTime, pThisContext->TimeReceived ); if( (ULONG)(TimeDifference.QuadPart/10) < pPacketInfo->MinTurnAroundTime ) { ULONG TimeToWait = pPacketInfo->MinTurnAroundTime - (ULONG)(TimeDifference.QuadPart/10);
//
// Potential hack...
//
if( TimeToWait > 1000 ) { #if !defined(ONLY_ERROR_MESSAGES)
DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() Enforcing turnaround time %d\n", TimeToWait)); #endif
NdisMSleep( TimeToWait ); } } } else { //
// irda protocol is broken
//
DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() pPacketInfo == NULL\n")); }
//
// Now that we have created the urb, we will send a
// request to the USB device object.
//
pUrbTargetDev = pThisDev->pUsbDevObj;
//
// make an irp sending to usbhub
//
pIrp = IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
if( NULL == pIrp ) { DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend failed to alloc IRP\n")); status = NDIS_STATUS_FAILURE;
//
// Give the packet back to the protocol
//
NdisMSendComplete( pThisDev->hNdisAdapter, pThisContext->pPacket, status ); InterlockedIncrement( (PLONG)&pThisDev->packetsSentDropped );
//
// Back to the available queue
//
ExInterlockedInsertTailList( &pThisDev->SendAvailableQueue, &pThisContext->ListEntry, &pThisDev->SendLock ); InterlockedIncrement( &pThisDev->SendAvailableCount ); goto done; }
pIrp->IoStatus.Status = STATUS_PENDING; pIrp->IoStatus.Information = 0;
pThisContext->pIrp = pIrp;
//
// Build our URB for USBD
//
pUrb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER ); pUrb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkOutPipeHandle; pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT ; // short packet is not treated as an error.
pUrb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; pUrb->UrbBulkOrInterruptTransfer.UrbLink = NULL; pUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL; pUrb->UrbBulkOrInterruptTransfer.TransferBuffer = pThisDev->pBuffer; pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = (int)BytesToWrite;
//
// Call the class driver to perform the operation.
//
pNextStack = IoGetNextIrpStackLocation( pIrp );
IRUSB_ASSERT( pNextStack != NULL );
//
// pass the URB to the USB driver stack
//
pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; pNextStack->Parameters.Others.Argument1 = pUrb; pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; IoSetCompletionRoutine( pIrp, // irp to use
SendCompletePacketSend, // routine to call when irp is done
DEV_TO_CONTEXT(pThisContext), // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE // call on cancel
);
#ifdef SERIALIZE
KeClearEvent( &pThisDev->EventSyncUrb ); #endif
//
// Call IoCallDriver to send the irp to the usb port.
//
ExInterlockedInsertTailList( &pThisDev->SendPendingQueue, &pThisContext->ListEntry, &pThisDev->SendLock ); InterlockedIncrement( &pThisDev->SendPendingCount ); status = MyIoCallDriver( pThisDev, pUrbTargetDev, pIrp );
//
// The USB driver should always return STATUS_PENDING when
// it receives a write irp
//
IRUSB_ASSERT( status == STATUS_PENDING );
status = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventSyncUrb, NULL, 0 );
if( status == STATUS_TIMEOUT ) { KIRQL OldIrql;
DEBUGMSG( DBG_ERR,(" SendPreprocessedPacketSend() TIMED OUT! return from IoCallDriver USBD %x\n", status)); KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql ); RemoveEntryList( &pThisContext->ListEntry ); KeReleaseSpinLock( &pThisDev->SendLock, OldIrql ); InterlockedDecrement( &pThisDev->SendPendingCount ); IrUsb_CancelIo( pThisDev, pIrp, &pThisDev->EventSyncUrb ); }
done: DEBUGMSG(DBG_FUNC, ("-SendPreprocessedPacketSend\n")); return status; }
/*****************************************************************************
* * Function: SendWaitCompletion * * Synopsis: Waits for a send operation to be completed. A send is completed when the * entire frame has been transmitted ove the IR medium * * Arguments: pThisDev - pointer to current ir device object * * Returns: NT status code * *****************************************************************************/ NTSTATUS SendWaitCompletion( IN OUT PIR_DEVICE pThisDev ) { NTSTATUS Status; LARGE_INTEGER CurrentTime, InitialTime; ULONG FifoCount, OldFifoCount = STIR4200_FIFO_SIZE;
//
// At low speed we simply force to wait
//
if( (pThisDev->currentSpeed <= MAX_MIR_SPEED) || (pThisDev->ChipRevision >= CHIP_REVISION_7) ) { //
// We force to wait until the end of transmit
//
KeQuerySystemTime( &InitialTime ); while( TRUE ) { //
// Read the status register and check
//
if( (Status = St4200ReadRegisters( pThisDev, STIR4200_STATUS_REG, 3 )) == STATUS_SUCCESS ) { //
// bit set means still in transmit mode...
//
if( pThisDev->StIrTranceiver.StatusReg & STIR4200_STAT_FFDIR ) { KeQuerySystemTime( &CurrentTime ); FifoCount = ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg)); if( ((CurrentTime.QuadPart-InitialTime.QuadPart) > (IRUSB_100ns_PER_ms*STIR4200_SEND_TIMEOUT) ) || (FifoCount > OldFifoCount) ) { pThisDev->PreFifoCount = 0; St4200DoubleResetFifo( pThisDev ); break; } OldFifoCount = FifoCount; } else { pThisDev->PreFifoCount = ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg)); break; } } else break; } } //
// In high speed we try to be smarter
//
else { if( (Status = St4200ReadRegisters( pThisDev, STIR4200_STATUS_REG, 3 )) == STATUS_SUCCESS ) { //
// bit set means still in transmit mode...
//
if( pThisDev->StIrTranceiver.StatusReg & STIR4200_STAT_FFDIR ) { ULONG Count;
Count = ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg)); NdisStallExecution( (STIR4200_WRITE_DELAY*Count)/MAX_TOTAL_SIZE_WITH_ALL_HEADERS ); pThisDev->PreFifoCount = 0; } else { pThisDev->PreFifoCount = ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg)); } } }
pThisDev->SendFifoCount = 0; return Status; }
/*****************************************************************************
* * Function: SendCheckForOverflow * * Synopsis: Makes sure we are not going to overflow the TX FIFO * * Arguments: pThisDev - pointer to current ir device object * * Returns: NT status code * *****************************************************************************/ NTSTATUS SendCheckForOverflow( IN OUT PIR_DEVICE pThisDev ) { NTSTATUS Status = STATUS_SUCCESS;
//
// Check what we think we have in the FIFO
//
if( pThisDev->SendFifoCount > (3*STIR4200_FIFO_SIZE/4) ) { //
// Always one initial read
//
if( (Status = St4200ReadRegisters( pThisDev, STIR4200_FIFOCNT_LSB_REG, 2 )) == STATUS_SUCCESS ) { pThisDev->SendFifoCount = (ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg); #if !defined(ONLY_ERROR_MESSAGES)
DEBUGMSG( DBG_ERR,(" SendCheckForOverflow() Count: %d\n", pThisDev->SendFifoCount)); #endif
} else goto done;
//
// Force reads to get the real count, until condition is satisfied
//
while( pThisDev->SendFifoCount > (3*STIR4200_FIFO_SIZE/4) ) { if( (Status = St4200ReadRegisters( pThisDev, STIR4200_FIFOCNT_LSB_REG, 2 )) == STATUS_SUCCESS ) { pThisDev->SendFifoCount = (ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg); #if !defined(ONLY_ERROR_MESSAGES)
DEBUGMSG( DBG_ERR,(" SendCheckForOverflow() Count: %d\n", pThisDev->SendFifoCount)); #endif
} else goto done; } }
done: return Status; }
/*****************************************************************************
* * Function: SendCompletePacketSend * * Synopsis: Completes USB write operation * * Arguments: pUsbDevObj - pointer to the USB device object which * completed the irp * pIrp - the irp which was completed by the * device object * Context - the context given to IoSetCompletionRoutine * before calling IoCallDriver on the irp * The Context is a pointer to the ir device object. * * Returns: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine * (IofCompleteRequest) to stop working on the irp. * *****************************************************************************/ NTSTATUS SendCompletePacketSend( IN PDEVICE_OBJECT pUsbDevObj, IN PIRP pIrp, IN PVOID Context ) { PIR_DEVICE pThisDev; PVOID pThisContextPacket; NTSTATUS status; PIRUSB_CONTEXT pThisContext = (PIRUSB_CONTEXT)Context; PIRP pContextIrp; PURB pContextUrb; ULONG BufLen; ULONG BytesTransfered; PLIST_ENTRY pListEntry;
DEBUGMSG(DBG_FUNC, ("+SendCompletePacketSend\n"));
//
// The context given to IoSetCompletionRoutine is an IRUSB_CONTEXT struct
//
IRUSB_ASSERT( NULL != pThisContext ); // we better have a non NULL buffer
pThisDev = pThisContext->pThisDev;
IRUSB_ASSERT( NULL != pThisDev );
pContextIrp = pThisContext->pIrp; pContextUrb = pThisDev->pUrb; BufLen = pThisDev->BufLen;
pThisContextPacket = pThisContext->pPacket; //save ptr to packet to access after context freed
//
// Perform various IRP, URB, and buffer 'sanity checks'
//
IRUSB_ASSERT( pContextIrp == pIrp ); // check we're not a bogus IRP
status = pIrp->IoStatus.Status;
//
// we should have failed, succeeded, or cancelled, but NOT be pending
//
IRUSB_ASSERT( STATUS_PENDING != status );
//
// Remove from the pending queue (only if NOT cancelled)
//
if( status != STATUS_CANCELLED ) { KIRQL OldIrql;
KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql ); RemoveEntryList( &pThisContext->ListEntry ); KeReleaseSpinLock( &pThisDev->SendLock, OldIrql ); InterlockedDecrement( &pThisDev->SendPendingCount ); }
//
// IoCallDriver has been called on this Irp;
// Set the length based on the TransferBufferLength
// value in the URB
//
pIrp->IoStatus.Information = pContextUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
BytesTransfered = (ULONG)pIrp->IoStatus.Information; // save for below need-termination test
#if DBG
if( STATUS_SUCCESS == status ) { IRUSB_ASSERT( pIrp->IoStatus.Information == BufLen ); } #endif
DEBUGMSG(DBG_OUT, (" SendCompletePacketSend pIrp->IoStatus.Status = 0x%x\n", status)); DEBUGMSG(DBG_OUT, (" SendCompletePacketSend pIrp->IoStatus.Information = 0x%x, dec %d\n", pIrp->IoStatus.Information,pIrp->IoStatus.Information));
//
// Keep statistics.
//
if( status == STATUS_SUCCESS ) { #if DBG
ULONG total = pThisDev->TotalBytesSent + BytesTransfered; InterlockedExchange( (PLONG)&pThisDev->TotalBytesSent, (LONG)total ); #endif
InterlockedIncrement( (PLONG)&pThisDev->packetsSent ); DEBUGMSG(DBG_OUT, (" SendCompletePacketSend Sent a packet, packets sent = dec %d\n",pThisDev->packetsSent)); } else { InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors ); InterlockedIncrement( (PLONG)&pThisDev->packetsSentDropped ); DEBUGMSG(DBG_ERR, (" SendCompletePacketSend DROPPED a packet, packets dropped = dec %d\n",pThisDev->packetsSentDropped)); }
//
// Free the IRP because we alloced it ourselves,
//
IoFreeIrp( pIrp ); InterlockedIncrement( (PLONG)&pThisDev->NumWrites );
//
// Indicate to the protocol the status of the sent packet and return
// ownership of the packet.
//
NdisMSendComplete( pThisDev->hNdisAdapter, pThisContextPacket, status );
//
// Enqueue the completed packet
//
ExInterlockedInsertTailList( &pThisDev->SendAvailableQueue, &pThisContext->ListEntry, &pThisDev->SendLock ); InterlockedIncrement( &pThisDev->SendAvailableCount );
IrUsb_DecIoCount( pThisDev ); // we will track count of pending irps
if( ( STATUS_SUCCESS != status ) && ( STATUS_CANCELLED != status ) ) { if( !pThisDev->fPendingWriteClearStall && !pThisDev->fPendingClearTotalStall && !pThisDev->fPendingHalt && !pThisDev->fPendingReset && pThisDev->fProcessing ) { DEBUGMSG(DBG_ERR, (" SendCompletePacketSend error, will schedule a clear stall via URB_FUNCTION_RESET_PIPE (OUT)\n")); InterlockedExchange( (PLONG)&pThisDev->fPendingWriteClearStall, TRUE ); ScheduleWorkItem( pThisDev, ResetPipeCallback, pThisDev->BulkOutPipeHandle, 0 ); } }
#ifdef SERIALIZE
KeSetEvent( &pThisDev->EventSyncUrb, 0, FALSE ); //signal we're done
#endif
DEBUGMSG(DBG_FUNC, ("-SendCompletePacketSend\n")); return STATUS_MORE_PROCESSING_REQUIRED; }
|