9
0
Fork 0

Add an upper half watchdog timer driver

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4604 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2012-04-13 23:37:52 +00:00
parent 63fd83d69c
commit 5bf7f95a58
6 changed files with 678 additions and 10 deletions

View File

@ -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.

View File

@ -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

View File

@ -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))

View File

@ -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 <gnutt@nuttx.org>
*
* 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
{

572
nuttx/drivers/watchdog.c Normal file
View File

@ -0,0 +1,572 @@
/****************************************************************************
* drivers/watchdog.c
*
* Copyright (C) 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 <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/fs/fs.h>
#include <nuttx/irq.h>
#include <nuttx/kmalloc.h>
#include <nuttx/watchdog.h>
#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 */

View File

@ -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