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 */