cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gpio_mouse.c (4740B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Driver for simulating a mouse on GPIO lines.
      4 *
      5 * Copyright (C) 2007 Atmel Corporation
      6 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/platform_device.h>
     11#include <linux/input.h>
     12#include <linux/gpio/consumer.h>
     13#include <linux/property.h>
     14#include <linux/of.h>
     15
     16/**
     17 * struct gpio_mouse
     18 * @scan_ms: the scan interval in milliseconds.
     19 * @up: GPIO line for up value.
     20 * @down: GPIO line for down value.
     21 * @left: GPIO line for left value.
     22 * @right: GPIO line for right value.
     23 * @bleft: GPIO line for left button.
     24 * @bmiddle: GPIO line for middle button.
     25 * @bright: GPIO line for right button.
     26 *
     27 * This struct must be added to the platform_device in the board code.
     28 * It is used by the gpio_mouse driver to setup GPIO lines and to
     29 * calculate mouse movement.
     30 */
     31struct gpio_mouse {
     32	u32 scan_ms;
     33	struct gpio_desc *up;
     34	struct gpio_desc *down;
     35	struct gpio_desc *left;
     36	struct gpio_desc *right;
     37	struct gpio_desc *bleft;
     38	struct gpio_desc *bmiddle;
     39	struct gpio_desc *bright;
     40};
     41
     42/*
     43 * Timer function which is run every scan_ms ms when the device is opened.
     44 * The dev input variable is set to the the input_dev pointer.
     45 */
     46static void gpio_mouse_scan(struct input_dev *input)
     47{
     48	struct gpio_mouse *gpio = input_get_drvdata(input);
     49	int x, y;
     50
     51	if (gpio->bleft)
     52		input_report_key(input, BTN_LEFT,
     53				 gpiod_get_value(gpio->bleft));
     54	if (gpio->bmiddle)
     55		input_report_key(input, BTN_MIDDLE,
     56				 gpiod_get_value(gpio->bmiddle));
     57	if (gpio->bright)
     58		input_report_key(input, BTN_RIGHT,
     59				 gpiod_get_value(gpio->bright));
     60
     61	x = gpiod_get_value(gpio->right) - gpiod_get_value(gpio->left);
     62	y = gpiod_get_value(gpio->down) - gpiod_get_value(gpio->up);
     63
     64	input_report_rel(input, REL_X, x);
     65	input_report_rel(input, REL_Y, y);
     66	input_sync(input);
     67}
     68
     69static int gpio_mouse_probe(struct platform_device *pdev)
     70{
     71	struct device *dev = &pdev->dev;
     72	struct gpio_mouse *gmouse;
     73	struct input_dev *input;
     74	int error;
     75
     76	gmouse = devm_kzalloc(dev, sizeof(*gmouse), GFP_KERNEL);
     77	if (!gmouse)
     78		return -ENOMEM;
     79
     80	/* Assign some default scanning time */
     81	error = device_property_read_u32(dev, "scan-interval-ms",
     82					 &gmouse->scan_ms);
     83	if (error || gmouse->scan_ms == 0) {
     84		dev_warn(dev, "invalid scan time, set to 50 ms\n");
     85		gmouse->scan_ms = 50;
     86	}
     87
     88	gmouse->up = devm_gpiod_get(dev, "up", GPIOD_IN);
     89	if (IS_ERR(gmouse->up))
     90		return PTR_ERR(gmouse->up);
     91	gmouse->down = devm_gpiod_get(dev, "down", GPIOD_IN);
     92	if (IS_ERR(gmouse->down))
     93		return PTR_ERR(gmouse->down);
     94	gmouse->left = devm_gpiod_get(dev, "left", GPIOD_IN);
     95	if (IS_ERR(gmouse->left))
     96		return PTR_ERR(gmouse->left);
     97	gmouse->right = devm_gpiod_get(dev, "right", GPIOD_IN);
     98	if (IS_ERR(gmouse->right))
     99		return PTR_ERR(gmouse->right);
    100
    101	gmouse->bleft = devm_gpiod_get_optional(dev, "button-left", GPIOD_IN);
    102	if (IS_ERR(gmouse->bleft))
    103		return PTR_ERR(gmouse->bleft);
    104	gmouse->bmiddle = devm_gpiod_get_optional(dev, "button-middle",
    105						  GPIOD_IN);
    106	if (IS_ERR(gmouse->bmiddle))
    107		return PTR_ERR(gmouse->bmiddle);
    108	gmouse->bright = devm_gpiod_get_optional(dev, "button-right",
    109						 GPIOD_IN);
    110	if (IS_ERR(gmouse->bright))
    111		return PTR_ERR(gmouse->bright);
    112
    113	input = devm_input_allocate_device(dev);
    114	if (!input)
    115		return -ENOMEM;
    116
    117	input->name = pdev->name;
    118	input->id.bustype = BUS_HOST;
    119
    120	input_set_drvdata(input, gmouse);
    121
    122	input_set_capability(input, EV_REL, REL_X);
    123	input_set_capability(input, EV_REL, REL_Y);
    124	if (gmouse->bleft)
    125		input_set_capability(input, EV_KEY, BTN_LEFT);
    126	if (gmouse->bmiddle)
    127		input_set_capability(input, EV_KEY, BTN_MIDDLE);
    128	if (gmouse->bright)
    129		input_set_capability(input, EV_KEY, BTN_RIGHT);
    130
    131	error = input_setup_polling(input, gpio_mouse_scan);
    132	if (error)
    133		return error;
    134
    135	input_set_poll_interval(input, gmouse->scan_ms);
    136
    137	error = input_register_device(input);
    138	if (error) {
    139		dev_err(dev, "could not register input device\n");
    140		return error;
    141	}
    142
    143	dev_dbg(dev, "%d ms scan time, buttons: %s%s%s\n",
    144		gmouse->scan_ms,
    145		gmouse->bleft ? "" : "left ",
    146		gmouse->bmiddle ? "" : "middle ",
    147		gmouse->bright ? "" : "right");
    148
    149	return 0;
    150}
    151
    152static const struct of_device_id gpio_mouse_of_match[] = {
    153	{ .compatible = "gpio-mouse", },
    154	{ },
    155};
    156MODULE_DEVICE_TABLE(of, gpio_mouse_of_match);
    157
    158static struct platform_driver gpio_mouse_device_driver = {
    159	.probe		= gpio_mouse_probe,
    160	.driver		= {
    161		.name	= "gpio_mouse",
    162		.of_match_table = gpio_mouse_of_match,
    163	}
    164};
    165module_platform_driver(gpio_mouse_device_driver);
    166
    167MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
    168MODULE_DESCRIPTION("GPIO mouse driver");
    169MODULE_LICENSE("GPL");
    170MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */