windows-nt/Source/XPSP1/NT/drivers/net/irda/sigmatel/sys/diags.c
2020-09-26 16:20:57 +08:00

1625 lines
43 KiB
C

/**************************************************************************************************************************
* DIAGS.C SigmaTel STIR4200 diagnostic module
**************************************************************************************************************************
* (C) Unpublished Copyright of Sigmatel, Inc. All Rights Reserved.
*
*
* Created: 04/27/2000
* Version 0.92
* Edited: 05/12/2000
* Version 0.94
* Edited: 05/19/2000
* Version 0.95
* Edited: 05/24/2000
* Version 0.96
* Edited: 10/09/2000
* Version 1.10
*
*
**************************************************************************************************************************/
#if defined(DIAGS)
#define DOBREAKS // enable debug breaks
#include <ndis.h>
#include <ntddndis.h> // defines OID's
#include <usbdi.h>
#include <usbdlib.h>
#include "debug.h"
#include "ircommon.h"
#include "irndis.h"
#include "irusb.h"
#include "stir4200.h"
#include "diags.h"
/*****************************************************************************
*
* Function: Diags_BufferToFirPacket
*
* Synopsis: convert a buffer to a Fir IR packet
*
* Write the IR packet into the provided buffer and report
* its actual size.
*
* Arguments: pIrDev - pointer to device instance
* pIrPacketBuf - output buffer
* IrPacketBufLen - output buffer size
* pContigPacketBuf - temporary staging buffer (input buffer)
* ContigPacketLen - input buffer size
* pIrPacketLen - lenght of the converted data
*
* Returns: TRUE - on success
* FALSE - on failure
*
*
*****************************************************************************/
BOOLEAN
Diags_BufferToFirPacket(
IN PIR_DEVICE pIrDev,
OUT PUCHAR pIrPacketBuf,
ULONG IrPacketBufLen,
IN PUCHAR pContigPacketBuf,
ULONG ContigPacketLen,
OUT PULONG pIrPacketLen
)
{
ULONG I_fieldBytes;
FAST_IR_FCS_TYPE fcs, *pfcs;
ULONG i, TotalBytes, EscSize;
PSTIR4200_FRAME_HEADER pFrameHeader = (PSTIR4200_FRAME_HEADER)pIrPacketBuf;
PUCHAR pIrPacketBufFrame = pIrPacketBuf + sizeof(STIR4200_FRAME_HEADER);
/***********************************************/
/* Make sure that the packet is big enough */
/* to be legal. It consists of an A, C, and */
/* variable-length I field. */
/***********************************************/
if( ContigPacketLen < IRDA_A_C_TOTAL_SIZE )
{
DEBUGMSG(DBG_ERR, (" Diags_BufferToFirPacket(): Packet is too small\n"));
return FALSE;
}
else
{
I_fieldBytes = ContigPacketLen - IRDA_A_C_TOTAL_SIZE;
}
/***********************************************/
/* Make sure that we won't overwrite our */
/* contiguous buffer */
/***********************************************/
if( (ContigPacketLen > MAX_TOTAL_SIZE_WITH_ALL_HEADERS) ||
(MAX_POSSIBLE_IR_PACKET_SIZE_FOR_DATA(I_fieldBytes) > IrPacketBufLen) )
{
/***********************************************/
/* The packet is too large. Tell the caller */
/* to retry with a packet size large enough */
/* to get past this stage next time. */
/***********************************************/
DEBUGMSG(DBG_ERR, (" Diags_BufferToFirPacket(): Packet is too big\n"));
return FALSE;
}
/***********************************************/
/* Compute the FCS on the packet BEFORE */
/* applying transparency fixups. The FCS */
/* also must be sent using ESC-char */
/* transparency. */
/***********************************************/
fcs = ComputeFCS32( pContigPacketBuf, ContigPacketLen );
/***********************************************/
/* Add FCS to packet... */
/***********************************************/
pfcs = (FAST_IR_FCS_TYPE *)&pContigPacketBuf[ContigPacketLen];
*pfcs = fcs;
/***********************************************/
/* Build the STIr4200 FIR frame. */
/***********************************************/
/***********************************************/
/* Add preamble... */
/***********************************************/
memset( pIrPacketBufFrame, STIR4200_FIR_PREAMBLE, STIR4200_FIR_PREAMBLE_SIZ );
/***********************************************/
/* Add BOF's... */
/***********************************************/
memset( &pIrPacketBufFrame[STIR4200_FIR_PREAMBLE_SIZ], STIR4200_FIR_BOF, STIR4200_FIR_BOF_SIZ );
/***********************************************/
/* Escape A, C, I & CRC fields of packet... */
/***********************************************/
EscSize = ContigPacketLen + FAST_IR_FCS_SIZE;
for( i = 0, TotalBytes = STIR4200_FIR_PREAMBLE_SIZ + STIR4200_FIR_BOF_SIZ; i < EscSize; i++ )
{
UCHAR c;
switch( c = pContigPacketBuf[i] )
{
case STIR4200_FIR_ESC_CHAR:
pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_CHAR;
pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_DATA_7D;
break;
case STIR4200_FIR_BOF: // BOF = EOF too
pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_CHAR;
pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_DATA_7E;
break;
case STIR4200_FIR_PREAMBLE:
pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_CHAR;
pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_DATA_7F;
break;
default:
pIrPacketBufFrame[TotalBytes++] = c;
}
}
/***********************************************/
/* Add EOF's... */
/***********************************************/
memset( &pIrPacketBufFrame[TotalBytes], STIR4200_FIR_EOF, STIR4200_FIR_EOF_SIZ );
/***********************************************/
/* Add in STIr4200 header... */
/***********************************************/
TotalBytes += STIR4200_FIR_EOF_SIZ;
pFrameHeader->id1 = STIR4200_HEADERID_BYTE1;
pFrameHeader->id2 = STIR4200_HEADERID_BYTE2;
pFrameHeader->sizlsb = LOBYTE(TotalBytes);
pFrameHeader->sizmsb = HIBYTE(TotalBytes);
/***********************************************/
/* Calc size packet w/escaped data... */
/***********************************************/
*pIrPacketLen = TotalBytes + sizeof(STIR4200_FRAME_HEADER);
return TRUE;
}
/*****************************************************************************
*
* Function: Diags_BufferToSirPacket
*
* Synopsis: convert a buffer to a Sir IR packet
*
* Write the IR packet into the provided buffer and report
* its actual size.
*
* Arguments: pIrDev - pointer to device instance
* pPacket - NDIS packet to convert
* pIrPacketBuf - output buffer
* IrPacketBufLen - output buffer size
* pContigPacketBuf - temporary staging buffer (input buffer)
* ContigPacketLen - input buffer size
* pIrPacketLen - lenght of the converted data
*
* Returns: TRUE - on success
* FALSE - on failure
*
*
*****************************************************************************/
BOOLEAN
Diags_BufferToSirPacket(
IN PIR_DEVICE pIrDev,
OUT PUCHAR pIrPacketBuf,
ULONG IrPacketBufLen,
IN PUCHAR pContigPacketBuf,
ULONG ContigPacketLen,
USHORT ExtraBOFs,
OUT PULONG pIrPacketLen
)
{
ULONG i;
ULONG I_fieldBytes, totalBytes = 0;
ULONG numExtraBOFs;
SLOW_IR_FCS_TYPE fcs, tmpfcs;
UCHAR fcsBuf[SLOW_IR_FCS_SIZE * 2];
ULONG fcsLen = 0;
UCHAR nextChar;
PSTIR4200_FRAME_HEADER pFrameHeader = (PSTIR4200_FRAME_HEADER)pIrPacketBuf;
PUCHAR pIrPacketBufFrame = pIrPacketBuf + sizeof(STIR4200_FRAME_HEADER);
/***********************************************/
/* Make sure that the packet is big enough */
/* to be legal. It consists of an A, C, and */
/* variable-length I field. */
/***********************************************/
if( ContigPacketLen < IRDA_A_C_TOTAL_SIZE )
{
DEBUGMSG(DBG_ERR, (" NdisToSirPacket(): Packet is too small\n"));
return FALSE;
}
else
{
I_fieldBytes = ContigPacketLen - IRDA_A_C_TOTAL_SIZE;
}
/***********************************************/
/* Make sure that we won't overwrite our */
/* contiguous buffer. Make sure that the */
/* passed-in buffer can accomodate this */
/* packet's data no matter how much it */
/* grows through adding ESC-sequences, etc. */
/***********************************************/
if( (ContigPacketLen > MAX_TOTAL_SIZE_WITH_ALL_HEADERS) ||
(MAX_POSSIBLE_IR_PACKET_SIZE_FOR_DATA(I_fieldBytes) > IrPacketBufLen) )
{
//
// Packet is too big
//
DEBUGMSG(DBG_ERR, (" NdisToSirPacket(): Packet is too big\n"));
return FALSE;
}
/***********************************************/
/* Compute the FCS on the packet BEFORE */
/* applying transparency fixups. The FCS */
/* also must be sent using ESC-char */
/* transparency, so figure out how large */
/* the fcs will really be. */
/***********************************************/
fcs = ComputeFCS16( pContigPacketBuf, ContigPacketLen );
for( i = 0, tmpfcs = fcs, fcsLen = 0; i < SLOW_IR_FCS_SIZE; tmpfcs >>= 8, i++ )
{
UCHAR fcsbyte = tmpfcs & 0x00ff;
switch( fcsbyte )
{
case SLOW_IR_BOF:
case SLOW_IR_EOF:
case SLOW_IR_ESC:
fcsBuf[fcsLen++] = SLOW_IR_ESC;
fcsBuf[fcsLen++] = fcsbyte ^ SLOW_IR_ESC_COMP;
break;
default:
fcsBuf[fcsLen++] = fcsbyte;
break;
}
}
/***********************************************/
/* Now begin building the IR frame. */
/* */
/* This is the final format: */
/* */
/* BOF (1) */
/* extra BOFs ... */
/* NdisMediumIrda packet (from NDIS): */
/* Address (1) */
/* Control (1) */
/* FCS (2) */
/* EOF (1) */
/* */
/* Prepend BOFs (extra BOFs + 1 actual BOF) */
/***********************************************/
numExtraBOFs = ExtraBOFs;
if( numExtraBOFs > MAX_NUM_EXTRA_BOFS )
{
numExtraBOFs = MAX_NUM_EXTRA_BOFS;
}
for( i = totalBytes = 0; i < numExtraBOFs; i++ )
{
*(SLOW_IR_BOF_TYPE*)(pIrPacketBufFrame + totalBytes) = SLOW_IR_EXTRA_BOF;
totalBytes += SLOW_IR_EXTRA_BOF_SIZE;
}
*(SLOW_IR_BOF_TYPE*)(pIrPacketBufFrame + totalBytes) = SLOW_IR_BOF;
totalBytes += SLOW_IR_BOF_SIZE;
/***********************************************/
/* Copy the NDIS packet from our contiguous */
/* buffer, applying escape-char */
/* transparency. */
/***********************************************/
for( i = 0; i < ContigPacketLen; i++ )
{
nextChar = pContigPacketBuf[i];
switch( nextChar )
{
case SLOW_IR_BOF:
case SLOW_IR_EOF:
case SLOW_IR_ESC:
pIrPacketBufFrame[totalBytes++] = SLOW_IR_ESC;
pIrPacketBufFrame[totalBytes++] = nextChar ^ SLOW_IR_ESC_COMP;
break;
default:
pIrPacketBufFrame[totalBytes++] = nextChar;
break;
}
}
/***********************************************/
/* Add FCS, EOF. */
/***********************************************/
NdisMoveMemory( (PVOID)(pIrPacketBufFrame + totalBytes), (PVOID)fcsBuf, fcsLen );
totalBytes += fcsLen;
*(SLOW_IR_EOF_TYPE*)(pIrPacketBufFrame + totalBytes) = (UCHAR)SLOW_IR_EOF;
totalBytes += SLOW_IR_EOF_SIZE;
/***********************************************/
/* Add in STIr4200 header... */
/***********************************************/
pFrameHeader->id1 = STIR4200_HEADERID_BYTE1;
pFrameHeader->id2 = STIR4200_HEADERID_BYTE2;
pFrameHeader->sizlsb = LOBYTE(totalBytes);
pFrameHeader->sizmsb = HIBYTE(totalBytes);
*pIrPacketLen = totalBytes + sizeof(STIR4200_FRAME_HEADER);
return TRUE;
}
/*****************************************************************************
*
* Function: Diags_Enable
*
* Synopsis: Switches the STIr4200 to diagnostic mode
*
* Arguments: pThisDev - pointer to IR device
*
* Returns: NT status code
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_Enable(
IN OUT PIR_DEVICE pThisDev
)
{
PIRUSB_CONTEXT pThisContext;
PLIST_ENTRY pListEntry;
//
// Make sure diags aren't already active
//
if( pThisDev->DiagsActive )
{
DEBUGMSG(DBG_ERR, (" Diags_Enable diags already active\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Get a context to switch to the new mode
//
pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
if( NULL == pListEntry )
{
//
// This must not happen
//
DEBUGMSG(DBG_ERR, (" Diags_Enable failed to find a free context struct\n"));
IRUSB_ASSERT( 0 );
return STATUS_UNSUCCESSFUL;
}
InterlockedDecrement( &pThisDev->SendAvailableCount );
pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
pThisContext->ContextType = CONTEXT_DIAGS_ENABLE;
//
// Disable further interaction with the stack
//
InterlockedExchange( &pThisDev->DiagsPendingActivation, TRUE );
//
// Queue the context and then wait
//
KeClearEvent( &pThisDev->EventDiags );
ExInterlockedInsertTailList(
&pThisDev->SendBuiltQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendBuiltCount );
MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, NULL, 0 );
return pThisDev->IOCTLStatus;
}
/*****************************************************************************
*
* Function: Diags_Disable
*
* Synopsis: Switches the STIr4200 back to normal mode
*
* Arguments: pThisDev - pointer to IR device
*
* Returns: NT status code
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_Disable(
IN OUT PIR_DEVICE pThisDev
)
{
PRCV_BUFFER pRecBuf;
PLIST_ENTRY pEntry;
//
// Make sure diags are active
//
if( !pThisDev->DiagsActive )
{
DEBUGMSG(DBG_ERR, (" Diags_Disable diags not active\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Enable interaction with the stack and no queuing of contexts is required
//
InterlockedExchange( &pThisDev->DiagsActive, FALSE );
InterlockedExchange( &pThisDev->DiagsPendingActivation, FALSE );
//
// Get rid of all the diagnostic buffers
//
while( pEntry=ExInterlockedRemoveHeadList(
&pThisDev->DiagsReceiveQueue,
&pThisDev->DiagsReceiveLock )
)
{
pRecBuf = CONTAINING_RECORD( pEntry, RCV_BUFFER, ListEntry );
InterlockedExchange( &pRecBuf->DataLen, 0 );
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
}
return STATUS_SUCCESS;
}
/*****************************************************************************
*
* Function: Diags_ReadRegisters
*
* Synopsis: Prepares a context to read the registers
*
* Arguments: pThisDev - pointer to IR device
* pIOCTL - pointer to IOCTL descriptor
* IOCTLSize - size of the IOCTL buffer
*
* Returns: NT status code
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_ReadRegisters(
IN OUT PIR_DEVICE pThisDev,
OUT PDIAGS_READ_REGISTERS_IOCTL pIOCTL,
ULONG IOCTLSize
)
{
PIRUSB_CONTEXT pThisContext;
PLIST_ENTRY pListEntry;
//
// First basic validation
//
if( IOCTLSize < sizeof(DIAGS_READ_REGISTERS_IOCTL) )
{
DEBUGMSG(DBG_ERR, (" Diags_ReadRegisters invalid output buffer\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Now we get a little more sofisticated
//
if( ((pIOCTL->FirstRegister+pIOCTL->NumberRegisters)>(STIR4200_MAX_REG+1)) ||
((IOCTLSize+1)<(sizeof(DIAGS_READ_REGISTERS_IOCTL)+pIOCTL->NumberRegisters)) )
{
DEBUGMSG(DBG_ERR, (" Diags_ReadRegisters invalid output buffer\n"));
return STATUS_UNSUCCESSFUL;
}
pThisDev->pIOCTL = pIOCTL;
pThisDev->IOCTLStatus = STATUS_UNSUCCESSFUL;
//
// Get a context to queue
//
pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
if( NULL == pListEntry )
{
//
// This must not happen
//
DEBUGMSG(DBG_ERR, (" Diags_ReadRegisters failed to find a free context struct\n"));
IRUSB_ASSERT( 0 );
return STATUS_UNSUCCESSFUL;
}
InterlockedDecrement( &pThisDev->SendAvailableCount );
pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
pThisContext->ContextType = CONTEXT_DIAGS_READ_REGISTERS;
//
// Queue the context and then wait
//
KeClearEvent( &pThisDev->EventDiags );
ExInterlockedInsertTailList(
&pThisDev->SendBuiltQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendBuiltCount );
MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, NULL, 0 );
return pThisDev->IOCTLStatus;
}
/*****************************************************************************
*
* Function: Diags_WriteRegister
*
* Synopsis: Prepares a context to write the registers
*
* Arguments: pThisDev - pointer to IR device
* pIOCTL - pointer to IOCTL descriptor
* IOCTLSize - size of the IOCTL buffer
*
* Returns: NT status code
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_WriteRegister(
IN OUT PIR_DEVICE pThisDev,
OUT PDIAGS_READ_REGISTERS_IOCTL pIOCTL,
ULONG IOCTLSize
)
{
PIRUSB_CONTEXT pThisContext;
PLIST_ENTRY pListEntry;
//
// Validation
//
if( (IOCTLSize < sizeof(DIAGS_READ_REGISTERS_IOCTL)) ||
(pIOCTL->FirstRegister>STIR4200_MAX_REG) )
{
DEBUGMSG(DBG_ERR, (" Diags_WriteRegister invalid output buffer\n"));
return STATUS_UNSUCCESSFUL;
}
pThisDev->pIOCTL = pIOCTL;
pThisDev->IOCTLStatus = STATUS_UNSUCCESSFUL;
//
// Get a context to queue
//
pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
if( NULL == pListEntry )
{
//
// This must not happen
//
DEBUGMSG(DBG_ERR, (" Diags_ReadRegisters failed to find a free context struct\n"));
IRUSB_ASSERT( 0 );
return STATUS_UNSUCCESSFUL;
}
InterlockedDecrement( &pThisDev->SendAvailableCount );
pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
pThisContext->ContextType = CONTEXT_DIAGS_WRITE_REGISTER;
//
// Queue the context and the wait
//
KeClearEvent( &pThisDev->EventDiags );
ExInterlockedInsertTailList(
&pThisDev->SendBuiltQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendBuiltCount );
MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, NULL, 0 );
return pThisDev->IOCTLStatus;
}
/*****************************************************************************
*
* Function: Diags_PrepareBulk
*
* Synopsis: Prepares a context to do a bulk transfer
*
* Arguments: pThisDev - pointer to IR device
* pIOCTL - pointer to IOCTL descriptor
* IOCTLSize - size of the IOCTL buffer
* DirectionOut - TRUE if bulk-out, FALSE if bulk-in
*
* Returns: NT status code
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_PrepareBulk(
IN OUT PIR_DEVICE pThisDev,
OUT PDIAGS_BULK_IOCTL pIOCTL,
ULONG IOCTLSize,
BOOLEAN DirectionOut
)
{
PIRUSB_CONTEXT pThisContext;
PLIST_ENTRY pListEntry;
//
// First basic validation
//
if( IOCTLSize < sizeof(DIAGS_BULK_IOCTL) )
{
DEBUGMSG(DBG_ERR, (" Diags_PrepareBulk invalid input buffer\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Now we get a little more sofisticated
//
if( IOCTLSize < (sizeof(DIAGS_BULK_IOCTL)+pIOCTL->DataSize-1) )
{
DEBUGMSG(DBG_ERR, (" Diags_PrepareBulk invalid output buffer\n"));
return STATUS_UNSUCCESSFUL;
}
pThisDev->pIOCTL = pIOCTL;
pThisDev->IOCTLStatus = STATUS_UNSUCCESSFUL;
//
// Get a context to queue
//
pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
if( NULL == pListEntry )
{
//
// This must not happen
//
DEBUGMSG(DBG_ERR, (" Diags_PrepareBulk failed to find a free context struct\n"));
IRUSB_ASSERT( 0 );
return STATUS_UNSUCCESSFUL;
}
InterlockedDecrement( &pThisDev->SendAvailableCount );
pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
if( DirectionOut )
pThisContext->ContextType = CONTEXT_DIAGS_BULK_OUT;
else
pThisContext->ContextType = CONTEXT_DIAGS_BULK_IN;
//
// Queue the context and then wait
//
KeClearEvent( &pThisDev->EventDiags );
ExInterlockedInsertTailList(
&pThisDev->SendBuiltQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendBuiltCount );
MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, NULL, 0 );
return pThisDev->IOCTLStatus;
}
/*****************************************************************************
*
* Function: Diags_PrepareSend
*
* Synopsis: Prepares a diagnostic send
*
* Arguments: pThisDev - pointer to IR device
* pIOCTL - pointer to IOCTL descriptor
* IOCTLSize - size of the IOCTL buffer
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_PrepareSend(
IN OUT PIR_DEVICE pThisDev,
OUT PDIAGS_SEND_IOCTL pIOCTL,
ULONG IOCTLSize
)
{
PIRUSB_CONTEXT pThisContext;
PLIST_ENTRY pListEntry;
ULONG Size = sizeof(DIAGS_SEND_IOCTL)+pIOCTL->DataSize-1;
//
// First basic validation
//
if( IOCTLSize < sizeof(DIAGS_SEND_IOCTL) )
{
DEBUGMSG(DBG_ERR, (" Diags_PrepareBulk invalid input buffer\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Now we get a little more sofisticated
//
if( IOCTLSize < (sizeof(DIAGS_SEND_IOCTL)+pIOCTL->DataSize-1) )
{
DEBUGMSG(DBG_ERR, (" Diags_PrepareSend invalid output buffer\n"));
return STATUS_UNSUCCESSFUL;
}
pThisDev->pIOCTL = pIOCTL;
pThisDev->IOCTLStatus = STATUS_UNSUCCESSFUL;
//
// Get a context to queue
//
pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
if( NULL == pListEntry )
{
//
// This must not happen
//
DEBUGMSG(DBG_ERR, (" Diags_PrepareSend failed to find a free context struct\n"));
IRUSB_ASSERT( 0 );
return STATUS_UNSUCCESSFUL;
}
InterlockedDecrement( &pThisDev->SendAvailableCount );
pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
pThisContext->ContextType = CONTEXT_DIAGS_SEND;
//
// Queue the context and then wait
//
KeClearEvent( &pThisDev->EventDiags );
ExInterlockedInsertTailList(
&pThisDev->SendBuiltQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendBuiltCount );
MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, NULL, 0 );
return pThisDev->IOCTLStatus;
}
/*****************************************************************************
*
* Function: Diags_Receive
*
* Synopsis: Diagnostic receive
*
* Arguments: pThisDev - pointer to IR device
* pIOCTL - pointer to IOCTL descriptor
* IOCTLSize - size of the IOCTL buffer
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_Receive(
IN OUT PIR_DEVICE pThisDev,
OUT PDIAGS_RECEIVE_IOCTL pIOCTL,
ULONG IOCTLSize
)
{
PLIST_ENTRY pListEntry;
PRCV_BUFFER pRecBuf;
//
// First basic validation
//
if( IOCTLSize < sizeof(DIAGS_RECEIVE_IOCTL) )
{
DEBUGMSG(DBG_ERR, (" Diags_Receive invalid input buffer\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Get a received packet
//
pListEntry = ExInterlockedRemoveHeadList( &pThisDev->DiagsReceiveQueue, &pThisDev->DiagsReceiveLock );
if( NULL == pListEntry )
{
//
// No packet available
//
return STATUS_UNSUCCESSFUL;
}
pRecBuf = CONTAINING_RECORD( pListEntry, RCV_BUFFER, ListEntry );
//
// Now we get a little more sofisticated
//
if( IOCTLSize < (sizeof(DIAGS_RECEIVE_IOCTL)+pIOCTL->DataSize-1) )
{
DEBUGMSG(DBG_ERR, (" Diags_Receive invalid output buffer\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Copy the data
//
NdisMoveMemory( pIOCTL->pData, pRecBuf->pDataBuf, pRecBuf->DataLen );
pIOCTL->DataSize = (USHORT)pRecBuf->DataLen;
pThisDev->pIOCTL = pIOCTL;
InterlockedExchange( &pRecBuf->DataLen, 0 );
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
return STATUS_SUCCESS;
}
/*****************************************************************************
*
* Function: Diags_GetSpeed
*
* Synopsis: Retrieves the current speed
*
* Arguments: pThisDev - pointer to IR device
* pIOCTL - pointer to IOCTL descriptor
* IOCTLSize - size of the IOCTL buffer
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_GetSpeed(
IN OUT PIR_DEVICE pThisDev,
OUT PDIAGS_SPEED_IOCTL pIOCTL,
ULONG IOCTLSize
)
{
//
// First basic validation
//
if( IOCTLSize < sizeof(DIAGS_SPEED_IOCTL) )
{
DEBUGMSG(DBG_ERR, (" Diags_GetSpeed invalid input buffer\n"));
return STATUS_UNSUCCESSFUL;
}
pIOCTL->Speed = pThisDev->currentSpeed;
return STATUS_SUCCESS;
}
/*****************************************************************************
*
* Function: Diags_SetSpeed
*
* Synopsis: Sets a new speed in diagnostic mode
*
* Arguments: pThisDev - pointer to IR device
* pIOCTL - pointer to IOCTL descriptor
* IOCTLSize - size of the IOCTL buffer
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
NTSTATUS
Diags_SetSpeed(
IN OUT PIR_DEVICE pThisDev,
OUT PDIAGS_SPEED_IOCTL pIOCTL,
ULONG IOCTLSize
)
{
NDIS_STATUS status;
USHORT i;
//
// First basic validation
//
if( IOCTLSize < sizeof(DIAGS_SPEED_IOCTL) )
{
DEBUGMSG(DBG_ERR, (" Diags_SetSpeed invalid input buffer\n"));
return STATUS_UNSUCCESSFUL;
}
if( pThisDev->currentSpeed == pIOCTL->Speed )
{
//
// We are already set to the requested speed.
//
return STATUS_SUCCESS;
}
DEBUGMSG(DBG_ERR, (" Diags_SetSpeed(OID_IRDA_LINK_SPEED, 0x%x, decimal %d)\n",pIOCTL->Speed, pIOCTL->Speed));
for( i = 0; i < NUM_BAUDRATES; i++ )
{
if( supportedBaudRateTable[i].BitsPerSec == pIOCTL->Speed )
{
//
// Keep a pointer to the link speed which has
// been requested.
//
pThisDev->linkSpeedInfo = &supportedBaudRateTable[i];
status = NDIS_STATUS_PENDING;
break; //for
}
}
//
// Don't set if there is an error
//
if( NDIS_STATUS_PENDING != status )
{
DEBUGMSG(DBG_ERR, (" Invalid link speed\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Set the new speed
//
IrUsb_PrepareSetSpeed( pThisDev );
while( pThisDev->linkSpeedInfo->BitsPerSec != pThisDev->currentSpeed )
{
NdisMSleep( 50000 );
}
return STATUS_SUCCESS;
}
/*****************************************************************************
*
* Function: Diags_CompleteEnable
*
* Synopsis: Completes the enabling of the diagnostic state
*
* Arguments: pThisDev - pointer to IR device
* pContext - pinter to the operation context
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
VOID
Diags_CompleteEnable(
IN OUT PIR_DEVICE pThisDev,
IN PVOID pContext
)
{
PIRUSB_CONTEXT pThisContext = pContext;
//
// Really enable diags
//
InterlockedExchange( &pThisDev->DiagsActive, TRUE );
//
// Return the context
//
ExInterlockedInsertTailList(
&pThisDev->SendAvailableQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendAvailableCount );
//
// Signal
//
KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
}
/*****************************************************************************
*
* Function: Diags_CompleteReadRegisters
*
* Synopsis: Reads the registers and returns the value
*
* Arguments: pThisDev - pointer to IR device
* pContext - pinter to the operation context
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
VOID
Diags_CompleteReadRegisters(
IN OUT PIR_DEVICE pThisDev,
IN PVOID pContext
)
{
PDIAGS_READ_REGISTERS_IOCTL pIOCTL = pThisDev->pIOCTL;
PIRUSB_CONTEXT pThisContext = pContext;
//
// Read the data
//
pThisDev->IOCTLStatus = St4200ReadRegisters( pThisDev, pIOCTL->FirstRegister, pIOCTL->NumberRegisters );
if( pThisDev->IOCTLStatus == STATUS_SUCCESS )
{
NdisMoveMemory(
&pIOCTL->pRegisterBuffer,
&pThisDev->StIrTranceiver.FifoDataReg+pIOCTL->FirstRegister,
pIOCTL->NumberRegisters
);
}
//
// Return the context
//
ExInterlockedInsertTailList(
&pThisDev->SendAvailableQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendAvailableCount );
//
// Signal
//
KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
}
/*****************************************************************************
*
* Function: Diags_CompleteWriteRegister
*
* Synopsis: Reads the registers and returns the value
*
* Arguments: pThisDev - pointer to IR device
* pContext - pinter to the operation context
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
VOID
Diags_CompleteWriteRegister(
IN OUT PIR_DEVICE pThisDev,
IN PVOID pContext
)
{
PDIAGS_READ_REGISTERS_IOCTL pIOCTL = pThisDev->pIOCTL;
PIRUSB_CONTEXT pThisContext = pContext;
//
// Copy the new register value
//
NdisMoveMemory(
&pThisDev->StIrTranceiver.FifoDataReg+pIOCTL->FirstRegister,
&pIOCTL->pRegisterBuffer,
1
);
//
// Write to the device
//
pThisDev->IOCTLStatus = St4200WriteRegister( pThisDev, pIOCTL->FirstRegister );
//
// Return the context
//
ExInterlockedInsertTailList(
&pThisDev->SendAvailableQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendAvailableCount );
//
// Signal
//
KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
}
/*****************************************************************************
*
* Function: Diags_Bulk
*
* Synopsis: Executes a diagnostic bulk transfer
*
* Arguments: pThisDev - pointer to IR device
* pContext - pinter to the operation context
* DirectionOut - TRUE if bulk-out, FALSE if bulk-in
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
VOID
Diags_Bulk(
IN OUT PIR_DEVICE pThisDev,
IN PVOID pContext,
BOOLEAN DirectionOut
)
{
PDIAGS_BULK_IOCTL pIOCTL = pThisDev->pIOCTL;
PIRUSB_CONTEXT pThisContext = pContext;
NTSTATUS status;
PIRP pIrp;
PURB pUrb = NULL;
PDEVICE_OBJECT pUrbTargetDev;
PIO_STACK_LOCATION pNextStack;
KIRQL OldIrql;
IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
IRUSB_ASSERT( NULL != pThisContext );
//
// Stop if a halt/reset is going on
//
if( pThisDev->fPendingWriteClearStall || pThisDev->fPendingHalt ||
pThisDev->fPendingReset || pThisDev->fPendingClearTotalStall )
{
DEBUGMSG(DBG_ERR, (" Diags_Bulk abort due to pending reset or halt\n"));
goto done;
}
pUrb = pThisDev->pUrb;
NdisZeroMemory( pUrb, pThisDev->UrbLen );
//
// Save the effective length
//
pThisDev->BufLen = pIOCTL->DataSize;
//
// 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, (" Diags_Bulk failed to alloc IRP\n"));
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;
if( DirectionOut )
{
pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT ;
pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkOutPipeHandle;
}
else
{
pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN ;
pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkInPipeHandle;
}
// 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 = pIOCTL->pData;
pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = (int)pIOCTL->DataSize;
//
// 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
Diags_CompleteIrp, // 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 )
{
DEBUGMSG( DBG_ERR,(" Diags_Bulk() TIMED OUT! return from IoCallDriver USBD %x\n", status));
IrUsb_CancelIo( pThisDev, pIrp, &pThisDev->EventSyncUrb );
}
done:
//
// Return the context
//
KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql );
RemoveEntryList( &pThisContext->ListEntry );
KeReleaseSpinLock( &pThisDev->SendLock, OldIrql );
InterlockedDecrement( &pThisDev->SendPendingCount );
ExInterlockedInsertTailList(
&pThisDev->SendAvailableQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendAvailableCount );
//
// Signal
//
KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
}
/*****************************************************************************
*
* Function: Diags_Send
*
* Synopsis: Sends a packet through the diagnostic path
*
* Arguments: pThisDev - pointer to IR device
* pContext - pinter to the operation context
*
* Returns: None
*
* Notes:
*
*****************************************************************************/
VOID
Diags_Send(
IN OUT PIR_DEVICE pThisDev,
IN PVOID pContext
)
{
PDIAGS_SEND_IOCTL pIOCTL = pThisDev->pIOCTL;
PIRUSB_CONTEXT pThisContext = pContext;
NTSTATUS status;
PIRP pIrp;
PURB pUrb = NULL;
PDEVICE_OBJECT pUrbTargetDev;
PIO_STACK_LOCATION pNextStack;
BOOLEAN fConvertedPacket;
KIRQL OldIrql;
ULONG BytesToWrite;
IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
IRUSB_ASSERT( NULL != pThisContext );
//
// Stop if a halt/reset is going on
//
if( pThisDev->fPendingWriteClearStall || pThisDev->fPendingHalt ||
pThisDev->fPendingReset || pThisDev->fPendingClearTotalStall )
{
DEBUGMSG(DBG_ERR, (" Diags_Send abort due to pending reset or halt\n"));
goto done;
}
pUrb = pThisDev->pUrb;
NdisZeroMemory( pUrb, pThisDev->UrbLen );
DEBUGMSG(DBG_ERR, (" Diags_Send() packet size: %d\n", pIOCTL->DataSize));
//
// Convert the packet to an ir frame and copy into our buffer
// and send the irp.
//
if( pThisDev->currentSpeed<=MAX_SIR_SPEED )
{
fConvertedPacket = Diags_BufferToSirPacket(
pThisDev,
(PUCHAR)pThisDev->pBuffer,
MAX_IRDA_DATA_SIZE,
pIOCTL->pData,
pIOCTL->DataSize,
pIOCTL->ExtraBOFs,
&BytesToWrite
);
}
else if( pThisDev->currentSpeed<=MAX_MIR_SPEED )
{
fConvertedPacket = Diags_BufferToFirPacket(
pThisDev,
(PUCHAR)pThisDev->pBuffer,
MAX_IRDA_DATA_SIZE,
pIOCTL->pData,
pIOCTL->DataSize,
&BytesToWrite
);
}
else
{
fConvertedPacket = Diags_BufferToFirPacket(
pThisDev,
(PUCHAR)pThisDev->pBuffer,
MAX_IRDA_DATA_SIZE,
pIOCTL->pData,
pIOCTL->DataSize,
&BytesToWrite
);
}
if( fConvertedPacket == FALSE )
{
DEBUGMSG(DBG_ERR, (" Diags_Send() NdisToIrPacket failed. Couldn't convert packet!\n"));
goto done;
}
//
// Always force turnaround
//
NdisMSleep( pThisDev->dongleCaps.turnAroundTime_usec );
//
// 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, (" Diags_Send failed to alloc IRP\n"));
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
Diags_CompleteIrp, // 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 )
{
DEBUGMSG( DBG_ERR,(" Diags_Send() TIMED OUT! return from IoCallDriver USBD %x\n", status));
IrUsb_CancelIo( pThisDev, pIrp, &pThisDev->EventSyncUrb );
}
done:
KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql );
RemoveEntryList( &pThisContext->ListEntry );
KeReleaseSpinLock( &pThisDev->SendLock, OldIrql );
InterlockedDecrement( &pThisDev->SendPendingCount );
ExInterlockedInsertTailList(
&pThisDev->SendAvailableQueue,
&pThisContext->ListEntry,
&pThisDev->SendLock
);
InterlockedIncrement( &pThisDev->SendAvailableCount );
//
// Signal
//
KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
}
/*****************************************************************************
*
* Function: Diags_CompleteIrp
*
* Synopsis: Completes a USB 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
Diags_CompleteIrp(
IN PDEVICE_OBJECT pUsbDevObj,
IN PIRP pIrp,
IN PVOID Context
)
{
PIR_DEVICE pThisDev;
NTSTATUS status;
PIRUSB_CONTEXT pThisContext = (PIRUSB_CONTEXT)Context;
PIRP pContextIrp;
PURB pContextUrb;
PDIAGS_BULK_IOCTL pIOCTL;
//
// 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;
pIOCTL = pThisDev->pIOCTL;
//
// Perform various IRP, URB, and buffer 'sanity checks'
//
IRUSB_ASSERT( pContextIrp == pIrp ); // check we're not a bogus IRP
status = pIrp->IoStatus.Status;
pThisDev->IOCTLStatus = status;
//
// we should have failed, succeeded, or cancelled, but NOT be pending
//
IRUSB_ASSERT( STATUS_PENDING != status );
//
// IoCallDriver has been called on this Irp;
// Set the length based on the TransferBufferLength
// value in the URB
//
pIrp->IoStatus.Information = pContextUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
pIOCTL->DataSize = (USHORT)pIrp->IoStatus.Information;
//
// Free the IRP because we alloced it ourselves,
//
IoFreeIrp( pIrp );
InterlockedIncrement( (PLONG)&pThisDev->NumWrites );
IrUsb_DecIoCount( pThisDev ); // we will track count of pending irps
#ifdef SERIALIZE
KeSetEvent( &pThisDev->EventSyncUrb, 0, FALSE ); //signal we're done
#endif
return STATUS_MORE_PROCESSING_REQUIRED;
}
#endif