Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) 1998-2001 Vojtech Pavlik
0004  *
0005  *   Based on the work of:
0006  *  Trystan Larey-Williams
0007  */
0008 
0009 /*
0010  * ThrustMaster DirectConnect (BSP) joystick family driver for Linux
0011  */
0012 
0013 /*
0014  */
0015 
0016 #include <linux/delay.h>
0017 #include <linux/kernel.h>
0018 #include <linux/slab.h>
0019 #include <linux/module.h>
0020 #include <linux/gameport.h>
0021 #include <linux/input.h>
0022 #include <linux/jiffies.h>
0023 
0024 #define DRIVER_DESC "ThrustMaster DirectConnect joystick driver"
0025 
0026 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
0027 MODULE_DESCRIPTION(DRIVER_DESC);
0028 MODULE_LICENSE("GPL");
0029 
0030 #define TMDC_MAX_START      600 /* 600 us */
0031 #define TMDC_MAX_STROBE     60  /* 60 us */
0032 #define TMDC_MAX_LENGTH     13
0033 
0034 #define TMDC_MODE_M3DI      1
0035 #define TMDC_MODE_3DRP      3
0036 #define TMDC_MODE_AT        4
0037 #define TMDC_MODE_FM        8
0038 #define TMDC_MODE_FGP       163
0039 
0040 #define TMDC_BYTE_ID        10
0041 #define TMDC_BYTE_REV       11
0042 #define TMDC_BYTE_DEF       12
0043 
0044 #define TMDC_ABS        7
0045 #define TMDC_ABS_HAT        4
0046 #define TMDC_BTN        16
0047 
0048 static const unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
0049 static const unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 };
0050 
0051 static const signed char tmdc_abs[TMDC_ABS] =
0052     { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
0053 static const signed char tmdc_abs_hat[TMDC_ABS_HAT] =
0054     { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
0055 static const signed char tmdc_abs_at[TMDC_ABS] =
0056     { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE };
0057 static const signed char tmdc_abs_fm[TMDC_ABS] =
0058     { ABS_RX, ABS_RY, ABS_X, ABS_Y };
0059 
0060 static const short tmdc_btn_pad[TMDC_BTN] =
0061     { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
0062 static const short tmdc_btn_joy[TMDC_BTN] =
0063     { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
0064       BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
0065 static const short tmdc_btn_fm[TMDC_BTN] =
0066         { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
0067 static const short tmdc_btn_at[TMDC_BTN] =
0068         { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4,
0069           BTN_BASE3, BTN_BASE2, BTN_BASE };
0070 
0071 static const struct {
0072         int x;
0073         int y;
0074 } tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}};
0075 
0076 static const struct tmdc_model {
0077     unsigned char id;
0078     const char *name;
0079     char abs;
0080     char hats;
0081     char btnc[4];
0082     char btno[4];
0083     const signed char *axes;
0084     const short *buttons;
0085 } tmdc_models[] = {
0086     {   1, "ThrustMaster Millennium 3D Inceptor",     6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
0087     {   3, "ThrustMaster Rage 3D Gamepad",        2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
0088     {   4, "ThrustMaster Attack Throttle",        5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
0089     {   8, "ThrustMaster FragMaster",         4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },
0090     { 163, "Thrustmaster Fusion GamePad",         2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
0091     {   0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }
0092 };
0093 
0094 
0095 struct tmdc_port {
0096     struct input_dev *dev;
0097     char name[64];
0098     char phys[32];
0099     int mode;
0100     const signed char *abs;
0101     const short *btn;
0102     unsigned char absc;
0103     unsigned char btnc[4];
0104     unsigned char btno[4];
0105 };
0106 
0107 struct tmdc {
0108     struct gameport *gameport;
0109     struct tmdc_port *port[2];
0110 #if 0
0111     struct input_dev *dev[2];
0112     char name[2][64];
0113     char phys[2][32];
0114     int mode[2];
0115     signed char *abs[2];
0116     short *btn[2];
0117     unsigned char absc[2];
0118     unsigned char btnc[2][4];
0119     unsigned char btno[2][4];
0120 #endif
0121     int reads;
0122     int bads;
0123     unsigned char exists;
0124 };
0125 
0126 /*
0127  * tmdc_read_packet() reads a ThrustMaster packet.
0128  */
0129 
0130 static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH])
0131 {
0132     unsigned char u, v, w, x;
0133     unsigned long flags;
0134     int i[2], j[2], t[2], p, k;
0135 
0136     p = gameport_time(gameport, TMDC_MAX_STROBE);
0137 
0138     for (k = 0; k < 2; k++) {
0139         t[k] = gameport_time(gameport, TMDC_MAX_START);
0140         i[k] = j[k] = 0;
0141     }
0142 
0143     local_irq_save(flags);
0144     gameport_trigger(gameport);
0145 
0146     w = gameport_read(gameport) >> 4;
0147 
0148     do {
0149         x = w;
0150         w = gameport_read(gameport) >> 4;
0151 
0152         for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) {
0153             if (~v & u & 2) {
0154                 if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue;
0155                 t[k] = p;
0156                 if (j[k] == 0) {                 /* Start bit */
0157                     if (~v & 1) t[k] = 0;
0158                     data[k][i[k]] = 0; j[k]++; continue;
0159                 }
0160                 if (j[k] == 9) {                /* Stop bit */
0161                     if (v & 1) t[k] = 0;
0162                     j[k] = 0; i[k]++; continue;
0163                 }
0164                 data[k][i[k]] |= (~v & 1) << (j[k]++ - 1);  /* Data bit */
0165             }
0166             t[k]--;
0167         }
0168     } while (t[0] > 0 || t[1] > 0);
0169 
0170     local_irq_restore(flags);
0171 
0172     return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1);
0173 }
0174 
0175 static int tmdc_parse_packet(struct tmdc_port *port, unsigned char *data)
0176 {
0177     int i, k, l;
0178 
0179     if (data[TMDC_BYTE_ID] != port->mode)
0180         return -1;
0181 
0182     for (i = 0; i < port->absc; i++) {
0183         if (port->abs[i] < 0)
0184             return 0;
0185 
0186         input_report_abs(port->dev, port->abs[i], data[tmdc_byte_a[i]]);
0187     }
0188 
0189     switch (port->mode) {
0190 
0191         case TMDC_MODE_M3DI:
0192 
0193             i = tmdc_byte_d[0];
0194             input_report_abs(port->dev, ABS_HAT0X, ((data[i] >> 3) & 1) - ((data[i] >> 1) & 1));
0195             input_report_abs(port->dev, ABS_HAT0Y, ((data[i] >> 2) & 1) - ( data[i]       & 1));
0196             break;
0197 
0198         case TMDC_MODE_AT:
0199 
0200             i = tmdc_byte_a[3];
0201             input_report_abs(port->dev, ABS_HAT0X, tmdc_hat_to_axis[(data[i] - 141) / 25].x);
0202             input_report_abs(port->dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[i] - 141) / 25].y);
0203             break;
0204 
0205     }
0206 
0207     for (k = l = 0; k < 4; k++) {
0208         for (i = 0; i < port->btnc[k]; i++)
0209             input_report_key(port->dev, port->btn[i + l],
0210                 ((data[tmdc_byte_d[k]] >> (i + port->btno[k])) & 1));
0211         l += port->btnc[k];
0212     }
0213 
0214     input_sync(port->dev);
0215 
0216     return 0;
0217 }
0218 
0219 /*
0220  * tmdc_poll() reads and analyzes ThrustMaster joystick data.
0221  */
0222 
0223 static void tmdc_poll(struct gameport *gameport)
0224 {
0225     unsigned char data[2][TMDC_MAX_LENGTH];
0226     struct tmdc *tmdc = gameport_get_drvdata(gameport);
0227     unsigned char r, bad = 0;
0228     int i;
0229 
0230     tmdc->reads++;
0231 
0232     if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
0233         bad = 1;
0234     else {
0235         for (i = 0; i < 2; i++) {
0236             if (r & (1 << i) & tmdc->exists) {
0237 
0238                 if (tmdc_parse_packet(tmdc->port[i], data[i]))
0239                     bad = 1;
0240             }
0241         }
0242     }
0243 
0244     tmdc->bads += bad;
0245 }
0246 
0247 static int tmdc_open(struct input_dev *dev)
0248 {
0249     struct tmdc *tmdc = input_get_drvdata(dev);
0250 
0251     gameport_start_polling(tmdc->gameport);
0252     return 0;
0253 }
0254 
0255 static void tmdc_close(struct input_dev *dev)
0256 {
0257     struct tmdc *tmdc = input_get_drvdata(dev);
0258 
0259     gameport_stop_polling(tmdc->gameport);
0260 }
0261 
0262 static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data)
0263 {
0264     const struct tmdc_model *model;
0265     struct tmdc_port *port;
0266     struct input_dev *input_dev;
0267     int i, j, b = 0;
0268     int err;
0269 
0270     tmdc->port[idx] = port = kzalloc(sizeof (struct tmdc_port), GFP_KERNEL);
0271     input_dev = input_allocate_device();
0272     if (!port || !input_dev) {
0273         err = -ENOMEM;
0274         goto fail;
0275     }
0276 
0277     port->mode = data[TMDC_BYTE_ID];
0278 
0279     for (model = tmdc_models; model->id && model->id != port->mode; model++)
0280         /* empty */;
0281 
0282     port->abs = model->axes;
0283     port->btn = model->buttons;
0284 
0285     if (!model->id) {
0286         port->absc = data[TMDC_BYTE_DEF] >> 4;
0287         for (i = 0; i < 4; i++)
0288             port->btnc[i] = i < (data[TMDC_BYTE_DEF] & 0xf) ? 8 : 0;
0289     } else {
0290         port->absc = model->abs;
0291         for (i = 0; i < 4; i++)
0292             port->btnc[i] = model->btnc[i];
0293     }
0294 
0295     for (i = 0; i < 4; i++)
0296         port->btno[i] = model->btno[i];
0297 
0298     snprintf(port->name, sizeof(port->name), model->name,
0299          port->absc, (data[TMDC_BYTE_DEF] & 0xf) << 3, port->mode);
0300     snprintf(port->phys, sizeof(port->phys), "%s/input%d", tmdc->gameport->phys, i);
0301 
0302     port->dev = input_dev;
0303 
0304     input_dev->name = port->name;
0305     input_dev->phys = port->phys;
0306     input_dev->id.bustype = BUS_GAMEPORT;
0307     input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
0308     input_dev->id.product = model->id;
0309     input_dev->id.version = 0x0100;
0310     input_dev->dev.parent = &tmdc->gameport->dev;
0311 
0312     input_set_drvdata(input_dev, tmdc);
0313 
0314     input_dev->open = tmdc_open;
0315     input_dev->close = tmdc_close;
0316 
0317     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
0318 
0319     for (i = 0; i < port->absc && i < TMDC_ABS; i++)
0320         if (port->abs[i] >= 0)
0321             input_set_abs_params(input_dev, port->abs[i], 8, 248, 2, 4);
0322 
0323     for (i = 0; i < model->hats && i < TMDC_ABS_HAT; i++)
0324         input_set_abs_params(input_dev, tmdc_abs_hat[i], -1, 1, 0, 0);
0325 
0326     for (i = 0; i < 4; i++) {
0327         for (j = 0; j < port->btnc[i] && j < TMDC_BTN; j++)
0328             set_bit(port->btn[j + b], input_dev->keybit);
0329         b += port->btnc[i];
0330     }
0331 
0332     err = input_register_device(port->dev);
0333     if (err)
0334         goto fail;
0335 
0336     return 0;
0337 
0338  fail:  input_free_device(input_dev);
0339     kfree(port);
0340     return err;
0341 }
0342 
0343 /*
0344  * tmdc_probe() probes for ThrustMaster type joysticks.
0345  */
0346 
0347 static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
0348 {
0349     unsigned char data[2][TMDC_MAX_LENGTH];
0350     struct tmdc *tmdc;
0351     int i;
0352     int err;
0353 
0354     if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL)))
0355         return -ENOMEM;
0356 
0357     tmdc->gameport = gameport;
0358 
0359     gameport_set_drvdata(gameport, tmdc);
0360 
0361     err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
0362     if (err)
0363         goto fail1;
0364 
0365     if (!(tmdc->exists = tmdc_read_packet(gameport, data))) {
0366         err = -ENODEV;
0367         goto fail2;
0368     }
0369 
0370     gameport_set_poll_handler(gameport, tmdc_poll);
0371     gameport_set_poll_interval(gameport, 20);
0372 
0373     for (i = 0; i < 2; i++) {
0374         if (tmdc->exists & (1 << i)) {
0375 
0376             err = tmdc_setup_port(tmdc, i, data[i]);
0377             if (err)
0378                 goto fail3;
0379         }
0380     }
0381 
0382     return 0;
0383 
0384  fail3: while (--i >= 0) {
0385         if (tmdc->port[i]) {
0386             input_unregister_device(tmdc->port[i]->dev);
0387             kfree(tmdc->port[i]);
0388         }
0389     }
0390  fail2: gameport_close(gameport);
0391  fail1: gameport_set_drvdata(gameport, NULL);
0392     kfree(tmdc);
0393     return err;
0394 }
0395 
0396 static void tmdc_disconnect(struct gameport *gameport)
0397 {
0398     struct tmdc *tmdc = gameport_get_drvdata(gameport);
0399     int i;
0400 
0401     for (i = 0; i < 2; i++) {
0402         if (tmdc->port[i]) {
0403             input_unregister_device(tmdc->port[i]->dev);
0404             kfree(tmdc->port[i]);
0405         }
0406     }
0407     gameport_close(gameport);
0408     gameport_set_drvdata(gameport, NULL);
0409     kfree(tmdc);
0410 }
0411 
0412 static struct gameport_driver tmdc_drv = {
0413     .driver     = {
0414         .name   = "tmdc",
0415         .owner  = THIS_MODULE,
0416     },
0417     .description    = DRIVER_DESC,
0418     .connect    = tmdc_connect,
0419     .disconnect = tmdc_disconnect,
0420 };
0421 
0422 module_gameport_driver(tmdc_drv);