brintos

brintos / linux-shallow public Read only

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