This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push: new 7381245 input/touchscreen: separate the interface for user interaction 7381245 is described below commit 73812451599a24fce017142a10ff34037c7d54dc Author: futerigele <futerig...@xiaomi.com> AuthorDate: Thu Oct 28 14:49:31 2021 +0800 input/touchscreen: separate the interface for user interaction Separate the interface for user interaction, touch upper half provides the interface uniformly. Signed-off-by: futerigele <futerig...@xiaomi.com> --- drivers/input/Kconfig | 11 + drivers/input/Make.defs | 4 + drivers/input/touchscreen_upper.c | 426 ++++++++++++++++++++++++++++++++++++++ include/nuttx/input/touchscreen.h | 140 ++++++++++--- 4 files changed, 551 insertions(+), 30 deletions(-) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index aca3379..2d2bab0 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -32,8 +32,19 @@ endif # INPUT_MOUSE config INPUT_TOUCHSCREEN bool + select MM_CIRCBUF default n +if INPUT_TOUCHSCREEN + +config INPUT_TOUCHSCREEN_NPOLLWAITERS + int "Number touchscreen poll waiters" + default 4 + ---help--- + Maximum number of threads that can be waiting on poll() + +endif # INPUT_TOUCHSCREEN + config INPUT_MAX11802 bool "MAX11802 touchscreen controller" default n diff --git a/drivers/input/Make.defs b/drivers/input/Make.defs index 218963d..44dbb5e 100644 --- a/drivers/input/Make.defs +++ b/drivers/input/Make.defs @@ -24,6 +24,10 @@ ifeq ($(CONFIG_INPUT),y) # Include the selected touchscreen drivers +ifeq ($(CONFIG_INPUT_TOUCHSCREEN),y) +CSRCS += touchscreen_upper.c +endif + ifeq ($(CONFIG_INPUT_TSC2007),y) CSRCS += tsc2007.c endif diff --git a/drivers/input/touchscreen_upper.c b/drivers/input/touchscreen_upper.c new file mode 100644 index 0000000..1298f03 --- /dev/null +++ b/drivers/input/touchscreen_upper.c @@ -0,0 +1,426 @@ +/**************************************************************************** + * drivers/input/touchscreen_upper.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <poll.h> +#include <fcntl.h> +#include <nuttx/kmalloc.h> +#include <nuttx/mm/circbuf.h> +#include <nuttx/input/touchscreen.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure is for touchscreen upper half driver */ + +struct touch_upperhalf_s +{ + uint8_t open_count; /* Number of times the device has been opened */ + uint32_t buff_nums; /* Number of touch point structure */ + uint8_t nwaiters; /* Number of threads waiting for touch point data */ + sem_t exclsem; /* Manages exclusive access to this structure */ + sem_t buffersem; /* Used to wait for the availability of data */ + struct circbuf_s buffer; /* Store touch point data in circle buffer */ + + /* The following is a list if poll structures of threads waiting for + * driver events. The 'struct pollfd' reference for each open is also + * retained in the f_priv field of the 'struct file'. + */ + + FAR struct pollfd *fds[CONFIG_INPUT_TOUCHSCREEN_NPOLLWAITERS]; + FAR struct touch_lowerhalf_s *lower; /* A pointer of lower half instance */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void touch_notify(FAR struct touch_upperhalf_s *upper, + pollevent_t eventset); +static int touch_open(FAR struct file *filep); +static int touch_close(FAR struct file *filep); +static ssize_t touch_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int touch_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); +static int touch_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_touch_fops = +{ + touch_open, + touch_close, + touch_read, + NULL, + NULL, + touch_ioctl, + touch_poll +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void touch_notify(FAR struct touch_upperhalf_s *upper, + pollevent_t eventset) +{ + FAR struct pollfd *fd; + int i; + + for (i = 0; i < CONFIG_INPUT_TOUCHSCREEN_NPOLLWAITERS; i++) + { + fd = upper->fds[i]; + if (fd) + { + fd->revents |= (fd->events & eventset); + if (fd->revents != 0) + { + /* report event log */ + + int semcount; + nxsem_get_value(fd->sem, &semcount); + if (semcount < 1) + { + nxsem_post(fd->sem); + } + } + } + } +} + +/**************************************************************************** + * Name: touch_open + ****************************************************************************/ + +static int touch_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct touch_upperhalf_s *upper = inode->i_private; + FAR struct touch_lowerhalf_s *lower = upper->lower; + int ret; + int tmp; + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + return ret; + } + + tmp = upper->open_count + 1; + if (tmp == 0) + { + ret = -EMFILE; + goto err_out; + } + else if (tmp == 1) + { + ret = circbuf_init(&upper->buffer, NULL, upper->buff_nums * + SIZEOF_TOUCH_SAMPLE_S(lower->maxpoint)); + if (ret < 0) + { + goto err_out; + } + } + + upper->open_count = tmp; + +err_out: + nxsem_post(&upper->exclsem); + return ret; +} + +/**************************************************************************** + * Name: touch_close + ****************************************************************************/ + +static int touch_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct touch_upperhalf_s *upper = inode->i_private; + int ret; + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + return ret; + } + + if (upper->open_count == 1) + { + upper->open_count--; + circbuf_uninit(&upper->buffer); + } + + nxsem_post(&upper->exclsem); + return ret; +} + +/**************************************************************************** + * Name: touch_read + ****************************************************************************/ + +static ssize_t touch_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct touch_upperhalf_s *upper = inode->i_private; + int ret; + + if (!buffer || !len) + { + return -EINVAL; + } + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + return ret; + } + + while (circbuf_is_empty(&upper->buffer)) + { + if (filep->f_oflags & O_NONBLOCK) + { + ret = -EAGAIN; + goto out; + } + else + { + nxsem_post(&upper->exclsem); + ret = nxsem_wait_uninterruptible(&upper->buffersem); + if (ret < 0) + { + return ret; + } + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + return ret; + } + } + } + + ret = circbuf_read(&upper->buffer, buffer, len); + +out: + nxsem_post(&upper->exclsem); + return ret; +} + +static int touch_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct touch_upperhalf_s *upper = inode->i_private; + FAR struct touch_lowerhalf_s *lower = upper->lower; + int ret; + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + return ret; + } + + if (lower->control) + { + ret = lower->control(lower, cmd, arg); + } + else + { + ret = -ENOTTY; + } + + nxsem_post(&upper->exclsem); + return ret; +} + +static int touch_poll(FAR struct file *filep, + struct pollfd *fds, bool setup) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct touch_upperhalf_s *upper = inode->i_private; + pollevent_t eventset = 0; + int ret; + int i; + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + return ret; + } + + if (setup) + { + for (i = 0; i < CONFIG_INPUT_TOUCHSCREEN_NPOLLWAITERS; i++) + { + if (NULL == upper->fds[i]) + { + upper->fds[i] = fds; + fds->priv = &upper->fds[i]; + break; + } + } + + if (i >= CONFIG_INPUT_TOUCHSCREEN_NPOLLWAITERS) + { + fds->priv = NULL; + ret = -EBUSY; + goto errout; + } + + if (!circbuf_is_empty(&upper->buffer)) + { + eventset |= (fds->events & POLLIN); + } + + if (eventset) + { + touch_notify(upper, eventset); + } + } + else if (fds->priv) + { + for (i = 0; i < CONFIG_INPUT_TOUCHSCREEN_NPOLLWAITERS; i++) + { + if (fds == upper->fds[i]) + { + upper->fds[i] = NULL; + fds->priv = NULL; + break; + } + } + } + +errout: + nxsem_post(&upper->exclsem); + return ret; +} + +/**************************************************************************** + * Public Function + ****************************************************************************/ + +void touch_event(FAR void *priv, FAR const struct touch_sample_s *sample) +{ + FAR struct touch_upperhalf_s *upper = priv; + int semcount; + + if (nxsem_wait(&upper->exclsem) < 0) + { + return; + } + + circbuf_overwrite(&upper->buffer, sample, + SIZEOF_TOUCH_SAMPLE_S(sample->npoints)); + touch_notify(upper, POLLIN); + nxsem_get_value(&upper->buffersem, &semcount); + if (semcount < 1) + { + nxsem_post(&upper->buffersem); + } + + nxsem_post(&upper->exclsem); +} + +int touch_register(FAR struct touch_lowerhalf_s *lower, + FAR const char *path, uint8_t buff_nums) +{ + FAR struct touch_upperhalf_s *upper; + int ret; + + iinfo("Registering %s\n", path); + + if (lower == NULL || !buff_nums) + { + ierr("ERROR: invalid touchscreen device\n"); + return -EINVAL; + } + + upper = kmm_zalloc(sizeof(struct touch_upperhalf_s)); + if (!upper) + { + ierr("ERROR: Failed to mem alloc!\n"); + return -ENOMEM; + } + + upper->lower = lower; + upper->buff_nums = buff_nums; + + nxsem_init(&upper->exclsem, 0, 1); + nxsem_init(&upper->buffersem, 0, 0); + + nxsem_set_protocol(&upper->buffersem, SEM_PRIO_NONE); + + lower->priv = upper; + + ret = register_driver(path, &g_touch_fops, 0666, upper); + if (ret < 0) + { + goto err_out; + } + + return ret; +err_out: + nxsem_destroy(&upper->exclsem); + nxsem_destroy(&upper->buffersem); + kmm_free(upper); + return ret; +} + +void touch_unregister(FAR struct touch_lowerhalf_s *lower, + FAR const char *path) +{ + FAR struct touch_upperhalf_s *upper; + + DEBUGASSERT(lower != NULL); + DEBUGASSERT(lower->priv != NULL); + + upper = lower->priv; + + iinfo("UnRegistering %s\n", path); + unregister_driver(path); + + nxsem_destroy(&upper->exclsem); + nxsem_destroy(&upper->buffersem); + + kmm_free(upper); +} diff --git a/include/nuttx/input/touchscreen.h b/include/nuttx/input/touchscreen.h index 0647a88..0af133a 100644 --- a/include/nuttx/input/touchscreen.h +++ b/include/nuttx/input/touchscreen.h @@ -1,4 +1,4 @@ -/************************************************************************************ +/**************************************************************************** * include/nuttx/input/touchscreen.h * * Licensed to the Apache Software Foundation (ASF) under one or more @@ -16,7 +16,7 @@ * License for the specific language governing permissions and limitations * under the License. * - ************************************************************************************/ + ****************************************************************************/ /* The TOUCHSCREEN driver exports a standard character driver interface. By * convention, the touchscreen driver is registers as an input device at @@ -30,20 +30,22 @@ #ifndef __INCLUDE_NUTTX_INPUT_TOUCHSCREEN_H #define __INCLUDE_NUTTX_INPUT_TOUCHSCREEN_H -/************************************************************************************ +/**************************************************************************** * Included Files - ************************************************************************************/ + ****************************************************************************/ #include <nuttx/config.h> #include <nuttx/fs/ioctl.h> +#include <nuttx/mm/circbuf.h> +#include <nuttx/semaphore.h> #ifdef CONFIG_INPUT -/************************************************************************************ +/**************************************************************************** * Pre-processor Definitions - ************************************************************************************/ + ****************************************************************************/ -/* IOCTL Commands *******************************************************************/ +/* IOCTL Commands ***********************************************************/ /* Common TSC IOCTL commands */ @@ -56,28 +58,29 @@ #define TSC_FIRST 0x0001 /* First common command */ #define TSC_NCMDS 5 /* Five common commands */ -/* User defined ioctl commands are also supported. However, the TSC driver must - * reserve a block of commands as follows in order prevent IOCTL command numbers - * from overlapping. +/* User defined ioctl commands are also supported. However, the + * TSC driver must reserve a block of commands as follows in order + * prevent IOCTL command numbers from overlapping. * - * This is generally done as follows. The first reservation for TSC driver A would - * look like: + * This is generally done as follows. The first reservation for + * TSC driver A would look like: * - * TSC_A_FIRST (TSC_FIRST + TSC_NCMDS) <- First command - * TSC_A_NCMDS 42 <- Number of commands + * TSC_A_FIRST (TSC_FIRST + TSC_NCMDS) <- First command + * TSC_A_NCMDS 42 <- Number of commands * - * IOCTL commands for TSC driver A would then be defined in a TSC A header file like: + * IOCTL commands for TSC driver A would then be defined in a + * TSC A header file like: * - * TSCIOC_A_CMD1 _TSIOC(TSC_A_FIRST + 0) - * TSCIOC_A_CMD2 _TSIOC(TSC_A_FIRST + 1) - * TSCIOC_A_CMD3 _TSIOC(TSC_A_FIRST + 2) + * TSCIOC_A_CMD1 _TSIOC(TSC_A_FIRST + 0) + * TSCIOC_A_CMD2 _TSIOC(TSC_A_FIRST + 1) + * TSCIOC_A_CMD3 _TSIOC(TSC_A_FIRST + 2) * ... - * TSCIOC_A_CMD42 _TSIOC(TSC_A_FIRST + 41) + * TSCIOC_A_CMD42 _TSIOC(TSC_A_FIRST + 41) * * The next reservation would look like: * - * TSC_B_FIRST (TSC_A_FIRST + TSC_A_NCMDS) <- Next command - * TSC_B_NCMDS 77 <- Number of commands + * TSC_B_FIRST (TSC_A_FIRST + TSC_A_NCMDS) <- Next command + * TSC_B_NCMDS 77 <- Number of commands */ /* These definitions provide the meaning of all of the bits that may be @@ -92,9 +95,9 @@ #define TOUCH_PRESSURE_VALID (1 << 5) /* Hardware provided a valid pressure */ #define TOUCH_SIZE_VALID (1 << 6) /* Hardware provided a valid H/W contact size */ -/************************************************************************************ +/**************************************************************************** * Public Types - ************************************************************************************/ + ****************************************************************************/ /* This structure contains information about a single touch point. * Positional units are device specific. @@ -111,9 +114,9 @@ struct touch_point_s uint16_t pressure; /* Touch pressure */ }; -/* The typical touchscreen driver is a read-only, input character device driver. - * the driver write() method is not supported and any attempt to open the - * driver in any mode other than read-only will fail. +/* The typical touchscreen driver is a read-only, input character device + * driver.the driver write() method is not supported and any attempt to + * open the driver in any mode other than read-only will fail. * * Data read from the touchscreen device consists only of touch events and * touch sample data. This is reflected by struct touch_sample_s. This @@ -121,8 +124,8 @@ struct touch_point_s * * On some devices, multiple touchpoints may be supported. So this top level * data structure is a struct touch_sample_s that "contains" a set of touch - * points. Each touch point is managed individually using an ID that identifies - * a touch from first contact until the end of the contact. + * points. Each touch point is managed individually using an ID that + * identifies a touch from first contact until the end of the contact. */ struct touch_sample_s @@ -134,9 +137,86 @@ struct touch_sample_s #define SIZEOF_TOUCH_SAMPLE_S(n) \ (sizeof(struct touch_sample_s) + ((n) - 1) * sizeof(struct touch_point_s)) -/************************************************************************************ +/* This structure is for touchscreen lower half driver */ + +struct touch_lowerhalf_s +{ + uint8_t maxpoint; /* Maximal point supported by the touchscreen */ + FAR void *priv; /* Save the upper half pointer */ + + /************************************************************************** + * Name: control + * + * Description: + * Users can use this interface to implement custom IOCTL. + * + * Arguments: + * lower - The instance of lower half of touchscreen device. + * cmd - User defined specific command. + * arg - Argument of the specific command. + * + * Return Value: + * Zero(OK) on success; a negated errno value on failure. + * -ENOTTY - The command is not supported. + **************************************************************************/ + + CODE int (*control)(FAR struct touch_lowerhalf_s *lower, + int cmd, unsigned long arg); +}; + +/**************************************************************************** * Public Function Prototypes - ************************************************************************************/ + ****************************************************************************/ + +/**************************************************************************** + * Name: touch_event + * + * Description: + * The lower half driver pushes touchscreen events through this interface, + * provided by touchscreen upper half. + * + * Arguments: + * priv - Upper half driver handle. + * sample - pointer to data of touch point event. + ****************************************************************************/ + +void touch_event(FAR void *priv, FAR const struct touch_sample_s *sample); + +/**************************************************************************** + * Name: touch_register + * + * Description: + * This function registers a touchscreen device, the upper half binds + * with hardware device through the lower half instance. + * + * Arguments: + * lower - A pointer of lower half instance. + * path - The path of touchscreen device. such as "/dev/input0" + * buff_nums - Number of the touch points structure. + * + * Return: + * OK if the driver was successfully registered; A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +int touch_register(FAR struct touch_lowerhalf_s *lower, + FAR const char *path, uint8_t buff_nums); + +/**************************************************************************** + * Name: touch_unregister + * + * Description: + * This function is used to touchscreen driver to unregister and + * release the occupied resources. + * + * Arguments: + * lower - A pointer to an insatnce of touchscreen lower half driver. + * path - The path of touchscreen device. such as "/dev/input0" + ****************************************************************************/ + +void touch_unregister(FAR struct touch_lowerhalf_s *lower, + FAR const char *path); #ifdef __cplusplus #define EXTERN extern "C"