diff --git a/Kconfig b/Kconfig index e57918a0ff4..ce0bfa5b13d 100644 --- a/Kconfig +++ b/Kconfig @@ -548,6 +548,16 @@ config DEBUG_INPUT this debug option is board-specific and may not be available for some boards. +config DEBUG_DISCRETE + bool "Discrete I/O Debug Output" + default n + depends on DISCRETE_IO + ---help--- + Enable low level debug SYSLOG output from the discrete I/O device + drivers such as LEDs and I/O expanders (disabled by default). + Support for this debug option is board-specific and may not be + available for some boards. + config DEBUG_ANALOG bool "Analog Device Debug Output" default n diff --git a/drivers/discrete/Kconfig b/drivers/discrete/Kconfig index afeaacb8347..9bd4492a9de 100644 --- a/drivers/discrete/Kconfig +++ b/drivers/discrete/Kconfig @@ -42,3 +42,39 @@ config PCA9555_INT_DISABLE endif # IOEXPANDER_PCA9555 endif # IOEXPANDER + +config USERLED + bool "LED driver" + default n + depends on ARCH_HAVE_LEDS + ---help--- + Enable standard user LED upper half driver. + +if USERLED + +config USERLED_LOWER + bool "Generic Lower Half LED Driver" + default n + ---help--- + If the board supports the standard LED interfaces as + defined in include/nuttx/board.h header file, then this + standard LED lower half driver might be usable. + + In order for this generic driver to be usable: + + 1. The board implementation must provide the LED + interfaces as defined in include/nuttx/board.h + 2. The board.h header file must provide the definition + NUM_USERLED, and + 3. The board.h header file must not include any other + header files that are not accessibble in this context + (such as those in arch//src/) UNLESS those + inclusions are conditioned on __KERNEL__. button_lower.c + will undefine __KERNEL__ before included board.h. + + If your board does not meet these requirements, then the + userled_lower.c file can still be copied to your your + board src/ directory and modified for your specific board + requirements. + +endif # USERLED diff --git a/drivers/discrete/Make.defs b/drivers/discrete/Make.defs index 94ae462c7cc..3dc5cfa176d 100644 --- a/drivers/discrete/Make.defs +++ b/drivers/discrete/Make.defs @@ -33,17 +33,31 @@ # ############################################################################ -# Don't build anything if there is no support for io expander devices +# Don't build anything if there is no support for discrete devices + +ifeq ($(CONFIG_DISCRETE_IO),y) + +# Include user LED driver + +ifeq ($(CONFIG_USERLED),y) + CSRCS += userled_upper.c +ifeq ($(CONFIG_USERLED_LOWER),y) + CSRCS += userled_lower.c +endif +endif + +# Check if I/O expander support is enabled ifeq ($(CONFIG_IOEXPANDER),y) -# Include the selected io expander drivers +# Include the selected I/O expander drivers ifeq ($(CONFIG_IOEXPANDER_PCA9555),y) CSRCS += pca9555.c endif +endif -# Include io expander device driver build support +# Include discrete I/O device driver build support DEPPATH += --dep-path discrete VPATH += :discrete diff --git a/drivers/discrete/userled_upper.c b/drivers/discrete/userled_upper.c new file mode 100644 index 00000000000..71030ea734a --- /dev/null +++ b/drivers/discrete/userled_upper.c @@ -0,0 +1,599 @@ +/**************************************************************************** + * drivers/button_upper.c + * + * Copyright (C) 2015 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. + * + ****************************************************************************/ + +/* This file provides a driver for a LED input devices. + * + * The LEDs driver exports a standard character driver interface. By + * convention, the LED driver is registered as an input device at + * /dev/btnN where N uniquely identifies the driver instance. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_VERBOSE +# undef CONFIG_DEBUG_DISCRETE +#endif + +#ifdef CONFIG_DEBUG_DISCRETE +# define ddbg lldbg +# ifdef CONFIG_DEBUG_VERBOSE +# define dvdbg lldbg +# else +# define dvdbg(x...) +# endif +#else +# define ddbg(x...) +# define dvdbg(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the state of one LED driver */ + +struct userled_upperhalf_s +{ + /* Saved binding to the lower half LED driver */ + + FAR const struct userled_lowerhalf_s *lu_lower; + + userled_set_t lu_supported; /* The set of supported LEDs */ + userled_set_t lu_ledset; /* Current state of LEDs */ + sem_t lu_exclsem; /* Supports exclusive access to the device */ + + /* The following is a singly linked list of open references to the + * LED device. + */ + + FAR struct userled_open_s *lu_open; +}; + +/* This structure describes the state of one open LED driver instance */ + +struct userled_open_s +{ + /* Supports a singly linked list */ + + FAR struct userled_open_s *bo_flink; + + /* The following will be true if we are closing */ + + volatile bool bo_closing; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Semaphore helpers */ + +static inline int userled_takesem(sem_t *sem); +#define userled_givesem(s) sem_post(s); + +/* Character driver methods */ + +static int userled_open(FAR struct file *filep); +static int userled_close(FAR struct file *filep); +static ssize_t userled_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int userled_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations userled_fops = +{ + userled_open, /* open */ + userled_close, /* close */ + 0, /* read */ + userled_write, /* write */ + 0, /* seek */ + userled_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , 0 /* poll */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: userled_takesem + ****************************************************************************/ + +static inline int userled_takesem(sem_t *sem) +{ + /* Take a count from the semaphore, possibly waiting */ + + if (sem_wait(sem) < 0) + { + /* EINTR is the only error that we expect */ + + int errcode = get_errno(); + DEBUGASSERT(errcode == EINTR); + return -errcode; + } + + return OK; +} + +/**************************************************************************** + * Name: userled_open + ****************************************************************************/ + +static int userled_open(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct userled_upperhalf_s *priv; + FAR struct userled_open_s *opriv; + int ret; + + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct userled_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = userled_takesem(&priv->lu_exclsem); + if (ret < 0) + { + dvdbg("ERROR: userled_takesem failed: %d\n", ret); + return ret; + } + + /* Allocate a new open structure */ + + opriv = (FAR struct userled_open_s *)kmm_zalloc(sizeof(struct userled_open_s)); + if (!opriv) + { + dvdbg("ERROR: Failled to allocate open structure\n"); + ret = -ENOMEM; + goto errout_with_sem; + } + + /* Attach the open structure to the device */ + + opriv->bo_flink = priv->lu_open; + priv->lu_open = opriv; + + /* Attach the open structure to the file structure */ + + filep->f_priv = (FAR void *)opriv; + ret = OK; + +errout_with_sem: + userled_givesem(&priv->lu_exclsem); + return ret; +} + +/**************************************************************************** + * Name: userled_close + ****************************************************************************/ + +static int userled_close(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct userled_upperhalf_s *priv; + FAR struct userled_open_s *opriv; + FAR struct userled_open_s *curr; + FAR struct userled_open_s *prev; + irqstate_t flags; + bool closing; + int ret; + + DEBUGASSERT(filep && filep->f_priv && filep->f_inode); + opriv = filep->f_priv; + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct userled_upperhalf_s *)inode->i_private; + + /* Handle an improbable race conditions with the following atomic test + * and set. + * + * This is actually a pretty feeble attempt to handle this. The + * improbable race condition occurs if two different threads try to + * close the LED driver at the same time. The rule: don't do + * that! It is feeble because we do not really enforce stale pointer + * detection anyway. + */ + + flags = irqsave(); + closing = opriv->bo_closing; + opriv->bo_closing = true; + irqrestore(flags); + + if (closing) + { + /* Another thread is doing the close */ + + return OK; + } + + /* Get exclusive access to the driver structure */ + + ret = userled_takesem(&priv->lu_exclsem); + if (ret < 0) + { + dvdbg("ERROR: userled_takesem failed: %d\n", ret); + return ret; + } + + /* Find the open structure in the list of open structures for the device */ + + for (prev = NULL, curr = priv->lu_open; + curr && curr != opriv; + prev = curr, curr = curr->bo_flink); + + DEBUGASSERT(curr); + if (!curr) + { + dvdbg("ERROR: Failed to find open entry\n"); + ret = -ENOENT; + goto errout_with_exclsem; + } + + /* Remove the structure from the device */ + + if (prev) + { + prev->bo_flink = opriv->bo_flink; + } + else + { + priv->lu_open = opriv->bo_flink; + } + + /* And free the open structure */ + + kmm_free(opriv); + ret = OK; + +errout_with_exclsem: + userled_givesem(&priv->lu_exclsem); + return ret; +} + +/**************************************************************************** + * Name: userled_write + ****************************************************************************/ + +static ssize_t userled_write(FAR struct file *filep, FAR const char *buffer, + size_t len) +{ + FAR struct inode *inode; + FAR struct userled_upperhalf_s *priv; + FAR const struct userled_lowerhalf_s *lower; + userled_set_t ledset; + int ret; + + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct userled_upperhalf_s *)inode->i_private; + + /* Make sure that the buffer is sufficiently large to hold at least one + * complete sample. + * + * REVISIT: Should also check buffer alignment. + */ + + if (len < sizeof(userled_set_t)) + { + dvdbg("ERROR: buffer too small: %lu\n", (unsigned long)len); + return -EINVAL; + } + + /* Get the LED set to write. + * REVISIT: if sizeof(userled_set_t) > 1, then we will have to address + * some buffer alignment issues. + */ + + DEBUGASSERT(buffer != NULL); + ledset = *(userled_set_t *)buffer; + + /* Get exclusive access to the driver structure */ + + ret = userled_takesem(&priv->lu_exclsem); + if (ret < 0) + { + dvdbg("ERROR: userled_takesem failed: %d\n", ret); + return ret; + } + + /* Read and return the current state of the LEDs */ + + lower = priv->lu_lower; + DEBUGASSERT(lower && lower->ll_ledset); + lower->ll_ledset(lower, ledset); + + userled_givesem(&priv->lu_exclsem); + return (ssize_t)sizeof(userled_set_t); +} + +/**************************************************************************** + * Name: userled_ioctl + ****************************************************************************/ + +static int userled_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode; + FAR struct userled_upperhalf_s *priv; + FAR const struct userled_lowerhalf_s *lower; + int ret; + + DEBUGASSERT(filep != NULL && filep->f_priv != NULL && filep->f_inode != NULL); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct userled_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = userled_takesem(&priv->lu_exclsem); + if (ret < 0) + { + dvdbg("ERROR: userled_takesem failed: %d\n", ret); + return ret; + } + + /* Handle the ioctl command */ + + ret = -EINVAL; + switch (cmd) + { + /* Command: ULEDIOC_SUPPORTED + * Description: Report the set of LEDs supported by the hardware; + * Argument: A pointer to writeable userled_set_t value in which to + * return the set of supported LEDs. + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + + case ULEDIOC_SUPPORTED: + { + FAR userled_set_t *supported = (FAR userled_set_t *)((uintptr_t)arg); + + /* Verify that a non-NULL pointer was provided */ + + if (supported) + { + *supported = priv->lu_supported; + ret = OK; + } + } + break; + + /* Command: ULEDIOC_SETLED + * Description: Set the state of one LED. + * Argument: A read-only pointer to an instance of struct userled_s + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + + case ULEDIOC_SETLED: + { + FAR struct userled_s *userled = (FAR struct userled_s *)((uintptr_t)arg); + int led; + bool ledon; + + /* Verify that a non-NULL pointer was provided */ + + if (userled) + { + led = userled->ul_led; + ledon = userled->ul_on; + + /* Check that a valid LED is being set */ + + if (led < 8 * sizeof(userled_set_t) && + (priv->lu_supported & (1 << led)) != 0) + { + /* Update the LED state */ + + if (ledon) + { + priv->lu_ledset |= (1 << led); + } + else + { + priv->lu_ledset &= ~(1 << led); + } + + /* Set the LED state */ + + lower = priv->lu_lower; + DEBUGASSERT(lower != NULL && lower->ll_led != NULL); + lower->ll_led(lower, led, ledon); + ret = OK; + } + } + } + break; + + /* Command: ULEDIOC_SETALL + * Description: Set the state of all LEDs. + * Argument: A value of type userled_set_t cast to unsigned long + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + + case ULEDIOC_SETALL: + { + userled_set_t ledset = (userled_set_t)((uintptr_t)arg); + + /* Verify that a valid LED set was provided */ + + if ((ledset & priv->lu_supported) == ledset) + { + /* Update the LED state */ + + priv->lu_ledset = ledset; + + /* Set the new LED state */ + + lower = priv->lu_lower; + DEBUGASSERT(lower != NULL && lower->ll_led != NULL); + lower->ll_ledset(lower, ledset); + ret = OK; + } + } + break; + + /* Command: ULEDIOC_GETALL + * Description: Get the state of one LED. + * Argument: A write-able pointer to a userled_set_t memory location in + * which to return the LED state. + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + + case ULEDIOC_GETALL: + { + FAR userled_set_t *ledset = (FAR userled_set_t *)((uintptr_t)arg); + + /* Verify that a non-NULL pointer was provided */ + + if (ledset) + { + *ledset = priv->lu_ledset; + ret = OK; + } + } + break; + + default: + dvdbg("ERROR: Unrecognized command: %ld\n", cmd); + ret = -ENOTTY; + break; + } + + userled_givesem(&priv->lu_exclsem); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: userled_register + * + * Description: + * Bind the lower half LED driver to an instance of the upper half + * LED driver and register the composite character driver as the + * specified device. + * + * Input Parameters: + * devname - The name of the LED device to be registered. + * This should be a string of the form "/dev/ledN" where N is the the + * minor device number. + * lower - An instance of the platform-specific LED lower half driver. + * + * Returned Values: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int userled_register(FAR const char *devname, + FAR const struct userled_lowerhalf_s *lower) +{ + FAR struct userled_upperhalf_s *priv; + int ret; + + DEBUGASSERT(devname && lower); + + /* Allocate a new LED driver instance */ + + priv = (FAR struct userled_upperhalf_s *) + kmm_zalloc(sizeof(struct userled_upperhalf_s)); + + if (!priv) + { + dvdbg("ERROR: Failed to allocate device structure\n"); + return -ENOMEM; + } + + /* Initialize the new LED driver instance */ + + priv->lu_lower = lower; + sem_init(&priv->lu_exclsem, 0, 1); + + DEBUGASSERT(lower && lower->ll_supported); + priv->lu_supported = lower->ll_supported(lower); + + DEBUGASSERT(lower && lower->ll_ledset); + priv->lu_ledset = 0; + lower->ll_ledset(lower, priv->lu_ledset); + + /* And register the LED driver */ + + ret = register_driver(devname, &userled_fops, 0666, priv); + if (ret < 0) + { + dvdbg("ERROR: register_driver failed: %d\n", ret); + goto errout_with_priv; + } + + return OK; + +errout_with_priv: + sem_destroy(&priv->lu_exclsem); + kmm_free(priv); + return ret; +} diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index e132870fb90..ebf00232ee4 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -354,7 +354,7 @@ config BUTTONS_LOWER will undefine __KERNEL__ before included board.h. If your board does not meet these requirements, then the - board_lower.c file can still be copied to your your + button_lower.c file can still be copied to your your board src/ directory and modified for your specific board requirements. diff --git a/include/nuttx/board.h b/include/nuttx/board.h index ab0511dff19..c603f40441a 100644 --- a/include/nuttx/board.h +++ b/include/nuttx/board.h @@ -101,6 +101,7 @@ #include #include +#include #include diff --git a/include/nuttx/discrete/userled.h b/include/nuttx/discrete/userled.h new file mode 100644 index 00000000000..7d80e1c5a6b --- /dev/null +++ b/include/nuttx/discrete/userled.h @@ -0,0 +1,185 @@ +/************************************************************************************ + * include/nuttx/input/userled.h + * + * Copyright (C) 2015 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. + * + ************************************************************************************/ + +#ifndef __INCLUDE_NUTTX_DISCRETE_USERLED_H +#define __INCLUDE_NUTTX_DISCRETE_USERLED_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* ioctl commands */ + +/* Command: ULEDIOC_SUPPORTED + * Description: Report the set of LEDs supported by the hardware; + * Argument: A pointer to writeable userled_set_t value in which to + * return the set of supported LEDs. + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + +#define ULEDIOC_SUPPORTED _ULEDIOC(0x0001) + +/* Command: ULEDIOC_SETLED + * Description: Set the state of one LED. + * Argument: A read-only pointer to an instance of struct userled_s + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + +#define ULEDIOC_SETLED _ULEDIOC(0x0002) + +/* Command: ULEDIOC_SETALL + * Description: Set the state of all LEDs. + * Argument: A value of type userled_set_t cast to unsigned long + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + +#define ULEDIOC_SETALL _ULEDIOC(0x0003) + +/* Command: ULEDIOC_GETALL + * Description: Get the state of one LED. + * Argument: A write-able pointer to a userled_set_t memory location in + * which to return the LED state. + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + +#define ULEDIOC_GETALL _ULEDIOC(0x0004) + +/**************************************************************************** + * Public Types + ****************************************************************************/ +/* This type is a bit set that contains the state of all LEDs as defined + * in arch/board/board.h. This is the value that is returned when reading + * from or writing to the LED driver. + */ + +typedef uint8_t userled_set_t; + +/* A reference to this structure is provided with the ULEDIOC_SETLED IOCTL + * command and describes the LED to be set and the new value of the LED. + * The encoding of LEDs is provided in the board-specific board.h header + * file. + */ + +struct userled_s +{ + uint8_t ul_led; /* Identifies the LED */ + bool ul_on; /* The LED state. true: ON; false: OFF */ +}; + +/* The user LED driver is a two-part driver: + * + * 1) A common upper half driver that provides the common user interface to + * the LEDs, + * 2) Platform-specific lower half drivers that provide the interface + * between the common upper half and the platform discrete LED outputs. + * + * This structure defines the interface between an instance of the lower + * half driver and the common upper half driver. Such an instance is + * passed to the upper half driver when the driver is initialized, binding + * the upper and lower halves into one driver. + */ + +struct userled_lowerhalf_s +{ + /* Return the set of LEDs supported by the board */ + + CODE userled_set_t (*ll_supported)(FAR const struct userled_lowerhalf_s *lower); + + /* Set the current state of one LED */ + + CODE void (*ll_led)(FAR const struct userled_lowerhalf_s *lower, + int led, bool ledon); + + /* Set the state of all LEDs */ + + CODE void (*ll_ledset)(FAR const struct userled_lowerhalf_s *lower, + userled_set_t ledset); +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: userled_register + * + * Description: + * Bind the lower half LED driver to an instance of the upper half + * LED driver and register the composite character driver as the + * specified device. + * + * Input Parameters: + * devname - The name of the LED device to be registered. + * This should be a string of the form "/dev/ledN" where N is the the + * minor device number. + * lower - An instance of the platform-specific LED lower half driver. + * + * Returned Values: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int userled_register(FAR const char *devname, + FAR const struct userled_lowerhalf_s *lower); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_DISCRETE_USERLED_H */ diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index 6814787005f..2e0d7a1aaee 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -78,8 +78,12 @@ #define _RELAYBASE (0x1900) /* Relay devices ioctl commands */ #define _CANBASE (0x1a00) /* CAN ioctl commands */ #define _BTNBASE (0x1b00) /* Button ioctl commands */ -#define _ZCBASE (0x1c00) /* Zero Cross ioctl commands */ -#define _BOARDBASE (0x1d00) /* boardctl ioctl commands */ +#define _ULEDBASE (0x1c00) /* User LED ioctl commands */ +#define _ZCBASE (0x1d00) /* Zero Cross ioctl commands */ + +/* boardctl commands share the same number space */ + +#define _BOARDBASE (0xff00) /* boardctl commands */ /* Macros used to manage ioctl commands */ @@ -339,11 +343,17 @@ #define _CANIOC(nr) _IOC(_CANBASE,nr) /* Button driver ioctl definitions ******************************************/ -/* (see nuttx/can.h */ +/* (see nuttx/input/buttons.h */ #define _BTNIOCVALID(c) (_IOC_TYPE(c)==_BTNBASE) #define _BTNIOC(nr) _IOC(_BTNBASE,nr) +/* User LED driver ioctl definitions ****************************************/ +/* (see nuttx/discrete/userled.h */ + +#define _ULEDIOCVALID(c) (_IOC_TYPE(c)==_ULEDBASE) +#define _ULEDIOC(nr) _IOC(_ULEDBASE,nr) + /* Zero Cross driver ioctl definitions **************************************/ /* (see nuttx/include/sensor/zerocross.h */