Linux Audio

Check our new training course

Loading...
v6.13.7
  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#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			0x201
 20#define L4_SELECT_ANALOG	0xa4
 21#define L4_SELECT_DIGITAL	0xa5
 22#define L4_SELECT_SECONDARY	0xa6
 23#define L4_CMD_ID		0x80
 24#define L4_CMD_GETCAL		0x92
 25#define L4_CMD_SETCAL		0x93
 26#define L4_ID			0x04
 27#define L4_BUSY			0x01
 28#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, so
174 * 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);
v5.4
  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);