Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 449917de authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "input: misc: add support for virtual mouse"

parents d95e0fa5 2f37c307
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,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
+293 −0
Original line number Diff line number Diff line
/* 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);
+1 −0
Original line number Diff line number Diff line
@@ -143,6 +143,7 @@ header-y += genetlink.h
header-y += gfs2_ondisk.h
header-y += gigaset_dev.h
header-y += hbtp_input.h
header-y += hbtp_vm.h
header-y += hdlc.h
header-y += hdlcdrv.h
header-y += hdreg.h
+27 −0
Original line number Diff line number Diff line
#ifndef _HBTP_VM_H
#define _HBTP_VM_H

#include <linux/input.h>

struct hbtp_vm_click {
	int x;
	int y;
	int mask;
};

#define HBTP_VM_BUTTON_LEFT  0x00000001
#define HBTP_VM_BUTTON_RIGHT 0x00000002
#define HBTP_VM_BUTTON_DOWN  0x10000000
#define HBTP_VM_BUTTON_UP    0x20000000

/* ioctls */
#define HBTP_VM_IOCTL_BASE  'V'
#define HBTP_VM_ENABLE	        _IO(HBTP_VM_IOCTL_BASE, 200)
#define HBTP_VM_DISABLE	        _IO(HBTP_VM_IOCTL_BASE, 201)
#define HBTP_VM_SET_TOUCHDATA	_IOW(HBTP_INPUT_IOCTL_BASE, 202, \
					struct hbtp_input_mt)
#define HBTP_VM_SEND_CLICK      _IOW(HBTP_INPUT_IOCTL_BASE, 203, \
					struct hbtp_vm_click)

#endif	/* _HBTP_VM_H */