2 * $Id: tmdc.c,v 1.18 2000/06/08 19:59:59 vojtech Exp $
4 * Copyright (c) 1998-2000 Vojtech Pavlik
8 * Based on the work of:
9 * Trystan Larey-Williams
14 * ThrustMaster DirectConnect (BSP) joystick family driver for Linux
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * Should you need to contact me, the author, you can do so either by
33 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
34 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
37 #include <linux/delay.h>
38 #include <linux/kernel.h>
39 #include <linux/malloc.h>
40 #include <linux/module.h>
41 #include <linux/init.h>
42 #include <linux/gameport.h>
43 #include <linux/input.h>
45 #define TMDC_MAX_START 400 /* 400 us */
46 #define TMDC_MAX_STROBE 45 /* 45 us */
47 #define TMDC_MAX_LENGTH 13
48 #define TMDC_REFRESH_TIME HZ/50 /* 20 ms */
50 #define TMDC_MODE_M3DI 1
51 #define TMDC_MODE_3DRP 3
52 #define TMDC_MODE_FGP 163
54 #define TMDC_BYTE_ID 10
55 #define TMDC_BYTE_REV 11
56 #define TMDC_BYTE_DEF 12
59 #define TMDC_ABS_HAT 4
60 #define TMDC_BTN_PAD 10
61 #define TMDC_BTN_JOY 16
63 static unsigned char tmdc_byte_a
[16] = { 0, 1, 3, 4, 6, 7 };
64 static unsigned char tmdc_byte_d
[16] = { 2, 5, 8, 9 };
66 static unsigned char tmdc_abs
[TMDC_ABS
] =
67 { ABS_X
, ABS_Y
, ABS_RUDDER
, ABS_THROTTLE
, ABS_RX
, ABS_RY
, ABS_RZ
};
68 static unsigned char tmdc_abs_hat
[TMDC_ABS_HAT
] =
69 { ABS_HAT0X
, ABS_HAT0Y
, ABS_HAT1X
, ABS_HAT1Y
};
70 static unsigned short tmdc_btn_pad
[TMDC_BTN_PAD
] =
71 { BTN_A
, BTN_B
, BTN_C
, BTN_X
, BTN_Y
, BTN_Z
, BTN_START
, BTN_SELECT
, BTN_TL
, BTN_TR
};
72 static unsigned short tmdc_btn_joy
[TMDC_BTN_JOY
] =
73 { BTN_TRIGGER
, BTN_THUMB
, BTN_TOP
, BTN_TOP2
, BTN_BASE
, BTN_BASE2
, BTN_THUMB2
, BTN_PINKIE
,
74 BTN_BASE3
, BTN_BASE4
, BTN_A
, BTN_B
, BTN_C
, BTN_X
, BTN_Y
, BTN_Z
};
77 struct gameport
*gameport
;
78 struct timer_list timer
;
79 struct input_dev dev
[2];
89 * tmdc_read_packet() reads a ThrustMaster packet.
92 static int tmdc_read_packet(struct gameport
*gameport
, unsigned char data
[2][TMDC_MAX_LENGTH
])
94 unsigned char u
, v
, w
, x
;
96 int i
[2], j
[2], t
[2], p
, k
;
98 p
= gameport_time(gameport
, TMDC_MAX_STROBE
);
100 for (k
= 0; k
< 2; k
++) {
101 t
[k
] = gameport_time(gameport
, TMDC_MAX_START
);
107 gameport_trigger(gameport
);
109 w
= gameport_read(gameport
) >> 4;
113 w
= gameport_read(gameport
) >> 4;
115 for (k
= 0, v
= w
, u
= x
; k
< 2; k
++, v
>>= 2, u
>>= 2) {
117 if (t
[k
] <= 0 || i
[k
] >= TMDC_MAX_LENGTH
) continue;
119 if (j
[k
] == 0) { /* Start bit */
120 if (~v
& 1) t
[k
] = 0;
121 data
[k
][i
[k
]] = 0; j
[k
]++; continue;
123 if (j
[k
] == 9) { /* Stop bit */
125 j
[k
] = 0; i
[k
]++; continue;
127 data
[k
][i
[k
]] |= (~v
& 1) << (j
[k
]++ - 1); /* Data bit */
131 } while (t
[0] > 0 || t
[1] > 0);
133 __restore_flags(flags
);
135 return (i
[0] == TMDC_MAX_LENGTH
) | ((i
[1] == TMDC_MAX_LENGTH
) << 1);
139 * tmdc_read() reads and analyzes ThrustMaster joystick data.
142 static void tmdc_timer(unsigned long private)
144 unsigned char data
[2][TMDC_MAX_LENGTH
];
145 struct tmdc
*tmdc
= (void *) private;
146 struct input_dev
*dev
;
147 unsigned char r
, bad
= 0;
152 if ((r
= tmdc_read_packet(tmdc
->gameport
, data
)) != tmdc
->exists
)
155 for (j
= 0; j
< 2; j
++)
156 if (r
& (1 << j
) & tmdc
->exists
) {
158 if (data
[j
][TMDC_BYTE_ID
] != tmdc
->mode
[j
]) {
165 for (i
= 0; i
< data
[j
][TMDC_BYTE_DEF
] >> 4; i
++)
166 input_report_abs(dev
, tmdc_abs
[i
], data
[j
][tmdc_byte_a
[i
]]);
168 switch (tmdc
->mode
[j
]) {
174 input_report_abs(dev
, ABS_HAT0X
, ((data
[j
][i
] >> 3) & 1) - ((data
[j
][i
] >> 1) & 1));
175 input_report_abs(dev
, ABS_HAT0Y
, ((data
[j
][i
] >> 2) & 1) - ( data
[j
][i
] & 1));
177 for (i
= 0; i
< 4; i
++)
178 input_report_key(dev
, tmdc_btn_joy
[i
],
179 (data
[j
][tmdc_byte_d
[0]] >> (i
+ 4)) & 1);
180 for (i
= 0; i
< 2; i
++)
181 input_report_key(dev
, tmdc_btn_joy
[i
+ 4],
182 (data
[j
][tmdc_byte_d
[1]] >> (i
+ 6)) & 1);
189 for (i
= 0; i
< 10; i
++)
190 input_report_key(dev
, tmdc_btn_pad
[i
],
191 (data
[j
][tmdc_byte_d
[i
>> 3]] >> (i
& 7)) & 1);
197 for (i
= 0; i
< ((data
[j
][TMDC_BYTE_DEF
] & 0xf) << 3) && i
< TMDC_BTN_JOY
; i
++)
198 input_report_key(dev
, tmdc_btn_joy
[i
],
199 (data
[j
][tmdc_byte_d
[i
>> 3]] >> (i
& 7)) & 1);
208 mod_timer(&tmdc
->timer
, jiffies
+ TMDC_REFRESH_TIME
);
211 static int tmdc_open(struct input_dev
*dev
)
213 struct tmdc
*tmdc
= dev
->private;
215 mod_timer(&tmdc
->timer
, jiffies
+ TMDC_REFRESH_TIME
);
219 static void tmdc_close(struct input_dev
*dev
)
221 struct tmdc
*tmdc
= dev
->private;
223 del_timer(&tmdc
->timer
);
227 * tmdc_probe() probes for ThrustMaster type joysticks.
230 static void tmdc_connect(struct gameport
*gameport
, struct gameport_dev
*dev
)
233 struct js_tm_models
{
240 } models
[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 0, 6, 0 },
241 { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, 0, 10 },
242 { 163, "Thrustmaster Fusion GamePad", 2, 0, 0, 10 },
243 { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, 0, 0 }};
244 unsigned char data
[2][TMDC_MAX_LENGTH
];
247 if (!(tmdc
= kmalloc(sizeof(struct tmdc
), GFP_KERNEL
)))
249 memset(tmdc
, 0, sizeof(struct tmdc
));
251 gameport
->private = tmdc
;
253 tmdc
->gameport
= gameport
;
254 init_timer(&tmdc
->timer
);
255 tmdc
->timer
.data
= (long) tmdc
;
256 tmdc
->timer
.function
= tmdc_timer
;
258 if (gameport_open(gameport
, dev
, GAMEPORT_MODE_RAW
))
261 if (!(tmdc
->exists
= tmdc_read_packet(gameport
, data
)))
264 for (j
= 0; j
< 2; j
++)
265 if (tmdc
->exists
& (1 << j
)) {
267 tmdc
->mode
[j
] = data
[j
][TMDC_BYTE_ID
];
269 for (m
= 0; models
[m
].id
&& models
[m
].id
!= tmdc
->mode
[j
]; m
++);
272 models
[m
].abs
= data
[j
][TMDC_BYTE_DEF
] >> 4;
273 models
[m
].joybtn
= (data
[j
][TMDC_BYTE_DEF
] & 0xf) << 3;
276 sprintf(tmdc
->name
[j
], models
[m
].name
, models
[m
].abs
, models
[m
].joybtn
, tmdc
->mode
[j
]);
278 tmdc
->dev
[j
].private = tmdc
;
279 tmdc
->dev
[j
].open
= tmdc_open
;
280 tmdc
->dev
[j
].close
= tmdc_close
;
282 tmdc
->dev
[j
].name
= tmdc
->name
[j
];
283 tmdc
->dev
[j
].idbus
= BUS_GAMEPORT
;
284 tmdc
->dev
[j
].idvendor
= GAMEPORT_ID_VENDOR_THRUSTMASTER
;
285 tmdc
->dev
[j
].idproduct
= models
[m
].id
;
286 tmdc
->dev
[j
].idversion
= 0x0100;
288 tmdc
->dev
[j
].evbit
[0] = BIT(EV_KEY
) | BIT(EV_ABS
);
290 for (i
= 0; i
< models
[m
].abs
&& i
< TMDC_ABS
; i
++) {
291 set_bit(tmdc_abs
[i
], tmdc
->dev
[j
].absbit
);
292 tmdc
->dev
[j
].absmin
[tmdc_abs
[i
]] = 8;
293 tmdc
->dev
[j
].absmax
[tmdc_abs
[i
]] = 248;
294 tmdc
->dev
[j
].absfuzz
[tmdc_abs
[i
]] = 2;
295 tmdc
->dev
[j
].absflat
[tmdc_abs
[i
]] = 4;
298 for (i
= 0; i
< models
[m
].hats
&& i
< TMDC_ABS_HAT
; i
++) {
299 set_bit(tmdc_abs_hat
[i
], tmdc
->dev
[j
].absbit
);
300 tmdc
->dev
[j
].absmin
[tmdc_abs_hat
[i
]] = -1;
301 tmdc
->dev
[j
].absmax
[tmdc_abs_hat
[i
]] = 1;
304 for (i
= 0; i
< models
[m
].joybtn
&& i
< TMDC_BTN_JOY
; i
++)
305 set_bit(tmdc_btn_joy
[i
], tmdc
->dev
[j
].keybit
);
307 for (i
= 0; i
< models
[m
].padbtn
&& i
< TMDC_BTN_PAD
; i
++)
308 set_bit(tmdc_btn_pad
[i
], tmdc
->dev
[j
].keybit
);
310 input_register_device(tmdc
->dev
+ j
);
311 printk(KERN_INFO
"input%d: %s on gameport%d.%d\n",
312 tmdc
->dev
[j
].number
, tmdc
->name
[j
], gameport
->number
, j
);
316 fail2
: gameport_close(gameport
);
320 static void tmdc_disconnect(struct gameport
*gameport
)
322 struct tmdc
*tmdc
= gameport
->private;
324 for (i
= 0; i
< 2; i
++)
325 if (tmdc
->exists
& (1 << i
))
326 input_unregister_device(tmdc
->dev
+ i
);
327 gameport_close(gameport
);
331 static struct gameport_dev tmdc_dev
= {
332 connect
: tmdc_connect
,
333 disconnect
: tmdc_disconnect
,
336 int __init
tmdc_init(void)
338 gameport_register_device(&tmdc_dev
);
342 void __exit
tmdc_exit(void)
344 gameport_unregister_device(&tmdc_dev
);
347 module_init(tmdc_init
);
348 module_exit(tmdc_exit
);