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

interact.c (7088B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) 2001 Vojtech Pavlik
      4 *
      5 *  Based on the work of:
      6 *	Toby Deshane
      7 */
      8
      9/*
     10 * InterAct digital gamepad/joystick driver for Linux
     11 */
     12
     13/*
     14 */
     15
     16#include <linux/kernel.h>
     17#include <linux/slab.h>
     18#include <linux/module.h>
     19#include <linux/delay.h>
     20#include <linux/gameport.h>
     21#include <linux/input.h>
     22#include <linux/jiffies.h>
     23
     24#define DRIVER_DESC	"InterAct digital joystick driver"
     25
     26MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
     27MODULE_DESCRIPTION(DRIVER_DESC);
     28MODULE_LICENSE("GPL");
     29
     30#define INTERACT_MAX_START	600	/* 400 us */
     31#define INTERACT_MAX_STROBE	60	/* 40 us */
     32#define INTERACT_MAX_LENGTH	32	/* 32 bits */
     33
     34#define INTERACT_TYPE_HHFX	0	/* HammerHead/FX */
     35#define INTERACT_TYPE_PP8D	1	/* ProPad 8 */
     36
     37struct interact {
     38	struct gameport *gameport;
     39	struct input_dev *dev;
     40	int bads;
     41	int reads;
     42	unsigned char type;
     43	unsigned char length;
     44	char phys[32];
     45};
     46
     47static short interact_abs_hhfx[] =
     48	{ ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
     49static short interact_abs_pp8d[] =
     50	{ ABS_X, ABS_Y, -1 };
     51
     52static short interact_btn_hhfx[] =
     53	{ BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 };
     54static short interact_btn_pp8d[] =
     55	{ BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 };
     56
     57struct interact_type {
     58	int id;
     59	short *abs;
     60	short *btn;
     61	char *name;
     62	unsigned char length;
     63	unsigned char b8;
     64};
     65
     66static struct interact_type interact_type[] = {
     67	{ 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX",    32, 4 },
     68	{ 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 },
     69	{ 0 }};
     70
     71/*
     72 * interact_read_packet() reads and InterAct joystick data.
     73 */
     74
     75static int interact_read_packet(struct gameport *gameport, int length, u32 *data)
     76{
     77	unsigned long flags;
     78	unsigned char u, v;
     79	unsigned int t, s;
     80	int i;
     81
     82	i = 0;
     83	data[0] = data[1] = data[2] = 0;
     84	t = gameport_time(gameport, INTERACT_MAX_START);
     85	s = gameport_time(gameport, INTERACT_MAX_STROBE);
     86
     87	local_irq_save(flags);
     88	gameport_trigger(gameport);
     89	v = gameport_read(gameport);
     90
     91	while (t > 0 && i < length) {
     92		t--;
     93		u = v; v = gameport_read(gameport);
     94		if (v & ~u & 0x40) {
     95			data[0] = (data[0] << 1) | ((v >> 4) & 1);
     96			data[1] = (data[1] << 1) | ((v >> 5) & 1);
     97			data[2] = (data[2] << 1) | ((v >> 7) & 1);
     98			i++;
     99			t = s;
    100		}
    101	}
    102
    103	local_irq_restore(flags);
    104
    105	return i;
    106}
    107
    108/*
    109 * interact_poll() reads and analyzes InterAct joystick data.
    110 */
    111
    112static void interact_poll(struct gameport *gameport)
    113{
    114	struct interact *interact = gameport_get_drvdata(gameport);
    115	struct input_dev *dev = interact->dev;
    116	u32 data[3];
    117	int i;
    118
    119	interact->reads++;
    120
    121	if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
    122		interact->bads++;
    123	} else {
    124
    125		for (i = 0; i < 3; i++)
    126			data[i] <<= INTERACT_MAX_LENGTH - interact->length;
    127
    128		switch (interact->type) {
    129
    130			case INTERACT_TYPE_HHFX:
    131
    132				for (i = 0; i < 4; i++)
    133					input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
    134
    135				for (i = 0; i < 2; i++)
    136					input_report_abs(dev, ABS_HAT0Y - i,
    137						((data[1] >> ((i << 1) + 17)) & 1)  - ((data[1] >> ((i << 1) + 16)) & 1));
    138
    139				for (i = 0; i < 8; i++)
    140					input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
    141
    142				for (i = 0; i < 4; i++)
    143					input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
    144
    145				break;
    146
    147			case INTERACT_TYPE_PP8D:
    148
    149				for (i = 0; i < 2; i++)
    150					input_report_abs(dev, interact_abs_pp8d[i],
    151						((data[0] >> ((i << 1) + 20)) & 1)  - ((data[0] >> ((i << 1) + 21)) & 1));
    152
    153				for (i = 0; i < 8; i++)
    154					input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
    155
    156				break;
    157		}
    158	}
    159
    160	input_sync(dev);
    161}
    162
    163/*
    164 * interact_open() is a callback from the input open routine.
    165 */
    166
    167static int interact_open(struct input_dev *dev)
    168{
    169	struct interact *interact = input_get_drvdata(dev);
    170
    171	gameport_start_polling(interact->gameport);
    172	return 0;
    173}
    174
    175/*
    176 * interact_close() is a callback from the input close routine.
    177 */
    178
    179static void interact_close(struct input_dev *dev)
    180{
    181	struct interact *interact = input_get_drvdata(dev);
    182
    183	gameport_stop_polling(interact->gameport);
    184}
    185
    186/*
    187 * interact_connect() probes for InterAct joysticks.
    188 */
    189
    190static int interact_connect(struct gameport *gameport, struct gameport_driver *drv)
    191{
    192	struct interact *interact;
    193	struct input_dev *input_dev;
    194	__u32 data[3];
    195	int i, t;
    196	int err;
    197
    198	interact = kzalloc(sizeof(struct interact), GFP_KERNEL);
    199	input_dev = input_allocate_device();
    200	if (!interact || !input_dev) {
    201		err = -ENOMEM;
    202		goto fail1;
    203	}
    204
    205	interact->gameport = gameport;
    206	interact->dev = input_dev;
    207
    208	gameport_set_drvdata(gameport, interact);
    209
    210	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
    211	if (err)
    212		goto fail1;
    213
    214	i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
    215
    216	if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
    217		err = -ENODEV;
    218		goto fail2;
    219	}
    220
    221	for (i = 0; interact_type[i].length; i++)
    222		if (interact_type[i].id == (data[2] >> 16))
    223			break;
    224
    225	if (!interact_type[i].length) {
    226		printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n",
    227			gameport->phys, i, data[0], data[1], data[2]);
    228		err = -ENODEV;
    229		goto fail2;
    230	}
    231
    232	gameport_set_poll_handler(gameport, interact_poll);
    233	gameport_set_poll_interval(gameport, 20);
    234
    235	snprintf(interact->phys, sizeof(interact->phys), "%s/input0", gameport->phys);
    236
    237	interact->type = i;
    238	interact->length = interact_type[i].length;
    239
    240	input_dev->name = interact_type[i].name;
    241	input_dev->phys = interact->phys;
    242	input_dev->id.bustype = BUS_GAMEPORT;
    243	input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT;
    244	input_dev->id.product = interact_type[i].id;
    245	input_dev->id.version = 0x0100;
    246	input_dev->dev.parent = &gameport->dev;
    247
    248	input_set_drvdata(input_dev, interact);
    249
    250	input_dev->open = interact_open;
    251	input_dev->close = interact_close;
    252
    253	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    254
    255	for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
    256		if (i < interact_type[interact->type].b8)
    257			input_set_abs_params(input_dev, t, 0, 255, 0, 0);
    258		else
    259			input_set_abs_params(input_dev, t, -1, 1, 0, 0);
    260	}
    261
    262	for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
    263		__set_bit(t, input_dev->keybit);
    264
    265	err = input_register_device(interact->dev);
    266	if (err)
    267		goto fail2;
    268
    269	return 0;
    270
    271fail2:	gameport_close(gameport);
    272fail1:  gameport_set_drvdata(gameport, NULL);
    273	input_free_device(input_dev);
    274	kfree(interact);
    275	return err;
    276}
    277
    278static void interact_disconnect(struct gameport *gameport)
    279{
    280	struct interact *interact = gameport_get_drvdata(gameport);
    281
    282	input_unregister_device(interact->dev);
    283	gameport_close(gameport);
    284	gameport_set_drvdata(gameport, NULL);
    285	kfree(interact);
    286}
    287
    288static struct gameport_driver interact_drv = {
    289	.driver		= {
    290		.name	= "interact",
    291	},
    292	.description	= DRIVER_DESC,
    293	.connect	= interact_connect,
    294	.disconnect	= interact_disconnect,
    295};
    296
    297module_gameport_driver(interact_drv);