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

hampshire.c (4631B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Hampshire serial touchscreen driver
      4 *
      5 * Copyright (c) 2010 Adam Bennett
      6 * Based on the dynapro driver (c) Tias Guns
      7 */
      8
      9
     10/*
     11 * 2010/04/08 Adam Bennett <abennett72@gmail.com>
     12 *   Copied dynapro.c and edited for Hampshire 4-byte protocol
     13 */
     14
     15#include <linux/errno.h>
     16#include <linux/kernel.h>
     17#include <linux/module.h>
     18#include <linux/slab.h>
     19#include <linux/input.h>
     20#include <linux/serio.h>
     21
     22#define DRIVER_DESC	"Hampshire serial touchscreen driver"
     23
     24MODULE_AUTHOR("Adam Bennett <abennett72@gmail.com>");
     25MODULE_DESCRIPTION(DRIVER_DESC);
     26MODULE_LICENSE("GPL");
     27
     28/*
     29 * Definitions & global arrays.
     30 */
     31
     32#define HAMPSHIRE_FORMAT_TOUCH_BIT 0x40
     33#define HAMPSHIRE_FORMAT_LENGTH 4
     34#define HAMPSHIRE_RESPONSE_BEGIN_BYTE 0x80
     35
     36#define HAMPSHIRE_MIN_XC 0
     37#define HAMPSHIRE_MAX_XC 0x1000
     38#define HAMPSHIRE_MIN_YC 0
     39#define HAMPSHIRE_MAX_YC 0x1000
     40
     41#define HAMPSHIRE_GET_XC(data) (((data[3] & 0x0c) >> 2) | (data[1] << 2) | ((data[0] & 0x38) << 6))
     42#define HAMPSHIRE_GET_YC(data) ((data[3] & 0x03) | (data[2] << 2) | ((data[0] & 0x07) << 9))
     43#define HAMPSHIRE_GET_TOUCHED(data) (HAMPSHIRE_FORMAT_TOUCH_BIT & data[0])
     44
     45/*
     46 * Per-touchscreen data.
     47 */
     48
     49struct hampshire {
     50	struct input_dev *dev;
     51	struct serio *serio;
     52	int idx;
     53	unsigned char data[HAMPSHIRE_FORMAT_LENGTH];
     54	char phys[32];
     55};
     56
     57static void hampshire_process_data(struct hampshire *phampshire)
     58{
     59	struct input_dev *dev = phampshire->dev;
     60
     61	if (HAMPSHIRE_FORMAT_LENGTH == ++phampshire->idx) {
     62		input_report_abs(dev, ABS_X, HAMPSHIRE_GET_XC(phampshire->data));
     63		input_report_abs(dev, ABS_Y, HAMPSHIRE_GET_YC(phampshire->data));
     64		input_report_key(dev, BTN_TOUCH,
     65				 HAMPSHIRE_GET_TOUCHED(phampshire->data));
     66		input_sync(dev);
     67
     68		phampshire->idx = 0;
     69	}
     70}
     71
     72static irqreturn_t hampshire_interrupt(struct serio *serio,
     73		unsigned char data, unsigned int flags)
     74{
     75	struct hampshire *phampshire = serio_get_drvdata(serio);
     76
     77	phampshire->data[phampshire->idx] = data;
     78
     79	if (HAMPSHIRE_RESPONSE_BEGIN_BYTE & phampshire->data[0])
     80		hampshire_process_data(phampshire);
     81	else
     82		dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
     83			phampshire->data[0]);
     84
     85	return IRQ_HANDLED;
     86}
     87
     88static void hampshire_disconnect(struct serio *serio)
     89{
     90	struct hampshire *phampshire = serio_get_drvdata(serio);
     91
     92	input_get_device(phampshire->dev);
     93	input_unregister_device(phampshire->dev);
     94	serio_close(serio);
     95	serio_set_drvdata(serio, NULL);
     96	input_put_device(phampshire->dev);
     97	kfree(phampshire);
     98}
     99
    100/*
    101 * hampshire_connect() is the routine that is called when someone adds a
    102 * new serio device that supports hampshire protocol and registers it as
    103 * an input device. This is usually accomplished using inputattach.
    104 */
    105
    106static int hampshire_connect(struct serio *serio, struct serio_driver *drv)
    107{
    108	struct hampshire *phampshire;
    109	struct input_dev *input_dev;
    110	int err;
    111
    112	phampshire = kzalloc(sizeof(struct hampshire), GFP_KERNEL);
    113	input_dev = input_allocate_device();
    114	if (!phampshire || !input_dev) {
    115		err = -ENOMEM;
    116		goto fail1;
    117	}
    118
    119	phampshire->serio = serio;
    120	phampshire->dev = input_dev;
    121	snprintf(phampshire->phys, sizeof(phampshire->phys),
    122		 "%s/input0", serio->phys);
    123
    124	input_dev->name = "Hampshire Serial TouchScreen";
    125	input_dev->phys = phampshire->phys;
    126	input_dev->id.bustype = BUS_RS232;
    127	input_dev->id.vendor = SERIO_HAMPSHIRE;
    128	input_dev->id.product = 0;
    129	input_dev->id.version = 0x0001;
    130	input_dev->dev.parent = &serio->dev;
    131	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    132	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    133	input_set_abs_params(phampshire->dev, ABS_X,
    134			     HAMPSHIRE_MIN_XC, HAMPSHIRE_MAX_XC, 0, 0);
    135	input_set_abs_params(phampshire->dev, ABS_Y,
    136			     HAMPSHIRE_MIN_YC, HAMPSHIRE_MAX_YC, 0, 0);
    137
    138	serio_set_drvdata(serio, phampshire);
    139
    140	err = serio_open(serio, drv);
    141	if (err)
    142		goto fail2;
    143
    144	err = input_register_device(phampshire->dev);
    145	if (err)
    146		goto fail3;
    147
    148	return 0;
    149
    150 fail3:	serio_close(serio);
    151 fail2:	serio_set_drvdata(serio, NULL);
    152 fail1:	input_free_device(input_dev);
    153	kfree(phampshire);
    154	return err;
    155}
    156
    157/*
    158 * The serio driver structure.
    159 */
    160
    161static const struct serio_device_id hampshire_serio_ids[] = {
    162	{
    163		.type	= SERIO_RS232,
    164		.proto	= SERIO_HAMPSHIRE,
    165		.id	= SERIO_ANY,
    166		.extra	= SERIO_ANY,
    167	},
    168	{ 0 }
    169};
    170
    171MODULE_DEVICE_TABLE(serio, hampshire_serio_ids);
    172
    173static struct serio_driver hampshire_drv = {
    174	.driver		= {
    175		.name	= "hampshire",
    176	},
    177	.description	= DRIVER_DESC,
    178	.id_table	= hampshire_serio_ids,
    179	.interrupt	= hampshire_interrupt,
    180	.connect	= hampshire_connect,
    181	.disconnect	= hampshire_disconnect,
    182};
    183
    184module_serio_driver(hampshire_drv);