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

penmount.c (6915B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Penmount serial touchscreen driver
      4 *
      5 * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
      6 * Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
      7 *
      8 * Based on ELO driver (drivers/input/touchscreen/elo.c)
      9 * Copyright (c) 2004 Vojtech Pavlik
     10 */
     11
     12
     13#include <linux/errno.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/slab.h>
     17#include <linux/input.h>
     18#include <linux/input/mt.h>
     19#include <linux/serio.h>
     20
     21#define DRIVER_DESC	"PenMount serial touchscreen driver"
     22
     23MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
     24MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
     25MODULE_DESCRIPTION(DRIVER_DESC);
     26MODULE_LICENSE("GPL");
     27
     28/*
     29 * Definitions & global arrays.
     30 */
     31
     32#define	PM_MAX_LENGTH	6
     33#define	PM_MAX_MTSLOT	16
     34#define	PM_3000_MTSLOT	2
     35#define	PM_6250_MTSLOT	12
     36
     37/*
     38 * Multi-touch slot
     39 */
     40
     41struct mt_slot {
     42	unsigned short x, y;
     43	bool active; /* is the touch valid? */
     44};
     45
     46/*
     47 * Per-touchscreen data.
     48 */
     49
     50struct pm {
     51	struct input_dev *dev;
     52	struct serio *serio;
     53	int idx;
     54	unsigned char data[PM_MAX_LENGTH];
     55	char phys[32];
     56	unsigned char packetsize;
     57	unsigned char maxcontacts;
     58	struct mt_slot slots[PM_MAX_MTSLOT];
     59	void (*parse_packet)(struct pm *);
     60};
     61
     62/*
     63 * pm_mtevent() sends mt events and also emulates pointer movement
     64 */
     65
     66static void pm_mtevent(struct pm *pm, struct input_dev *input)
     67{
     68	int i;
     69
     70	for (i = 0; i < pm->maxcontacts; ++i) {
     71		input_mt_slot(input, i);
     72		input_mt_report_slot_state(input, MT_TOOL_FINGER,
     73				pm->slots[i].active);
     74		if (pm->slots[i].active) {
     75			input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x);
     76			input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y);
     77		}
     78	}
     79
     80	input_mt_report_pointer_emulation(input, true);
     81	input_sync(input);
     82}
     83
     84/*
     85 * pm_checkpacket() checks if data packet is valid
     86 */
     87
     88static bool pm_checkpacket(unsigned char *packet)
     89{
     90	int total = 0;
     91	int i;
     92
     93	for (i = 0; i < 5; i++)
     94		total += packet[i];
     95
     96	return packet[5] == (unsigned char)~(total & 0xff);
     97}
     98
     99static void pm_parse_9000(struct pm *pm)
    100{
    101	struct input_dev *dev = pm->dev;
    102
    103	if ((pm->data[0] & 0x80) && pm->packetsize == ++pm->idx) {
    104		input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]);
    105		input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]);
    106		input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
    107		input_sync(dev);
    108		pm->idx = 0;
    109	}
    110}
    111
    112static void pm_parse_6000(struct pm *pm)
    113{
    114	struct input_dev *dev = pm->dev;
    115
    116	if ((pm->data[0] & 0xbf) == 0x30 && pm->packetsize == ++pm->idx) {
    117		if (pm_checkpacket(pm->data)) {
    118			input_report_abs(dev, ABS_X,
    119					pm->data[2] * 256 + pm->data[1]);
    120			input_report_abs(dev, ABS_Y,
    121					pm->data[4] * 256 + pm->data[3]);
    122			input_report_key(dev, BTN_TOUCH, pm->data[0] & 0x40);
    123			input_sync(dev);
    124		}
    125		pm->idx = 0;
    126	}
    127}
    128
    129static void pm_parse_3000(struct pm *pm)
    130{
    131	struct input_dev *dev = pm->dev;
    132
    133	if ((pm->data[0] & 0xce) == 0x40 && pm->packetsize == ++pm->idx) {
    134		if (pm_checkpacket(pm->data)) {
    135			int slotnum = pm->data[0] & 0x0f;
    136			pm->slots[slotnum].active = pm->data[0] & 0x30;
    137			pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
    138			pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
    139			pm_mtevent(pm, dev);
    140		}
    141		pm->idx = 0;
    142	}
    143}
    144
    145static void pm_parse_6250(struct pm *pm)
    146{
    147	struct input_dev *dev = pm->dev;
    148
    149	if ((pm->data[0] & 0xb0) == 0x30 && pm->packetsize == ++pm->idx) {
    150		if (pm_checkpacket(pm->data)) {
    151			int slotnum = pm->data[0] & 0x0f;
    152			pm->slots[slotnum].active = pm->data[0] & 0x40;
    153			pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
    154			pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
    155			pm_mtevent(pm, dev);
    156		}
    157		pm->idx = 0;
    158	}
    159}
    160
    161static irqreturn_t pm_interrupt(struct serio *serio,
    162		unsigned char data, unsigned int flags)
    163{
    164	struct pm *pm = serio_get_drvdata(serio);
    165
    166	pm->data[pm->idx] = data;
    167
    168	pm->parse_packet(pm);
    169
    170	return IRQ_HANDLED;
    171}
    172
    173/*
    174 * pm_disconnect() is the opposite of pm_connect()
    175 */
    176
    177static void pm_disconnect(struct serio *serio)
    178{
    179	struct pm *pm = serio_get_drvdata(serio);
    180
    181	serio_close(serio);
    182
    183	input_unregister_device(pm->dev);
    184	kfree(pm);
    185
    186	serio_set_drvdata(serio, NULL);
    187}
    188
    189/*
    190 * pm_connect() is the routine that is called when someone adds a
    191 * new serio device that supports PenMount protocol and registers it as
    192 * an input device.
    193 */
    194
    195static int pm_connect(struct serio *serio, struct serio_driver *drv)
    196{
    197	struct pm *pm;
    198	struct input_dev *input_dev;
    199	int max_x, max_y;
    200	int err;
    201
    202	pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
    203	input_dev = input_allocate_device();
    204	if (!pm || !input_dev) {
    205		err = -ENOMEM;
    206		goto fail1;
    207	}
    208
    209	pm->serio = serio;
    210	pm->dev = input_dev;
    211	snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
    212	pm->maxcontacts = 1;
    213
    214	input_dev->name = "PenMount Serial TouchScreen";
    215	input_dev->phys = pm->phys;
    216	input_dev->id.bustype = BUS_RS232;
    217	input_dev->id.vendor = SERIO_PENMOUNT;
    218	input_dev->id.product = 0;
    219	input_dev->id.version = 0x0100;
    220	input_dev->dev.parent = &serio->dev;
    221
    222	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    223	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    224
    225	switch (serio->id.id) {
    226	default:
    227	case 0:
    228		pm->packetsize = 5;
    229		pm->parse_packet = pm_parse_9000;
    230		input_dev->id.product = 0x9000;
    231		max_x = max_y = 0x3ff;
    232		break;
    233
    234	case 1:
    235		pm->packetsize = 6;
    236		pm->parse_packet = pm_parse_6000;
    237		input_dev->id.product = 0x6000;
    238		max_x = max_y = 0x3ff;
    239		break;
    240
    241	case 2:
    242		pm->packetsize = 6;
    243		pm->parse_packet = pm_parse_3000;
    244		input_dev->id.product = 0x3000;
    245		max_x = max_y = 0x7ff;
    246		pm->maxcontacts = PM_3000_MTSLOT;
    247		break;
    248
    249	case 3:
    250		pm->packetsize = 6;
    251		pm->parse_packet = pm_parse_6250;
    252		input_dev->id.product = 0x6250;
    253		max_x = max_y = 0x3ff;
    254		pm->maxcontacts = PM_6250_MTSLOT;
    255		break;
    256	}
    257
    258	input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0);
    259	input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
    260
    261	if (pm->maxcontacts > 1) {
    262		input_mt_init_slots(pm->dev, pm->maxcontacts, 0);
    263		input_set_abs_params(pm->dev,
    264				     ABS_MT_POSITION_X, 0, max_x, 0, 0);
    265		input_set_abs_params(pm->dev,
    266				     ABS_MT_POSITION_Y, 0, max_y, 0, 0);
    267	}
    268
    269	serio_set_drvdata(serio, pm);
    270
    271	err = serio_open(serio, drv);
    272	if (err)
    273		goto fail2;
    274
    275	err = input_register_device(pm->dev);
    276	if (err)
    277		goto fail3;
    278
    279	return 0;
    280
    281 fail3:	serio_close(serio);
    282 fail2:	serio_set_drvdata(serio, NULL);
    283 fail1:	input_free_device(input_dev);
    284	kfree(pm);
    285	return err;
    286}
    287
    288/*
    289 * The serio driver structure.
    290 */
    291
    292static const struct serio_device_id pm_serio_ids[] = {
    293	{
    294		.type	= SERIO_RS232,
    295		.proto	= SERIO_PENMOUNT,
    296		.id	= SERIO_ANY,
    297		.extra	= SERIO_ANY,
    298	},
    299	{ 0 }
    300};
    301
    302MODULE_DEVICE_TABLE(serio, pm_serio_ids);
    303
    304static struct serio_driver pm_drv = {
    305	.driver		= {
    306		.name	= "serio-penmount",
    307	},
    308	.description	= DRIVER_DESC,
    309	.id_table	= pm_serio_ids,
    310	.interrupt	= pm_interrupt,
    311	.connect	= pm_connect,
    312	.disconnect	= pm_disconnect,
    313};
    314
    315module_serio_driver(pm_drv);