0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/slab.h>
0016 #include <linux/gameport.h>
0017 #include <linux/input.h>
0018 #include <linux/jiffies.h>
0019
0020 #define DRIVER_DESC "FP-Gaming Assassin 3D joystick driver"
0021
0022 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
0023 MODULE_DESCRIPTION(DRIVER_DESC);
0024 MODULE_LICENSE("GPL");
0025
0026 #define A3D_MAX_START 600
0027 #define A3D_MAX_STROBE 80
0028 #define A3D_MAX_LENGTH 40
0029
0030 #define A3D_MODE_A3D 1
0031 #define A3D_MODE_PAN 2
0032 #define A3D_MODE_OEM 3
0033 #define A3D_MODE_PXL 4
0034
0035 static char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
0036 "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
0037
0038 struct a3d {
0039 struct gameport *gameport;
0040 struct gameport *adc;
0041 struct input_dev *dev;
0042 int axes[4];
0043 int buttons;
0044 int mode;
0045 int length;
0046 int reads;
0047 int bads;
0048 char phys[32];
0049 };
0050
0051
0052
0053
0054
0055 static int a3d_read_packet(struct gameport *gameport, int length, char *data)
0056 {
0057 unsigned long flags;
0058 unsigned char u, v;
0059 unsigned int t, s;
0060 int i;
0061
0062 i = 0;
0063 t = gameport_time(gameport, A3D_MAX_START);
0064 s = gameport_time(gameport, A3D_MAX_STROBE);
0065
0066 local_irq_save(flags);
0067 gameport_trigger(gameport);
0068 v = gameport_read(gameport);
0069
0070 while (t > 0 && i < length) {
0071 t--;
0072 u = v; v = gameport_read(gameport);
0073 if (~v & u & 0x10) {
0074 data[i++] = v >> 5;
0075 t = s;
0076 }
0077 }
0078
0079 local_irq_restore(flags);
0080
0081 return i;
0082 }
0083
0084
0085
0086
0087
0088 static int a3d_csum(char *data, int count)
0089 {
0090 int i, csum = 0;
0091
0092 for (i = 0; i < count - 2; i++)
0093 csum += data[i];
0094 return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
0095 }
0096
0097 static void a3d_read(struct a3d *a3d, unsigned char *data)
0098 {
0099 struct input_dev *dev = a3d->dev;
0100
0101 switch (a3d->mode) {
0102
0103 case A3D_MODE_A3D:
0104 case A3D_MODE_OEM:
0105 case A3D_MODE_PAN:
0106
0107 input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
0108 input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
0109
0110 input_report_key(dev, BTN_RIGHT, data[2] & 1);
0111 input_report_key(dev, BTN_LEFT, data[3] & 2);
0112 input_report_key(dev, BTN_MIDDLE, data[3] & 4);
0113
0114 input_sync(dev);
0115
0116 a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
0117 a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
0118 a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
0119 a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
0120
0121 a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
0122
0123 break;
0124
0125 case A3D_MODE_PXL:
0126
0127 input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
0128 input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
0129
0130 input_report_key(dev, BTN_RIGHT, data[2] & 1);
0131 input_report_key(dev, BTN_LEFT, data[3] & 2);
0132 input_report_key(dev, BTN_MIDDLE, data[3] & 4);
0133 input_report_key(dev, BTN_SIDE, data[7] & 2);
0134 input_report_key(dev, BTN_EXTRA, data[7] & 4);
0135
0136 input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
0137 input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
0138 input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
0139 input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
0140
0141 input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1));
0142 input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
0143 input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1));
0144 input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1));
0145
0146 input_report_key(dev, BTN_TRIGGER, data[8] & 1);
0147 input_report_key(dev, BTN_THUMB, data[8] & 2);
0148 input_report_key(dev, BTN_TOP, data[8] & 4);
0149 input_report_key(dev, BTN_PINKIE, data[7] & 1);
0150
0151 input_sync(dev);
0152
0153 break;
0154 }
0155 }
0156
0157
0158
0159
0160
0161
0162 static void a3d_poll(struct gameport *gameport)
0163 {
0164 struct a3d *a3d = gameport_get_drvdata(gameport);
0165 unsigned char data[A3D_MAX_LENGTH];
0166
0167 a3d->reads++;
0168 if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
0169 data[0] != a3d->mode || a3d_csum(data, a3d->length))
0170 a3d->bads++;
0171 else
0172 a3d_read(a3d, data);
0173 }
0174
0175
0176
0177
0178
0179
0180
0181 static int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
0182 {
0183 struct a3d *a3d = gameport->port_data;
0184 int i;
0185
0186 for (i = 0; i < 4; i++)
0187 axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
0188 *buttons = a3d->buttons;
0189 return 0;
0190 }
0191
0192
0193
0194
0195
0196
0197 static int a3d_adc_open(struct gameport *gameport, int mode)
0198 {
0199 struct a3d *a3d = gameport->port_data;
0200
0201 if (mode != GAMEPORT_MODE_COOKED)
0202 return -1;
0203
0204 gameport_start_polling(a3d->gameport);
0205 return 0;
0206 }
0207
0208
0209
0210
0211
0212 static void a3d_adc_close(struct gameport *gameport)
0213 {
0214 struct a3d *a3d = gameport->port_data;
0215
0216 gameport_stop_polling(a3d->gameport);
0217 }
0218
0219
0220
0221
0222
0223 static int a3d_open(struct input_dev *dev)
0224 {
0225 struct a3d *a3d = input_get_drvdata(dev);
0226
0227 gameport_start_polling(a3d->gameport);
0228 return 0;
0229 }
0230
0231
0232
0233
0234
0235 static void a3d_close(struct input_dev *dev)
0236 {
0237 struct a3d *a3d = input_get_drvdata(dev);
0238
0239 gameport_stop_polling(a3d->gameport);
0240 }
0241
0242
0243
0244
0245
0246 static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
0247 {
0248 struct a3d *a3d;
0249 struct input_dev *input_dev;
0250 struct gameport *adc;
0251 unsigned char data[A3D_MAX_LENGTH];
0252 int i;
0253 int err;
0254
0255 a3d = kzalloc(sizeof(struct a3d), GFP_KERNEL);
0256 input_dev = input_allocate_device();
0257 if (!a3d || !input_dev) {
0258 err = -ENOMEM;
0259 goto fail1;
0260 }
0261
0262 a3d->dev = input_dev;
0263 a3d->gameport = gameport;
0264
0265 gameport_set_drvdata(gameport, a3d);
0266
0267 err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
0268 if (err)
0269 goto fail1;
0270
0271 i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
0272
0273 if (!i || a3d_csum(data, i)) {
0274 err = -ENODEV;
0275 goto fail2;
0276 }
0277
0278 a3d->mode = data[0];
0279
0280 if (!a3d->mode || a3d->mode > 5) {
0281 printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
0282 "(%s, id=%d), contact <vojtech@ucw.cz>\n", gameport->phys, a3d->mode);
0283 err = -ENODEV;
0284 goto fail2;
0285 }
0286
0287 gameport_set_poll_handler(gameport, a3d_poll);
0288 gameport_set_poll_interval(gameport, 20);
0289
0290 snprintf(a3d->phys, sizeof(a3d->phys), "%s/input0", gameport->phys);
0291
0292 input_dev->name = a3d_names[a3d->mode];
0293 input_dev->phys = a3d->phys;
0294 input_dev->id.bustype = BUS_GAMEPORT;
0295 input_dev->id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
0296 input_dev->id.product = a3d->mode;
0297 input_dev->id.version = 0x0100;
0298 input_dev->dev.parent = &gameport->dev;
0299 input_dev->open = a3d_open;
0300 input_dev->close = a3d_close;
0301
0302 input_set_drvdata(input_dev, a3d);
0303
0304 if (a3d->mode == A3D_MODE_PXL) {
0305
0306 int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
0307
0308 a3d->length = 33;
0309
0310 input_dev->evbit[0] |= BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY) |
0311 BIT_MASK(EV_REL);
0312 input_dev->relbit[0] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y);
0313 input_dev->absbit[0] |= BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
0314 BIT_MASK(ABS_THROTTLE) | BIT_MASK(ABS_RUDDER) |
0315 BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) |
0316 BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y);
0317 input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_RIGHT) |
0318 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
0319 BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
0320 input_dev->keybit[BIT_WORD(BTN_JOYSTICK)] |=
0321 BIT_MASK(BTN_TRIGGER) | BIT_MASK(BTN_THUMB) |
0322 BIT_MASK(BTN_TOP) | BIT_MASK(BTN_PINKIE);
0323
0324 a3d_read(a3d, data);
0325
0326 for (i = 0; i < 4; i++) {
0327 if (i < 2)
0328 input_set_abs_params(input_dev, axes[i],
0329 48, input_abs_get_val(input_dev, axes[i]) * 2 - 48, 0, 8);
0330 else
0331 input_set_abs_params(input_dev, axes[i], 2, 253, 0, 0);
0332 input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
0333 }
0334
0335 } else {
0336 a3d->length = 29;
0337
0338 input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
0339 input_dev->relbit[0] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y);
0340 input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_RIGHT) |
0341 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE);
0342
0343 a3d_read(a3d, data);
0344
0345 if (!(a3d->adc = adc = gameport_allocate_port()))
0346 printk(KERN_ERR "a3d: Not enough memory for ADC port\n");
0347 else {
0348 adc->port_data = a3d;
0349 adc->open = a3d_adc_open;
0350 adc->close = a3d_adc_close;
0351 adc->cooked_read = a3d_adc_cooked_read;
0352 adc->fuzz = 1;
0353
0354 gameport_set_name(adc, a3d_names[a3d->mode]);
0355 gameport_set_phys(adc, "%s/gameport0", gameport->phys);
0356 adc->dev.parent = &gameport->dev;
0357
0358 gameport_register_port(adc);
0359 }
0360 }
0361
0362 err = input_register_device(a3d->dev);
0363 if (err)
0364 goto fail3;
0365
0366 return 0;
0367
0368 fail3: if (a3d->adc)
0369 gameport_unregister_port(a3d->adc);
0370 fail2: gameport_close(gameport);
0371 fail1: gameport_set_drvdata(gameport, NULL);
0372 input_free_device(input_dev);
0373 kfree(a3d);
0374 return err;
0375 }
0376
0377 static void a3d_disconnect(struct gameport *gameport)
0378 {
0379 struct a3d *a3d = gameport_get_drvdata(gameport);
0380
0381 input_unregister_device(a3d->dev);
0382 if (a3d->adc)
0383 gameport_unregister_port(a3d->adc);
0384 gameport_close(gameport);
0385 gameport_set_drvdata(gameport, NULL);
0386 kfree(a3d);
0387 }
0388
0389 static struct gameport_driver a3d_drv = {
0390 .driver = {
0391 .name = "adc",
0392 .owner = THIS_MODULE,
0393 },
0394 .description = DRIVER_DESC,
0395 .connect = a3d_connect,
0396 .disconnect = a3d_disconnect,
0397 };
0398
0399 module_gameport_driver(a3d_drv);