| 1 | |
| 2 | |
| 3 | * Copyright (c) 1998-2005 Vojtech Pavlik
|
| 4 |
|
| 5 |
|
| 6 | |
| 7 | * Microsoft SideWinder joystick family driver for Linux
|
| 8 |
|
| 9 |
|
| 10 | #include <linux/delay.h>
|
| 11 | #include <linux/kernel.h>
|
| 12 | #include <linux/module.h>
|
| 13 | #include <linux/slab.h>
|
| 14 | #include <linux/input.h>
|
| 15 | #include <linux/gameport.h>
|
| 16 | #include <linux/jiffies.h>
|
| 17 | #include <linux/string_choices.h>
|
| 18 |
|
| 19 | #define DRIVER_DESC "Microsoft SideWinder joystick family driver"
|
| 20 |
|
| 21 | MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");
|
| 22 | MODULE_DESCRIPTION(DRIVER_DESC);
|
| 23 | MODULE_LICENSE("GPL");
|
| 24 |
|
| 25 | |
| 26 | * These are really magic values. Changing them can make a problem go away,
|
| 27 | * as well as break everything.
|
| 28 |
|
| 29 |
|
| 30 | #undef SW_DEBUG
|
| 31 | #undef SW_DEBUG_DATA
|
| 32 |
|
| 33 | #define SW_START 600
|
| 34 | #define SW_STROBE 60
|
| 35 | #define SW_TIMEOUT 6
|
| 36 | #define SW_KICK 45
|
| 37 | #define SW_END 8
|
| 38 | #define SW_FAIL 16
|
| 39 | #define SW_BAD 2
|
| 40 | #define SW_OK 64
|
| 41 | #define SW_LENGTH 512
|
| 42 |
|
| 43 | #ifdef SW_DEBUG
|
| 44 | #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
|
| 45 | #else
|
| 46 | #define dbg(format, arg...) do {} while (0)
|
| 47 | #endif
|
| 48 |
|
| 49 | |
| 50 | * SideWinder joystick types ...
|
| 51 |
|
| 52 |
|
| 53 | #define SW_ID_3DP 0
|
| 54 | #define SW_ID_GP 1
|
| 55 | #define SW_ID_PP 2
|
| 56 | #define SW_ID_FFP 3
|
| 57 | #define SW_ID_FSP 4
|
| 58 | #define SW_ID_FFW 5
|
| 59 |
|
| 60 | |
| 61 | * Names, buttons, axes ...
|
| 62 |
|
| 63 |
|
| 64 | static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro",
|
| 65 | "Force Feedback Wheel" };
|
| 66 |
|
| 67 | static char sw_abs[][7] = {
|
| 68 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
|
| 69 | { ABS_X, ABS_Y },
|
| 70 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
|
| 71 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
|
| 72 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
|
| 73 | { ABS_RX, ABS_RUDDER, ABS_THROTTLE }};
|
| 74 |
|
| 75 | static char sw_bit[][7] = {
|
| 76 | { 10, 10, 9, 10, 1, 1 },
|
| 77 | { 1, 1 },
|
| 78 | { 10, 10, 6, 7, 1, 1 },
|
| 79 | { 10, 10, 6, 7, 1, 1 },
|
| 80 | { 10, 10, 6, 1, 1 },
|
| 81 | { 10, 7, 7, 1, 1 }};
|
| 82 |
|
| 83 | static short sw_btn[][12] = {
|
| 84 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE },
|
| 85 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE },
|
| 86 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
|
| 87 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
|
| 88 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
|
| 89 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }};
|
| 90 |
|
| 91 | static struct {
|
| 92 | int x;
|
| 93 | int y;
|
| 94 | } sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
| 95 |
|
| 96 | struct sw {
|
| 97 | struct gameport *gameport;
|
| 98 | struct input_dev *dev[4];
|
| 99 | char name[64];
|
| 100 | char phys[4][32];
|
| 101 | int length;
|
| 102 | int type;
|
| 103 | int bits;
|
| 104 | int number;
|
| 105 | int fail;
|
| 106 | int ok;
|
| 107 | int reads;
|
| 108 | int bads;
|
| 109 | };
|
| 110 |
|
| 111 | |
| 112 | * sw_read_packet() is a function which reads either a data packet, or an
|
| 113 | * identification packet from a SideWinder joystick. The protocol is very,
|
| 114 | * very, very braindamaged. Microsoft patented it in US patent #5628686.
|
| 115 |
|
| 116 |
|
| 117 | static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id)
|
| 118 | {
|
| 119 | unsigned long flags;
|
| 120 | int timeout, bitout, sched, i, kick, start, strobe;
|
| 121 | unsigned char pending, u, v;
|
| 122 |
|
| 123 | i = -id;
|
| 124 | timeout = id ? gameport_time(gameport, SW_TIMEOUT * 1000) : 0;
|
| 125 | kick = id ? gameport_time(gameport, SW_KICK) : 0;
|
| 126 | start = gameport_time(gameport, SW_START);
|
| 127 | strobe = gameport_time(gameport, SW_STROBE);
|
| 128 | bitout = start;
|
| 129 | pending = 0;
|
| 130 | sched = 0;
|
| 131 |
|
| 132 | local_irq_save(flags);
|
| 133 |
|
| 134 | gameport_trigger(gameport);
|
| 135 | v = gameport_read(gameport);
|
| 136 |
|
| 137 | do {
|
| 138 | bitout--;
|
| 139 | u = v;
|
| 140 | v = gameport_read(gameport);
|
| 141 | } while (!(~v & u & 0x10) && (bitout > 0));
|
| 142 |
|
| 143 | if (bitout > 0)
|
| 144 | bitout = strobe;
|
| 145 |
|
| 146 | while ((timeout > 0 || bitout > 0) && (i < length)) {
|
| 147 |
|
| 148 | timeout--;
|
| 149 | bitout--;
|
| 150 | sched--;
|
| 151 |
|
| 152 | u = v;
|
| 153 | v = gameport_read(gameport);
|
| 154 |
|
| 155 | if ((~u & v & 0x10) && (bitout > 0)) {
|
| 156 | if (i >= 0)
|
| 157 | buf[i] = v >> 5;
|
| 158 | i++;
|
| 159 | bitout = strobe;
|
| 160 | }
|
| 161 |
|
| 162 | if (kick && (~v & u & 0x01)) {
|
| 163 | sched = kick;
|
| 164 | kick = 0;
|
| 165 | pending = 1;
|
| 166 | }
|
| 167 |
|
| 168 | if (pending && sched < 0 && (i > -SW_END)) {
|
| 169 | gameport_trigger(gameport);
|
| 170 | bitout = start;
|
| 171 | pending = 0;
|
| 172 | timeout = 0;
|
| 173 | }
|
| 174 | }
|
| 175 |
|
| 176 | local_irq_restore(flags);
|
| 177 |
|
| 178 | #ifdef SW_DEBUG_DATA
|
| 179 | {
|
| 180 | int j;
|
| 181 | printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
|
| 182 | for (j = 0; j < i; j++) printk("%d", buf[j]);
|
| 183 | printk("]\n");
|
| 184 | }
|
| 185 | #endif
|
| 186 |
|
| 187 | return i;
|
| 188 | }
|
| 189 |
|
| 190 | |
| 191 | * sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
|
| 192 | * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
|
| 193 | * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
|
| 194 | * is number of bits per triplet.
|
| 195 |
|
| 196 |
|
| 197 | #define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits)
|
| 198 |
|
| 199 | static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits)
|
| 200 | {
|
| 201 | __u64 data = 0;
|
| 202 | int tri = pos % bits;
|
| 203 | int i = pos / bits;
|
| 204 | int bit = 0;
|
| 205 |
|
| 206 | while (num--) {
|
| 207 | data |= (__u64)((buf[i] >> tri++) & 1) << bit++;
|
| 208 | if (tri == bits) {
|
| 209 | i++;
|
| 210 | tri = 0;
|
| 211 | }
|
| 212 | }
|
| 213 |
|
| 214 | return data;
|
| 215 | }
|
| 216 |
|
| 217 | |
| 218 | * sw_init_digital() initializes a SideWinder 3D Pro joystick
|
| 219 | * into digital mode.
|
| 220 |
|
| 221 |
|
| 222 | static void sw_init_digital(struct gameport *gameport)
|
| 223 | {
|
| 224 | static const int seq[] = { 140, 140+725, 140+300, 0 };
|
| 225 | unsigned long flags;
|
| 226 | int i, t;
|
| 227 |
|
| 228 | local_irq_save(flags);
|
| 229 |
|
| 230 | i = 0;
|
| 231 | do {
|
| 232 | gameport_trigger(gameport);
|
| 233 | t = gameport_time(gameport, SW_TIMEOUT * 1000);
|
| 234 | while ((gameport_read(gameport) & 1) && t) t--;
|
| 235 | udelay(seq[i]);
|
| 236 | } while (seq[++i]);
|
| 237 |
|
| 238 | gameport_trigger(gameport);
|
| 239 |
|
| 240 | local_irq_restore(flags);
|
| 241 | }
|
| 242 |
|
| 243 | |
| 244 | * sw_parity() computes parity of __u64
|
| 245 |
|
| 246 |
|
| 247 | static int sw_parity(__u64 t)
|
| 248 | {
|
| 249 | int x = t ^ (t >> 32);
|
| 250 |
|
| 251 | x ^= x >> 16;
|
| 252 | x ^= x >> 8;
|
| 253 | x ^= x >> 4;
|
| 254 | x ^= x >> 2;
|
| 255 | x ^= x >> 1;
|
| 256 | return x & 1;
|
| 257 | }
|
| 258 |
|
| 259 | |
| 260 | * sw_ccheck() checks synchronization bits and computes checksum of nibbles.
|
| 261 |
|
| 262 |
|
| 263 | static int sw_check(__u64 t)
|
| 264 | {
|
| 265 | unsigned char sum = 0;
|
| 266 |
|
| 267 | if ((t & 0x8080808080808080ULL) ^ 0x80)
|
| 268 | return -1;
|
| 269 |
|
| 270 | while (t) {
|
| 271 | sum += t & 0xf;
|
| 272 | t >>= 4;
|
| 273 | }
|
| 274 |
|
| 275 | return sum & 0xf;
|
| 276 | }
|
| 277 |
|
| 278 | |
| 279 | * sw_parse() analyzes SideWinder joystick data, and writes the results into
|
| 280 | * the axes and buttons arrays.
|
| 281 |
|
| 282 |
|
| 283 | static int sw_parse(unsigned char *buf, struct sw *sw)
|
| 284 | {
|
| 285 | int hat, i, j;
|
| 286 | struct input_dev *dev;
|
| 287 |
|
| 288 | switch (sw->type) {
|
| 289 |
|
| 290 | case SW_ID_3DP:
|
| 291 |
|
| 292 | if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8)
|
| 293 | return -1;
|
| 294 |
|
| 295 | dev = sw->dev[0];
|
| 296 |
|
| 297 | input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7));
|
| 298 | input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7));
|
| 299 | input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7));
|
| 300 | input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7));
|
| 301 |
|
| 302 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
|
| 303 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
|
| 304 |
|
| 305 | for (j = 0; j < 7; j++)
|
| 306 | input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1));
|
| 307 |
|
| 308 | input_report_key(dev, BTN_BASE4, !GB(38,1));
|
| 309 | input_report_key(dev, BTN_BASE5, !GB(37,1));
|
| 310 |
|
| 311 | input_sync(dev);
|
| 312 |
|
| 313 | return 0;
|
| 314 |
|
| 315 | case SW_ID_GP:
|
| 316 |
|
| 317 | for (i = 0; i < sw->number; i ++) {
|
| 318 |
|
| 319 | if (sw_parity(GB(i*15,15)))
|
| 320 | return -1;
|
| 321 |
|
| 322 | input_report_abs(sw->dev[i], ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
|
| 323 | input_report_abs(sw->dev[i], ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
|
| 324 |
|
| 325 | for (j = 0; j < 10; j++)
|
| 326 | input_report_key(sw->dev[i], sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
|
| 327 |
|
| 328 | input_sync(sw->dev[i]);
|
| 329 | }
|
| 330 |
|
| 331 | return 0;
|
| 332 |
|
| 333 | case SW_ID_PP:
|
| 334 | case SW_ID_FFP:
|
| 335 |
|
| 336 | if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8)
|
| 337 | return -1;
|
| 338 |
|
| 339 | dev = sw->dev[0];
|
| 340 | input_report_abs(dev, ABS_X, GB( 9,10));
|
| 341 | input_report_abs(dev, ABS_Y, GB(19,10));
|
| 342 | input_report_abs(dev, ABS_RZ, GB(36, 6));
|
| 343 | input_report_abs(dev, ABS_THROTTLE, GB(29, 7));
|
| 344 |
|
| 345 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
|
| 346 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
|
| 347 |
|
| 348 | for (j = 0; j < 9; j++)
|
| 349 | input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
|
| 350 |
|
| 351 | input_sync(dev);
|
| 352 |
|
| 353 | return 0;
|
| 354 |
|
| 355 | case SW_ID_FSP:
|
| 356 |
|
| 357 | if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8)
|
| 358 | return -1;
|
| 359 |
|
| 360 | dev = sw->dev[0];
|
| 361 | input_report_abs(dev, ABS_X, GB( 0,10));
|
| 362 | input_report_abs(dev, ABS_Y, GB(16,10));
|
| 363 | input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
|
| 364 |
|
| 365 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
|
| 366 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
|
| 367 |
|
| 368 | for (j = 0; j < 6; j++)
|
| 369 | input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1));
|
| 370 |
|
| 371 | input_report_key(dev, BTN_TR, !GB(26,1));
|
| 372 | input_report_key(dev, BTN_START, !GB(27,1));
|
| 373 | input_report_key(dev, BTN_MODE, !GB(38,1));
|
| 374 | input_report_key(dev, BTN_SELECT, !GB(39,1));
|
| 375 |
|
| 376 | input_sync(dev);
|
| 377 |
|
| 378 | return 0;
|
| 379 |
|
| 380 | case SW_ID_FFW:
|
| 381 |
|
| 382 | if (!sw_parity(GB(0,33)))
|
| 383 | return -1;
|
| 384 |
|
| 385 | dev = sw->dev[0];
|
| 386 | input_report_abs(dev, ABS_RX, GB( 0,10));
|
| 387 | input_report_abs(dev, ABS_RUDDER, GB(10, 6));
|
| 388 | input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
|
| 389 |
|
| 390 | for (j = 0; j < 8; j++)
|
| 391 | input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
|
| 392 |
|
| 393 | input_sync(dev);
|
| 394 |
|
| 395 | return 0;
|
| 396 | }
|
| 397 |
|
| 398 | return -1;
|
| 399 | }
|
| 400 |
|
| 401 | |
| 402 | * sw_read() reads SideWinder joystick data, and reinitializes
|
| 403 | * the joystick in case of persistent problems. This is the function that is
|
| 404 | * called from the generic code to poll the joystick.
|
| 405 |
|
| 406 |
|
| 407 | static int sw_read(struct sw *sw)
|
| 408 | {
|
| 409 | unsigned char buf[SW_LENGTH];
|
| 410 | int i;
|
| 411 |
|
| 412 | i = sw_read_packet(sw->gameport, buf, sw->length, 0);
|
| 413 |
|
| 414 | if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) {
|
| 415 |
|
| 416 | if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) {
|
| 417 | printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s"
|
| 418 | " - going to reinitialize.\n", sw->gameport->phys);
|
| 419 | sw->fail = SW_FAIL;
|
| 420 | i = 128;
|
| 421 | }
|
| 422 |
|
| 423 | if (i < 66 && GB(0,64) == GB(i*3-66,64))
|
| 424 | i = 66;
|
| 425 |
|
| 426 | if (i < 66 && GB(0,64) == GB(66,64))
|
| 427 | i = 66;
|
| 428 |
|
| 429 | if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) {
|
| 430 | memmove(buf, buf + i - 22, 22);
|
| 431 | i = 66;
|
| 432 | }
|
| 433 | }
|
| 434 |
|
| 435 | if (i == sw->length && !sw_parse(buf, sw)) {
|
| 436 |
|
| 437 | sw->fail = 0;
|
| 438 | sw->ok++;
|
| 439 |
|
| 440 | if (sw->type == SW_ID_3DP && sw->length == 66
|
| 441 | && sw->ok > SW_OK) {
|
| 442 |
|
| 443 | printk(KERN_INFO "sidewinder.c: No more trouble on %s"
|
| 444 | " - enabling optimization again.\n", sw->gameport->phys);
|
| 445 | sw->length = 22;
|
| 446 | }
|
| 447 |
|
| 448 | return 0;
|
| 449 | }
|
| 450 |
|
| 451 | sw->ok = 0;
|
| 452 | sw->fail++;
|
| 453 |
|
| 454 | if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) {
|
| 455 |
|
| 456 | printk(KERN_INFO "sidewinder.c: Many bit errors on %s"
|
| 457 | " - disabling optimization.\n", sw->gameport->phys);
|
| 458 | sw->length = 66;
|
| 459 | }
|
| 460 |
|
| 461 | if (sw->fail < SW_FAIL)
|
| 462 | return -1;
|
| 463 |
|
| 464 | printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s"
|
| 465 | " - reinitializing joystick.\n", sw->gameport->phys);
|
| 466 |
|
| 467 | if (!i && sw->type == SW_ID_3DP) {
|
| 468 | mdelay(3 * SW_TIMEOUT);
|
| 469 | sw_init_digital(sw->gameport);
|
| 470 | }
|
| 471 |
|
| 472 | mdelay(SW_TIMEOUT);
|
| 473 | i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0);
|
| 474 | mdelay(SW_TIMEOUT);
|
| 475 | sw_read_packet(sw->gameport, buf, SW_LENGTH, i);
|
| 476 |
|
| 477 | sw->fail = SW_FAIL;
|
| 478 |
|
| 479 | return -1;
|
| 480 | }
|
| 481 |
|
| 482 | static void sw_poll(struct gameport *gameport)
|
| 483 | {
|
| 484 | struct sw *sw = gameport_get_drvdata(gameport);
|
| 485 |
|
| 486 | sw->reads++;
|
| 487 | if (sw_read(sw))
|
| 488 | sw->bads++;
|
| 489 | }
|
| 490 |
|
| 491 | static int sw_open(struct input_dev *dev)
|
| 492 | {
|
| 493 | struct sw *sw = input_get_drvdata(dev);
|
| 494 |
|
| 495 | gameport_start_polling(sw->gameport);
|
| 496 | return 0;
|
| 497 | }
|
| 498 |
|
| 499 | static void sw_close(struct input_dev *dev)
|
| 500 | {
|
| 501 | struct sw *sw = input_get_drvdata(dev);
|
| 502 |
|
| 503 | gameport_stop_polling(sw->gameport);
|
| 504 | }
|
| 505 |
|
| 506 | |
| 507 | * sw_print_packet() prints the contents of a SideWinder packet.
|
| 508 |
|
| 509 |
|
| 510 | static void sw_print_packet(char *name, int length, unsigned char *buf, char bits)
|
| 511 | {
|
| 512 | int i;
|
| 513 |
|
| 514 | printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length);
|
| 515 | for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
|
| 516 | printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits));
|
| 517 | printk("]\n");
|
| 518 | }
|
| 519 |
|
| 520 | |
| 521 | * sw_3dp_id() translates the 3DP id into a human legible string.
|
| 522 | * Unfortunately I don't know how to do this for the other SW types.
|
| 523 |
|
| 524 |
|
| 525 | static void sw_3dp_id(unsigned char *buf, char *comment, size_t size)
|
| 526 | {
|
| 527 | int i;
|
| 528 | char pnp[8], rev[9];
|
| 529 |
|
| 530 | for (i = 0; i < 7; i++)
|
| 531 | pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1);
|
| 532 |
|
| 533 | for (i = 0; i < 8; i++)
|
| 534 | rev[i] = sw_get_bits(buf, 88+8*i, 8, 1);
|
| 535 |
|
| 536 | pnp[7] = rev[8] = 0;
|
| 537 |
|
| 538 | snprintf(comment, size, " [PnP %d.%02d id %s rev %s]",
|
| 539 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
|
| 540 | sw_get_bits(buf, 16, 6, 1)) / 100,
|
| 541 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
|
| 542 | sw_get_bits(buf, 16, 6, 1)) % 100,
|
| 543 | pnp, rev);
|
| 544 | }
|
| 545 |
|
| 546 | |
| 547 | * sw_guess_mode() checks the upper two button bits for toggling -
|
| 548 | * indication of that the joystick is in 3-bit mode. This is documented
|
| 549 | * behavior for 3DP ID packet, and for example the FSP does this in
|
| 550 | * normal packets instead. Fun ...
|
| 551 |
|
| 552 |
|
| 553 | static int sw_guess_mode(unsigned char *buf, int len)
|
| 554 | {
|
| 555 | int i;
|
| 556 | unsigned char xor = 0;
|
| 557 |
|
| 558 | for (i = 1; i < len; i++)
|
| 559 | xor |= (buf[i - 1] ^ buf[i]) & 6;
|
| 560 |
|
| 561 | return !!xor * 2 + 1;
|
| 562 | }
|
| 563 |
|
| 564 | |
| 565 | * sw_connect() probes for SideWinder type joysticks.
|
| 566 |
|
| 567 |
|
| 568 | static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
|
| 569 | {
|
| 570 | struct sw *sw;
|
| 571 | struct input_dev *input_dev;
|
| 572 | int i, j, k, l;
|
| 573 | int err = 0;
|
| 574 | unsigned char *buf = NULL;
|
| 575 | unsigned char *idbuf = NULL;
|
| 576 | unsigned char m = 1;
|
| 577 | char comment[40];
|
| 578 |
|
| 579 | comment[0] = 0;
|
| 580 |
|
| 581 | sw = kzalloc_obj(*sw);
|
| 582 | buf = kmalloc(SW_LENGTH, GFP_KERNEL);
|
| 583 | idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
|
| 584 | if (!sw || !buf || !idbuf) {
|
| 585 | err = -ENOMEM;
|
| 586 | goto fail1;
|
| 587 | }
|
| 588 |
|
| 589 | sw->gameport = gameport;
|
| 590 |
|
| 591 | gameport_set_drvdata(gameport, sw);
|
| 592 |
|
| 593 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
|
| 594 | if (err)
|
| 595 | goto fail1;
|
| 596 |
|
| 597 | dbg("Init 0: Opened %s, io %#x, speed %d",
|
| 598 | gameport->phys, gameport->io, gameport->speed);
|
| 599 |
|
| 600 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0);
|
| 601 | msleep(SW_TIMEOUT);
|
| 602 | dbg("Init 1: Mode %d. Length %d.", m , i);
|
| 603 |
|
| 604 | if (!i) {
|
| 605 | sw_init_digital(gameport);
|
| 606 | msleep(SW_TIMEOUT);
|
| 607 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0);
|
| 608 | msleep(SW_TIMEOUT);
|
| 609 | dbg("Init 1b: Length %d.", i);
|
| 610 | if (!i) {
|
| 611 | err = -ENODEV;
|
| 612 | goto fail2;
|
| 613 | }
|
| 614 | }
|
| 615 |
|
| 616 | j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);
|
| 617 | m |= sw_guess_mode(idbuf, j);
|
| 618 | dbg("Init 2: Mode %d. ID Length %d.", m, j);
|
| 619 |
|
| 620 | if (j <= 0) {
|
| 621 | msleep(SW_TIMEOUT);
|
| 622 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0);
|
| 623 | m |= sw_guess_mode(buf, i);
|
| 624 | dbg("Init 2b: Mode %d. Length %d.", m, i);
|
| 625 | if (!i) {
|
| 626 | err = -ENODEV;
|
| 627 | goto fail2;
|
| 628 | }
|
| 629 | msleep(SW_TIMEOUT);
|
| 630 | j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);
|
| 631 | dbg("Init 2c: ID Length %d.", j);
|
| 632 | }
|
| 633 |
|
| 634 | sw->type = -1;
|
| 635 | k = SW_FAIL;
|
| 636 | l = 0;
|
| 637 |
|
| 638 | do {
|
| 639 | k--;
|
| 640 | msleep(SW_TIMEOUT);
|
| 641 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0);
|
| 642 | dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
|
| 643 |
|
| 644 | if (i > l) {
|
| 645 |
|
| 646 | l = i;
|
| 647 |
|
| 648 | sw->number = 1;
|
| 649 | sw->gameport = gameport;
|
| 650 | sw->length = i;
|
| 651 | sw->bits = m;
|
| 652 |
|
| 653 | dbg("Init 3a: Case %d.\n", i * m);
|
| 654 |
|
| 655 | switch (i * m) {
|
| 656 | case 60:
|
| 657 | sw->number++;
|
| 658 | fallthrough;
|
| 659 | case 45:
|
| 660 | if (j <= 40) {
|
| 661 | fallthrough;
|
| 662 | case 43:
|
| 663 | sw->type = SW_ID_FSP;
|
| 664 | break;
|
| 665 | }
|
| 666 | sw->number++;
|
| 667 | fallthrough;
|
| 668 | case 30:
|
| 669 | sw->number++;
|
| 670 | fallthrough;
|
| 671 | case 15:
|
| 672 | sw->type = SW_ID_GP;
|
| 673 | break;
|
| 674 | case 33:
|
| 675 | case 31:
|
| 676 | sw->type = SW_ID_FFW;
|
| 677 | break;
|
| 678 | case 48:
|
| 679 | if (j == 14) {
|
| 680 | sw->type = SW_ID_FFP;
|
| 681 | sprintf(comment, " [AC %s]", str_off_on(sw_get_bits(idbuf,38,1,3)));
|
| 682 | } else
|
| 683 | sw->type = SW_ID_PP;
|
| 684 | break;
|
| 685 | case 66:
|
| 686 | sw->bits = 3;
|
| 687 | fallthrough;
|
| 688 | case 198:
|
| 689 | sw->length = 22;
|
| 690 | fallthrough;
|
| 691 | case 64:
|
| 692 | sw->type = SW_ID_3DP;
|
| 693 | if (j == 160)
|
| 694 | sw_3dp_id(idbuf, comment, sizeof(comment));
|
| 695 | break;
|
| 696 | }
|
| 697 | }
|
| 698 |
|
| 699 | } while (k && sw->type == -1);
|
| 700 |
|
| 701 | if (sw->type == -1) {
|
| 702 | printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
|
| 703 | "on %s, contact <[email protected]>\n", gameport->phys);
|
| 704 | sw_print_packet("ID", j * 3, idbuf, 3);
|
| 705 | sw_print_packet("Data", i * m, buf, m);
|
| 706 | err = -ENODEV;
|
| 707 | goto fail2;
|
| 708 | }
|
| 709 |
|
| 710 | #ifdef SW_DEBUG
|
| 711 | sw_print_packet("ID", j * 3, idbuf, 3);
|
| 712 | sw_print_packet("Data", i * m, buf, m);
|
| 713 | #endif
|
| 714 |
|
| 715 | gameport_set_poll_handler(gameport, sw_poll);
|
| 716 | gameport_set_poll_interval(gameport, 20);
|
| 717 |
|
| 718 | k = i;
|
| 719 | l = j;
|
| 720 |
|
| 721 | for (i = 0; i < sw->number; i++) {
|
| 722 | int bits, code;
|
| 723 |
|
| 724 | snprintf(sw->name, sizeof(sw->name),
|
| 725 | "Microsoft SideWinder %s", sw_name[sw->type]);
|
| 726 | snprintf(sw->phys[i], sizeof(sw->phys[i]),
|
| 727 | "%s/input%d", gameport->phys, i);
|
| 728 |
|
| 729 | sw->dev[i] = input_dev = input_allocate_device();
|
| 730 | if (!input_dev) {
|
| 731 | err = -ENOMEM;
|
| 732 | goto fail3;
|
| 733 | }
|
| 734 |
|
| 735 | input_dev->name = sw->name;
|
| 736 | input_dev->phys = sw->phys[i];
|
| 737 | input_dev->id.bustype = BUS_GAMEPORT;
|
| 738 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT;
|
| 739 | input_dev->id.product = sw->type;
|
| 740 | input_dev->id.version = 0x0100;
|
| 741 | input_dev->dev.parent = &gameport->dev;
|
| 742 |
|
| 743 | input_set_drvdata(input_dev, sw);
|
| 744 |
|
| 745 | input_dev->open = sw_open;
|
| 746 | input_dev->close = sw_close;
|
| 747 |
|
| 748 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
| 749 |
|
| 750 | for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
|
| 751 | int min, max, fuzz, flat;
|
| 752 |
|
| 753 | code = sw_abs[sw->type][j];
|
| 754 | min = bits == 1 ? -1 : 0;
|
| 755 | max = (1 << bits) - 1;
|
| 756 | fuzz = (bits >> 1) >= 2 ? 1 << ((bits >> 1) - 2) : 0;
|
| 757 | flat = code == ABS_THROTTLE || bits < 5 ?
|
| 758 | 0 : 1 << (bits - 5);
|
| 759 |
|
| 760 | input_set_abs_params(input_dev, code,
|
| 761 | min, max, fuzz, flat);
|
| 762 | }
|
| 763 |
|
| 764 | for (j = 0; (code = sw_btn[sw->type][j]); j++)
|
| 765 | __set_bit(code, input_dev->keybit);
|
| 766 |
|
| 767 | dbg("%s%s [%d-bit id %d data %d]\n", sw->name, comment, m, l, k);
|
| 768 |
|
| 769 | err = input_register_device(sw->dev[i]);
|
| 770 | if (err)
|
| 771 | goto fail4;
|
| 772 | }
|
| 773 |
|
| 774 | out: kfree(buf);
|
| 775 | kfree(idbuf);
|
| 776 |
|
| 777 | return err;
|
| 778 |
|
| 779 | fail4: input_free_device(sw->dev[i]);
|
| 780 | fail3: while (--i >= 0)
|
| 781 | input_unregister_device(sw->dev[i]);
|
| 782 | fail2: gameport_close(gameport);
|
| 783 | fail1: gameport_set_drvdata(gameport, NULL);
|
| 784 | kfree(sw);
|
| 785 | goto out;
|
| 786 | }
|
| 787 |
|
| 788 | static void sw_disconnect(struct gameport *gameport)
|
| 789 | {
|
| 790 | struct sw *sw = gameport_get_drvdata(gameport);
|
| 791 | int i;
|
| 792 |
|
| 793 | for (i = 0; i < sw->number; i++)
|
| 794 | input_unregister_device(sw->dev[i]);
|
| 795 | gameport_close(gameport);
|
| 796 | gameport_set_drvdata(gameport, NULL);
|
| 797 | kfree(sw);
|
| 798 | }
|
| 799 |
|
| 800 | static struct gameport_driver sw_drv = {
|
| 801 | .driver = {
|
| 802 | .name = "sidewinder",
|
| 803 | .owner = THIS_MODULE,
|
| 804 | },
|
| 805 | .description = DRIVER_DESC,
|
| 806 | .connect = sw_connect,
|
| 807 | .disconnect = sw_disconnect,
|
| 808 | };
|
| 809 |
|
| 810 | module_gameport_driver(sw_drv);
|