diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 4804f5174a..d103007752 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -27,6 +27,10 @@ if(CONFIG_INPUT) list(APPEND SRCS touchscreen_upper.c) endif() + if(CONFIG_INPUT_MOUSE) + list(APPEND SRCS mouse_upper.c) + endif() + if(CONFIG_INPUT_UINPUT) list(APPEND SRCS uinput.c) endif() diff --git a/drivers/input/Make.defs b/drivers/input/Make.defs index 3f8795041b..48faabfcfe 100644 --- a/drivers/input/Make.defs +++ b/drivers/input/Make.defs @@ -28,6 +28,10 @@ ifeq ($(CONFIG_INPUT_TOUCHSCREEN),y) CSRCS += touchscreen_upper.c endif +ifeq ($(CONFIG_INPUT_MOUSE),y) + CSRCS += mouse_upper.c +endif + ifeq ($(CONFIG_INPUT_TSC2007),y) CSRCS += tsc2007.c endif diff --git a/drivers/input/mouse_upper.c b/drivers/input/mouse_upper.c new file mode 100644 index 0000000000..598e6b6bd1 --- /dev/null +++ b/drivers/input/mouse_upper.c @@ -0,0 +1,363 @@ +/**************************************************************************** + * drivers/input/mouse_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 + +#include +#include +#include + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct mouse_openpriv_s +{ + struct circbuf_s circbuf; /* Store mouse point data in circle buffer */ + struct list_node node; /* Opened file buffer linked list node */ + FAR struct pollfd *fds; /* Polling structure of waiting thread */ + sem_t waitsem; /* Used to wait for the availability of data */ + mutex_t lock; /* Manages exclusive access to this structure */ +}; + +/* This structure is for mouse upper half driver */ + +struct mouse_upperhalf_s +{ + uint8_t nums; /* Number of mouse point structure */ + mutex_t lock; /* Manages exclusive access to this structure */ + struct list_node head; /* Opened file buffer chain header node */ + FAR struct mouse_lowerhalf_s *lower; /* A pointer of lower half instance */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int mouse_open(FAR struct file *filep); +static int mouse_close(FAR struct file *filep); +static ssize_t mouse_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int mouse_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_mouse_fops = +{ + mouse_open, /* open */ + mouse_close, /* close */ + mouse_read, /* read */ + NULL, /* write */ + NULL, /* seek */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + mouse_poll /* poll */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mouse_open + ****************************************************************************/ + +static int mouse_open(FAR struct file *filep) +{ + FAR struct mouse_openpriv_s *openpriv; + FAR struct inode *inode = filep->f_inode; + FAR struct mouse_upperhalf_s *upper = inode->i_private; + int ret; + + ret = nxmutex_lock(&upper->lock); + if (ret < 0) + { + return ret; + } + + openpriv = kmm_zalloc(sizeof(struct mouse_openpriv_s)); + if (openpriv == NULL) + { + nxmutex_unlock(&upper->lock); + return -ENOMEM; + } + + ret = circbuf_init(&openpriv->circbuf, NULL, + upper->nums * sizeof(struct mouse_report_s)); + if (ret < 0) + { + kmm_free(openpriv); + nxmutex_unlock(&upper->lock); + return ret; + } + + nxsem_init(&openpriv->waitsem, 0, 0); + nxmutex_init(&openpriv->lock); + list_add_tail(&upper->head, &openpriv->node); + + /* Save the buffer node pointer so that it can be used directly + * in the read operation. + */ + + filep->f_priv = openpriv; + nxmutex_unlock(&upper->lock); + return ret; +} + +/**************************************************************************** + * Name: mouse_close + ****************************************************************************/ + +static int mouse_close(FAR struct file *filep) +{ + FAR struct mouse_openpriv_s *openpriv = filep->f_priv; + FAR struct inode *inode = filep->f_inode; + FAR struct mouse_upperhalf_s *upper = inode->i_private; + int ret; + + ret = nxmutex_lock(&upper->lock); + if (ret < 0) + { + return ret; + } + + list_delete(&openpriv->node); + circbuf_uninit(&openpriv->circbuf); + nxsem_destroy(&openpriv->waitsem); + nxmutex_destroy(&openpriv->lock); + kmm_free(openpriv); + + nxmutex_unlock(&upper->lock); + return ret; +} + +/**************************************************************************** + * Name: mouse_read + ****************************************************************************/ + +static ssize_t mouse_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct mouse_openpriv_s *openpriv = filep->f_priv; + ssize_t ret; + + if (!buffer || !len) + { + return -EINVAL; + } + + ret = nxmutex_lock(&openpriv->lock); + if (ret < 0) + { + return ret; + } + + while (circbuf_is_empty(&openpriv->circbuf)) + { + if (filep->f_oflags & O_NONBLOCK) + { + ret = -EAGAIN; + goto out; + } + else + { + nxmutex_unlock(&openpriv->lock); + ret = nxsem_wait_uninterruptible(&openpriv->waitsem); + if (ret < 0) + { + return ret; + } + + ret = nxmutex_lock(&openpriv->lock); + if (ret < 0) + { + return ret; + } + } + } + + ret = circbuf_read(&openpriv->circbuf, buffer, len); + +out: + nxmutex_unlock(&openpriv->lock); + return ret; +} + +/**************************************************************************** + * Name: mouse_poll + ****************************************************************************/ + +static int mouse_poll(FAR struct file *filep, struct pollfd *fds, bool setup) +{ + FAR struct mouse_openpriv_s *openpriv = filep->f_priv; + pollevent_t eventset = 0; + int ret; + + ret = nxmutex_lock(&openpriv->lock); + if (ret < 0) + { + return ret; + } + + if (setup) + { + if (openpriv->fds == NULL) + { + openpriv->fds = fds; + fds->priv = &openpriv->fds; + } + else + { + ret = -EBUSY; + goto errout; + } + + if (!circbuf_is_empty(&openpriv->circbuf)) + { + eventset |= POLLIN; + } + + poll_notify(&openpriv->fds, 1, eventset); + } + else if (fds->priv) + { + openpriv->fds = NULL; + fds->priv = NULL; + } + +errout: + nxmutex_unlock(&openpriv->lock); + return ret; +} + +/**************************************************************************** + * Public Function + ****************************************************************************/ + +/**************************************************************************** + * Name: mouse_event + ****************************************************************************/ + +void mouse_event(FAR void *priv, FAR const struct mouse_report_s *sample) +{ + FAR struct mouse_upperhalf_s *upper = priv; + FAR struct mouse_openpriv_s *openpriv; + int semcount; + + if (nxmutex_lock(&upper->lock) < 0) + { + return; + } + + list_for_every_entry(&upper->head, openpriv, struct mouse_openpriv_s, node) + { + circbuf_overwrite(&openpriv->circbuf, sample, + sizeof(struct mouse_report_s)); + + nxsem_get_value(&openpriv->waitsem, &semcount); + if (semcount < 1) + { + nxsem_post(&openpriv->waitsem); + } + + if (openpriv->fds && openpriv->fds->fd >= 0) + { + poll_notify(&openpriv->fds, 1, POLLIN); + } + } + + nxmutex_unlock(&upper->lock); +} + +/**************************************************************************** + * Name: mouse_register + ****************************************************************************/ + +int mouse_register(FAR struct mouse_lowerhalf_s *lower, + FAR const char *path, uint8_t nums) +{ + FAR struct mouse_upperhalf_s *upper; + int ret; + + iinfo("Registering %s\n", path); + + if (lower == NULL || nums == 0) + { + ierr("ERROR: invalid mouse device\n"); + return -EINVAL; + } + + upper = kmm_zalloc(sizeof(struct mouse_upperhalf_s)); + if (!upper) + { + ierr("ERROR: Failed to mem alloc!\n"); + return -ENOMEM; + } + + lower->priv = upper; + upper->lower = lower; + upper->nums = nums; + list_initialize(&upper->head); + nxmutex_init(&upper->lock); + + ret = register_driver(path, &g_mouse_fops, 0666, upper); + if (ret < 0) + { + nxmutex_destroy(&upper->lock); + kmm_free(upper); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: mouse_unregister + ****************************************************************************/ + +void mouse_unregister(FAR struct mouse_lowerhalf_s *lower, + FAR const char *path) +{ + FAR struct mouse_upperhalf_s *upper; + + DEBUGASSERT(lower != NULL); + DEBUGASSERT(lower->priv != NULL); + + upper = lower->priv; + iinfo("UnRegistering %s\n", path); + unregister_driver(path); + + nxmutex_destroy(&upper->lock); + kmm_free(upper); +} diff --git a/include/nuttx/input/mouse.h b/include/nuttx/input/mouse.h index 9873f2693a..806a4bd7d1 100644 --- a/include/nuttx/input/mouse.h +++ b/include/nuttx/input/mouse.h @@ -47,31 +47,91 @@ #define MOUSE_BUTTON_1 (1 << 0) /* True: Left mouse button pressed */ #define MOUSE_BUTTON_2 (1 << 1) /* True: Right mouse button pressed */ #define MOUSE_BUTTON_3 (1 << 2) /* True: Middle mouse button pressed */ +#define MOUSE_BUTTON_4 (1 << 3) /* True: Left mouse button released */ +#define MOUSE_BUTTON_5 (1 << 4) /* True: Right mouse button released */ +#define MOUSE_BUTTON_6 (1 << 5) /* True: Middle mouse button released */ /**************************************************************************** * Public Types ****************************************************************************/ -/* This structure contains information about the current mouse button states - * and mouse position. Positional units are device specific and determined - * by mouse configuration settings. +/* This structure contains information about the current mouse button + * states and mouse position. Positional units are device specific + * and determined by mouseconfiguration settings. */ struct mouse_report_s { - uint8_t buttons; /* See TOUCH_* definitions above */ - /* Possibly padded with 1 byte here */ - int16_t x; /* X coordinate of the mouse position */ - int16_t y; /* Y coordinate of the mouse position */ + uint8_t buttons; /* See MOUSE_* definitions above */ + /* Possibly padded with 1 byte here */ + int16_t x; /* X coordinate of the mouse position */ + int16_t y; /* Y coordinate of the mouse position */ #ifdef CONFIG_INPUT_MOUSE_WHEEL - int16_t wheel; /* Mouse wheel position */ + int16_t wheel; /* Mouse wheel position */ #endif }; +/* This structure is for mouse lower half driver */ + +struct mouse_lowerhalf_s +{ + FAR void *priv; /* Save the upper half pointer */ +}; + /**************************************************************************** - * Public Data + * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: mouse_event + * + * Description: + * The lower half driver pushes mouse events through this interface, + * provided by mouse upper half. + * + * Arguments: + * priv - Upper half driver handle. + * sample - pointer to data of mouse point event. + ****************************************************************************/ + +void mouse_event(FAR void *priv, FAR const struct mouse_report_s *sample); + +/**************************************************************************** + * Name: mouse_register + * + * Description: + * This function registers a mouse 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 mouse device. such as "/dev/mouse0" + * nums - Number of the mouse points structure. + * + * Return: + * OK if the driver was successfully registered; A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +int mouse_register(FAR struct mouse_lowerhalf_s *lower, + FAR const char *path, uint8_t nums); + +/**************************************************************************** + * Name: mouse_unregister + * + * Description: + * This function is used to mouse driver to unregister and + * release the occupied resources. + * + * Arguments: + * lower - A pointer to an insatnce of mouse lower half driver. + * path - The path of mouse device. such as "/dev/mouse0" + ****************************************************************************/ + +void mouse_unregister(FAR struct mouse_lowerhalf_s *lower, + FAR const char *path); + #ifdef __cplusplus #define EXTERN extern "C" extern "C"