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

adi.c (13191B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) 1998-2005 Vojtech Pavlik
      4 */
      5
      6/*
      7 * Logitech ADI joystick family driver for Linux
      8 */
      9
     10/*
     11 */
     12
     13#include <linux/delay.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/string.h>
     17#include <linux/slab.h>
     18#include <linux/input.h>
     19#include <linux/gameport.h>
     20#include <linux/jiffies.h>
     21
     22#define DRIVER_DESC	"Logitech ADI joystick family driver"
     23
     24MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
     25MODULE_DESCRIPTION(DRIVER_DESC);
     26MODULE_LICENSE("GPL");
     27
     28/*
     29 * Times, array sizes, flags, ids.
     30 */
     31
     32#define ADI_MAX_START		200	/* Trigger to packet timeout [200us] */
     33#define ADI_MAX_STROBE		40	/* Single bit timeout [40us] */
     34#define ADI_INIT_DELAY		10	/* Delay after init packet [10ms] */
     35#define ADI_DATA_DELAY		4	/* Delay after data packet [4ms] */
     36
     37#define ADI_MAX_LENGTH		256
     38#define ADI_MIN_LENGTH		8
     39#define ADI_MIN_LEN_LENGTH	10
     40#define ADI_MIN_ID_LENGTH	66
     41#define ADI_MAX_NAME_LENGTH	64
     42#define ADI_MAX_CNAME_LENGTH	16
     43#define ADI_MAX_PHYS_LENGTH	64
     44
     45#define ADI_FLAG_HAT		0x04
     46#define ADI_FLAG_10BIT		0x08
     47
     48#define ADI_ID_TPD		0x01
     49#define ADI_ID_WGP		0x06
     50#define ADI_ID_WGPE		0x08
     51#define ADI_ID_MAX		0x0a
     52
     53/*
     54 * Names, buttons, axes ...
     55 */
     56
     57static char *adi_names[] = {	"WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
     58				"WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
     59				"WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
     60				"WingMan GamePad USB", "Unknown Device %#x" };
     61
     62static char adi_wmgpe_abs[] =	{ ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
     63static char adi_wmi_abs[] =	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
     64static char adi_wmed3d_abs[] =	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
     65static char adi_cm2_abs[] =	{ ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
     66static char adi_wmf_abs[] =	{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
     67
     68static short adi_wmgpe_key[] =	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,  BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
     69static short adi_wmi_key[] =	{ BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
     70static short adi_wmed3d_key[] =	{ BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
     71static short adi_cm2_key[] =	{ BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
     72
     73static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
     74			   adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
     75
     76static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
     77			    adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
     78
     79/*
     80 * Hat to axis conversion arrays.
     81 */
     82
     83static struct {
     84	int x;
     85	int y;
     86} adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
     87
     88/*
     89 * Per-port information.
     90 */
     91
     92struct adi {
     93	struct input_dev *dev;
     94	int length;
     95	int ret;
     96	int idx;
     97	unsigned char id;
     98	char buttons;
     99	char axes10;
    100	char axes8;
    101	signed char pad;
    102	char hats;
    103	char *abs;
    104	short *key;
    105	char name[ADI_MAX_NAME_LENGTH];
    106	char cname[ADI_MAX_CNAME_LENGTH];
    107	char phys[ADI_MAX_PHYS_LENGTH];
    108	unsigned char data[ADI_MAX_LENGTH];
    109};
    110
    111struct adi_port {
    112	struct gameport *gameport;
    113	struct adi adi[2];
    114	int bad;
    115	int reads;
    116};
    117
    118/*
    119 * adi_read_packet() reads a Logitech ADI packet.
    120 */
    121
    122static void adi_read_packet(struct adi_port *port)
    123{
    124	struct adi *adi = port->adi;
    125	struct gameport *gameport = port->gameport;
    126	unsigned char u, v, w, x;
    127	int t[2], s[2], i;
    128	unsigned long flags;
    129
    130	for (i = 0; i < 2; i++) {
    131		adi[i].ret = -1;
    132		t[i] = gameport_time(gameport, ADI_MAX_START);
    133		s[i] = 0;
    134	}
    135
    136	local_irq_save(flags);
    137
    138	gameport_trigger(gameport);
    139	v = gameport_read(gameport);
    140
    141	do {
    142		u = v;
    143		w = u ^ (v = x = gameport_read(gameport));
    144		for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
    145			t[i]--;
    146			if ((w & 0x30) && s[i]) {
    147				if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
    148					adi[i].data[++adi[i].ret] = w;
    149					t[i] = gameport_time(gameport, ADI_MAX_STROBE);
    150				} else t[i] = 0;
    151			} else if (!(x & 0x30)) s[i] = 1;
    152		}
    153	} while (t[0] > 0 || t[1] > 0);
    154
    155	local_irq_restore(flags);
    156
    157	return;
    158}
    159
    160/*
    161 * adi_move_bits() detects a possible 2-stream mode, and moves
    162 * the bits accordingly.
    163 */
    164
    165static void adi_move_bits(struct adi_port *port, int length)
    166{
    167	int i;
    168	struct adi *adi = port->adi;
    169
    170	adi[0].idx = adi[1].idx = 0;
    171
    172	if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
    173	if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
    174
    175	for (i = 1; i <= adi[1].ret; i++)
    176		adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
    177
    178	adi[0].ret += adi[1].ret;
    179	adi[1].ret = -1;
    180}
    181
    182/*
    183 * adi_get_bits() gathers bits from the data packet.
    184 */
    185
    186static inline int adi_get_bits(struct adi *adi, int count)
    187{
    188	int bits = 0;
    189	int i;
    190	if ((adi->idx += count) > adi->ret) return 0;
    191	for (i = 0; i < count; i++)
    192		bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i;
    193	return bits;
    194}
    195
    196/*
    197 * adi_decode() decodes Logitech joystick data into input events.
    198 */
    199
    200static int adi_decode(struct adi *adi)
    201{
    202	struct input_dev *dev = adi->dev;
    203	char *abs = adi->abs;
    204	short *key = adi->key;
    205	int i, t;
    206
    207	if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
    208		return -1;
    209
    210	for (i = 0; i < adi->axes10; i++)
    211		input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
    212
    213	for (i = 0; i < adi->axes8; i++)
    214		input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
    215
    216	for (i = 0; i < adi->buttons && i < 63; i++) {
    217		if (i == adi->pad) {
    218			t = adi_get_bits(adi, 4);
    219			input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t       & 1));
    220			input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
    221		}
    222		input_report_key(dev, *key++, adi_get_bits(adi, 1));
    223	}
    224
    225	for (i = 0; i < adi->hats; i++) {
    226		if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
    227		input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
    228		input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
    229	}
    230
    231	for (i = 63; i < adi->buttons; i++)
    232		input_report_key(dev, *key++, adi_get_bits(adi, 1));
    233
    234	input_sync(dev);
    235
    236	return 0;
    237}
    238
    239/*
    240 * adi_read() reads the data packet and decodes it.
    241 */
    242
    243static int adi_read(struct adi_port *port)
    244{
    245	int i;
    246	int result = 0;
    247
    248	adi_read_packet(port);
    249	adi_move_bits(port, port->adi[0].length);
    250
    251	for (i = 0; i < 2; i++)
    252		if (port->adi[i].length)
    253			 result |= adi_decode(port->adi + i);
    254
    255	return result;
    256}
    257
    258/*
    259 * adi_poll() repeatedly polls the Logitech joysticks.
    260 */
    261
    262static void adi_poll(struct gameport *gameport)
    263{
    264	struct adi_port *port = gameport_get_drvdata(gameport);
    265
    266	port->bad -= adi_read(port);
    267	port->reads++;
    268}
    269
    270/*
    271 * adi_open() is a callback from the input open routine.
    272 */
    273
    274static int adi_open(struct input_dev *dev)
    275{
    276	struct adi_port *port = input_get_drvdata(dev);
    277
    278	gameport_start_polling(port->gameport);
    279	return 0;
    280}
    281
    282/*
    283 * adi_close() is a callback from the input close routine.
    284 */
    285
    286static void adi_close(struct input_dev *dev)
    287{
    288	struct adi_port *port = input_get_drvdata(dev);
    289
    290	gameport_stop_polling(port->gameport);
    291}
    292
    293/*
    294 * adi_init_digital() sends a trigger & delay sequence
    295 * to reset and initialize a Logitech joystick into digital mode.
    296 */
    297
    298static void adi_init_digital(struct gameport *gameport)
    299{
    300	static const int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
    301	int i;
    302
    303	for (i = 0; seq[i]; i++) {
    304		gameport_trigger(gameport);
    305		if (seq[i] > 0)
    306			msleep(seq[i]);
    307		if (seq[i] < 0) {
    308			mdelay(-seq[i]);
    309			udelay(-seq[i]*14);	/* It looks like mdelay() is off by approx 1.4% */
    310		}
    311	}
    312}
    313
    314static void adi_id_decode(struct adi *adi, struct adi_port *port)
    315{
    316	int i, t;
    317
    318	if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
    319		return;
    320
    321	if (adi->ret < (t = adi_get_bits(adi, 10))) {
    322		printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret);
    323		return;
    324	}
    325
    326	adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
    327
    328	if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
    329
    330	adi->length = adi_get_bits(adi, 10);
    331
    332	if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
    333		printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
    334		adi->length = 0;
    335		return;
    336	}
    337
    338	adi->axes8 = adi_get_bits(adi, 4);
    339	adi->buttons = adi_get_bits(adi, 6);
    340
    341	if (adi_get_bits(adi, 6) != 8 && adi->hats) {
    342		printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
    343		adi->length = 0;
    344		return;
    345	}
    346
    347	adi->buttons += adi_get_bits(adi, 6);
    348	adi->hats += adi_get_bits(adi, 4);
    349
    350	i = adi_get_bits(adi, 4);
    351
    352	if (t & ADI_FLAG_10BIT) {
    353		adi->axes10 = adi->axes8 - i;
    354		adi->axes8 = i;
    355	}
    356
    357	t = adi_get_bits(adi, 4);
    358
    359	for (i = 0; i < t; i++)
    360		adi->cname[i] = adi_get_bits(adi, 8);
    361	adi->cname[i] = 0;
    362
    363	t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
    364	if (adi->length != t && adi->length != t + (t & 1)) {
    365		printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
    366		adi->length = 0;
    367		return;
    368	}
    369
    370	switch (adi->id) {
    371		case ADI_ID_TPD:
    372			adi->pad = 4;
    373			adi->buttons -= 4;
    374			break;
    375		case ADI_ID_WGP:
    376			adi->pad = 0;
    377			adi->buttons -= 4;
    378			break;
    379		default:
    380			adi->pad = -1;
    381			break;
    382	}
    383}
    384
    385static int adi_init_input(struct adi *adi, struct adi_port *port, int half)
    386{
    387	struct input_dev *input_dev;
    388	char buf[ADI_MAX_NAME_LENGTH];
    389	int i, t;
    390
    391	adi->dev = input_dev = input_allocate_device();
    392	if (!input_dev)
    393		return -ENOMEM;
    394
    395	t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
    396
    397	snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id);
    398	snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s [%s]", buf, adi->cname);
    399	snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half);
    400
    401	adi->abs = adi_abs[t];
    402	adi->key = adi_key[t];
    403
    404	input_dev->name = adi->name;
    405	input_dev->phys = adi->phys;
    406	input_dev->id.bustype = BUS_GAMEPORT;
    407	input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH;
    408	input_dev->id.product = adi->id;
    409	input_dev->id.version = 0x0100;
    410	input_dev->dev.parent = &port->gameport->dev;
    411
    412	input_set_drvdata(input_dev, port);
    413
    414	input_dev->open = adi_open;
    415	input_dev->close = adi_close;
    416
    417	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    418
    419	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++)
    420		set_bit(adi->abs[i], input_dev->absbit);
    421
    422	for (i = 0; i < adi->buttons; i++)
    423		set_bit(adi->key[i], input_dev->keybit);
    424
    425	return 0;
    426}
    427
    428static void adi_init_center(struct adi *adi)
    429{
    430	int i, t, x;
    431
    432	if (!adi->length)
    433		return;
    434
    435	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) {
    436
    437		t = adi->abs[i];
    438		x = input_abs_get_val(adi->dev, t);
    439
    440		if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE)
    441			x = i < adi->axes10 ? 512 : 128;
    442
    443		if (i < adi->axes10)
    444			input_set_abs_params(adi->dev, t, 64, x * 2 - 64, 2, 16);
    445		else if (i < adi->axes10 + adi->axes8)
    446			input_set_abs_params(adi->dev, t, 48, x * 2 - 48, 1, 16);
    447		else
    448			input_set_abs_params(adi->dev, t, -1, 1, 0, 0);
    449	}
    450}
    451
    452/*
    453 * adi_connect() probes for Logitech ADI joysticks.
    454 */
    455
    456static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
    457{
    458	struct adi_port *port;
    459	int i;
    460	int err;
    461
    462	port = kzalloc(sizeof(struct adi_port), GFP_KERNEL);
    463	if (!port)
    464		return -ENOMEM;
    465
    466	port->gameport = gameport;
    467
    468	gameport_set_drvdata(gameport, port);
    469
    470	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
    471	if (err)
    472		goto fail1;
    473
    474	adi_init_digital(gameport);
    475	adi_read_packet(port);
    476
    477	if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
    478		adi_move_bits(port, adi_get_bits(port->adi, 10));
    479
    480	for (i = 0; i < 2; i++) {
    481		adi_id_decode(port->adi + i, port);
    482
    483		if (!port->adi[i].length)
    484			continue;
    485
    486		err = adi_init_input(port->adi + i, port, i);
    487		if (err)
    488			goto fail2;
    489	}
    490
    491	if (!port->adi[0].length && !port->adi[1].length) {
    492		err = -ENODEV;
    493		goto fail2;
    494	}
    495
    496	gameport_set_poll_handler(gameport, adi_poll);
    497	gameport_set_poll_interval(gameport, 20);
    498
    499	msleep(ADI_INIT_DELAY);
    500	if (adi_read(port)) {
    501		msleep(ADI_DATA_DELAY);
    502		adi_read(port);
    503	}
    504
    505	for (i = 0; i < 2; i++)
    506		if (port->adi[i].length > 0) {
    507			adi_init_center(port->adi + i);
    508			err = input_register_device(port->adi[i].dev);
    509			if (err)
    510				goto fail3;
    511		}
    512
    513	return 0;
    514
    515 fail3: while (--i >= 0) {
    516		if (port->adi[i].length > 0) {
    517			input_unregister_device(port->adi[i].dev);
    518			port->adi[i].dev = NULL;
    519		}
    520	}
    521 fail2:	for (i = 0; i < 2; i++)
    522		input_free_device(port->adi[i].dev);
    523	gameport_close(gameport);
    524 fail1:	gameport_set_drvdata(gameport, NULL);
    525	kfree(port);
    526	return err;
    527}
    528
    529static void adi_disconnect(struct gameport *gameport)
    530{
    531	int i;
    532	struct adi_port *port = gameport_get_drvdata(gameport);
    533
    534	for (i = 0; i < 2; i++)
    535		if (port->adi[i].length > 0)
    536			input_unregister_device(port->adi[i].dev);
    537	gameport_close(gameport);
    538	gameport_set_drvdata(gameport, NULL);
    539	kfree(port);
    540}
    541
    542static struct gameport_driver adi_drv = {
    543	.driver		= {
    544		.name	= "adi",
    545	},
    546	.description	= DRIVER_DESC,
    547	.connect	= adi_connect,
    548	.disconnect	= adi_disconnect,
    549};
    550
    551module_gameport_driver(adi_drv);