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

stinger.c (4668B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) 2000-2001 Vojtech Pavlik
      4 *  Copyright (c) 2000 Mark Fletcher
      5 */
      6
      7/*
      8 * Gravis Stinger gamepad driver for Linux
      9 */
     10
     11/*
     12 */
     13
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/slab.h>
     17#include <linux/input.h>
     18#include <linux/serio.h>
     19
     20#define DRIVER_DESC	"Gravis Stinger gamepad driver"
     21
     22MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
     23MODULE_DESCRIPTION(DRIVER_DESC);
     24MODULE_LICENSE("GPL");
     25
     26/*
     27 * Constants.
     28 */
     29
     30#define STINGER_MAX_LENGTH 8
     31
     32/*
     33 * Per-Stinger data.
     34 */
     35
     36struct stinger {
     37	struct input_dev *dev;
     38	int idx;
     39	unsigned char data[STINGER_MAX_LENGTH];
     40	char phys[32];
     41};
     42
     43/*
     44 * stinger_process_packet() decodes packets the driver receives from the
     45 * Stinger. It updates the data accordingly.
     46 */
     47
     48static void stinger_process_packet(struct stinger *stinger)
     49{
     50	struct input_dev *dev = stinger->dev;
     51	unsigned char *data = stinger->data;
     52
     53	if (!stinger->idx) return;
     54
     55	input_report_key(dev, BTN_A,	  ((data[0] & 0x20) >> 5));
     56	input_report_key(dev, BTN_B,	  ((data[0] & 0x10) >> 4));
     57	input_report_key(dev, BTN_C,	  ((data[0] & 0x08) >> 3));
     58	input_report_key(dev, BTN_X,	  ((data[0] & 0x04) >> 2));
     59	input_report_key(dev, BTN_Y,	  ((data[3] & 0x20) >> 5));
     60	input_report_key(dev, BTN_Z,	  ((data[3] & 0x10) >> 4));
     61	input_report_key(dev, BTN_TL,     ((data[3] & 0x08) >> 3));
     62	input_report_key(dev, BTN_TR,     ((data[3] & 0x04) >> 2));
     63	input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1));
     64	input_report_key(dev, BTN_START,   (data[3] & 0x01));
     65
     66	input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6));
     67	input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F));
     68
     69	input_sync(dev);
     70
     71	return;
     72}
     73
     74/*
     75 * stinger_interrupt() is called by the low level driver when characters
     76 * are ready for us. We then buffer them for further processing, or call the
     77 * packet processing routine.
     78 */
     79
     80static irqreturn_t stinger_interrupt(struct serio *serio,
     81	unsigned char data, unsigned int flags)
     82{
     83	struct stinger *stinger = serio_get_drvdata(serio);
     84
     85	/* All Stinger packets are 4 bytes */
     86
     87	if (stinger->idx < STINGER_MAX_LENGTH)
     88		stinger->data[stinger->idx++] = data;
     89
     90	if (stinger->idx == 4) {
     91		stinger_process_packet(stinger);
     92		stinger->idx = 0;
     93	}
     94
     95	return IRQ_HANDLED;
     96}
     97
     98/*
     99 * stinger_disconnect() is the opposite of stinger_connect()
    100 */
    101
    102static void stinger_disconnect(struct serio *serio)
    103{
    104	struct stinger *stinger = serio_get_drvdata(serio);
    105
    106	serio_close(serio);
    107	serio_set_drvdata(serio, NULL);
    108	input_unregister_device(stinger->dev);
    109	kfree(stinger);
    110}
    111
    112/*
    113 * stinger_connect() is the routine that is called when someone adds a
    114 * new serio device that supports Stinger protocol and registers it as
    115 * an input device.
    116 */
    117
    118static int stinger_connect(struct serio *serio, struct serio_driver *drv)
    119{
    120	struct stinger *stinger;
    121	struct input_dev *input_dev;
    122	int err = -ENOMEM;
    123
    124	stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL);
    125	input_dev = input_allocate_device();
    126	if (!stinger || !input_dev)
    127		goto fail1;
    128
    129	stinger->dev = input_dev;
    130	snprintf(stinger->phys, sizeof(stinger->phys), "%s/serio0", serio->phys);
    131
    132	input_dev->name = "Gravis Stinger";
    133	input_dev->phys = stinger->phys;
    134	input_dev->id.bustype = BUS_RS232;
    135	input_dev->id.vendor = SERIO_STINGER;
    136	input_dev->id.product = 0x0001;
    137	input_dev->id.version = 0x0100;
    138	input_dev->dev.parent = &serio->dev;
    139
    140	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    141	input_dev->keybit[BIT_WORD(BTN_A)] = BIT_MASK(BTN_A) | BIT_MASK(BTN_B) |
    142		BIT_MASK(BTN_C) | BIT_MASK(BTN_X) | BIT_MASK(BTN_Y) |
    143		BIT_MASK(BTN_Z) | BIT_MASK(BTN_TL) | BIT_MASK(BTN_TR) |
    144		BIT_MASK(BTN_START) | BIT_MASK(BTN_SELECT);
    145	input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 4);
    146	input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 4);
    147
    148	serio_set_drvdata(serio, stinger);
    149
    150	err = serio_open(serio, drv);
    151	if (err)
    152		goto fail2;
    153
    154	err = input_register_device(stinger->dev);
    155	if (err)
    156		goto fail3;
    157
    158	return 0;
    159
    160 fail3:	serio_close(serio);
    161 fail2:	serio_set_drvdata(serio, NULL);
    162 fail1:	input_free_device(input_dev);
    163	kfree(stinger);
    164	return err;
    165}
    166
    167/*
    168 * The serio driver structure.
    169 */
    170
    171static const struct serio_device_id stinger_serio_ids[] = {
    172	{
    173		.type	= SERIO_RS232,
    174		.proto	= SERIO_STINGER,
    175		.id	= SERIO_ANY,
    176		.extra	= SERIO_ANY,
    177	},
    178	{ 0 }
    179};
    180
    181MODULE_DEVICE_TABLE(serio, stinger_serio_ids);
    182
    183static struct serio_driver stinger_drv = {
    184	.driver		= {
    185		.name	= "stinger",
    186	},
    187	.description	= DRIVER_DESC,
    188	.id_table	= stinger_serio_ids,
    189	.interrupt	= stinger_interrupt,
    190	.connect	= stinger_connect,
    191	.disconnect	= stinger_disconnect,
    192};
    193
    194module_serio_driver(stinger_drv);