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