xref: /openbmc/linux/drivers/input/joystick/tmdc.c (revision ba61bb17)
1 /*
2  *  Copyright (c) 1998-2001 Vojtech Pavlik
3  *
4  *   Based on the work of:
5  *	Trystan Larey-Williams
6  */
7 
8 /*
9  * ThrustMaster DirectConnect (BSP) joystick family driver for Linux
10  */
11 
12 /*
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.
17  *
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.
22  *
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
26  *
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, Simunkova 1594, Prague 8, 182 00 Czech Republic
30  */
31 
32 #include <linux/delay.h>
33 #include <linux/kernel.h>
34 #include <linux/slab.h>
35 #include <linux/module.h>
36 #include <linux/gameport.h>
37 #include <linux/input.h>
38 #include <linux/jiffies.h>
39 
40 #define DRIVER_DESC	"ThrustMaster DirectConnect joystick driver"
41 
42 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
43 MODULE_DESCRIPTION(DRIVER_DESC);
44 MODULE_LICENSE("GPL");
45 
46 #define TMDC_MAX_START		600	/* 600 us */
47 #define TMDC_MAX_STROBE		60	/* 60 us */
48 #define TMDC_MAX_LENGTH		13
49 
50 #define TMDC_MODE_M3DI		1
51 #define TMDC_MODE_3DRP		3
52 #define TMDC_MODE_AT		4
53 #define TMDC_MODE_FM		8
54 #define TMDC_MODE_FGP		163
55 
56 #define TMDC_BYTE_ID		10
57 #define TMDC_BYTE_REV		11
58 #define TMDC_BYTE_DEF		12
59 
60 #define TMDC_ABS		7
61 #define TMDC_ABS_HAT		4
62 #define TMDC_BTN		16
63 
64 static const unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
65 static const unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 };
66 
67 static const signed char tmdc_abs[TMDC_ABS] =
68 	{ ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
69 static const signed char tmdc_abs_hat[TMDC_ABS_HAT] =
70 	{ ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
71 static const signed char tmdc_abs_at[TMDC_ABS] =
72 	{ ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE };
73 static const signed char tmdc_abs_fm[TMDC_ABS] =
74 	{ ABS_RX, ABS_RY, ABS_X, ABS_Y };
75 
76 static const short tmdc_btn_pad[TMDC_BTN] =
77 	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
78 static const short tmdc_btn_joy[TMDC_BTN] =
79 	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
80 	  BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
81 static const short tmdc_btn_fm[TMDC_BTN] =
82         { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
83 static const short tmdc_btn_at[TMDC_BTN] =
84         { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4,
85           BTN_BASE3, BTN_BASE2, BTN_BASE };
86 
87 static const struct {
88         int x;
89         int y;
90 } tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}};
91 
92 static const struct tmdc_model {
93 	unsigned char id;
94 	const char *name;
95 	char abs;
96 	char hats;
97 	char btnc[4];
98 	char btno[4];
99 	const signed char *axes;
100 	const short *buttons;
101 } tmdc_models[] = {
102 	{   1, "ThrustMaster Millenium 3D Inceptor",	  6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
103 	{   3, "ThrustMaster Rage 3D Gamepad",		  2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
104 	{   4, "ThrustMaster Attack Throttle",		  5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
105 	{   8, "ThrustMaster FragMaster",		  4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },
106 	{ 163, "Thrustmaster Fusion GamePad",		  2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
107 	{   0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }
108 };
109 
110 
111 struct tmdc_port {
112 	struct input_dev *dev;
113 	char name[64];
114 	char phys[32];
115 	int mode;
116 	const signed char *abs;
117 	const short *btn;
118 	unsigned char absc;
119 	unsigned char btnc[4];
120 	unsigned char btno[4];
121 };
122 
123 struct tmdc {
124 	struct gameport *gameport;
125 	struct tmdc_port *port[2];
126 #if 0
127 	struct input_dev *dev[2];
128 	char name[2][64];
129 	char phys[2][32];
130 	int mode[2];
131 	signed char *abs[2];
132 	short *btn[2];
133 	unsigned char absc[2];
134 	unsigned char btnc[2][4];
135 	unsigned char btno[2][4];
136 #endif
137 	int reads;
138 	int bads;
139 	unsigned char exists;
140 };
141 
142 /*
143  * tmdc_read_packet() reads a ThrustMaster packet.
144  */
145 
146 static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH])
147 {
148 	unsigned char u, v, w, x;
149 	unsigned long flags;
150 	int i[2], j[2], t[2], p, k;
151 
152 	p = gameport_time(gameport, TMDC_MAX_STROBE);
153 
154 	for (k = 0; k < 2; k++) {
155 		t[k] = gameport_time(gameport, TMDC_MAX_START);
156 		i[k] = j[k] = 0;
157 	}
158 
159 	local_irq_save(flags);
160 	gameport_trigger(gameport);
161 
162 	w = gameport_read(gameport) >> 4;
163 
164 	do {
165 		x = w;
166 		w = gameport_read(gameport) >> 4;
167 
168 		for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) {
169 			if (~v & u & 2) {
170 				if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue;
171 				t[k] = p;
172 				if (j[k] == 0) {				 /* Start bit */
173 					if (~v & 1) t[k] = 0;
174 					data[k][i[k]] = 0; j[k]++; continue;
175 				}
176 				if (j[k] == 9) {				/* Stop bit */
177 					if (v & 1) t[k] = 0;
178 					j[k] = 0; i[k]++; continue;
179 				}
180 				data[k][i[k]] |= (~v & 1) << (j[k]++ - 1);	/* Data bit */
181 			}
182 			t[k]--;
183 		}
184 	} while (t[0] > 0 || t[1] > 0);
185 
186 	local_irq_restore(flags);
187 
188 	return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1);
189 }
190 
191 static int tmdc_parse_packet(struct tmdc_port *port, unsigned char *data)
192 {
193 	int i, k, l;
194 
195 	if (data[TMDC_BYTE_ID] != port->mode)
196 		return -1;
197 
198 	for (i = 0; i < port->absc; i++) {
199 		if (port->abs[i] < 0)
200 			return 0;
201 
202 		input_report_abs(port->dev, port->abs[i], data[tmdc_byte_a[i]]);
203 	}
204 
205 	switch (port->mode) {
206 
207 		case TMDC_MODE_M3DI:
208 
209 			i = tmdc_byte_d[0];
210 			input_report_abs(port->dev, ABS_HAT0X, ((data[i] >> 3) & 1) - ((data[i] >> 1) & 1));
211 			input_report_abs(port->dev, ABS_HAT0Y, ((data[i] >> 2) & 1) - ( data[i]       & 1));
212 			break;
213 
214 		case TMDC_MODE_AT:
215 
216 			i = tmdc_byte_a[3];
217 			input_report_abs(port->dev, ABS_HAT0X, tmdc_hat_to_axis[(data[i] - 141) / 25].x);
218 			input_report_abs(port->dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[i] - 141) / 25].y);
219 			break;
220 
221 	}
222 
223 	for (k = l = 0; k < 4; k++) {
224 		for (i = 0; i < port->btnc[k]; i++)
225 			input_report_key(port->dev, port->btn[i + l],
226 				((data[tmdc_byte_d[k]] >> (i + port->btno[k])) & 1));
227 		l += port->btnc[k];
228 	}
229 
230 	input_sync(port->dev);
231 
232 	return 0;
233 }
234 
235 /*
236  * tmdc_poll() reads and analyzes ThrustMaster joystick data.
237  */
238 
239 static void tmdc_poll(struct gameport *gameport)
240 {
241 	unsigned char data[2][TMDC_MAX_LENGTH];
242 	struct tmdc *tmdc = gameport_get_drvdata(gameport);
243 	unsigned char r, bad = 0;
244 	int i;
245 
246 	tmdc->reads++;
247 
248 	if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
249 		bad = 1;
250 	else {
251 		for (i = 0; i < 2; i++) {
252 			if (r & (1 << i) & tmdc->exists) {
253 
254 				if (tmdc_parse_packet(tmdc->port[i], data[i]))
255 					bad = 1;
256 			}
257 		}
258 	}
259 
260 	tmdc->bads += bad;
261 }
262 
263 static int tmdc_open(struct input_dev *dev)
264 {
265 	struct tmdc *tmdc = input_get_drvdata(dev);
266 
267 	gameport_start_polling(tmdc->gameport);
268 	return 0;
269 }
270 
271 static void tmdc_close(struct input_dev *dev)
272 {
273 	struct tmdc *tmdc = input_get_drvdata(dev);
274 
275 	gameport_stop_polling(tmdc->gameport);
276 }
277 
278 static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data)
279 {
280 	const struct tmdc_model *model;
281 	struct tmdc_port *port;
282 	struct input_dev *input_dev;
283 	int i, j, b = 0;
284 	int err;
285 
286 	tmdc->port[idx] = port = kzalloc(sizeof (struct tmdc_port), GFP_KERNEL);
287 	input_dev = input_allocate_device();
288 	if (!port || !input_dev) {
289 		err = -ENOMEM;
290 		goto fail;
291 	}
292 
293 	port->mode = data[TMDC_BYTE_ID];
294 
295 	for (model = tmdc_models; model->id && model->id != port->mode; model++)
296 		/* empty */;
297 
298 	port->abs = model->axes;
299 	port->btn = model->buttons;
300 
301 	if (!model->id) {
302 		port->absc = data[TMDC_BYTE_DEF] >> 4;
303 		for (i = 0; i < 4; i++)
304 			port->btnc[i] = i < (data[TMDC_BYTE_DEF] & 0xf) ? 8 : 0;
305 	} else {
306 		port->absc = model->abs;
307 		for (i = 0; i < 4; i++)
308 			port->btnc[i] = model->btnc[i];
309 	}
310 
311 	for (i = 0; i < 4; i++)
312 		port->btno[i] = model->btno[i];
313 
314 	snprintf(port->name, sizeof(port->name), model->name,
315 		 port->absc, (data[TMDC_BYTE_DEF] & 0xf) << 3, port->mode);
316 	snprintf(port->phys, sizeof(port->phys), "%s/input%d", tmdc->gameport->phys, i);
317 
318 	port->dev = input_dev;
319 
320 	input_dev->name = port->name;
321 	input_dev->phys = port->phys;
322 	input_dev->id.bustype = BUS_GAMEPORT;
323 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
324 	input_dev->id.product = model->id;
325 	input_dev->id.version = 0x0100;
326 	input_dev->dev.parent = &tmdc->gameport->dev;
327 
328 	input_set_drvdata(input_dev, tmdc);
329 
330 	input_dev->open = tmdc_open;
331 	input_dev->close = tmdc_close;
332 
333 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
334 
335 	for (i = 0; i < port->absc && i < TMDC_ABS; i++)
336 		if (port->abs[i] >= 0)
337 			input_set_abs_params(input_dev, port->abs[i], 8, 248, 2, 4);
338 
339 	for (i = 0; i < model->hats && i < TMDC_ABS_HAT; i++)
340 		input_set_abs_params(input_dev, tmdc_abs_hat[i], -1, 1, 0, 0);
341 
342 	for (i = 0; i < 4; i++) {
343 		for (j = 0; j < port->btnc[i] && j < TMDC_BTN; j++)
344 			set_bit(port->btn[j + b], input_dev->keybit);
345 		b += port->btnc[i];
346 	}
347 
348 	err = input_register_device(port->dev);
349 	if (err)
350 		goto fail;
351 
352 	return 0;
353 
354  fail:	input_free_device(input_dev);
355 	kfree(port);
356 	return err;
357 }
358 
359 /*
360  * tmdc_probe() probes for ThrustMaster type joysticks.
361  */
362 
363 static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
364 {
365 	unsigned char data[2][TMDC_MAX_LENGTH];
366 	struct tmdc *tmdc;
367 	int i;
368 	int err;
369 
370 	if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL)))
371 		return -ENOMEM;
372 
373 	tmdc->gameport = gameport;
374 
375 	gameport_set_drvdata(gameport, tmdc);
376 
377 	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
378 	if (err)
379 		goto fail1;
380 
381 	if (!(tmdc->exists = tmdc_read_packet(gameport, data))) {
382 		err = -ENODEV;
383 		goto fail2;
384 	}
385 
386 	gameport_set_poll_handler(gameport, tmdc_poll);
387 	gameport_set_poll_interval(gameport, 20);
388 
389 	for (i = 0; i < 2; i++) {
390 		if (tmdc->exists & (1 << i)) {
391 
392 			err = tmdc_setup_port(tmdc, i, data[i]);
393 			if (err)
394 				goto fail3;
395 		}
396 	}
397 
398 	return 0;
399 
400  fail3: while (--i >= 0) {
401 		if (tmdc->port[i]) {
402 			input_unregister_device(tmdc->port[i]->dev);
403 			kfree(tmdc->port[i]);
404 		}
405 	}
406  fail2:	gameport_close(gameport);
407  fail1:	gameport_set_drvdata(gameport, NULL);
408 	kfree(tmdc);
409 	return err;
410 }
411 
412 static void tmdc_disconnect(struct gameport *gameport)
413 {
414 	struct tmdc *tmdc = gameport_get_drvdata(gameport);
415 	int i;
416 
417 	for (i = 0; i < 2; i++) {
418 		if (tmdc->port[i]) {
419 			input_unregister_device(tmdc->port[i]->dev);
420 			kfree(tmdc->port[i]);
421 		}
422 	}
423 	gameport_close(gameport);
424 	gameport_set_drvdata(gameport, NULL);
425 	kfree(tmdc);
426 }
427 
428 static struct gameport_driver tmdc_drv = {
429 	.driver		= {
430 		.name	= "tmdc",
431 		.owner	= THIS_MODULE,
432 	},
433 	.description	= DRIVER_DESC,
434 	.connect	= tmdc_connect,
435 	.disconnect	= tmdc_disconnect,
436 };
437 
438 module_gameport_driver(tmdc_drv);
439