diff mbox series

[v2] Drivers: input: misc: Add driver touchscreen-buttons to support physically labeled buttons on touch screen surfaces

Message ID 20201029180448.e3aadaf2422d58470a9d0fcc@uvos.xyz
State Superseded
Headers show
Series [v2] Drivers: input: misc: Add driver touchscreen-buttons to support physically labeled buttons on touch screen surfaces | expand

Commit Message

Carl Philipp Klemm Oct. 29, 2020, 5:04 p.m. UTC
Adds a driver for supporting permanet, physically labeled, buttons on touchscreen surfaces. As are common on android phones designed with android 1.0 to 2.3 in mind. The driver works by attaching to another input device and mirroring its events, while inserting key events and filtering for touches that land on the buttons. Buttons are arbitrary rectangles configurable via dts.

Signed-off-by: Carl Philipp Klemm <carl@uvos.xyz>

---

Comments

kernel test robot Nov. 2, 2020, 11:55 p.m. UTC | #1
Hi Carl,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on input/next]
[also build test WARNING on v5.10-rc2 next-20201102]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Carl-Philipp-Klemm/Drivers-input-misc-Add-driver-touchscreen-buttons-to-support-physically-labeled-buttons-on-touch-screen-surfaces/20201030-010622
base:   https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
config: mips-allyesconfig (attached as .config)
compiler: mips-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/00fd93a32ffbfc2ce311ed11e49a596eae970933
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Carl-Philipp-Klemm/Drivers-input-misc-Add-driver-touchscreen-buttons-to-support-physically-labeled-buttons-on-touch-screen-surfaces/20201030-010622
        git checkout 00fd93a32ffbfc2ce311ed11e49a596eae970933
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=mips 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/input/misc/touchscreen-buttons.c: In function 'touchscreen_buttons_input_event':
   drivers/input/misc/touchscreen-buttons.c:179:85: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]
     179 |  } else if (buttons->queue.lastindex < EVENT_QUEUE_SIZE && buttons->queue.lastindex >= 0) {
         |                                                                                     ^~
   drivers/input/misc/touchscreen-buttons.c: At top level:
>> drivers/input/misc/touchscreen-buttons.c:230:6: warning: no previous prototype for 'merge_task_handler' [-Wmissing-prototypes]
     230 | void merge_task_handler(struct work_struct *work)
         |      ^~~~~~~~~~~~~~~~~~
>> drivers/input/misc/touchscreen-buttons.c:240:6: warning: no previous prototype for 'close_task_handler' [-Wmissing-prototypes]
     240 | void close_task_handler(struct work_struct *work)
         |      ^~~~~~~~~~~~~~~~~~
>> drivers/input/misc/touchscreen-buttons.c:250:6: warning: no previous prototype for 'open_task_handler' [-Wmissing-prototypes]
     250 | void open_task_handler(struct work_struct *work)
         |      ^~~~~~~~~~~~~~~~~
>> drivers/input/misc/touchscreen-buttons.c:382:5: warning: no previous prototype for 'touchscreen_buttons_idev_opened' [-Wmissing-prototypes]
     382 | int touchscreen_buttons_idev_opened(struct input_dev *idev)
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/input/misc/touchscreen-buttons.c:405:6: warning: no previous prototype for 'touchscreen_buttons_idev_closed' [-Wmissing-prototypes]
     405 | void touchscreen_buttons_idev_closed(struct input_dev *idev)
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

vim +/merge_task_handler +230 drivers/input/misc/touchscreen-buttons.c

   229	
 > 230	void merge_task_handler(struct work_struct *work)
   231	{
   232		struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, merge_task);
   233	
   234		mutex_lock(&buttons->mutex);
   235		if (buttons->ts_handle && buttons->ts_handle->dev)
   236			touchscreen_buttons_merge_capabilitys(buttons->filtered_ts_idev, buttons->ts_handle->dev);
   237		mutex_unlock(&buttons->mutex);
   238	}
   239	
 > 240	void close_task_handler(struct work_struct *work)
   241	{
   242		struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, close_task);
   243	
   244		mutex_lock(&buttons->mutex);
   245		if (buttons && buttons->ts_handle && buttons->ts_handle->open != 0)
   246			input_close_device(buttons->ts_handle);
   247		mutex_unlock(&buttons->mutex);
   248	}
   249	
 > 250	void open_task_handler(struct work_struct *work)
   251	{
   252		struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, open_task);
   253		int error;
   254	
   255		mutex_lock(&buttons->mutex);
   256		if (buttons && buttons->ts_handle) {
   257			error = input_open_device(buttons->ts_handle);
   258			if (error) {
   259				dev_err(buttons->dev, "Failed to open input device, error %d\n", error);
   260				input_unregister_handle(buttons->ts_handle);
   261				kfree(buttons->ts_handle);
   262				buttons->ts_handle = NULL;
   263			}
   264		}
   265		mutex_unlock(&buttons->mutex);
   266	}
   267	
   268	static int touchscreen_buttons_input_connect(struct input_handler *handler,
   269						     struct input_dev *dev, const struct input_device_id *id)
   270	{
   271		struct touchscreen_buttons *buttons;
   272	
   273		buttons = handler->private;
   274	
   275		mutex_lock(&buttons->mutex);
   276	
   277		if ((!buttons->ts_handle && device_match_of_node(&dev->dev, buttons->map->ts_node)) ||
   278			(dev->dev.parent && device_match_of_node(dev->dev.parent, buttons->map->ts_node))) {
   279			int error;
   280	
   281			dev_info(buttons->dev, "Binding to device: %s\n", dev_name(&dev->dev));
   282	
   283			buttons->ts_handle = kzalloc(sizeof(*buttons->ts_handle), GFP_KERNEL);
   284			if (!buttons->ts_handle) {
   285				mutex_unlock(&buttons->mutex);
   286				return -ENOMEM;
   287			}
   288	
   289			buttons->ts_handle->dev = dev;
   290			buttons->ts_handle->handler = handler;
   291			buttons->ts_handle->name = "touchscreen-buttons";
   292			buttons->ts_handle->private = handler->private;
   293			buttons->queue.lastindex = 0;
   294	
   295			error = input_register_handle(buttons->ts_handle);
   296			if (error) {
   297				dev_err(buttons->dev, "Failed to register input handler, error %d\n", error);
   298				kfree(buttons->ts_handle);
   299				buttons->ts_handle = NULL;
   300				mutex_unlock(&buttons->mutex);
   301				return error;
   302			}
   303	
   304			queue_work(buttons->workqueue, &buttons->merge_task);
   305	
   306			if (buttons->filtered_ts_idev->users > 0 && buttons->ts_handle->open == 0)
   307				queue_work(buttons->workqueue, &buttons->open_task);
   308		}
   309	
   310		mutex_unlock(&buttons->mutex);
   311		return 0;
   312	}
   313	
   314	static void touchscreen_buttons_input_disconnect(struct input_handle *handle)
   315	{
   316		struct touchscreen_buttons *buttons;
   317	
   318		buttons = handle->private;
   319	
   320		mutex_lock(&buttons->mutex);
   321		if (handle == buttons->ts_handle) {
   322			input_close_device(handle);
   323			input_unregister_handle(handle);
   324			kfree(handle);
   325			buttons->ts_handle = NULL;
   326			dev_info(buttons->dev, "Touchscreen device disconnected buttons disabled\n");
   327		} else {
   328			dev_err(buttons->dev, "Unknown device disconnected, %p should be %p", handle,
   329				buttons->ts_handle);
   330		}
   331		mutex_unlock(&buttons->mutex);
   332	}
   333	
   334	static struct touchscreen_button_map
   335	*touchscreen_buttons_get_devtree_pdata(struct device *dev)
   336	{
   337		struct touchscreen_button_map *map;
   338		struct fwnode_handle *child_node;
   339		struct device_node *node;
   340		int i;
   341	
   342		map = kzalloc(sizeof(*map), GFP_KERNEL);
   343		if (!map)
   344			return ERR_PTR(-ENOMEM);
   345	
   346		map->count = device_get_child_node_count(dev);
   347		if (map->count == 0)
   348			return ERR_PTR(-ENODEV);
   349	
   350		map->buttons = kcalloc(map->count, sizeof(*map->buttons), GFP_KERNEL);
   351		if (!map->buttons)
   352			return ERR_PTR(-ENOMEM);
   353	
   354		node = dev->of_node;
   355		map->ts_node = of_parse_phandle(node, "touchscreen_phandle", 0);
   356		if (!map->ts_node) {
   357			dev_err(dev, "touchscreen_phandle node missing\n");
   358			return ERR_PTR(-ENODEV);
   359		}
   360	
   361		dev_info(dev, "Device_node name: %s\n", map->ts_node->name);
   362	
   363		i = 0;
   364		device_for_each_child_node(dev, child_node) {
   365			struct touchscreen_button *button;
   366	
   367			button = &map->buttons[i];
   368	
   369			fwnode_property_read_u32(child_node, "x-position", &button->x);
   370			fwnode_property_read_u32(child_node, "y-position", &button->y);
   371			fwnode_property_read_u32(child_node, "x-size", &button->width);
   372			fwnode_property_read_u32(child_node, "y-size", &button->height);
   373			fwnode_property_read_u32(child_node, "keycode", &button->keycode);
   374			dev_info(dev,
   375				 "Adding button at x=%u y=%u size %u x %u keycode=%u\n",
   376				 button->x, button->y, button->width, button->height, button->keycode);
   377			++i;
   378		}
   379		return map;
   380	}
   381	
 > 382	int touchscreen_buttons_idev_opened(struct input_dev *idev)
   383	{
   384		struct touchscreen_buttons *buttons;
   385	
   386		buttons = dev_get_drvdata(idev->dev.parent);
   387	
   388		mutex_lock(&buttons->mutex);
   389		if (buttons && buttons->ts_handle) {
   390			if (buttons->ts_handle->open == 0) {
   391				queue_work(buttons->workqueue, &buttons->open_task);
   392				dev_dbg(idev->dev.parent, "idev opened\n");
   393			} else {
   394				dev_info(idev->dev.parent, "idev allready opened\n");
   395			}
   396		} else {
   397			dev_warn(idev->dev.parent,
   398				 "Input device opend but touchscreen not opened. %p %p\n", buttons,
   399				 buttons->ts_handle);
   400		}
   401		mutex_unlock(&buttons->mutex);
   402		return 0;
   403	}
   404	
 > 405	void touchscreen_buttons_idev_closed(struct input_dev *idev)
   406	{
   407		struct touchscreen_buttons *buttons;
   408	
   409		buttons = dev_get_drvdata(idev->dev.parent);
   410	
   411		mutex_lock(&buttons->mutex);
   412		if (buttons && buttons->ts_handle && buttons->ts_handle->open != 0) {
   413			queue_work(buttons->workqueue, &buttons->close_task);
   414			dev_dbg(idev->dev.parent, "idev closed\n");
   415		}
   416		mutex_unlock(&buttons->mutex);
   417	}
   418	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Nov. 3, 2020, 12:34 p.m. UTC | #2
