Correct IOCTL_SERIAL_CLEAR_STATS and IOCTL_SERIAL_PURGE
authorHervé Poussineau <hpoussin@reactos.org>
Mon, 4 Apr 2005 22:48:51 +0000 (22:48 +0000)
committerHervé Poussineau <hpoussin@reactos.org>
Mon, 4 Apr 2005 22:48:51 +0000 (22:48 +0000)
Manage read errors (overrun, parity, ...)
Use output buffer even if Uart is ready to transmit

svn path=/trunk/; revision=14490

reactos/drivers/dd/serial/devctrl.c
reactos/drivers/dd/serial/misc.c
reactos/drivers/dd/serial/rw.c
reactos/drivers/dd/serial/serial.h

index 12c2e61..fb43321 100644 (file)
@@ -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:
index e521dee..04c2205 100644 (file)
@@ -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;
index 2ec9ddc..da82736 100644 (file)
@@ -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;
index b248160..9fb3094 100644 (file)
@@ -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 */