|
|
/*****************************************************************************
* * Copyright (c) 1996-1999 Microsoft Corporation * * @doc * @module receive.c | IrSIR NDIS Miniport Driver * @comm * *----------------------------------------------------------------------------- * * Author: Scott Holden (sholden) * * Date: 10/4/1996 (created) * * Contents: * *****************************************************************************/
#include "irsir.h"
VOID SetSpeedCallback( PIR_WORK_ITEM pWorkItem );
#if LOGGING
ULONG LogIndex = 0; LOG Log[NUM_LOG]; #endif
#ifdef DEBUG_IRSIR
static ULONG_PTR irpCount; static ULONG_PTR bytesReceived;
#endif //DEBUG_IRSIR
//
// Declarations.
//
NTSTATUS SerialIoCompleteRead( IN PDEVICE_OBJECT pSerialDevObj, IN PIRP pIrp, IN PVOID Context ); NTSTATUS SerialIoCompleteWait( IN PDEVICE_OBJECT pSerialDevObj, IN PIRP pIrp, IN PVOID Context );
NTSTATUS ProcessData( IN PIR_DEVICE pThisDev, IN PUCHAR rawBuffer, IN UINT rawBytesRead ); VOID DeliverBuffer( IN PIR_DEVICE pThisDev );
VOID StartSerialReadCallback(PIR_WORK_ITEM pWorkItem);
#pragma alloc_text(PAGE,SetSpeedCallback)
#pragma alloc_text(PAGE,StartSerialReadCallback)
VOID DBG_PrintBuf(PUCHAR bufptr, UINT buflen) { UINT i, linei;
#define ISPRINT(ch) (((ch) >= ' ') && ((ch) <= '~'))
#define PRINTCHAR(ch) (UCHAR)(ISPRINT(ch) ? (ch) : '.')
DbgPrint("\r\n %d bytes @%x:", buflen, bufptr);
/*
* Print whole lines of 8 characters with HEX and ASCII */ for (i = 0; i+8 <= buflen; i += 8) { UCHAR ch0 = bufptr[i+0], ch1 = bufptr[i+1], ch2 = bufptr[i+2], ch3 = bufptr[i+3], ch4 = bufptr[i+4], ch5 = bufptr[i+5], ch6 = bufptr[i+6], ch7 = bufptr[i+7];
DbgPrint("\r\n %02x %02x %02x %02x %02x %02x %02x %02x" " %c %c %c %c %c %c %c %c", ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7, PRINTCHAR(ch0), PRINTCHAR(ch1), PRINTCHAR(ch2), PRINTCHAR(ch3), PRINTCHAR(ch4), PRINTCHAR(ch5), PRINTCHAR(ch6), PRINTCHAR(ch7)); }
/*
* Print final incomplete line */ DbgPrint("\r\n "); for (linei = 0; (linei < 8) && (i < buflen); i++, linei++){ DbgPrint(" %02x", (UINT)(bufptr[i])); }
DbgPrint(" "); i -= linei; while (linei++ < 8) DbgPrint(" ");
for (linei = 0; (linei < 8) && (i < buflen); i++, linei++){ UCHAR ch = bufptr[i]; DbgPrint(" %c", PRINTCHAR(ch)); }
DbgPrint("\t\t<>\r\n");
}
NTSTATUS StartSerialRead(IN PIR_DEVICE pThisDev) /*++
Routine Description:
Allocates an irp and calls the serial driver.
Arguments:
pThisDev - Current IR device.
Return Value:
STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
--*/ { NTSTATUS Status; PIRP pIrp;
LOG_ENTRY('SR', pThisDev, 0, 0);
#if DBG
NdisZeroMemory( pThisDev->pRcvIrpBuffer, SERIAL_RECEIVE_BUFFER_LENGTH ); #endif
//
// Now that we have processed the irp, we will send another read
// request to the serial device object.
//
pIrp = SerialBuildReadWriteIrp( pThisDev->pSerialDevObj, IRP_MJ_READ, pThisDev->pRcvIrpBuffer, SERIAL_RECEIVE_BUFFER_LENGTH, NULL );
if (pIrp == NULL) { DEBUGMSG(DBG_ERR, (" SerialBuildReadWriteIrp failed.\n"));
Status = STATUS_INSUFFICIENT_RESOURCES;
pThisDev->fReceiving = FALSE;
goto done; }
//
// Set up the io completion routine for the irp.
//
IoSetCompletionRoutine( pIrp, // irp to use
SerialIoCompleteRead, // routine to call when irp is done
DEV_TO_CONTEXT(pThisDev), // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Call IoCallDriver to send the irp to the serial port.
//
LOG_ENTRY('2I', pThisDev, pIrp, 0); IoCallDriver( pThisDev->pSerialDevObj, pIrp );
Status=STATUS_PENDING;
done:
return Status; }
VOID StartSerialReadCallback(PIR_WORK_ITEM pWorkItem) /*++
Routine Description:
Arguments:
Return Value: none
--*/ { PIR_DEVICE pThisDev = pWorkItem->pIrDevice;
FreeWorkItem(pWorkItem);
(void)StartSerialRead(pThisDev);
return; }
/*****************************************************************************
* * Function: InitializeReceive * * Synopsis: Initialize the receive functionality. * * Arguments: pThisDevice - pointer to current ir device object * * Returns: NDIS_STATUS_SUCCESS - if irp is successfully sent to serial * device object * NDIS_STATUS_RESOURCES - if mem can't be alloc'd * NDIS_STATUS_FAILURE - otherwise * * Algorithm: * 1) Set the receive timeout to READ_INTERVAL_TIMEOUT_MSEC. * 2) Initialize our rcvInfo and associate info for our * receive state machine. * 3) Build an IRP_MJ_READ irp to send to the serial device * object, and set the completion(or timeout) routine * to SerialIoCompleteRead. * * History: dd-mm-yyyy Author Comment * 10/4/1996 sholden author * * Notes: * * This routine must be called in IRQL PASSIVE_LEVEL. * *****************************************************************************/
NDIS_STATUS InitializeReceive( IN PIR_DEVICE pThisDev ) { PIRP pIrp; PIO_STACK_LOCATION irpSp; NDIS_STATUS status; #if IRSIR_EVENT_DRIVEN
NTSTATUS NtStatus; SERIAL_CHARS SerialChars; #endif
DEBUGMSG(DBG_FUNC, ("+InitializeReceive\n"));
#ifdef DEBUG_IRSIR
irpCount = 0; bytesReceived = 0;
#endif //DEBUG_IRSIR
//
// Set up the receive information for our read completion routine.
//
pThisDev->rcvInfo.rcvState = RCV_STATE_READY; pThisDev->rcvInfo.rcvBufPos = 0;
if (pThisDev->rcvInfo.pRcvBuffer == NULL) { pThisDev->rcvInfo.pRcvBuffer = (PRCV_BUFFER)MyInterlockedRemoveHeadList( &(pThisDev->rcvFreeQueue), &(pThisDev->rcvQueueSpinLock) );
ASSERT(pThisDev->rcvInfo.pRcvBuffer != NULL); }
#if IRSIR_EVENT_DRIVEN
NtStatus = (NDIS_STATUS) SerialSetTimeouts(pThisDev->pSerialDevObj, &SerialTimeoutsActive);
NtStatus = SerialGetChars(pThisDev->pSerialDevObj, &SerialChars);
if (NtStatus!=STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, ("IRSIR: SerialGetChars failed (0x%x:%d)\n", NtStatus)); } else { SerialChars.EventChar = SLOW_IR_EOF;
NtStatus = SerialSetChars(pThisDev->pSerialDevObj, &SerialChars); }
if (NtStatus!=STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, ("IRSIR: SerialSetChars failed (0x%x:%d)\n", NtStatus)); } else { ULONG WaitMask = SERIAL_EV_RXFLAG | SERIAL_EV_RX80FULL;
NtStatus = SerialSetWaitMask(pThisDev->pSerialDevObj, &WaitMask); }
if (NtStatus!=STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, ("IRSIR: SerialSetWaitMask failed (0x%x:%d)\n", NtStatus)); } else { if (InterlockedExchange(&pThisDev->fWaitPending, 1)==0) { NtStatus = SerialCallbackOnMask(pThisDev->pSerialDevObj, SerialIoCompleteWait, &pThisDev->WaitIosb, DEV_TO_CONTEXT(pThisDev), &pThisDev->MaskResult);
if (NtStatus==STATUS_PENDING) { NtStatus = STATUS_SUCCESS; } } }
if (NtStatus!=STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, ("IRSIR: SerialCallbackOnMask failed (0x%x:%d)\n", NtStatus)); ASSERT(0); }
status = NtStatus; #else
pThisDev->fReceiving = TRUE;
(void)SerialSetTimeouts(pThisDev->pSerialDevObj, &SerialTimeoutsIdle);
status = (NDIS_STATUS)StartSerialRead(pThisDev);
if ( (status != STATUS_SUCCESS) && (status != STATUS_PENDING) && (status != STATUS_TIMEOUT) ) { DEBUGMSG(DBG_ERR, (" IoCallDriver failed. Returned 0x%.8x\n", status)); status = NDIS_STATUS_FAILURE;
pThisDev->fReceiving = FALSE;
goto error10; }
//
// If IoCallDriver returned STATUS_PENDING, we were successful
// in sending the irp to the serial device object. This
// routine will return STATUS_SUCCESS.
//
if (status == NDIS_STATUS_PENDING) { status = NDIS_STATUS_SUCCESS; }
//
// Set us into the receive state.
//
goto done;
error10:
#endif
done: DEBUGMSG(DBG_FUNC, ("-InitializeReceive\n"));
return status; }
VOID SetSpeedCallback( PIR_WORK_ITEM pWorkItem ) { PIR_DEVICE pThisDev = pWorkItem->pIrDevice; NDIS_STATUS status; BOOLEAN fSwitchSuccessful; NDIS_HANDLE hSwitchToMiniport;
//
// Set speed of serial device object by request of
// IrsirSetInformation(OID_IRDA_LINK_SPEED).
//
DEBUGMSG(DBG_STAT, (" primPassive = PASSIVE_SET_SPEED\n"));
//
// The set speed event should not be set until a set
// speed is required.
//
ASSERT(pThisDev->fPendingSetSpeed == TRUE);
//
// Ensure that receives and sends have been stopped.
//
ASSERT(pThisDev->fReceiving == FALSE);
PausePacketProcessing(&pThisDev->SendPacketQueue,TRUE);
//
// We can perform the set speed now.
//
status = SetSpeed(pThisDev);
if (status != STATUS_SUCCESS) { DEBUGMSG(DBG_STAT, (" SetSpeed failed. Returned 0x%.8x\n", status)); }
ActivatePacketProcessing(&pThisDev->SendPacketQueue);
pThisDev->fPendingSetSpeed = FALSE;
{ NdisMSetInformationComplete( pThisDev->hNdisAdapter, (NDIS_STATUS)status ); }
//
// NOTE: PassiveLevelThread is only signalled with primPassive
// equal to PASSIVE_SET_SPEED from the receive completion
// routine. After this thread is signalled, the receive
// completion routine is shut down...we need to start
// it up again.
//
status = InitializeReceive(pThisDev);
if (status != STATUS_SUCCESS) { DEBUGMSG(DBG_ERROR, (" InitializeReceive failed = 0x%.8x\n", status));
}
FreeWorkItem(pWorkItem);
return; }
/*****************************************************************************
* * Function: SerialIoCompleteRead * * Synopsis: * * Arguments: pSerialDevObj - pointer to the serial device object which * completed the irp * pIrp - the irp which was completed by the serial 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. * * Algorithm: * This is the completion routine for all pending IRP_MJ_READ irps * sent to the serial device object. * * If there is a pending halt or reset, we exit the completion * routine without sending another irp to the serial device object. * * If there is a pending set speed, this function will wait for * any pending sends to complete and then perform the set speed. * * If the IRP_MJ_READ irp returned either STATUS_SUCCESS or * STATUS_TIMEOUT, we must process any data (stripping BOFs, ESC * sequences, and EOF) into an NDIS_BUFFER and NDIS_PACKET. * * Another irp is then built (we just re-use the incoming irp) and * sent to the serial device object with another IRP_MJ_READ * request. * * History: dd-mm-yyyy Author Comment * 10/5/1996 sholden author * * Notes: * * This routine is called (by the io manager) in IRQL DISPATCH_LEVEL. * *****************************************************************************/
NTSTATUS SerialIoCompleteRead( IN PDEVICE_OBJECT pSerialDevObj, IN PIRP pIrp, IN PVOID Context ) { PIR_DEVICE pThisDev; BOOLEAN fSwitchSuccessful; NDIS_HANDLE hSwitchToMiniport; NTSTATUS status; ULONG_PTR BytesRead; BOOLEAN NewRead = TRUE;
// DEBUGMSG(DBG_FUNC, ("+SerialIoCompleteRead\n"));
//
// The context given to IoSetCompletionRoutine is simply the the ir
// device object pointer.
//
pThisDev = CONTEXT_TO_DEV(Context);
//
// Need to check if there is a pending halt or reset. If there is, we
// just leave the receive completion. Since we maintain one irp associated
// with the receive functionality, the irp will be deallocated in
// the ir device object deinitialization routine.
//
if ((pThisDev->fPendingHalt == TRUE) || (pThisDev->fPendingReset == TRUE)) { //
// Set the fReceiving boolean so that the halt and reset routines
// know when it is okay to continue.
//
pThisDev->fReceiving = FALSE;
//
// Free the irp and associate memory...the rest will be
// freed in the halt or reset.
//
LOG_ENTRY('3i', pThisDev, pIrp, 0); IoFreeIrp(pIrp);
goto done; }
//
// Next we take care of any pending set speeds.
//
//
// This completion routine is running at IRQL DISPATCH_LEVEL. Therefore,
// we cannot make a synchronous call to the serial driver. Set an event
// to notify the PassiveLevelThread to perform the speed change. We will
// exit this without creating another irp to the serial device object.
// PassiveLevelThread will call InitializeReceive after the speed has
// been set.
//
if (pThisDev->fPendingSetSpeed == TRUE) { pThisDev->fReceiving = FALSE;
if (ScheduleWorkItem(PASSIVE_SET_SPEED, pThisDev, SetSpeedCallback, NULL, 0) != NDIS_STATUS_SUCCESS) { status = NDIS_STATUS_SUCCESS; } else { status = NDIS_STATUS_PENDING; }
LOG_ENTRY('4i', pThisDev, pIrp, 0); IoFreeIrp(pIrp);
goto done; }
//
// We have a number of cases:
// 1) The serial read timed out and we received no data.
// 2) The serial read timed out and we received some data.
// 3) The serial read was successful and fully filled our irp buffer.
// 4) The irp was cancelled.
// 5) Some other failure from the serial device object.
//
status = pIrp->IoStatus.Status; BytesRead = pIrp->IoStatus.Information; LOG_ENTRY('CR', pThisDev, BytesRead, 0);
switch (status) { case STATUS_SUCCESS: case STATUS_TIMEOUT:
if (BytesRead > 0) { #ifdef DEBUG_IRSIR
//
// Count number of irps received with data. Count will be
// reset when delivering a buffer to the protocol.
//
irpCount++; bytesReceived += pIrp->IoStatus.Information;
#endif //DEBUG_IRSIR
//
// Indicate that the next send should implement
// the min turnaround delay.
//
pThisDev->fRequireMinTurnAround = TRUE;
ProcessData( pThisDev, pThisDev->pRcvIrpBuffer, (UINT) pIrp->IoStatus.Information ); }
break; // STATUS_SUCCESS || STATUS_TIMEOUT
case STATUS_DELETE_PENDING: NewRead = FALSE; pThisDev->fReceiving = FALSE; break;
case STATUS_CANCELLED: //
// If our irp was cancelled, we just ignore and continue as if
// we processed data.
//
break;
case STATUS_PENDING: case STATUS_UNSUCCESSFUL: case STATUS_INSUFFICIENT_RESOURCES: default:
ASSERT(FALSE);
break; }
//
// Free the irp and reinit the buffer and status block.
//
LOG_ENTRY('5i', pThisDev, pIrp, 0); IoFreeIrp(pIrp);
if (NewRead) { pThisDev->NumReads++;
if (InterlockedIncrement(&pThisDev->ReadRecurseLevel)>1) { if (ScheduleWorkItem(0, pThisDev, StartSerialReadCallback, 0, 0)!=NDIS_STATUS_SUCCESS) { DEBUGMSG(DBG_ERR, ("IRSIR:SerialIoCompleteRead: Timed out and couldn't reschedule read.\n" " We're going down.\n")); pThisDev->fReceiving = FALSE; } } else { StartSerialRead(pThisDev); }
InterlockedDecrement(&pThisDev->ReadRecurseLevel); }
done: // DEBUGMSG(DBG_FUNC, ("-SerialIoCompleteRead\n"));
//
// We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
// routine (IofCompleteRequest) will stop working on the irp.
//
status = STATUS_MORE_PROCESSING_REQUIRED;
return status; }
/*****************************************************************************
* * Function: ProcessData * * Synopsis: State machine to process the input data by stripping BOFs, EOFs * and ESC sequences in the data. * * Arguments: pThisDev - a pointer to the current ir device object * rawBuffer - a pointer to the input data to process * rawBytesRead - the number of bytes in rawBuffer * * Returns: STATUS_SUCCESS * * Algorithm: * * The state machine for receiving characters is as follows: * * ------------------------------------------------------------------- * | Event/State || READY | BOF | IN_ESC | RX | * ------------------------------------------------------------------- * ------------------------------------------------------------------- * | || | | | | * | char = BOF || state = | | reset | reset | * | || BOF | | state = | state = | * | || | | BOF | BOF | * ------------------------------------------------------------------- * | || | | error | | * | char = ESC || | state = | reset | state = | * | || | IN_ESC | state = | IN_ESC | * | || | | READY | | * ------------------------------------------------------------------- * | || | | | if valid | * | char = EOF || | state = | error | FCS { | * | || | READY | reset | indicate | * | || | | state = | data | * | || | | READY | state = | * | || | | | READY } | * ------------------------------------------------------------------- * | || | | complement| | * | char = || | state = | bit 6 of | data[] = | * | || | RX | char | char | * | || | | data[] = | | * | || | data[] = | char | | * | || | char | state = | | * | || | | RX | | * ------------------------------------------------------------------- * * History: dd-mm-yyyy Author Comment * 10/7/1996 sholden author * * Notes: * * *****************************************************************************/
NTSTATUS ProcessData( IN PIR_DEVICE pThisDev, IN PUCHAR rawBuffer, IN UINT rawBytesRead ) { UINT rawBufPos; UCHAR currentChar; PUCHAR pReadBuffer; NTSTATUS status;
#if DBG
int i = 0;
#endif //DBG
DEBUGMSG(DBG_FUNC, ("+ProcessData\n")); DBGTIME("+ProcessData"); DEBUGMSG(DBG_OUT, (" Address: 0x%.8x, Length: %d\n", rawBuffer, rawBytesRead));
LOG_ENTRY('DP', pThisDev, rawBuffer, rawBytesRead); status = STATUS_SUCCESS;
pReadBuffer = pThisDev->rcvInfo.pRcvBuffer->dataBuf;
//
// While there is data in the buffer which we have not processed.
//
//
// NOTE: We have to loop once more after getting MAX_RCV_DATA_SIZE bytes
// so that we can see the 'EOF'; hence the <= and not <.
// Also, to ensure that we don't overrun the buffer,
// RCV_BUFFER_SIZE = MAX_RCV_DATA_SIZE + 4;
//
for ( rawBufPos = 0; (rawBufPos < rawBytesRead) && (pThisDev->rcvInfo.rcvBufPos <= MAX_RCV_DATA_SIZE); rawBufPos++ ) { #if DBG
i++;
if (i > 10000) { ASSERT(0); }
#endif //DBG
currentChar = rawBuffer[rawBufPos];
switch (pThisDev->rcvInfo.rcvState) { case RCV_STATE_READY:
switch (currentChar) { case SLOW_IR_BOF:
pThisDev->rcvInfo.rcvState = RCV_STATE_BOF;
break;
case SLOW_IR_EOF: case SLOW_IR_ESC: default:
//
// Ignore this data.
//
break; }
break; // RCV_STATE_READY
case RCV_STATE_BOF:
switch (currentChar) { case SLOW_IR_EOF:
pThisDev->rcvInfo.rcvState = RCV_STATE_READY; pThisDev->rcvInfo.rcvBufPos = 0;
break;
case SLOW_IR_ESC:
pThisDev->rcvInfo.rcvState = RCV_STATE_IN_ESC; pThisDev->rcvInfo.rcvBufPos = 0;
break;
case SLOW_IR_BOF:
//
// state = RCV_STATE_BOF
//
break;
default:
//
// We have data, copy the character into the buffer and
// change our state to RCV_STATE_RX.
//
pReadBuffer[0] = currentChar;
pThisDev->rcvInfo.rcvState = RCV_STATE_RX; pThisDev->rcvInfo.rcvBufPos = 1;
break; }
break; // RCV_STATE_BOF
case RCV_STATE_IN_ESC:
switch (currentChar) { //
// ESC + (ESC||EOF||BOF) is an abort sequence.
//
// If ESC + (ESC||EOF) then state = READY.
// If ESC + BOF then state = BOF.
//
case SLOW_IR_ESC: case SLOW_IR_EOF:
pThisDev->rcvInfo.rcvState = RCV_STATE_READY; pThisDev->rcvInfo.rcvBufPos = 0;
break;
case SLOW_IR_BOF:
pThisDev->rcvInfo.rcvState = RCV_STATE_BOF; pThisDev->rcvInfo.rcvBufPos = 0;
break;
case SLOW_IR_BOF^SLOW_IR_ESC_COMP: case SLOW_IR_ESC^SLOW_IR_ESC_COMP: case SLOW_IR_EOF^SLOW_IR_ESC_COMP:
//
// Escape sequence for BOF, ESC or EOF chars.
//
//
// Fall through, do same as unnecessary escape
// sequence.
//
default:
//
// Unnecessary escape sequence, copy the data in to the buffer
// we must complement bit 6 of the data.
//
pReadBuffer[pThisDev->rcvInfo.rcvBufPos++] = currentChar ^ SLOW_IR_ESC_COMP; pThisDev->rcvInfo.rcvState = RCV_STATE_RX;
break; }
break; // RCV_STATE_IN_ESC
case RCV_STATE_RX:
switch (currentChar) { case SLOW_IR_BOF:
//
// Reset.
//
pThisDev->rcvInfo.rcvState = RCV_STATE_BOF; pThisDev->rcvInfo.rcvBufPos = 0;
break;
case SLOW_IR_ESC:
pThisDev->rcvInfo.rcvState = RCV_STATE_IN_ESC;
break;
case SLOW_IR_EOF:
if (pThisDev->rcvInfo.rcvBufPos < (SLOW_IR_ADDR_SIZE + SLOW_IR_CONTROL_SIZE + SLOW_IR_FCS_SIZE) ) { //
// Reset. Not enough data.
//
pThisDev->rcvInfo.rcvState = RCV_STATE_READY; pThisDev->rcvInfo.rcvBufPos = 0;
break; }
//
// Need to set the length to the proper amount.
// (It isn't rcvBufPos + 1 since it was incremented
// the next free location...which we are not using.)
//
pThisDev->rcvInfo.pRcvBuffer->dataLen = pThisDev->rcvInfo.rcvBufPos;
DEBUGMSG(DBG_OUT, (" RcvBuffer = 0x%.8x, Length = %d\n", pReadBuffer, pThisDev->rcvInfo.rcvBufPos ));
//
// DeliverBuffer attempts to deliver the current
// frame in pThisDev->rcvInfo. If the ownership
// of the packet is retained by the protocol, the
// DeliverBuffer routine gives us a new receive
// buffer.
//
DeliverBuffer( pThisDev );
//
// Since DeliverBuffer could have given us a new
// buffer, we must update our pReadBuffer pointer.
//
pReadBuffer = pThisDev->rcvInfo.pRcvBuffer->dataBuf;
pThisDev->rcvInfo.rcvState = RCV_STATE_READY; pThisDev->rcvInfo.rcvBufPos = 0;
break;
default:
//
// The current character is data in the frame.
//
pReadBuffer[pThisDev->rcvInfo.rcvBufPos++] = currentChar;
break; }
break; // RCV_STATE_RX
default: DEBUGMSG(DBG_ERR, (" Illegal state\n"));
//
// Reset.
//
pThisDev->rcvInfo.rcvState = RCV_STATE_READY; pThisDev->rcvInfo.rcvBufPos = 0;
break; } }
//
// There are two ways to break the for loop:
// 1) out of data - this is fine
// 2) overrun, the frame is larger than our buffer size
//
if (pThisDev->rcvInfo.rcvBufPos > MAX_RCV_DATA_SIZE) { DEBUGMSG(DBG_WARN, (" Overrun in ProcessData!!!\n"));
//
// Reset the buffer for our next read.
//
pThisDev->rcvInfo.rcvState = RCV_STATE_READY; pThisDev->rcvInfo.rcvBufPos = 0; pThisDev->packetsReceivedOverflow++; }
DEBUGMSG(DBG_FUNC, ("-ProcessData\n"));
return status; }
VOID ProcessReturnPacket( PIR_DEVICE pThisDev, PRCV_BUFFER pRcvBuffer ) { PNDIS_BUFFER pBuffer;
NdisQueryPacket( pRcvBuffer->packet, NULL, // physical buffer count, don't care
NULL, // buffer count, don't care, we know it is 1
&pBuffer, // get a pointer to our buffer
NULL // total packet lenght, don't care
);
//
// We adjusted the buffer length of the NDIS_BUFFER to the size
// of the data before we gave ownership to the protocol. Now we
// should reset the buffer length to the full size of the data
// buffer.
//
NdisAdjustBufferLength( pBuffer, RCV_BUFFER_SIZE ); #if DBG
NdisZeroMemory( pRcvBuffer->dataBuf, RCV_BUFFER_SIZE ); #endif
pRcvBuffer->dataLen = 0;
InterlockedDecrement(&pThisDev->packetsHeldByProtocol);
//
// Add the buffer to the free queue.
//
MyInterlockedInsertTailList( &(pThisDev->rcvFreeQueue), &pRcvBuffer->linkage, &(pThisDev->rcvQueueSpinLock) );
}
/*****************************************************************************
* * Function: DeliverBuffer * * Synopsis: Delivers the buffer to the protocol via * NdisMIndicateReceivePacket. * * Arguments: pThisDev - pointer to the current ir device object * * Returns: STATUS_SUCCESS - on success * STATUS_UNSUCCESSFUL - if packet can't be delivered to protocol * * Algorithm: * * History: dd-mm-yyyy Author Comment * 10/7/1996 sholden author * * Notes: * * *****************************************************************************/
VOID DeliverBuffer( IN PIR_DEVICE pThisDev ) { SLOW_IR_FCS_TYPE fcs; PNDIS_BUFFER pBuffer; BOOLEAN fProcessPacketNow; NDIS_HANDLE hSwitchToMiniport; NTSTATUS status; PRCV_BUFFER pThisBuffer, pNextBuffer;
DEBUGMSG(DBG_FUNC, ("+DeliverBuffer\n"));
LOG_ENTRY('BD', pThisDev, pThisDev->rcvInfo.pRcvBuffer->dataBuf, pThisDev->rcvInfo.pRcvBuffer->dataLen); #if 0
LOG_ENTRY('DD', ((PULONG)pThisDev->rcvInfo.pRcvBuffer->dataBuf)[0], ((PULONG)pThisDev->rcvInfo.pRcvBuffer->dataBuf)[1], ((PULONG)pThisDev->rcvInfo.pRcvBuffer->dataBuf)[2]); #endif
#ifdef DEBUG_IRSIR
//
// This is the count of how many irps with data to get this frame.
//
DEBUGMSG(DBG_STAT, ("****IrpCount = %d, Bytes = %d, Frame Length = %d\n", irpCount, bytesReceived, pThisDev->rcvInfo.pRcvBuffer->dataLen)); irpCount = 0; bytesReceived = 0;
#endif //DEBUG_IRSIR
pNextBuffer = (PRCV_BUFFER)MyInterlockedRemoveHeadList( &(pThisDev->rcvFreeQueue), &(pThisDev->rcvQueueSpinLock) ); //
// Compute the FCS.
//
fcs = ComputeFCS( pThisDev->rcvInfo.pRcvBuffer->dataBuf, pThisDev->rcvInfo.pRcvBuffer->dataLen );
if (fcs != GOOD_FCS || !pNextBuffer) { //
// Bad frame, just drop it and increment our dropped packets
// count.
//
pThisDev->packetsReceivedDropped++;
#if DBG
if (fcs != GOOD_FCS) { LOG_ENTRY('CF', pThisDev, 0, 0); DEBUGMSG(DBG_STAT|DBG_WARN, (" FCS ERR Len(%d)\n", pThisDev->rcvInfo.pRcvBuffer->dataLen)); } if (!pNextBuffer) { LOG_ENTRY('BI', pThisDev, 0, 0); DEBUGMSG(DBG_STAT|DBG_WARN, (" Dropped packet due to insufficient buffers\n")); } #endif
#if 0
DBG_PrintBuf(pThisDev->rcvInfo.pRcvBuffer->dataBuf, pThisDev->rcvInfo.pRcvBuffer->dataLen); #endif
status = STATUS_UNSUCCESSFUL;
NdisZeroMemory( pThisDev->rcvInfo.pRcvBuffer->dataBuf, RCV_BUFFER_SIZE );
pThisDev->rcvInfo.pRcvBuffer->dataLen = 0;
if (pNextBuffer) { MyInterlockedInsertHeadList( &(pThisDev->rcvFreeQueue), &pNextBuffer->linkage, &(pThisDev->rcvQueueSpinLock) ); }
goto done; }
LOG_ENTRY('HF', pThisDev, 0, 0); //
// Remove fcs from the end of the packet.
//
pThisDev->rcvInfo.pRcvBuffer->dataLen -= SLOW_IR_FCS_SIZE;
//
// Fix up some other packet fields.
//
NDIS_SET_PACKET_HEADER_SIZE( pThisDev->rcvInfo.pRcvBuffer->packet, SLOW_IR_ADDR_SIZE + SLOW_IR_CONTROL_SIZE );
//
// We need to call NdisQueryPacket to get a pointer to the
// NDIS_BUFFER so that we can adjust the buffer length
// to the actual size of the data and not the size
// of the buffer.
//
// NdisQueryPacket will return other information, but since
// we built the packet ourselves, we already know that info.
//
NdisQueryPacket( pThisDev->rcvInfo.pRcvBuffer->packet, NULL, // physical buffer count, don't care
NULL, // buffer count, don't care, we know it is 1
&pBuffer, // get a pointer to our buffer
NULL // total packet lenght, don't care
);
NdisAdjustBufferLength( pBuffer, pThisDev->rcvInfo.pRcvBuffer->dataLen );
//
// Set to use the new buffer before we indicate the packet.
//
pThisBuffer = pThisDev->rcvInfo.pRcvBuffer; pThisDev->rcvInfo.pRcvBuffer = pNextBuffer;
ASSERT(pThisDev->rcvInfo.pRcvBuffer != NULL);
//
// Indicate the packet to NDIS.
//
InterlockedIncrement(&pThisDev->packetsHeldByProtocol);
NdisMIndicateReceivePacket( pThisDev->hNdisAdapter, &pThisBuffer->packet, 1 );
done:
DEBUGMSG(DBG_FUNC, ("-DeliverBuffer\n"));
return; }
/*****************************************************************************
* * Function: IrsirReturnPacket * * 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. * * Algorithm: * 1) Take the receive buffer off of the pending queue. * 2) Put the receive buffer back on the free queue. * * History: dd-mm-yyyy Author Comment * 10/8/1996 sholden author * * Notes: * * *****************************************************************************/
VOID IrsirReturnPacket( IN NDIS_HANDLE Context, IN PNDIS_PACKET pReturnedPacket ) { PIR_DEVICE pThisDev; PNDIS_BUFFER pBuffer; PRCV_BUFFER pRcvBuffer; PLIST_ENTRY pTmpListEntry;
DEBUGMSG(DBG_FUNC, ("+IrsirReturnPacket\n"));
//
// The context is just the pointer to the current ir device object.
//
pThisDev = CONTEXT_TO_DEV(Context);
pThisDev->packetsReceived++;
{ PPACKET_RESERVED_BLOCK PacketReserved;
PacketReserved=(PPACKET_RESERVED_BLOCK)&pReturnedPacket->MiniportReservedEx[0];
pRcvBuffer=PacketReserved->Context; }
ProcessReturnPacket(pThisDev, pRcvBuffer);
DEBUGMSG(DBG_FUNC, ("-IrsirReturnPacket\n"));
return; }
VOID SerialWaitCallback(PIR_WORK_ITEM pWorkItem) /*++
Routine Description:
Arguments:
Return Value: none
--*/ { PIR_DEVICE pThisDev = pWorkItem->pIrDevice; NTSTATUS Status; ULONG BytesRead;
FreeWorkItem(pWorkItem);
do { SerialSynchronousRead(pThisDev->pSerialDevObj, pThisDev->pRcvIrpBuffer, SERIAL_RECEIVE_BUFFER_LENGTH, &BytesRead);
if (BytesRead>0) { ProcessData(pThisDev, pThisDev->pRcvIrpBuffer, BytesRead); }
} while ( BytesRead == SERIAL_RECEIVE_BUFFER_LENGTH );
if (InterlockedExchange(&pThisDev->fWaitPending, 1)==0) { LARGE_INTEGER Time; KeQuerySystemTime(&Time); LOG_ENTRY('WS', pThisDev, Time.LowPart/10000, Time.HighPart);
Status = SerialCallbackOnMask(pThisDev->pSerialDevObj, SerialIoCompleteWait, &pThisDev->WaitIosb, DEV_TO_CONTEXT(pThisDev), &pThisDev->MaskResult); if (Status!=STATUS_SUCCESS && Status!=STATUS_PENDING) { DEBUGMSG(DBG_ERROR, ("IRSIR: SerialCallbackOnMask failed (0x%x:%d)\n", Status)); ASSERT(0); } }
return; }
NTSTATUS SerialIoCompleteWait( IN PDEVICE_OBJECT pSerialDevObj, IN PIRP pIrp, IN PVOID Context ) { PIR_DEVICE pThisDev; BOOLEAN fSwitchSuccessful; NDIS_HANDLE hSwitchToMiniport; NTSTATUS status = STATUS_SUCCESS; ULONG BytesRead; ULONG WaitWasPending;
DEBUGMSG(DBG_FUNC, ("+SerialIoCompleteWait\n"));
//
// The context given to IoSetCompletionRoutine is simply the the ir
// device object pointer.
//
pThisDev = CONTEXT_TO_DEV(Context);
WaitWasPending = InterlockedExchange(&pThisDev->fWaitPending, 0); ASSERT(WaitWasPending);
*pIrp->UserIosb = pIrp->IoStatus;
LOG_ENTRY('1i', pThisDev, pIrp, 0); IoFreeIrp(pIrp); //
// Need to check if there is a pending halt or reset. If there is, we
// just leave the receive completion. Since we maintain one irp associated
// with the receive functionality, the irp will be deallocated in
// the ir device object deinitialization routine.
//
if ((pThisDev->fPendingHalt == TRUE) || (pThisDev->fPendingReset == TRUE)) { //
// Set the fReceiving boolean so that the halt and reset routines
// know when it is okay to continue.
//
pThisDev->fReceiving = FALSE;
//
// Free the irp and associate memory...the rest will be
// freed in the halt or reset.
//
goto done; }
//
// Next we take care of any pending set speeds.
//
//
// This completion routine is running at IRQL DISPATCH_LEVEL. Therefore,
// we cannot make a synchronous call to the serial driver. Set an event
// to notify the PassiveLevelThread to perform the speed change. We will
// exit this without creating another irp to the serial device object.
// PassiveLevelThread will call InitializeReceive after the speed has
// been set.
//
if (pThisDev->fPendingSetSpeed == TRUE) { pThisDev->fReceiving = FALSE;
goto done; } //
// Free the irp and reinit the buffer and status block.
//
{ LARGE_INTEGER Time; KeQuerySystemTime(&Time); LOG_ENTRY('ES', pThisDev, Time.LowPart/10000, Time.HighPart); } if (ScheduleWorkItem(0, pThisDev, SerialWaitCallback, (PVOID)0, 0)!=NDIS_STATUS_SUCCESS ) { DEBUGMSG(DBG_ERR, ("IRSIR:SerialIoCompleteWait: Timed out and couldn't reschedule Wait.\n" " We're going down.\n")); }
done: DEBUGMSG(DBG_FUNC, ("-SerialIoCompleteWait\n"));
//
// We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
// routine (IofCompleteRequest) will stop working on the irp.
//
status = STATUS_MORE_PROCESSING_REQUIRED;
return status; }
|