Correct IOCTL_SERIAL_CLEAR_STATS and IOCTL_SERIAL_PURGE
Manage read errors (overrun, parity, ...)
Use output buffer even if Uart is ready to transmit
Modified: trunk/reactos/drivers/dd/serial/devctrl.c
Modified: trunk/reactos/drivers/dd/serial/misc.c
Modified: trunk/reactos/drivers/dd/serial/rw.c
Modified: trunk/reactos/drivers/dd/serial/serial.h
_____
Modified: trunk/reactos/drivers/dd/serial/devctrl.c
--- trunk/reactos/drivers/dd/serial/devctrl.c 2005-04-04 22:05:08 UTC
(rev 14489)
+++ trunk/reactos/drivers/dd/serial/devctrl.c 2005-04-04 22:48:51 UTC
(rev 14490)
@@ -182,9 +182,10 @@
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 @@
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 @@
KeSynchronizeExecution(
DeviceExtension->Interrupt,
(PKSYNCHRONIZE_ROUTINE)SerialClearPerfStats,
- &DeviceExtension->SerialPerfStats);
+ DeviceExtension);
Status = STATUS_SUCCESS;
break;
}
@@ -552,27 +564,52 @@
}
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:
_____
Modified: trunk/reactos/drivers/dd/serial/misc.c
--- trunk/reactos/drivers/dd/serial/misc.c 2005-04-04 22:05:08 UTC
(rev 14489)
+++ trunk/reactos/drivers/dd/serial/misc.c 2005-04-04 22:48:51 UTC
(rev 14490)
@@ -78,7 +78,7 @@
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 @@
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 @@
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 @@
}
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.SerialOverrunErro
rCount);
+ 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;
_____
Modified: trunk/reactos/drivers/dd/serial/rw.c
--- trunk/reactos/drivers/dd/serial/rw.c 2005-04-04 22:05:08 UTC
(rev 14489)
+++ trunk/reactos/drivers/dd/serial/rw.c 2005-04-04 22:48:51 UTC
(rev 14490)
@@ -274,25 +274,8 @@
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 @@
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;
_____
Modified: trunk/reactos/drivers/dd/serial/serial.h
--- trunk/reactos/drivers/dd/serial/serial.h 2005-04-04 22:05:08 UTC
(rev 14489)
+++ trunk/reactos/drivers/dd/serial/serial.h 2005-04-04 22:48:51 UTC
(rev 14490)
@@ -90,6 +90,7 @@
UART_TYPE UartType;
ULONG WaitMask;
+ ULONG BreakInterruptErrorCount;
SERIALPERF_STATS SerialPerfStats;
SERIAL_TIMEOUTS SerialTimeOuts;
BOOLEAN IsOpened;
@@ -169,11 +170,23 @@
#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 */