diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index fb593026105..1389e7f694b 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -320,4 +320,23 @@ config STMPE811_REGDEBUG ---help--- Enable very low register-level debug output. -endif +endif # INPUT_STMPE811 + +config DJOYSTICK + bool "Discrete Joystick" + default n + ---help--- + Enable standard discrete joystick upper half driver. A discrete + joystick refers to a joystick that could be implemented entirely + with GPIO input pins. So up, down, left, and right are all discrete + values like buttons (as opposed to integer values like you might + obtain from an analog joystick). + +if DJOYSTICK + +config DJOYSTICK_NPOLLWAITERS + int "Max Number of Poll Waiters + default 2 + depends on !DISABLE_POLL + +endif # DJOYSTICK diff --git a/drivers/input/Make.defs b/drivers/input/Make.defs index 2071fcb479a..b13cbf26006 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_DJOYSTICK),y) + CSRCS += djoystick.c +endif + # Include input device driver build support DEPPATH += --dep-path input diff --git a/drivers/input/djoystick.c b/drivers/input/djoystick.c new file mode 100644 index 00000000000..dea01d1602f --- /dev/null +++ b/drivers/input/djoystick.c @@ -0,0 +1,836 @@ +/**************************************************************************** + * drivers/djoystick.c + * + * Copyright (C) 2014 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 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the state of one discrete joystick driver */ + +struct djoy_upperhalf_s +{ + /* Saved binding to the lower half discrete joystick driver */ + + FAR const struct djoy_lowerhalf_s *du_lower; + + djoy_buttonset_t du_enabled; /* Set of currently enabled button interrupts */ + djoy_buttonset_t du_sample; /* Last sampled button states */ + sem_t du_exclsem; /* Supports exclusive access to the device */ + + /* The following is a singly linked list of open references to the + * joystick device. + */ + + FAR struct djoy_open_s *du_open; +}; + +/* This structure describes the state of one open joystick driver instance */ + +struct djoy_open_s +{ + /* Supports a singly linked list */ + + FAR struct djoy_open_s *do_flink; + + /* The following will be true if we are closing */ + + volatile bool do_closing; + +#ifndef CONFIG_DISABLE_SIGNALS + /* Joystick event notification information */ + + pid_t do_pid; + struct djoy_notify_s do_notify; +#endif + +#ifndef CONFIG_DISABLE_POLL + /* Poll event information */ + + struct djoy_pollevents_s do_pollevents; + + /* The following is a list if poll structures of threads waiting for + * driver events. + */ + + FAR struct pollfd *do_fds[CONFIG_DJOYSTICK_NPOLLWAITERS]; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Semaphore helpers */ + +static inline int djoy_takesem(sem_t *sem); +#define djoy_givesem(s) sem_post(s); + +/* Sampling and Interrupt handling */ + +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) +static void djoy_enable(FAR struct djoy_upperhalf_s *priv); +static void djoy_interrupt(FAR const struct djoy_lowerhalf_s *lower, + FAR void *arg); +#endif + +/* Sampling */ + +static void djoy_sample(FAR struct djoy_upperhalf_s *priv); + +/* Character driver methods */ + +static int djoy_open(FAR struct file *filep); +static int djoy_close(FAR struct file *filep); +static ssize_t djoy_read(FAR struct file *, FAR char *, size_t); +static int djoy_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); +#ifndef CONFIG_DISABLE_POLL +static int djoy_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations djoy_fops = +{ + djoy_open, /* open */ + djoy_close, /* close */ + djoy_read, /* read */ + 0, /* write */ + 0, /* seek */ + djoy_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , djoy_poll /* poll */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: djoy_takesem + ****************************************************************************/ + +static inline int djoy_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: djoy_enable + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) +static void djoy_enable(FAR struct djoy_upperhalf_s *priv) +{ + FAR const struct djoy_lowerhalf_s *lower = priv->du_lower; + FAR struct djoy_open_s *opriv; + djoy_buttonset_t intmask; + irqstate_t flags; +#ifndef CONFIG_DISABLE_POLL + int i; +#endif + + DEBUGASSERT(priv && priv->du_lower); + lower = priv->du_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 */ + + intmask = 0; + for (opriv = priv->du_open; opriv; opriv = opriv->do_flink) + { +#ifndef CONFIG_DISABLE_POLL + /* Are there any poll waiters? */ + + for (i = 0; i < CONFIG_DJOYSTICK_NPOLLWAITERS; i++) + { + if (opriv->do_fds[i]) + { + /* Yes.. OR in the poll event buttons */ + + intmask |= (opriv->do_pollevents.dp_press | + opriv->do_pollevents.dp_release); + break; + } + } +#endif + +#ifndef CONFIG_DISABLE_SIGNALS + /* OR in the signal events */ + + intmask |= (opriv->do_notify.dn_press | opriv->do_notify.dn_release); +#endif + } + + /* Enable/disable button interrupts */ + + DEBUGASSERT(lower->dl_enable); + if (intmask != 0) + { + /* Enable interrupts with the new button set */ + + lower->dl_enable(lower, intmask, (djoy_interrupt_t)djoy_interrupt, priv); + } + else + { + /* Disable further interrupts */ + + lower->dl_enable(lower, 0, NULL, NULL); + } + + irqrestore(flags); +} +#endif + +/**************************************************************************** + * Name: djoy_interrupt + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) +static void djoy_interrupt(FAR const struct djoy_lowerhalf_s *lower, + FAR void *arg) +{ + FAR struct djoy_upperhalf_s *priv = (FAR struct djoy_upperhalf_s *)arg; + + DEBUGASSERT(priv); + + /* Process the next sample */ + + djoy_sample(priv); +} +#endif + +/**************************************************************************** + * Name: djoy_sample + ****************************************************************************/ + +static void djoy_sample(FAR struct djoy_upperhalf_s *priv) +{ + FAR const struct djoy_lowerhalf_s *lower = priv->du_lower; + FAR struct djoy_open_s *opriv; + djoy_buttonset_t sample; +#if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) + djoy_buttonset_t change; + djoy_buttonset_t press; + djoy_buttonset_t release; +#endif + irqstate_t flags; +#ifndef CONFIG_DISABLE_POLL + int i; +#endif + + DEBUGASSERT(priv && priv->du_lower); + lower = priv->du_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->dl_sample); + sample = lower->dl_sample(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->du_sample; + press = change & sample; + + DEBUGASSERT(lower->dl_supported); + release = change & (lower->dl_supported(lower) & ~sample); + + /* Visit each opened reference to the device */ + + for (opriv = priv->du_open; opriv; opriv = opriv->do_flink) + { +#ifndef CONFIG_DISABLE_POLL + /* Have any poll events occurred? */ + + if ((press & opriv->do_pollevents.dp_press) != 0 || + (release & opriv->do_pollevents.dp_release) != 0) + { + /* Yes.. Notify all waiters */ + + for (i = 0; i < CONFIG_DJOYSTICK_NPOLLWAITERS; i++) + { + FAR struct pollfd *fds = opriv->do_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->do_notify.dn_press) != 0 || + (release & opriv->do_notify.dn_release) != 0) + { + /* Yes.. Signal the waiter */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + union sigval value; + value.sival_int = (int)sample; + (void)sigqueue(opriv->do_pid, opriv->do_notify.dn_signo, value); +#else + (void)sigqueue(opriv->do_pid, opriv->do_notify.dn.signo, + (FAR void *)sample); +#endif + } +#endif + } + + /* Enable/disable interrupt handling */ + + djoy_enable(priv); +#endif + + priv->du_sample = sample; + irqrestore(flags); +} + +/**************************************************************************** + * Name: djoy_open + ****************************************************************************/ + +static int djoy_open(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct djoy_upperhalf_s *priv; + FAR const struct djoy_lowerhalf_s *lower; + FAR struct djoy_open_s *opriv; +#ifndef CONFIG_DISABLE_POLL + djoy_buttonset_t supported; +#endif + int ret; + + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct djoy_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = djoy_takesem(&priv->du_exclsem); + if (ret < 0) + { + ivdbg("ERROR: djoy_takesem failed: %d\n", ret); + return ret; + } + + /* Allocate a new open structure */ + + opriv = (FAR struct djoy_open_s *)kmm_zalloc(sizeof(struct djoy_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->du_lower; + DEBUGASSERT(lower && lower->dl_supported); + supported = lower->dl_supported(lower); + + opriv->do_pollevents.dp_press = supported; + opriv->do_pollevents.dp_release = supported; +#endif + + /* Attach the open structure to the device */ + + opriv->do_flink = priv->du_open; + priv->du_open = opriv; + + /* Attach the open structure to the file structure */ + + filep->f_priv = (FAR void *)opriv; + ret = OK; + +errout_with_sem: + djoy_givesem(&priv->du_exclsem); + return ret; +} + +/**************************************************************************** + * Name: djoy_close + ****************************************************************************/ + +static int djoy_close(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct djoy_upperhalf_s *priv; + FAR struct djoy_open_s *opriv; + FAR struct djoy_open_s *curr; + FAR struct djoy_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 djoy_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 joystick 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->do_closing; + if (!closing) + { + opriv->do_closing = true; + } + + irqrestore(flags); + if (closing) + { + /* Another thread is doing the close */ + + return OK; + } + + /* Get exclusive access to the driver structure */ + + ret = djoy_takesem(&priv->du_exclsem); + if (ret < 0) + { + ivdbg("ERROR: djoy_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->du_open; + curr && curr != opriv; + prev = curr, curr = curr->do_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->do_flink = opriv->do_flink; + } + else + { + priv->du_open = opriv->do_flink; + } + + /* And free the open structure */ + + kmm_free(opriv); + + /* Enable/disable interrupt handling */ + + djoy_enable(priv); + djoy_givesem(&priv->du_exclsem); + return OK; + +errout_with_exclsem: + djoy_givesem(&priv->du_exclsem); + return ret; +} + +/**************************************************************************** + * Name: djoy_read + ****************************************************************************/ + +static ssize_t djoy_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct inode *inode; + FAR struct djoy_upperhalf_s *priv; + FAR const struct djoy_lowerhalf_s *lower; + int ret; + + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + DEBUGASSERT(inode->i_private); + priv = (FAR struct djoy_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = djoy_takesem(&priv->du_exclsem); + if (ret < 0) + { + ivdbg("ERROR: djoy_takesem failed: %d\n", ret); + return ret; + } + + /* Read and return the current state of the joystick buttons */ + + lower = priv->du_lower; + DEBUGASSERT(lower && lower->dl_sample); + priv->du_sample = lower->dl_sample(lower); + *(djoy_buttonset_t*)buffer = priv->du_sample; + ret = sizeof(djoy_buttonset_t); + + djoy_givesem(&priv->du_exclsem); + return ret; +} + +/**************************************************************************** + * Name: djoy_ioctl + ****************************************************************************/ + +static int djoy_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode; + FAR struct djoy_upperhalf_s *priv; + FAR struct djoy_open_s *opriv; + 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 djoy_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = djoy_takesem(&priv->du_exclsem); + if (ret < 0) + { + ivdbg("ERROR: djoy_takesem failed: %d\n", ret); + return ret; + } + + /* Handle the ioctl command */ + + ret = -EINVAL; + switch (cmd) + { +#ifndef CONFIG_DISABLE_POLL + /* Command: DJOYIOC_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 + * djoy_pollevents_s + * Return: Zero (OK) on success. Minus one will be returned on + * failure with the errno value set appropriately. + */ + + case DJOYIOC_POLLEVENTS: + { + FAR struct djoy_pollevents_s *pollevents = + (FAR struct djoy_pollevents_s *)((uintptr_t)arg); + + if (pollevents) + { + /* Save the poll events */ + + opriv->do_pollevents.dp_press = pollevents->dp_press; + opriv->do_pollevents.dp_release = pollevents->dp_release; + + /* Enable/disable interrupt handling */ + + djoy_enable(priv); + ret = OK; + } + } + break; +#endif + +#ifndef CONFIG_DISABLE_SIGNALS + /* Command: DJOYIOC_REGISTER + * Description: Register to receive a signal whenever there is a change + * in any of the joystick discrete inputs. This feature, + * of course, depends upon interrupt GPIO support from the + * platform. + * Argument: A read-only pointer to an instance of struct + * djoy_notify_s + * Return: Zero (OK) on success. Minus one will be returned on + * failure with the errno value set appropriately. + */ + + case DJOYIOC_REGISTER: + { + FAR struct djoy_notify_s *notify = + (FAR struct djoy_notify_s *)((uintptr_t)arg); + + if (notify) + { + /* Save the notification events */ + + opriv->do_notify.dn_press = notify->dn_press; + opriv->do_notify.dn_release = notify->dn_release; + opriv->do_notify.dn_signo = notify->dn_signo; + opriv->do_pid = getpid(); + + /* Enable/disable interrupt handling */ + + djoy_enable(priv); + ret = OK; + } + } + break; +#endif + + default: + ivdbg("ERROR: Unrecognized command: %ld\n", cmd); + ret = -ENOTTY; + break; + } + + djoy_givesem(&priv->du_exclsem); + return ret; +} + +/**************************************************************************** + * Name: djoy_poll + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int djoy_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup) +{ + FAR struct inode *inode; + FAR struct djoy_upperhalf_s *priv; + FAR struct djoy_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 djoy_upperhalf_s *)inode->i_private; + + /* Get exclusive access to the driver structure */ + + ret = djoy_takesem(&priv->du_exclsem); + if (ret < 0) + { + ivdbg("ERROR: djoy_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_DJOYSTICK_NPOLLWAITERS; i++) + { + /* Find an available slot */ + + if (!opriv->do_fds[i]) + { + /* Bind the poll structure and this slot */ + + opriv->do_fds[i] = fds; + fds->priv = &opriv->do_fds[i]; + break; + } + } + + if (i >= CONFIG_DJOYSTICK_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: + djoy_givesem(&priv->du_exclsem); + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: djoy_register + * + * Description: + * Bind the lower half discrete joystick driver to an instance of the + * upper half discrete 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. + * This should be a string of the form "/priv/djoyN" where N is the the + * minor device number. + * lower - An instance of the platform-specific discrete joystick 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 djoy_register(FAR const char *devname, + FAR const struct djoy_lowerhalf_s *lower) + +{ + FAR struct djoy_upperhalf_s *priv; + int ret; + + DEBUGASSERT(devname && lower); + + /* Allocate a new djoystick driver instance */ + + priv = (FAR struct djoy_upperhalf_s *) + kmm_zalloc(sizeof(struct djoy_upperhalf_s)); + + if (!priv) + { + ivdbg("ERROR: Failed to allocate device structure\n"); + return -ENOMEM; + } + + /* Make sure that all djoystick interrupts are disabled */ + + DEBUGASSERT(lower->dl_enable); + lower->dl_enable(lower, (djoy_buttonset_t)0, NULL, NULL); + + /* Initialize the new djoystick driver instance */ + + priv->du_lower = lower; + sem_init(&priv->du_exclsem, 0, 1); + + DEBUGASSERT(lower->dl_sample); + priv->du_sample = lower->dl_sample(lower); + + /* And register the djoystick driver */ + + ret = register_driver(devname, &djoy_fops, 0666, NULL); + if (ret < 0) + { + ivdbg("ERROR: register_driver failed: %d\n", ret); + sem_destroy(&priv->du_exclsem); + kmm_free(priv); + } + + return ret; +} diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 3cc77987427..9d82178b58b 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -1123,10 +1123,10 @@ static int uart_close(FAR struct file *filep) static int uart_open(FAR struct file *filep) { - struct inode *inode = filep->f_inode; - uart_dev_t *dev = inode->i_private; - uint8_t tmp; - int ret; + FAR struct inode *inode = filep->f_inode; + FAR uart_dev_t *dev = inode->i_private; + uint8_t tmp; + int ret; /* If the port is the middle of closing, wait until the close is finished. * If a signal is received while we are waiting, then return EINTR. diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index 5b74687f29b..3a2111ebd92 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -71,6 +71,7 @@ #define _WLIOCBASE (0x1200) /* Wireless modules ioctl commands */ #define _CFGDIOCBASE (0x1300) /* Config Data device (app config) ioctl commands */ #define _TCIOCBASE (0x1400) /* Timer ioctl commands */ +#define _DJOYBASE (0x1500) /* Discrete joystick ioctl commands */ /* Macros used to manage ioctl commands */ @@ -94,11 +95,6 @@ #define _WDIOCVALID(c) (_IOC_TYPE(c)==_WDIOCBASE) #define _WDIOC(nr) _IOC(_WDIOCBASE,nr) -/* Timer driver ioctl commands *******************************************/ - -#define _TCIOCVALID(c) (_IOC_TYPE(c)==_TCIOCBASE) -#define _TCIOC(nr) _IOC(_TCIOCBASE,nr) - /* NuttX file system ioctl definitions **************************************/ #define _FIOCVALID(c) (_IOC_TYPE(c)==_FIOCBASE) @@ -291,23 +287,40 @@ /* (see nuttx/include/configdata.h */ #define _CFGDIOCVALID(c) (_IOC_TYPE(c)==_CFGDIOCBASE) -#define _CFGDIOC(nr) _IOC(_CFGDIOCBASE,nr) +#define _CFGDIOC(nr) _IOC(_CFGDIOCBASE,nr) + +/* Timer driver ioctl commands **********************************************/ +/* (see nuttx/include/timer.h */ + +#define _TCIOCVALID(c) (_IOC_TYPE(c)==_TCIOCBASE) +#define _TCIOC(nr) _IOC(_TCIOCBASE,nr) + +/* Application Config Data driver ioctl definitions *************************/ +/* (see nuttx/include/input/djoystick.h */ + +#define _DJOYIOCVALID(c) (_IOC_TYPE(c)==_DJOYBASE) +#define _DJOYIOC(nr) _IOC(_DJOYBASE,nr) /**************************************************************************** * Public Type Definitions ****************************************************************************/ /**************************************************************************** - * Public Function Prototypes + * Public Data ****************************************************************************/ #ifdef __cplusplus #define EXTERN extern "C" -extern "C" { +extern "C" +{ #else #define EXTERN extern #endif +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + #undef EXTERN #ifdef __cplusplus } diff --git a/include/nuttx/input/djoystick.h b/include/nuttx/input/djoystick.h new file mode 100644 index 00000000000..c973936b73e --- /dev/null +++ b/include/nuttx/input/djoystick.h @@ -0,0 +1,237 @@ +/**************************************************************************** + * include/nuttx/input/djoystick.h + * + * Copyright (C) 2014 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 header file provides definition for a standard discrete joystick + * interface. A discrete joystick refers to a joystick that could be + * implemented entirely with GPIO input pins. So up, down, left, and right + * are all discrete values like buttons (as opposed to integer values like + * you might obtain from an analog joystick). + * + * The discrete joystick driver exports a standard character driver + * interface. By convention, the discrete joystick is registered as an input + * device at /dev/djoyN where N uniquely identifies the driver instance. + * + * This header file documents the generic interface that all NuttX discrete + * joystick devices must conform. It adds standards and conventions on top + * of the standard character driver interface. + */ + +#ifndef __INCLUDE_NUTTX_INPUT_DJOYSTICK_H +#define __INCLUDE_NUTTX_INPUT_DJOYSTICK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_DJOYSTICK_NPOLLWAITERS +# define CONFIG_DJOYSTICK_NPOLLWAITERS 2 +#endif + +/* Joystick Interface *******************************************************/ +/* These definitions provide the meaning of all of the bits that may be + * reported in the djoy_buttonset_t bitset. + */ + +#define DJOY_UP (1 << 0) /* Bit 0: True = Joystick UP */ +#define DJOY_DOWN (1 << 1) /* Bit 1: True = Joystick DOWN */ +#define DJOY_LEFT (1 << 2) /* Bit 2: True = Joystick LEFT */ +#define DJOY_RIGHT (1 << 3) /* Bit 3: True = Joystick RIGHT */ +#define DJOY_BUTTON_1 (1 << 4) /* Bit 4: True = Button 1 pressed */ +#define DJOY_BUTTON_2 (1 << 5) /* Bit 5: True = Button 2 pressed */ +#define DJOY_BUTTON_3 (1 << 6) /* Bit 6: True = Button 3 pressed */ +#define DJOY_BUTTON_3 (1 << 7) /* Bit 7: True = Button 4 pressed */ +#define DJOY_BUTTONS_ALL 0xff /* The set of all buttons */ + +/* IOCTL commands + * + * Discrete joystick drivers do not support the character driver write() or + * seek() methods. The remaining driver methods behave as follows: + * + * 1) The read() method will always return a single value of size + * djoy_buttonset_t represent the current state of the joystick buttons. + * 2) The poll() method can be used to notify a client if there is a change + * in any of the joystick discrete inputs. This feature, of course, + * depends upon interrupt GPIO support from the platform. + * 3) The ioctl() method supports the commands documented below: + */ + +/* Command: DJOYIOC_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 djoy_pollevents_s + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + +#define DJOYIOC_POLLEVENTS _DJOYIOC(0x0001) + +/* Command: DJOYIOC_REGISTER + * Description: Register to receive a signal whenever there is a change in + * any of the joystick discrete inputs. This feature, of + * course, depends upon interrupt GPIO support from the + * platform. + * Argument: A read-only pointer to an instance of struct djoy_notify_s + * Return: Zero (OK) on success. Minus one will be returned on failure + * with the errno value set appropriately. + */ + +#define DJOYIOC_REGISTER _DJOYIOC(0x0002) + +/**************************************************************************** + * Public Types + ****************************************************************************/ +/* This type is a bit set that contains the state of all discrete joystick + * buttons. + */ + +typedef uint8_t djoy_buttonset_t; + +/* A reference to this structure is provided with the DJOYIOC_POLLEVENTS IOCTL + * command and describes the conditions under which the client would like + * to receive notification. + */ + +struct djoy_pollevents_s +{ + djoy_buttonset_t dp_press; /* Set of button depressions to wake up the poll */ + djoy_buttonset_t dp_release; /* Set of button releases to wake up the poll */ +}; + +/* A reference to this structure is provided with the DJOYIOC_REGISTER IOCTL + * command and describes the conditions under which the client would like + * to receive notification. + */ + +struct djoy_notify_s +{ + djoy_buttonset_t dn_press; /* Set of button depressions to be notified */ + djoy_buttonset_t dn_release; /* Set of button releases to be notified */ + uint8_t dn_signo; /* Signal number to use in the notification */ +}; + +/* This is the type of the discrete joystick interrupt handler used with + * the struct djoy_lowerhalf_s enable() method. + */ + +typedef CODE void (*djoy_interrupt_t) + (FAR const struct djoy_lowerhalf_s *lower, FAR void *arg); + +/* The discrete joystick driver is a two-part driver: + * + * 1) A common upper half driver that provides the common user interface to + * the joystick, + * 2) Platform-specific lower half drivers that provide the interface + * between the common upper half and the platform discrete 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 djoy_lowerhalf_s +{ + /* Return the set of buttons supported on the discrete joystick device */ + + CODE djoy_buttonset_t (*dl_supported)(FAR const struct djoy_lowerhalf_s *lower); + + /* Return the current state of all discrete joystick buttons */ + + CODE djoy_buttonset_t (*dl_sample)(FAR const struct djoy_lowerhalf_s *lower); + + /* Enable interrupts on the selecte set of joystick buttons. And empty + * set will disable all interrupts. + */ + + CODE void (*dl_enable)(FAR const struct djoy_lowerhalf_s *lower, + djoy_buttonset_t buttons, + djoy_interrupt_t handler, FAR void *arg); +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: djoy_register + * + * Description: + * Bind the lower half discrete joystick driver to an instance of the + * upper half discrete 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. + * This should be a string of the form "/dev/djoyN" where N is the the + * minor device number. + * lower - An instance of the platform-specific discrete joystick 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 djoy_register(FAR const char *devname, + FAR const struct djoy_lowerhalf_s *lower); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_INPUT_DJOYSTICK_H */ diff --git a/include/nuttx/input/mouse.h b/include/nuttx/input/mouse.h index da92e8fc700..f3367216402 100644 --- a/include/nuttx/input/mouse.h +++ b/include/nuttx/input/mouse.h @@ -34,7 +34,7 @@ ************************************************************************************/ /* The mouse driver exports a standard character driver interface. By - * convention, the mouse driver is registers as an input device at + * convention, the mouse driver is registered as an input device at * /dev/mouseN where N uniquely identifies the driver instance. * * This header file documents the generic interface that all NuttX