Linux 2.3.7pre1
[davej-history.git] / drivers / char / joystick / joy-thrustmaster.c
blob3ea71416dbb68e23105d5831088b7df66b4af689
1 /*
2 * joy-thrustmaster.c Version 1.2
4 * Copyright (c) 1998 Vojtech Pavlik
5 */
7 /*
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
32 #include <asm/io.h>
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;
71 struct js_tm_info {
72 int io;
73 unsigned char mode;
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)
84 unsigned int t, t1;
85 unsigned char u, v, error;
86 int i, j;
87 unsigned long flags;
89 int start = (js_time_speed * JS_TM_MAX_START) >> 10;
90 int strobe = (js_time_speed * JS_TM_MAX_STROBE) >> 10;
92 error = 0;
93 i = j = 0;
95 __save_flags(flags);
96 __cli();
97 outb(0xff,io);
99 t = js_get_time();
101 do {
102 u = inb(io);
103 t1 = js_get_time();
104 } while ((u & 1) && js_delta(t1, t) < start);
106 t = t1;
107 u >>= 4;
109 do {
110 v = inb(io) >> 4;
111 t1 = js_get_time();
112 if ((u ^ v) & u & 2) {
113 if (j) {
114 if (j < 9) { /* Data bit */
115 data[i] |= (~v & 1) << (j - 1);
116 j++;
117 } else { /* Stop bit */
118 error |= v & 1;
119 j = 0;
120 i++;
122 } else { /* Start bit */
123 data[i] = 0;
124 error |= ~v & 1;
125 j++;
127 t = t1;
129 u = v;
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");
148 return -1;
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);
153 return -1;
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]);
158 return -1;
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);
176 return 0;
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);
186 return 0;
190 return -1;
194 * js_tm_open() is a callback from the file open routine.
197 static int js_tm_open(struct js_dev *jd)
199 MOD_INC_USE_COUNT;
200 return 0;
204 * js_tm_close() is a callback from the file release routine.
207 static int js_tm_close(struct js_dev *jd)
209 MOD_DEC_USE_COUNT;
210 return 0;
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)
220 int j;
222 for (j = 0; j < num_axes; j++) {
223 corr[0][j].type = JS_CORR_BROKEN;
224 corr[0][j].prec = 0;
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);
231 switch (mode) {
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;
239 corr[0][j].prec = 0;
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];
261 unsigned char u;
263 if (check_region(io, 1)) return port;
265 if (((u = inb(io)) & 3) == 3) return port;
266 outb(0xff,io);
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");
271 return port;
274 info.io = io;
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",
282 io, info.mode);
283 return port;
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);
298 return port;
301 #ifdef MODULE
302 int init_module(void)
303 #else
304 int __init js_tm_init(void)
305 #endif
307 int *p;
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;
312 #ifdef MODULE
313 printk(KERN_WARNING "joy-thrustmaster: no joysticks found\n");
314 #endif
316 return -ENODEV;
319 #ifdef MODULE
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);
331 #endif