summaryrefslogtreecommitdiff
path: root/drivers/input/misc
diff options
context:
space:
mode:
authorMohan Pallaka <mpallaka@codeaurora.org>2015-03-13 16:20:15 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:58:02 -0700
commitd42befffb2fec4fd226c3c2d3ae332b1643586b3 (patch)
tree38c45dbf7d7f1b770d8db626c29e4417a0d676f7 /drivers/input/misc
parent8366ca71813ba9a97bfb3141863fab9a62e181bf (diff)
input: misc: add support for virtual mouse
Add input driver for virtual mouse feature. The events are received through ioctls and transfer them through input framework. Change-Id: I0842b49ec1c8c6bef3005d9f4419ab15e3abe024 Signed-off-by: Mohan Pallaka <mpallaka@codeaurora.org>
Diffstat (limited to 'drivers/input/misc')
-rw-r--r--drivers/input/misc/Makefile2
-rw-r--r--drivers/input/misc/hbtp_vm.c293
2 files changed, 294 insertions, 1 deletions
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index f6606c1526ab..4019f19dd848 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -35,7 +35,7 @@ obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
obj-$(CONFIG_INPUT_GPIO) += gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o
-obj-$(CONFIG_INPUT_HBTP_INPUT) += hbtp_input.o
+obj-$(CONFIG_INPUT_HBTP_INPUT) += hbtp_input.o hbtp_vm.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
diff --git a/drivers/input/misc/hbtp_vm.c b/drivers/input/misc/hbtp_vm.c
new file mode 100644
index 000000000000..408bf5d67b63
--- /dev/null
+++ b/drivers/input/misc/hbtp_vm.c
@@ -0,0 +1,293 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/input/mt.h>
+#include <uapi/linux/hbtp_input.h>
+#include <uapi/linux/hbtp_vm.h>
+
+#define hbtp_vm_name "hbtp_vm"
+
+struct hbtp_virtual_mouse {
+ struct input_dev *input_dev;
+ s32 open_count;
+ struct mutex mutex;
+ bool touch_status[HBTP_MAX_FINGER];
+
+ int enabled;
+ int last_x;
+ int last_y;
+ int parking_dist_x;
+};
+
+static struct hbtp_virtual_mouse *hbtp_vm;
+
+static int hbtp_vm_open(struct inode *inode, struct file *file)
+{
+ mutex_lock(&hbtp_vm->mutex);
+ if (hbtp_vm->open_count)
+ pr_debug("hbtp_vm was already opened\n");
+ hbtp_vm->open_count++;
+ mutex_unlock(&hbtp_vm->mutex);
+
+ return 0;
+}
+
+static int hbtp_vm_release(struct inode *inode, struct file *file)
+{
+ mutex_lock(&hbtp_vm->mutex);
+ if (!hbtp_vm->open_count) {
+ pr_err("%s wasn't opened\n", hbtp_vm_name);
+ mutex_unlock(&hbtp_vm->mutex);
+ return -ENOTTY;
+ }
+ hbtp_vm->open_count--;
+ mutex_unlock(&hbtp_vm->mutex);
+ return 0;
+}
+
+static int hbtp_vm_create_input_dev(void)
+{
+ struct input_dev *input_dev;
+ int error;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ pr_err("%s: input_allocate_device failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ kfree(input_dev->name);
+ input_dev->name = kstrndup(hbtp_vm_name, sizeof(hbtp_vm_name),
+ GFP_KERNEL);
+
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ __set_bit(EV_REL, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+ __set_bit(REL_HWHEEL, input_dev->relbit);
+
+ input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+
+ error = input_register_device(input_dev);
+ if (error) {
+ pr_err("%s: input_register_device failed\n", __func__);
+ goto err_input_reg_dev;
+ }
+
+ hbtp_vm->input_dev = input_dev;
+ return 0;
+
+err_input_reg_dev:
+ input_free_device(input_dev);
+ return error;
+}
+
+static int hbtp_vm_report_events(struct hbtp_virtual_mouse *hbtp_data,
+ struct hbtp_input_mt *mt_data)
+{
+ struct hbtp_input_touch *tch;
+ int dx = 0;
+ int dy = 0;
+
+ if (mt_data->num_touches > 1) {
+ pr_err("virtual mouse received multi touch reports\n");
+ return 0;
+ }
+
+ if (mt_data->num_touches == 1) {
+ tch = &(mt_data->touches[0]);
+ if (hbtp_vm->last_x != -1 && hbtp_vm->last_x != -1) {
+ dx = tch->x - hbtp_vm->last_x;
+ dy = tch->y - hbtp_vm->last_y;
+ }
+
+ if (!(dx == 0 && dy == 0)) {
+ input_report_rel(hbtp_vm->input_dev, REL_X, dx);
+ input_report_rel(hbtp_vm->input_dev, REL_Y, dy);
+ input_sync(hbtp_vm->input_dev);
+ }
+
+ hbtp_vm->last_x = tch->x;
+ hbtp_vm->last_y = tch->y;
+ } else {
+ hbtp_vm->last_x = -1;
+ hbtp_vm->last_y = -1;
+ }
+
+ return 0;
+}
+
+static int hbtp_vm_report_clicks(struct hbtp_virtual_mouse *hbtp_data,
+ struct hbtp_vm_click *click_data)
+{
+ unsigned int code = BTN_LEFT;
+ int value = 1;
+
+ if (click_data->mask & HBTP_VM_BUTTON_RIGHT)
+ code = BTN_RIGHT;
+
+ if (click_data->mask & HBTP_VM_BUTTON_UP)
+ value = 0;
+
+ input_report_key(hbtp_vm->input_dev, code, value);
+ input_sync(hbtp_vm->input_dev);
+
+ return 0;
+}
+
+static long hbtp_vm_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int error = 0;
+ struct hbtp_input_mt mt_data;
+ struct hbtp_vm_click clik_data;
+
+ if (!hbtp_vm) {
+ pr_err("%s: virtual mouse driver not initialized\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ switch (cmd) {
+ case HBTP_VM_ENABLE:
+ if (hbtp_vm->enabled) {
+ pr_err("virtual mouse device is already enabled\n");
+ return 0;
+ }
+ hbtp_vm->enabled = true;
+ input_report_rel(hbtp_vm->input_dev, REL_X, -2000);
+ input_report_rel(hbtp_vm->input_dev, REL_Y, -2000);
+ input_sync(hbtp_vm->input_dev);
+ input_report_rel(hbtp_vm->input_dev, REL_X, 100);
+ input_report_rel(hbtp_vm->input_dev, REL_Y, 100);
+ input_sync(hbtp_vm->input_dev);
+
+ break;
+
+ case HBTP_VM_DISABLE:
+ if (!hbtp_vm->enabled) {
+ pr_err("virtual mouse device is already disabled\n");
+ return 0;
+ }
+ hbtp_vm->enabled = false;
+ input_report_rel(hbtp_vm->input_dev, REL_X, 2000);
+ input_report_rel(hbtp_vm->input_dev, REL_Y, 2000);
+ input_sync(hbtp_vm->input_dev);
+ break;
+
+ case HBTP_VM_SET_TOUCHDATA:
+ if (!hbtp_vm->input_dev) {
+ pr_err("%s: virtual mouse input device hasn't been created\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&mt_data, (void *)arg,
+ sizeof(struct hbtp_input_mt))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+
+ hbtp_vm_report_events(hbtp_vm, &mt_data);
+ error = 0;
+ break;
+
+ case HBTP_VM_SEND_CLICK:
+ if (!hbtp_vm->input_dev) {
+ pr_err("%s: virtual mouse input device hasn't been created\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(&clik_data, (void *)arg,
+ sizeof(struct hbtp_vm_click))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+
+ hbtp_vm_report_clicks(hbtp_vm, &clik_data);
+ error = 0;
+ break;
+ default:
+ pr_err("%s: Unsupported ioctl command %u\n", __func__, cmd);
+ error = -EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+static const struct file_operations hbtp_vm_fops = {
+ .owner = THIS_MODULE,
+ .open = hbtp_vm_open,
+ .release = hbtp_vm_release,
+ .unlocked_ioctl = hbtp_vm_ioctl,
+ .compat_ioctl = hbtp_vm_ioctl,
+};
+
+static struct miscdevice hbtp_vm_misc = {
+ .fops = &hbtp_vm_fops,
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = hbtp_vm_name,
+};
+
+static int __init hbtp_vm_init(void)
+{
+ int error;
+
+ hbtp_vm = kzalloc(sizeof(struct hbtp_virtual_mouse), GFP_KERNEL);
+
+ if (!hbtp_vm)
+ return -ENOMEM;
+
+ hbtp_vm->last_x = -1;
+ hbtp_vm->last_y = -1;
+
+ mutex_init(&hbtp_vm->mutex);
+ error = misc_register(&hbtp_vm_misc);
+ if (error) {
+ pr_err("%s: misc_register failed\n", hbtp_vm_name);
+ goto err_misc_reg;
+ }
+
+ hbtp_vm_create_input_dev();
+ return 0;
+
+err_misc_reg:
+ kfree(hbtp_vm);
+ return error;
+}
+
+static void __exit hbtp_vm_exit(void)
+{
+ misc_deregister(&hbtp_vm_misc);
+ if (hbtp_vm->input_dev) {
+ input_unregister_device(hbtp_vm->input_dev);
+ hbtp_vm->input_dev = NULL;
+ }
+ kfree(hbtp_vm);
+}
+
+MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR);
+MODULE_ALIAS("devname:" hbtp_vm_name);
+MODULE_DESCRIPTION("kernel module to support virtual mouse");
+MODULE_LICENSE("GPL v2");
+module_init(hbtp_vm_init);
+module_exit(hbtp_vm_exit);