diff --git a/ChangeLog b/ChangeLog index 887081c9b4..374e99b091 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11021,3 +11021,6 @@ (2015-10-9). * fs/tmpfs: TMPFS file system is code complete and bascially functional although it has not been heavilay tested (2015-10-9). + * drivers/input/buttons/c and include/nuttx/input/buttons.h: Add a + driver to support application access to board buttons (2015-10-12). + diff --git a/arch b/arch index 8a9c89d35a..9f6b9305b1 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 8a9c89d35a4babc8f45687e5293e01e56126ed8c +Subproject commit 9f6b9305b14423c28abeb6261b8ba7095073f316 diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index cd2a096a81..480403a534 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -322,6 +322,22 @@ config STMPE811_REGDEBUG endif # INPUT_STMPE811 +config BUTTONS + bool "Button Inputs" + default n + depends on ARCH_BUTTONS + ---help--- + Enable standard button upper half driver. + +if BUTTONS + +config BUTTONS_NPOLLWAITERS + int "Max Number of Poll Waiters" + default 2 + depends on !DISABLE_POLL + +endif # BUTTONS + config DJOYSTICK bool "Discrete Joystick" default n diff --git a/drivers/input/Make.defs b/drivers/input/Make.defs index dc01bda886..899f6cdacb 100644 --- a/drivers/input/Make.defs +++ b/drivers/input/Make.defs @@ -71,6 +71,10 @@ ifneq ($(CONFIG_INPUT_STMPE811_TEMP_DISABLE),y) endif endif +ifeq ($(CONFIG_BUTTONS),y) + CSRCS += buttons.c +endif + ifeq ($(CONFIG_DJOYSTICK),y) CSRCS += djoystick.c endif diff --git a/drivers/input/ajoystick.c b/drivers/input/ajoystick.c index 0e00b907ed..ea1fc7848c 100644 --- a/drivers/input/ajoystick.c +++ b/drivers/input/ajoystick.c @@ -67,11 +67,11 @@ * Private Types ****************************************************************************/ -/* This structure provides the state of one discrete joystick driver */ +/* This structure provides the state of one analog joystick driver */ struct ajoy_upperhalf_s { - /* Saved binding to the lower half discrete joystick driver */ + /* Saved binding to the lower half analog joystick driver */ FAR const struct ajoy_lowerhalf_s *au_lower; @@ -823,15 +823,15 @@ errout_with_dusem: * Name: ajoy_register * * Description: - * Bind the lower half discrete joystick driver to an instance of the - * upper half discrete joystick driver and register the composite character + * Bind the lower half analog joystick driver to an instance of the + * upper half analog joystick driver and register the composite character * driver as the specific device. * * Input Parameters: - * devname - The name of the discrete joystick device to be registers. + * devname - The name of the analog joystick device to be registers. * This should be a string of the form "/priv/ajoyN" where N is the the * minor device number. - * lower - An instance of the platform-specific discrete joystick lower + * lower - An instance of the platform-specific analog joystick lower * half driver. * * Returned Values: diff --git a/drivers/input/buttons.c b/drivers/input/buttons.c new file mode 100644 index 0000000000..b9b49e24cf --- /dev/null +++ b/drivers/input/buttons.c @@ -0,0 +1,882 @@ +/**************************************************************************** + * drivers/buttons.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 button input devices. + * + * The buttons driver exports a standard character driver interface. By + * convention, the button 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 +#include + +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the state of one button driver */ + +struct btn_upperhalf_s +{ + /* Saved binding to the lower half button driver */ + + FAR const struct btn_lowerhalf_s *bu_lower; + + btn_buttonset_t bu_enabled; /* Set of currently enabled button interrupts */ + btn_buttonset_t bu_sample; /* Last sampled button states */ + sem_t bu_exclsem; /* Supports exclusive access to the device */ + + /* The following is a singly linked list of open references to the + * button device. + */ + + FAR struct btn_open_s *bu_open; +}; + +/* This structure describes the state of one open button driver instance */ + +struct btn_open_s +{ + /* Supports a singly linked list */ + + FAR struct btn_open_s *bo_flink; + + /* The following will be true if we are closing */ + + volatile bool bo_closing; + +#ifndef CONFIG_DISABLE_SIGNALS + /* Button event notification information */ + + pid_t bo_pid; + struct btn_notify_s bo_notify; +#endif + +#ifndef CONFIG_DISABLE_POLL + /* Poll event information */ + + struct btn_pollevents_s bo_pollevents; + + /* The following is a list if poll structures of threads waiting for + * driver events. + */ + + FAR struct pollfd *bo_fds[CONFIG_BUTTONS_NPOLLWAITERS]; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Semaphore helpers */ + +static inline int btn_takesem(sem_t *sem); +#define btn_givesem(s) sem_post(s); + +/* Sampling and Interrupt handling */ + +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) +static void btn_enable(FAR struct btn_upperhalf_s *priv); +static void btn_interrupt(FAR const struct btn_lowerhalf_s *lower, + FAR void *arg); +#endif + +/* Sampling */ + +static void btn_sample(FAR struct btn_upperhalf_s *priv); + +/* Character driver methods */ + +static int btn_open(FAR struct file *filep); +static int btn_close(FAR struct file *filep); +static ssize_t btn_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int btn_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); +#ifndef CONFIG_DISABLE_POLL +static int btn_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations btn_fops = +{ + btn_open, /* open */ + btn_close, /* close */ + btn_read, /* read */ + 0, /* write */ + 0, /* seek */ + btn_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , btn_poll /* poll */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: btn_takesem + ****************************************************************************/ + +static inline int btn_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: btn_enable + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) +static void btn_enable(FAR struct btn_upperhalf_s *priv) +{ + FAR const struct btn_lowerhalf_s *lower = priv->bu_lower; + FAR struct btn_open_s *opriv; + btn_buttonset_t press; + btn_buttonset_t release; + irqstate_t flags; +#ifndef CONFIG_DISABLE_POLL + int i; +#endif + + DEBUGASSERT(priv && priv->bu_lower); + lower = priv->bu_lower; + + /* This routine is called both task level and interrupt level, so + * interrupts must be disabled. + */ + + flags = irqsave(); + + /* Visit each opened reference to the device */ + + press = 0; + release = 0; + + for (opriv = priv->bu_open; opriv; opriv = opriv->bo_flink) + { +#ifndef CONFIG_DISABLE_POLL + /* Are there any poll waiters? */ + + for (i = 0; i < CONFIG_BUTTONS_NPOLLWAITERS; i++) + { + if (opriv->bo_fds[i]) + { + /* Yes.. OR in the poll event buttons */ + + press |= opriv->bo_pollevents.ap_press; + release |= opriv->bo_pollevents.ap_release; + break; + } + } +#endif + +#ifndef CONFIG_DISABLE_SIGNALS + /* OR in the signal events */ + + press |= opriv->bo_notify.bn_press; + release |= opriv->bo_notify.bn_release; +#endif + } + + /* Enable/disable button interrupts */ + + DEBUGASSERT(lower->bl_enable); + if (press != 0 || release != 0) + { + /* Enable interrupts with the new button set */ + + lower->bl_enable(lower, press, release, + (btn_handler_t)btn_interrupt, priv); + } + else + { + /* Disable further interrupts */ + + lower->bl_enable(lower, 0, 0, NULL, NULL); + } + + irqrestore(flags); +} +#endif + +/**************************************************************************** + * Name: btn_interrupt + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) +static void btn_interrupt(FAR const struct btn_lowerhalf_s *lower, + FAR void *arg) +{ + FAR struct btn_upperhalf_s *priv = (FAR struct btn_upperhalf_s *)arg; + + DEBUGASSERT(priv); + + /* Process the next sample */ + + btn_sample(priv); +} +#endif + +/**************************************************************************** + * Name: btn_sample + ****************************************************************************/ + +static void btn_sample(FAR struct btn_upperhalf_s *priv) +{ + FAR const struct btn_lowerhalf_s *lower = priv->bu_lower; + FAR struct btn_open_s *opriv; + btn_buttonset_t sample; +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) + btn_buttonset_t change; + btn_buttonset_t press; + btn_buttonset_t release; +#endif + irqstate_t flags; +#ifndef CONFIG_DISABLE_POLL + int i; +#endif + + DEBUGASSERT(priv && priv->bu_lower); + lower = priv->bu_lower; + + /* This routine is called both task level and interrupt level, so + * interrupts must be disabled. + */ + + flags = irqsave(); + + /* Sample the new button state */ + + DEBUGASSERT(lower->bl_buttons); + sample = lower->bl_buttons(lower); + +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) + /* Determine which buttons have been newly pressed and which have been + * newly released. + */ + + change = sample ^ priv->bu_sample; + press = change & sample; + + DEBUGASSERT(lower->bl_supported); + release = change & (lower->bl_supported(lower) & ~sample); + + /* Visit each opened reference to the device */ + + for (opriv = priv->bu_open; opriv; opriv = opriv->bo_flink) + { +#ifndef CONFIG_DISABLE_POLL + /* Have any poll events occurred? */ + + if ((press & opriv->bo_pollevents.ap_press) != 0 || + (release & opriv->bo_pollevents.ap_release) != 0) + { + /* Yes.. Notify all waiters */ + + for (i = 0; i < CONFIG_BUTTONS_NPOLLWAITERS; i++) + { + FAR struct pollfd *fds = opriv->bo_fds[i]; + if (fds) + { + fds->revents |= (fds->events & POLLIN); + if (fds->revents != 0) + { + ivdbg("Report events: %02x\n", fds->revents); + sem_post(fds->sem); + } + } + } + } +#endif + +#ifndef CONFIG_DISABLE_SIGNALS + /* Have any signal events occurred? */ + + if ((press & opriv->bo_notify.bn_press) != 0 || + (release & opriv->bo_notify.bn_release) != 0) + { + /* Yes.. Signal the waiter */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + union sigval value; + value.sival_int = (int)sample; + (void)sigqueue(opriv->bo_pid, opriv->bo_notify.bn_signo, value); +#else + (void)sigqueue(opriv->bo_pid, opriv->bo_notify.dn.signo, + (FAR void *)sample); +#endif + } +#endif + } + + /* Enable/disable interrupt handling */ + + btn_enable(priv); +#endif + + priv->bu_sample = sample; + irqrestore(flags); +} + +/**************************************************************************** + * Name: btn_open + ****************************************************************************/ + +static int btn_open(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct btn_upperhalf_s *priv; + FAR struct btn_open_s *opriv; +#ifndef CONFIG_DISABLE_POLL + FAR const struct btn_lowerhalf_s *lower; + btn_buttonset_t supported; +#endif + int ret; + + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct btn_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = btn_takesem(&priv->bu_exclsem); + if (ret < 0) + { + ivdbg("ERROR: btn_takesem failed: %d\n", ret); + return ret; + } + + /* Allocate a new open structure */ + + opriv = (FAR struct btn_open_s *)kmm_zalloc(sizeof(struct btn_open_s)); + if (!opriv) + { + ivdbg("ERROR: Failled to allocate open structure\n"); + ret = -ENOMEM; + goto errout_with_sem; + } + + /* Initialize the open structure */ + +#ifndef CONFIG_DISABLE_POLL + lower = priv->bu_lower; + DEBUGASSERT(lower && lower->bl_supported); + supported = lower->bl_supported(lower); + + opriv->bo_pollevents.ap_press = supported; + opriv->bo_pollevents.ap_release = supported; +#endif + + /* Attach the open structure to the device */ + + opriv->bo_flink = priv->bu_open; + priv->bu_open = opriv; + + /* Attach the open structure to the file structure */ + + filep->f_priv = (FAR void *)opriv; + ret = OK; + +errout_with_sem: + btn_givesem(&priv->bu_exclsem); + return ret; +} + +/**************************************************************************** + * Name: btn_close + ****************************************************************************/ + +static int btn_close(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct btn_upperhalf_s *priv; + FAR struct btn_open_s *opriv; + FAR struct btn_open_s *curr; + FAR struct btn_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 btn_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 button 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 = btn_takesem(&priv->bu_exclsem); + if (ret < 0) + { + ivdbg("ERROR: btn_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->bu_open; + curr && curr != opriv; + prev = curr, curr = curr->bo_flink); + + DEBUGASSERT(curr); + if (!curr) + { + ivdbg("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->bu_open = opriv->bo_flink; + } + + /* And free the open structure */ + + kmm_free(opriv); + + /* Enable/disable interrupt handling */ + + btn_enable(priv); + ret = OK; + +errout_with_exclsem: + btn_givesem(&priv->bu_exclsem); + return ret; +} + +/**************************************************************************** + * Name: btn_read + ****************************************************************************/ + +static ssize_t btn_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct inode *inode; + FAR struct btn_upperhalf_s *priv; + FAR const struct btn_lowerhalf_s *lower; + int ret; + + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct btn_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(btn_buttonset_t)) + { + ivdbg("ERROR: buffer too small: %lu\n", (unsigned long)len); + return -EINVAL; + } + + /* Get exclusive access to the driver structure */ + + ret = btn_takesem(&priv->bu_exclsem); + if (ret < 0) + { + ivdbg("ERROR: btn_takesem failed: %d\n", ret); + return ret; + } + + /* Read and return the current state of the buttons */ + + lower = priv->bu_lower; + DEBUGASSERT(lower && lower->bl_buttons); + *(FAR btn_buttonset_t *)buffer = lower->bl_buttons(lower); + + btn_givesem(&priv->bu_exclsem); + return (ssize_t)sizeof(btn_buttonset_t); +} + +/**************************************************************************** + * Name: btn_ioctl + ****************************************************************************/ + +static int btn_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode; + FAR struct btn_upperhalf_s *priv; + FAR struct btn_open_s *opriv; + FAR const struct btn_lowerhalf_s *lower; + 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 btn_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = btn_takesem(&priv->bu_exclsem); + if (ret < 0) + { + ivdbg("ERROR: btn_takesem failed: %d\n", ret); + return ret; + } + + /* Handle the ioctl command */ + + ret = -EINVAL; + switch (cmd) + { + /* Command: BTNIOC_SUPPORTED + * Description: Report the set of button events supported by the hardware; + * Argument: A pointer to writeable integer value in which to return the + * set of supported buttons. + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + + case BTNIOC_SUPPORTED: + { + FAR btn_buttonset_t *supported = (FAR btn_buttonset_t *)((uintptr_t)arg); + + if (supported) + { + lower = priv->bu_lower; + DEBUGASSERT(lower && lower->bl_supported); + + *supported = lower->bl_supported(lower); + ret = OK; + } + } + break; + +#ifndef CONFIG_DISABLE_POLL + /* Command: BTNIOC_POLLEVENTS + * Description: Specify the set of button events that can cause a poll() + * to awaken. The default is all button depressions and + * all button releases (all supported buttons); + * Argument: A read-only pointer to an instance of struct + * btn_pollevents_s + * Return: Zero (OK) on success. Minus one will be returned on + * failure with the errno value set appropriately. + */ + + case BTNIOC_POLLEVENTS: + { + FAR struct btn_pollevents_s *pollevents = + (FAR struct btn_pollevents_s *)((uintptr_t)arg); + + if (pollevents) + { + /* Save the poll events */ + + opriv->bo_pollevents.ap_press = pollevents->ap_press; + opriv->bo_pollevents.ap_release = pollevents->ap_release; + + /* Enable/disable interrupt handling */ + + btn_enable(priv); + ret = OK; + } + } + break; +#endif + +#ifndef CONFIG_DISABLE_SIGNALS + /* Command: BTNIOC_REGISTER + * Description: Register to receive a signal whenever there is a change + * in any of the discrete buttone inputs. This feature, + * of course, depends upon interrupt GPIO support from the + * platform. + * Argument: A read-only pointer to an instance of struct + * btn_notify_s + * Return: Zero (OK) on success. Minus one will be returned on + * failure with the errno value set appropriately. + */ + + case BTNIOC_REGISTER: + { + FAR struct btn_notify_s *notify = + (FAR struct btn_notify_s *)((uintptr_t)arg); + + if (notify) + { + /* Save the notification events */ + + opriv->bo_notify.bn_press = notify->bn_press; + opriv->bo_notify.bn_release = notify->bn_release; + opriv->bo_notify.bn_signo = notify->bn_signo; + opriv->bo_pid = getpid(); + + /* Enable/disable interrupt handling */ + + btn_enable(priv); + ret = OK; + } + } + break; +#endif + + default: + ivdbg("ERROR: Unrecognized command: %ld\n", cmd); + ret = -ENOTTY; + break; + } + + btn_givesem(&priv->bu_exclsem); + return ret; +} + +/**************************************************************************** + * Name: btn_poll + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int btn_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup) +{ + FAR struct inode *inode; + FAR struct btn_upperhalf_s *priv; + FAR struct btn_open_s *opriv; + int ret; + int i; + + DEBUGASSERT(filep && filep->f_priv && filep->f_inode); + opriv = filep->f_priv; + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct btn_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = btn_takesem(&priv->bu_exclsem); + if (ret < 0) + { + ivdbg("ERROR: btn_takesem failed: %d\n", ret); + return ret; + } + + /* Are we setting up the poll? Or tearing it down? */ + + 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_BUTTONS_NPOLLWAITERS; i++) + { + /* Find an available slot */ + + if (!opriv->bo_fds[i]) + { + /* Bind the poll structure and this slot */ + + opriv->bo_fds[i] = fds; + fds->priv = &opriv->bo_fds[i]; + break; + } + } + + if (i >= CONFIG_BUTTONS_NPOLLWAITERS) + { + ivdbg("ERROR: Too man poll waiters\n"); + fds->priv = NULL; + ret = -EBUSY; + goto errout_with_dusem; + } + } + else if (fds->priv) + { + /* This is a request to tear down the poll. */ + + FAR struct pollfd **slot = (FAR struct pollfd **)fds->priv; + +#ifdef CONFIG_DEBUG + if (!slot) + { + ivdbg("ERROR: Poll slot not found\n"); + ret = -EIO; + goto errout_with_dusem; + } +#endif + + /* Remove all memory of the poll setup */ + + *slot = NULL; + fds->priv = NULL; + } + +errout_with_dusem: + btn_givesem(&priv->bu_exclsem); + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: btn_register + * + * Description: + * Bind the lower half button driver to an instance of the upper half + * button driver and register the composite character driver as the + * specified device. + * + * Input Parameters: + * devname - The name of the button device to be registered. + * This should be a string of the form "/dev/btnN" where N is the the + * minor device number. + * lower - An instance of the platform-specific button 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 btn_register(FAR const char *devname, + FAR const struct btn_lowerhalf_s *lower) + +{ + FAR struct btn_upperhalf_s *priv; + int ret; + + DEBUGASSERT(devname && lower); + + /* Allocate a new button driver instance */ + + priv = (FAR struct btn_upperhalf_s *) + kmm_zalloc(sizeof(struct btn_upperhalf_s)); + + if (!priv) + { + ivdbg("ERROR: Failed to allocate device structure\n"); + return -ENOMEM; + } + + /* Make sure that all button interrupts are disabled */ + + DEBUGASSERT(lower->bl_enable); + lower->bl_enable(lower, 0, 0, NULL, NULL); + + /* Initialize the new button driver instance */ + + priv->bu_lower = lower; + sem_init(&priv->bu_exclsem, 0, 1); + + DEBUGASSERT(lower->bl_buttons); + priv->bu_sample = lower->bl_buttons(lower); + + /* And register the button driver */ + + ret = register_driver(devname, &btn_fops, 0666, priv); + if (ret < 0) + { + ivdbg("ERROR: register_driver failed: %d\n", ret); + goto errout_with_priv; + } + + return OK; + +errout_with_priv: + sem_destroy(&priv->bu_exclsem); + kmm_free(priv); + return ret; +} diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index 827f62e4c5..7a5d17f702 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -77,7 +77,8 @@ #define _RTCBASE (0x1800) /* RTC ioctl commands */ #define _RELAYBASE (0x1900) /* Relay devices ioctl commands */ #define _CANBASE (0x1a00) /* CAN ioctl commands */ -#define _BOARDBASE (0x1b00) /* boardctl ioctl commands */ +#define _BTNBASE (0x1b00) /* Button ioctl commands */ +#define _BOARDBASE (0x1c00) /* boardctl ioctl commands */ /* Macros used to manage ioctl commands */ @@ -336,6 +337,12 @@ #define _CANIOCVALID(c) (_IOC_TYPE(c)==_CANBASE) #define _CANIOC(nr) _IOC(_CANBASE,nr) +/* Button driver ioctl definitions ******************************************/ +/* (see nuttx/can.h */ + +#define _BTNIOCVALID(c) (_IOC_TYPE(c)==_BTNBASE) +#define _BTNIOC(nr) _IOC(_BTNBASE,nr) + /* boardctl() command definitions *******************************************/ #define _BOARDIOCVALID(c) (_IOC_TYPE(c)==_BOARDBASE) diff --git a/include/nuttx/input/ajoystick.h b/include/nuttx/input/ajoystick.h index b2f49c527d..b672ed57ed 100644 --- a/include/nuttx/input/ajoystick.h +++ b/include/nuttx/input/ajoystick.h @@ -275,7 +275,7 @@ extern "C" * driver as the specified device. * * Input Parameters: - * devname - The name of the analog joystick device to be registers. + * devname - The name of the analog joystick device to be registered. * This should be a string of the form "/dev/ajoyN" where N is the the * minor device number. * lower - An instance of the platform-specific analog joystick lower diff --git a/include/nuttx/input/buttons.h b/include/nuttx/input/buttons.h new file mode 100644 index 0000000000..f31a197a1e --- /dev/null +++ b/include/nuttx/input/buttons.h @@ -0,0 +1,185 @@ +/************************************************************************************ + * include/nuttx/input/buttons.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_INPUT_BUTTONS_H +#define __INCLUDE_NUTTX_INPUT_BUTTONS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_BUTTONS_NPOLLWAITERS +# define CONFIG_BUTTONS_NPOLLWAITERS 2 +#endif + +/* ioctl commands */ + +/* Command: BTNIOC_SUPPORTED + * Description: Report the set of button events supported by the hardware; + * Argument: A pointer to writeable btn_buttonset_t value in which to + * return the set of supported buttons. + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + +#define BTNIOC_SUPPORTED _BTNIOC(0x0001) + +/* Command: BTNIOC_REGISTER + * Description: Register to receive a signal whenever there is a change in + * the state of button inputs. This feature, of course, depends + * upon interrupt GPIO support from the platform. + * Argument: A read-only pointer to an instance of struct btn_notify_s + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + +#define BTNIOC_REGISTER _BTNIOC(0x0002) + +/**************************************************************************** + * Public Types + ****************************************************************************/ +/* This type is a bit set that contains the state of all buttons as defined + * in arch/board/board.h. This is the value that is returned when reading + * from the button driver. + */ + +typedef uint8_t btn_buttonset_t; + +/* A reference to this structure is provided with the BTNIOC_REGISTER IOCTL + * command and describes the conditions under which the client would like + * to receive notification. + */ + +struct btn_notify_s +{ + btn_buttonset_t bn_press; /* Set of button depressions to be notified */ + btn_buttonset_t bn_release; /* Set of button releases to be notified */ + uint8_t bn_signo; /* Signal number to use in the notification */ +}; + +/* This is the type of the button interrupt handler used with the struct + * btn_lowerhalf_s enable() method. + */ + +struct btn_lowerhalf_s; +typedef CODE void (*btn_handler_t) + (FAR const struct btn_lowerhalf_s *lower, FAR void *arg); + +/* The button driver is a two-part driver: + * + * 1) A common upper half driver that provides the common user interface to + * the buttons, + * 2) Platform-specific lower half drivers that provide the interface + * between the common upper half and the platform discrete button inputs. + * + * 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 btn_lowerhalf_s +{ + /* Return the set of buttons supported by the board */ + + CODE btn_buttonset_t (*bl_supported)(FAR const struct btn_lowerhalf_s *lower); + + /* Return the current state of button data (only) */ + + CODE btn_buttonset_t (*bl_buttons)(FAR const struct btn_lowerhalf_s *lower); + + /* Enable interrupts on the selected set of buttons. An empty set will + * disable all interrupts. + */ + + CODE void (*bl_enable)(FAR const struct btn_lowerhalf_s *lower, + btn_buttonset_t press, btn_buttonset_t release, + btn_handler_t handler, FAR void *arg); +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: btn_register + * + * Description: + * Bind the lower half button driver to an instance of the upper half + * button driver and register the composite character driver as the + * specified device. + * + * Input Parameters: + * devname - The name of the button device to be registered. + * This should be a string of the form "/dev/btnN" where N is the the + * minor device number. + * lower - An instance of the platform-specific button 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 btn_register(FAR const char *devname, + FAR const struct btn_lowerhalf_s *lower); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_INPUT_BUTTONS_H */ + diff --git a/tools/nxstyle.c b/tools/nxstyle.c index 1eada32187..4fa84eb523 100644 --- a/tools/nxstyle.c +++ b/tools/nxstyle.c @@ -688,6 +688,8 @@ int main(int argc, char **argv, char **envp) else if (line[n+1] == ')') { + /* REVISIT: This gives false alarms on syntax like *--ptr */ + if (line[n-1] != ' ') { fprintf(stderr, @@ -748,6 +750,8 @@ int main(int argc, char **argv, char **envp) n++; } + /* REVISIT: This gives false alarms on syntax like *--ptr */ + if (line[curr] != '-' && line[next] != ' ' && line[next] != '\n') { fprintf(stderr,