You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2830 lines
81 KiB
2830 lines
81 KiB
/**************************************************************************************************************************
|
|
* RECEIVE.C SigmaTel STIR4200 packet reception and decoding module
|
|
**************************************************************************************************************************
|
|
* (C) Unpublished Copyright of Sigmatel, Inc. All Rights Reserved.
|
|
*
|
|
*
|
|
* Created: 04/06/2000
|
|
* Version 0.9
|
|
* Edited: 04/24/2000
|
|
* Version 0.91
|
|
* Edited: 04/27/2000
|
|
* Version 0.92
|
|
* Edited: 05/03/2000
|
|
* Version 0.93
|
|
* Edited: 05/12/2000
|
|
* Version 0.94
|
|
* Edited: 05/19/2000
|
|
* Version 0.95
|
|
* Edited: 07/13/2000
|
|
* Version 1.00
|
|
* 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
|
|
* Edited: 02/20/2001
|
|
* Version 1.15
|
|
*
|
|
**************************************************************************************************************************/
|
|
|
|
#define DOBREAKS // enable debug breaks
|
|
|
|
#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"
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveProcessFifoData
|
|
*
|
|
* Synopsis: Processes the received data and indicates packets to the protocol
|
|
*
|
|
* Arguments: pThisDev - pointer to current ir device object
|
|
*
|
|
* Returns: None
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
VOID
|
|
ReceiveProcessFifoData(
|
|
IN OUT PIR_DEVICE pThisDev
|
|
)
|
|
{
|
|
ULONG BytesProcessed;
|
|
BOOLEAN ReturnValue = TRUE;
|
|
|
|
while( ReturnValue )
|
|
{
|
|
if( pThisDev->currentSpeed<=MAX_SIR_SPEED )
|
|
{
|
|
ReturnValue = ReceiveSirStepFSM( pThisDev, &BytesProcessed );
|
|
}
|
|
else if( pThisDev->currentSpeed<=MAX_MIR_SPEED )
|
|
{
|
|
ReturnValue = ReceiveMirStepFSM( pThisDev, &BytesProcessed );
|
|
}
|
|
else
|
|
{
|
|
ReturnValue = ReceiveFirStepFSM( pThisDev, &BytesProcessed );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Indicate that we are no more receiving
|
|
//
|
|
InterlockedExchange( (PLONG)&pThisDev->fCurrentlyReceiving, FALSE );
|
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveResetPointers
|
|
*
|
|
* Synopsis: Reset the receive pointers as the data is gone when we are sending
|
|
*
|
|
* Arguments: pThisDev - pointer to current ir device object
|
|
*
|
|
* Returns: None
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
VOID
|
|
ReceiveResetPointers(
|
|
IN OUT PIR_DEVICE pThisDev
|
|
)
|
|
{
|
|
pThisDev->rcvState = STATE_INIT;
|
|
pThisDev->readBufPos = 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceivePreprocessFifo
|
|
*
|
|
* Synopsis: Verifies if there is data to be received
|
|
*
|
|
* Arguments: MiniportAdapterContext - pointer to current ir device object
|
|
* pFifoCount - pinter to count to return
|
|
*
|
|
* Returns: NT status code
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS
|
|
ReceivePreprocessFifo(
|
|
IN OUT PIR_DEVICE pThisDev,
|
|
OUT PULONG pFifoCount
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
#ifdef WORKAROUND_POLLING_FIFO_COUNT
|
|
LARGE_INTEGER CurrentTime;
|
|
BOOLEAN SlowReceive;
|
|
ULONG OldFifoCount = 0;
|
|
LONG Delay;
|
|
|
|
//
|
|
// Set the receive algorithm
|
|
//
|
|
#if defined(SUPPORT_LA8)
|
|
if( pThisDev->ChipRevision >= CHIP_REVISION_8 )
|
|
SlowReceive = FALSE;
|
|
else
|
|
#endif
|
|
SlowReceive = TRUE;
|
|
|
|
if( SlowReceive )
|
|
{
|
|
Status = St4200GetFifoCount( pThisDev, pFifoCount );
|
|
if( Status != STATUS_SUCCESS )
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ReceivePreprocessFifo(): USB failure\n"));
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pFifoCount = 1;
|
|
}
|
|
|
|
//
|
|
// Receive the data
|
|
//
|
|
if( *pFifoCount || pThisDev->fReadHoldingReg )
|
|
{
|
|
//
|
|
// See if we need to take care of the fake empty FIFO
|
|
//
|
|
#if defined( WORKAROUND_FAKE_EMPTY_FIFO )
|
|
if( *pFifoCount )
|
|
{
|
|
#endif
|
|
//
|
|
// If we are in SIR read again until we see a stable value
|
|
//
|
|
if( (pThisDev->currentSpeed <= MAX_SIR_SPEED) && (pThisDev->currentSpeed != SPEED_9600) && SlowReceive )
|
|
{
|
|
//
|
|
// Make also sure we don't ever wrap
|
|
//
|
|
while( (OldFifoCount != *pFifoCount) && (*pFifoCount < 9*STIR4200_FIFO_SIZE/10) )
|
|
{
|
|
OldFifoCount = *pFifoCount;
|
|
St4200GetFifoCount( pThisDev, pFifoCount );
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are in FIR we need to delay
|
|
//
|
|
if( (pThisDev->currentSpeed > MAX_MIR_SPEED) && SlowReceive )
|
|
{
|
|
if( pThisDev->ChipRevision < CHIP_REVISION_7 )
|
|
{
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG(DBG_ERR, (" ReceivePreprocessFifo(): Delaying\n"));
|
|
#endif
|
|
Delay = STIR4200_READ_DELAY - (STIR4200_READ_DELAY*(*pFifoCount))/STIR4200_ESC_PACKET_SIZE;
|
|
if( Delay > 0 )
|
|
{
|
|
// MS Security bug #540780 - use NdisMSleep instead of NdisStallExecution
|
|
NdisMSleep( (ULONG)Delay );
|
|
}
|
|
}
|
|
else //if( pThisDev->dongleCaps.windowSize == 2 )
|
|
{
|
|
/*if( !(*pFifoCount%10) )
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ReceivePreprocessFifo(): Forcing wrap\n"));
|
|
NdisMSleep( 1000 );
|
|
}*/
|
|
Delay = pThisDev->ReceiveAdaptiveDelay -
|
|
(pThisDev->ReceiveAdaptiveDelay*(*pFifoCount))/STIR4200_MULTIPLE_READ_THREHOLD;
|
|
if( Delay > 0 )
|
|
{
|
|
// MS Security bug #540780 - use NdisMSleep instead of NdisStallExecution
|
|
NdisMSleep( (ULONG)Delay );
|
|
}
|
|
}
|
|
}
|
|
#if defined( WORKAROUND_FAKE_EMPTY_FIFO )
|
|
}
|
|
//
|
|
// Read after a successful bulk-in with count of zero
|
|
//
|
|
else
|
|
{
|
|
pThisDev->fReadHoldingReg = FALSE;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Perform the read
|
|
//
|
|
pThisDev->PreReadBuffer.DataLen = 0;
|
|
Status = ReceivePacketRead(
|
|
pThisDev,
|
|
&pThisDev->PreReadBuffer
|
|
);
|
|
|
|
if( Status == STATUS_SUCCESS )
|
|
{
|
|
*pFifoCount = pThisDev->PreReadBuffer.DataLen;
|
|
|
|
#if defined( WORKAROUND_FAKE_EMPTY_FIFO )
|
|
//
|
|
// If we got data restore the flag
|
|
//
|
|
if( *pFifoCount )
|
|
{
|
|
pThisDev->fReadHoldingReg = TRUE;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(ONLY_ERROR_MESSAGES) && defined( WORKAROUND_FAKE_EMPTY_FIFO )
|
|
if( *pFifoCount && !pThisDev->fReadHoldingReg )
|
|
DEBUGMSG(DBG_ERR, (" ReceivePreprocessFifo(): Final byte(s) workaround\n"));
|
|
#endif
|
|
|
|
#if defined(RECEIVE_LOGGING)
|
|
if( pThisDev->ReceiveFileHandle && *pFifoCount )
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
ZwWriteFile(
|
|
pThisDev->ReceiveFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
pThisDev->PreReadBuffer.pDataBuf,
|
|
pThisDev->PreReadBuffer.DataLen,
|
|
(PLARGE_INTEGER)&pThisDev->ReceiveFilePosition,
|
|
NULL
|
|
);
|
|
|
|
pThisDev->ReceiveFilePosition += pThisDev->PreReadBuffer.DataLen;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ReceivePreprocessFifo(): USB failure\n"));
|
|
pThisDev->PreReadBuffer.DataLen = 0;
|
|
*pFifoCount = 0;
|
|
}
|
|
}
|
|
#else
|
|
Status = ReceivePacketRead(
|
|
pThisDev,
|
|
&pThisDev->PreReadBuffer
|
|
);
|
|
|
|
if( Status == STATUS_SUCCESS )
|
|
*pFifoCount = pThisDev->PreReadBuffer.DataLen;
|
|
#endif
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveGetFifoData
|
|
*
|
|
* Synopsis: Load the preprocessed data if any is vailable, otherwise tries to read and load new data
|
|
*
|
|
* Arguments: pThisDev - pointer to current ir device object
|
|
* pData - buffer to copy to
|
|
* pBytesRead - pointer to return bytes read
|
|
* BytesToRead - requested number of bytes
|
|
*
|
|
* Returns: Number of bytes in the FIFO
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS
|
|
ReceiveGetFifoData(
|
|
IN OUT PIR_DEVICE pThisDev,
|
|
OUT PUCHAR pData,
|
|
OUT PULONG pBytesRead,
|
|
ULONG BytesToRead
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
#ifdef WORKAROUND_POLLING_FIFO_COUNT
|
|
LARGE_INTEGER CurrentTime;
|
|
BOOLEAN SlowReceive;
|
|
ULONG FifoCount = 0, OldFifoCount = 0;
|
|
LONG Delay;
|
|
|
|
//
|
|
// Make sure if there is data in the preread buffer
|
|
//
|
|
if( pThisDev->PreReadBuffer.DataLen )
|
|
{
|
|
ULONG OutputBufferSize;
|
|
|
|
IRUSB_ASSERT( pThisDev->PreReadBuffer.DataLen <= BytesToRead );
|
|
|
|
//
|
|
// Copy the data
|
|
//
|
|
RtlCopyMemory( pData, pThisDev->PreReadBuffer.pDataBuf, pThisDev->PreReadBuffer.DataLen );
|
|
|
|
#if !defined(WORKAROUND_BROKEN_MIR)
|
|
//
|
|
// Consider MIR
|
|
//
|
|
if( pThisDev->currentSpeed == SPEED_1152000 )
|
|
ReceiveMirUnstuff(
|
|
pThisDev,
|
|
pData,
|
|
pThisDev->PreReadBuffer.DataLen,
|
|
pThisDev->pRawUnstuffedBuf,
|
|
&OutputBufferSize
|
|
);
|
|
#endif
|
|
|
|
*pBytesRead = pThisDev->PreReadBuffer.DataLen;
|
|
pThisDev->PreReadBuffer.DataLen = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
//
|
|
// Try to read if no data is already available
|
|
//
|
|
else
|
|
{
|
|
//
|
|
// Set the receive algorithm
|
|
//
|
|
#if defined(SUPPORT_LA8)
|
|
if( pThisDev->ChipRevision >= CHIP_REVISION_8 )
|
|
SlowReceive = FALSE;
|
|
else
|
|
#endif
|
|
SlowReceive = TRUE;
|
|
|
|
if( SlowReceive )
|
|
{
|
|
Status = St4200GetFifoCount( pThisDev, &FifoCount );
|
|
if( Status != STATUS_SUCCESS )
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ReceiveGetFifoData(): USB failure\n"));
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FifoCount = 1;
|
|
}
|
|
|
|
//
|
|
// Receive the data
|
|
//
|
|
if( FifoCount || pThisDev->fReadHoldingReg )
|
|
{
|
|
//
|
|
// See if we need to take care of the fake empty FIFO
|
|
//
|
|
#if defined( WORKAROUND_FAKE_EMPTY_FIFO )
|
|
if( FifoCount )
|
|
{
|
|
#endif
|
|
//
|
|
// If we are in SIR read again until we see a stable value
|
|
//
|
|
#if defined( WORKAROUND_9600_ANTIBOUNCING )
|
|
if( (pThisDev->currentSpeed <= MAX_SIR_SPEED) && SlowReceive )
|
|
{
|
|
if( pThisDev->currentSpeed != SPEED_9600 )
|
|
{
|
|
//
|
|
// Make also sure we don't ever wrap
|
|
//
|
|
while( (OldFifoCount != FifoCount) && (FifoCount < 9*STIR4200_FIFO_SIZE/10) )
|
|
{
|
|
OldFifoCount = FifoCount;
|
|
St4200GetFifoCount( pThisDev, &FifoCount );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pThisDev->rcvState != STATE_INIT )
|
|
{
|
|
while( OldFifoCount != FifoCount )
|
|
{
|
|
OldFifoCount = FifoCount;
|
|
St4200GetFifoCount( pThisDev, &FifoCount );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
if( (pThisDev->currentSpeed <= MAX_SIR_SPEED) && ( pThisDev->currentSpeed != SPEED_9600) && SlowReceive )
|
|
{
|
|
while( OldFifoCount != FifoCount )
|
|
{
|
|
OldFifoCount = FifoCount;
|
|
St4200GetFifoCount( pThisDev, &FifoCount );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If we are in FIR we need to delay
|
|
//
|
|
if( (pThisDev->currentSpeed > MAX_MIR_SPEED) && SlowReceive )
|
|
{
|
|
if( pThisDev->ChipRevision <= CHIP_REVISION_6 )
|
|
{
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG(DBG_ERR, (" ReceiveGetFifoData(): Delaying\n"));
|
|
#endif
|
|
Delay = STIR4200_READ_DELAY - (STIR4200_READ_DELAY*FifoCount)/STIR4200_ESC_PACKET_SIZE;
|
|
if( Delay > 0 )
|
|
{
|
|
// MS Security bug #540780 - use NdisMSleep instead of NdisStallExecution
|
|
NdisMSleep( (ULONG)Delay );
|
|
}
|
|
}
|
|
else //if( pThisDev->dongleCaps.windowSize == 2 )
|
|
{
|
|
/*if( !(FifoCount%10) )
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ReceiveGetFifoData(): Forcing wrap\n"));
|
|
NdisMSleep( 1000 );
|
|
}*/
|
|
Delay = pThisDev->ReceiveAdaptiveDelay -
|
|
(pThisDev->ReceiveAdaptiveDelay*FifoCount)/STIR4200_MULTIPLE_READ_THREHOLD;
|
|
if( Delay > 0 )
|
|
{
|
|
// MS Security bug #540780 - use NdisMSleep instead of NdisStallExecution
|
|
NdisMSleep( (ULONG)Delay );
|
|
}
|
|
}
|
|
}
|
|
#if defined( WORKAROUND_FAKE_EMPTY_FIFO )
|
|
}
|
|
else
|
|
{
|
|
// Force antibouncing to take care of OHCI
|
|
if( pThisDev->currentSpeed <= MAX_SIR_SPEED )
|
|
{
|
|
if( pThisDev->rcvState != STATE_INIT )
|
|
{
|
|
OldFifoCount = 1;
|
|
while( OldFifoCount != FifoCount )
|
|
{
|
|
OldFifoCount = FifoCount;
|
|
St4200GetFifoCount( pThisDev, &FifoCount );
|
|
}
|
|
}
|
|
}
|
|
pThisDev->fReadHoldingReg = FALSE;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Perform the read
|
|
//
|
|
pThisDev->PreReadBuffer.DataLen = 0;
|
|
Status = ReceivePacketRead(
|
|
pThisDev,
|
|
&pThisDev->PreReadBuffer
|
|
);
|
|
|
|
if( Status == STATUS_SUCCESS )
|
|
{
|
|
IRUSB_ASSERT( pThisDev->PreReadBuffer.DataLen <= BytesToRead );
|
|
|
|
//
|
|
// Copy the data
|
|
//
|
|
RtlCopyMemory( pData, pThisDev->PreReadBuffer.pDataBuf, pThisDev->PreReadBuffer.DataLen );
|
|
FifoCount = pThisDev->PreReadBuffer.DataLen;
|
|
|
|
#if defined( WORKAROUND_FAKE_EMPTY_FIFO )
|
|
//
|
|
// If we got data restore the flag
|
|
//
|
|
if( FifoCount )
|
|
{
|
|
pThisDev->fReadHoldingReg = TRUE;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(ONLY_ERROR_MESSAGES) && defined( WORKAROUND_FAKE_EMPTY_FIFO )
|
|
if( FifoCount && !pThisDev->fReadHoldingReg )
|
|
DEBUGMSG(DBG_ERR, (" ReceiveGetFifoData(): Final byte(s) workaround\n"));
|
|
#endif
|
|
|
|
#if defined(RECEIVE_LOGGING)
|
|
if( pThisDev->ReceiveFileHandle && FifoCount )
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
ZwWriteFile(
|
|
pThisDev->ReceiveFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
pThisDev->PreReadBuffer.pDataBuf,
|
|
pThisDev->PreReadBuffer.DataLen,
|
|
(PLARGE_INTEGER)&pThisDev->ReceiveFilePosition,
|
|
NULL
|
|
);
|
|
|
|
pThisDev->ReceiveFilePosition += pThisDev->PreReadBuffer.DataLen;
|
|
}
|
|
#endif
|
|
pThisDev->PreReadBuffer.DataLen = 0;
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ReceiveGetFifoData(): USB failure\n"));
|
|
pThisDev->PreReadBuffer.DataLen = 0;
|
|
FifoCount = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pBytesRead = FifoCount;
|
|
return Status;
|
|
#else
|
|
if( pThisDev->PreReadBuffer.DataLen )
|
|
{
|
|
IRUSB_ASSERT( pThisDev->PreReadBuffer.DataLen <= BytesToRead );
|
|
|
|
//
|
|
// Copy the data
|
|
//
|
|
RtlCopyMemory( pData, pThisDev->PreReadBuffer.pDataBuf, pThisDev->PreReadBuffer.DataLen );
|
|
*pBytesRead = pThisDev->PreReadBuffer.DataLen;
|
|
pThisDev->PreReadBuffer.DataLen = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Status = ReceivePacketRead(
|
|
pThisDev,
|
|
&pThisDev->PreReadBuffer
|
|
);
|
|
|
|
if( Status == STATUS_SUCCESS )
|
|
{
|
|
RtlCopyMemory( pData, pThisDev->PreReadBuffer.pDataBuf, pThisDev->PreReadBuffer.DataLen );
|
|
*pBytesRead = pThisDev->PreReadBuffer.DataLen;
|
|
pThisDev->PreReadBuffer.DataLen = 0;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveFirStepFSM
|
|
*
|
|
* Synopsis: Step the receive FSM to read in a piece of an IrDA frame.
|
|
* Strip the BOFs and EOF, and eliminate escape sequences.
|
|
*
|
|
* Arguments: pIrDev - pointer to the current IR device object
|
|
* pBytesProcessed - pointer to bytes processed
|
|
*
|
|
* Returns: TRUE after an entire frame has been read in
|
|
* FALSE otherwise
|
|
*
|
|
*****************************************************************************/
|
|
BOOLEAN
|
|
ReceiveFirStepFSM(
|
|
IN OUT PIR_DEVICE pIrDev,
|
|
OUT PULONG pBytesProcessed
|
|
)
|
|
{
|
|
ULONG rawBufPos=0, rawBytesRead=0;
|
|
BOOLEAN FrameProcessed = FALSE, ForceExit = FALSE;
|
|
UCHAR ThisChar;
|
|
PUCHAR pRawBuf, pReadBuf;
|
|
PRCV_BUFFER pRecBuf;
|
|
|
|
*pBytesProcessed = 0;
|
|
|
|
if( !pIrDev->pCurrentRecBuf )
|
|
{
|
|
UINT Index;
|
|
|
|
pRecBuf = ReceiveGetBuf( pIrDev, &Index, RCV_STATE_FULL );
|
|
if( !pRecBuf )
|
|
{
|
|
//
|
|
// no buffers available; stop
|
|
//
|
|
DEBUGMSG(DBG_ERR, (" ReceiveSirStepFSM out of buffers\n"));
|
|
pIrDev->packetsReceivedNoBuffer ++;
|
|
return FALSE;
|
|
}
|
|
|
|
pIrDev->pCurrentRecBuf = pRecBuf;
|
|
}
|
|
else
|
|
pRecBuf = pIrDev->pCurrentRecBuf;
|
|
|
|
pReadBuf = pRecBuf->pDataBuf;
|
|
pRawBuf = pIrDev->pRawBuf;
|
|
|
|
/***********************************************/
|
|
/* Read in and process groups of incoming */
|
|
/* bytes from the FIFO. */
|
|
/***********************************************/
|
|
while( (pIrDev->rcvState != STATE_SAW_EOF) &&
|
|
(pIrDev->readBufPos <= (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE)) &&
|
|
!ForceExit )
|
|
{
|
|
if( pIrDev->rcvState == STATE_CLEANUP )
|
|
{
|
|
/***********************************************/
|
|
/* We returned a complete packet last time, */
|
|
/* but we had read some extra bytes, which */
|
|
/* we stored into the rawBuf after */
|
|
/* returning the previous complete buffer */
|
|
/* to the user. So instead of calling */
|
|
/* DoRcvDirect() in this first execution of */
|
|
/* this loop, we just use these previously */
|
|
/* read bytes. (This is typically only 1 or */
|
|
/* 2 bytes). */
|
|
/***********************************************/
|
|
rawBytesRead = pIrDev->rawCleanupBytesRead;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
}
|
|
else
|
|
{
|
|
if( ReceiveGetFifoData( pIrDev, pRawBuf, &rawBytesRead, STIR4200_FIFO_SIZE ) == STATUS_SUCCESS )
|
|
{
|
|
if( rawBytesRead == (ULONG)-1 )
|
|
{
|
|
/***********************************************/
|
|
/* Receive error...back to INIT state... */
|
|
/***********************************************/
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
continue;
|
|
}
|
|
else if( rawBytesRead == 0 )
|
|
{
|
|
/***********************************************/
|
|
/* No more receive bytes...break out... */
|
|
/***********************************************/
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
/***********************************************/
|
|
/* Let the receive state machine process */
|
|
/* this group of bytes. */
|
|
/* */
|
|
/* NOTE: We have to loop once more after */
|
|
/* getting MAX_RCV_DATA_SIZE bytes so that */
|
|
/* we can see the 'EOF'; hence <= and not */
|
|
/* <. */
|
|
/***********************************************/
|
|
for( rawBufPos = 0;
|
|
((pIrDev->rcvState != STATE_SAW_EOF) && (rawBufPos < rawBytesRead) &&
|
|
(pIrDev->readBufPos <= (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE)));
|
|
rawBufPos++ )
|
|
{
|
|
*pBytesProcessed += 1;
|
|
ThisChar = pRawBuf[rawBufPos];
|
|
switch( pIrDev->rcvState )
|
|
{
|
|
case STATE_INIT:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_FIR_BOF:
|
|
pIrDev->rcvState = STATE_GOT_FIR_BOF;
|
|
break;
|
|
#if defined(WORKAROUND_XX_HANG)
|
|
case 0x3F:
|
|
if( (rawBufPos+1) < rawBytesRead )
|
|
{
|
|
if( pRawBuf[rawBufPos+1] == 0x3F )
|
|
{
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): hang sequence in INIT state\n"));
|
|
St4200ResetFifo( pIrDev );
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
#if defined(WORKAROUND_FF_HANG)
|
|
case 0xFF:
|
|
if( (rawBufPos+2) < rawBytesRead )
|
|
{
|
|
if( (pRawBuf[rawBufPos+2] == 0xFF) && (pRawBuf[rawBufPos+1] == 0xFF) &&
|
|
(rawBytesRead>STIR4200_FIFO_OVERRUN_THRESHOLD) )
|
|
{
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): overflow sequence in INIT state\n"));
|
|
|
|
//
|
|
// First time aroud try resetting the FIFO
|
|
//
|
|
if( !pIrDev->StuckFir )
|
|
{
|
|
St4200ResetFifo( pIrDev );
|
|
pIrDev->StuckFir = TRUE;
|
|
}
|
|
//
|
|
// Otherwise reset the part
|
|
//
|
|
else
|
|
{
|
|
InterlockedExchange( (PLONG)&pIrDev->fPendingClearTotalStall, TRUE );
|
|
ScheduleWorkItem( pIrDev, RestoreIrDevice, NULL, 0 );
|
|
pIrDev->StuckFir = FALSE;
|
|
}
|
|
rawBufPos = rawBytesRead;
|
|
ForceExit = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): invalid char in INIT state\n"));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_GOT_FIR_BOF:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_FIR_BOF:
|
|
pIrDev->rcvState = STATE_GOT_BOF;
|
|
break;
|
|
#if defined(WORKAROUND_BAD_ESC)
|
|
case STIR4200_FIR_ESC_CHAR:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): invalid char in BOF state, bufpos=%d, char=%X\n", pIrDev->readBufPos, (ULONG)ThisChar));
|
|
if( rawBufPos < (rawBytesRead-1) )
|
|
{
|
|
pIrDev->rcvState = STATE_GOT_BOF;
|
|
rawBufPos ++;
|
|
}
|
|
else
|
|
{
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): invalid char in BOF state, bufpos=%d, char=%X\n", pIrDev->readBufPos, (ULONG)ThisChar));
|
|
#if defined(WORKAROUND_BAD_SOF)
|
|
pIrDev->rcvState = STATE_GOT_BOF;
|
|
rawBufPos --;
|
|
#else
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
#endif
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_GOT_BOF:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_FIR_BOF:
|
|
/***********************************************/
|
|
/* It's a mistake, but could still be valid data
|
|
/***********************************************/
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): More than legal BOFs, bufpos=%d\n", pIrDev->readBufPos));
|
|
pIrDev->rcvState = STATE_GOT_BOF;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
case STIR4200_FIR_PREAMBLE:
|
|
/***********************************************/
|
|
/* Garbage */
|
|
/***********************************************/
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): invalid char in BOF state, bufpos=%d, char=%X\n", pIrDev->readBufPos, (ULONG)ThisChar));
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
case STIR4200_FIR_ESC_CHAR:
|
|
/***********************************************/
|
|
/* Start of data. Our first data byte */
|
|
/* happens to be an ESC sequence. */
|
|
/***********************************************/
|
|
pIrDev->rcvState = STATE_ESC_SEQUENCE;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
default:
|
|
pReadBuf[0] = ThisChar;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
pIrDev->readBufPos = 1;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_ACCEPTING:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_FIR_EOF:
|
|
#if defined( WORKAROUND_33_HANG )
|
|
if( pIrDev->readBufPos < (IRDA_A_C_TOTAL_SIZE + FAST_IR_FCS_SIZE - 1) )
|
|
#else
|
|
if( pIrDev->readBufPos < (IRDA_A_C_TOTAL_SIZE + FAST_IR_FCS_SIZE) )
|
|
#endif
|
|
{
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
("ReceiveFirStepFSM(): WARNING: EOF encountered in short packet, bufpos=%d\n", pIrDev->readBufPos));
|
|
pIrDev->packetsReceivedRunt ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
}
|
|
else
|
|
{
|
|
#if defined( WORKAROUND_MISSING_7E )
|
|
// Force to get out if there is one EOF and we have no more data
|
|
if( rawBufPos == (rawBytesRead-1) )
|
|
{
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG(DBG_INT_ERR, ("ReceiveFirStepFSM(): Using a single 7E EOF\n"));
|
|
#endif
|
|
pIrDev->rcvState = STATE_SAW_EOF;
|
|
}
|
|
else
|
|
pIrDev->rcvState = STATE_SAW_FIR_BOF;
|
|
#else
|
|
pIrDev->rcvState = STATE_SAW_FIR_BOF;
|
|
#endif
|
|
}
|
|
break;
|
|
case STIR4200_FIR_ESC_CHAR:
|
|
pIrDev->rcvState = STATE_ESC_SEQUENCE;
|
|
break;
|
|
case STIR4200_FIR_PREAMBLE:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): invalid preamble char in ACCEPTING state, bufpos=%d\n", pIrDev->readBufPos));
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
default:
|
|
pReadBuf[pIrDev->readBufPos++] = ThisChar;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_ESC_SEQUENCE:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_FIR_ESC_DATA_7D:
|
|
pReadBuf[pIrDev->readBufPos++] = 0x7d;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
case STIR4200_FIR_ESC_DATA_7E:
|
|
pReadBuf[pIrDev->readBufPos++] = 0x7e;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
case STIR4200_FIR_ESC_DATA_7F:
|
|
pReadBuf[pIrDev->readBufPos++] = 0x7f;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): invalid escaped char=%X\n", (ULONG)ThisChar));
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_SAW_FIR_BOF:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_FIR_EOF:
|
|
pIrDev->rcvState = STATE_SAW_EOF;
|
|
break;
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): invalid char=%X, expected EOF\n", (ULONG)ThisChar));
|
|
pIrDev->rcvState = STATE_SAW_EOF;
|
|
#if !defined(WORKAROUND_MISSING_7E)
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
#endif
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_SAW_EOF:
|
|
default:
|
|
DEBUGMSG(DBG_ERR, (" ReceiveFirStepFSM(): Illegal state, bufpos=%d\n", pIrDev->readBufPos));
|
|
IRUSB_ASSERT( 0 );
|
|
pIrDev->readBufPos = 0;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// * Set result and do any post-cleanup.
|
|
switch( pIrDev->rcvState )
|
|
{
|
|
case STATE_SAW_EOF:
|
|
/***********************************************/
|
|
/* We've read in the entire packet. Queue */
|
|
/* it and return TRUE. */
|
|
/***********************************************/
|
|
pIrDev->StuckFir = FALSE;
|
|
pRecBuf->DataLen = pIrDev->readBufPos;
|
|
pIrDev->pCurrentRecBuf = NULL;
|
|
ReceiveDeliverBuffer(
|
|
pIrDev,
|
|
pRecBuf
|
|
);
|
|
FrameProcessed = TRUE;
|
|
if( rawBufPos < rawBytesRead )
|
|
{
|
|
/***********************************************/
|
|
/* This is ugly. We have some more */
|
|
/* unprocessed bytes in the raw buffer. */
|
|
/* Move these to the beginning of the raw */
|
|
/* buffer go to the CLEANUP state, which */
|
|
/* indicates that these bytes be used up */
|
|
/* during the next call. (This is typically */
|
|
/* only 1 or 2 bytes). */
|
|
/* */
|
|
/* Note: We can't just leave these in the */
|
|
/* raw buffer because we might be */
|
|
/* supporting connections to multiple COM */
|
|
/* ports. */
|
|
/* */
|
|
/***********************************************/
|
|
RtlMoveMemory( pRawBuf, &pRawBuf[rawBufPos], rawBytesRead - rawBufPos );
|
|
pIrDev->rawCleanupBytesRead = rawBytesRead - rawBufPos;
|
|
pIrDev->rcvState = STATE_CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
pIrDev->rcvState = STATE_INIT;
|
|
}
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
default:
|
|
if( pIrDev->readBufPos > (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE) )
|
|
{
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveFirStepFSM() Overflow\n"));
|
|
St4200ResetFifo( pIrDev );
|
|
|
|
pIrDev->packetsReceivedOverflow ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
pIrDev->pCurrentRecBuf = NULL;
|
|
InterlockedExchange( &pRecBuf->DataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
}
|
|
else
|
|
{
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): returning with partial packet, read %d bytes\n", pIrDev->readBufPos));
|
|
#endif
|
|
}
|
|
FrameProcessed = FALSE;
|
|
break;
|
|
}
|
|
return FrameProcessed;
|
|
}
|
|
|
|
|
|
#if !defined(WORKAROUND_BROKEN_MIR)
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveMirUnstuff
|
|
*
|
|
* Synopsis: Software unstuffing for a MIR frmae
|
|
*
|
|
* Arguments: pIrDev - pointer to the current IR device object
|
|
* pBytesProcessed - pointer to bytes processed
|
|
*
|
|
* Returns: TRUE after an entire frame has been read in
|
|
*
|
|
*****************************************************************************/
|
|
BOOLEAN
|
|
ReceiveMirUnstuff(
|
|
IN OUT PIR_DEVICE pIrDev,
|
|
IN PUCHAR pInputBuffer,
|
|
ULONG InputBufferSize,
|
|
OUT PUCHAR pOutputBuffer,
|
|
OUT PULONG pOutputBufferSize
|
|
)
|
|
{
|
|
ULONG MirIncompleteBitCount = pIrDev->MirIncompleteBitCount;
|
|
ULONG MirOneBitCount = pIrDev->MirOneBitCount;
|
|
UCHAR MirIncompleteByte = pIrDev->MirIncompleteByte;
|
|
ULONG ByteCounter, BitCounter;
|
|
BOOL MirUnstuffNext = FALSE;
|
|
|
|
*pOutputBufferSize = 0;
|
|
|
|
if( MirOneBitCount == 5 )
|
|
{
|
|
MirUnstuffNext = TRUE;
|
|
}
|
|
|
|
//
|
|
// Loop on the input buffer
|
|
//
|
|
for( ByteCounter=0; ByteCounter<InputBufferSize; ByteCounter++ )
|
|
{
|
|
//
|
|
// Loop on the byte
|
|
//
|
|
for( BitCounter=0; BitCounter<8; BitCounter++ )
|
|
{
|
|
//
|
|
// test for one
|
|
//
|
|
if( pInputBuffer[ByteCounter] & (0x01<<BitCounter) )
|
|
{
|
|
//
|
|
// Sixth one, reset
|
|
//
|
|
if( MirUnstuffNext )
|
|
{
|
|
MirOneBitCount = 0;
|
|
MirUnstuffNext = FALSE;
|
|
|
|
pIrDev->MirFlagCount ++;
|
|
}
|
|
//
|
|
// Increase the one count
|
|
//
|
|
else
|
|
{
|
|
MirOneBitCount ++;
|
|
if( MirOneBitCount == 5 )
|
|
{
|
|
MirUnstuffNext = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy to the temp byte
|
|
//
|
|
MirIncompleteByte += 0x01<<MirIncompleteBitCount;
|
|
|
|
//
|
|
// Increase the output bit count
|
|
//
|
|
MirIncompleteBitCount ++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Increase the output bit count if we are not stuffing
|
|
//
|
|
if( !MirUnstuffNext )
|
|
{
|
|
MirIncompleteBitCount ++;
|
|
}
|
|
|
|
//
|
|
// Reset
|
|
//
|
|
MirOneBitCount = 0;
|
|
MirUnstuffNext = FALSE;
|
|
|
|
//
|
|
// No copy needs to be done
|
|
//
|
|
}
|
|
|
|
//
|
|
// Flush to output buffer
|
|
//
|
|
if( MirIncompleteBitCount == 8 )
|
|
{
|
|
pOutputBuffer[*pOutputBufferSize] = MirIncompleteByte;
|
|
(*pOutputBufferSize) ++;
|
|
|
|
MirIncompleteBitCount = 0;
|
|
MirIncompleteByte = 0;
|
|
}
|
|
|
|
//
|
|
// Check for complete packet
|
|
//
|
|
if( pIrDev->MirFlagCount == 2 )
|
|
{
|
|
pIrDev->MirFlagCount = 0;
|
|
|
|
pIrDev->MirIncompleteBitCount = 0;
|
|
pIrDev->MirOneBitCount = 0;
|
|
pIrDev->MirIncompleteByte = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// roll over
|
|
//
|
|
pIrDev->MirIncompleteBitCount = MirIncompleteBitCount;
|
|
pIrDev->MirOneBitCount = MirOneBitCount;
|
|
pIrDev->MirIncompleteByte = MirIncompleteByte;
|
|
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveMirStepFSM
|
|
*
|
|
* Synopsis: Step the receive FSM to read in a piece of an IrDA frame.
|
|
* Strip the BOFs and EOF, and eliminate escape sequences.
|
|
*
|
|
* Arguments: pIrDev - pointer to the current IR device object
|
|
* pBytesProcessed - pointer to bytes processed
|
|
*
|
|
* Returns: TRUE after an entire frame has been read in
|
|
* FALSE otherwise
|
|
*
|
|
*****************************************************************************/
|
|
BOOLEAN
|
|
ReceiveMirStepFSM(
|
|
IN OUT PIR_DEVICE pIrDev,
|
|
OUT PULONG pBytesProcessed
|
|
)
|
|
{
|
|
ULONG rawBufPos=0, rawBytesRead=0;
|
|
BOOLEAN FrameProcessed = FALSE, ForceExit = FALSE;
|
|
UCHAR ThisChar;
|
|
PUCHAR pRawBuf, pReadBuf;
|
|
PRCV_BUFFER pRecBuf;
|
|
|
|
*pBytesProcessed = 0;
|
|
|
|
if( !pIrDev->pCurrentRecBuf )
|
|
{
|
|
UINT Index;
|
|
|
|
pRecBuf = ReceiveGetBuf( pIrDev, &Index, RCV_STATE_FULL );
|
|
if ( !pRecBuf)
|
|
{
|
|
//
|
|
// no buffers available; stop
|
|
//
|
|
DEBUGMSG(DBG_ERR, (" ReceiveMirStepFSM out of buffers\n"));
|
|
pIrDev->packetsReceivedNoBuffer ++;
|
|
return FALSE;
|
|
}
|
|
|
|
pIrDev->pCurrentRecBuf = pRecBuf;
|
|
}
|
|
else
|
|
pRecBuf = pIrDev->pCurrentRecBuf;
|
|
|
|
pReadBuf = pRecBuf->pDataBuf;
|
|
pRawBuf = pIrDev->pRawBuf;
|
|
|
|
/***********************************************/
|
|
/* Read in and process groups of incoming */
|
|
/* bytes from the FIFO. */
|
|
/***********************************************/
|
|
while( (pIrDev->rcvState != STATE_SAW_EOF) &&
|
|
(pIrDev->readBufPos <= (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + MEDIUM_IR_FCS_SIZE)) &&
|
|
!ForceExit )
|
|
{
|
|
if( pIrDev->rcvState == STATE_CLEANUP )
|
|
{
|
|
/***********************************************/
|
|
/* We returned a complete packet last time, */
|
|
/* but we had read some extra bytes, which */
|
|
/* we stored into the rawBuf after */
|
|
/* returning the previous complete buffer */
|
|
/* to the user. So instead of calling */
|
|
/* DoRcvDirect() in this first execution of */
|
|
/* this loop, we just use these previously */
|
|
/* read bytes. (This is typically only 1 or */
|
|
/* 2 bytes). */
|
|
/***********************************************/
|
|
rawBytesRead = pIrDev->rawCleanupBytesRead;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
}
|
|
else
|
|
{
|
|
if( ReceiveGetFifoData( pIrDev, pRawBuf, &rawBytesRead, STIR4200_FIFO_SIZE ) == STATUS_SUCCESS )
|
|
{
|
|
if( rawBytesRead == (ULONG)-1 )
|
|
{
|
|
/***********************************************/
|
|
/* Receive error...back to INIT state... */
|
|
/***********************************************/
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
continue;
|
|
}
|
|
else if( rawBytesRead == 0 )
|
|
{
|
|
/***********************************************/
|
|
/* No more receive bytes...break out... */
|
|
/***********************************************/
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
/***********************************************/
|
|
/* Let the receive state machine process */
|
|
/* this group of bytes. */
|
|
/* */
|
|
/* NOTE: We have to loop once more after */
|
|
/* getting MAX_RCV_DATA_SIZE bytes so that */
|
|
/* we can see the 'EOF'; hence <= and not */
|
|
/* <. */
|
|
/***********************************************/
|
|
for( rawBufPos = 0;
|
|
((pIrDev->rcvState != STATE_SAW_EOF) && (rawBufPos < rawBytesRead) &&
|
|
(pIrDev->readBufPos <= (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + MEDIUM_IR_FCS_SIZE)));
|
|
rawBufPos++ )
|
|
{
|
|
*pBytesProcessed += 1;
|
|
ThisChar = pRawBuf[rawBufPos];
|
|
switch( pIrDev->rcvState )
|
|
{
|
|
case STATE_INIT:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_MIR_BOF:
|
|
pIrDev->rcvState = STATE_GOT_MIR_BOF;
|
|
break;
|
|
case 0xFF:
|
|
if( ((rawBufPos+2) < rawBytesRead) && (rawBufPos==0) )
|
|
{
|
|
if( (pRawBuf[rawBufPos+2] == 0xFF) && (pRawBuf[rawBufPos+1] == 0xFF) )
|
|
{
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveMirStepFSM(): overflow sequence in INIT state\n"));
|
|
St4200ResetFifo( pIrDev );
|
|
St4200SoftReset( pIrDev );
|
|
//rawBufPos = rawBytesRead;
|
|
//ForceExit = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_GOT_MIR_BOF:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_MIR_BOF:
|
|
pIrDev->rcvState = STATE_GOT_BOF;
|
|
break;
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveMirStepFSM(): invalid char in BOF state, bufpos=%d\n", pIrDev->readBufPos));
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_GOT_BOF:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_MIR_BOF:
|
|
/***********************************************/
|
|
/* It's a mistake, but could still be valid data
|
|
/***********************************************/
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveMirStepFSM(): More than legal BOFs, bufpos=%d\n", pIrDev->readBufPos));
|
|
pIrDev->readBufPos = 0;
|
|
pIrDev->rcvState = STATE_GOT_BOF;
|
|
break;
|
|
case STIR4200_MIR_ESC_CHAR:
|
|
/***********************************************/
|
|
/* Start of data. Our first data byte */
|
|
/* happens to be an ESC sequence. */
|
|
/***********************************************/
|
|
pIrDev->readBufPos = 0;
|
|
pIrDev->rcvState = STATE_ESC_SEQUENCE;
|
|
break;
|
|
default:
|
|
pReadBuf[0] = ThisChar;
|
|
pIrDev->readBufPos = 1;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_ACCEPTING:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_MIR_EOF:
|
|
if( pIrDev->readBufPos < (IRDA_A_C_TOTAL_SIZE + MEDIUM_IR_FCS_SIZE) )
|
|
{
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveMirStepFSM(): WARNING: EOF encountered in short packet, bufpos=%d\n", pIrDev->readBufPos));
|
|
pIrDev->packetsReceivedRunt ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
}
|
|
else
|
|
{
|
|
pIrDev->rcvState = STATE_SAW_FIR_BOF;
|
|
}
|
|
break;
|
|
case STIR4200_MIR_ESC_CHAR:
|
|
pIrDev->rcvState = STATE_ESC_SEQUENCE;
|
|
break;
|
|
default:
|
|
pReadBuf[pIrDev->readBufPos++] = ThisChar;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_ESC_SEQUENCE:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_MIR_ESC_DATA_7D:
|
|
pReadBuf[pIrDev->readBufPos++] = 0x7d;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
case STIR4200_MIR_ESC_DATA_7E:
|
|
pReadBuf[pIrDev->readBufPos++] = 0x7e;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): invalid escaped char=%X\n", (ULONG)ThisChar));
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_SAW_MIR_BOF:
|
|
switch( ThisChar )
|
|
{
|
|
case STIR4200_MIR_EOF:
|
|
pIrDev->rcvState = STATE_SAW_EOF;
|
|
break;
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveMirStepFSM(): invalid char=%X, expected EOF\n", (ULONG)ThisChar));
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_SAW_EOF:
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveMirStepFSM(): Illegal state, bufpos=%d\n", pIrDev->readBufPos));
|
|
IRUSB_ASSERT( 0 );
|
|
pIrDev->readBufPos = 0;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// * Set result and do any post-cleanup.
|
|
switch( pIrDev->rcvState )
|
|
{
|
|
case STATE_SAW_EOF:
|
|
/***********************************************/
|
|
/* We've read in the entire packet. Queue */
|
|
/* it and return TRUE. */
|
|
/***********************************************/
|
|
pRecBuf->DataLen = pIrDev->readBufPos;
|
|
pIrDev->pCurrentRecBuf = NULL;
|
|
ReceiveDeliverBuffer(
|
|
pIrDev,
|
|
pRecBuf
|
|
);
|
|
FrameProcessed = TRUE;
|
|
if( rawBufPos < rawBytesRead )
|
|
{
|
|
/***********************************************/
|
|
/* This is ugly. We have some more */
|
|
/* unprocessed bytes in the raw buffer. */
|
|
/* Move these to the beginning of the raw */
|
|
/* buffer go to the CLEANUP state, which */
|
|
/* indicates that these bytes be used up */
|
|
/* during the next call. (This is typically */
|
|
/* only 1 or 2 bytes). */
|
|
/* */
|
|
/* Note: We can't just leave these in the */
|
|
/* raw buffer because we might be */
|
|
/* supporting connections to multiple COM */
|
|
/* ports. */
|
|
/* */
|
|
/***********************************************/
|
|
RtlMoveMemory( pRawBuf, &pRawBuf[rawBufPos], rawBytesRead - rawBufPos );
|
|
pIrDev->rawCleanupBytesRead = rawBytesRead - rawBufPos;
|
|
pIrDev->rcvState = STATE_CLEANUP;
|
|
}
|
|
else
|
|
{
|
|
pIrDev->rcvState = STATE_INIT;
|
|
}
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
default:
|
|
if( pIrDev->readBufPos > (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + MEDIUM_IR_FCS_SIZE) )
|
|
{
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveMirStepFSM() Overflow\n"));
|
|
|
|
pIrDev->packetsReceivedOverflow ++;
|
|
pIrDev->readBufPos = 0;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->pCurrentRecBuf = NULL;
|
|
InterlockedExchange( &pRecBuf->DataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
}
|
|
else
|
|
{
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveMirStepFSM(): returning with partial packet, read %d bytes\n", pIrDev->readBufPos));
|
|
#endif
|
|
}
|
|
FrameProcessed = FALSE;
|
|
break;
|
|
}
|
|
return FrameProcessed;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveSirStepFSM
|
|
*
|
|
* Synopsis: Step the receive FSM to read in a piece of an IrDA frame.
|
|
* Strip the BOFs and EOF, and eliminate escape sequences.
|
|
*
|
|
* Arguments: pIrDev - pointer to the current IR device object
|
|
* pBytesProcessed - pointer to bytes processed
|
|
*
|
|
* Returns: TRUE after an entire frame has been read in
|
|
* FALSE otherwise
|
|
*
|
|
*****************************************************************************/
|
|
BOOLEAN
|
|
ReceiveSirStepFSM(
|
|
IN OUT PIR_DEVICE pIrDev,
|
|
OUT PULONG pBytesProcessed
|
|
)
|
|
{
|
|
ULONG rawBufPos=0, rawBytesRead=0;
|
|
BOOLEAN FrameProcessed = FALSE, ForceExit = FALSE;
|
|
UCHAR ThisChar;
|
|
PUCHAR pRawBuf, pReadBuf;
|
|
PRCV_BUFFER pRecBuf;
|
|
|
|
*pBytesProcessed = 0;
|
|
|
|
if( !pIrDev->pCurrentRecBuf )
|
|
{
|
|
UINT Index;
|
|
|
|
pRecBuf = ReceiveGetBuf( pIrDev, &Index, RCV_STATE_FULL );
|
|
if ( !pRecBuf)
|
|
{
|
|
//
|
|
// no buffers available; stop
|
|
//
|
|
DEBUGMSG(DBG_ERR, (" ReceiveSirStepFSM out of buffers\n"));
|
|
pIrDev->packetsReceivedNoBuffer ++;
|
|
return FALSE;
|
|
}
|
|
|
|
pIrDev->pCurrentRecBuf = pRecBuf;
|
|
}
|
|
else
|
|
pRecBuf = pIrDev->pCurrentRecBuf;
|
|
|
|
pReadBuf = pRecBuf->pDataBuf;
|
|
pRawBuf = pIrDev->pRawBuf;
|
|
|
|
// Read in and process groups of incoming bytes from the FIFO.
|
|
// NOTE: We have to loop once more after getting MAX_RCV_DATA_SIZE
|
|
// bytes so that we can see the 'EOF'; hence <= and not <.
|
|
while( (pIrDev->rcvState != STATE_SAW_EOF) &&
|
|
(pIrDev->readBufPos <= (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + SLOW_IR_FCS_SIZE)) &&
|
|
!ForceExit )
|
|
{
|
|
if( pIrDev->rcvState == STATE_CLEANUP )
|
|
{
|
|
/***********************************************/
|
|
/* We returned a complete packet last time, */
|
|
/* but we had read some extra bytes, which */
|
|
/* we stored into the rawBuf after */
|
|
/* returning the previous complete buffer */
|
|
/* to the user. So instead of calling */
|
|
/* DoRcvDirect() in this first execution of */
|
|
/* this loop, we just use these previously */
|
|
/* read bytes. (This is typically only 1 or */
|
|
/* 2 bytes). */
|
|
/***********************************************/
|
|
rawBytesRead = pIrDev->rawCleanupBytesRead;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
}
|
|
else
|
|
{
|
|
if( ReceiveGetFifoData( pIrDev, pRawBuf, &rawBytesRead, STIR4200_FIFO_SIZE ) == STATUS_SUCCESS )
|
|
{
|
|
if( rawBytesRead == (ULONG)-1 )
|
|
{
|
|
/***********************************************/
|
|
/* Receive error...back to INIT state... */
|
|
/***********************************************/
|
|
DEBUGMSG( DBG_ERR,(" ReceiveSirStepFSM() Error in receiving packet\n"));
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
continue;
|
|
}
|
|
else if( rawBytesRead == 0 )
|
|
{
|
|
/***********************************************/
|
|
/* No more receive bytes...break out... */
|
|
/***********************************************/
|
|
#if defined(WORKAROUND_MISSING_C1)
|
|
if( (pIrDev->rcvState == STATE_ACCEPTING) && (pIrDev->ChipRevision <= CHIP_REVISION_7) )
|
|
{
|
|
pIrDev->rcvState = STATE_SAW_EOF;
|
|
DEBUGMSG(DBG_INT_ERR, (" ReceiveSirStepFSM(): Missing C1 workaround\n"));
|
|
pRecBuf->MissingC1Detected = TRUE;
|
|
}
|
|
#endif
|
|
#if defined(WORKAROUND_CASIO)
|
|
if( (pRecBuf->MissingC1Possible) &&
|
|
(pIrDev->rcvState == STATE_ACCEPTING) && (pIrDev->currentSpeed != SPEED_9600) )
|
|
{
|
|
pIrDev->rcvState = STATE_SAW_EOF;
|
|
//DEBUGMSG(DBG_INT_ERR, (" ReceiveSirStepFSM(): Missing C1 workaround\n"));
|
|
pRecBuf->MissingC1Detected = TRUE;
|
|
pRecBuf->MissingC1Possible = FALSE;
|
|
}
|
|
if( (pIrDev->rcvState == STATE_ACCEPTING) && (pIrDev->currentSpeed != SPEED_9600) )
|
|
{
|
|
pRecBuf->MissingC1Possible = TRUE;
|
|
goto no_break;
|
|
}
|
|
#endif
|
|
break;
|
|
#if defined(WORKAROUND_CASIO)
|
|
no_break: ;
|
|
#endif
|
|
}
|
|
#if defined(WORKAROUND_CASIO)
|
|
else
|
|
{
|
|
pRecBuf->MissingC1Possible = FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
/***********************************************/
|
|
/* Let the receive state machine process */
|
|
/* this group of bytes. */
|
|
/* */
|
|
/* NOTE: We have to loop once more after */
|
|
/* getting MAX_RCV_DATA_SIZE bytes so that */
|
|
/* we can see the 'EOF'; hence <= and not */
|
|
/* <. */
|
|
/***********************************************/
|
|
for( rawBufPos = 0;
|
|
((pIrDev->rcvState != STATE_SAW_EOF) && (rawBufPos < rawBytesRead) &&
|
|
(pIrDev->readBufPos <= (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + SLOW_IR_FCS_SIZE)));
|
|
rawBufPos ++ )
|
|
{
|
|
*pBytesProcessed += 1;
|
|
ThisChar = pRawBuf[rawBufPos];
|
|
switch( pIrDev->rcvState )
|
|
{
|
|
case STATE_INIT:
|
|
switch( ThisChar )
|
|
{
|
|
#if defined(WORKAROUND_FF_HANG)
|
|
case 0xFF:
|
|
if( (rawBufPos+2) < rawBytesRead )
|
|
{
|
|
if( (pRawBuf[rawBufPos+2] == 0xFF) && (pRawBuf[rawBufPos+1] == 0xFF) &&
|
|
(rawBytesRead>STIR4200_FIFO_OVERRUN_THRESHOLD) )
|
|
{
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveFirStepFSM(): overflow sequence in INIT state\n"));
|
|
St4200DoubleResetFifo( pIrDev );
|
|
rawBufPos = rawBytesRead;
|
|
ForceExit = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
#if defined( WORKAROUND_E0_81_FLAG )
|
|
// This will take care of wrong start flags at low rates
|
|
case 0x81:
|
|
case 0xe0:
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveSirStepFSM(): WORKAROUND_E0_81_FLAG\n"));
|
|
#endif
|
|
#endif
|
|
case SLOW_IR_BOF:
|
|
pIrDev->rcvState = STATE_GOT_BOF;
|
|
break;
|
|
case SLOW_IR_EOF:
|
|
case SLOW_IR_ESC:
|
|
default:
|
|
/***********************************************/
|
|
/* Byte is garbage...scan past it.... */
|
|
/***********************************************/
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveSirStepFSM(): invalid char in INIT state\n"));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_GOT_BOF:
|
|
switch( ThisChar )
|
|
{
|
|
case SLOW_IR_BOF:
|
|
break;
|
|
case SLOW_IR_EOF:
|
|
/***********************************************/
|
|
/* Garbage */
|
|
/***********************************************/
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveSirStepFSM() Invalid char in BOF state\n"));
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
case SLOW_IR_ESC:
|
|
/***********************************************/
|
|
/* Start of data. Our first data byte */
|
|
/* happens to be an ESC sequence. */
|
|
/***********************************************/
|
|
pIrDev->rcvState = STATE_ESC_SEQUENCE;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
default:
|
|
pReadBuf[0] = ThisChar;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
pIrDev->readBufPos = 1;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_ACCEPTING:
|
|
switch( ThisChar )
|
|
{
|
|
case SLOW_IR_BOF:
|
|
//
|
|
// Either a new packet is starting here and we're missing parts of the old one
|
|
// or it's garbage
|
|
//
|
|
#if !defined(WORKAROUND_MISSING_C1)
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveSirStepFSM() Invalid char in ACCEPTING state\n"));
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
#elif defined(WORKAROUND_CASIO)
|
|
pIrDev->rcvState = STATE_GOT_BOF;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
#else
|
|
//
|
|
// Take the packet and decrement the pointer in the FIFO decoding so that
|
|
// the new packet can be processed
|
|
//
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveSirStepFSM() C0 in ACCEPTING state, trying workaround\n"));
|
|
rawBufPos --;
|
|
pRecBuf->MissingC1Detected = TRUE;
|
|
#endif
|
|
case SLOW_IR_EOF:
|
|
if( pIrDev->readBufPos < (IRDA_A_C_TOTAL_SIZE + SLOW_IR_FCS_SIZE) )
|
|
{
|
|
pIrDev->packetsReceivedRunt ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
#if defined(WORKAROUND_MISSING_C1)
|
|
if( pRecBuf->MissingC1Detected )
|
|
pRecBuf->MissingC1Detected = FALSE;
|
|
else
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveSirStepFSM() Error packet too small\n"));
|
|
#else
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveSirStepFSM() Error packet too small\n"));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
pIrDev->rcvState = STATE_SAW_EOF;
|
|
}
|
|
break;
|
|
case SLOW_IR_ESC:
|
|
pIrDev->rcvState = STATE_ESC_SEQUENCE;
|
|
break;
|
|
default:
|
|
pReadBuf[pIrDev->readBufPos++] = ThisChar;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_ESC_SEQUENCE:
|
|
switch( ThisChar )
|
|
{
|
|
case SLOW_IR_EOF:
|
|
case SLOW_IR_BOF:
|
|
case SLOW_IR_ESC:
|
|
/***********************************************/
|
|
/* ESC + {EOF|BOF|ESC} is an abort sequence */
|
|
/***********************************************/
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
case SLOW_IR_EOF ^ SLOW_IR_ESC_COMP:
|
|
case SLOW_IR_BOF ^ SLOW_IR_ESC_COMP:
|
|
case SLOW_IR_ESC ^ SLOW_IR_ESC_COMP:
|
|
pReadBuf[pIrDev->readBufPos++] = ThisChar ^ SLOW_IR_ESC_COMP;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
#if defined(WORKAROUND_CASIO)
|
|
case 0xf8:
|
|
pReadBuf[pIrDev->readBufPos++] = 0xc1;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
case 0xf0:
|
|
pReadBuf[pIrDev->readBufPos++] = 0xc0;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;
|
|
/*case 0xf4:
|
|
pReadBuf[pIrDev->readBufPos++] = 0x7d;
|
|
pIrDev->rcvState = STATE_ACCEPTING;
|
|
break;*/
|
|
#endif
|
|
default:
|
|
// junk
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveSirStepFSM(): invalid escaped char=%X\n", (ULONG)ThisChar));
|
|
pIrDev->packetsReceivedDropped ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case STATE_SAW_EOF:
|
|
default:
|
|
DEBUGMSG(DBG_INT_ERR,
|
|
(" ReceiveSirStepFSM(): Illegal state, bufpos=%d\n", pIrDev->readBufPos));
|
|
IRUSB_ASSERT( 0 );
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// * Set result and do any post-cleanup.
|
|
switch( pIrDev->rcvState )
|
|
{
|
|
case STATE_SAW_EOF:
|
|
// We've read in the entire packet.
|
|
// Queue it and return TRUE.
|
|
pRecBuf->DataLen = pIrDev->readBufPos;
|
|
pIrDev->pCurrentRecBuf = NULL;
|
|
ReceiveDeliverBuffer(
|
|
pIrDev,
|
|
pRecBuf
|
|
);
|
|
FrameProcessed = TRUE;
|
|
if( rawBufPos < rawBytesRead )
|
|
{
|
|
/***********************************************/
|
|
/* This is ugly. We have some more */
|
|
/* unprocessed bytes in the raw buffer. */
|
|
/* Move these to the beginning of the raw */
|
|
/* buffer go to the CLEANUP state, which */
|
|
/* indicates that these bytes be used up */
|
|
/* during the next call. (This is typically */
|
|
/* only 1 or 2 bytes). */
|
|
/* */
|
|
/* Note: We can't just leave these in the */
|
|
/* raw buffer because we might be */
|
|
/* supporting connections to multiple COM */
|
|
/* ports. */
|
|
/* */
|
|
/***********************************************/
|
|
RtlMoveMemory( pRawBuf, &pRawBuf[rawBufPos], rawBytesRead - rawBufPos );
|
|
pIrDev->rawCleanupBytesRead = rawBytesRead - rawBufPos;
|
|
pIrDev->rcvState = STATE_CLEANUP;
|
|
#if defined( WORKAROUND_9600_ANTIBOUNCING )
|
|
if( (pIrDev->currentSpeed == SPEED_9600) && (pIrDev->ChipRevision <= CHIP_REVISION_7) )
|
|
{
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG(DBG_INT_ERR, (" ReceiveSirStepFSM(): Delaying\n"));
|
|
#endif
|
|
NdisMSleep( 10*1000 );
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
pIrDev->rcvState = STATE_INIT;
|
|
}
|
|
pIrDev->readBufPos = 0;
|
|
break;
|
|
default:
|
|
if( pIrDev->readBufPos > (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + SLOW_IR_FCS_SIZE + 1) )
|
|
{
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveSirStepFSM() Overflow\n"));
|
|
|
|
pIrDev->packetsReceivedOverflow ++;
|
|
pIrDev->rcvState = STATE_INIT;
|
|
pIrDev->readBufPos = 0;
|
|
pIrDev->pCurrentRecBuf = NULL;
|
|
InterlockedExchange( &pRecBuf->DataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
}
|
|
else if( pIrDev->readBufPos == (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + SLOW_IR_FCS_SIZE + 1) )
|
|
{
|
|
//DEBUGMSG( DBG_INT_ERR,(" ReceiveSirStepFSM() Overflow Workaround\n"));
|
|
|
|
//
|
|
// Try patching up
|
|
//
|
|
pRecBuf->DataLen = pIrDev->readBufPos-1;
|
|
pIrDev->pCurrentRecBuf = NULL;
|
|
ReceiveDeliverBuffer(
|
|
pIrDev,
|
|
pRecBuf
|
|
);
|
|
FrameProcessed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG(DBG_INT_ERR, (" ReceiveSirStepFSM(): returning with partial packet, read %d bytes\n", pIrDev->readBufPos));
|
|
#endif
|
|
}
|
|
FrameProcessed = FALSE;
|
|
break;
|
|
}
|
|
return FrameProcessed;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveProcessReturnPacket
|
|
*
|
|
* Synopsis: Returns the packet to the free pool after preparing for reuse
|
|
*
|
|
* Arguments: pThisDev - pointer to the current ir device object
|
|
* pReceiveBuffer - pointer to a RCV_BUFFER struct
|
|
*
|
|
* Returns: None
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
VOID
|
|
ReceiveProcessReturnPacket(
|
|
OUT PIR_DEVICE pThisDev,
|
|
OUT PRCV_BUFFER pReceiveBuffer
|
|
)
|
|
{
|
|
PNDIS_BUFFER pBuffer;
|
|
|
|
DEBUGONCE(DBG_FUNC, ("+ReceiveProcessReturnPacket\n"));
|
|
|
|
//
|
|
// Deallocate the buffer
|
|
//
|
|
NdisUnchainBufferAtFront( (PNDIS_PACKET)pReceiveBuffer->pPacket, &pBuffer );
|
|
IRUSB_ASSERT( pBuffer );
|
|
if( pBuffer )
|
|
{
|
|
NdisFreeBuffer( pBuffer );
|
|
}
|
|
|
|
//
|
|
// Get ready to reuse
|
|
//
|
|
InterlockedExchange( &pReceiveBuffer->DataLen, 0 );
|
|
InterlockedExchange( &pReceiveBuffer->fInRcvDpc, FALSE );
|
|
InterlockedExchange( (PULONG)&pReceiveBuffer->BufferState, RCV_STATE_FREE );
|
|
|
|
#if DBG
|
|
if( InterlockedDecrement(&pThisDev->packetsHeldByProtocol)<0 )
|
|
{
|
|
IRUSB_ASSERT(0);
|
|
}
|
|
#endif
|
|
|
|
DEBUGMSG(DBG_FUNC, ("-ReceiveProcessReturnPacket\n"));
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveDeliverBuffer
|
|
*
|
|
* Synopsis: Delivers the buffer to the protocol via
|
|
* NdisMIndicateReceivePacket.
|
|
*
|
|
* Arguments: pThisDev - pointer to the current ir device object
|
|
* pRecBuf - poiter to descriptor to deliver
|
|
*
|
|
* Returns: None
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
VOID
|
|
ReceiveDeliverBuffer(
|
|
IN OUT PIR_DEVICE pThisDev,
|
|
IN PRCV_BUFFER pRecBuf
|
|
)
|
|
{
|
|
PNDIS_BUFFER pBuffer;
|
|
NDIS_STATUS Status;
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+ReceiveDeliverBuffer\n"));
|
|
|
|
if( pThisDev->currentSpeed <= MAX_MIR_SPEED )
|
|
{
|
|
USHORT sirfcs;
|
|
|
|
/***********************************************/
|
|
/* The packet we have already has had BOFs, */
|
|
/* EOF, and * escape-sequences removed. It */
|
|
/* contains an FCS code at the end, which */
|
|
/* we need to verify and then remove before */
|
|
/* delivering the frame. We compute the FCS */
|
|
/* on the packet with the packet FCS */
|
|
/* attached; this should produce the */
|
|
/* constant value GOOD_FCS. */
|
|
/***********************************************/
|
|
if( (sirfcs = ComputeFCS16(pRecBuf->pDataBuf, pRecBuf->DataLen)) != GOOD_FCS )
|
|
{
|
|
#if !defined(WORKAROUND_EXTRA_BYTE) && !defined(WORKAROUND_MISSING_C1)
|
|
//
|
|
// FCS error...drop frame...
|
|
//
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveDeliverBuffer(): Bad FCS, size: %d\n",pRecBuf->DataLen));
|
|
pThisDev->packetsReceivedChecksum ++;
|
|
InterlockedExchange( &pRecBuf->DataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
goto done;
|
|
#else
|
|
//
|
|
// Calculate again stripping off the last byte
|
|
//
|
|
if( pRecBuf->MissingC1Detected )
|
|
{
|
|
if( (sirfcs = ComputeFCS16(pRecBuf->pDataBuf, pRecBuf->DataLen-1)) != GOOD_FCS )
|
|
{
|
|
#if defined(RECEIVE_ERROR_LOGGING)
|
|
if( pThisDev->ReceiveErrorFileHandle )
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
ZwWriteFile(
|
|
pThisDev->ReceiveErrorFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
pRecBuf->pDataBuf,
|
|
pRecBuf->DataLen,
|
|
(PLARGE_INTEGER)&pThisDev->ReceiveErrorFilePosition,
|
|
NULL
|
|
);
|
|
|
|
pThisDev->ReceiveErrorFilePosition += pRecBuf->DataLen;
|
|
}
|
|
#endif
|
|
//
|
|
// It is really junk
|
|
//
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveDeliverBuffer(): Bad FCS, size: %d\n",pRecBuf->DataLen));
|
|
pThisDev->packetsReceivedChecksum ++;
|
|
InterlockedExchange( &pRecBuf->DataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
pRecBuf->MissingC1Detected = FALSE;
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Readjust to get rid of the extra byte
|
|
//
|
|
pRecBuf->DataLen --;
|
|
pRecBuf->MissingC1Detected = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Or maybe the first one
|
|
//
|
|
if( (sirfcs = ComputeFCS16(pRecBuf->pDataBuf+1, pRecBuf->DataLen-1)) != GOOD_FCS )
|
|
{
|
|
#if defined(RECEIVE_ERROR_LOGGING)
|
|
if( pThisDev->ReceiveErrorFileHandle )
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
ZwWriteFile(
|
|
pThisDev->ReceiveErrorFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
pRecBuf->pDataBuf,
|
|
pRecBuf->DataLen,
|
|
(PLARGE_INTEGER)&pThisDev->ReceiveErrorFilePosition,
|
|
NULL
|
|
);
|
|
|
|
pThisDev->ReceiveErrorFilePosition += pRecBuf->DataLen;
|
|
}
|
|
#endif
|
|
//
|
|
// It is really junk
|
|
//
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveDeliverBuffer(): Bad FCS, size: %d\n",pRecBuf->DataLen));
|
|
pThisDev->packetsReceivedChecksum ++;
|
|
InterlockedExchange( &pRecBuf->DataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
goto done;
|
|
}
|
|
//
|
|
else
|
|
{
|
|
//
|
|
// Readjust to get rid of the extra byte
|
|
//
|
|
pRecBuf->DataLen --;
|
|
RtlMoveMemory( pRecBuf->pDataBuf, &pRecBuf->pDataBuf[1], pRecBuf->DataLen );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/***********************************************/
|
|
/* Remove FCS from end of packet... */
|
|
/***********************************************/
|
|
pRecBuf->DataLen -= SLOW_IR_FCS_SIZE;
|
|
}
|
|
else
|
|
{
|
|
LONG firfcs;
|
|
|
|
#if !defined(WORKAROUND_33_HANG)
|
|
if( (firfcs = ComputeFCS32(pRecBuf->dataBuf, pRecBuf->dataLen)) != FIR_GOOD_FCS )
|
|
{
|
|
/***********************************************/
|
|
/* FCS error...drop frame... */
|
|
/***********************************************/
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveDeliverBuffer(): Bad FCS, size: %d\n",pRecBuf->dataLen));
|
|
pThisDev->packetsReceivedChecksum ++;
|
|
InterlockedExchange( &pRecBuf->dataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->state, RCV_STATE_FREE );
|
|
goto done;
|
|
}
|
|
#else
|
|
if( (firfcs = ComputeFCS32(pRecBuf->pDataBuf, pRecBuf->DataLen)) != FIR_GOOD_FCS )
|
|
{
|
|
NTSTATUS rc;
|
|
|
|
//
|
|
// Try again with the data stuffed with 0x33
|
|
//
|
|
if( pRecBuf->DataLen < (MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE) )
|
|
{
|
|
pRecBuf->pDataBuf[pRecBuf->DataLen] = 0x33;
|
|
pRecBuf->DataLen ++;
|
|
|
|
if( (firfcs = ComputeFCS32(pRecBuf->pDataBuf, pRecBuf->DataLen)) != FIR_GOOD_FCS )
|
|
{
|
|
#if defined(RECEIVE_ERROR_LOGGING)
|
|
if( pThisDev->ReceiveErrorFileHandle )
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
ZwWriteFile(
|
|
pThisDev->ReceiveErrorFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
pRecBuf->pDataBuf,
|
|
pRecBuf->DataLen,
|
|
(PLARGE_INTEGER)&pThisDev->ReceiveErrorFilePosition,
|
|
NULL
|
|
);
|
|
|
|
pThisDev->ReceiveErrorFilePosition += pRecBuf->DataLen;
|
|
}
|
|
#endif
|
|
/***********************************************/
|
|
/* FCS error...drop frame... */
|
|
/***********************************************/
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveDeliverBuffer(): Bad FCS, size: %d\n",pRecBuf->DataLen));
|
|
pThisDev->ReceiveAdaptiveDelayBoost += STIR4200_DELTA_DELAY;
|
|
if( pThisDev->ReceiveAdaptiveDelayBoost <= STIR4200_MAX_BOOST_DELAY )
|
|
pThisDev->ReceiveAdaptiveDelay += STIR4200_DELTA_DELAY;
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveDeliverBuffer(): Delay: %d\n",pThisDev->ReceiveAdaptiveDelay));
|
|
pThisDev->packetsReceivedChecksum ++;
|
|
InterlockedExchange( &pRecBuf->DataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if defined(RECEIVE_ERROR_LOGGING)
|
|
if( pThisDev->ReceiveErrorFileHandle )
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
ZwWriteFile(
|
|
pThisDev->ReceiveErrorFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
pRecBuf->pDataBuf,
|
|
pRecBuf->DataLen,
|
|
(PLARGE_INTEGER)&pThisDev->ReceiveErrorFilePosition,
|
|
NULL
|
|
);
|
|
|
|
pThisDev->ReceiveErrorFilePosition += pRecBuf->DataLen;
|
|
}
|
|
#endif
|
|
/***********************************************/
|
|
/* FCS error...drop frame... */
|
|
/***********************************************/
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveDeliverBuffer(): Bad FCS, size: %d\n",pRecBuf->DataLen));
|
|
pThisDev->ReceiveAdaptiveDelayBoost += STIR4200_DELTA_DELAY;
|
|
if( pThisDev->ReceiveAdaptiveDelayBoost <= STIR4200_MAX_BOOST_DELAY )
|
|
pThisDev->ReceiveAdaptiveDelay += STIR4200_DELTA_DELAY;
|
|
DEBUGMSG( DBG_INT_ERR,(" ReceiveDeliverBuffer(): Delay: %d\n",pThisDev->ReceiveAdaptiveDelay));
|
|
pThisDev->packetsReceivedChecksum ++;
|
|
InterlockedExchange( &pRecBuf->DataLen, 0 );
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Reset the USB of the part
|
|
//
|
|
if( pThisDev->ChipRevision <= CHIP_REVISION_7 )
|
|
{
|
|
St4200ResetFifo( pThisDev );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***********************************************/
|
|
/* Remove FCS from end of packet... */
|
|
/***********************************************/
|
|
pRecBuf->DataLen -= FAST_IR_FCS_SIZE;
|
|
}
|
|
|
|
//
|
|
// If in normal mode, give the packet to the protocol
|
|
//
|
|
#if defined(DIAGS)
|
|
if( !pThisDev->DiagsActive )
|
|
{
|
|
#endif
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&pBuffer,
|
|
pThisDev->hBufferPool,
|
|
(PVOID)pRecBuf->pDataBuf,
|
|
pRecBuf->DataLen
|
|
);
|
|
|
|
if( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
DEBUGMSG( DBG_ERR,(" ReceiveDeliverBuffer(): No packets available...\n"));
|
|
InterlockedExchange( &pRecBuf->DataLen, 0);
|
|
InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
|
|
goto done;
|
|
}
|
|
|
|
NdisChainBufferAtFront( (PNDIS_PACKET)pRecBuf->pPacket, pBuffer );
|
|
|
|
//
|
|
// Fix up some other packet fields.
|
|
// Remember, we only account for A and C fields
|
|
//
|
|
NDIS_SET_PACKET_HEADER_SIZE(
|
|
(PNDIS_PACKET)pRecBuf->pPacket,
|
|
IRDA_CONTROL_FIELD_SIZE + IRDA_ADDRESS_FIELD_SIZE
|
|
);
|
|
|
|
#if DBG
|
|
InterlockedIncrement( &pThisDev->packetsHeldByProtocol );
|
|
if( pThisDev->packetsHeldByProtocol > pThisDev->MaxPacketsHeldByProtocol )
|
|
{
|
|
pThisDev->MaxPacketsHeldByProtocol = pThisDev->packetsHeldByProtocol; //keep record of our longest attained len
|
|
}
|
|
#endif
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG( DBG_INT_ERR,
|
|
(" ReceiveDeliverBuffer() Handed packet to protocol, size: %d\n", pRecBuf->DataLen ));
|
|
#endif
|
|
|
|
//
|
|
// Indicate the packet to NDIS
|
|
//
|
|
NDIS_SET_PACKET_STATUS( (PNDIS_PACKET)pRecBuf->pPacket, NDIS_STATUS_PENDING );
|
|
InterlockedExchange( &pRecBuf->fInRcvDpc, TRUE );
|
|
NdisMIndicateReceivePacket(
|
|
pThisDev->hNdisAdapter,
|
|
&((PNDIS_PACKET)pRecBuf->pPacket),
|
|
1
|
|
);
|
|
|
|
//
|
|
// Check to see if the packet is not pending (patch for 98)
|
|
//
|
|
#if defined(LEGACY_NDIS5)
|
|
Status = NDIS_GET_PACKET_STATUS( (PNDIS_PACKET)pRecBuf->pPacket );
|
|
if( (Status == NDIS_STATUS_SUCCESS) || (Status == NDIS_STATUS_RESOURCES) )
|
|
{
|
|
ReceiveProcessReturnPacket( pThisDev, pRecBuf ) ;
|
|
}
|
|
#endif
|
|
#if defined(DIAGS)
|
|
}
|
|
//
|
|
// Do a diagnostic receive
|
|
//
|
|
else
|
|
{
|
|
#if !defined(ONLY_ERROR_MESSAGES)
|
|
DEBUGMSG( DBG_INT_ERR,
|
|
(" ReceiveDeliverBuffer() Queued packet, size: %d\n", pRecBuf->DataLen ));
|
|
#endif
|
|
//
|
|
// Put the buffer in the diagnostic queue
|
|
//
|
|
ExInterlockedInsertTailList(
|
|
&pThisDev->DiagsReceiveQueue,
|
|
&pRecBuf->ListEntry,
|
|
&pThisDev->DiagsReceiveLock
|
|
);
|
|
}
|
|
#endif
|
|
|
|
done:
|
|
DEBUGMSG(DBG_FUNC, ("-ReceiveDeliverBuffer\n"));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: StIrUsbReturnPacket
|
|
*
|
|
* Synopsis: The protocol returns ownership of a receive packet to
|
|
* the ir device object.
|
|
*
|
|
* Arguments: Context - a pointer to the current ir device obect.
|
|
* pReturnedPacket - a pointer the packet which the protocol
|
|
* is returning ownership.
|
|
*
|
|
* Returns: None.
|
|
*
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
VOID
|
|
StIrUsbReturnPacket(
|
|
IN OUT NDIS_HANDLE Context,
|
|
IN OUT PNDIS_PACKET pReturnedPacket
|
|
)
|
|
{
|
|
PIR_DEVICE pThisDev;
|
|
PNDIS_BUFFER pBuffer;
|
|
PRCV_BUFFER pRecBuffer;
|
|
UINT Index;
|
|
BOOLEAN found = FALSE;
|
|
|
|
DEBUGONCE(DBG_FUNC, ("+StIrUsbReturnPacket\n"));
|
|
|
|
//
|
|
// The context is just the pointer to the current ir device object.
|
|
//
|
|
pThisDev = CONTEXT_TO_DEV( Context );
|
|
|
|
NdisInterlockedIncrement( (PLONG)&pThisDev->packetsReceived );
|
|
|
|
//
|
|
// Search the queue to find the right packet.
|
|
//
|
|
for( Index=0; Index < NUM_RCV_BUFS; Index ++ )
|
|
{
|
|
pRecBuffer = &(pThisDev->rcvBufs[Index]);
|
|
|
|
if( ((PNDIS_PACKET) pRecBuffer->pPacket) == pReturnedPacket )
|
|
{
|
|
if( pRecBuffer->fInRcvDpc )
|
|
{
|
|
ReceiveProcessReturnPacket( pThisDev, pRecBuffer );
|
|
found = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" StIrUsbReturnPacket, queues are corrupt\n"));
|
|
IRUSB_ASSERT( 0 );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ensure that the packet was found.
|
|
//
|
|
IRUSB_ASSERT( found );
|
|
|
|
DEBUGMSG(DBG_FUNC, ("-StIrUsbReturnPacket\n"));
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveGetBuf
|
|
*
|
|
* Synopsis: Gets a receive buffer
|
|
*
|
|
* Arguments: pThisDev - a pointer to the current ir device obect
|
|
* pIndex - pointer to return the buffer index
|
|
* state - state to set the buffer to
|
|
*
|
|
* Returns: buffer
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
PRCV_BUFFER
|
|
ReceiveGetBuf(
|
|
IN PIR_DEVICE pThisDev,
|
|
OUT PUINT pIndex,
|
|
IN RCV_BUFFER_STATE BufferState
|
|
)
|
|
{
|
|
UINT Index;
|
|
PRCV_BUFFER pBuf = NULL;
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+ReceiveGetBuf()\n"));
|
|
|
|
//
|
|
// Look for a free buffer to return
|
|
//
|
|
for( Index=0; Index<NUM_RCV_BUFS; Index++ )
|
|
{
|
|
if( pThisDev->rcvBufs[Index].BufferState == RCV_STATE_FREE )
|
|
{
|
|
//
|
|
// set to input state
|
|
//
|
|
InterlockedExchange( (PULONG)&pThisDev->rcvBufs[Index].BufferState, (ULONG)BufferState );
|
|
*pIndex = Index;
|
|
pBuf = &(pThisDev->rcvBufs[*pIndex]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DEBUGMSG(DBG_FUNC, ("-ReceiveGetBuf()\n"));
|
|
return pBuf;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceivePacketRead
|
|
*
|
|
* Synopsis: Reads a packet from the US device
|
|
* the inbound USB header, check for overrun,
|
|
* deliver to the protocol
|
|
*
|
|
* Arguments: pThisDev - pointer to the current ir device object
|
|
* pRecBuf - pointer to a RCV_BUFFER struct
|
|
*
|
|
* Returns: NT status code
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
NTSTATUS
|
|
ReceivePacketRead(
|
|
IN PIR_DEVICE pThisDev,
|
|
OUT PFIFO_BUFFER pRecBuf
|
|
)
|
|
{
|
|
ULONG UrbSize;
|
|
ULONG TransferLength;
|
|
PURB pUrb = NULL;
|
|
PDEVICE_OBJECT pUrbTargetDev;
|
|
PIO_STACK_LOCATION pNextStack;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+ReceivePacketRead()\n"));
|
|
|
|
IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
|
|
|
|
UrbSize = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
|
|
TransferLength = STIR4200_FIFO_SIZE;
|
|
|
|
//
|
|
// Stop if a halt/reset/suspend is going on
|
|
//
|
|
if( pThisDev->fPendingReadClearStall || pThisDev->fPendingHalt ||
|
|
pThisDev->fPendingReset || pThisDev->fPendingClearTotalStall || !pThisDev->fProcessing )
|
|
{
|
|
//
|
|
// USB reset going on?
|
|
//
|
|
DEBUGMSG( DBG_ERR,(" ReceivePacketRead() rejecting a packet due to pendig halt/reset\n"));
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// MS Security recommendation - allocate a new urb.
|
|
//
|
|
pRecBuf->UrbLen = UrbSize;
|
|
pRecBuf->pUrb = MyUrbAlloc(pRecBuf->UrbLen);
|
|
if (pRecBuf->pUrb == NULL)
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" ReceivePacketRead abort due to urb alloc failure\n"));
|
|
goto done;
|
|
}
|
|
pUrb = pRecBuf->pUrb;
|
|
|
|
IRUSB_ASSERT( pThisDev->BulkInPipeHandle );
|
|
|
|
//
|
|
// Now that we have created the urb, we will send a
|
|
// request to the USB device object.
|
|
//
|
|
KeClearEvent( &pThisDev->EventSyncUrb );
|
|
|
|
pUrbTargetDev = pThisDev->pUsbDevObj;
|
|
|
|
IRUSB_ASSERT( pUrbTargetDev );
|
|
|
|
//
|
|
// make an irp sending to usbhub
|
|
//
|
|
pRecBuf->pIrp = IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
|
|
|
|
if( NULL == pRecBuf->pIrp )
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" read failed to alloc IRP\n"));
|
|
MyUrbFree(pRecBuf->pUrb, pRecBuf->UrbLen);
|
|
pRecBuf->pUrb = NULL;
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
((PIRP)pRecBuf->pIrp)->IoStatus.Status = STATUS_PENDING;
|
|
((PIRP)pRecBuf->pIrp)->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Build our URB for USBD
|
|
//
|
|
pUrb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)UrbSize;
|
|
pUrb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
|
|
pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkInPipeHandle;
|
|
pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN ;
|
|
|
|
//
|
|
// short packet is not treated as an error.
|
|
//
|
|
pUrb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
|
|
|
|
//
|
|
// not using linked urb's
|
|
//
|
|
pUrb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
|
|
pUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
|
|
pUrb->UrbBulkOrInterruptTransfer.TransferBuffer = pRecBuf->pDataBuf;
|
|
pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = TransferLength;
|
|
|
|
//
|
|
// Call the class driver to perform the operation.
|
|
//
|
|
pNextStack = IoGetNextIrpStackLocation( (PIRP)pRecBuf->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)pRecBuf->pIrp), // irp to use
|
|
ReceiveCompletePacketRead, // routine to call when irp is done
|
|
pRecBuf, // context to pass routine is the RCV_BUFFER
|
|
TRUE, // call on success
|
|
TRUE, // call on error
|
|
TRUE // call on cancel
|
|
);
|
|
|
|
//
|
|
// Call IoCallDriver to send the irp to the usb port.
|
|
//
|
|
InterlockedExchange( (PLONG)&pRecBuf->BufferState, RCV_STATE_PENDING );
|
|
Status = MyIoCallDriver( pThisDev, pUrbTargetDev, (PIRP)pRecBuf->pIrp ); // Start UsbRead()
|
|
|
|
DEBUGMSG(DBG_FUNC, (" ReceivePacketRead() after IoCallDriver () status = 0x%x\n", Status));
|
|
|
|
IRUSB_ASSERT( STATUS_SUCCESS != Status );
|
|
|
|
//
|
|
// Wait for completion
|
|
//
|
|
Status = MyKeWaitForSingleObject(
|
|
pThisDev,
|
|
&pThisDev->EventSyncUrb, // event to wait on
|
|
0
|
|
);
|
|
|
|
if( Status == STATUS_TIMEOUT )
|
|
{
|
|
// MS Security recommendation - cannot cancel IRP.
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update the status to reflect the real return code
|
|
//
|
|
Status = pThisDev->StatusSendReceive;
|
|
}
|
|
|
|
IRUSB_ASSERT( NULL == pRecBuf->pIrp ); // Will be nulled by completion routine
|
|
DEBUGMSG(DBG_FUNC, (" ReceivePacketRead() after KeWaitForSingleObject() Status = 0x%x\n", Status));
|
|
|
|
done:
|
|
DEBUGMSG(DBG_FUNC, ("-ReceivePacketRead()\n"));
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: ReceiveCompletePacketRead
|
|
*
|
|
* Synopsis: Completes USB read 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
|
|
ReceiveCompletePacketRead(
|
|
IN PDEVICE_OBJECT pUsbDevObj,
|
|
IN PIRP pIrp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PIR_DEVICE pThisDev;
|
|
NTSTATUS status;
|
|
ULONG_PTR BytesRead;
|
|
PFIFO_BUFFER pFifoBuf;
|
|
PURB pUrb;
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+ReceiveCompletePacketRead\n"));
|
|
|
|
//
|
|
// The context given to ReceiveCompletePacketRead is the receive buffer object
|
|
//
|
|
pFifoBuf = (PFIFO_BUFFER)Context;
|
|
|
|
pThisDev = (PIR_DEVICE)pFifoBuf->pThisDev;
|
|
|
|
IRUSB_ASSERT( pFifoBuf->pIrp == pIrp );
|
|
|
|
IRUSB_ASSERT( NULL != pThisDev );
|
|
|
|
pUrb = pFifoBuf->pUrb;
|
|
IRUSB_ASSERT( pUrb != NULL );
|
|
|
|
//
|
|
// We have a number of cases:
|
|
// 1) The USB read timed out and we received no data.
|
|
// 2) The USB read timed out and we received some data.
|
|
// 3) The USB read was successful and fully filled our irp buffer.
|
|
// 4) The irp was cancelled.
|
|
// 5) Some other failure from the USB device object.
|
|
//
|
|
status = pIrp->IoStatus.Status;
|
|
|
|
//
|
|
// IoCallDriver has been called on this Irp;
|
|
// Set the length based on the TransferBufferLength
|
|
// value in the URB
|
|
//
|
|
pIrp->IoStatus.Information = pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
|
|
|
|
BytesRead = pIrp->IoStatus.Information;
|
|
|
|
DEBUGMSG(DBG_FUNC, (" ReceiveCompletePacketRead Bytes Read = 0x%x, dec %d\n", BytesRead,BytesRead ));
|
|
|
|
switch( status )
|
|
{
|
|
case STATUS_SUCCESS:
|
|
DEBUGMSG(DBG_FUNC, (" ReceiveCompletePacketRead STATUS_SUCCESS\n"));
|
|
|
|
if( BytesRead > 0 )
|
|
{
|
|
pFifoBuf->DataLen = (UINT)pIrp->IoStatus.Information;
|
|
}
|
|
break; // STATUS_SUCCESS
|
|
|
|
case STATUS_TIMEOUT:
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
|
|
DEBUGMSG(DBG_FUNC, (" ReceiveCompletePacketRead STATUS_TIMEOUT\n"));
|
|
break;
|
|
|
|
case STATUS_PENDING:
|
|
DEBUGMSG(DBG_FUNC, (" ReceiveCompletePacketRead STATUS_PENDING\n"));
|
|
break;
|
|
|
|
case STATUS_DEVICE_DATA_ERROR:
|
|
// can get during shutdown
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
|
|
DEBUGMSG(DBG_FUNC, (" ReceiveCompletePacketRead STATUS_DEVICE_DATA_ERROR\n"));
|
|
break;
|
|
|
|
case STATUS_UNSUCCESSFUL:
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
|
|
DEBUGMSG(DBG_ERR, (" ReceiveCompletePacketRead STATUS_UNSUCCESSFUL\n"));
|
|
break;
|
|
|
|
case STATUS_INSUFFICIENT_RESOURCES:
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
|
|
DEBUGMSG(DBG_ERR, (" ReceiveCompletePacketRead STATUS_INSUFFICIENT_RESOURCES\n"));
|
|
break;
|
|
case STATUS_INVALID_PARAMETER:
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
|
|
DEBUGMSG(DBG_ERR, (" ReceiveCompletePacketRead STATUS_INVALID_PARAMETER\n"));
|
|
break;
|
|
|
|
case STATUS_CANCELLED:
|
|
DEBUGMSG(DBG_FUNC, (" ReceiveCompletePacketRead STATUS_CANCELLED\n"));
|
|
break;
|
|
|
|
case STATUS_DEVICE_NOT_CONNECTED:
|
|
// can get during shutdown
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
|
|
DEBUGMSG(DBG_ERR, (" ReceiveCompletePacketRead STATUS_DEVICE_NOT_CONNECTED\n"));
|
|
break;
|
|
|
|
case STATUS_DEVICE_POWER_FAILURE:
|
|
// can get during shutdown
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
|
|
DEBUGMSG(DBG_ERR, (" ReceiveCompletePacketRead STATUS_DEVICE_POWER_FAILURE\n"));
|
|
break;
|
|
|
|
default:
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
|
|
DEBUGMSG(DBG_ERR, (" ReceiveCompletePacketRead UNKNOWN WEIRD STATUS = 0x%x, dec %d\n",status,status ));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// change the status
|
|
//
|
|
if( STATUS_SUCCESS != status )
|
|
{
|
|
InterlockedExchange( (PLONG)&pFifoBuf->BufferState, RCV_STATE_FREE );
|
|
}
|
|
else
|
|
{
|
|
InterlockedExchange( (PLONG)&pFifoBuf->BufferState, RCV_STATE_FULL );
|
|
}
|
|
|
|
//
|
|
// Free the IRP and its mdl because they were allocated by us
|
|
//
|
|
IoFreeIrp( pIrp );
|
|
pFifoBuf->pIrp = NULL;
|
|
InterlockedIncrement( (PLONG)&pThisDev->NumReads );
|
|
|
|
//
|
|
// we will track count of pending irps
|
|
//
|
|
IrUsb_DecIoCount( pThisDev );
|
|
|
|
if( ( STATUS_SUCCESS != status ) && ( STATUS_CANCELLED != status ) &&
|
|
( STATUS_DEVICE_NOT_CONNECTED != status ) )
|
|
{
|
|
PURB urb = pFifoBuf->pUrb;
|
|
|
|
DEBUGMSG(DBG_ERR, (" USBD status = 0x%x\n", urb->UrbHeader.Status));
|
|
DEBUGMSG(DBG_ERR, (" NT status = 0x%x\n", status));
|
|
|
|
if( !pThisDev->fPendingReadClearStall && !pThisDev->fPendingClearTotalStall &&
|
|
!pThisDev->fPendingHalt && !pThisDev->fPendingReset && pThisDev->fProcessing )
|
|
{
|
|
DEBUGMSG(DBG_ERR,
|
|
(" ReceiveCompletePacketRead error, will schedule a clear stall via URB_FUNCTION_RESET_PIPE (IN)\n"));
|
|
InterlockedExchange( &pThisDev->fPendingReadClearStall, TRUE );
|
|
ScheduleWorkItem( pThisDev, ResetPipeCallback, pThisDev->BulkInPipeHandle, 0 );
|
|
}
|
|
}
|
|
|
|
// Free the URB.
|
|
MyUrbFree(pFifoBuf->pUrb, pFifoBuf->UrbLen);
|
|
pFifoBuf->pUrb = NULL;
|
|
|
|
//
|
|
// This will only work as long as we serialize the access to the hardware
|
|
//
|
|
pThisDev->StatusSendReceive = status;
|
|
|
|
//
|
|
// Signal completion
|
|
//
|
|
KeSetEvent( &pThisDev->EventSyncUrb, 0, FALSE );
|
|
|
|
//
|
|
// We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
|
|
// routine (IoCompleteRequest) will stop working on the irp.
|
|
//
|
|
DEBUGMSG(DBG_FUNC, ("-ReceiveCompletePacketRead\n"));
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|