diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index e3ae3716c..48c21d29e 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -2651,3 +2651,4 @@ with OUT SETUP requests. * include/nuttx/watchdog.h: Add the definition of a standard watchdog driver interface. + * drivers/watchdog.c: The "upper half" watchdog timer driver. diff --git a/nuttx/drivers/Kconfig b/nuttx/drivers/Kconfig index e5148e6b4..e5fbd42d3 100644 --- a/nuttx/drivers/Kconfig +++ b/nuttx/drivers/Kconfig @@ -43,19 +43,110 @@ config RAMLOG config CAN bool "CAN support" default n + ---help--- + This selection enables building of the "upper-half" CAN driver. + See include/nuttx/can.h for further CAN driver information. + +if CAN +config CONFIG_CAN_EXTID + bool "CAN extended IDs" + default n + ---help--- + Enables support for the 29-bit extended ID. Default Standard 11-bit IDs. + +config CONFIG_CAN_FIFOSIZE + int "CAN driver I/O buffer size" + default 8 + ---help--- + The size of the circular buffer of CAN messages. Default: 8 + +config CONFIG_CAN_NPENDINGRTR + int "Number of pending RTRs" + default 4 + ---help--- + The size of the list of pending RTR requests. Default: 4 + +config CONFIG_CAN_LOOPBACK + bool "CAN extended IDs" + default n + ---help--- + A CAN driver may or may not support a loopback mode for testing. If the + driver does support loopback mode, the setting will enable it. (If the + driver does not, this setting will have no effect). + +endif config PWM bool "PWM support" default n + ---help--- + This selection enables building of the "upper-half" PWM driver. + See include/nuttx/pwm.h for further PWM driver information. + +if PWM +config PWM_PULSECOUNT + bool "PWM pulse count support" + default n + ---help--- + Some hardware will support generation of a fixed number of pulses. This + might be used, for example to support a stepper motor. If the hardware + will support a fixed pulse count, then this configuration should be set to + enable the capability. + +endif config I2C bool "I2C support" default y + ---help--- + This selection enables building of the "upper-half" I2C driver. + See include/nuttx/i2c.h for further I2C driver information. + +if I2C +endif config SPI bool "SPI support" default y - + ---help--- + This selection enables building of the "upper-half" SPI driver. + See include/nuttx/spi.h for further SPI driver information. + +if SPI +config SPI_OWNBUS + bool "SPI single device" + default y + ---help--- + Set if there is only one active device on the SPI bus. No locking or SPI + configuration will be performed. It is not necessary for clients to lock, + re-configure, etc.. + +config SPI_EXCHANGE + bool "SPI exchange" + default y + ---help--- + Driver supports a single exchange method (vs a recvblock() and sndblock ()methods). + +config SPI_CMDDATA + bool "SPI CMD/DATA" + default y + ---help--- + Devices on the SPI bus require out-of-band support to distinguish command + transfers from data transfers. Such devices will often support either 9-bit + SPI (yech) or 8-bit SPI and a GPIO output that selects between command and data. + +endif + +config WATCHDOG + bool "Watchdog timer support" + default y + ---help--- + This selection enables building of the "upper-half" watchdog timer driver. + See include/nuttx/watchdog.h for further watchdog timer driver information. + +if WATCHDOG +endif + menuconfig ANALOG bool "Analog Device(adc,dac) support" default n diff --git a/nuttx/drivers/Makefile b/nuttx/drivers/Makefile index 8b0701490..e32075624 100644 --- a/nuttx/drivers/Makefile +++ b/nuttx/drivers/Makefile @@ -82,6 +82,10 @@ endif ifeq ($(CONFIG_PWM),y) CSRCS += pwm.c endif + +ifeq ($(CONFIG_WATCHDOG),y) + CSRCS += watchdog.c +endif endif AOBJS = $(ASRCS:.S=$(OBJEXT)) diff --git a/nuttx/drivers/pwm.c b/nuttx/drivers/pwm.c index 78b800634..62fb4d2fb 100644 --- a/nuttx/drivers/pwm.c +++ b/nuttx/drivers/pwm.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/pwm.c * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -85,7 +85,7 @@ * Private Type Definitions ****************************************************************************/ -/* This structure describes the state of the upper half drivere */ +/* This structure describes the state of the upper half driver */ struct pwm_upperhalf_s { diff --git a/nuttx/drivers/watchdog.c b/nuttx/drivers/watchdog.c new file mode 100644 index 000000000..52436ac56 --- /dev/null +++ b/nuttx/drivers/watchdog.c @@ -0,0 +1,572 @@ +/**************************************************************************** + * drivers/watchdog.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_WATCHDOG + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Debug ********************************************************************/ +/* Non-standard debug that may be enabled just for testing PWM */ + +#ifdef CONFIG_DEBUG_WATCHDOG +# define wddbg dbg +# define wdvdbg vdbg +# define wdlldbg lldbg +# define wdllvdbg llvdbg +#else +# define wddbg(x...) +# define wdvdbg(x...) +# define wdlldbg(x...) +# define wdllvdbg(x...) +#endif + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +/* This structure describes the state of the upper half driver */ + +struct watchdog_upperhalf_s +{ + uint8_t crefs; /* The number of times the device has been opened */ + sem_t exclsem; /* Supports mutual exclusion */ + FAR char *path; /* Registration path */ + + /* The contained lower-half driver */ + + FAR struct watchdog_lowerhalf_s *lower; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int wdog_open(FAR struct file *filep); +static int wdog_close(FAR struct file *filep); +static ssize_t wdog_read(FAR struct file *filep, FAR char *buffer, size_t buflen); +static ssize_t wdog_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); +static int wdog_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_wdogops = +{ + wdog_open, /* open */ + wdog_close, /* close */ + wdog_read, /* read */ + wdog_write, /* write */ + 0, /* seek */ + wdog_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , 0 /* poll */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/************************************************************************************ + * Name: wdog_open + * + * Description: + * This function is called whenever the watchdog timer device is opened. + * + ************************************************************************************/ + +static int wdog_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct watchdog_upperhalf_s *upper = inode->i_private; + uint8_t tmp; + int ret; + + wdvdbg("crefs: %d\n", upper->crefs); + + /* Get exclusive access to the device structures */ + + ret = sem_wait(&upper->exclsem); + if (ret < 0) + { + ret = -errno; + goto errout; + } + + /* Increment the count of references to the device. If this the first + * time that the driver has been opened for this device, then initialize + * the device. + */ + + tmp = upper->crefs + 1; + if (tmp == 0) + { + /* More than 255 opens; uint8_t overflows to zero */ + + ret = -EMFILE; + goto errout_with_sem; + } + + /* Save the new open count */ + + upper->crefs = tmp; + ret = OK; + +errout_with_sem: + sem_post(&upper->exclsem); + +errout: + return ret; +} + +/************************************************************************************ + * Name: wdog_close + * + * Description: + * This function is called when the watchdog timer device is closed. + * + ************************************************************************************/ + +static int wdog_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct watchdog_upperhalf_s *upper = inode->i_private; + int ret; + + wdvdbg("crefs: %d\n", upper->crefs); + + /* Get exclusive access to the device structures */ + + ret = sem_wait(&upper->exclsem); + if (ret < 0) + { + ret = -errno; + goto errout; + } + + /* Decrement the references to the driver. If the reference count will + * decrement to 0, then uninitialize the driver. + */ + + if (upper->crefs > 0) + { + upper->crefs--; + } + + sem_post(&upper->exclsem); + ret = OK; + +errout: + return ret; +} + +/************************************************************************************ + * Name: wdog_read + * + * Description: + * A dummy read method. This is provided only to satsify the VFS layer. + * + ************************************************************************************/ + +static ssize_t wdog_read(FAR struct file *filep, FAR char *buffer, size_t buflen) +{ + /* Return zero -- usually meaning end-of-file */ + + return 0; +} + +/************************************************************************************ + * Name: wdog_write + * + * Description: + * A dummy write method. This is provided only to satsify the VFS layer. + * + ************************************************************************************/ + +static ssize_t wdog_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) +{ + return 0; +} + +/************************************************************************************ + * Name: wdog_ioctl + * + * Description: + * The standard ioctl method. This is where ALL of the watchdog timer work is + * done. + * + ************************************************************************************/ + +static int wdog_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct watchdog_upperhalf_s *upper = inode->i_private; + FAR struct watchdog_lowerhalf_s *lower = upper->lower; + int ret; + + wdvdbg("cmd: %d arg: %ld\n", cmd, arg); + DEBUGASSERT(upper && lower); + + /* Get exclusive access to the device structures */ + + ret = sem_wait(&upper->exclsem); + if (ret < 0) + { + return ret; + } + + /* Handle built-in ioctl commands */ + + switch (cmd) + { + /* cmd: WDIOC_START + * Description: Start the watchdog timer + * Argument: Ignored + */ + + case WDIOC_START: + { + /* Start the watchdog timer, resetting the time to the current timeout */ + + DEBUGASSERT(lower->ops->start); /* Required */ + ret = lower->ops->start(lower); + } + break; + + /* cmd: WDIOC_STOP + * Description: Stop the watchdog timer + * Argument: Ignored + */ + + case WDIOC_STOP: + { + /* Stop the watchdog timer */ + + DEBUGASSERT(lower->ops->stop); /* Required */ + ret = lower->ops->stop(lower); + } + break; + + /* cmd: WDIOC_GETSTATUS + * Description: et the status of the watchdog timer. + * Argument: A writeable pointer to struct watchdog_status_s. + */ + + case WDIOC_GETSTATUS: + { + FAR struct watchdog_status_s *status; + + /* Get the current watchdog timer status */ + + if (lower->ops->getstatus) /* Optional */ + { + status = (FAR struct watchdog_status_s *)((uintptr_t)arg); + if (status) + { + ret = lower->ops->getstatus(lower, status); + } + else + { + ret = -EINVAL; + } + } + else + { + ret = -ENOSYS; + } + } + break; + + /* cmd: WDIOC_SETTIMEOUT + * Description: Reset the watchdog timeout to this value + * Argument: A 32-bit timeout value in milliseconds. + */ + + case WDIOC_SETTIMEOUT: + { + /* Set a new timeout value (and reset the watchdog timer) */ + + if (lower->ops->settimeout) /* Optional */ + { + ret = lower->ops->settimeout(lower, (uint32_t)arg); + } + else + { + ret = -ENOSYS; + } + } + break; + + /* cmd: WDIOC_CAPTURE + * Description: Do not reset. Instead, called this handler. + * Argument: A pointer to struct watchdog_capture_s. + */ + + case WDIOC_CAPTURE: + { + FAR struct watchdog_capture_s *capture; + + /* Don't reset on watchdog timer timeout; instead, call this user + * provider timeout handler. NOTE: Providing handler==NULL will + * restore the reset behavior. + */ + + if (lower->ops->capture) /* Optional */ + { + capture = (FAR struct watchdog_capture_s *)((uintptr_t)arg); + if (capture) + { + capture->oldhandler = + lower->ops->capture(lower, capture->newhandler); + ret = OK; + } + else + { + ret = -EINVAL; + } + } + else + { + ret = -ENOSYS; + } + } + break; + + /* cmd: WDIOC_KEEPALIVE + * Description: Reset the watchdog timer ("ping", "pet the dog") + * Argument: Argument: Ignored + */ + + case WDIOC_KEEPALIVE: + { + /* Reset the watchdog timer to the current timeout value, prevent any + * imminent watchdog timeouts. This is sometimes referred as + * "pinging" the watchdog timer or "petting the dog". + */ + + if (lower->ops->keepalive) /* Optional */ + { + ret = lower->ops->keepalive(lower); + } + else + { + ret = -ENOSYS; + } + } + break; + + + /* Any unrecognized IOCTL commands might be platform-specific ioctl commands */ + + default: + { + wdvdbg("Forwarding unrecognized cmd: %d arg: %ld\n", cmd, arg); + + /* An ioctl commands that are not recognized by the "upper-half" + * driver are forwarded to the lower half driver through this + * method. + */ + + if (lower->ops->ioctl) /* Optional */ + { + ret = lower->ops->ioctl(lower, cmd, arg); + } + else + { + ret = -ENOSYS; + } + } + break; + } + + sem_post(&upper->exclsem); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: watchdog_register + * + * Description: + * This function binds an instance of a "lower half" watchdog driver with the + * "upper half" watchdog device and registers that device so that can be used + * by application code. + * + * When this function is called, the "lower half" driver should be in the + * disabled state (as if the stop() method had already been called). + * + * Input parameters: + * dev path - The full path to the driver to be registers in the NuttX + * pseudo-filesystem. The recommended convention is to name all watchdog + * drivers as "/dev/watchdog0", "/dev/watchdog1", etc. where the driver + * path differs only in the "minor" number at the end of the device name. + * lower - A pointer to an instance of lower half watchdog driver. This + * instance is bound to the watchdog driver and must persists as long as + * the driver persists. + * + * Returned Value: + * On success, a non-NULL handle is returned to the caller. In the event + * of any failure, a NULL value is returned. + * + ****************************************************************************/ + +FAR void *watchdog_register(FAR const char *path, + FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct watchdog_upperhalf_s *upper; + int ret; + + DEBUGASSERT(path && lower); + + /* Allocate the upper-half data structure */ + + upper = (FAR struct watchdog_upperhalf_s *) + kzalloc(sizeof(struct watchdog_upperhalf_s)); + if (!upper) + { + wddbg("Upper half allocation failed\n"); + goto errout; + } + + /* Initialize the watchdog timer device structure (it was already zeroed + * by kzalloc()). + */ + + sem_init(&upper->exclsem, 0, 1); + upper->lower = lower; + + /* Copy the registration path */ + + upper->path = strdup(path); + if (!upper->path) + { + wddbg("Path allocation failed\n"); + goto errout_with_upper; + } + + /* Register the watchdog timer device */ + + wdvdbg("Registering %s\n", path); + ret = register_driver(path, &g_wdogops, 0666, upper); + if (ret < 0) + { + wddbg("register_driver failed: %d\n", ret); + goto errout_with_path; + } + + return (FAR void *)upper; + +errout_with_path: + kfree(upper->path); + +errout_with_upper: + sem_destroy(&upper->exclsem); + kfree(upper); + +errout: + return NULL; +} + +/**************************************************************************** + * Name: watchdog_unregister + * + * Description: + * This function can be called to disable and unregister the watchdog + * device driver. + * + * Input parameters: + * handle - This is the handle that was returned by watchdog_register() + * + * Returned Value: + * None + * + ****************************************************************************/ + +void watchdog_unregister(FAR void *handle) +{ + FAR struct watchdog_upperhalf_s *upper; + FAR struct watchdog_lowerhalf_s *lower; + + wdvdbg("cmd: %d arg: %ld\n", cmd, arg); + + /* Recover the pointer to the upper-half driver state */ + + upper = (FAR struct watchdog_upperhalf_s *)handle; + lower = upper->lower; + DEBUGASSERT(upper && lower); + + /* Disable the watchdog timer */ + + DEBUGASSERT(lower->ops->stop); /* Required */ + (void)lower->ops->stop(lower); + + /* Unregister the watchdog timer device */ + + (void)unregister_driver(upper->path); + + /* Then free all of the driver resources */ + + kfree(upper->path); + sem_destroy(&upper->exclsem); + kfree(upper); +} + +#endif /* CONFIG_WATCHDOG */ diff --git a/nuttx/include/nuttx/watchdog.h b/nuttx/include/nuttx/watchdog.h index 7c721a63b..75e5f4c91 100755 --- a/nuttx/include/nuttx/watchdog.h +++ b/nuttx/include/nuttx/watchdog.h @@ -56,7 +56,7 @@ * * WDIOC_START - Start the watchdog timer * Argument: Ignored - * WDIOC_START - Stop the watchdog timer + * WDIOC_STOP - Stop the watchdog timer * Argument: Ignored * WDIOC_GETSTATUS - Get the status of the watchdog timer. * Argument: A writeable pointer to struct watchdog_status_s. @@ -133,7 +133,7 @@ struct watchdog_ops_s /* Get the current watchdog timer status */ CODE int (*getstatus)(FAR struct watchdog_lowerhalf_s *lower, - FAR watchdog_state_s *status); + FAR struct watchdog_status_s *status); /* Set a new timeout value (and reset the watchdog timer) */ @@ -141,14 +141,14 @@ struct watchdog_ops_s uint32_t timeout); /* Don't reset on watchdog timer timeout; instead, call this user provider - * timeout handler. NOTE: Providing handler==NULL will store the reset + * timeout handler. NOTE: Providing handler==NULL will restore the reset * behavior. */ CODE xcpt_t (*capture)(FAR struct watchdog_lowerhalf_s *lower, - xcpt_t handler); + CODE xcpt_t handler); - /* An ioctl commands that are not recognized by the "upper-half" driver + /* Any ioctl commands that are not recognized by the "upper-half" driver * are forwarded to the lower half driver through this method. */ @@ -217,8 +217,8 @@ extern "C" { * ****************************************************************************/ -FAR void *watchdog_register(FAR const char *path, - FAR struct watchdog_lowerhalf_s *lower); +EXTERN FAR void *watchdog_register(FAR const char *path, + FAR struct watchdog_lowerhalf_s *lower); /**************************************************************************** * Name: watchdog_unregister