2 * joy-analog.c Version 1.2
4 * Copyright (c) 1996-1999 Vojtech Pavlik
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
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"
75 #define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" )
76 #define DELTA(x,y) ((x)-(y))
77 #define TIME_NAME "TSC"
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"
84 #define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) )
85 #define DELTA(x,y) ((x)-(y))
86 #define TIME_NAME "PCC"
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"
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
;
107 unsigned char buf
[4];
108 unsigned int time
[4];
109 unsigned char u
, v
, w
;
110 unsigned int p
, q
, r
, s
, t
;
113 an
->buttons
= ~inb(io
) >> 4;
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);
125 __restore_flags(flags
);
134 __restore_flags(flags
);
135 if ((u
^ v
) && (DELTA(t
,s
) < p
)) {
140 } while (v
&& (i
< 4) && (DELTA(t
,r
) < q
));
144 for (--i
; i
>= 0; 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
);
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
;
170 js_an_faketime
+= 830;
175 restore_flags(flags
);
177 info
->speed
= DELTA(t2
, t1
) - DELTA(t3
, t2
);
181 for(i
= 0; i
< 50; i
++) {
185 for(t
= 0; t
< 50; t
++) { inb(io
); GET_TIME(t2
); }
187 restore_flags(flags
);
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
;
206 if (io
< 0) return port
;
208 if (check_region(io
, 1)) return port
;
212 udelay(JS_AN_MAX_TIME
);
213 u
= (inb(io
) ^ u
) & u
;
216 if (u
& 0xf0) return port
;
218 if ((numdev
= js_an_probe_devs(&info
.an
, u
, mask0
, mask1
, port
)) <= 0)
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
);
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
),
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);
245 int __init
js_an_setup(SETUP_PARAM
)
249 for (i
= 0; i
<= ints
[0] && i
< 24; i
++) js_an
[i
] = ints
[i
+1];
252 __setup("js_an=", js_an_setup
);
256 int init_module(void)
258 int __init
js_an_init(void)
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
);
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;
273 printk(KERN_WARNING
"joy-analog: no joysticks found\n");
280 void cleanup_module(void)
283 struct js_ax_info
*info
;
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
);