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 <futerigele@xiaomi.com>
This commit is contained in:
futerigele 2021-10-28 14:49:31 +08:00 committed by Xiang Xiao
parent ad4a42189f
commit 7381245159
4 changed files with 551 additions and 30 deletions

View File

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

View File

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

View File

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

View File

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