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

lightning.c (6176B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) 1998-2001 Vojtech Pavlik
      4 */
      5
      6/*
      7 * PDPI Lightning 4 gamecard driver for Linux.
      8 */
      9
     10/*
     11 */
     12
     13#include <asm/io.h>
     14#include <linux/delay.h>
     15#include <linux/errno.h>
     16#include <linux/ioport.h>
     17#include <linux/kernel.h>
     18#include <linux/module.h>
     19#include <linux/init.h>
     20#include <linux/gameport.h>
     21
     22#define L4_PORT			0x201
     23#define L4_SELECT_ANALOG	0xa4
     24#define L4_SELECT_DIGITAL	0xa5
     25#define L4_SELECT_SECONDARY	0xa6
     26#define L4_CMD_ID		0x80
     27#define L4_CMD_GETCAL		0x92
     28#define L4_CMD_SETCAL		0x93
     29#define L4_ID			0x04
     30#define L4_BUSY			0x01
     31#define L4_TIMEOUT		80	/* 80 us */
     32
     33MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
     34MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver");
     35MODULE_LICENSE("GPL");
     36
     37struct l4 {
     38	struct gameport *gameport;
     39	unsigned char port;
     40};
     41
     42static struct l4 l4_ports[8];
     43
     44/*
     45 * l4_wait_ready() waits for the L4 to become ready.
     46 */
     47
     48static int l4_wait_ready(void)
     49{
     50	unsigned int t = L4_TIMEOUT;
     51
     52	while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
     53	return -(t <= 0);
     54}
     55
     56/*
     57 * l4_cooked_read() reads data from the Lightning 4.
     58 */
     59
     60static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
     61{
     62	struct l4 *l4 = gameport->port_data;
     63	unsigned char status;
     64	int i, result = -1;
     65
     66	outb(L4_SELECT_ANALOG, L4_PORT);
     67	outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
     68
     69	if (inb(L4_PORT) & L4_BUSY) goto fail;
     70	outb(l4->port & 3, L4_PORT);
     71
     72	if (l4_wait_ready()) goto fail;
     73	status = inb(L4_PORT);
     74
     75	for (i = 0; i < 4; i++)
     76		if (status & (1 << i)) {
     77			if (l4_wait_ready()) goto fail;
     78			axes[i] = inb(L4_PORT);
     79			if (axes[i] > 252) axes[i] = -1;
     80		}
     81
     82	if (status & 0x10) {
     83		if (l4_wait_ready()) goto fail;
     84		*buttons = inb(L4_PORT) & 0x0f;
     85	}
     86
     87	result = 0;
     88
     89fail:	outb(L4_SELECT_ANALOG, L4_PORT);
     90	return result;
     91}
     92
     93static int l4_open(struct gameport *gameport, int mode)
     94{
     95	struct l4 *l4 = gameport->port_data;
     96
     97        if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
     98		return -1;
     99	outb(L4_SELECT_ANALOG, L4_PORT);
    100	return 0;
    101}
    102
    103/*
    104 * l4_getcal() reads the L4 with calibration values.
    105 */
    106
    107static int l4_getcal(int port, int *cal)
    108{
    109	int i, result = -1;
    110
    111	outb(L4_SELECT_ANALOG, L4_PORT);
    112	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
    113	if (inb(L4_PORT) & L4_BUSY)
    114		goto out;
    115
    116	outb(L4_CMD_GETCAL, L4_PORT);
    117	if (l4_wait_ready())
    118		goto out;
    119
    120	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
    121		goto out;
    122
    123	if (l4_wait_ready())
    124		goto out;
    125        outb(port & 3, L4_PORT);
    126
    127	for (i = 0; i < 4; i++) {
    128		if (l4_wait_ready())
    129			goto out;
    130		cal[i] = inb(L4_PORT);
    131	}
    132
    133	result = 0;
    134
    135out:	outb(L4_SELECT_ANALOG, L4_PORT);
    136	return result;
    137}
    138
    139/*
    140 * l4_setcal() programs the L4 with calibration values.
    141 */
    142
    143static int l4_setcal(int port, int *cal)
    144{
    145	int i, result = -1;
    146
    147	outb(L4_SELECT_ANALOG, L4_PORT);
    148	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
    149	if (inb(L4_PORT) & L4_BUSY)
    150		goto out;
    151
    152	outb(L4_CMD_SETCAL, L4_PORT);
    153	if (l4_wait_ready())
    154		goto out;
    155
    156	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
    157		goto out;
    158
    159	if (l4_wait_ready())
    160		goto out;
    161        outb(port & 3, L4_PORT);
    162
    163	for (i = 0; i < 4; i++) {
    164		if (l4_wait_ready())
    165			goto out;
    166		outb(cal[i], L4_PORT);
    167	}
    168
    169	result = 0;
    170
    171out:	outb(L4_SELECT_ANALOG, L4_PORT);
    172	return result;
    173}
    174
    175/*
    176 * l4_calibrate() calibrates the L4 for the attached device, so
    177 * that the device's resistance fits into the L4's 8-bit range.
    178 */
    179
    180static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
    181{
    182	int i, t;
    183	int cal[4];
    184	struct l4 *l4 = gameport->port_data;
    185
    186	if (l4_getcal(l4->port, cal))
    187		return -1;
    188
    189	for (i = 0; i < 4; i++) {
    190		t = (max[i] * cal[i]) / 200;
    191		t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
    192		axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
    193		axes[i] = (axes[i] > 252) ? 252 : axes[i];
    194		cal[i] = t;
    195	}
    196
    197	if (l4_setcal(l4->port, cal))
    198		return -1;
    199
    200	return 0;
    201}
    202
    203static int __init l4_create_ports(int card_no)
    204{
    205	struct l4 *l4;
    206	struct gameport *port;
    207	int i, idx;
    208
    209	for (i = 0; i < 4; i++) {
    210
    211		idx = card_no * 4 + i;
    212		l4 = &l4_ports[idx];
    213
    214		if (!(l4->gameport = port = gameport_allocate_port())) {
    215			printk(KERN_ERR "lightning: Memory allocation failed\n");
    216			while (--i >= 0) {
    217				gameport_free_port(l4->gameport);
    218				l4->gameport = NULL;
    219			}
    220			return -ENOMEM;
    221		}
    222		l4->port = idx;
    223
    224		port->port_data = l4;
    225		port->open = l4_open;
    226		port->cooked_read = l4_cooked_read;
    227		port->calibrate = l4_calibrate;
    228
    229		gameport_set_name(port, "PDPI Lightning 4");
    230		gameport_set_phys(port, "isa%04x/gameport%d", L4_PORT, idx);
    231
    232		if (idx == 0)
    233			port->io = L4_PORT;
    234	}
    235
    236	return 0;
    237}
    238
    239static int __init l4_add_card(int card_no)
    240{
    241	int cal[4] = { 255, 255, 255, 255 };
    242	int i, rev, result;
    243	struct l4 *l4;
    244
    245	outb(L4_SELECT_ANALOG, L4_PORT);
    246	outb(L4_SELECT_DIGITAL + card_no, L4_PORT);
    247
    248	if (inb(L4_PORT) & L4_BUSY)
    249		return -1;
    250	outb(L4_CMD_ID, L4_PORT);
    251
    252	if (l4_wait_ready())
    253		return -1;
    254
    255	if (inb(L4_PORT) != L4_SELECT_DIGITAL + card_no)
    256		return -1;
    257
    258	if (l4_wait_ready())
    259		return -1;
    260	if (inb(L4_PORT) != L4_ID)
    261		return -1;
    262
    263	if (l4_wait_ready())
    264		return -1;
    265	rev = inb(L4_PORT);
    266
    267	if (!rev)
    268		return -1;
    269
    270	result = l4_create_ports(card_no);
    271	if (result)
    272		return result;
    273
    274	printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
    275		card_no ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
    276
    277	for (i = 0; i < 4; i++) {
    278		l4 = &l4_ports[card_no * 4 + i];
    279
    280		if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
    281			l4_setcal(l4->port, cal);
    282		gameport_register_port(l4->gameport);
    283	}
    284
    285	return 0;
    286}
    287
    288static int __init l4_init(void)
    289{
    290	int i, cards = 0;
    291
    292	if (!request_region(L4_PORT, 1, "lightning"))
    293		return -EBUSY;
    294
    295	for (i = 0; i < 2; i++)
    296		if (l4_add_card(i) == 0)
    297			cards++;
    298
    299	outb(L4_SELECT_ANALOG, L4_PORT);
    300
    301	if (!cards) {
    302		release_region(L4_PORT, 1);
    303		return -ENODEV;
    304	}
    305
    306	return 0;
    307}
    308
    309static void __exit l4_exit(void)
    310{
    311	int i;
    312	int cal[4] = { 59, 59, 59, 59 };
    313
    314	for (i = 0; i < 8; i++)
    315		if (l4_ports[i].gameport) {
    316			l4_setcal(l4_ports[i].port, cal);
    317			gameport_unregister_port(l4_ports[i].gameport);
    318		}
    319
    320	outb(L4_SELECT_ANALOG, L4_PORT);
    321	release_region(L4_PORT, 1);
    322}
    323
    324module_init(l4_init);
    325module_exit(l4_exit);