Import 2.4.0-test2pre6
[davej-history.git] / drivers / char / joystick / joy-analog.c
blobf73ee8ded76a2f19dfb95e067207096fabde08f5
1 /*
2 * joy-analog.c Version 1.2
4 * Copyright (c) 1996-1999 Vojtech Pavlik
6 * Sponsored by SuSE
7 */
9 /*
10 * This is a module for the Linux joystick driver, supporting
11 * up to two analog (or CHF/FCS) joysticks on a single joystick port.
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * Should you need to contact me, the author, you can do so either by
30 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
31 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
34 #include <asm/io.h>
35 #include <asm/param.h>
36 #include <asm/system.h>
37 #include <linux/config.h>
38 #include <linux/delay.h>
39 #include <linux/errno.h>
40 #include <linux/ioport.h>
41 #include <linux/joystick.h>
42 #include <linux/kernel.h>
43 #include <linux/module.h>
44 #include <linux/sched.h>
45 #include <linux/string.h>
46 #include <linux/init.h>
48 #define JS_AN_MAX_TIME 3000 /* 3 ms */
49 #define JS_AN_LOOP_TIME 2000 /* 2 t */
51 static int js_an_port_list[] __initdata = {0x201, 0};
52 static struct js_port* js_an_port __initdata = NULL;
54 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
55 MODULE_PARM(js_an, "2-24i");
57 static int __initdata js_an[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
59 #include "joy-analog.h"
61 struct js_ax_info {
62 int io;
63 int speed;
64 int loop;
65 int timeout;
66 struct js_an_info an;
70 * Time macros.
73 #ifdef __i386__
74 #ifdef CONFIG_X86_TSC
75 #define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" )
76 #define DELTA(x,y) ((x)-(y))
77 #define TIME_NAME "TSC"
78 #else
79 #define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
80 #define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
81 #define TIME_NAME "PIT"
82 #endif
83 #elif __alpha__
84 #define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) )
85 #define DELTA(x,y) ((x)-(y))
86 #define TIME_NAME "PCC"
87 #endif
89 #ifndef GET_TIME
90 #define FAKE_TIME
91 static unsigned long js_an_faketime = 0;
92 #define GET_TIME(x) do { x = js_an_faketime++; } while(0)
93 #define DELTA(x,y) ((x)-(y))
94 #define TIME_NAME "Unreliable"
95 #endif
98 * js_an_read() reads analog joystick data.
101 static int js_an_read(void *xinfo, int **axes, int **buttons)
103 struct js_ax_info *info = xinfo;
104 struct js_an_info *an = &info->an;
105 int io = info->io;
106 unsigned long flags;
107 unsigned char buf[4];
108 unsigned int time[4];
109 unsigned char u, v, w;
110 unsigned int p, q, r, s, t;
111 int i, j;
113 an->buttons = ~inb(io) >> 4;
115 i = 0;
116 w = ((an->mask[0] | an->mask[1]) & JS_AN_AXES_STD) | (an->extensions & JS_AN_HAT_FCS)
117 | ((an->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((an->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
118 p = info->loop;
119 q = info->timeout;
121 __save_flags(flags);
122 __cli();
123 outb(0xff,io);
124 GET_TIME(r);
125 __restore_flags(flags);
126 t = r;
127 v = w;
128 do {
129 s = t;
130 u = v;
131 __cli();
132 v = inb(io) & w;
133 GET_TIME(t);
134 __restore_flags(flags);
135 if ((u ^ v) && (DELTA(t,s) < p)) {
136 time[i] = t;
137 buf[i] = u ^ v;
138 i++;
140 } while (v && (i < 4) && (DELTA(t,r) < q));
142 v <<= 4;
144 for (--i; i >= 0; i--) {
145 v |= buf[i];
146 for (j = 0; j < 4; j++)
147 if (buf[i] & (1 << j)) an->axes[j] = (DELTA(time[i],r) << 10) / info->speed;
150 js_an_decode(an, axes, buttons);
152 return -(v != w);
156 * js_an_calibrate_timer() calibrates the timer and computes loop
157 * and timeout values for a joystick port.
160 static void __init js_an_calibrate_timer(struct js_ax_info *info)
162 unsigned int i, t, tx, t1, t2, t3;
163 unsigned long flags;
164 int io = info->io;
166 save_flags(flags);
167 cli();
168 GET_TIME(t1);
169 #ifdef FAKE_TIME
170 js_an_faketime += 830;
171 #endif
172 udelay(1000);
173 GET_TIME(t2);
174 GET_TIME(t3);
175 restore_flags(flags);
177 info->speed = DELTA(t2, t1) - DELTA(t3, t2);
179 tx = 1 << 30;
181 for(i = 0; i < 50; i++) {
182 save_flags(flags);
183 cli();
184 GET_TIME(t1);
185 for(t = 0; t < 50; t++) { inb(io); GET_TIME(t2); }
186 GET_TIME(t3);
187 restore_flags(flags);
188 udelay(i);
189 if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
192 info->loop = (JS_AN_LOOP_TIME * t) / 50000;
193 info->timeout = (JS_AN_MAX_TIME * info->speed) / 1000;
197 * js_an_probe() probes for analog joysticks.
200 static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct js_port *port)
202 struct js_ax_info info, *ax;
203 int i, numdev;
204 unsigned char u;
206 if (io < 0) return port;
208 if (check_region(io, 1)) return port;
210 outb(0xff,io);
211 u = inb(io);
212 udelay(JS_AN_MAX_TIME);
213 u = (inb(io) ^ u) & u;
215 if (!u) return port;
216 if (u & 0xf0) return port;
218 if ((numdev = js_an_probe_devs(&info.an, u, mask0, mask1, port)) <= 0)
219 return port;
221 info.io = io;
222 js_an_calibrate_timer(&info);
224 request_region(info.io, 1, "joystick (analog)");
225 port = js_register_port(port, &info, numdev, sizeof(struct js_ax_info), js_an_read);
226 ax = port->info;
228 for (i = 0; i < numdev; i++)
229 printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
230 js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an),
231 js_an_name(i, &ax->an), THIS_MODULE, NULL, NULL),
232 js_an_name(i, &ax->an),
233 ax->io,
234 ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed,
235 ax->speed > 10000 ? "M" : "k",
236 ax->loop * 1000000000 / JS_AN_LOOP_TIME / ax->speed);
238 js_an_read(ax, port->axes, port->buttons);
239 js_an_init_corr(&ax->an, port->axes, port->corr, 8);
241 return port;
244 #ifndef MODULE
245 int __init js_an_setup(SETUP_PARAM)
247 int i;
248 SETUP_PARSE(24);
249 for (i = 0; i <= ints[0] && i < 24; i++) js_an[i] = ints[i+1];
250 return 1;
252 __setup("js_an=", js_an_setup);
253 #endif
255 #ifdef MODULE
256 int init_module(void)
257 #else
258 int __init js_an_init(void)
259 #endif
261 int i;
263 if (js_an[0] >= 0) {
264 for (i = 0; (js_an[i*3] >= 0) && i < 8; i++)
265 js_an_port = js_an_probe(js_an[i*3], js_an[i*3+1], js_an[i*3+2], js_an_port);
266 } else {
267 for (i = 0; js_an_port_list[i]; i++)
268 js_an_port = js_an_probe(js_an_port_list[i], 0, 0, js_an_port);
270 if (js_an_port) return 0;
272 #ifdef MODULE
273 printk(KERN_WARNING "joy-analog: no joysticks found\n");
274 #endif
276 return -ENODEV;
279 #ifdef MODULE
280 void cleanup_module(void)
282 int i;
283 struct js_ax_info *info;
285 while (js_an_port) {
286 for (i = 0; i < js_an_port->ndevs; i++)
287 if (js_an_port->devs[i])
288 js_unregister_device(js_an_port->devs[i]);
289 info = js_an_port->info;
290 release_region(info->io, 1);
291 js_an_port = js_unregister_port(js_an_port);
295 #endif