2 * joy-sidewinder.c Version 1.2
4 * Copyright (c) 1998 Vojtech Pavlik
8 * This is a module for the Linux joystick driver, supporting
9 * Microsoft SideWinder digital joystick family.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * Should you need to contact me, the author, you can do so either by
28 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
29 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
33 #include <asm/system.h>
34 #include <linux/delay.h>
35 #include <linux/errno.h>
36 #include <linux/ioport.h>
37 #include <linux/joystick.h>
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/string.h>
42 #define JS_SW_MAX_START 250
43 #define JS_SW_MIN_STROBE 25
44 #define JS_SW_EXT_STROBE 45
45 #define JS_SW_MIN_TIME 1500
46 #define JS_SW_MAX_TIME 4000
48 #define JS_SW_MAX_LENGTH 72
50 #define JS_SW_MODE_3DP 1
51 #define JS_SW_MODE_PP 2
52 #define JS_SW_MODE_GP 3
54 static int js_sw_port_list
[] __initdata
= {0x201, 0};
55 static struct js_port
* js_sw_port __initdata
= NULL
;
60 } js_sw_hat_to_axis
[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
66 unsigned char optimize
;
70 * js_sw_init_digital() switches a SideWinder into digital mode.
73 static void __init
js_sw_init_digital(int io
)
76 unsigned int timeout
= (js_time_speed
* JS_SW_MAX_TIME
) >> 10;
77 int delays
[] = {140, 140+726, 140+300, 0};
86 while ((inb(io
) & 1) && (js_delta(js_get_time(),t
) < timeout
));
88 } while (delays
[i
++]);
89 __restore_flags(flags
);
91 for (i
= 0; i
< 4; i
++) {
100 * js_sw_read_packet() reads a SideWinder packet.
103 static int js_sw_read_packet(int io
, int l1
, int l2
, int strobe
, __u64
*data
)
105 static unsigned char buf
[JS_SW_MAX_LENGTH
];
111 int length
= l1
< l2
? l2
: l1
;
112 int start
= (js_time_speed
* JS_SW_MAX_START
) >> 10;
113 strobe
= (js_time_speed
* strobe
) >> 10;
128 } while (!((u
^ v
) & u
& 0x10) && js_delta(t1
, t
) < start
);
135 if ((u
^ v
) & v
& 0x10) {
140 } while (i
< length
&& js_delta(t1
,t
) < strobe
);
142 __restore_flags(flags
);
148 for (i
= 0; i
< t
; i
++)
149 *data
|= (__u64
) (buf
[i
] & 1) << i
;
154 for (i
= 0; i
< t
; i
++)
155 *data
|= (__u64
) buf
[i
] << (3 * i
);
163 * js_sw_parity computes parity of __u64
166 static int js_sw_parity(__u64 t
)
178 * js_sw_csum() computes checksum of nibbles in __u64
181 static int js_sw_csum(__u64 t
)
192 * js_sw_read() reads and analyzes SideWinder joystick data.
195 static int js_sw_read(void *xinfo
, int **axes
, int **buttons
)
197 struct js_sw_info
*info
= xinfo
;
201 switch (info
->mode
) {
205 if (info
->optimize
) {
206 i
= js_sw_read_packet(info
->io
, -1, 22, JS_SW_EXT_STROBE
, &data
);
208 i
= js_sw_read_packet(info
->io
, 64, 66, JS_SW_EXT_STROBE
, &data
);
209 if (i
== 198) info
->optimize
= 1;
213 js_sw_init_digital(info
->io
);
218 if (((data
& 0x8080808080808080ULL
) ^ 0x80) || js_sw_csum(data
) ||
219 (hat
= ((data
>> 3) & 0x08) | ((data
>> 60) & 0x07)) > 8) {
223 axes
[0][0] = ((data
<< 4) & 0x380) | ((data
>> 16) & 0x07f);
224 axes
[0][1] = ((data
<< 7) & 0x380) | ((data
>> 24) & 0x07f);
225 axes
[0][2] = ((data
>> 28) & 0x180) | ((data
>> 40) & 0x07f);
226 axes
[0][3] = ((data
>> 25) & 0x380) | ((data
>> 48) & 0x07f);
227 axes
[0][4] = js_sw_hat_to_axis
[hat
].x
;
228 axes
[0][5] = js_sw_hat_to_axis
[hat
].y
;
229 buttons
[0][0] = ((~data
>> 31) & 0x80) | ((~data
>> 8) & 0x7f);
235 if (js_sw_read_packet(info
->io
, 48, 16, JS_SW_EXT_STROBE
, &data
) != 48) return -1;
236 if (!js_sw_parity(data
) || (hat
= (data
>> 42) & 0xf) > 8) return -1;
238 axes
[0][0] = (data
>> 9) & 0x3ff;
239 axes
[0][1] = (data
>> 19) & 0x3ff;
240 axes
[0][2] = (data
>> 29) & 0x07f;
241 axes
[0][3] = (data
>> 36) & 0x03f;
242 axes
[0][4] = js_sw_hat_to_axis
[hat
].x
;
243 axes
[0][5] = js_sw_hat_to_axis
[hat
].y
;
244 buttons
[0][0] = ~data
& 0x1ff;
250 if (js_sw_read_packet(info
->io
, 15 * info
->number
, 5 * info
->number
,
251 JS_SW_EXT_STROBE
, &data
) != 15 * info
->number
) return -1;
252 if (js_sw_parity(data
)) return -1;
254 for (i
= 0; i
< info
->number
; i
++) {
255 axes
[i
][0] = ((data
>> 3) & 1) - ((data
>> 2) & 1);
256 axes
[i
][1] = ( data
& 1) - ((data
>> 1) & 1);
257 buttons
[i
][0] = (~data
>> 4) & 0x3ff;
269 * js_sw_open() is a callback from the file open routine.
272 static int js_sw_open(struct js_dev
*jd
)
279 * js_sw_close() is a callback from the file release routine.
282 static int js_sw_close(struct js_dev
*jd
)
289 * js_sw_init_corr() initializes the correction values for
293 static void __init
js_sw_init_corr(int num_axes
, int mode
, int number
, struct js_corr
**corr
)
297 for (i
= 0; i
< number
; i
++) {
299 for (j
= 0; j
< num_axes
; j
++) {
300 corr
[i
][j
].type
= JS_CORR_BROKEN
;
302 corr
[i
][j
].coef
[0] = 511 - 32;
303 corr
[i
][j
].coef
[1] = 512 + 32;
304 corr
[i
][j
].coef
[2] = (1 << 29) / (511 - 32);
305 corr
[i
][j
].coef
[3] = (1 << 29) / (511 - 32);
312 corr
[i
][2].type
= JS_CORR_BROKEN
;
314 corr
[i
][2].coef
[0] = 255 - 16;
315 corr
[i
][2].coef
[1] = 256 + 16;
316 corr
[i
][2].coef
[2] = (1 << 29) / (255 - 16);
317 corr
[i
][2].coef
[3] = (1 << 29) / (255 - 16);
325 corr
[i
][2].type
= JS_CORR_BROKEN
;
327 corr
[i
][2].coef
[0] = 63 - 4;
328 corr
[i
][2].coef
[1] = 64 + 4;
329 corr
[i
][2].coef
[2] = (1 << 29) / (63 - 4);
330 corr
[i
][2].coef
[3] = (1 << 29) / (63 - 4);
332 corr
[i
][3].type
= JS_CORR_BROKEN
;
334 corr
[i
][3].coef
[0] = 31 - 2;
335 corr
[i
][3].coef
[1] = 32 + 2;
336 corr
[i
][3].coef
[2] = (1 << 29) / (31 - 2);
337 corr
[i
][3].coef
[3] = (1 << 29) / (31 - 2);
349 for (; j
< num_axes
; j
++) {
350 corr
[i
][j
].type
= JS_CORR_BROKEN
;
352 corr
[i
][j
].coef
[0] = 0;
353 corr
[i
][j
].coef
[1] = 0;
354 corr
[i
][j
].coef
[2] = (1 << 29);
355 corr
[i
][j
].coef
[3] = (1 << 29);
361 * js_sw_probe() probes for SideWinder type joysticks.
364 static struct js_port __init
*js_sw_probe(int io
, struct js_port
*port
)
366 struct js_sw_info info
;
368 int i
, j
, axes
, buttons
;
373 if (check_region(io
, 1)) return port
;
374 if (((u
= inb(io
)) & 3) == 3) return port
;
376 if (!((inb(io
) ^ u
) & ~u
& 0xf)) return port
;
378 i
= js_sw_read_packet(io
, JS_SW_MAX_LENGTH
, -1, JS_SW_EXT_STROBE
, &data
);
381 udelay(JS_SW_MIN_TIME
);
382 js_sw_init_digital(io
);
383 udelay(JS_SW_MAX_TIME
);
384 i
= js_sw_read_packet(io
, JS_SW_MAX_LENGTH
, -1, JS_SW_EXT_STROBE
, &data
);
397 info
.mode
= JS_SW_MODE_GP
;
398 outb(0xff,io
); /* Kick into 3-bit mode */
399 udelay(JS_SW_MAX_TIME
);
400 i
= js_sw_read_packet(io
, 60, -1, JS_SW_EXT_STROBE
, &data
); /* Get total length */
401 udelay(JS_SW_MIN_TIME
);
402 j
= js_sw_read_packet(io
, 15, -1, JS_SW_MIN_STROBE
, &data
); /* Get subpacket length */
404 printk(KERN_WARNING
"joy-sidewinder: SideWinder GamePad detected (%d,%d),"
405 " but not idenfitied.\n", i
, j
);
409 axes
= 2; buttons
= 10; name
= "SideWinder GamePad";
413 info
.mode
= JS_SW_MODE_PP
; info
.number
= 1;
414 axes
= 6; buttons
= 9; name
= "SideWinder Precision Pro";
418 info
.mode
= JS_SW_MODE_3DP
; info
.number
= 1; info
.optimize
= 0;
419 axes
= 6; buttons
= 8; name
= "SideWinder 3D Pro";
424 printk(KERN_WARNING
"joy-sidewinder: unknown joystick device detected "
425 "(io=%#x, count=%d, data=0x%08x%08x), contact <vojtech@ucw.cz>\n",
426 io
, i
, (int)(data
>> 32), (int)(data
& 0xffffffff));
432 request_region(io
, 1, "joystick (sidewinder)");
433 port
= js_register_port(port
, &info
, info
.number
, sizeof(struct js_sw_info
), js_sw_read
);
434 for (i
= 0; i
< info
.number
; i
++)
435 printk(KERN_INFO
"js%d: %s at %#x\n",
436 js_register_device(port
, i
, axes
, buttons
, name
, js_sw_open
, js_sw_close
), name
, io
);
437 js_sw_init_corr(axes
, info
.mode
, info
.number
, port
->corr
);
443 int init_module(void)
445 int __init
js_sw_init(void)
450 for (p
= js_sw_port_list
; *p
; p
++) js_sw_port
= js_sw_probe(*p
, js_sw_port
);
451 if (js_sw_port
) return 0;
454 printk(KERN_WARNING
"joy-sidewinder: no joysticks found\n");
461 void cleanup_module(void)
464 struct js_sw_info
*info
;
466 while (js_sw_port
!= NULL
) {
467 for (i
= 0; i
< js_sw_port
->ndevs
; i
++)
468 if (js_sw_port
->devs
[i
] != NULL
)
469 js_unregister_device(js_sw_port
->devs
[i
]);
470 info
= js_sw_port
->info
;
471 release_region(info
->io
, 1);
472 js_sw_port
= js_unregister_port(js_sw_port
);