Hi Carl,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on input/next]
[also build test WARNING on v5.10-rc2 next-20201103]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Carl-Philipp-Klemm/Drivers-input-misc-Add-driver-touchscreen-buttons-to-support-physically-labeled-buttons-on-touch-screen-surfaces/20201030-010622
base:   https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
config: x86_64-randconfig-m001-20201103 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

smatch warnings:
drivers/input/misc/touchscreen-buttons.c:179 touchscreen_buttons_input_event() warn: always true condition '(buttons->queue.lastindex >= 0) => (0-u32max >= 0)'
drivers/input/misc/touchscreen-buttons.c:348 touchscreen_buttons_get_devtree_pdata() warn: possible memory leak of 'map'
drivers/input/misc/touchscreen-buttons.c:397 touchscreen_buttons_idev_opened() error: we previously assumed 'buttons' could be null (see line 389)

vim +179 drivers/input/misc/touchscreen-buttons.c

   166	
   167	static void touchscreen_buttons_input_event(struct input_handle *handle,
   168						    unsigned int type, unsigned int code, int value)
   169	{
   170		struct touchscreen_buttons *buttons;
   171	
   172		buttons = handle->private;
   173	
   174		if (type == EV_SYN && code == SYN_REPORT) {
   175			if (touchscreen_buttons_process_syn(&buttons->queue,
   176				buttons->map, buttons->buttons_idev) == 0)
   177				touchscreen_buttons_resend_events(&buttons->queue, buttons->filtered_ts_idev);
   178			buttons->queue.lastindex = 0;
 > 179		} else if (buttons->queue.lastindex < EVENT_QUEUE_SIZE && buttons->queue.lastindex >= 0) {
   180			buttons->queue.events[buttons->queue.lastindex].type = type;
   181			buttons->queue.events[buttons->queue.lastindex].code = code;
   182			buttons->queue.events[buttons->queue.lastindex].value = value;
   183			++buttons->queue.lastindex;
   184		} else {
   185			dev_warn(buttons->dev,
   186				 "event_qeue overrun, will not capture events until next SYN_REPORT\n");
   187		}
   188	}
   189	
   190	static void touchscreen_buttons_merge_capabilitys(struct input_dev *target, struct input_dev *source)
   191	{
   192		unsigned int i;
   193	
   194		mutex_lock(&target->mutex);
   195		mutex_lock(&source->mutex);
   196		for (i = 0; i < BITS_TO_LONGS(INPUT_PROP_CNT); ++i)
   197			target->propbit[i] = target->propbit[i] | source->propbit[i];
   198		for (i = 0; i < BITS_TO_LONGS(EV_CNT); ++i)
   199			target->evbit[i] = target->evbit[i] | source->evbit[i];
   200		for (i = 0; i < BITS_TO_LONGS(KEY_CNT); ++i)
   201			target->keybit[i] = target->keybit[i] | source->keybit[i];
   202		for (i = 0; i < BITS_TO_LONGS(REL_CNT); ++i)
   203			target->relbit[i] = target->relbit[i] | source->relbit[i];
   204		for (i = 0; i < BITS_TO_LONGS(ABS_CNT); ++i)
   205			target->absbit[i] = target->absbit[i] | source->absbit[i];
   206		for (i = 0; i < BITS_TO_LONGS(MSC_CNT); ++i)
   207			target->mscbit[i] = target->mscbit[i] | source->mscbit[i];
   208		for (i = 0; i < BITS_TO_LONGS(LED_CNT); ++i)
   209			target->ledbit[i] = target->ledbit[i] | source->ledbit[i];
   210		for (i = 0; i < BITS_TO_LONGS(SND_CNT); ++i)
   211			target->sndbit[i] = target->sndbit[i] | source->sndbit[i];
   212		for (i = 0; i < BITS_TO_LONGS(FF_CNT); ++i)
   213			target->ffbit[i] = target->ffbit[i] | source->ffbit[i];
   214		for (i = 0; i < BITS_TO_LONGS(SW_CNT); ++i)
   215			target->swbit[i] = target->swbit[i] | source->swbit[i];
   216	
   217		if (*source->evbit & (1 << EV_ABS)) {
   218			input_alloc_absinfo(target);
   219			for (i = 0; i < ABS_CNT; ++i)
   220				target->absinfo[i] = source->absinfo[i];
   221			if (source->mt) {
   222				input_mt_init_slots(target, source->mt->num_slots, source->mt->flags);
   223				touchscreen_buttons_copy_mt_slots(target, source);
   224			}
   225		}
   226		mutex_unlock(&source->mutex);
   227		mutex_unlock(&target->mutex);
   228	}
   229	
   230	void merge_task_handler(struct work_struct *work)
   231	{
   232		struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, merge_task);
   233	
   234		mutex_lock(&buttons->mutex);
   235		if (buttons->ts_handle && buttons->ts_handle->dev)
   236			touchscreen_buttons_merge_capabilitys(buttons->filtered_ts_idev, buttons->ts_handle->dev);
   237		mutex_unlock(&buttons->mutex);
   238	}
   239	
   240	void close_task_handler(struct work_struct *work)
   241	{
   242		struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, close_task);
   243	
   244		mutex_lock(&buttons->mutex);
   245		if (buttons && buttons->ts_handle && buttons->ts_handle->open != 0)
   246			input_close_device(buttons->ts_handle);
   247		mutex_unlock(&buttons->mutex);
   248	}
   249	
   250	void open_task_handler(struct work_struct *work)
   251	{
   252		struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, open_task);
   253		int error;
   254	
   255		mutex_lock(&buttons->mutex);
   256		if (buttons && buttons->ts_handle) {
   257			error = input_open_device(buttons->ts_handle);
   258			if (error) {
   259				dev_err(buttons->dev, "Failed to open input device, error %d\n", error);
   260				input_unregister_handle(buttons->ts_handle);
   261				kfree(buttons->ts_handle);
   262				buttons->ts_handle = NULL;
   263			}
   264		}
   265		mutex_unlock(&buttons->mutex);
   266	}
   267	
   268	static int touchscreen_buttons_input_connect(struct input_handler *handler,
   269						     struct input_dev *dev, const struct input_device_id *id)
   270	{
   271		struct touchscreen_buttons *buttons;
   272	
   273		buttons = handler->private;
   274	
   275		mutex_lock(&buttons->mutex);
   276	
   277		if ((!buttons->ts_handle && device_match_of_node(&dev->dev, buttons->map->ts_node)) ||
   278			(dev->dev.parent && device_match_of_node(dev->dev.parent, buttons->map->ts_node))) {
   279			int error;
   280	
   281			dev_info(buttons->dev, "Binding to device: %s\n", dev_name(&dev->dev));
   282	
   283			buttons->ts_handle = kzalloc(sizeof(*buttons->ts_handle), GFP_KERNEL);
   284			if (!buttons->ts_handle) {
   285				mutex_unlock(&buttons->mutex);
   286				return -ENOMEM;
   287			}
   288	
   289			buttons->ts_handle->dev = dev;
   290			buttons->ts_handle->handler = handler;
   291			buttons->ts_handle->name = "touchscreen-buttons";
   292			buttons->ts_handle->private = handler->private;
   293			buttons->queue.lastindex = 0;
   294	
   295			error = input_register_handle(buttons->ts_handle);
   296			if (error) {
   297				dev_err(buttons->dev, "Failed to register input handler, error %d\n", error);
   298				kfree(buttons->ts_handle);
   299				buttons->ts_handle = NULL;
   300				mutex_unlock(&buttons->mutex);
   301				return error;
   302			}
   303	
   304			queue_work(buttons->workqueue, &buttons->merge_task);
   305	
   306			if (buttons->filtered_ts_idev->users > 0 && buttons->ts_handle->open == 0)
   307				queue_work(buttons->workqueue, &buttons->open_task);
   308		}
   309	
   310		mutex_unlock(&buttons->mutex);
   311		return 0;
   312	}
   313	
   314	static void touchscreen_buttons_input_disconnect(struct input_handle *handle)
   315	{
   316		struct touchscreen_buttons *buttons;
   317	
   318		buttons = handle->private;
   319	
   320		mutex_lock(&buttons->mutex);
   321		if (handle == buttons->ts_handle) {
   322			input_close_device(handle);
   323			input_unregister_handle(handle);
   324			kfree(handle);
   325			buttons->ts_handle = NULL;
   326			dev_info(buttons->dev, "Touchscreen device disconnected buttons disabled\n");
   327		} else {
   328			dev_err(buttons->dev, "Unknown device disconnected, %p should be %p", handle,
   329				buttons->ts_handle);
   330		}
   331		mutex_unlock(&buttons->mutex);
   332	}
   333	
   334	static struct touchscreen_button_map
   335	*touchscreen_buttons_get_devtree_pdata(struct device *dev)
   336	{
   337		struct touchscreen_button_map *map;
   338		struct fwnode_handle *child_node;
   339		struct device_node *node;
   340		int i;
   341	
   342		map = kzalloc(sizeof(*map), GFP_KERNEL);
   343		if (!map)
   344			return ERR_PTR(-ENOMEM);
   345	
   346		map->count = device_get_child_node_count(dev);
   347		if (map->count == 0)
 > 348			return ERR_PTR(-ENODEV);
   349	
   350		map->buttons = kcalloc(map->count, sizeof(*map->buttons), GFP_KERNEL);
   351		if (!map->buttons)
   352			return ERR_PTR(-ENOMEM);
   353	
   354		node = dev->of_node;
   355		map->ts_node = of_parse_phandle(node, "touchscreen_phandle", 0);
   356		if (!map->ts_node) {
   357			dev_err(dev, "touchscreen_phandle node missing\n");
   358			return ERR_PTR(-ENODEV);
   359		}
   360	
   361		dev_info(dev, "Device_node name: %s\n", map->ts_node->name);
   362	
   363		i = 0;
   364		device_for_each_child_node(dev, child_node) {
   365			struct touchscreen_button *button;
   366	
   367			button = &map->buttons[i];
   368	
   369			fwnode_property_read_u32(child_node, "x-position", &button->x);
   370			fwnode_property_read_u32(child_node, "y-position", &button->y);
   371			fwnode_property_read_u32(child_node, "x-size", &button->width);
   372			fwnode_property_read_u32(child_node, "y-size", &button->height);
   373			fwnode_property_read_u32(child_node, "keycode", &button->keycode);
   374			dev_info(dev,
   375				 "Adding button at x=%u y=%u size %u x %u keycode=%u\n",
   376				 button->x, button->y, button->width, button->height, button->keycode);
   377			++i;
   378		}
   379		return map;
   380	}
   381	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 362e8a01980c..3d487b8e7d8b 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -318,6 +318,14 @@  config INPUT_CPCAP_PWRBUTTON
 	  To compile this driver as a module, choose M here. The module will
 	  be called cpcap-pwrbutton.
 
