Import 2.4.0-test2pre6
[davej-history.git] / drivers / char / joystick / joy-lightning.c
blob26c18856a16811ac45897e82a9ded513247d7aee
1 /*
2 * joy-lightning.c Version 1.2
4 * Copyright (c) 1998-1999 Vojtech Pavlik
6 * Sponsored by SuSE
7 */
9 /*
10 * This is a module for the Linux joystick driver, supporting
11 * PDPI Lightning 4 gamecards and analog joysticks connected
12 * to them.
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 * Should you need to contact me, the author, you can do so either by
31 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
32 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
35 #include <asm/io.h>
36 #include <linux/delay.h>
37 #include <linux/errno.h>
38 #include <linux/ioport.h>
39 #include <linux/joystick.h>
40 #include <linux/kernel.h>
41 #include <linux/module.h>
42 #include <linux/string.h>
43 #include <linux/init.h>
45 #define JS_L4_PORT 0x201
46 #define JS_L4_SELECT_ANALOG 0xa4
47 #define JS_L4_SELECT_DIGITAL 0xa5
48 #define JS_L4_SELECT_SECONDARY 0xa6
49 #define JS_L4_CMD_ID 0x80
50 #define JS_L4_CMD_GETCAL 0x92
51 #define JS_L4_CMD_SETCAL 0x93
52 #define JS_L4_ID 0x04
53 #define JS_L4_BUSY 0x01
54 #define JS_L4_TIMEOUT 80 /* 80 us */
56 static struct js_port* __initdata js_l4_port = NULL;
58 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
59 MODULE_PARM(js_l4, "2-24i");
61 static int __initdata js_l4[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
63 #include "joy-analog.h"
65 struct js_l4_info {
66 int port;
67 struct js_an_info an;
71 * js_l4_wait_ready() waits for the L4 to become ready.
74 static int js_l4_wait_ready(void)
76 unsigned int t;
77 t = JS_L4_TIMEOUT;
78 while ((inb(JS_L4_PORT) & JS_L4_BUSY) && t > 0) t--;
79 return -(t<=0);
83 * js_l4_read() reads data from the Lightning 4.
86 static int js_l4_read(void *xinfo, int **axes, int **buttons)
88 struct js_l4_info *info = xinfo;
89 int i;
90 unsigned char status;
92 outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
93 outb(JS_L4_SELECT_DIGITAL + (info->port >> 2), JS_L4_PORT);
95 if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
96 outb(info->port & 3, JS_L4_PORT);
98 if (js_l4_wait_ready()) return -1;
99 status = inb(JS_L4_PORT);
101 for (i = 0; i < 4; i++)
102 if (status & (1 << i)) {
103 if (js_l4_wait_ready()) return -1;
104 info->an.axes[i] = inb(JS_L4_PORT);
107 if (status & 0x10) {
108 if (js_l4_wait_ready()) return -1;
109 info->an.buttons = inb(JS_L4_PORT);
112 js_an_decode(&info->an, axes, buttons);
114 return 0;
118 * js_l4_getcal() reads the L4 with calibration values.
121 static int js_l4_getcal(int port, int *cal)
123 int i;
125 outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
126 outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT);
128 if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
129 outb(JS_L4_CMD_GETCAL, JS_L4_PORT);
131 if (js_l4_wait_ready()) return -1;
132 if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1;
134 if (js_l4_wait_ready()) return -1;
135 outb(port & 3, JS_L4_PORT);
137 for (i = 0; i < 4; i++) {
138 if (js_l4_wait_ready()) return -1;
139 cal[i] = inb(JS_L4_PORT);
142 return 0;
146 * js_l4_setcal() programs the L4 with calibration values.
149 static int js_l4_setcal(int port, int *cal)
151 int i;
153 outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
154 outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT);
156 if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
157 outb(JS_L4_CMD_SETCAL, JS_L4_PORT);
159 if (js_l4_wait_ready()) return -1;
160 if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1;
162 if (js_l4_wait_ready()) return -1;
163 outb(port & 3, JS_L4_PORT);
165 for (i = 0; i < 4; i++) {
166 if (js_l4_wait_ready()) return -1;
167 outb(cal[i], JS_L4_PORT);
170 return 0;
174 * js_l4_calibrate() calibrates the L4 for the attached device, so
175 * that the device's resistance fits into the L4's 8-bit range.
178 static void js_l4_calibrate(struct js_l4_info *info)
180 int i;
181 int cal[4];
182 int axes[4];
183 int t;
185 js_l4_getcal(info->port, cal);
187 for (i = 0; i < 4; i++)
188 axes[i] = info->an.axes[i];
190 if ((info->an.extensions & JS_AN_BUTTON_PXY_X) && !(info->an.extensions & JS_AN_BUTTON_PXY_U))
191 axes[2] >>= 1; /* Pad button X */
193 if ((info->an.extensions & JS_AN_BUTTON_PXY_Y) && !(info->an.extensions & JS_AN_BUTTON_PXY_V))
194 axes[3] >>= 1; /* Pad button Y */
196 if (info->an.extensions & JS_AN_HAT_FCS)
197 axes[3] >>= 1; /* FCS hat */
199 if (((info->an.mask[0] & 0xb) == 0xb) || ((info->an.mask[1] & 0xb) == 0xb))
200 axes[3] = (axes[0] + axes[1]) >> 1; /* Throttle */
202 for (i = 0; i < 4; i++) {
203 t = (axes[i] * cal[i]) / 100;
204 if (t > 255) t = 255;
205 info->an.axes[i] = (info->an.axes[i] * cal[i]) / t;
206 cal[i] = t;
209 js_l4_setcal(info->port, cal);
213 * js_l4_probe() probes for joysticks on the L4 cards.
216 static struct js_port __init *js_l4_probe(unsigned char *cards, int l4port, int mask0, int mask1, struct js_port *port)
218 struct js_l4_info iniinfo;
219 struct js_l4_info *info = &iniinfo;
220 int cal[4] = {255,255,255,255};
221 int i, numdev;
222 unsigned char u;
224 if (l4port < 0) return port;
225 if (!cards[(l4port >> 2)]) return port;
227 memset(info, 0, sizeof(struct js_l4_info));
228 info->port = l4port;
230 if (cards[l4port >> 2] > 0x28) js_l4_setcal(info->port, cal);
231 if (js_l4_read(info, NULL, NULL)) return port;
233 for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 253) u |= 1 << i;
235 if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
236 return port;
238 port = js_register_port(port, info, numdev, sizeof(struct js_l4_info), js_l4_read);
240 info = port->info;
242 for (i = 0; i < numdev; i++)
243 printk(KERN_INFO "js%d: %s on L4 port %d\n",
244 js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
245 js_an_name(i, &info->an), THIS_MODULE, NULL, NULL),
246 js_an_name(i, &info->an), info->port);
248 js_l4_calibrate(info);
249 js_l4_read(info, port->axes, port->buttons);
250 js_an_init_corr(&info->an, port->axes, port->corr, 0);
252 return port;
256 * js_l4_card_probe() probes for presence of the L4 card(s).
259 static void __init js_l4_card_probe(unsigned char *cards)
261 int i;
262 unsigned char rev = 0;
264 if (check_region(JS_L4_PORT, 1)) return;
266 for (i = 0; i < 2; i++) {
268 outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
269 outb(JS_L4_SELECT_DIGITAL + i, JS_L4_PORT); /* Select card 0-1 */
271 if (inb(JS_L4_PORT) & JS_L4_BUSY) continue;
272 outb(JS_L4_CMD_ID, JS_L4_PORT); /* Get card ID & rev */
274 if (js_l4_wait_ready()) continue;
275 if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + i) continue;
277 if (js_l4_wait_ready()) continue;
278 if (inb(JS_L4_PORT) != JS_L4_ID) continue;
280 if (js_l4_wait_ready()) continue;
281 rev = inb(JS_L4_PORT);
283 cards[i] = rev;
285 printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d at %#x\n",
286 i ? "secondary" : "primary", (i << 2), (i << 2) + 3, rev >> 4, rev & 0xf, JS_L4_PORT);
291 #ifndef MODULE
292 int __init js_l4_setup(SETUP_PARAM)
294 int i;
295 SETUP_PARSE(24);
296 for (i = 0; i <= ints[0] && i < 24; i++) js_l4[i] = ints[i+1];
297 return 1;
299 __setup("js_l4=", js_l4_setup);
300 #endif
302 #ifdef MODULE
303 int init_module(void)
304 #else
305 int __init js_l4_init(void)
306 #endif
308 int i;
309 unsigned char cards[2] = {0, 0};
311 js_l4_card_probe(cards);
313 if (js_l4[0] >= 0) {
314 for (i = 0; (js_l4[i*3] >= 0) && i < 8; i++)
315 js_l4_port = js_l4_probe(cards, js_l4[i*3], js_l4[i*3+1], js_l4[i*3+2], js_l4_port);
316 } else {
317 for (i = 0; i < 8; i++)
318 js_l4_port = js_l4_probe(cards, i, 0, 0, js_l4_port);
321 if (!js_l4_port) {
322 #ifdef MODULE
323 printk(KERN_WARNING "joy-lightning: no joysticks found\n");
324 #endif
325 return -ENODEV;
328 request_region(JS_L4_PORT, 1, "joystick (lightning)");
330 return 0;
333 #ifdef MODULE
334 void cleanup_module(void)
336 int i;
337 int cal[4] = {59, 59, 59, 59};
338 struct js_l4_info *info;
340 while (js_l4_port) {
341 for (i = 0; i < js_l4_port->ndevs; i++)
342 if (js_l4_port->devs[i])
343 js_unregister_device(js_l4_port->devs[i]);
344 info = js_l4_port->info;
345 js_l4_setcal(info->port, cal);
346 js_l4_port = js_unregister_port(js_l4_port);
348 outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
349 release_region(JS_L4_PORT, 1);
351 #endif