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

sermouse.c (8010B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) 1999-2001 Vojtech Pavlik
      4 */
      5
      6/*
      7 *  Serial mouse driver for Linux
      8 */
      9
     10/*
     11 */
     12
     13#include <linux/delay.h>
     14#include <linux/module.h>
     15#include <linux/slab.h>
     16#include <linux/interrupt.h>
     17#include <linux/input.h>
     18#include <linux/serio.h>
     19
     20#define DRIVER_DESC	"Serial mouse driver"
     21
     22MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
     23MODULE_DESCRIPTION(DRIVER_DESC);
     24MODULE_LICENSE("GPL");
     25
     26static const char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
     27					"Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
     28					"Logitech MZ++ Mouse"};
     29
     30struct sermouse {
     31	struct input_dev *dev;
     32	signed char buf[8];
     33	unsigned char count;
     34	unsigned char type;
     35	unsigned long last;
     36	char phys[32];
     37};
     38
     39/*
     40 * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and
     41 * applies some prediction to the data, resulting in 96 updates per
     42 * second, which is as good as a PS/2 or USB mouse.
     43 */
     44
     45static void sermouse_process_msc(struct sermouse *sermouse, signed char data)
     46{
     47	struct input_dev *dev = sermouse->dev;
     48	signed char *buf = sermouse->buf;
     49
     50	switch (sermouse->count) {
     51
     52		case 0:
     53			if ((data & 0xf8) != 0x80)
     54				return;
     55			input_report_key(dev, BTN_LEFT,   !(data & 4));
     56			input_report_key(dev, BTN_RIGHT,  !(data & 1));
     57			input_report_key(dev, BTN_MIDDLE, !(data & 2));
     58			break;
     59
     60		case 1:
     61		case 3:
     62			input_report_rel(dev, REL_X, data / 2);
     63			input_report_rel(dev, REL_Y, -buf[1]);
     64			buf[0] = data - data / 2;
     65			break;
     66
     67		case 2:
     68		case 4:
     69			input_report_rel(dev, REL_X, buf[0]);
     70			input_report_rel(dev, REL_Y, buf[1] - data);
     71			buf[1] = data / 2;
     72			break;
     73	}
     74
     75	input_sync(dev);
     76
     77	if (++sermouse->count == 5)
     78		sermouse->count = 0;
     79}
     80
     81/*
     82 * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and
     83 * generates events. With prediction it gets 80 updates/sec, assuming
     84 * standard 3-byte packets and 1200 bps.
     85 */
     86
     87static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
     88{
     89	struct input_dev *dev = sermouse->dev;
     90	signed char *buf = sermouse->buf;
     91
     92	if (data & 0x40)
     93		sermouse->count = 0;
     94	else if (sermouse->count == 0)
     95		return;
     96
     97	switch (sermouse->count) {
     98
     99		case 0:
    100			buf[1] = data;
    101			input_report_key(dev, BTN_LEFT,   (data >> 5) & 1);
    102			input_report_key(dev, BTN_RIGHT,  (data >> 4) & 1);
    103			break;
    104
    105		case 1:
    106			buf[2] = data;
    107			data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f));
    108			input_report_rel(dev, REL_X, data / 2);
    109			input_report_rel(dev, REL_Y, buf[4]);
    110			buf[3] = data - data / 2;
    111			break;
    112
    113		case 2:
    114			/* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */
    115			if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1]))
    116				input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key));
    117			buf[0] = buf[1];
    118
    119			data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f));
    120			input_report_rel(dev, REL_X, buf[3]);
    121			input_report_rel(dev, REL_Y, data - buf[4]);
    122			buf[4] = data / 2;
    123			break;
    124
    125		case 3:
    126
    127			switch (sermouse->type) {
    128
    129				case SERIO_MS:
    130					sermouse->type = SERIO_MP;
    131					fallthrough;
    132
    133				case SERIO_MP:
    134					if ((data >> 2) & 3) break;	/* M++ Wireless Extension packet. */
    135					input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1);
    136					input_report_key(dev, BTN_SIDE,   (data >> 4) & 1);
    137					break;
    138
    139				case SERIO_MZP:
    140				case SERIO_MZPP:
    141					input_report_key(dev, BTN_SIDE,   (data >> 5) & 1);
    142					fallthrough;
    143
    144				case SERIO_MZ:
    145					input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
    146					input_report_rel(dev, REL_WHEEL,  (data & 8) - (data & 7));
    147					break;
    148			}
    149
    150			break;
    151
    152		case 4:
    153		case 6:	/* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */
    154			buf[1] = (data >> 2) & 0x0f;
    155			break;
    156
    157		case 5:
    158		case 7: /* Ignore anything besides MZ++ */
    159			if (sermouse->type != SERIO_MZPP)
    160				break;
    161
    162			switch (buf[1]) {
    163
    164				case 1: /* Extra mouse info */
    165
    166					input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
    167					input_report_key(dev, BTN_EXTRA, (data >> 5) & 1);
    168					input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8));
    169
    170					break;
    171
    172				default: /* We don't decode anything else yet. */
    173
    174					printk(KERN_WARNING
    175						"sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]);
    176					break;
    177			}
    178
    179			break;
    180	}
    181
    182	input_sync(dev);
    183
    184	sermouse->count++;
    185}
    186
    187/*
    188 * sermouse_interrupt() handles incoming characters, either gathering them into
    189 * packets or passing them to the command routine as command output.
    190 */
    191
    192static irqreturn_t sermouse_interrupt(struct serio *serio,
    193		unsigned char data, unsigned int flags)
    194{
    195	struct sermouse *sermouse = serio_get_drvdata(serio);
    196
    197	if (time_after(jiffies, sermouse->last + HZ/10))
    198		sermouse->count = 0;
    199
    200	sermouse->last = jiffies;
    201
    202	if (sermouse->type > SERIO_SUN)
    203		sermouse_process_ms(sermouse, data);
    204	else
    205		sermouse_process_msc(sermouse, data);
    206
    207	return IRQ_HANDLED;
    208}
    209
    210/*
    211 * sermouse_disconnect() cleans up after we don't want talk
    212 * to the mouse anymore.
    213 */
    214
    215static void sermouse_disconnect(struct serio *serio)
    216{
    217	struct sermouse *sermouse = serio_get_drvdata(serio);
    218
    219	serio_close(serio);
    220	serio_set_drvdata(serio, NULL);
    221	input_unregister_device(sermouse->dev);
    222	kfree(sermouse);
    223}
    224
    225/*
    226 * sermouse_connect() is a callback form the serio module when
    227 * an unhandled serio port is found.
    228 */
    229
    230static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
    231{
    232	struct sermouse *sermouse;
    233	struct input_dev *input_dev;
    234	unsigned char c = serio->id.extra;
    235	int err = -ENOMEM;
    236
    237	sermouse = kzalloc(sizeof(struct sermouse), GFP_KERNEL);
    238	input_dev = input_allocate_device();
    239	if (!sermouse || !input_dev)
    240		goto fail1;
    241
    242	sermouse->dev = input_dev;
    243	snprintf(sermouse->phys, sizeof(sermouse->phys), "%s/input0", serio->phys);
    244	sermouse->type = serio->id.proto;
    245
    246	input_dev->name = sermouse_protocols[sermouse->type];
    247	input_dev->phys = sermouse->phys;
    248	input_dev->id.bustype = BUS_RS232;
    249	input_dev->id.vendor  = sermouse->type;
    250	input_dev->id.product = c;
    251	input_dev->id.version = 0x0100;
    252	input_dev->dev.parent = &serio->dev;
    253
    254	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
    255	input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
    256		BIT_MASK(BTN_RIGHT);
    257	input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
    258
    259	if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit);
    260	if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit);
    261	if (c & 0x04) set_bit(BTN_EXTRA, input_dev->keybit);
    262	if (c & 0x10) set_bit(REL_WHEEL, input_dev->relbit);
    263	if (c & 0x20) set_bit(REL_HWHEEL, input_dev->relbit);
    264
    265	serio_set_drvdata(serio, sermouse);
    266
    267	err = serio_open(serio, drv);
    268	if (err)
    269		goto fail2;
    270
    271	err = input_register_device(sermouse->dev);
    272	if (err)
    273		goto fail3;
    274
    275	return 0;
    276
    277 fail3:	serio_close(serio);
    278 fail2:	serio_set_drvdata(serio, NULL);
    279 fail1:	input_free_device(input_dev);
    280	kfree(sermouse);
    281	return err;
    282}
    283
    284static struct serio_device_id sermouse_serio_ids[] = {
    285	{
    286		.type	= SERIO_RS232,
    287		.proto	= SERIO_MSC,
    288		.id	= SERIO_ANY,
    289		.extra	= SERIO_ANY,
    290	},
    291	{
    292		.type	= SERIO_RS232,
    293		.proto	= SERIO_SUN,
    294		.id	= SERIO_ANY,
    295		.extra	= SERIO_ANY,
    296	},
    297	{
    298		.type	= SERIO_RS232,
    299		.proto	= SERIO_MS,
    300		.id	= SERIO_ANY,
    301		.extra	= SERIO_ANY,
    302	},
    303	{
    304		.type	= SERIO_RS232,
    305		.proto	= SERIO_MP,
    306		.id	= SERIO_ANY,
    307		.extra	= SERIO_ANY,
    308	},
    309	{
    310		.type	= SERIO_RS232,
    311		.proto	= SERIO_MZ,
    312		.id	= SERIO_ANY,
    313		.extra	= SERIO_ANY,
    314	},
    315	{
    316		.type	= SERIO_RS232,
    317		.proto	= SERIO_MZP,
    318		.id	= SERIO_ANY,
    319		.extra	= SERIO_ANY,
    320	},
    321	{
    322		.type	= SERIO_RS232,
    323		.proto	= SERIO_MZPP,
    324		.id	= SERIO_ANY,
    325		.extra	= SERIO_ANY,
    326	},
    327	{ 0 }
    328};
    329
    330MODULE_DEVICE_TABLE(serio, sermouse_serio_ids);
    331
    332static struct serio_driver sermouse_drv = {
    333	.driver		= {
    334		.name	= "sermouse",
    335	},
    336	.description	= DRIVER_DESC,
    337	.id_table	= sermouse_serio_ids,
    338	.interrupt	= sermouse_interrupt,
    339	.connect	= sermouse_connect,
    340	.disconnect	= sermouse_disconnect,
    341};
    342
    343module_serio_driver(sermouse_drv);