+config INPUT_TOUCHSCREEN_BUTTONS
+	tristate "Touchscreen Buttons"
+	help
+	  Say Y here if you want to enable buttons on touchscreen devices.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called touchscreen-buttons.
+
 config INPUT_WISTRON_BTNS
 	tristate "x86 Wistron laptop button interface"
 	depends on X86_32
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index a48e5f2d859d..18032a1b2a9c 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -84,4 +84,5 @@  obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)	+= xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
 obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR)	+= ideapad_slidebar.o
+obj-$(CONFIG_INPUT_TOUCHSCREEN_BUTTONS)	+= touchscreen-buttons.o
 
diff --git a/drivers/input/misc/touchscreen-buttons.c b/drivers/input/misc/touchscreen-buttons.c
new file mode 100644
index 000000000000..d7b912ce8ef1
--- /dev/null
+++ b/drivers/input/misc/touchscreen-buttons.c
@@ -0,0 +1,558 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/**
+ * Touchscreen Virutal Button Input Driver
+ *
+ * Copyright (C) 2020 Carl Klemm <carl@uvos.xyz>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/input/mt.h>
+#include <linux/device/bus.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+
+#define EVENT_QUEUE_SIZE 32
+
+struct touchscreen_button {
+	u32 x;
+	u32 y;
+	u32 width;
+	u32 height;
+	u32 keycode;
+	u8 depressed;
+};
+
+struct touchscreen_button_map {
+	struct touchscreen_button *buttons;
+	u32 count;
+	struct device_node *ts_node;
+};
+
+struct event {
+	unsigned int type;
+	unsigned int code;
+	int value;
+};
+
+struct event_queue {
+	struct event events[EVENT_QUEUE_SIZE];
+	unsigned int lastindex;
+};
+
+struct touchscreen_buttons {
+	struct device *dev;
+	struct input_dev *buttons_idev;
+	struct input_dev *filtered_ts_idev;
+	struct touchscreen_button_map *map;
+	struct input_handler *handler;
+	struct input_handle *ts_handle;
+	struct event_queue queue;
+	struct workqueue_struct *workqueue;
+	struct work_struct open_task;
+	struct work_struct close_task;
+	struct work_struct merge_task;
+	struct mutex mutex;
+};
+
+static const struct input_device_id touchscreen_buttons_ids[] = {
+	{
+	 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+	 .evbit = {BIT_MASK(EV_ABS)},
+	 },
+	{
+	 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+	 .evbit = {BIT_MASK(EV_KEY)},
+	 },
+	{
+	 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+	 .evbit = {BIT_MASK(EV_SYN)},
+	 },
+	{},
+};
+
+static int touchscreen_buttons_process_syn(const struct event_queue *queue,
+										   const struct touchscreen_button_map *map,
+										   struct input_dev *idev)
+{
+	u32 i;
+	int x, y, ret, pressed;
+
+	x = INT_MIN;
+	y = INT_MIN;
+	pressed = -1;
+	ret = 0;
+
+	for (i = 0; i < queue->lastindex; ++i) {
+		const struct event *ev;
+
+		ev = &queue->events[i];
+		if (ev->type == EV_ABS && ev->code == ABS_X)
+			x = ev->value;
+		else if (ev->type == EV_ABS && ev->code == ABS_Y)
+			y = ev->value;
+		else if (ev->type == EV_KEY && ev->code == BTN_TOUCH)
+			pressed = ev->value;
+	}
+
+	for (i = 0; i < map->count; ++i) {
+		struct touchscreen_button *button = &map->buttons[i];
+
+		if (pressed == 1 &&
+		    button->x <= x &&
+		    button->y <= y &&
+		    button->width + button->x >= x &&
+		    button->height + button->y >= y &&
+		    button->depressed == 0) {
+			input_report_key(idev, button->keycode, 1);
+			button->depressed = 1;
+			ret = 1;
+		} else if (button->depressed == 1) {
+			if (pressed == 0) {
+				input_report_key(idev, button->keycode, 0);
+				button->depressed = 0;
+			}
+			ret = 2;
+		}
+	}
+
+	if (ret != 0) {
+		input_event(idev, EV_SYN, SYN_REPORT, 0);
+	} else if (ret == 0) {
+		bool buttonpressed = false;
+
+		for (i = 0; i < map->count; ++i)
+			buttonpressed = buttonpressed || map->buttons[i].depressed;
+		if (buttonpressed)
+			ret = 3;
+	}
+
+	return ret;
+}
+
+static void touchscreen_buttons_resend_events(const struct event_queue *queue, struct input_dev *idev)
+{
+	u32 i;
+
+	for (i = 0; i < queue->lastindex; ++i)
+		input_event(idev, queue->events[i].type, queue->events[i].code, queue->events[i].value);
+	input_event(idev, EV_SYN, SYN_REPORT, 0);
+}
+
+static void touchscreen_buttons_copy_mt_slots(struct input_dev *target, struct input_dev *source)
+{
+	if (source->mt && target->mt && source->mt->num_slots == target->mt->num_slots) {
+		memcpy(target->mt->slots, source->mt->slots,
+		       sizeof(struct input_mt_slot) * source->mt->num_slots);
+	}
+}
+
+static void touchscreen_buttons_input_event(struct input_handle *handle,
+					    unsigned int type, unsigned int code, int value)
+{
+	struct touchscreen_buttons *buttons;
+
+	buttons = handle->private;
+
+	if (type == EV_SYN && code == SYN_REPORT) {
+		if (touchscreen_buttons_process_syn(&buttons->queue,
+			buttons->map, buttons->buttons_idev) == 0)
+			touchscreen_buttons_resend_events(&buttons->queue, buttons->filtered_ts_idev);
+		buttons->queue.lastindex = 0;
+	} else if (buttons->queue.lastindex < EVENT_QUEUE_SIZE && buttons->queue.lastindex >= 0) {
+		buttons->queue.events[buttons->queue.lastindex].type = type;
+		buttons->queue.events[buttons->queue.lastindex].code = code;
+		buttons->queue.events[buttons->queue.lastindex].value = value;
+		++buttons->queue.lastindex;
+	} else {
+		dev_warn(buttons->dev,
+			 "event_qeue overrun, will not capture events until next SYN_REPORT\n");
+	}
+}
+
+static void touchscreen_buttons_merge_capabilitys(struct input_dev *target, struct input_dev *source)
+{
+	unsigned int i;
+
+	mutex_lock(&target->mutex);
+	mutex_lock(&source->mutex);
+	for (i = 0; i < BITS_TO_LONGS(INPUT_PROP_CNT); ++i)
+		target->propbit[i] = target->propbit[i] | source->propbit[i];
+	for (i = 0; i < BITS_TO_LONGS(EV_CNT); ++i)
+		target->evbit[i] = target->evbit[i] | source->evbit[i];
+	for (i = 0; i < BITS_TO_LONGS(KEY_CNT); ++i)
+		target->keybit[i] = target->keybit[i] | source->keybit[i];
+	for (i = 0; i < BITS_TO_LONGS(REL_CNT); ++i)
+		target->relbit[i] = target->relbit[i] | source->relbit[i];
+	for (i = 0; i < BITS_TO_LONGS(ABS_CNT); ++i)
+		target->absbit[i] = target->absbit[i] | source->absbit[i];
+	for (i = 0; i < BITS_TO_LONGS(MSC_CNT); ++i)
+		target->mscbit[i] = target->mscbit[i] | source->mscbit[i];
+	for (i = 0; i < BITS_TO_LONGS(LED_CNT); ++i)
+		target->ledbit[i] = target->ledbit[i] | source->ledbit[i];
+	for (i = 0; i < BITS_TO_LONGS(SND_CNT); ++i)
+		target->sndbit[i] = target->sndbit[i] | source->sndbit[i];
+	for (i = 0; i < BITS_TO_LONGS(FF_CNT); ++i)
+		target->ffbit[i] = target->ffbit[i] | source->ffbit[i];
+	for (i = 0; i < BITS_TO_LONGS(SW_CNT); ++i)
+		target->swbit[i] = target->swbit[i] | source->swbit[i];
+
+	if (*source->evbit & (1 << EV_ABS)) {
+		input_alloc_absinfo(target);
+		for (i = 0; i < ABS_CNT; ++i)
+			target->absinfo[i] = source->absinfo[i];
+		if (source->mt) {
+			input_mt_init_slots(target, source->mt->num_slots, source->mt->flags);
+			touchscreen_buttons_copy_mt_slots(target, source);
+		}
+	}
+	mutex_unlock(&source->mutex);
+	mutex_unlock(&target->mutex);
+}
+
+void merge_task_handler(struct work_struct *work)
+{
+	struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, merge_task);
+
+	mutex_lock(&buttons->mutex);
+	if (buttons->ts_handle && buttons->ts_handle->dev)
+		touchscreen_buttons_merge_capabilitys(buttons->filtered_ts_idev, buttons->ts_handle->dev);
+	mutex_unlock(&buttons->mutex);
+}
+
+void close_task_handler(struct work_struct *work)
+{
+	struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, close_task);
+
+	mutex_lock(&buttons->mutex);
+	if (buttons && buttons->ts_handle && buttons->ts_handle->open != 0)
+		input_close_device(buttons->ts_handle);
+	mutex_unlock(&buttons->mutex);
+}
+
+void open_task_handler(struct work_struct *work)
+{
+	struct touchscreen_buttons *buttons = container_of(work, struct touchscreen_buttons, open_task);
+	int error;
+
+	mutex_lock(&buttons->mutex);
+	if (buttons && buttons->ts_handle) {
+		error = input_open_device(buttons->ts_handle);
+		if (error) {
+			dev_err(buttons->dev, "Failed to open input device, error %d\n", error);
+			input_unregister_handle(buttons->ts_handle);
+			kfree(buttons->ts_handle);
+			buttons->ts_handle = NULL;
+		}
+	}
+	mutex_unlock(&buttons->mutex);
+}
+
+static int touchscreen_buttons_input_connect(struct input_handler *handler,
+					     struct input_dev *dev, const struct input_device_id *id)
+{
+	struct touchscreen_buttons *buttons;
+
+	buttons = handler->private;
+
+	mutex_lock(&buttons->mutex);
+
+	if ((!buttons->ts_handle && device_match_of_node(&dev->dev, buttons->map->ts_node)) ||
+		(dev->dev.parent && device_match_of_node(dev->dev.parent, buttons->map->ts_node))) {
+		int error;
+
+		dev_info(buttons->dev, "Binding to device: %s\n", dev_name(&dev->dev));
+
+		buttons->ts_handle = kzalloc(sizeof(*buttons->ts_handle), GFP_KERNEL);
+		if (!buttons->ts_handle) {
+			mutex_unlock(&buttons->mutex);
+			return -ENOMEM;
+		}
+
+		buttons->ts_handle->dev = dev;
+		buttons->ts_handle->handler = handler;
+		buttons->ts_handle->name = "touchscreen-buttons";
+		buttons->ts_handle->private = handler->private;
+		buttons->queue.lastindex = 0;
+
+		error = input_register_handle(buttons->ts_handle);
+		if (error) {
+			dev_err(buttons->dev, "Failed to register input handler, error %d\n", error);
+			kfree(buttons->ts_handle);
+			buttons->ts_handle = NULL;
+			mutex_unlock(&buttons->mutex);
+			return error;
+		}
+
+		queue_work(buttons->workqueue, &buttons->merge_task);
+
+		if (buttons->filtered_ts_idev->users > 0 && buttons->ts_handle->open == 0)
+			queue_work(buttons->workqueue, &buttons->open_task);
+	}
+
+	mutex_unlock(&buttons->mutex);
+	return 0;
+}
+
+static void touchscreen_buttons_input_disconnect(struct input_handle *handle)
+{
+	struct touchscreen_buttons *buttons;
+
+	buttons = handle->private;
+
+	mutex_lock(&buttons->mutex);
+	if (handle == buttons->ts_handle) {
+		input_close_device(handle);
+		input_unregister_handle(handle);
+		kfree(handle);
+		buttons->ts_handle = NULL;
+		dev_info(buttons->dev, "Touchscreen device disconnected buttons disabled\n");
+	} else {
+		dev_err(buttons->dev, "Unknown device disconnected, %p should be %p", handle,
+			buttons->ts_handle);
+	}
+	mutex_unlock(&buttons->mutex);
+}
+
+static struct touchscreen_button_map
+*touchscreen_buttons_get_devtree_pdata(struct device *dev)
+{
+	struct touchscreen_button_map *map;
+	struct fwnode_handle *child_node;
+	struct device_node *node;
+	int i;
+
+	map = kzalloc(sizeof(*map), GFP_KERNEL);
+	if (!map)
+		return ERR_PTR(-ENOMEM);
+
+	map->count = device_get_child_node_count(dev);
+	if (map->count == 0)
+		return ERR_PTR(-ENODEV);
+
+	map->buttons = kcalloc(map->count, sizeof(*map->buttons), GFP_KERNEL);
+	if (!map->buttons)
+		return ERR_PTR(-ENOMEM);
+
+	node = dev->of_node;
+	map->ts_node = of_parse_phandle(node, "touchscreen_phandle", 0);
+	if (!map->ts_node) {
+		dev_err(dev, "touchscreen_phandle node missing\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	dev_info(dev, "Device_node name: %s\n", map->ts_node->name);
+
+	i = 0;
+	device_for_each_child_node(dev, child_node) {
+		struct touchscreen_button *button;
+
+		button = &map->buttons[i];
+
+		fwnode_property_read_u32(child_node, "x-position", &button->x);
+		fwnode_property_read_u32(child_node, "y-position", &button->y);
+		fwnode_property_read_u32(child_node, "x-size", &button->width);
+		fwnode_property_read_u32(child_node, "y-size", &button->height);
+		fwnode_property_read_u32(child_node, "keycode", &button->keycode);
+		dev_info(dev,
+			 "Adding button at x=%u y=%u size %u x %u keycode=%u\n",
+			 button->x, button->y, button->width, button->height, button->keycode);
+		++i;
+	}
+	return map;
+}
+
+int touchscreen_buttons_idev_opened(struct input_dev *idev)
+{
+	struct touchscreen_buttons *buttons;
+
+	buttons = dev_get_drvdata(idev->dev.parent);
+
+	mutex_lock(&buttons->mutex);
+	if (buttons && buttons->ts_handle) {
+		if (buttons->ts_handle->open == 0) {
+			queue_work(buttons->workqueue, &buttons->open_task);
+			dev_dbg(idev->dev.parent, "idev opened\n");
+		} else {
+			dev_info(idev->dev.parent, "idev allready opened\n");
+		}
+	} else {
+		dev_warn(idev->dev.parent,
+			 "Input device opend but touchscreen not opened. %p %p\n", buttons,
+			 buttons->ts_handle);
+	}
+	mutex_unlock(&buttons->mutex);
+	return 0;
+}
+
+void touchscreen_buttons_idev_closed(struct input_dev *idev)
+{
+	struct touchscreen_buttons *buttons;
+
+	buttons = dev_get_drvdata(idev->dev.parent);
+
+	mutex_lock(&buttons->mutex);
+	if (buttons && buttons->ts_handle && buttons->ts_handle->open != 0) {
+		queue_work(buttons->workqueue, &buttons->close_task);
+		dev_dbg(idev->dev.parent, "idev closed\n");
+	}
+	mutex_unlock(&buttons->mutex);
+}
+
+static int touchscreen_buttons_probe(struct platform_device *pdev)
+{
+	struct touchscreen_buttons *buttons;
+	int error, i;
+
+	buttons = kzalloc(sizeof(*buttons), GFP_KERNEL);
+	if (!buttons)
+		return -ENOMEM;
+
+	dev_set_drvdata(&pdev->dev, buttons);
+
+	buttons->workqueue = create_singlethread_workqueue("touchscreen-buttons-workqueue");
+	INIT_WORK(&buttons->merge_task, merge_task_handler);
+	INIT_WORK(&buttons->open_task, open_task_handler);
+	INIT_WORK(&buttons->close_task, close_task_handler);
+
+	mutex_init(&buttons->mutex);
+
+	buttons->queue.lastindex = 0;
+	buttons->dev = &pdev->dev;
+
+	buttons->map = touchscreen_buttons_get_devtree_pdata(&pdev->dev);
+	if (IS_ERR(buttons->map))
+		return PTR_ERR(buttons->map);
+
+	/*filtered touchscreen device */
+	buttons->filtered_ts_idev = input_allocate_device();
+	if (!buttons->filtered_ts_idev)
+		return -ENOMEM;
+	buttons->filtered_ts_idev->name = "Filtered Touchscreen";
+	buttons->filtered_ts_idev->phys = "touchscreen-buttons/input1";
+	buttons->filtered_ts_idev->dev.parent = buttons->dev;
+	buttons->filtered_ts_idev->open = touchscreen_buttons_idev_opened;
+	buttons->filtered_ts_idev->close = touchscreen_buttons_idev_closed;
+
+	/*buttons input device */
+	buttons->buttons_idev = input_allocate_device();
+	if (!buttons->buttons_idev)
+		return -ENOMEM;
+	buttons->buttons_idev->name = "Touchscreen Buttons";
+	buttons->buttons_idev->phys = "touchscreen-buttons/input0";
+	buttons->buttons_idev->dev.parent = buttons->dev;
+	for (i = 0; i < buttons->map->count; ++i)
+		input_set_capability(buttons->buttons_idev, EV_KEY, buttons->map->buttons[i].keycode);
+
+	/*handler for touchscreen input device */
+	buttons->handler = kzalloc(sizeof(*buttons->handler), GFP_KERNEL);
+
+	buttons->handler->event = touchscreen_buttons_input_event;
+	buttons->handler->connect = touchscreen_buttons_input_connect;
+	buttons->handler->disconnect = touchscreen_buttons_input_disconnect;
+	buttons->handler->name = "touchscreen-buttons";
+	buttons->handler->id_table = touchscreen_buttons_ids;
+	buttons->handler->private = buttons;
+
+	error = input_register_handler(buttons->handler);
+	if (error) {
+		dev_err(&pdev->dev, "Input handler register failed: %d\n", error);
+		return error;
+	}
+
+	error = input_register_device(buttons->buttons_idev);
+	if (error) {
+		dev_err(&pdev->dev, "Input device register failed: %d\n", error);
+		return error;
+	}
+
+	error = input_register_device(buttons->filtered_ts_idev);
+	if (error) {
+		dev_err(&pdev->dev, "Input device register failed: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int touchscreen_buttons_remove(struct platform_device *pdev)
+{
+	struct touchscreen_buttons *buttons;
+	struct input_handle *ts_handle;
+
+	buttons = dev_get_drvdata(&pdev->dev);
+
+	mutex_lock(&buttons->mutex);
+
+	ts_handle = buttons->ts_handle;
+
+	input_unregister_handler(buttons->handler);
+	if (buttons->ts_handle) {
+		if (buttons->ts_handle->open != 0)
+			input_close_device(buttons->ts_handle);
+		input_unregister_handle(buttons->ts_handle);
+		buttons->ts_handle = NULL;
+	}
+
+	mutex_unlock(&buttons->mutex);
+
+	flush_workqueue(buttons->workqueue);
+	destroy_workqueue(buttons->workqueue);
+
+	input_unregister_device(buttons->buttons_idev);
+	input_unregister_device(buttons->filtered_ts_idev);
+
+	kfree(ts_handle);
+
+	if (buttons->map) {
+		kfree(buttons->map->buttons);
+		kfree(buttons->map);
+	}
+	kfree(buttons->handler);
+
+	kfree(buttons);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id touchscreen_buttons_dt_match_table[] = {
+	{.compatible = "touchscreen-buttons"},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, touchscreen_buttons_dt_match_table);
+#endif
+
+static struct platform_driver touchscreen_buttons_driver = {
+	.probe = touchscreen_buttons_probe,
+	.remove = touchscreen_buttons_remove,
+	.driver = {
+		   .name = "touchscreen-buttons",
+		   .of_match_table = of_match_ptr(touchscreen_buttons_dt_match_table),
+		   },
+};
+
+module_platform_driver(touchscreen_buttons_driver);
+
+MODULE_ALIAS("platform:touchscreen-buttons");
+MODULE_DESCRIPTION("touchscreen-buttons");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Carl Klemm <carl@uvos.xyz>");