diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-10-18 13:52:21 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-10-18 13:52:21 +0000 |
commit | 0ee20483b0ff4150e09338821ef7e5a62eab2d47 (patch) | |
tree | 15c6069e637ef2c122e4a48db9e52dd4dde10bdd /nuttx/drivers/serial.c | |
parent | 00a3fe0fd33b150ac10dd3e576fc4893abb61893 (diff) | |
download | px4-nuttx-0ee20483b0ff4150e09338821ef7e5a62eab2d47.tar.gz px4-nuttx-0ee20483b0ff4150e09338821ef7e5a62eab2d47.tar.bz2 px4-nuttx-0ee20483b0ff4150e09338821ef7e5a62eab2d47.zip |
Move some drivers to separate subdirectories
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2156 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/drivers/serial.c')
-rw-r--r-- | nuttx/drivers/serial.c | 741 |
1 files changed, 0 insertions, 741 deletions
diff --git a/nuttx/drivers/serial.c b/nuttx/drivers/serial.c deleted file mode 100644 index a7cb42b20..000000000 --- a/nuttx/drivers/serial.c +++ /dev/null @@ -1,741 +0,0 @@ -/************************************************************************************ - * drivers/serial.c - * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> - * - * 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 <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.h> -#include <nuttx/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) - -/************************************************************************************ - * 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, boolean 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 void uart_takesem(FAR sem_t *sem) -{ - while (sem_wait(sem) != 0) - { - /* The only case that an error should occur here is if - * the wait was awakened by a signal. - */ - - ASSERT(*get_errno_ptr() == EINTR); - } -} - -/************************************************************************************ - * 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_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 - ************************************************************************************/ - -static void uart_putxmitchar(FAR uart_dev_t *dev, int ch) -{ - int nexthead = dev->xmit.head + 1; - if (nexthead >= dev->xmit.size) - { - nexthead = 0; - } - - for(;;) - { - if (nexthead != dev->xmit.tail) - { - dev->xmit.buffer[dev->xmit.head] = ch; - dev->xmit.head = nexthead; - return; - } - else - { - /* Inform the interrupt level logic that we are waiting */ - - dev->xmitwaiting = TRUE; - - /* Wait for some characters to be sent from the buffer - * with the TX interrupt enabled. When the TX interrupt - * is enabled, uart_xmitchars should execute and remove - * some of the data from the TX buffer. - */ - - uart_enabletxint(dev); - uart_takesem(&dev->xmitsem); - uart_disabletxint(dev); - } - } -} - -/************************************************************************************ - * Name: uart_irqwrite - ************************************************************************************/ - -static 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++; - uart_putc(ch); - - /* If this is the console, then we should replace LF with LF-CR */ - - if (ch == '\n') - { - uart_putc('\r'); - } - } - - 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 ret = buflen; - - /* 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) - { - if (dev->isconsole) - { - irqstate_t flags = irqsave(); - ret = uart_irqwrite(dev, buffer, buflen); - irqrestore(flags); - return ret; - } - else - { - return ERROR; - } - } - - /* Only one user can be accessing dev->xmit.head at once */ - - uart_takesem(&dev->xmit.sem); - - /* 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++; - - /* 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->isconsole && ch == '\n') - { - uart_putxmitchar(dev, '\r'); - } - } - - if (dev->xmit.head != dev->xmit.tail) - { - uart_enabletxint(dev); - } - - uart_givesem(&dev->xmit.sem); - return ret; -} - -/************************************************************************************ - * 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; - ssize_t recvd = 0; - - /* Only one user can be accessing dev->recv.tail at once */ - - uart_takesem(&dev->recv.sem); - - /* 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. - */ - - uart_disablerxint(dev); - while (recvd < buflen) - { - /* Check if there is more data to return in the circular buffer */ - - if (dev->recv.head != dev->recv.tail) - { - *buffer++ = dev->recv.buffer[dev->recv.tail]; - recvd++; - - if (++(dev->recv.tail) >= dev->recv.size) - { - dev->recv.tail = 0; - } - } - -#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 - { - /* Wait for some characters to be sent from the buffer - * with the TX interrupt re-enabled. - */ - - dev->recvwaiting = TRUE; - uart_enablerxint(dev); - uart_takesem(&dev->recvsem); - uart_disablerxint(dev); - } - } - - 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, boolean setup) -{ - FAR struct inode *inode = filep->f_inode; - FAR uart_dev_t *dev = inode->i_private; - pollevent_t eventset; - int ndx; - int ret = OK; - int i; - - /* Some sanity checking */ - -#if CONFIG_DEBUG - if (!dev || !fds) - { - return -ENODEV; - } -#endif - - /* Are we setting up the poll? Or tearing it down? */ - - uart_takesem(&dev->pollsem); - 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_DEV_CONSOLE_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_DEV_CONSOLE_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should immediately notify on any of the requested events? - * First, 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); - } - - } - 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; - - uart_takesem(&dev->closesem); - 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(500*1000); -#else - up_mdelay(500); -#endif - } - - /* And wait for the TX fifo to drain */ - - while (!uart_txempty(dev)) - { -#ifndef CONFIG_DISABLE_SIGNALS - usleep(500*1000); -#else - up_mdelay(500); -#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; - ubyte tmp; - int ret = OK; - - /* If the port is the middle of closing, wait until the close is finished */ - - uart_takesem(&dev->closesem); - - /* Start up serial port */ - /* Increment the count of references to the device. */ - - tmp = dev->open_count + 1; - if (tmp == 0) - { - /* More than 255 opens; ubyte 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); -} - - |