mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 01:21:26 +08:00
Add poll method to serial drivers
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1268 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
@@ -565,6 +565,6 @@
|
|||||||
|
|
||||||
0.3.19 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
0.3.19 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
* Add poll() and select() APIs (in the initial check-in, these work only with character devices)
|
* Add poll() and select() APIs (in the initial check-in, these work only with character devices)
|
||||||
* Add poll() methods to /dev/null, /dev/zero, pipes, and fifos.
|
* Add poll() methods to /dev/null, /dev/zero, pipes, fifos, and serial drivers.
|
||||||
* Add examples/poll for testing poll() and select()
|
* Add examples/poll for testing poll() and select()
|
||||||
|
|
||||||
|
|||||||
@@ -1201,7 +1201,7 @@ buildroot-0.1.2 2007-11-06 <spudmonkey@racsa.co.cr>
|
|||||||
<pre><ul>
|
<pre><ul>
|
||||||
nuttx-0.3.19 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
nuttx-0.3.19 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
* Add poll() and select() APIs (in the initial check-in, these work only with character devices)
|
* Add poll() and select() APIs (in the initial check-in, these work only with character devices)
|
||||||
* Add poll() methods to /dev/null, /dev/zero, pipes, and fifos.
|
* Add poll() methods to /dev/null, /dev/zero, pipes, fifos, and serial drivers.
|
||||||
* Add examples/poll for testing poll() and select()
|
* Add examples/poll for testing poll() and select()
|
||||||
|
|
||||||
pascal-0.1.3 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
pascal-0.1.3 2008-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
|||||||
@@ -53,6 +53,9 @@
|
|||||||
|
|
||||||
static ssize_t devconsole_read(struct file *, char *, size_t);
|
static ssize_t devconsole_read(struct file *, char *, size_t);
|
||||||
static ssize_t devconsole_write(struct file *, const char *, size_t);
|
static ssize_t devconsole_write(struct file *, const char *, size_t);
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
static int devconsole_poll(FAR struct file *filep, FAR struct pollfd *fds);
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
@@ -62,14 +65,16 @@ static struct file_operations devconsole_fops =
|
|||||||
{
|
{
|
||||||
.read = devconsole_read,
|
.read = devconsole_read,
|
||||||
.write = devconsole_write,
|
.write = devconsole_write,
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
.poll = devconsole_poll,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
static ssize_t devconsole_read(struct file *filp, char *buffer, size_t len)
|
||||||
static ssize_t devconsole_read(struct file *filp, char *buffer, size_t len)
|
|
||||||
{
|
{
|
||||||
return up_hostread(buffer, len);
|
return up_hostread(buffer, len);
|
||||||
}
|
}
|
||||||
@@ -79,6 +84,11 @@ static ssize_t devconsole_write(struct file *filp, const char *buffer, size_t le
|
|||||||
return up_hostwrite(buffer, len);
|
return up_hostwrite(buffer, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int devconsole_poll(FAR struct file *filep, FAR struct pollfd *fds)
|
||||||
|
{
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
+182
-2
@@ -44,6 +44,7 @@
|
|||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
@@ -77,6 +78,9 @@ static int uart_close(FAR struct file *filep);
|
|||||||
static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen);
|
static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen);
|
||||||
static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t buflen);
|
static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t buflen);
|
||||||
static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
static int uart_poll(FAR struct file *filep, FAR struct pollfd *fds);
|
||||||
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Private Variables
|
* Private Variables
|
||||||
@@ -89,8 +93,10 @@ struct file_operations g_serialops =
|
|||||||
uart_read, /* read */
|
uart_read, /* read */
|
||||||
uart_write, /* write */
|
uart_write, /* write */
|
||||||
0, /* seek */
|
0, /* seek */
|
||||||
uart_ioctl, /* ioctl */
|
uart_ioctl /* ioctl */
|
||||||
0 /* poll */
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
, uart_poll /* poll */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@@ -119,6 +125,33 @@ static void uart_takesem(FAR sem_t *sem)
|
|||||||
|
|
||||||
#define uart_givesem(sem) (void)sem_post(sem)
|
#define uart_givesem(sem) (void)sem_post(sem)
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: uart_pollnotify
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
static void uart_pollnotify(FAR uart_dev_t *dev, pollevent_t eventset)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < CONFIG_DEV_CONSOLE_NPOLLWAITERS; i++)
|
||||||
|
{
|
||||||
|
struct pollfd *fds = dev->fds[i];
|
||||||
|
if (fds)
|
||||||
|
{
|
||||||
|
fds->revents |= (fds->events & eventset);
|
||||||
|
if (fds->revents != 0)
|
||||||
|
{
|
||||||
|
fvdbg("Report events: %02x\n", fds->revents);
|
||||||
|
sem_post(fds->sem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define uart_pollnotify(dev,event)
|
||||||
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Name: uart_putxmitchar
|
* Name: uart_putxmitchar
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
@@ -340,6 +373,98 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
return dev->ops->ioctl(filep, cmd, arg);
|
return dev->ops->ioctl(filep, cmd, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: uart_poll
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
int uart_poll(FAR struct file *filep, FAR struct pollfd *fds)
|
||||||
|
{
|
||||||
|
FAR struct inode *inode = filep->f_inode;
|
||||||
|
FAR uart_dev_t *dev = inode->i_private;
|
||||||
|
pollevent_t eventset;
|
||||||
|
int ndx;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Some sanity checking */
|
||||||
|
#if CONFIG_DEBUG
|
||||||
|
if (!dev)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Find an available slot for the poll structure reference */
|
||||||
|
|
||||||
|
uart_takesem(&dev->pollsem);
|
||||||
|
for (i = 0; i < CONFIG_DEV_CONSOLE_NPOLLWAITERS; i++)
|
||||||
|
{
|
||||||
|
/* Find the slot with the value equal to filep->f_priv. If there
|
||||||
|
* is not previously installed poll structure, then f_priv will
|
||||||
|
* be NULL and we will find the first unused slot. If f_priv is
|
||||||
|
* is non-NULL, then we will find the slot that was used for the
|
||||||
|
* previous setup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (dev->fds[i] == filep->f_priv)
|
||||||
|
{
|
||||||
|
dev->fds[i] = fds;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= CONFIG_DEV_CONSOLE_NPOLLWAITERS)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(fds == NULL);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set or clear the poll event structure reference in the 'struct file'
|
||||||
|
* private data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
filep->f_priv = fds;
|
||||||
|
|
||||||
|
/* Check if we should immediately notify on any of the requested events */
|
||||||
|
|
||||||
|
if (fds)
|
||||||
|
{
|
||||||
|
/* Check if the xmit buffer is full. */
|
||||||
|
|
||||||
|
eventset = 0;
|
||||||
|
|
||||||
|
uart_takesem(&dev->xmit.sem);
|
||||||
|
ndx = dev->xmit.head + 1;
|
||||||
|
if (ndx >= dev->xmit.size)
|
||||||
|
{
|
||||||
|
ndx = 0;
|
||||||
|
}
|
||||||
|
if (ndx != dev->xmit.tail)
|
||||||
|
{
|
||||||
|
eventset |= POLLOUT;
|
||||||
|
}
|
||||||
|
uart_givesem(&dev->xmit.sem);
|
||||||
|
|
||||||
|
/* Check if the receive buffer is empty */
|
||||||
|
|
||||||
|
uart_takesem(&dev->recv.sem);
|
||||||
|
if (dev->recv.head != dev->recv.tail)
|
||||||
|
{
|
||||||
|
eventset |= POLLIN;
|
||||||
|
}
|
||||||
|
uart_givesem(&dev->recv.sem);
|
||||||
|
|
||||||
|
if (eventset)
|
||||||
|
{
|
||||||
|
uart_pollnotify(dev, eventset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_givesem(&dev->pollsem);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Name: uart_close
|
* Name: uart_close
|
||||||
*
|
*
|
||||||
@@ -513,7 +638,62 @@ int uart_register(FAR const char *path, FAR uart_dev_t *dev)
|
|||||||
sem_init(&dev->closesem, 0, 1);
|
sem_init(&dev->closesem, 0, 1);
|
||||||
sem_init(&dev->xmitsem, 0, 0);
|
sem_init(&dev->xmitsem, 0, 0);
|
||||||
sem_init(&dev->recvsem, 0, 0);
|
sem_init(&dev->recvsem, 0, 0);
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
sem_init(&dev->pollsem, 0, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
dbg("Registering %s\n", path);
|
dbg("Registering %s\n", path);
|
||||||
return register_driver(path, &g_serialops, 0666, dev);
|
return register_driver(path, &g_serialops, 0666, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_datareceived
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is called from uart_recvchars when new serial data is place in
|
||||||
|
* the driver's circular buffer. This function will wake-up any stalled read()
|
||||||
|
* operations that are waiting for incoming data.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
void uart_datareceived(FAR uart_dev_t *dev)
|
||||||
|
{
|
||||||
|
/* Awaken any awaiting read() operations */
|
||||||
|
|
||||||
|
if (dev->recvwaiting)
|
||||||
|
{
|
||||||
|
dev->recvwaiting = FALSE;
|
||||||
|
(void)sem_post(&dev->recvsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify all poll/select waiters that they can read from the recv buffer */
|
||||||
|
|
||||||
|
uart_pollnotify(dev, POLLIN);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_datasent
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is called from uart_xmitchars after serial data has been sent,
|
||||||
|
* freeing up some space in the driver's circular buffer. This function will
|
||||||
|
* wake-up any stalled write() operations that was waiting for space to buffer
|
||||||
|
* outgoing data.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
void uart_datasent(FAR uart_dev_t *dev)
|
||||||
|
{
|
||||||
|
if (dev->xmitwaiting)
|
||||||
|
{
|
||||||
|
dev->xmitwaiting = FALSE;
|
||||||
|
(void)sem_post(&dev->xmitsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify all poll/select waiters that they can write to xmit buffer */
|
||||||
|
|
||||||
|
uart_pollnotify(dev, POLLOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+21
-20
@@ -80,6 +80,8 @@
|
|||||||
|
|
||||||
void uart_xmitchars(FAR uart_dev_t *dev)
|
void uart_xmitchars(FAR uart_dev_t *dev)
|
||||||
{
|
{
|
||||||
|
uint16 nbytes = 0;
|
||||||
|
|
||||||
/* Send while we still have data & room in the fifo */
|
/* Send while we still have data & room in the fifo */
|
||||||
|
|
||||||
while (dev->xmit.head != dev->xmit.tail && uart_txready(dev))
|
while (dev->xmit.head != dev->xmit.tail && uart_txready(dev))
|
||||||
@@ -87,6 +89,7 @@ void uart_xmitchars(FAR uart_dev_t *dev)
|
|||||||
/* Send the next byte */
|
/* Send the next byte */
|
||||||
|
|
||||||
uart_send(dev, dev->xmit.buffer[dev->xmit.tail]);
|
uart_send(dev, dev->xmit.buffer[dev->xmit.tail]);
|
||||||
|
nbytes++;
|
||||||
|
|
||||||
/* Increment the tail index */
|
/* Increment the tail index */
|
||||||
|
|
||||||
@@ -94,16 +97,6 @@ void uart_xmitchars(FAR uart_dev_t *dev)
|
|||||||
{
|
{
|
||||||
dev->xmit.tail = 0;
|
dev->xmit.tail = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A byte was removed from the buffer. Inform any waiters
|
|
||||||
* there there is space available.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (dev->xmitwaiting)
|
|
||||||
{
|
|
||||||
dev->xmitwaiting = FALSE;
|
|
||||||
(void)sem_post(&dev->xmitsem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When all of the characters have been sent from the buffer
|
/* When all of the characters have been sent from the buffer
|
||||||
@@ -114,6 +107,15 @@ void uart_xmitchars(FAR uart_dev_t *dev)
|
|||||||
{
|
{
|
||||||
uart_disabletxint(dev);
|
uart_disabletxint(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If any bytes were removed from the buffer, inform any waiters
|
||||||
|
* there there is space available.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (nbytes)
|
||||||
|
{
|
||||||
|
uart_datasent(dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@@ -131,6 +133,7 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
{
|
{
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
int nexthead = dev->recv.head + 1;
|
int nexthead = dev->recv.head + 1;
|
||||||
|
uint16 nbytes = 0;
|
||||||
|
|
||||||
if (nexthead >= dev->recv.size)
|
if (nexthead >= dev->recv.size)
|
||||||
{
|
{
|
||||||
@@ -146,6 +149,7 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
/* Add the character to the buffer */
|
/* Add the character to the buffer */
|
||||||
|
|
||||||
dev->recv.buffer[dev->recv.head] = uart_receive(dev, &status);
|
dev->recv.buffer[dev->recv.head] = uart_receive(dev, &status);
|
||||||
|
nbytes++;
|
||||||
|
|
||||||
/* Increment the head index */
|
/* Increment the head index */
|
||||||
|
|
||||||
@@ -154,18 +158,15 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
{
|
{
|
||||||
nexthead = 0;
|
nexthead = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* A character was added... if there is a thread waiting for more data, then
|
/* If any bytes were added to the buffer, inform any waiters
|
||||||
* post the recvsem semaphore to wake it up. NOTE: There is a logic error in
|
* there there is new incoming data available.
|
||||||
* the above looping logic: If nexthead == dev->recv.tail on entry and
|
*/
|
||||||
* recvwaiting is true, the recvsem will never get posted!
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (dev->recvwaiting)
|
if (nbytes)
|
||||||
{
|
{
|
||||||
dev->recvwaiting = FALSE;
|
uart_datareceived(dev);
|
||||||
(void)sem_post(&dev->recvsem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -526,14 +526,6 @@ static uint16 usbclass_fillrequest(FAR struct usbser_dev_s *priv, char *reqbuf,
|
|||||||
{
|
{
|
||||||
xmit->tail = 0;
|
xmit->tail = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we have to wake up the serial driver */
|
|
||||||
|
|
||||||
if (serdev->xmitwaiting)
|
|
||||||
{
|
|
||||||
serdev->xmitwaiting = FALSE;
|
|
||||||
sem_post(&serdev->xmitsem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When all of the characters have been sent from the buffer
|
/* When all of the characters have been sent from the buffer
|
||||||
@@ -545,6 +537,15 @@ static uint16 usbclass_fillrequest(FAR struct usbser_dev_s *priv, char *reqbuf,
|
|||||||
uart_disabletxint(serdev);
|
uart_disabletxint(serdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If any bytes were removed from the buffer, inform any waiters
|
||||||
|
* there there is space available.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (nbytes)
|
||||||
|
{
|
||||||
|
uart_datasent(serdev);
|
||||||
|
}
|
||||||
|
|
||||||
irqrestore(flags);
|
irqrestore(flags);
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
@@ -651,6 +652,7 @@ static inline int usbclass_recvpacket(FAR struct usbser_dev_s *priv,
|
|||||||
FAR struct uart_buffer_s *recv = &serdev->recv;
|
FAR struct uart_buffer_s *recv = &serdev->recv;
|
||||||
uint16 currhead;
|
uint16 currhead;
|
||||||
uint16 nexthead;
|
uint16 nexthead;
|
||||||
|
uint16 nbytes = 0;
|
||||||
|
|
||||||
/* Get the next head index. During the time that RX interrupts are disabled, the
|
/* Get the next head index. During the time that RX interrupts are disabled, the
|
||||||
* the serial driver will be extracting data from the circular buffer and modifying
|
* the serial driver will be extracting data from the circular buffer and modifying
|
||||||
@@ -684,7 +686,7 @@ static inline int usbclass_recvpacket(FAR struct usbser_dev_s *priv,
|
|||||||
* then we have overrun the serial driver and data will be lost.
|
* then we have overrun the serial driver and data will be lost.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while (nexthead != recv->tail && reqlen > 0)
|
while (nexthead != recv->tail && nbytes < reqlen)
|
||||||
{
|
{
|
||||||
/* Copy one byte to the head of the circular RX buffer */
|
/* Copy one byte to the head of the circular RX buffer */
|
||||||
|
|
||||||
@@ -693,21 +695,7 @@ static inline int usbclass_recvpacket(FAR struct usbser_dev_s *priv,
|
|||||||
/* Update counts and indices */
|
/* Update counts and indices */
|
||||||
|
|
||||||
currhead = nexthead;
|
currhead = nexthead;
|
||||||
reqlen--;
|
nbytes++;
|
||||||
|
|
||||||
/* Wake up the serial driver if it is waiting for incoming data. If we
|
|
||||||
* are running in an interrupt handler, then the serial driver will
|
|
||||||
* not run until the interrupt handler returns. But we will exercise
|
|
||||||
* care in the following just in case the serial driver does run.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (priv->rxenabled && serdev->recvwaiting)
|
|
||||||
{
|
|
||||||
recv->head = currhead;
|
|
||||||
serdev->recvwaiting = FALSE;
|
|
||||||
sem_post(&serdev->recvsem);
|
|
||||||
currhead = recv->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment the head index and check for wrap around */
|
/* Increment the head index and check for wrap around */
|
||||||
|
|
||||||
@@ -731,9 +719,20 @@ static inline int usbclass_recvpacket(FAR struct usbser_dev_s *priv,
|
|||||||
priv->rxhead = currhead;
|
priv->rxhead = currhead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If data was added to the incoming serial buffer, then wake up any
|
||||||
|
* threads is waiting for incoming data. If we are running in an interrupt
|
||||||
|
* handler, then the serial driver will not run until the interrupt handler
|
||||||
|
* returns.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (priv->rxenabled && nbytes > 0)
|
||||||
|
{
|
||||||
|
uart_datareceived(serdev);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return an error if the entire packet could not be transferred */
|
/* Return an error if the entire packet could not be transferred */
|
||||||
|
|
||||||
if (reqlen > 0)
|
if (nbytes < reqlen)
|
||||||
{
|
{
|
||||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RXOVERRUN), 0);
|
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RXOVERRUN), 0);
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
@@ -2017,15 +2016,9 @@ static void usbser_rxint(FAR struct uart_dev_s *dev, boolean enable)
|
|||||||
{
|
{
|
||||||
serdev->recv.head = priv->rxhead;
|
serdev->recv.head = priv->rxhead;
|
||||||
|
|
||||||
/* Is the serial driver waiting for more data? */
|
/* Yes... signal the availability of new data */
|
||||||
|
|
||||||
if (serdev->recvwaiting)
|
uart_datareceived(serdev);
|
||||||
{
|
|
||||||
/* Yes... signal the availability of new data */
|
|
||||||
|
|
||||||
sem_post(&serdev->recvsem);
|
|
||||||
serdev->recvwaiting = FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX "interrupts are no longer disabled */
|
/* RX "interrupts are no longer disabled */
|
||||||
|
|||||||
+115
-52
@@ -57,6 +57,17 @@
|
|||||||
* Definitions
|
* Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEV_CONSOLE) && !defined(CONFIG_DEV_LOWCONSOLE)
|
||||||
|
# define HAVE_CONSOLE
|
||||||
|
# define NPOLLFDS 2
|
||||||
|
# define CONSNDX 0
|
||||||
|
# define FIFONDX 1
|
||||||
|
#else
|
||||||
|
# undef HAVE_CONSOLE
|
||||||
|
# define NPOLLFDS 1
|
||||||
|
# define FIFONDX 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -79,13 +90,15 @@
|
|||||||
|
|
||||||
void *poll_listener(pthread_addr_t pvarg)
|
void *poll_listener(pthread_addr_t pvarg)
|
||||||
{
|
{
|
||||||
struct pollfd fds;
|
struct pollfd fds[NPOLLFDS];
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
ssize_t nbytes;
|
ssize_t nbytes;
|
||||||
boolean timeout;
|
boolean timeout;
|
||||||
boolean pollin;
|
boolean pollin;
|
||||||
|
int nevents;
|
||||||
int fd;
|
int fd;
|
||||||
int ret;
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Open the FIFO for non-blocking read */
|
/* Open the FIFO for non-blocking read */
|
||||||
|
|
||||||
@@ -105,15 +118,20 @@ void *poll_listener(pthread_addr_t pvarg)
|
|||||||
{
|
{
|
||||||
message("poll_listener: Calling poll()\n");
|
message("poll_listener: Calling poll()\n");
|
||||||
|
|
||||||
memset(&fds, 0, sizeof(struct pollfd));
|
memset(fds, 0, sizeof(struct pollfd)*NPOLLFDS);
|
||||||
fds.fd = fd;
|
#ifdef HAVE_CONSOLE
|
||||||
fds.events = POLLIN;
|
fds[CONSNDX].fd = 0;
|
||||||
fds.revents = 0;
|
fds[CONSNDX].events = POLLIN;
|
||||||
|
fds[CONSNDX].revents = 0;
|
||||||
|
#endif
|
||||||
|
fds[FIFONDX].fd = fd;
|
||||||
|
fds[FIFONDX].events = POLLIN;
|
||||||
|
fds[FIFONDX].revents = 0;
|
||||||
|
|
||||||
timeout = FALSE;
|
timeout = FALSE;
|
||||||
pollin = FALSE;
|
pollin = FALSE;
|
||||||
|
|
||||||
ret = poll(&fds, 1, POLL_LISTENER_DELAY);
|
ret = poll(fds, NPOLLFDS, POLL_LISTENER_DELAY);
|
||||||
|
|
||||||
message("\npoll_listener: poll returned: %d\n", ret);
|
message("\npoll_listener: poll returned: %d\n", ret);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@@ -122,70 +140,115 @@ void *poll_listener(pthread_addr_t pvarg)
|
|||||||
}
|
}
|
||||||
else if (ret == 0)
|
else if (ret == 0)
|
||||||
{
|
{
|
||||||
message("poll_listener: Timeout, revents=%02x\n", fds.revents);
|
message("poll_listener: Timeout\n");
|
||||||
timeout = TRUE;
|
timeout = TRUE;
|
||||||
if (fds.revents != 0)
|
}
|
||||||
{
|
else if (ret > NPOLLFDS)
|
||||||
message("poll_listener: ERROR? expected revents=00, received revents=%02x\n",
|
{
|
||||||
fds.revents);
|
message("poll_listener: ERROR poll reported: %d\n");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ret != 1)
|
pollin = TRUE;
|
||||||
{
|
}
|
||||||
message("poll_listener: ERROR poll reported: %d\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pollin = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
message("poll_listener: revents=%02x\n", fds.revents);
|
nevents = 0;
|
||||||
if (fds.revents != POLLIN)
|
for (i = 0; i < NPOLLFDS; i++)
|
||||||
|
{
|
||||||
|
message("poll_listener: FIFO revents[%d]=%02x\n", i, fds[i].revents);
|
||||||
|
if (timeout)
|
||||||
{
|
{
|
||||||
message("poll_listener: ERROR expected revents=%02x, received revents=%02x\n",
|
if (fds[i].revents != 0)
|
||||||
fds.revents);
|
{
|
||||||
message(" (might just be a race condition)\n");
|
message("poll_listener: ERROR? expected revents=00, received revents[%d]=%02x\n",
|
||||||
|
fds[i].revents, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pollin)
|
||||||
|
{
|
||||||
|
if (fds[i].revents == POLLIN)
|
||||||
|
{
|
||||||
|
nevents++;
|
||||||
|
}
|
||||||
|
else if (fds[i].revents != 0)
|
||||||
|
{
|
||||||
|
message("poll_listener: ERROR unexpected revents[i]=%02x\n",
|
||||||
|
i, fds[i].revents);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In any event, read until the pipe is empty */
|
if (pollin && nevents != ret)
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
nbytes = read(fd, buffer, 63);
|
message("poll_listener: ERROR found %d events, poll reported %d\n", nevents, ret);
|
||||||
if (nbytes <= 0)
|
}
|
||||||
|
|
||||||
|
/* In any event, read until the pipe/serial is empty */
|
||||||
|
|
||||||
|
for (i = 0; i < NPOLLFDS; i++)
|
||||||
|
{
|
||||||
|
do
|
||||||
{
|
{
|
||||||
if (nbytes == 0 || errno == EAGAIN)
|
#ifdef HAVE_CONSOLE
|
||||||
|
/* Hack to work around the fact that the console driver on the
|
||||||
|
* simulator is always non-blocking.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (i == CONSNDX)
|
||||||
{
|
{
|
||||||
if (pollin)
|
if ((fds[CONSNDX].revents & POLLIN) != 0)
|
||||||
{
|
{
|
||||||
message("poll_listener: ERROR no read data\n");
|
buffer[0] = getchar();
|
||||||
|
nbytes = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nbytes = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (errno != EINTR)
|
else
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
message("poll_listener: read failed: %d\n", errno);
|
/* The pipe works differently, it returns whatever data
|
||||||
}
|
* it has available without blocking.
|
||||||
nbytes = 0;
|
*/
|
||||||
}
|
|
||||||
else
|
nbytes = read(fds[i].fd, buffer, 63);
|
||||||
{
|
|
||||||
if (timeout)
|
|
||||||
{
|
|
||||||
message("poll_listener: ERROR? Poll timeout, but data read\n");
|
|
||||||
message(" (might just be a race condition)\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[nbytes] = '\0';
|
if (nbytes <= 0)
|
||||||
message("poll_listener: Read '%s' (%d bytes)\n", buffer, nbytes);
|
{
|
||||||
}
|
if (nbytes == 0 || errno == EAGAIN)
|
||||||
|
{
|
||||||
|
if ((fds[i].revents & POLLIN) != 0)
|
||||||
|
{
|
||||||
|
message("poll_listener: ERROR no read data[%d]\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (errno != EINTR)
|
||||||
|
{
|
||||||
|
message("poll_listener: read[%d] failed: %d\n", i, errno);
|
||||||
|
}
|
||||||
|
nbytes = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (timeout)
|
||||||
|
{
|
||||||
|
message("poll_listener: ERROR? Poll timeout, but data read[%d]\n", i);
|
||||||
|
message(" (might just be a race condition)\n");
|
||||||
|
}
|
||||||
|
|
||||||
timeout = FALSE;
|
buffer[nbytes] = '\0';
|
||||||
pollin = FALSE;
|
message("poll_listener: Read[%d] '%s' (%d bytes)\n", i, buffer, nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Suppress error report if no read data on the next time through */
|
||||||
|
|
||||||
|
fds[i].revents = 0;
|
||||||
|
}
|
||||||
|
while (nbytes > 0);
|
||||||
}
|
}
|
||||||
while (nbytes > 0);
|
|
||||||
|
|
||||||
/* Make sure that everything is displayed */
|
/* Make sure that everything is displayed */
|
||||||
|
|
||||||
|
|||||||
+47
-1
@@ -49,6 +49,14 @@
|
|||||||
* Definitions
|
* Definitions
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
|
/* Maximum number of threads than can be waiting for POLL events */
|
||||||
|
|
||||||
|
#ifndef CONFIG_DEV_CONSOLE_NPOLLWAITERS
|
||||||
|
# define CONFIG_DEV_CONSOLE_NPOLLWAITERS 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* vtable access helpers */
|
||||||
|
|
||||||
#define uart_setup(dev) dev->ops->setup(dev)
|
#define uart_setup(dev) dev->ops->setup(dev)
|
||||||
#define uart_shutdown(dev) dev->ops->shutdown(dev)
|
#define uart_shutdown(dev) dev->ops->shutdown(dev)
|
||||||
#define uart_attach(dev) dev->ops->attach(dev)
|
#define uart_attach(dev) dev->ops->attach(dev)
|
||||||
@@ -186,10 +194,23 @@ struct uart_dev_s
|
|||||||
sem_t closesem; /* Locks out new open while close is in progress */
|
sem_t closesem; /* Locks out new open while close is in progress */
|
||||||
sem_t xmitsem; /* Wakeup user waiting for space in xmit.buffer */
|
sem_t xmitsem; /* Wakeup user waiting for space in xmit.buffer */
|
||||||
sem_t recvsem; /* Wakeup user waiting for data in recv.buffer */
|
sem_t recvsem; /* Wakeup user waiting for data in recv.buffer */
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
sem_t pollsem; /* Manages exclusive access to fds[] */
|
||||||
|
#endif
|
||||||
struct uart_buffer_s xmit; /* Describes transmit buffer */
|
struct uart_buffer_s xmit; /* Describes transmit buffer */
|
||||||
struct uart_buffer_s recv; /* Describes receive buffer */
|
struct uart_buffer_s recv; /* Describes receive buffer */
|
||||||
FAR const struct uart_ops_s *ops; /* Arch-specific operations */
|
FAR const struct uart_ops_s *ops; /* Arch-specific operations */
|
||||||
FAR void *priv; /* Used by the arch-specific logic */
|
FAR void *priv; /* Used by the arch-specific logic */
|
||||||
|
|
||||||
|
/* The following is a list if poll structures of threads waiting for
|
||||||
|
* driver events. The 'struct pollfd' reference for each open is also
|
||||||
|
* retained in the f_priv field of the 'struct file'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
|
struct pollfd *fds[CONFIG_DEV_CONSOLE_NPOLLWAITERS];
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
typedef struct uart_dev_s uart_dev_t;
|
typedef struct uart_dev_s uart_dev_t;
|
||||||
|
|
||||||
@@ -245,6 +266,31 @@ EXTERN void uart_xmitchars(FAR uart_dev_t *dev);
|
|||||||
|
|
||||||
EXTERN void uart_recvchars(FAR uart_dev_t *dev);
|
EXTERN void uart_recvchars(FAR uart_dev_t *dev);
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_datareceived
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is called from uart_recvchars when new serial data is place in
|
||||||
|
* the driver's circular buffer. This function will wake-up any stalled read()
|
||||||
|
* operations that are waiting for incoming data.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
EXTERN void uart_datareceived(FAR uart_dev_t *dev);
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_datasent
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is called from uart_xmitchars after serial data has been sent,
|
||||||
|
* freeing up some space in the driver's circular buffer. This function will
|
||||||
|
* wake-up any stalled write() operations that was waiting for space to buffer
|
||||||
|
* outgoing data.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
EXTERN void uart_datasent(FAR uart_dev_t *dev);
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user