From 4f0238339e54067ffdf64b63c849da345552cdda Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 1 Aug 2017 07:39:08 -0600 Subject: [PATCH] serial.c: Finish implementation of TCDRAIN. Based partly on logic from Sebastien Lorquet. --- drivers/serial/serial.c | 86 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index cc0e2fe441a..46955382389 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -1001,12 +1001,94 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; -#if 0 case TCDRN: { + /* Get exclusive access to the to dev->tmit. We cannot permit + * new data to be written while we are trying to flush the old + * data. + * + * A signal received while waiting for access to the xmit.head + * will abort the operation with EINTR. + */ + + ret = (ssize_t)uart_takesem(&dev->xmit.sem, true); + if (ret >= 0) + { + irqstate_t flags; + + /* Trigger emission to flush the contents of the tx buffer */ + + flags = enter_critical_section(); + +#ifdef CONFIG_SERIAL_REMOVABLE + /* Check if the removable device is no longer connected + * while we have interrupts off. We do not want the + * transition to occur as a race condition before we begin + * the wait. + */ + + if (dev->disconnected) + { + ret = -ENOTCONN; + } + else +#endif + { + /* Continue waiting while the TX buffer is not empty */ + + ret = OK; + while (ret >= 0 && dev->xmit.head != dev->xmit.tail) + { + /* Inform the interrupt level logic that we are + * waiting. + */ + + dev->xmitwaiting = true; + + /* Wait for some characters to be sent from the + * buffer with the TX interrupt enabled. When the + * TX interrupt is enabled, uart_xmitchars() + * should execute and remove some of the data from + * the TX buffer. We mayhave to wait several + * times for the TX buffer to be entirely emptied. + * + * NOTE that interrupts will be re-enabled while we + * wait for the semaphore. + */ + +#ifdef CONFIG_SERIAL_DMA + uart_dmatxavail(dev); +#endif + uart_enabletxint(dev); + ret = uart_takesem(&dev->xmitsem, true); + uart_disabletxint(dev); + } + } + + leave_critical_section(flags); + + /* The TX buffer is empty (or an error occurred). But + * there still may be data in the UART TX FIFO. We get no + * asynchronous indication of this event, so we have to do + * a busy wait poll. + */ + + if (ret >= 0) + { + while (!uart_txempty(dev)) + { +#ifndef CONFIG_DISABLE_SIGNALS + usleep(HALF_SECOND_USEC); +#else + up_mdelay(HALF_SECOND_MSEC); +#endif + } + } + + uart_givesem(&dev->xmit.sem); + } } break; -#endif #endif } }