diff options
author | Lorenz Meier <lm@inf.ethz.ch> | 2013-06-01 01:04:32 +0200 |
---|---|---|
committer | Lorenz Meier <lm@inf.ethz.ch> | 2013-06-01 01:04:32 +0200 |
commit | 5375bb5b86e266157ceceef08c367da711b8144e (patch) | |
tree | 88bc81cab11d8f0b2b6f9391f803051c081b2ecb /nuttx/drivers/pipes/pipe_common.c | |
parent | 27ee36b2049167a1272122548fe61aa2993d79c1 (diff) | |
download | px4-firmware-5375bb5b86e266157ceceef08c367da711b8144e.tar.gz px4-firmware-5375bb5b86e266157ceceef08c367da711b8144e.tar.bz2 px4-firmware-5375bb5b86e266157ceceef08c367da711b8144e.zip |
Cleanup, WIP, needs a NuttX checkout to Firmware/NuttX now
Diffstat (limited to 'nuttx/drivers/pipes/pipe_common.c')
-rw-r--r-- | nuttx/drivers/pipes/pipe_common.c | 682 |
1 files changed, 0 insertions, 682 deletions
diff --git a/nuttx/drivers/pipes/pipe_common.c b/nuttx/drivers/pipes/pipe_common.c deleted file mode 100644 index 5f61fdd8e..000000000 --- a/nuttx/drivers/pipes/pipe_common.c +++ /dev/null @@ -1,682 +0,0 @@ -/**************************************************************************** - * drivers/pipes/pipe_common.c - * - * Copyright (C) 2008-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 <sys/stat.h> -#include <stdint.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <sched.h> -#include <semaphore.h> -#include <fcntl.h> -#include <errno.h> -#include <assert.h> -#include <debug.h> - -#include <nuttx/kmalloc.h> -#include <nuttx/fs/fs.h> -#if CONFIG_DEBUG -# include <nuttx/arch.h> -#endif - -#include "pipe_common.h" - -#if CONFIG_DEV_PIPE_SIZE > 0 - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* CONFIG_DEV_PIPEDUMP will dump the contents of each transfer into and out - * of the pipe. - */ - -#ifdef CONFIG_DEV_PIPEDUMP -# define pipe_dumpbuffer(m,a,n) lib_dumpbuffer(m,a,n) -#else -# define pipe_dumpbuffer(m,a,n) -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static void pipecommon_semtake(sem_t *sem); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pipecommon_semtake - ****************************************************************************/ - -static void pipecommon_semtake(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(errno == EINTR); - } -} - -/**************************************************************************** - * Name: pipecommon_pollnotify - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static void pipecommon_pollnotify(FAR struct pipe_dev_s *dev, pollevent_t eventset) -{ - int i; - - for (i = 0; i < CONFIG_DEV_PIPE_NPOLLWAITERS; i++) - { - struct pollfd *fds = dev->d_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 pipecommon_pollnotify(dev,event) -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pipecommon_allocdev - ****************************************************************************/ - -FAR struct pipe_dev_s *pipecommon_allocdev(void) -{ - struct pipe_dev_s *dev; - - /* Allocate a private structure to manage the pipe */ - - dev = (struct pipe_dev_s *)kmalloc(sizeof(struct pipe_dev_s)); - if (dev) - { - /* Initialize the private structure */ - - memset(dev, 0, sizeof(struct pipe_dev_s)); - sem_init(&dev->d_bfsem, 0, 1); - sem_init(&dev->d_rdsem, 0, 0); - sem_init(&dev->d_wrsem, 0, 0); - } - - return dev; -} - -/**************************************************************************** - * Name: pipecommon_freedev - ****************************************************************************/ - -void pipecommon_freedev(FAR struct pipe_dev_s *dev) -{ - sem_destroy(&dev->d_bfsem); - sem_destroy(&dev->d_rdsem); - sem_destroy(&dev->d_wrsem); - kfree(dev); -} - -/**************************************************************************** - * Name: pipecommon_open - ****************************************************************************/ - -int pipecommon_open(FAR struct file *filep) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; - int sval; - int ret; - - /* Some sanity checking */ -#if CONFIG_DEBUG - if (!dev) - { - return -EBADF; - } -#endif - - /* Make sure that we have exclusive access to the device structure. The - * sem_wait() call should fail only if we are awakened by a signal. - */ - - ret = sem_wait(&dev->d_bfsem); - if (ret != OK) - { - fdbg("sem_wait failed: %d\n", errno); - DEBUGASSERT(errno > 0); - return -errno; - } - - /* If this the first reference on the device, then allocate the buffer */ - - if (dev->d_refs == 0) - { - dev->d_buffer = (uint8_t*)kmalloc(CONFIG_DEV_PIPE_SIZE); - if (!dev->d_buffer) - { - (void)sem_post(&dev->d_bfsem); - return -ENOMEM; - } - } - - /* Increment the reference count on the pipe instance */ - - dev->d_refs++; - - /* If opened for writing, increment the count of writers on on the pipe instance */ - - if ((filep->f_oflags & O_WROK) != 0) - { - dev->d_nwriters++; - - /* If this this is the first writer, then the read semaphore indicates the - * number of readers waiting for the first writer. Wake them all up. - */ - - if (dev->d_nwriters == 1) - { - while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_rdsem); - } - } - } - - /* If opened for read-only, then wait for at least one writer on the pipe */ - - sched_lock(); - (void)sem_post(&dev->d_bfsem); - if ((filep->f_oflags & O_RDWR) == O_RDONLY && dev->d_nwriters < 1) - { - /* NOTE: d_rdsem is normally used when the read logic waits for more - * data to be written. But until the first writer has opened the - * pipe, the meaning is different: it is used prevent O_RDONLY open - * calls from returning until there is at least one writer on the pipe. - * This is required both by spec and also because it prevents - * subsequent read() calls from returning end-of-file because there is - * no writer on the pipe. - */ - - ret = sem_wait(&dev->d_rdsem); - if (ret != OK) - { - /* The sem_wait() call should fail only if we are awakened by - * a signal. - */ - - fdbg("sem_wait failed: %d\n", errno); - DEBUGASSERT(errno > 0); - ret = -errno; - - /* Immediately close the pipe that we just opened */ - - (void)pipecommon_close(filep); - } - } - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: pipecommon_close - ****************************************************************************/ - -int pipecommon_close(FAR struct file *filep) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; - int sval; - - /* Some sanity checking */ -#if CONFIG_DEBUG - if (!dev) - { - return -EBADF; - } -#endif - - /* Make sure that we have exclusive access to the device structure. - * NOTE: close() is supposed to return EINTR if interrupted, however - * I've never seen anyone check that. - */ - - pipecommon_semtake(&dev->d_bfsem); - - /* Check if the decremented reference count would go to zero */ - - if (dev->d_refs > 1) - { - /* No.. then just decrement the reference count */ - - dev->d_refs--; - - /* If opened for writing, decrement the count of writers on on the pipe instance */ - - if ((filep->f_oflags & O_WROK) != 0) - { - /* If there are no longer any writers on the pipe, then notify all of the - * waiting readers that they must return end-of-file. - */ - - if (--dev->d_nwriters <= 0) - { - while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_rdsem); - } - } - } - } - else - { - /* Yes... deallocate the buffer */ - - kfree(dev->d_buffer); - dev->d_buffer = NULL; - - /* And reset all counts and indices */ - - dev->d_wrndx = 0; - dev->d_rdndx = 0; - dev->d_refs = 0; - dev->d_nwriters = 0; - } - - sem_post(&dev->d_bfsem); - return OK; -} - -/**************************************************************************** - * Name: pipecommon_read - ****************************************************************************/ - -ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; -#ifdef CONFIG_DEV_PIPEDUMP - FAR uint8_t *start = (uint8_t*)buffer; -#endif - ssize_t nread = 0; - int sval; - int ret; - - /* Some sanity checking */ -#if CONFIG_DEBUG - if (!dev) - { - return -ENODEV; - } -#endif - - /* Make sure that we have exclusive access to the device structure */ - - if (sem_wait(&dev->d_bfsem) < 0) - { - return ERROR; - } - - /* If the pipe is empty, then wait for something to be written to it */ - - while (dev->d_wrndx == dev->d_rdndx) - { - /* If O_NONBLOCK was set, then return EGAIN */ - - if (filep->f_oflags & O_NONBLOCK) - { - sem_post(&dev->d_bfsem); - return -EAGAIN; - } - - /* If there are no writers on the pipe, then return end of file */ - - if (dev->d_nwriters <= 0) - { - sem_post(&dev->d_bfsem); - return 0; - } - - /* Otherwise, wait for something to be written to the pipe */ - - sched_lock(); - sem_post(&dev->d_bfsem); - ret = sem_wait(&dev->d_rdsem); - sched_unlock(); - - if (ret < 0 || sem_wait(&dev->d_bfsem) < 0) - { - return ERROR; - } - } - - /* Then return whatever is available in the pipe (which is at least one byte) */ - - nread = 0; - while (nread < len && dev->d_wrndx != dev->d_rdndx) - { - *buffer++ = dev->d_buffer[dev->d_rdndx]; - if (++dev->d_rdndx >= CONFIG_DEV_PIPE_SIZE) - { - dev->d_rdndx = 0; - } - nread++; - } - - /* Notify all waiting writers that bytes have been removed from the buffer */ - - while (sem_getvalue(&dev->d_wrsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_wrsem); - } - - /* Notify all poll/select waiters that they can write to the FIFO */ - - pipecommon_pollnotify(dev, POLLOUT); - - sem_post(&dev->d_bfsem); - pipe_dumpbuffer("From PIPE:", start, nread); - return nread; -} - -/**************************************************************************** - * Name: pipecommon_write - ****************************************************************************/ - -ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer, size_t len) -{ - struct inode *inode = filep->f_inode; - struct pipe_dev_s *dev = inode->i_private; - ssize_t nwritten = 0; - ssize_t last; - int nxtwrndx; - int sval; - - /* Some sanity checking */ - -#if CONFIG_DEBUG - if (!dev) - { - return -ENODEV; - } -#endif - - pipe_dumpbuffer("To PIPE:", (uint8_t*)buffer, len); - - /* At present, this method cannot be called from interrupt handlers. That is - * because it calls sem_wait (via pipecommon_semtake below) and sem_wait cannot - * be called from interrupt level. This actually happens fairly commonly - * IF dbg() is called from interrupt handlers and stdout is being redirected - * via a pipe. In that case, the debug output will try to go out the pipe - * (interrupt handlers should use the lldbg() APIs). - * - * On the other hand, it would be very valuable to be able to feed the pipe - * from an interrupt handler! TODO: Consider disabling interrupts instead - * of taking semaphores so that pipes can be written from interupt handlers - */ - - DEBUGASSERT(up_interrupt_context() == false) - - /* Make sure that we have exclusive access to the device structure */ - - if (sem_wait(&dev->d_bfsem) < 0) - { - return ERROR; - } - - /* Loop until all of the bytes have been written */ - - last = 0; - for (;;) - { - /* Calculate the write index AFTER the next byte is written */ - - nxtwrndx = dev->d_wrndx + 1; - if (nxtwrndx >= CONFIG_DEV_PIPE_SIZE) - { - nxtwrndx = 0; - } - - /* Would the next write overflow the circular buffer? */ - - if (nxtwrndx != dev->d_rdndx) - { - /* No... copy the byte */ - - dev->d_buffer[dev->d_wrndx] = *buffer++; - dev->d_wrndx = nxtwrndx; - - /* Is the write complete? */ - - if (++nwritten >= len) - { - /* Yes.. Notify all of the waiting readers that more data is available */ - - while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_rdsem); - } - - /* Notify all poll/select waiters that they can write to the FIFO */ - - pipecommon_pollnotify(dev, POLLIN); - - /* Return the number of bytes written */ - - sem_post(&dev->d_bfsem); - return len; - } - } - else - { - /* There is not enough room for the next byte. Was anything written in this pass? */ - - if (last < nwritten) - { - /* Yes.. Notify all of the waiting readers that more data is available */ - - while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval < 0) - { - sem_post(&dev->d_rdsem); - } - } - last = nwritten; - - /* If O_NONBLOCK was set, then return partial bytes written or EGAIN */ - - if (filep->f_oflags & O_NONBLOCK) - { - if (nwritten == 0) - { - nwritten = -EAGAIN; - } - sem_post(&dev->d_bfsem); - return nwritten; - } - - /* There is more to be written.. wait for data to be removed from the pipe */ - - sched_lock(); - sem_post(&dev->d_bfsem); - pipecommon_semtake(&dev->d_wrsem); - sched_unlock(); - pipecommon_semtake(&dev->d_bfsem); - } - } -} - -/**************************************************************************** - * Name: pipecommon_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct pipe_dev_s *dev = inode->i_private; - pollevent_t eventset; - pipe_ndx_t nbytes; - 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? */ - - pipecommon_semtake(&dev->d_bfsem); - 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_PIPE_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!dev->d_fds[i]) - { - /* Bind the poll structure and this slot */ - - dev->d_fds[i] = fds; - fds->priv = &dev->d_fds[i]; - break; - } - } - - if (i >= CONFIG_DEV_PIPE_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should immediately notify on any of the requested events? - * First, determine how many bytes are in the buffer - */ - - if (dev->d_wrndx >= dev->d_rdndx) - { - nbytes = dev->d_wrndx - dev->d_rdndx; - } - else - { - nbytes = (CONFIG_DEV_PIPE_SIZE-1) + dev->d_wrndx - dev->d_rdndx; - } - - /* Notify the POLLOUT event if the pipe is not full */ - - eventset = 0; - if (nbytes < (CONFIG_DEV_PIPE_SIZE-1)) - { - eventset |= POLLOUT; - } - - /* Notify the POLLIN event if the pipe is not empty */ - - if (nbytes > 0) - { - eventset |= POLLIN; - } - - if (eventset) - { - pipecommon_pollnotify(dev, eventset); - } - } - else - { - /* 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: - sem_post(&dev->d_bfsem); - return ret; -} -#endif - -#endif /* CONFIG_DEV_PIPE_SIZE > 0 */ |