From e0b4a10dfa86d5dfb891720a0b19d0471005e509 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 25 Jul 2016 14:06:32 -0600 Subject: [PATCH] drivers/serial/pty.c, serial.c, usbdev/cdcacm.c, include/nuttx/fs/ioctl.h: Fix FIONWRITE and add FIONSPACE. All implementations of FIONWRITE were wrong. FIONWRITE should return the number of bytes waiting in the outgoing send queue, not the free space. Rather, FIONSPACE should return the free space in the send queue. --- drivers/pipes/pipe_common.c | 21 +++++++++++++++++---- drivers/serial/pty.c | 31 +++++++++++++++++++++++++++++++ drivers/serial/serial.c | 35 +++++++++++++++++++++++++++++++++-- drivers/usbdev/cdcacm.c | 35 +++++++++++++++++++++++++++++++++-- include/nuttx/fs/ioctl.h | 5 ++++- 5 files changed, 118 insertions(+), 9 deletions(-) diff --git a/drivers/pipes/pipe_common.c b/drivers/pipes/pipe_common.c index 3bb5fc405e..2bc153efc7 100644 --- a/drivers/pipes/pipe_common.c +++ b/drivers/pipes/pipe_common.c @@ -785,11 +785,18 @@ int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; - case FIONREAD: + case FIONWRITE: /* Number of bytes waiting in send queue */ + case FIONREAD: /* Number of bytes available for reading */ { int count; - /* Determine the number of bytes available in the buffer */ + /* Determine the number of bytes written to the buffer. This is, + * of course, also the number of bytes that may be read from the + * buffer. + * + * d_rdndx - index to remove next byte from the buffer + * d_wrndx - Index to next location to add a byte to the buffer. + */ if (dev->d_wrndx < dev->d_rdndx) { @@ -805,11 +812,17 @@ int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; - case FIONWRITE: + /* Free space in buffer */ + + case FIONSPACE: { int count; - /* Determine the number of bytes free in the buffer */ + /* Determine the number of bytes free in the buffer. + * + * d_rdndx - index to remove next byte from the buffer + * d_wrndx - Index to next location to add a byte to the buffer. + */ if (dev->d_wrndx < dev->d_rdndx) { diff --git a/drivers/serial/pty.c b/drivers/serial/pty.c index 29b752fac9..ae5ac1619b 100644 --- a/drivers/serial/pty.c +++ b/drivers/serial/pty.c @@ -774,17 +774,48 @@ static int pty_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; #endif + + /* Get the number of bytes that are immediately available for reading + * from the source pipe. + */ + + case FIONREAD: + { + ret = file_ioctl(&dev->pd_src, cmd, arg); + } + break; + + /* Get the number of bytes waiting in the sink pipe (FIONWRITE) or the + * number of unused bytes in the sink pipe (FIONSPACE). + */ + + case FIONWRITE: + case FIONSPACE: + { + ret = file_ioctl(&dev->pd_sink, cmd, arg); + } + break; + /* Any unrecognized IOCTL commands will be passed to the contained * pipe driver. + * + * REVISIT: We know for a fact that the pipe driver only supports + * FIONREAD, FIONWRITE, FIONSPACE and PIPEIOC_POLICY. The first two + * are handled above and PIPEIOC_POLICY should not be managed by + * applications -- it can break the PTY! */ default: { +#if 0 ret = file_ioctl(&dev->pd_src, cmd, arg); if (ret >= 0 || ret == -ENOTTY) { ret = file_ioctl(&dev->pd_sink, cmd, arg); } +#else + ret = ENOTTY; +#endif } break; } diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 566cf834e6..49d6a970b7 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -910,12 +910,16 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { switch (cmd) { + /* Get the number of bytes that may be read from the RX buffer + * (without waiting) + */ + case FIONREAD: { int count; irqstate_t flags = enter_critical_section(); - /* Determine the number of bytes available in the buffer */ + /* Determine the number of bytes available in the RX buffer */ if (dev->recv.tail <= dev->recv.head) { @@ -933,12 +937,39 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + /* Get the number of bytes that have been written to the TX buffer. */ + case FIONWRITE: { int count; irqstate_t flags = enter_critical_section(); - /* Determine the number of bytes free in the buffer */ + /* Determine the number of bytes waiting in the TX buffer */ + + if (dev->xmit.head < dev->xmit.tail) + { + count = dev->xmit.head - dev->xmit.tail; + } + else + { + count = dev->xmit.size - (dev->xmit.tail - dev->xmit.head); + } + + leave_critical_section(flags); + + *(FAR int *)((uintptr_t)arg) = count; + ret = 0; + } + break; + + /* Get the number of free bytes in the TX buffer */ + + case FIONSPACE: + { + int count; + irqstate_t flags = enter_critical_section(); + + /* Determine the number of bytes free in the TX buffer */ if (dev->xmit.head < dev->xmit.tail) { diff --git a/drivers/usbdev/cdcacm.c b/drivers/usbdev/cdcacm.c index 28d498363b..64e2e68075 100644 --- a/drivers/usbdev/cdcacm.c +++ b/drivers/usbdev/cdcacm.c @@ -1982,12 +1982,16 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) break; #endif + /* Get the number of bytes that may be read from the RX buffer (without + * waiting) + */ + case FIONREAD: { int count; irqstate_t flags = enter_critical_section(); - /* Determine the number of bytes available in the buffer. */ + /* Determine the number of bytes available in the RX buffer. */ if (serdev->recv.tail <= serdev->recv.head) { @@ -2005,12 +2009,39 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + /* Get the number of bytes that have been written to the TX buffer. */ + case FIONWRITE: { int count; irqstate_t flags = enter_critical_section(); - /* Determine the number of bytes free in the buffer. */ + /* Determine the number of bytes waiting in the TX buffer. */ + + if (serdev->xmit.tail <= serdev->xmit.head) + { + count = serdev->xmit.head - serdev->xmit.tail; + } + else + { + count = serdev->xmit.size - (serdev->xmit.tail - serdev->xmit.head); + } + + leave_critical_section(flags); + + *(int *)arg = count; + ret = 0; + } + break; + + /* Get the number of free bytes in the TX buffer */ + + case FIONSPACE: + { + int count; + irqstate_t flags = enter_critical_section(); + + /* Determine the number of bytes free in the TX buffer */ if (serdev->xmit.head < serdev->xmit.tail) { diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index ba7586e3da..63074a3a9b 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -137,7 +137,10 @@ * OUT: Bytes readable from this fd */ #define FIONWRITE _FIOC(0x0006) /* IN: Location to return value (int *) - * OUT: Bytes writable to this fd + * OUT: Number bytes in send queue + */ +#define FIONSPACE _FIOC(0x0007) /* IN: Location to return value (int *) + * OUT: Free space in send queue. */ /* NuttX file system ioctl definitions **************************************/