2 * joy-thrustmaster.c Version 1.2
4 * Copyright (c) 1998-1999 Vojtech Pavlik
10 * This is a module for the Linux joystick driver, supporting
11 * ThrustMaster DirectConnect (BSP) joystick family.
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/system.h>
36 #include <linux/delay.h>
37 #include <linux/errno.h>
38 #include <linux/ioport.h>
39 #include <linux/joystick.h>
40 #include <linux/kernel.h>
41 #include <linux/module.h>
42 #include <linux/string.h>
43 #include <linux/init.h>
45 #define JS_TM_MAX_START 400
46 #define JS_TM_MAX_STROBE 45
47 #define JS_TM_MAX_LENGTH 13
49 #define JS_TM_MODE_M3DI 1
50 #define JS_TM_MODE_3DRP 3
51 #define JS_TM_MODE_FGP 163
53 #define JS_TM_BYTE_ID 10
54 #define JS_TM_BYTE_REV 11
55 #define JS_TM_BYTE_DEF 12
57 static int js_tm_port_list
[] __initdata
= {0x201, 0};
58 static struct js_port
* js_tm_port __initdata
= NULL
;
60 static unsigned char js_tm_byte_a
[16] = { 0, 1, 3, 4, 6, 7 };
61 static unsigned char js_tm_byte_d
[16] = { 2, 5, 8, 9 };
69 * js_tm_read_packet() reads a ThrustMaster packet.
72 static int js_tm_read_packet(int io
, unsigned char *data
)
75 unsigned char u
, v
, error
;
81 p
= t
= JS_TM_MAX_START
;
91 u
= v
; v
= inb(io
) >> 4;
94 if (j
< 9) { /* Data bit */
95 data
[i
] |= (~v
& 1) << (j
- 1);
97 } else { /* Stop bit */
102 } else { /* Start bit */
107 p
= t
= (p
- t
) << 1;
109 } while (!error
&& i
< JS_TM_MAX_LENGTH
&& t
> 0);
111 __restore_flags(flags
);
113 return -(i
!= JS_TM_MAX_LENGTH
);
117 * js_tm_read() reads and analyzes ThrustMaster joystick data.
120 static int js_tm_read(void *xinfo
, int **axes
, int **buttons
)
122 struct js_tm_info
*info
= xinfo
;
123 unsigned char data
[JS_TM_MAX_LENGTH
];
126 if (js_tm_read_packet(info
->io
, data
)) return -1;
127 if (data
[JS_TM_BYTE_ID
] != info
->mode
) return -1;
129 for (i
= 0; i
< data
[JS_TM_BYTE_DEF
] >> 4; i
++) axes
[0][i
] = data
[js_tm_byte_a
[i
]];
131 switch (info
->mode
) {
133 case JS_TM_MODE_M3DI
:
135 axes
[0][4] = ((data
[js_tm_byte_d
[0]] >> 3) & 1) - ((data
[js_tm_byte_d
[0]] >> 1) & 1);
136 axes
[0][5] = ((data
[js_tm_byte_d
[0]] >> 2) & 1) - ( data
[js_tm_byte_d
[0]] & 1);
138 buttons
[0][0] = ((data
[js_tm_byte_d
[0]] >> 6) & 0x01) | ((data
[js_tm_byte_d
[0]] >> 3) & 0x06)
139 | ((data
[js_tm_byte_d
[0]] >> 4) & 0x08) | ((data
[js_tm_byte_d
[1]] >> 2) & 0x30);
143 case JS_TM_MODE_3DRP
:
146 buttons
[0][0] = (data
[js_tm_byte_d
[0]] & 0x3f) | ((data
[js_tm_byte_d
[1]] << 6) & 0xc0)
147 | (( ((int) data
[js_tm_byte_d
[0]]) << 2) & 0x300);
155 for (i
= 0; i
< (data
[JS_TM_BYTE_DEF
] & 0xf); i
++)
156 buttons
[0][0] |= ((int) data
[js_tm_byte_d
[i
]]) << (i
<< 3);
166 * js_tm_init_corr() initializes the correction values for
167 * ThrustMaster joysticks.
170 static void __init
js_tm_init_corr(int num_axes
, int mode
, int **axes
, struct js_corr
**corr
)
174 for (; j
< num_axes
; j
++) {
175 corr
[0][j
].type
= JS_CORR_BROKEN
;
177 corr
[0][j
].coef
[0] = 127 - 2;
178 corr
[0][j
].coef
[1] = 128 + 2;
179 corr
[0][j
].coef
[2] = (1 << 29) / (127 - 4);
180 corr
[0][j
].coef
[3] = (1 << 29) / (127 - 4);
184 case JS_TM_MODE_M3DI
: j
= 4; break;
188 for (; j
< num_axes
; j
++) {
189 corr
[0][j
].type
= JS_CORR_BROKEN
;
191 corr
[0][j
].coef
[0] = 0;
192 corr
[0][j
].coef
[1] = 0;
193 corr
[0][j
].coef
[2] = (1 << 29);
194 corr
[0][j
].coef
[3] = (1 << 29);
200 * js_tm_probe() probes for ThrustMaster type joysticks.
203 static struct js_port __init
*js_tm_probe(int io
, struct js_port
*port
)
205 struct js_tm_info info
;
206 struct js_rm_models
{
211 } models
[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 6 },
212 { 3, "ThrustMaster Rage 3D Gamepad", 2, 10 },
213 { 163, "Thrustmaster Fusion GamePad", 2, 10 },
216 unsigned char data
[JS_TM_MAX_LENGTH
];
220 if (check_region(io
, 1)) return port
;
222 if (js_tm_read_packet(io
, data
)) return port
;
225 info
.mode
= data
[JS_TM_BYTE_ID
];
227 if (!info
.mode
) return port
;
229 for (i
= 0; models
[i
].id
&& models
[i
].id
!= info
.mode
; i
++);
231 if (models
[i
].id
!= info
.mode
) {
232 a
= data
[JS_TM_BYTE_DEF
] >> 4;
233 b
= (data
[JS_TM_BYTE_DEF
] & 0xf) << 3;
234 sprintf(name
, "Unknown %d-axis, %d-button TM device %d", a
, b
, info
.mode
);
236 sprintf(name
, models
[i
].name
);
238 b
= models
[i
].buttons
;
241 request_region(io
, 1, "joystick (thrustmaster)");
242 port
= js_register_port(port
, &info
, 1, sizeof(struct js_tm_info
), js_tm_read
);
243 printk(KERN_INFO
"js%d: %s revision %d at %#x\n",
244 js_register_device(port
, 0, a
, b
, name
, THIS_MODULE
, NULL
, NULL
), name
, data
[JS_TM_BYTE_REV
], io
);
245 js_tm_init_corr(a
, info
.mode
, port
->axes
, port
->corr
);
251 int init_module(void)
253 int __init
js_tm_init(void)
258 for (p
= js_tm_port_list
; *p
; p
++) js_tm_port
= js_tm_probe(*p
, js_tm_port
);
259 if (js_tm_port
) return 0;
262 printk(KERN_WARNING
"joy-thrustmaster: no joysticks found\n");
269 void cleanup_module(void)
271 struct js_tm_info
*info
;
274 js_unregister_device(js_tm_port
->devs
[0]);
275 info
= js_tm_port
->info
;
276 release_region(info
->io
, 1);
277 js_tm_port
= js_unregister_port(js_tm_port
);