mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 12:23:31 +00:00
Correct IOCTL_SERIAL_CLEAR_STATS and IOCTL_SERIAL_PURGE
Manage read errors (overrun, parity, ...) Use output buffer even if Uart is ready to transmit svn path=/trunk/; revision=14490
This commit is contained in:
@@ -182,9 +182,10 @@ SerialSetLineControl(
|
||||
|
||||
BOOLEAN
|
||||
SerialClearPerfStats(
|
||||
IN PSERIALPERF_STATS pSerialPerfStats)
|
||||
IN PSERIAL_DEVICE_EXTENSION DeviceExtension)
|
||||
{
|
||||
RtlZeroMemory(pSerialPerfStats, sizeof(SERIALPERF_STATS));
|
||||
RtlZeroMemory(&DeviceExtension->SerialPerfStats, sizeof(SERIALPERF_STATS));
|
||||
DeviceExtension->BreakInterruptErrorCount = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -258,7 +259,18 @@ SerialGetCommStatus(
|
||||
|
||||
RtlZeroMemory(pSerialStatus, sizeof(SERIAL_STATUS));
|
||||
|
||||
pSerialStatus->Errors = 0; /* FIXME */
|
||||
pSerialStatus->Errors = 0;
|
||||
if (DeviceExtension->BreakInterruptErrorCount)
|
||||
pSerialStatus->Errors |= SERIAL_ERROR_BREAK;
|
||||
if (DeviceExtension->SerialPerfStats.FrameErrorCount)
|
||||
pSerialStatus->Errors |= SERIAL_ERROR_FRAMING;
|
||||
if (DeviceExtension->SerialPerfStats.SerialOverrunErrorCount)
|
||||
pSerialStatus->Errors |= SERIAL_ERROR_OVERRUN;
|
||||
if (DeviceExtension->SerialPerfStats.BufferOverrunErrorCount)
|
||||
pSerialStatus->Errors |= SERIAL_ERROR_QUEUEOVERRUN;
|
||||
if (DeviceExtension->SerialPerfStats.ParityErrorCount)
|
||||
pSerialStatus->Errors |= SERIAL_ERROR_PARITY;
|
||||
|
||||
pSerialStatus->HoldReasons = 0; /* FIXME */
|
||||
|
||||
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
|
||||
@@ -311,7 +323,7 @@ SerialDeviceControl(
|
||||
KeSynchronizeExecution(
|
||||
DeviceExtension->Interrupt,
|
||||
(PKSYNCHRONIZE_ROUTINE)SerialClearPerfStats,
|
||||
&DeviceExtension->SerialPerfStats);
|
||||
DeviceExtension);
|
||||
Status = STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
@@ -552,27 +564,52 @@ SerialDeviceControl(
|
||||
}
|
||||
case IOCTL_SERIAL_PURGE:
|
||||
{
|
||||
KIRQL Irql1, Irql2;
|
||||
KIRQL Irql;
|
||||
DPRINT("Serial: IOCTL_SERIAL_PURGE\n");
|
||||
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql1);
|
||||
KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql2);
|
||||
DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0;
|
||||
DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0;
|
||||
/* Clear receive/transmit buffers */
|
||||
if (DeviceExtension->UartType >= Uart16550A)
|
||||
/* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
|
||||
* should stop current request */
|
||||
if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
else
|
||||
{
|
||||
/* 16550 UARTs also have FIFO queues, but they are unusable due to a bug */
|
||||
Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
if (NT_SUCCESS(Status))
|
||||
ULONG PurgeMask = *(PULONG)BufferIn;
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
/* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
|
||||
if (PurgeMask & SERIAL_PURGE_RXCLEAR)
|
||||
{
|
||||
WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT);
|
||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
|
||||
DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0;
|
||||
if (DeviceExtension->UartType >= Uart16550A)
|
||||
{
|
||||
/* Clear also Uart FIFO */
|
||||
Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_RCVR);
|
||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
}
|
||||
}
|
||||
KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
|
||||
}
|
||||
|
||||
if (PurgeMask & SERIAL_PURGE_TXCLEAR)
|
||||
{
|
||||
KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
|
||||
DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0;
|
||||
if (DeviceExtension->UartType >= Uart16550A)
|
||||
{
|
||||
/* Clear also Uart FIFO */
|
||||
Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_XMIT);
|
||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
}
|
||||
}
|
||||
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
|
||||
}
|
||||
}
|
||||
else
|
||||
Status = STATUS_SUCCESS;
|
||||
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql2);
|
||||
KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql1);
|
||||
break;
|
||||
}
|
||||
case IOCTL_SERIAL_RESET_DEVICE:
|
||||
|
||||
@@ -78,7 +78,7 @@ SerialReceiveByte(
|
||||
ComPortBase = (PUCHAR)DeviceExtension->BaseAddress;
|
||||
|
||||
KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
|
||||
while (READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR)
|
||||
while (READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DATA_RECEIVED)
|
||||
{
|
||||
Byte = READ_PORT_UCHAR(SER_RBR(ComPortBase));
|
||||
DPRINT("Serial: Byte received on COM%lu: 0x%02x\n",
|
||||
@@ -116,7 +116,7 @@ SerialSendByte(
|
||||
|
||||
KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
|
||||
while (!IsCircularBufferEmpty(&DeviceExtension->OutputBuffer)
|
||||
&& READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE)
|
||||
&& READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_THR_EMPTY)
|
||||
{
|
||||
Status = PopCircularBufferEntry(&DeviceExtension->OutputBuffer, &Byte);
|
||||
if (!NT_SUCCESS(Status))
|
||||
@@ -153,16 +153,28 @@ SerialInterruptService(
|
||||
Iir &= SR_IIR_ID_MASK;
|
||||
if ((Iir & SR_IIR_SELF) != 0) { return FALSE; }
|
||||
|
||||
/* FIXME: sometimes, update DeviceExtension->MCR */
|
||||
switch (Iir)
|
||||
{
|
||||
case SR_IIR_MSR_CHANGE:
|
||||
{
|
||||
UCHAR IER;
|
||||
DPRINT1("Serial: SR_IIR_MSR_CHANGE\n");
|
||||
UCHAR MSR, IER;
|
||||
DPRINT("Serial: SR_IIR_MSR_CHANGE\n");
|
||||
|
||||
DeviceExtension->MSR = READ_PORT_UCHAR(SER_MSR(ComPortBase));
|
||||
/* FIXME: what to do? */
|
||||
MSR = READ_PORT_UCHAR(SER_MSR(ComPortBase));
|
||||
if (MSR & SR_MSR_CTS_CHANGED)
|
||||
{
|
||||
if (MSR & SR_MSR_CTS)
|
||||
KeInsertQueueDpc(&DeviceExtension->SendByteDpc, NULL, NULL);
|
||||
else
|
||||
; /* FIXME: stop transmission */
|
||||
}
|
||||
if (MSR & SR_MSR_DSR_CHANGED)
|
||||
{
|
||||
if (MSR & SR_MSR_DSR)
|
||||
KeInsertQueueDpc(&DeviceExtension->ReceivedByteDpc, NULL, NULL);
|
||||
else
|
||||
; /* FIXME: stop reception */
|
||||
}
|
||||
IER = READ_PORT_UCHAR(SER_IER(ComPortBase));
|
||||
WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER | SR_IER_MSR_CHANGE);
|
||||
return TRUE;
|
||||
@@ -183,24 +195,20 @@ SerialInterruptService(
|
||||
}
|
||||
case SR_IIR_ERROR:
|
||||
{
|
||||
/* FIXME: what to do? */
|
||||
DPRINT1("Serial: SR_IIR_ERROR\n");
|
||||
break;
|
||||
/*Error = READ_PORT_UCHAR( Self->Port + UART_LSR );
|
||||
if( Error & LSR_OVERRUN )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::OVERRUN );
|
||||
DeviceExtension->SerialPerfStats.SerialOverrunErrorCount++;
|
||||
if( Error & LSR_PARITY_ERROR )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::PARITY );
|
||||
DeviceExtension->SerialPerfStats.ParityErrorCount++;
|
||||
if( Error & LSR_FRAMING_ERROR )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::FRAMING );
|
||||
DeviceExtension->SerialPerfStats.FrameErrorCount++;
|
||||
if( Error & LSR_BREAK )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::BREAK );
|
||||
if( Error & LSR_TIMEOUT )
|
||||
Self->WaitingReadBytes.PushBack( SerialFifo::TIMEOUT );
|
||||
return KeInsertQueueDpc( &Self->DataInDpc, Self, 0 );*/
|
||||
UCHAR LSR;
|
||||
DPRINT("Serial: SR_IIR_ERROR\n");
|
||||
|
||||
LSR = READ_PORT_UCHAR(SER_LSR(ComPortBase));
|
||||
if (LSR & SR_LSR_OVERRUN_ERROR)
|
||||
InterlockedIncrement(&DeviceExtension->SerialPerfStats.SerialOverrunErrorCount);
|
||||
if (LSR & SR_LSR_PARITY_ERROR)
|
||||
InterlockedIncrement(&DeviceExtension->SerialPerfStats.ParityErrorCount);
|
||||
if (LSR & SR_LSR_FRAMING_ERROR)
|
||||
InterlockedIncrement(&DeviceExtension->SerialPerfStats.FrameErrorCount);
|
||||
if (LSR & SR_LSR_BREAK_INT)
|
||||
InterlockedIncrement(&DeviceExtension->BreakInterruptErrorCount);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
@@ -274,25 +274,8 @@ SerialWrite(
|
||||
if (!NT_SUCCESS(Status))
|
||||
goto ByeBye;
|
||||
|
||||
/* push bytes into output buffer */
|
||||
KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
|
||||
if (IsCircularBufferEmpty(&DeviceExtension->OutputBuffer))
|
||||
{
|
||||
/* Put the maximum amount of data in UART output buffer */
|
||||
while (Information < Length)
|
||||
{
|
||||
/* if UART output buffer is not full, directly write to it */
|
||||
if ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE) != 0)
|
||||
{
|
||||
DPRINT("Serial: direct write 0x%02x (%c)\n", Buffer[Information], Buffer[Information]);
|
||||
WRITE_PORT_UCHAR(SER_THR(ComPortBase), Buffer[Information]);
|
||||
DeviceExtension->SerialPerfStats.TransmittedCount++;
|
||||
Information++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* write remaining bytes into output buffer */
|
||||
while (Information < Length)
|
||||
{
|
||||
Status = PushCircularBufferEntry(&DeviceExtension->OutputBuffer, Buffer[Information]);
|
||||
@@ -302,11 +285,13 @@ SerialWrite(
|
||||
DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++;
|
||||
break;
|
||||
}
|
||||
DPRINT1("Serial: write to buffer 0x%02x\n", Buffer[Information]);
|
||||
Information++;
|
||||
}
|
||||
KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
|
||||
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, (PVOID)DeviceExtension->ComPort);
|
||||
|
||||
/* send bytes */
|
||||
SerialSendByte(NULL, DeviceExtension, NULL, NULL);
|
||||
|
||||
ByeBye:
|
||||
Irp->IoStatus.Information = Information;
|
||||
|
||||
@@ -90,6 +90,7 @@ typedef struct _SERIAL_DEVICE_EXTENSION
|
||||
UART_TYPE UartType;
|
||||
ULONG WaitMask;
|
||||
|
||||
ULONG BreakInterruptErrorCount;
|
||||
SERIALPERF_STATS SerialPerfStats;
|
||||
SERIAL_TIMEOUTS SerialTimeOuts;
|
||||
BOOLEAN IsOpened;
|
||||
@@ -169,11 +170,23 @@ typedef struct _WORKITEM_DATA
|
||||
#define SR_MCR_DTR 0x01
|
||||
#define SR_MCR_RTS 0x02
|
||||
#define SER_LSR(x) ((x)+5) /* Line Status Register */
|
||||
#define SR_LSR_DR 0x01
|
||||
#define SR_LSR_TBE 0x20
|
||||
#define SR_LSR_DATA_RECEIVED 0x01
|
||||
#define SR_LSR_OVERRUN_ERROR 0x02
|
||||
#define SR_LSR_PARITY_ERROR 0x04
|
||||
#define SR_LSR_FRAMING_ERROR 0x08
|
||||
#define SR_LSR_BREAK_INT 0x10
|
||||
#define SR_LSR_THR_EMPTY 0x20
|
||||
#define SR_LSR_TSR_EMPTY 0x40
|
||||
#define SR_LSR_ERROR_IN_FIFO 0x80 /* Uart >= 16550A */
|
||||
#define SER_MSR(x) ((x)+6) /* Modem Status Register */
|
||||
#define SR_MSR_CTS 0x10
|
||||
#define SR_MSR_DSR 0x20
|
||||
#define SR_MSR_CTS_CHANGED 0x01
|
||||
#define SR_MSR_DSR_CHANGED 0x02
|
||||
#define SR_MSR_RI_CHANGED 0x04
|
||||
#define SR_MSR_DCD_CHANGED 0x08
|
||||
#define SR_MSR_CTS 0x10 /* Clear To Send */
|
||||
#define SR_MSR_DSR 0x20 /* Data Set Ready */
|
||||
#define SI_MSR_RI 0x40 /* Ring Indicator */
|
||||
#define SR_MSR_DCD 0x80 /* Data Carrier Detect */
|
||||
#define SER_SCR(x) ((x)+7) /* Scratch Pad Register */
|
||||
|
||||
/************************************ circularbuffer.c */
|
||||
|
||||
Reference in New Issue
Block a user