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

cobra.c (5665B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) 1999-2001 Vojtech Pavlik
      4 */
      5
      6/*
      7 * Creative Labs Blaster GamePad Cobra 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/gameport.h>
     17#include <linux/input.h>
     18#include <linux/jiffies.h>
     19
     20#define DRIVER_DESC	"Creative Labs Blaster GamePad Cobra driver"
     21
     22MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
     23MODULE_DESCRIPTION(DRIVER_DESC);
     24MODULE_LICENSE("GPL");
     25
     26#define COBRA_MAX_STROBE	45	/* 45 us max wait for first strobe */
     27#define COBRA_LENGTH		36
     28
     29static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
     30
     31struct cobra {
     32	struct gameport *gameport;
     33	struct input_dev *dev[2];
     34	int reads;
     35	int bads;
     36	unsigned char exists;
     37	char phys[2][32];
     38};
     39
     40static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
     41{
     42	unsigned long flags;
     43	unsigned char u, v, w;
     44	__u64 buf[2];
     45	int r[2], t[2];
     46	int i, j, ret;
     47
     48	int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
     49
     50	for (i = 0; i < 2; i++) {
     51		r[i] = buf[i] = 0;
     52		t[i] = COBRA_MAX_STROBE;
     53	}
     54
     55	local_irq_save(flags);
     56
     57	u = gameport_read(gameport);
     58
     59	do {
     60		t[0]--; t[1]--;
     61		v = gameport_read(gameport);
     62		for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
     63			if (w & 0x30) {
     64				if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
     65					buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
     66					t[i] = strobe;
     67					u = v;
     68				} else t[i] = 0;
     69			}
     70	} while (t[0] > 0 || t[1] > 0);
     71
     72	local_irq_restore(flags);
     73
     74	ret = 0;
     75
     76	for (i = 0; i < 2; i++) {
     77
     78		if (r[i] != COBRA_LENGTH) continue;
     79
     80		for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
     81			buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
     82
     83		if (j < COBRA_LENGTH) ret |= (1 << i);
     84
     85		data[i] = ((buf[i] >>  7) & 0x000001f) | ((buf[i] >>  8) & 0x00003e0)
     86			| ((buf[i] >>  9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
     87			| ((buf[i] >> 11) & 0x1f00000);
     88
     89	}
     90
     91	return ret;
     92}
     93
     94static void cobra_poll(struct gameport *gameport)
     95{
     96	struct cobra *cobra = gameport_get_drvdata(gameport);
     97	struct input_dev *dev;
     98	unsigned int data[2];
     99	int i, j, r;
    100
    101	cobra->reads++;
    102
    103	if ((r = cobra_read_packet(gameport, data)) != cobra->exists) {
    104		cobra->bads++;
    105		return;
    106	}
    107
    108	for (i = 0; i < 2; i++)
    109		if (cobra->exists & r & (1 << i)) {
    110
    111			dev = cobra->dev[i];
    112
    113			input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
    114			input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
    115
    116			for (j = 0; cobra_btn[j]; j++)
    117				input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
    118
    119			input_sync(dev);
    120
    121		}
    122}
    123
    124static int cobra_open(struct input_dev *dev)
    125{
    126	struct cobra *cobra = input_get_drvdata(dev);
    127
    128	gameport_start_polling(cobra->gameport);
    129	return 0;
    130}
    131
    132static void cobra_close(struct input_dev *dev)
    133{
    134	struct cobra *cobra = input_get_drvdata(dev);
    135
    136	gameport_stop_polling(cobra->gameport);
    137}
    138
    139static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
    140{
    141	struct cobra *cobra;
    142	struct input_dev *input_dev;
    143	unsigned int data[2];
    144	int i, j;
    145	int err;
    146
    147	cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL);
    148	if (!cobra)
    149		return -ENOMEM;
    150
    151	cobra->gameport = gameport;
    152
    153	gameport_set_drvdata(gameport, cobra);
    154
    155	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
    156	if (err)
    157		goto fail1;
    158
    159	cobra->exists = cobra_read_packet(gameport, data);
    160
    161	for (i = 0; i < 2; i++)
    162		if ((cobra->exists >> i) & data[i] & 1) {
    163			printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d"
    164				" Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7);
    165			cobra->exists &= ~(1 << i);
    166		}
    167
    168	if (!cobra->exists) {
    169		err = -ENODEV;
    170		goto fail2;
    171	}
    172
    173	gameport_set_poll_handler(gameport, cobra_poll);
    174	gameport_set_poll_interval(gameport, 20);
    175
    176	for (i = 0; i < 2; i++) {
    177		if (~(cobra->exists >> i) & 1)
    178			continue;
    179
    180		cobra->dev[i] = input_dev = input_allocate_device();
    181		if (!input_dev) {
    182			err = -ENOMEM;
    183			goto fail3;
    184		}
    185
    186		snprintf(cobra->phys[i], sizeof(cobra->phys[i]),
    187			 "%s/input%d", gameport->phys, i);
    188
    189		input_dev->name = "Creative Labs Blaster GamePad Cobra";
    190		input_dev->phys = cobra->phys[i];
    191		input_dev->id.bustype = BUS_GAMEPORT;
    192		input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE;
    193		input_dev->id.product = 0x0008;
    194		input_dev->id.version = 0x0100;
    195		input_dev->dev.parent = &gameport->dev;
    196
    197		input_set_drvdata(input_dev, cobra);
    198
    199		input_dev->open = cobra_open;
    200		input_dev->close = cobra_close;
    201
    202		input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    203		input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0);
    204		input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0);
    205		for (j = 0; cobra_btn[j]; j++)
    206			set_bit(cobra_btn[j], input_dev->keybit);
    207
    208		err = input_register_device(cobra->dev[i]);
    209		if (err)
    210			goto fail4;
    211	}
    212
    213	return 0;
    214
    215 fail4:	input_free_device(cobra->dev[i]);
    216 fail3:	while (--i >= 0)
    217		if (cobra->dev[i])
    218			input_unregister_device(cobra->dev[i]);
    219 fail2:	gameport_close(gameport);
    220 fail1:	gameport_set_drvdata(gameport, NULL);
    221	kfree(cobra);
    222	return err;
    223}
    224
    225static void cobra_disconnect(struct gameport *gameport)
    226{
    227	struct cobra *cobra = gameport_get_drvdata(gameport);
    228	int i;
    229
    230	for (i = 0; i < 2; i++)
    231		if ((cobra->exists >> i) & 1)
    232			input_unregister_device(cobra->dev[i]);
    233	gameport_close(gameport);
    234	gameport_set_drvdata(gameport, NULL);
    235	kfree(cobra);
    236}
    237
    238static struct gameport_driver cobra_drv = {
    239	.driver		= {
    240		.name	= "cobra",
    241	},
    242	.description	= DRIVER_DESC,
    243	.connect	= cobra_connect,
    244	.disconnect	= cobra_disconnect,
    245};
    246
    247module_gameport_driver(cobra_drv);