From 8fb19a43597dd7d3185a619fc716545ff6ffd96d Mon Sep 17 00:00:00 2001 From: ligd Date: Wed, 6 Nov 2019 07:01:27 -0600 Subject: [PATCH] drivers/serial/serial_dma.c: Avoid uart_xmitchars_done() move the tail bigger then head. If ioctl(TCOFLUSH) occurs between uart_xmitchars_dma() and uart_xmitchars_done(), TCOFLUSH will reset xmit buffer, then uart_xmitchars_done() will move the 'tail' ahead of 'head', then sends lots of wrong data. --- drivers/serial/serial_dma.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/serial/serial_dma.c b/drivers/serial/serial_dma.c index 17c453a79a..de82c9c146 100644 --- a/drivers/serial/serial_dma.c +++ b/drivers/serial/serial_dma.c @@ -193,11 +193,18 @@ void uart_xmitchars_done(FAR uart_dev_t *dev) size_t nbytes = xfer->nbytes; struct uart_buffer_s *txbuf = &dev->xmit; - /* Move tail for nbytes. */ + /* Skip the update if the tail position change which mean + * someone reset (e.g. TCOFLUSH) the xmit buffer during DMA. + */ - txbuf->tail = (txbuf->tail + nbytes) % txbuf->size; - xfer->nbytes = 0; - xfer->length = xfer->nlength = 0; + if (xfer->buffer == &txbuf->buffer[txbuf->tail]) + { + /* Move tail for nbytes. */ + + txbuf->tail = (txbuf->tail + nbytes) % txbuf->size; + xfer->nbytes = 0; + xfer->length = xfer->nlength = 0; + } /* If any bytes were removed from the buffer, inform any waiters there there is * space available.