Merge branch 'NuttX/master' from git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5027 7fd9a85b-ad96-42d3-883c-3090e2eb8679

This commit is contained in:
px4dev
2012-08-14 09:07:59 -07:00
45 changed files with 626 additions and 249 deletions
+195 -48
View File
@@ -113,16 +113,29 @@ static const struct file_operations g_serialops =
* Name: uart_takesem
************************************************************************************/
static void uart_takesem(FAR sem_t *sem)
static int uart_takesem(FAR sem_t *sem, bool errout)
{
while (sem_wait(sem) != 0)
/* Loop, ignoring interrupts, until we have successfully acquired the semaphore */
while (sem_wait(sem) != OK)
{
/* The only case that an error should occur here is if
* the wait was awakened by a signal.
/* The only case that an error should occur here is if the wait was awakened
* by a signal.
*/
ASSERT(get_errno() == EINTR);
/* When the signal is received, should we errout? Or should we just continue
* waiting until we have the semaphore?
*/
if (errout)
{
return -EINTR;
}
}
return OK;
}
/************************************************************************************
@@ -162,10 +175,11 @@ static void uart_pollnotify(FAR uart_dev_t *dev, pollevent_t eventset)
* Name: uart_putxmitchar
************************************************************************************/
static void uart_putxmitchar(FAR uart_dev_t *dev, int ch)
static int uart_putxmitchar(FAR uart_dev_t *dev, int ch)
{
irqstate_t flags;
int nexthead;
int ret;
/* Increment to see what the next head pointer will be. We need to use the "next"
* head pointer to determine when the circular buffer would overrun
@@ -185,36 +199,50 @@ static void uart_putxmitchar(FAR uart_dev_t *dev, int ch)
{
dev->xmit.buffer[dev->xmit.head] = ch;
dev->xmit.head = nexthead;
return;
return OK;
}
else
{
/* Inform the interrupt level logic that we are waiting.
* This and the following steps must be atomic.
/* Inform the interrupt level logic that we are waiting. This and
* the following steps must be atomic.
*/
flags = irqsave();
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.
/* 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.
*/
uart_enabletxint(dev);
uart_takesem(&dev->xmitsem);
ret = uart_takesem(&dev->xmitsem, true);
uart_disabletxint(dev);
irqrestore(flags);
/* Check if we were awakened by signal. */
if (ret < 0)
{
/* A signal received while waiting for the xmit buffer to become
* non-full will abort the transfer.
*/
return -EINTR;
}
}
}
/* We won't get here */
return OK;
}
/************************************************************************************
* Name: uart_irqwrite
************************************************************************************/
static ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer, size_t buflen)
static inline ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer, size_t buflen)
{
ssize_t ret = buflen;
@@ -223,14 +251,17 @@ static ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer, size_t
for (; buflen; buflen--)
{
int ch = *buffer++;
uart_putc(ch);
/* If this is the console, then we should replace LF with LF-CR */
/* If this is the console, then we should replace LF with CR-LF */
if (ch == '\n')
{
uart_putc('\r');
}
/* Output the character, using the low-level direct UART interfaces */
uart_putc(ch);
}
return ret;
@@ -242,18 +273,22 @@ static ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer, size_t
static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t buflen)
{
FAR struct inode *inode = filep->f_inode;
FAR uart_dev_t *dev = inode->i_private;
ssize_t ret = buflen;
FAR struct inode *inode = filep->f_inode;
FAR uart_dev_t *dev = inode->i_private;
ssize_t nread = buflen;
int ret;
/* We may receive console writes through this path from
* interrupt handlers and from debug output in the IDLE task!
* In these cases, we will need to do things a little
* differently.
/* We may receive console writes through this path from interrupt handlers and
* from debug output in the IDLE task! In these cases, we will need to do things
* a little differently.
*/
if (up_interrupt_context() || getpid() == 0)
{
/* up_putc() will be used to generate the output in a busy-wait loop.
* up_putc() is only available for the console device.
*/
if (dev->isconsole)
{
irqstate_t flags = irqsave();
@@ -263,13 +298,22 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
}
else
{
return ERROR;
return -EPERM;
}
}
/* Only one user can be accessing dev->xmit.head at once */
/* Only one user can access dev->xmit.head at a time */
uart_takesem(&dev->xmit.sem);
ret = (ssize_t)uart_takesem(&dev->xmit.sem, true);
if (ret < 0)
{
/* A signal received while waiting for access to the xmit.head will
* abort the transfer. After the transfer has started, we are committed
* and signals will be ignored.
*/
return ret;
}
/* Loop while we still have data to copy to the transmit buffer.
* we add data to the head of the buffer; uart_xmitchars takes the
@@ -281,15 +325,50 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
{
int ch = *buffer++;
/* If the ONLCR flag is set, we should translate \n to \r\n */
ret = OK;
if ((ch == '\n') && (dev->termios_s.c_oflag && ONLCR))
{
ret = uart_putxmitchar(dev, '\r');
}
/* Put the character into the transmit buffer */
uart_putxmitchar(dev, ch);
/* If this is the console, then we should replace LF with LF-CR */
if ((dev->termios_s.c_oflag && ONLCR) && ch == '\n')
if (ret == OK)
{
uart_putxmitchar(dev, '\r');
ret = uart_putxmitchar(dev, ch);
}
/* Were we awakened by a signal? That should be the only condition that
* uart_putxmitchar() should return an error.
*/
if (ret < 0)
{
/* POSIX requires that we return -1 and errno set if no data was
* transferred. Otherwise, we return the number of bytes in the
* interrupted transfer.
*/
if (buflen < nread)
{
/* Some data was transferred. Return the number of bytes that were
* successfully transferred.
*/
nread -= buflen;
}
else
{
/* No data was transferred. Return -EINTR. The VFS layer will
* set the errno value appropriately).
*/
nread = -EINTR;
}
break;
}
}
@@ -299,7 +378,7 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer, size_t
}
uart_givesem(&dev->xmit.sem);
return ret;
return nread;
}
/************************************************************************************
@@ -313,10 +392,20 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
irqstate_t flags;
ssize_t recvd = 0;
int16_t tail;
int ret;
/* Only one user can be accessing dev->recv.tail at once */
/* Only one user can access dev->recv.tail at a time */
uart_takesem(&dev->recv.sem);
ret = uart_takesem(&dev->recv.sem, true);
if (ret < 0)
{
/* A signal received while waiting for access to the recv.tail will avort
* the transfer. After the transfer has started, we are committed and
* signals will be ignored.
*/
return ret;
}
/* Loop while we still have data to copy to the receive buffer.
* we add data to the head of the buffer; uart_xmitchars takes the
@@ -353,6 +442,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
{
tail = 0;
}
dev->recv.tail = tail;
}
@@ -427,12 +517,34 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
uart_enablerxint(dev);
/* Now wait with the Rx interrupt re-enabled. NuttX will
* automatically re-enable global interrupts when this
* thread goes to sleep.
* automatically re-enable global interrupts when this thread
* goes to sleep.
*/
uart_takesem(&dev->recvsem);
ret = uart_takesem(&dev->recvsem, true);
irqrestore(flags);
/* Was a signal received while waiting for data to be received? */
if (ret < 0)
{
/* POSIX requires that we return after a signal is received.
* If some bytes were read, we need to return the number of bytes
* read; if no bytes were read, we need to return -1 with the
* errno set correctly.
*/
if (recvd == 0)
{
/* No bytes were read, return -EINTR (the VFS layer will
* set the errno value appropriately.
*/
recvd = -EINTR;
}
break;
}
}
else
{
@@ -513,7 +625,7 @@ int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
FAR uart_dev_t *dev = inode->i_private;
pollevent_t eventset;
int ndx;
int ret = OK;
int ret;
int i;
/* Some sanity checking */
@@ -527,7 +639,16 @@ int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
/* Are we setting up the poll? Or tearing it down? */
uart_takesem(&dev->pollsem);
ret = uart_takesem(&dev->pollsem, true);
if (ret < 0)
{
/* A signal received while waiting for access to the poll data
* will abort the operation.
*/
return ret;
}
if (setup)
{
/* This is a request to set up the poll. Find an available
@@ -555,31 +676,43 @@ int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
goto errout;
}
/* Should immediately notify on any of the requested events?
/* Should we immediately notify on any of the requested events?
* First, check if the xmit buffer is full.
*
* Get exclusive access to the xmit buffer indices. NOTE: that we do not
* let this wait be interrupted by a signal (we probably should, but that
* would be a little awkward).
*/
eventset = 0;
(void)uart_takesem(&dev->xmit.sem, false);
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 */
/* Check if the receive buffer is empty
*
* Get exclusive access to the recv buffer indices. NOTE: that we do not
* let this wait be interrupted by a signal (we probably should, but that
* would be a little awkward).
*/
uart_takesem(&dev->recv.sem);
(void)uart_takesem(&dev->recv.sem, false);
if (dev->recv.head != dev->recv.tail)
{
eventset |= POLLIN;
}
uart_givesem(&dev->recv.sem);
if (eventset)
@@ -629,7 +762,13 @@ static int uart_close(FAR struct file *filep)
FAR uart_dev_t *dev = inode->i_private;
irqstate_t flags;
uart_takesem(&dev->closesem);
/* Get exclusive access to the close semaphore (to synchronize open/close operations.
* NOTE: that we do not let this wait be interrupted by a signal. Technically, we
* should, but almost no one every checks the return value from close() so we avoid
* a potential memory leak by ignoring signals in this case.
*/
(void)uart_takesem(&dev->closesem, false);
if (dev->open_count > 1)
{
dev->open_count--;
@@ -694,11 +833,19 @@ static int uart_open(FAR struct file *filep)
struct inode *inode = filep->f_inode;
uart_dev_t *dev = inode->i_private;
uint8_t tmp;
int ret = OK;
int ret;
/* If the port is the middle of closing, wait until the close is finished */
/* If the port is the middle of closing, wait until the close is finished.
* If a signal is received while we are waiting, then return EINTR.
*/
uart_takesem(&dev->closesem);
ret = uart_takesem(&dev->closesem, true);
if (ret < 0)
{
/* A signal received while waiting for the last close operation. */
return ret;
}
/* Start up serial port */
/* Increment the count of references to the device. */