2 * joy-thrustmaster.c Version 1.2
4 * Copyright (c) 1998 Vojtech Pavlik
8 * This is a module for the Linux joystick driver, supporting
9 * ThrustMaster DirectConnect (BSP) 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_TM_MAX_START 400
43 #define JS_TM_MAX_STROBE 25
44 #define JS_TM_MAX_LENGTH 13
46 #define JS_TM_MODE_M3DI 1
47 #define JS_TM_MODE_3DRP 3
48 #define JS_TM_MODE_WCS3 4
50 #define JS_TM_MODE_MAX 5 /* Last mode + 1 */
52 #define JS_TM_BYTE_A0 0
53 #define JS_TM_BYTE_A1 1
54 #define JS_TM_BYTE_A2 3
55 #define JS_TM_BYTE_A3 4
56 #define JS_TM_BYTE_A4 6
57 #define JS_TM_BYTE_A5 7
59 #define JS_TM_BYTE_D0 2
60 #define JS_TM_BYTE_D1 5
61 #define JS_TM_BYTE_D2 8
62 #define JS_TM_BYTE_D3 9
64 #define JS_TM_BYTE_ID 10
65 #define JS_TM_BYTE_REV 11
66 #define JS_TM_BYTE_DEF 12
68 static int js_tm_port_list
[] __initdata
= {0x201, 0};
69 static struct js_port
* js_tm_port __initdata
= NULL
;
76 static int js_tm_id_to_def
[JS_TM_MODE_MAX
] = {0x00, 0x42, 0x00, 0x22, 0x00};
79 * js_tm_read_packet() reads a ThrustMaster packet.
82 static int js_tm_read_packet(int io
, unsigned char *data
)
85 unsigned char u
, v
, error
;
89 int start
= (js_time_speed
* JS_TM_MAX_START
) >> 10;
90 int strobe
= (js_time_speed
* JS_TM_MAX_STROBE
) >> 10;
104 } while ((u
& 1) && js_delta(t1
, t
) < start
);
112 if ((u
^ v
) & u
& 2) {
114 if (j
< 9) { /* Data bit */
115 data
[i
] |= (~v
& 1) << (j
- 1);
117 } else { /* Stop bit */
122 } else { /* Start bit */
130 } while (!error
&& i
< JS_TM_MAX_LENGTH
&& js_delta(t1
,t
) < strobe
);
132 __restore_flags(flags
);
134 return -(i
!= JS_TM_MAX_LENGTH
);
138 * js_tm_read() reads and analyzes ThrustMaster joystick data.
141 static int js_tm_read(void *xinfo
, int **axes
, int **buttons
)
143 struct js_tm_info
*info
= xinfo
;
144 unsigned char data
[JS_TM_MAX_LENGTH
];
146 if (js_tm_read_packet(info
->io
, data
)) {
147 printk(KERN_WARNING
"joy-thrustmaster: failed to read data packet\n");
150 if (data
[JS_TM_BYTE_ID
] != info
->mode
) {
151 printk(KERN_WARNING
"joy-thrustmaster: ID (%d) != mode (%d)\n",
152 data
[JS_TM_BYTE_ID
], info
->mode
);
155 if (data
[JS_TM_BYTE_DEF
] != js_tm_id_to_def
[info
->mode
]) {
156 printk(KERN_WARNING
"joy-thrustmaster: DEF (%d) != def(mode) (%d)\n",
157 data
[JS_TM_BYTE_DEF
], js_tm_id_to_def
[info
->mode
]);
161 switch (info
->mode
) {
163 case JS_TM_MODE_M3DI
:
165 axes
[0][0] = data
[JS_TM_BYTE_A0
];
166 axes
[0][1] = data
[JS_TM_BYTE_A1
];
167 axes
[0][2] = data
[JS_TM_BYTE_A2
];
168 axes
[0][3] = data
[JS_TM_BYTE_A3
];
170 axes
[0][4] = ((data
[JS_TM_BYTE_D0
] >> 3) & 1) - ((data
[JS_TM_BYTE_D0
] >> 1) & 1);
171 axes
[0][5] = ((data
[JS_TM_BYTE_D0
] >> 2) & 1) - ( data
[JS_TM_BYTE_D0
] & 1);
173 buttons
[0][0] = ((data
[JS_TM_BYTE_D0
] >> 6) & 0x01) | ((data
[JS_TM_BYTE_D0
] >> 3) & 0x06)
174 | ((data
[JS_TM_BYTE_D0
] >> 4) & 0x08) | ((data
[JS_TM_BYTE_D1
] >> 2) & 0x30);
178 case JS_TM_MODE_3DRP
:
180 axes
[0][0] = data
[JS_TM_BYTE_A0
];
181 axes
[0][1] = data
[JS_TM_BYTE_A1
];
183 buttons
[0][0] = ( data
[JS_TM_BYTE_D0
] & 0x3f) | ((data
[JS_TM_BYTE_D1
] << 6) & 0xc0)
184 | (( ((int) data
[JS_TM_BYTE_D0
]) << 2) & 0x300);
194 * js_tm_open() is a callback from the file open routine.
197 static int js_tm_open(struct js_dev
*jd
)
204 * js_tm_close() is a callback from the file release routine.
207 static int js_tm_close(struct js_dev
*jd
)
214 * js_tm_init_corr() initializes the correction values for
215 * ThrustMaster joysticks.
218 static void __init
js_tm_init_corr(int num_axes
, int mode
, int **axes
, struct js_corr
**corr
)
222 for (j
= 0; j
< num_axes
; j
++) {
223 corr
[0][j
].type
= JS_CORR_BROKEN
;
225 corr
[0][j
].coef
[0] = 127 - 2;
226 corr
[0][j
].coef
[1] = 128 + 2;
227 corr
[0][j
].coef
[2] = (1 << 29) / (127 - 4);
228 corr
[0][j
].coef
[3] = (1 << 29) / (127 - 4);
232 case JS_TM_MODE_M3DI
: j
= 4; break;
233 case JS_TM_MODE_3DRP
: j
= 2; break;
234 default: j
= 0; break;
237 for (; j
< num_axes
; j
++) {
238 corr
[0][j
].type
= JS_CORR_BROKEN
;
240 corr
[0][j
].coef
[0] = 0;
241 corr
[0][j
].coef
[1] = 0;
242 corr
[0][j
].coef
[2] = (1 << 29);
243 corr
[0][j
].coef
[3] = (1 << 29);
249 * js_tm_probe() probes for ThrustMaster type joysticks.
252 static struct js_port __init
*js_tm_probe(int io
, struct js_port
*port
)
254 struct js_tm_info info
;
255 char *names
[JS_TM_MODE_MAX
] = { NULL
, "ThrustMaster Millenium 3D Inceptor", NULL
,
256 "ThrustMaster Rage 3D Gamepad", "ThrustMaster WCS III" };
257 char axes
[JS_TM_MODE_MAX
] = { 0, 6, 0, 2, 0 };
258 char buttons
[JS_TM_MODE_MAX
] = { 0, 5, 0, 10, 0 };
260 unsigned char data
[JS_TM_MAX_LENGTH
];
263 if (check_region(io
, 1)) return port
;
265 if (((u
= inb(io
)) & 3) == 3) return port
;
267 if (!((inb(io
) ^ u
) & ~u
& 0xf)) return port
;
269 if(js_tm_read_packet(io
, data
)) {
270 printk(KERN_WARNING
"joy-thrustmaster: probe - can't read packet\n");
275 info
.mode
= data
[JS_TM_BYTE_ID
];
277 if (!info
.mode
) return port
;
279 if (info
.mode
>= JS_TM_MODE_MAX
|| !names
[info
.mode
]) {
280 printk(KERN_WARNING
"joy-thrustmaster: unknown device detected "
281 "(io=%#x, id=%d), contact <vojtech@ucw.cz>\n",
286 if (data
[JS_TM_BYTE_DEF
] != js_tm_id_to_def
[info
.mode
]) {
287 printk(KERN_WARNING
"joy-thrustmaster: wrong DEF (%d) for ID %d - should be %d\n",
288 data
[JS_TM_BYTE_DEF
], info
.mode
, js_tm_id_to_def
[info
.mode
]);
291 request_region(io
, 1, "joystick (thrustmaster)");
292 port
= js_register_port(port
, &info
, 1, sizeof(struct js_tm_info
), js_tm_read
);
293 printk(KERN_INFO
"js%d: %s revision %d at %#x\n",
294 js_register_device(port
, 0, axes
[info
.mode
], buttons
[info
.mode
],
295 names
[info
.mode
], js_tm_open
, js_tm_close
), names
[info
.mode
], data
[JS_TM_BYTE_REV
], io
);
296 js_tm_init_corr(axes
[info
.mode
], info
.mode
, port
->axes
, port
->corr
);
302 int init_module(void)
304 int __init
js_tm_init(void)
309 for (p
= js_tm_port_list
; *p
; p
++) js_tm_port
= js_tm_probe(*p
, js_tm_port
);
310 if (js_tm_port
) return 0;
313 printk(KERN_WARNING
"joy-thrustmaster: no joysticks found\n");
320 void cleanup_module(void)
322 struct js_tm_info
*info
;
324 while (js_tm_port
!= NULL
) {
325 js_unregister_device(js_tm_port
->devs
[0]);
326 info
= js_tm_port
->info
;
327 release_region(info
->io
, 1);
328 js_tm_port
= js_unregister_port(js_tm_port
);