Problem : OUTPUT OF THE RECEIVED DATA AT THE PORT THROWS REPEAT CHARACTERS
CORRECT TX DATA : The Quick Brown Fox Jumps Over The Lazy Dogs Tail And Back Again 1234567890
There are no errors in the rx data if the comm. is between only one UART,but as soon as interrupts come into picture (to comm. with 6 UARTs) ,following error appear and cause failure. Its the repeat characters that should be avoided.
The Quick Brown Fox J Jumps Over The Lazy Dogs Tail And Back Again 1234567890
The Quick Brownwn Fox Jumps Over The Lazy Dogs Tail And Back Again 1234567890
The Quick Brown Fox Jumps Over Thehe Lazy Dogs Tail And Back Again 1234567890
The Quick Brown n Fox Jumps Over The Lazy Dogs Tail And Back Again 1234567890
The Quick Brown Fox Jumps Over The Lazy Dogs Tail And Back Again 1 1234567890
#include "SerialPort.h"
#include "SuppFunc.h"
enum SerialPortConstants
{
SerialDefXON = 0x11,
SerialDefXOFF = 0x13,
MaximumBaudRate = 38400,
BaseMode1Value = 0x00,
BaseMode2Value = 0x00,
InitialQueueSize = 8192,
BlockAReceiveInterrupt = 0x02,
BlockBReceiveInterrupt = 0x20,
BlockATransmitInterrupt = 0x01,
BlockBTransmitInterrupt = 0x10,
FIFOErrorFlags = 0x70,
FrameStatusError = 0x40,
ParityStatusError = 0x20,
OverrunStatusError = 0x10,
RxRDYStatus = 0x01,
FFULLStatus = 0x02,
TxRDYStatus = 0x04,
BreakOnCommand = 0x60,
BreakOffCommand = 0x70,
DisableRxCommand = 0x02,
EnableRxCommand = 0x01,
MillisecondsTo100Nanoseconds = 10000,
};
unsigned char SerialPortValidateFlags( ULONG providedFlags, ULONG allValidFlags );
void SerialPortResetConnectionSettings( SerialPort* serialPort );
void UpdateQueue( Queue* queue, unsigned int newSize );
void SerialPortTransmitByte( SerialPort* serialPort );
void SerialPortReceiveByte( SerialPort* serialPort );
void TryCancellingRead( SerialPort* serialPort );
PIRP GetAndResetPendingRead( SerialPort* serialPort, unsigned int* bufferLength );
void TryCancellingWrite( SerialPort* serialPort );
PIRP GetAndResetPendingWrite( SerialPort* serialPort, unsigned int* bufferLength );
void ProcessUARTInterrupts( SerialPort* serialPort, UARTRegisterValue interruptStatusValue, UARTRegisterValue transmitInterruptMask, UARTRegisterValue receiveInterruptMask );
DRIVER_CANCEL SerialCancelCurrentRead;
void SerialCancelCurrentRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
#define SerialPortCopyFromReceiveBuffer( serialPort, numberOfBytes, buffer, numberOfBytesRead ) ( *numberOfBytesRead = FillBufferFromQueue( &serialPort->receiveQueue, buffer, numberOfBytes ) )
#define SerialPortCopyToWriteBuffer( serialPort, numberOfBytes, buffer, numberOfBytesWritten ) ( *numberOfBytesWritten = FillQueueFromBuffer( &serialPort->transmitQueue, buffer, numberOfBytes ) )
#define ResetSerialPortModeRegisterPointer( _serialPort ) ResetUARTModeRegisterPointer( _serialPort->baseAddress, _serialPort->uartType )
#define SerialPortResetReceiver( _serialPort ) ResetReceiver( _serialPort->baseAddress, _serialPort->uartType )
#define WriteSerialPortRegister( _serialPort, _uartRegister, _value ) WriteUARTRegister( _serialPort->baseAddress, _uartRegister, _serialPort->uartType, _value )
#define ReadSerialPortRegister( _serialPort, _uartRegister, _value ) ReadUARTRegister( _serialPort->baseAddress, _uartRegister, _serialPort->uartType, _value )
NTSTATUS SerialPortInitialise( SerialPort* serialPort, unsigned char deviceNumber )
{
NTSTATUS status = STATUS_SUCCESS;
unsigned long baseAddress = 0;
UARTType uartType = UARTDummyUnit;
unsigned char uartId = 255;
if ( serialPort == NULL )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( deviceNumber != 0 )
{
baseAddress = ( ( deviceNumber - 1 ) / 2 ) * UARTPairRegistersSize;
if ( ( ( deviceNumber - 1 ) % 2 ) == 0 )
{
uartType = UARTUnitA;
}
else
{
uartType = UARTUnitB;
}
uartId = deviceNumber - 1;
}
DebugPrintf(( "SerialPortInitialise: device id: %u, base address: %u, UART type: %s\n",
deviceNumber, baseAddress,
( ( uartType == UARTUnitA ) ? "UARTUnitA" :
( ( uartType == UARTUnitB ) ? "UARTUnitB" : "UARTDummyUnit" ) ) ));
serialPort->uartId = uartId;
serialPort->baseAddress = baseAddress;
serialPort->uartType = uartType;
serialPort->open = 0;
serialPort->waitMask.currentWaitMask = 0;
serialPort->waitMask.waitOnMaskPending = 0;
serialPort->waitMask.pIrp = NULL;
serialPort->waitMask.waitEvents = NULL;
serialPort->pendingRead.pIrp = NULL;
serialPort->pendingRead.bufferLength = 0;
KeInitializeSpinLock( &serialPort->pendingRead.lock );
SerialPortResetConnectionSettings( serialPort );
InitialiseQueueLock( &serialPort->receiveQueue );
InitialiseQueueLock( &serialPort->transmitQueue );
InitializeListHead( &serialPort->readCompletionWorkerList );
KeInitializeSpinLock( &serialPort->readCompletionWorkerListLock );
serialPort->readCompletionWorkerActive = 0;
SerialPortClearStats( serialPort );
serialPort->numberOfQueuedWriteBytes = 0;
LockQueue( &serialPort->receiveQueue );
serialPort->receiveQueue.buffer = NULL;
InitialiseQueue( &serialPort->receiveQueue, InitialQueueSize );
UnlockQueue( &serialPort->receiveQueue );
LockQueue( &serialPort->transmitQueue );
serialPort->transmitQueue.buffer = NULL;
InitialiseQueue( &serialPort->transmitQueue, InitialQueueSize );
UnlockQueue( &serialPort->transmitQueue );
}
return status;
}
NTSTATUS SerialPortOpen( SerialPort* serialPort )
{
NTSTATUS status = STATUS_SUCCESS;
UARTRegisterValue dataElement;
if ( serialPort == NULL )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( serialPort->open == 1 )
{
status = STATUS_ACCESS_DENIED;
}
else
{
serialPort->open = 1;
LockQueue( &serialPort->receiveQueue );
InitialiseQueue( &serialPort->receiveQueue, InitialQueueSize );
UnlockQueue( &serialPort->receiveQueue );
LockQueue( &serialPort->transmitQueue );
InitialiseQueue( &serialPort->transmitQueue, InitialQueueSize );
UnlockQueue( &serialPort->transmitQueue );
serialPort->numberOfQueuedWriteBytes = 0;
SerialPortClearStats( serialPort );
if ( OpenUART( serialPort->baseAddress, serialPort->uartType ) == 0 )
{
DebugPrintf(( "Failed to Open the UART.\n" ));
}
}
}
return status;
}
NTSTATUS SerialPortClose( SerialPort* serialPort )
{
NTSTATUS status = STATUS_SUCCESS;
unsigned int debugStat = 0;
if ( serialPort == NULL )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( serialPort->waitMask.pIrp != NULL )
{
PlxCompleteIrpWithInformation( serialPort->waitMask.pIrp, STATUS_SUCCESS, 0 );
serialPort->waitMask.pIrp = NULL;
}
serialPort->open = 0;
serialPort->waitMask.currentWaitMask = 0;
serialPort->waitMask.waitOnMaskPending = 0;
serialPort->waitMask.waitEvents = NULL;
TryCancellingRead( serialPort );
TryCancellingWrite( serialPort );
SerialPortResetConnectionSettings( serialPort );
LockQueue( &serialPort->receiveQueue );
FreeQueue( &serialPort->receiveQueue );
UnlockQueue( &serialPort->receiveQueue );
LockQueue( &serialPort->transmitQueue );
FreeQueue( &serialPort->transmitQueue );
UnlockQueue( &serialPort->transmitQueue );
if ( CloseUART( serialPort->baseAddress, serialPort->uartType ) == 0 )
{
DebugPrintf(( "Failed to Close the UART.\n" ));
}
}
return status;
}
NTSTATUS SerialPortSetQueueSize( SerialPort* serialPort, PSERIAL_QUEUE_SIZE serialQueueSize )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( serialQueueSize == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
DebugPrintf(( "SerialPortSetQueueSize InSize %d, OutSize %d\n", serialQueueSize->InSize, serialQueueSize->OutSize ));
UpdateQueue( &serialPort->receiveQueue, serialQueueSize->InSize );
UpdateQueue( &serialPort->transmitQueue, serialQueueSize->OutSize );
}
return status;
}
NTSTATUS SerialPortConfigSize( SerialPort* serialPort, PULONG configSize )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( configSize == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
*configSize = 0;
DebugPrintf(( "SerialPortConfigSize %d\n", *configSize ));
}
return status;
}
NTSTATUS SerialPortGetBaudRate( SerialPort* serialPort, PSERIAL_BAUD_RATE baudRate )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( baudRate == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
baudRate->BaudRate = serialPort->baudRate;
DebugPrintf(( "SerialPortGetBaudRate %d\n", baudRate->BaudRate ));
}
return status;
}
NTSTATUS SerialPortSetBaudRate( SerialPort* serialPort, PSERIAL_BAUD_RATE baudRate )
{
NTSTATUS status = STATUS_SUCCESS;
UARTRegisterValue csrData;
if ( ( baudRate == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
DebugPrintf(( "SerialPortSetBaudRate %u\n", baudRate->BaudRate ));
if ( GetBAUDRate( baudRate->BaudRate, &csrData ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
DebugPrintf(( "Invalid baud rate %u\n", baudRate->BaudRate ));
}
else
{
serialPort->baudRate = baudRate->BaudRate;
WriteSerialPortRegister( serialPort, StatusAndClockSelect, csrData );
}
}
return status;
}
NTSTATUS SerialPortGetLineControl( SerialPort* serialPort, PSERIAL_LINE_CONTROL lineControl )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( lineControl == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
lineControl->WordLength = serialPort->lineControl.WordLength;
lineControl->Parity = serialPort->lineControl.Parity;
lineControl->StopBits = serialPort->lineControl.StopBits;
DebugPrintf(( "SerialPortGetLineControl -> WordLength: %d, Parity: %d, StopBits: %d\n", lineControl->WordLength, lineControl->Parity, lineControl->StopBits ));
}
return status;
}
NTSTATUS SerialPortSetLineControl( SerialPort* serialPort, PSERIAL_LINE_CONTROL lineControl )
{
NTSTATUS status = STATUS_SUCCESS;
UARTRegisterValue dataBits;
UARTRegisterValue parity;
UARTRegisterValue stopBits;
unsigned char fiveStopBits = 0;
if ( ( lineControl == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( ResetSerialPortModeRegisterPointer( serialPort ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
DebugPrintf(( "SerialPortSetLineControl -> FAILED to Reset the Mode register pointer\n" ));
}
else
{
if ( GetDataBits( lineControl->WordLength, &dataBits ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
DebugPrintf(( "SerialPortSetLineControl -> FAILED to GetDataBits WordLength: %d\n", lineControl->WordLength ));
}
else
{
if ( GetParity( lineControl->Parity, &parity ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
DebugPrintf(( "SerialPortSetLineControl -> FAILED to GetParity Parity: %d\n", lineControl->Parity ));
}
else
{
if ( lineControl->WordLength == 5 )
{
fiveStopBits = 1;
}
if ( GetStopBits( lineControl->StopBits, &stopBits, fiveStopBits ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
DebugPrintf(( "SerialPortSetLineControl -> FAILED to GetStopBits StopBits: %d\n", lineControl->StopBits ));
}
else
{
if ( WriteSerialPortRegister( serialPort, Mode, parity | dataBits ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
DebugPrintf(( "SerialPortSetLineControl -> FAILED to Write Mode 1 register\n" ));
}
else
{
serialPort->lineControl.WordLength = lineControl->WordLength;
serialPort->lineControl.Parity = lineControl->Parity;
if ( WriteSerialPortRegister( serialPort, Mode, stopBits ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
DebugPrintf(( "SerialPortSetLineControl -> FAILED to Write Mode 2 register\n" ));
}
else
{
serialPort->lineControl.StopBits = lineControl->StopBits;
}
}
}
}
}
}
DebugPrintf(( "SerialPortSetLineControl -> WordLength: %d, Parity: %d, StopBits: %d\n", lineControl->WordLength, lineControl->Parity, lineControl->StopBits ));
}
return status;
}
NTSTATUS SerialPortGetChars( SerialPort* serialPort, PSERIAL_CHARS chars )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( chars == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
chars->EofChar = serialPort->serialChars.EofChar;
chars->ErrorChar = serialPort->serialChars.ErrorChar;
chars->BreakChar = serialPort->serialChars.BreakChar;
chars->EventChar = serialPort->serialChars.EventChar;
chars->XonChar = serialPort->serialChars.XonChar;
chars->XoffChar = serialPort->serialChars.XoffChar;
DebugPrintf(( "SerialPortGetChars -> EofChar: %d, ErrorChar: %d, BreakChar: %d, EventChar: %d, XonChar: %d, XoffChar: %d\n",
chars->EofChar, chars->ErrorChar, chars->BreakChar, chars->EventChar, chars->XonChar, chars->XoffChar ));
}
return status;
}
NTSTATUS SerialPortSetChars( SerialPort* serialPort, PSERIAL_CHARS chars )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( chars == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
serialPort->serialChars.EofChar = chars->EofChar;
serialPort->serialChars.ErrorChar = chars->ErrorChar;
serialPort->serialChars.BreakChar = chars->BreakChar;
serialPort->serialChars.EventChar = chars->EventChar;
serialPort->serialChars.XonChar = chars->XonChar;
serialPort->serialChars.XoffChar = chars->XoffChar;
DebugPrintf(( "SerialPortSetChars -> EofChar: %d, ErrorChar: %d, BreakChar: %d, EventChar: %d, XonChar: %d, XoffChar: %d\n",
chars->EofChar, chars->ErrorChar, chars->BreakChar, chars->EventChar, chars->XonChar, chars->XoffChar ));
}
return status;
}
NTSTATUS SerialPortGetHandflow( SerialPort* serialPort, PSERIAL_HANDFLOW handflow )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( handflow == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
handflow->ControlHandShake = serialPort->handflow.ControlHandShake;
handflow->FlowReplace = serialPort->handflow.FlowReplace;
handflow->XonLimit = serialPort->handflow.XonLimit;
handflow->XoffLimit = serialPort->handflow.XoffLimit;
DebugPrintf(( "SerialPortGetHandflow -> ControlHandShake: %X, FlowReplace: %X, XonLimit: %d, XoffLimit: %d\n",
handflow->ControlHandShake, handflow->FlowReplace, handflow->XonLimit, handflow->XoffLimit ));
}
return status;
}
NTSTATUS SerialPortSetHandflow( SerialPort* serialPort, PSERIAL_HANDFLOW handflow )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( handflow == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
serialPort->handflow.ControlHandShake = handflow->ControlHandShake;
serialPort->handflow.FlowReplace = handflow->FlowReplace;
serialPort->handflow.XonLimit = handflow->XonLimit;
serialPort->handflow.XoffLimit = handflow->XoffLimit;
DebugPrintf(( "SerialPortSetHandflow -> ControlHandShake: %X, FlowReplace: %X, XonLimit: %d, XoffLimit: %d\n",
handflow->ControlHandShake, handflow->FlowReplace, handflow->XonLimit, handflow->XoffLimit ));
}
return status;
}
NTSTATUS SerialPortSetRTS( SerialPort* serialPort )
{
NTSTATUS status = STATUS_SUCCESS;
if ( serialPort == NULL )
{
status = STATUS_INVALID_PARAMETER;
}
DebugPrintf(( "SerialPortSetRTS\n" ));
return status;
}
NTSTATUS SerialPortClearRTS( SerialPort* serialPort )
{
NTSTATUS status = STATUS_SUCCESS;
if ( serialPort == NULL )
{
status = STATUS_INVALID_PARAMETER;
}
DebugPrintf(( "SerialPortClearRTS\n" ));
return status;
}
NTSTATUS SerialPortSetDTR( SerialPort* serialPort )
{
NTSTATUS status = STATUS_SUCCESS;
if ( serialPort == NULL )
{
status = STATUS_INVALID_PARAMETER;
}
DebugPrintf(( "SerialPortSetDTR\n" ));
return status;
}
NTSTATUS SerialPortClearDTR( SerialPort* serialPort )
{
NTSTATUS status = STATUS_SUCCESS;
if ( serialPort == NULL )
{
status = STATUS_INVALID_PARAMETER;
}
DebugPrintf(( "SerialPortClearDTR\n" ));
return status;
}
NTSTATUS SerialPortSetTimeouts( SerialPort* serialPort, PSERIAL_TIMEOUTS timeouts )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( timeouts == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( ( timeouts->ReadIntervalTimeout == MAXULONG ) &&
( timeouts->ReadTotalTimeoutConstant == MAXULONG ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
serialPort->timeouts.ReadIntervalTimeout = timeouts->ReadIntervalTimeout;
serialPort->timeouts.ReadTotalTimeoutMultiplier = timeouts->ReadTotalTimeoutMultiplier;
serialPort->timeouts.ReadTotalTimeoutConstant = timeouts->ReadTotalTimeoutConstant;
serialPort->timeouts.WriteTotalTimeoutMultiplier = timeouts->WriteTotalTimeoutMultiplier;
serialPort->timeouts.WriteTotalTimeoutConstant = timeouts->WriteTotalTimeoutConstant;
}
DebugPrintf(( "SerialPortSetTimeouts -> ReadIntervalTimeout: %u, ReadTotalTimeoutMultiplier: %u, ReadTotalTimeoutConstant: %u, WriteTotalTimeoutMultiplier: %u, WriteTotalTimeoutConstant: %u\n",
timeouts->ReadIntervalTimeout, timeouts->ReadTotalTimeoutMultiplier, timeouts->ReadTotalTimeoutConstant, timeouts->WriteTotalTimeoutMultiplier, timeouts->WriteTotalTimeoutConstant ));
}
return status;
}
NTSTATUS SerialPortGetTimeouts( SerialPort* serialPort, PSERIAL_TIMEOUTS timeouts )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( timeouts == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
timeouts->ReadIntervalTimeout = serialPort->timeouts.ReadIntervalTimeout;
timeouts->ReadTotalTimeoutMultiplier = serialPort->timeouts.ReadTotalTimeoutMultiplier;
timeouts->ReadTotalTimeoutConstant = serialPort->timeouts.ReadTotalTimeoutConstant;
timeouts->WriteTotalTimeoutMultiplier = serialPort->timeouts.WriteTotalTimeoutMultiplier;
timeouts->WriteTotalTimeoutConstant = serialPort->timeouts.WriteTotalTimeoutConstant;
DebugPrintf(( "SerialPortGetTimeouts -> ReadIntervalTimeout: %u, ReadTotalTimeoutMultiplier: %u, ReadTotalTimeoutConstant: %u, WriteTotalTimeoutMultiplier: %u, WriteTotalTimeoutConstant: %u\n",
timeouts->ReadIntervalTimeout, timeouts->ReadTotalTimeoutMultiplier, timeouts->ReadTotalTimeoutConstant, timeouts->WriteTotalTimeoutMultiplier, timeouts->WriteTotalTimeoutConstant ));
}
return status;
}
NTSTATUS SerialPortWaitOnMask( SerialPort* serialPort, PULONG waitEvents, PIRP pIrp )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( waitEvents == NULL ) || ( pIrp == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( ( serialPort->waitMask.currentWaitMask == 0 ) || ( serialPort->waitMask.waitOnMaskPending == 1 ) )
{
status = STATUS_INVALID_PARAMETER;
*waitEvents = 0;
}
else
{
serialPort->waitMask.waitOnMaskPending = 1;
status = STATUS_PENDING;
serialPort->waitMask.pIrp = pIrp;
serialPort->waitMask.waitEvents = waitEvents;
*waitEvents = 0;
}
DebugPrintf(( "SerialPortWaitOnMask 0x%X\n", *waitEvents ));
}
return status;
}
NTSTATUS SerialPortSetWaitMask( SerialPort* serialPort, PULONG newWaitMask )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( newWaitMask == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( SerialPortValidateFlags( *newWaitMask,
SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG |
SERIAL_EV_TXEMPTY | SERIAL_EV_CTS |
SERIAL_EV_DSR | SERIAL_EV_RLSD |
SERIAL_EV_BREAK | SERIAL_EV_ERR |
SERIAL_EV_RING | SERIAL_EV_PERR |
SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2 ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
}
if ( status == STATUS_SUCCESS )
{
if ( serialPort->waitMask.waitOnMaskPending == 1 )
{
PlxCompleteIrpWithInformation( serialPort->waitMask.pIrp, STATUS_SUCCESS, 0 );
serialPort->waitMask.waitOnMaskPending = 0;
serialPort->waitMask.pIrp = NULL;
}
serialPort->waitMask.currentWaitMask = *newWaitMask;
}
DebugPrintf(( "SerialPortSetWaitMask 0x%X\n", serialPort->waitMask.currentWaitMask ));
}
return status;
}
NTSTATUS SerialPortGetWaitMask( SerialPort* serialPort, PULONG waitMask )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( waitMask == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
*waitMask = serialPort->waitMask.currentWaitMask;
DebugPrintf(( "SerialPortGetWaitMask 0x%X\n", serialPort->waitMask.currentWaitMask ));
}
return status;
}
NTSTATUS SerialPortPurge( SerialPort* serialPort, PULONG purgeMask )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( purgeMask == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( SerialPortValidateFlags( *purgeMask,
SERIAL_PURGE_RXABORT |
SERIAL_PURGE_RXCLEAR |
SERIAL_PURGE_TXABORT |
SERIAL_PURGE_TXCLEAR ) == 0 )
{
status = STATUS_INVALID_PARAMETER;
DebugPrintf(( "SerialPortPurge invalid flag set %d\n", *purgeMask ));
}
else
{
if ( *purgeMask & SERIAL_PURGE_RXABORT )
{
TryCancellingRead( serialPort );
}
if ( *purgeMask & SERIAL_PURGE_RXCLEAR )
{
TryCancellingRead( serialPort );
LockQueue( &serialPort->receiveQueue );
InitialiseQueue( &serialPort->receiveQueue, serialPort->receiveQueue.size );
UnlockQueue( &serialPort->receiveQueue );
}
if ( *purgeMask & ( SERIAL_PURGE_TXABORT | SERIAL_PURGE_TXCLEAR ) )
{
TryCancellingWrite( serialPort );
}
DebugPrintf(( "SerialPortPurge 0x%.1X\n", *purgeMask ));
}
}
return status;
}
NTSTATUS SerialPortGetCommStatus( SerialPort* serialPort, PSERIAL_STATUS serialStatus )
{
NTSTATUS status = STATUS_SUCCESS;
ULONG currentTxQueueUsed = 0;
ULONG currentRxQueueUsed = 0;
if ( ( serialStatus == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
LockQueue( &serialPort->receiveQueue );
currentRxQueueUsed = serialPort->receiveQueue.used;
UnlockQueue( &serialPort->receiveQueue );
LockQueue( &serialPort->transmitQueue );
currentTxQueueUsed = serialPort->transmitQueue.used;
UnlockQueue( &serialPort->transmitQueue );
serialStatus->Errors = 0;
serialStatus->HoldReasons = 0;
serialStatus->AmountInInQueue = currentRxQueueUsed;
serialStatus->AmountInOutQueue = currentTxQueueUsed;
serialStatus->EofReceived = 0;
serialStatus->WaitForImmediate = 0;
DebugPrintf(( "SerialPortGetCommStatus\n"));
}
return status;
}
NTSTATUS SerialPortGetProperties( SerialPort* serialPort, PSERIAL_COMMPROP commProperties )
{
NTSTATUS status = STATUS_SUCCESS;
ULONG currentTxQueueSize = 0;
ULONG currentRxQueueSize = 0;
if ( ( commProperties == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
commProperties->PacketLength = sizeof( SERIAL_COMMPROP );
commProperties->PacketVersion = 2;
commProperties->ServiceMask = SERIAL_SP_SERIALCOMM;
commProperties->MaxTxQueue = 0;
commProperties->MaxRxQueue = 0;
commProperties->MaxBaud = SERIAL_BAUD_38400;
commProperties->ProvSubType = SERIAL_SP_RS232;
commProperties->ProvCapabilities = SERIAL_PCF_PARITY_CHECK | SERIAL_PCF_SETXCHAR | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS | SERIAL_PCF_SPECIALCHARS;
commProperties->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_PARITY_CHECK;
commProperties->SettableBaud = SERIAL_BAUD_075 | SERIAL_BAUD_110 | SERIAL_BAUD_150 | SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_1800 |
SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_9600 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400;
commProperties->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8;
commProperties->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE;
LockQueue( &serialPort->receiveQueue );
currentRxQueueSize = serialPort->receiveQueue.size;
UnlockQueue( &serialPort->receiveQueue );
commProperties->CurrentTxQueue = currentTxQueueSize;
commProperties->CurrentRxQueue = currentRxQueueSize;
commProperties->ProvSpec1 = 0;
commProperties->ProvSpec2 = 0;
commProperties->ProvChar[0] = 0;
DebugPrintf(( "SerialPortGetProperties\n" ));
}
return status;
}
NTSTATUS SerialPortWrite( SerialPort* serialPort, unsigned int numberOfBytes, void* buffer, unsigned int* numberOfBytesWritten, PIRP pIrp )
{
NTSTATUS status = STATUS_SUCCESS;
LARGE_INTEGER dueTime = { 0 };
if ( ( numberOfBytesWritten == NULL ) || ( buffer == NULL ) || ( serialPort == NULL ) )
{
if ( numberOfBytesWritten != NULL )
{
*numberOfBytesWritten = 0;
}
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( numberOfBytes == 0 )
{
*numberOfBytesWritten = 0;
}
else
{
SerialPortCopyToWriteBuffer( serialPort, numberOfBytes, buffer, numberOfBytesWritten );
dueTime.QuadPart = -((LONGLONG)( ( serialPort->timeouts.WriteTotalTimeoutMultiplier * numberOfBytes ) + serialPort->timeouts.WriteTotalTimeoutConstant ) * MillisecondsTo100Nanoseconds );
if ( dueTime.QuadPart != 0 )
{
KeSetTimer( &serialPort->writeTimeout.timer, dueTime, &serialPort->writeTimeout.timeoutDpc );
}
{
SetWriteInterrupt( serialPort->baseAddress, serialPort->uartType );
}
}
}
return status;
}
NTSTATUS SerialPortRead( SerialPort* serialPort, unsigned int numberOfBytes, void* buffer, unsigned int* numberOfBytesRead, PIRP pIrp )
{
KIRQL cancelIRQL;
NTSTATUS status = STATUS_SUCCESS;
unsigned char pendRequest = 0;
LARGE_INTEGER dueTime = { 0 };
unsigned int receiveQueueUsed = 0;
if ( numberOfBytesRead != NULL )
{
*numberOfBytesRead = 0;
}
if ( ( numberOfBytesRead == NULL ) || ( buffer == NULL ) || ( serialPort == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
if ( ( serialPort->timeouts.ReadIntervalTimeout == MAXULONG ) &&
( serialPort->timeouts.ReadTotalTimeoutConstant == 0 ) &&
( serialPort->timeouts.ReadTotalTimeoutMultiplier == 0 ) )
{
}
else
{
LockQueue( &serialPort->receiveQueue );
receiveQueueUsed = serialPort->receiveQueue.used;
UnlockQueue( &serialPort->receiveQueue );
if ( ( serialPort->timeouts.ReadIntervalTimeout == MAXULONG ) &&
( serialPort->timeouts.ReadTotalTimeoutMultiplier == MAXULONG ) &&
( serialPort->timeouts.ReadTotalTimeoutConstant < MAXULONG ) )
{
if ( receiveQueueUsed == 0 )
{
pendRequest = 1;
numberOfBytes = 1;
}
}
else if ( receiveQueueUsed < numberOfBytes )
{
pendRequest = 1;
}
}
if ( pendRequest == 1 )
{
status = STATUS_PENDING;
KeAcquireSpinLock( &serialPort->pendingRead.lock, &serialPort->pendingRead.irqlOriginal );
serialPort->pendingRead.pIrp = pIrp;
serialPort->pendingRead.bufferLength = numberOfBytes;
IoAcquireCancelSpinLock( &cancelIRQL );
IoSetCancelRoutine( pIrp, SerialCancelCurrentRead );
IoReleaseCancelSpinLock( cancelIRQL );
KeReleaseSpinLock( &serialPort->pendingRead.lock, serialPort->pendingRead.irqlOriginal );
IoMarkIrpPending( pIrp );
dueTime.QuadPart = -((LONGLONG)( ( serialPort->timeouts.ReadTotalTimeoutMultiplier * numberOfBytes ) + serialPort->timeouts.ReadTotalTimeoutConstant ) * MillisecondsTo100Nanoseconds );
if ( dueTime.QuadPart != 0 )
{
KeSetTimer( &serialPort->readTimeout.timer, dueTime, &serialPort->readTimeout.timeoutDpc );
}
}
else
{
SerialPortCopyFromReceiveBuffer( serialPort, numberOfBytes, buffer, numberOfBytesRead );
}
}
return status;
}
NTSTATUS SerialPortClearStats( SerialPort* serialPort )
{
NTSTATUS status = STATUS_SUCCESS;
if ( serialPort == NULL )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
serialPort->performanceStats.ReceivedCount = 0;
serialPort->performanceStats.TransmittedCount = 0;
serialPort->performanceStats.FrameErrorCount = 0;
serialPort->performanceStats.SerialOverrunErrorCount = 0;
serialPort->performanceStats.BufferOverrunErrorCount = 0;
serialPort->performanceStats.ParityErrorCount = 0;
DebugPrintf(( "SerialClearStats\n" ));
}
return status;
}
NTSTATUS SerialPortGetStats( SerialPort* serialPort, SERIALPERF_STATS* performanceStats )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( serialPort == NULL ) || ( performanceStats == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
performanceStats->ReceivedCount = serialPort->performanceStats.ReceivedCount;
performanceStats->TransmittedCount = serialPort->performanceStats.TransmittedCount;
performanceStats->FrameErrorCount = serialPort->performanceStats.FrameErrorCount;
performanceStats->SerialOverrunErrorCount = serialPort->performanceStats.SerialOverrunErrorCount;
performanceStats->BufferOverrunErrorCount = serialPort->performanceStats.BufferOverrunErrorCount;
performanceStats->ParityErrorCount = serialPort->performanceStats.ParityErrorCount;
DebugPrintf(( "SerialGetStats: ReceivedCount %d, TransmittedCount %d, FrameErrorCount %d, SerialOverrunErrorCount %d, BufferOverrunErrorCount %d, ParityErrorCount %d\n",
serialPort->performanceStats.ReceivedCount,
serialPort->performanceStats.TransmittedCount,
serialPort->performanceStats.FrameErrorCount,
serialPort->performanceStats.SerialOverrunErrorCount,
serialPort->performanceStats.BufferOverrunErrorCount,
serialPort->performanceStats.ParityErrorCount ));
}
return status;
}
NTSTATUS SerialPortGetDTRRTS( SerialPort* serialPort, PULONG dtrRts )
{
NTSTATUS status = STATUS_SUCCESS;
if ( ( serialPort == NULL ) || ( dtrRts == NULL ) )
{
status = STATUS_INVALID_PARAMETER;
}
else
{
*dtrRts = 0;
DebugPrintf(( "SerialPortGetDTRRTS\n" ));
}
return status;
}
What I have tried:
1.Disabled the keAquireSpinlock and keReleasespinlock - which reduced the frequency of errors but the underlying problem of repeat characters persists.