mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-25 03:13:34 +08:00
Resync new repository with old repo r5166
git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
############################################################################
|
||||
# drivers/serial/Make.defs
|
||||
#
|
||||
# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
|
||||
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# 3. Neither the name NuttX nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_NFILE_DESCRIPTORS),0)
|
||||
|
||||
# Include serial drivers
|
||||
|
||||
CSRCS += serial.c serialirq.c lowconsole.c
|
||||
|
||||
ifeq ($(CONFIG_16550_UART),y)
|
||||
CSRCS += uart_16550.c
|
||||
endif
|
||||
|
||||
# Include serial build support
|
||||
|
||||
DEPPATH += --dep-path serial
|
||||
VPATH += :serial
|
||||
endif
|
||||
@@ -0,0 +1,132 @@
|
||||
/****************************************************************************
|
||||
* drivers/serial/lowconsole.c
|
||||
*
|
||||
* Copyright (C) 2008-2009, 2012 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The architecture must provide up_putc for this driver */
|
||||
|
||||
#ifndef CONFIG_ARCH_LOWPUTC
|
||||
# error "Architecture must provide up_putc() for this driver"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t lowconsole_read(struct file *filep, char *buffer, size_t buflen);
|
||||
static ssize_t lowconsole_write(struct file *filep, const char *buffer, size_t buflen);
|
||||
static int lowconsole_ioctl(struct file *filep, int cmd, unsigned long arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Variables
|
||||
****************************************************************************/
|
||||
|
||||
static const struct file_operations g_consoleops =
|
||||
{
|
||||
0, /* open */
|
||||
0, /* close */
|
||||
lowconsole_read, /* read */
|
||||
lowconsole_write, /* write */
|
||||
0, /* seek */
|
||||
lowconsole_ioctl /* ioctl */
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
, 0 /* poll */
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lowconsole_ioctl
|
||||
****************************************************************************/
|
||||
|
||||
static int lowconsole_ioctl(struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lowconsole_read
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t lowconsole_read(struct file *filep, char *buffer, size_t buflen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lowconsole_write
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t lowconsole_write(struct file *filep, const char *buffer, size_t buflen)
|
||||
{
|
||||
ssize_t ret = buflen;
|
||||
|
||||
for (; buflen; buflen--)
|
||||
{
|
||||
up_putc(*buffer++);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lowconsole_init
|
||||
****************************************************************************/
|
||||
|
||||
void lowconsole_init(void)
|
||||
{
|
||||
(void)register_driver("/dev/console", &g_consoleops, 0666, NULL);
|
||||
}
|
||||
@@ -0,0 +1,954 @@
|
||||
/************************************************************************************
|
||||
* drivers/serial/serial.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Included Files
|
||||
************************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <semaphore.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/serial/serial.h>
|
||||
|
||||
/************************************************************************************
|
||||
* Definitions
|
||||
************************************************************************************/
|
||||
|
||||
/* The architecture must provide up_putc for this driver */
|
||||
|
||||
#ifndef CONFIG_ARCH_LOWPUTC
|
||||
# error "Architecture must provide up_putc() for this driver"
|
||||
#endif
|
||||
|
||||
#define uart_putc(ch) up_putc(ch)
|
||||
|
||||
#define HALF_SECOND_MSEC 500
|
||||
#define HALF_SECOND_USEC 500000L
|
||||
|
||||
/************************************************************************************
|
||||
* Private Types
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Private Function Prototypes
|
||||
************************************************************************************/
|
||||
|
||||
static int uart_open(FAR struct file *filep);
|
||||
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_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);
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
static int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup);
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Private Variables
|
||||
************************************************************************************/
|
||||
|
||||
static const struct file_operations g_serialops =
|
||||
{
|
||||
uart_open, /* open */
|
||||
uart_close, /* close */
|
||||
uart_read, /* read */
|
||||
uart_write, /* write */
|
||||
0, /* seek */
|
||||
uart_ioctl /* ioctl */
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
, uart_poll /* poll */
|
||||
#endif
|
||||
};
|
||||
|
||||
/************************************************************************************
|
||||
* Private Functions
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_takesem
|
||||
************************************************************************************/
|
||||
|
||||
static int uart_takesem(FAR sem_t *sem, bool errout)
|
||||
{
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_givesem
|
||||
************************************************************************************/
|
||||
|
||||
#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_SERIAL_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
|
||||
************************************************************************************/
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
nexthead = dev->xmit.head + 1;
|
||||
if (nexthead >= dev->xmit.size)
|
||||
{
|
||||
nexthead = 0;
|
||||
}
|
||||
|
||||
/* Loop until we are able to add the character to the TX buffer */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (nexthead != dev->xmit.tail)
|
||||
{
|
||||
dev->xmit.buffer[dev->xmit.head] = ch;
|
||||
dev->xmit.head = nexthead;
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
uart_enabletxint(dev);
|
||||
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 inline ssize_t uart_irqwrite(FAR uart_dev_t *dev, FAR const char *buffer, size_t buflen)
|
||||
{
|
||||
ssize_t ret = buflen;
|
||||
|
||||
/* Force each character through the low level interface */
|
||||
|
||||
for (; buflen; buflen--)
|
||||
{
|
||||
int ch = *buffer++;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_write
|
||||
************************************************************************************/
|
||||
|
||||
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 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.
|
||||
*/
|
||||
|
||||
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();
|
||||
ret = uart_irqwrite(dev, buffer, buflen);
|
||||
irqrestore(flags);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only one user can access dev->xmit.head at a time */
|
||||
|
||||
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
|
||||
* data from the end of the buffer.
|
||||
*/
|
||||
|
||||
uart_disabletxint(dev);
|
||||
for (; buflen; buflen--)
|
||||
{
|
||||
int ch = *buffer++;
|
||||
|
||||
/* If this is the console, then we should replace LF with CR-LF */
|
||||
|
||||
ret = OK;
|
||||
if (dev->isconsole && ch == '\n')
|
||||
{
|
||||
ret = uart_putxmitchar(dev, '\r');
|
||||
}
|
||||
|
||||
/* Put the character into the transmit buffer */
|
||||
|
||||
if (ret == OK)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->xmit.head != dev->xmit.tail)
|
||||
{
|
||||
uart_enabletxint(dev);
|
||||
}
|
||||
|
||||
uart_givesem(&dev->xmit.sem);
|
||||
return nread;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_read
|
||||
************************************************************************************/
|
||||
|
||||
static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR uart_dev_t *dev = inode->i_private;
|
||||
irqstate_t flags;
|
||||
ssize_t recvd = 0;
|
||||
int16_t tail;
|
||||
int ret;
|
||||
|
||||
/* Only one user can access dev->recv.tail at a time */
|
||||
|
||||
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
|
||||
* data from the end of the buffer.
|
||||
*/
|
||||
|
||||
while (recvd < buflen)
|
||||
{
|
||||
/* Check if there is more data to return in the circular buffer.
|
||||
* NOTE: Rx interrupt handling logic may aynchronously increment
|
||||
* the head index but must not modify the tail index. The tail
|
||||
* index is only modified in this function. Therefore, no
|
||||
* special handshaking is required here.
|
||||
*
|
||||
* The head and tail pointers are 16-bit values. The only time that
|
||||
* the following could be unsafe is if the CPU made two non-atomic
|
||||
* 8-bit accesses to obtain the 16-bit head index.
|
||||
*/
|
||||
|
||||
tail = dev->recv.tail;
|
||||
if (dev->recv.head != tail)
|
||||
{
|
||||
/* Take the next character from the tail of the buffer */
|
||||
|
||||
*buffer++ = dev->recv.buffer[tail];
|
||||
recvd++;
|
||||
|
||||
/* Increment the tail index. Most operations are done using the
|
||||
* local variable 'tail' so that the final dev->recv.tail update
|
||||
* is atomic.
|
||||
*/
|
||||
|
||||
if (++tail >= dev->recv.size)
|
||||
{
|
||||
tail = 0;
|
||||
}
|
||||
|
||||
dev->recv.tail = tail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEV_SERIAL_FULLBLOCKS
|
||||
/* No... then we would have to wait to get receive more data.
|
||||
* If the user has specified the O_NONBLOCK option, then just
|
||||
* return what we have.
|
||||
*/
|
||||
|
||||
else if (filep->f_oflags & O_NONBLOCK)
|
||||
{
|
||||
/* If nothing was transferred, then return the -EAGAIN
|
||||
* error (not zero which means end of file).
|
||||
*/
|
||||
|
||||
if (recvd < 1)
|
||||
{
|
||||
recvd = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
/* No... the circular buffer is empty. Have we returned anything
|
||||
* to the caller?
|
||||
*/
|
||||
|
||||
else if (recvd > 0)
|
||||
{
|
||||
/* Yes.. break out of the loop and return the number of bytes
|
||||
* received up to the wait condition.
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* No... then we would have to wait to get receive some data.
|
||||
* If the user has specified the O_NONBLOCK option, then do not
|
||||
* wait.
|
||||
*/
|
||||
|
||||
else if (filep->f_oflags & O_NONBLOCK)
|
||||
{
|
||||
/* Break out of the loop returning -EAGAIN */
|
||||
|
||||
recvd = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
/* Otherwise we are going to have to wait for data to arrive */
|
||||
|
||||
else
|
||||
{
|
||||
/* Disable Rx interrupts and test again... */
|
||||
|
||||
uart_disablerxint(dev);
|
||||
|
||||
/* If the Rx ring buffer still empty? Bytes may have been addded
|
||||
* between the last time that we checked and when we disabled Rx
|
||||
* interrupts.
|
||||
*/
|
||||
|
||||
if (dev->recv.head == dev->recv.tail)
|
||||
{
|
||||
/* Yes.. the buffer is still empty. Wait for some characters
|
||||
* to be received into the buffer with the RX interrupt re-
|
||||
* enabled. All interrupts are disabled briefly to assure
|
||||
* that the following operations are atomic.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
dev->recvwaiting = true;
|
||||
uart_enablerxint(dev);
|
||||
|
||||
/* Now wait with the Rx interrupt re-enabled. NuttX will
|
||||
* automatically re-enable global interrupts when this thread
|
||||
* goes to sleep.
|
||||
*/
|
||||
|
||||
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
|
||||
{
|
||||
/* No... the ring buffer is no longer empty. Just re-enable Rx
|
||||
* interrupts and accept the new data on the next time through
|
||||
* the loop.
|
||||
*/
|
||||
|
||||
uart_enablerxint(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uart_givesem(&dev->recv.sem);
|
||||
return recvd;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_ioctl
|
||||
************************************************************************************/
|
||||
|
||||
static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR uart_dev_t *dev = inode->i_private;
|
||||
|
||||
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, bool setup)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR uart_dev_t *dev = inode->i_private;
|
||||
pollevent_t eventset;
|
||||
int ndx;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Some sanity checking */
|
||||
|
||||
#if CONFIG_DEBUG
|
||||
if (!dev || !fds)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Are we setting up the poll? Or tearing it down? */
|
||||
|
||||
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
|
||||
* slot for the poll structure reference
|
||||
*/
|
||||
|
||||
for (i = 0; i < CONFIG_SERIAL_NPOLLWAITERS; i++)
|
||||
{
|
||||
/* Find an available slot */
|
||||
|
||||
if (!dev->fds[i])
|
||||
{
|
||||
/* Bind the poll structure and this slot */
|
||||
|
||||
dev->fds[i] = fds;
|
||||
fds->priv = &dev->fds[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= CONFIG_SERIAL_NPOLLWAITERS)
|
||||
{
|
||||
fds->priv = NULL;
|
||||
ret = -EBUSY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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
|
||||
*
|
||||
* 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).
|
||||
*/
|
||||
|
||||
(void)uart_takesem(&dev->recv.sem, false);
|
||||
if (dev->recv.head != dev->recv.tail)
|
||||
{
|
||||
eventset |= POLLIN;
|
||||
}
|
||||
|
||||
uart_givesem(&dev->recv.sem);
|
||||
|
||||
if (eventset)
|
||||
{
|
||||
uart_pollnotify(dev, eventset);
|
||||
}
|
||||
|
||||
}
|
||||
else if (fds->priv)
|
||||
{
|
||||
/* This is a request to tear down the poll. */
|
||||
|
||||
struct pollfd **slot = (struct pollfd **)fds->priv;
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
if (!slot)
|
||||
{
|
||||
ret = -EIO;
|
||||
goto errout;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remove all memory of the poll setup */
|
||||
|
||||
*slot = NULL;
|
||||
fds->priv = NULL;
|
||||
}
|
||||
|
||||
errout:
|
||||
uart_givesem(&dev->pollsem);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_close
|
||||
*
|
||||
* Description:
|
||||
* This routine is called when the serial port gets closed.
|
||||
* It waits for the last remaining data to be sent.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
static int uart_close(FAR struct file *filep)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR uart_dev_t *dev = inode->i_private;
|
||||
irqstate_t flags;
|
||||
|
||||
/* 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--;
|
||||
uart_givesem(&dev->closesem);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* There are no more references to the port */
|
||||
|
||||
dev->open_count = 0;
|
||||
|
||||
/* Stop accepting input */
|
||||
|
||||
uart_disablerxint(dev);
|
||||
|
||||
/* Now we wait for the transmit buffer to clear */
|
||||
|
||||
while (dev->xmit.head != dev->xmit.tail)
|
||||
{
|
||||
#ifndef CONFIG_DISABLE_SIGNALS
|
||||
usleep(HALF_SECOND_USEC);
|
||||
#else
|
||||
up_mdelay(HALF_SECOND_MSEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* And wait for the TX fifo to drain */
|
||||
|
||||
while (!uart_txempty(dev))
|
||||
{
|
||||
#ifndef CONFIG_DISABLE_SIGNALS
|
||||
usleep(HALF_SECOND_USEC);
|
||||
#else
|
||||
up_mdelay(HALF_SECOND_MSEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Free the IRQ and disable the UART */
|
||||
|
||||
flags = irqsave(); /* Disable interrupts */
|
||||
uart_detach(dev); /* Detach interrupts */
|
||||
if (!dev->isconsole) /* Check for the serial console UART */
|
||||
{
|
||||
uart_shutdown(dev); /* Disable the UART */
|
||||
}
|
||||
irqrestore(flags);
|
||||
|
||||
uart_givesem(&dev->closesem);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_open
|
||||
*
|
||||
* Description:
|
||||
* This routine is called whenever a serial port is opened.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
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;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
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. */
|
||||
|
||||
tmp = dev->open_count + 1;
|
||||
if (tmp == 0)
|
||||
{
|
||||
/* More than 255 opens; uint8_t overflows to zero */
|
||||
|
||||
ret = -EMFILE;
|
||||
goto errout_with_sem;
|
||||
}
|
||||
|
||||
/* Check if this is the first time that the driver has been opened. */
|
||||
|
||||
if (tmp == 1)
|
||||
{
|
||||
irqstate_t flags = irqsave();
|
||||
|
||||
/* If this is the console, then the UART has already been initialized. */
|
||||
|
||||
if (!dev->isconsole)
|
||||
{
|
||||
/* Perform one time hardware initialization */
|
||||
|
||||
ret = uart_setup(dev);
|
||||
if (ret < 0)
|
||||
{
|
||||
irqrestore(flags);
|
||||
goto errout_with_sem;
|
||||
}
|
||||
}
|
||||
|
||||
/* In any event, we do have to configure for interrupt driven mode of
|
||||
* operation. Attach the hardware IRQ(s). Hmm.. should shutdown() the
|
||||
* the device in the rare case that uart_attach() fails, tmp==1, and
|
||||
* this is not the console.
|
||||
*/
|
||||
|
||||
ret = uart_attach(dev);
|
||||
if (ret < 0)
|
||||
{
|
||||
uart_shutdown(dev);
|
||||
irqrestore(flags);
|
||||
goto errout_with_sem;
|
||||
}
|
||||
|
||||
/* Mark the io buffers empty */
|
||||
|
||||
dev->xmit.head = 0;
|
||||
dev->xmit.tail = 0;
|
||||
dev->recv.head = 0;
|
||||
dev->recv.tail = 0;
|
||||
|
||||
/* Enable the RX interrupt */
|
||||
|
||||
uart_enablerxint(dev);
|
||||
irqrestore(flags);
|
||||
}
|
||||
|
||||
/* Save the new open count on success */
|
||||
|
||||
dev->open_count = tmp;
|
||||
|
||||
errout_with_sem:
|
||||
uart_givesem(&dev->closesem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_register
|
||||
*
|
||||
* Description:
|
||||
* Register serial console and serial ports.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
int uart_register(FAR const char *path, FAR uart_dev_t *dev)
|
||||
{
|
||||
sem_init(&dev->xmit.sem, 0, 1);
|
||||
sem_init(&dev->recv.sem, 0, 1);
|
||||
sem_init(&dev->closesem, 0, 1);
|
||||
sem_init(&dev->xmitsem, 0, 0);
|
||||
sem_init(&dev->recvsem, 0, 0);
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
sem_init(&dev->pollsem, 0, 1);
|
||||
#endif
|
||||
|
||||
dbg("Registering %s\n", path);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/************************************************************************************
|
||||
* drivers/serial/serialirq.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Included Files
|
||||
************************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <semaphore.h>
|
||||
#include <debug.h>
|
||||
#include <nuttx/serial/serial.h>
|
||||
|
||||
/************************************************************************************
|
||||
* Pre-processor Definitions
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Private Types
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Private Function Prototypes
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Private Variables
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Private Functions
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_xmitchars
|
||||
*
|
||||
* Description:
|
||||
* This function is called from the UART interrupt handler when an interrupt
|
||||
* is received indicating that there is more space in the transmit FIFO. This
|
||||
* function will send characters from the tail of the xmit buffer while the driver
|
||||
* write() logic adds data to the head of the xmit buffer.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
void uart_xmitchars(FAR uart_dev_t *dev)
|
||||
{
|
||||
uint16_t nbytes = 0;
|
||||
|
||||
/* Send while we still have data & room in the fifo */
|
||||
|
||||
while (dev->xmit.head != dev->xmit.tail && uart_txready(dev))
|
||||
{
|
||||
/* Send the next byte */
|
||||
|
||||
uart_send(dev, dev->xmit.buffer[dev->xmit.tail]);
|
||||
nbytes++;
|
||||
|
||||
/* Increment the tail index */
|
||||
|
||||
if (++(dev->xmit.tail) >= dev->xmit.size)
|
||||
{
|
||||
dev->xmit.tail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* When all of the characters have been sent from the buffer disable the TX
|
||||
* interrupt.
|
||||
*/
|
||||
|
||||
if (dev->xmit.head == dev->xmit.tail)
|
||||
{
|
||||
uart_disabletxint(dev);
|
||||
}
|
||||
|
||||
/* If any bytes were removed from the buffer, inform any waiters there there is
|
||||
* space available.
|
||||
*/
|
||||
|
||||
if (nbytes)
|
||||
{
|
||||
uart_datasent(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: uart_receivechars
|
||||
*
|
||||
* Description:
|
||||
* This function is called from the UART interrupt handler when an interrupt
|
||||
* is received indicating that are bytes available in the receive fifo. This
|
||||
* function will add chars to head of receive buffer. Driver read() logic will
|
||||
* take characters from the tail of the buffer.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
void uart_recvchars(FAR uart_dev_t *dev)
|
||||
{
|
||||
unsigned int status;
|
||||
int nexthead = dev->recv.head + 1;
|
||||
uint16_t nbytes = 0;
|
||||
|
||||
if (nexthead >= dev->recv.size)
|
||||
{
|
||||
nexthead = 0;
|
||||
}
|
||||
|
||||
/* Loop putting characters into the receive buffer until either there are no
|
||||
* further characters to available.
|
||||
*/
|
||||
|
||||
while (uart_rxavailable(dev))
|
||||
{
|
||||
char ch = uart_receive(dev, &status);
|
||||
|
||||
/* If the RX buffer becomes full, then the serial data is discarded. This is
|
||||
* necessary because on most serial hardware, you must read the data in order
|
||||
* to clear the RX interrupt. An option on some hardware might be to simply
|
||||
* disable RX interrupts until the RX buffer becomes non-FULL. However, that
|
||||
* would probably just cause the overrun to occur in hardware (unless it has
|
||||
* some large internal buffering).
|
||||
*/
|
||||
|
||||
if (nexthead != dev->recv.tail)
|
||||
{
|
||||
/* Add the character to the buffer */
|
||||
|
||||
dev->recv.buffer[dev->recv.head] = ch;
|
||||
nbytes++;
|
||||
|
||||
/* Increment the head index */
|
||||
|
||||
dev->recv.head = nexthead;
|
||||
if (++nexthead >= dev->recv.size)
|
||||
{
|
||||
nexthead = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If any bytes were added to the buffer, inform any waiters there there is new
|
||||
* incoming data available.
|
||||
*/
|
||||
|
||||
if (nbytes)
|
||||
{
|
||||
uart_datareceived(dev);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user