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

warrior.c (5247B)


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