--- linux-2.6.13.1/drivers/input/joystick/interact.c 2005-09-09 22:42:58.000000000 -0400 +++ linux-2.6.13.1-Interact/drivers/input/joystick/interact.c 2005-09-12 16:07:50.000000000 -0400 @@ -5,10 +5,16 @@ * * Based on the work of: * Toby Deshane + * + * History: + * -------- + * 2005-09-12: rrwood - Add support for RaiderPro */ /* * InterAct digital gamepad/joystick driver for Linux + * + * Note that the "new" Interact web site is http://www.speed-link.com/ */ /* @@ -45,45 +51,66 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -#define INTERACT_MAX_START 600 /* 400 us */ -#define INTERACT_MAX_STROBE 60 /* 40 us */ +#define INTERACT_MAX_START 600 /* 600 us */ +#define INTERACT_MAX_STROBE 60 /* 60 us */ #define INTERACT_MAX_LENGTH 32 /* 32 bits */ #define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */ #define INTERACT_TYPE_PP8D 1 /* ProPad 8 */ +#define INTERACT_TYPE_RAIDERPRO 2 /* RaiderPro */ struct interact { - struct gameport *gameport; - struct input_dev dev; - int bads; - int reads; - unsigned char type; - unsigned char length; - char phys[32]; + struct gameport *gameport; /* Kernel gameport struct ptr */ + struct input_dev dev; /* Kernel input_dev struct ptr */ + int bads; /* Count of bad reads from joystick */ + int reads; /* Count of total reads from joystick */ + unsigned char type; /* Joystick model index */ + unsigned char length; /* Number of bits in input packets */ + char phys[32]; /* Physical device name */ }; -static short interact_abs_hhfx[] = + +/* I think the original purpose of setting up lists of controller + * axes/buttons was to provide a single location to maintain such + * information. Although the table-based approach certainly makes + * the interact_connect() code below MUCH simpler and cleaner, the + * interact_poll() code ends up being very hard to read, unfortunately. + * + * I was tempted to either rewrite interact_poll() in a clearer fashion, + * or to implement a more comprehensive table-driven decoding approach + * (with values for offset, masking, shifting of each value). I'm a + * bit leery of making such massive change though, since I don't have the + * controllers to test the result. Instead, I'll just add support + * for the RaiderPro as clearly as I can..... + */ + +static short interact_abs_hhfx[] = { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 }; static short interact_abs_pp8d[] = { ABS_X, ABS_Y, -1 }; +static short interact_abs_raiderpro[] = + { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; static short interact_btn_hhfx[] = { BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 }; static short interact_btn_pp8d[] = { BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 }; +static short interact_btn_raiderpro[] = + { BTN_TRIGGER, BTN_THUMB, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; struct interact_type { - int id; - short *abs; - short *btn; - char *name; - unsigned char length; - unsigned char b8; + int id; /* Numeric device ID read during configuration */ + short *abs; /* Pointer to list of axes identifiers */ + short *btn; /* Pointer to list of button identifiers */ + char *name; /* Pointer to device model descriptor string */ + unsigned char length; /* Number of bits in input data packet */ + unsigned char b8; /* Count of analog (non-hat) axes in *abs list */ }; static struct interact_type interact_type[] = { { 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 }, { 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 }, + { 0x51F8, interact_abs_raiderpro, interact_btn_raiderpro, "InterAct RaiderPro Digital", 32, 3 }, { 0 }}; /* @@ -137,44 +164,70 @@ interact->reads++; if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) { + /* Couldn't read a full packet, so update the bad-count, + * queue another read, and get out */ interact->bads++; - } else { + input_sync(dev); + return; + } + +/* During development and debugging, it's nice to see all the read data */ +/* printk("d0:%08X d1:%08X d2:%08X\n", data[0], data[1], data[2]); */ + + if (INTERACT_MAX_LENGTH - interact->length > 0) { + /* If data packets are less than max length, shift them + * for easier processing below (ProPad goofiness) */ for (i = 0; i < 3; i++) data[i] <<= INTERACT_MAX_LENGTH - interact->length; + } - switch (interact->type) { - - case INTERACT_TYPE_HHFX: - - for (i = 0; i < 4; i++) - input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff); - - for (i = 0; i < 2; i++) - input_report_abs(dev, ABS_HAT0Y - i, - ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1)); - - for (i = 0; i < 8; i++) - input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1); - - for (i = 0; i < 4; i++) - input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1); - - break; - - case INTERACT_TYPE_PP8D: + + /* Unpack the data we read and pass along the info to the input layer */ + + if (interact->type == INTERACT_TYPE_HHFX) { + for (i = 0; i < 4; i++) + input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff); - for (i = 0; i < 2; i++) - input_report_abs(dev, interact_abs_pp8d[i], - ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); + for (i = 0; i < 2; i++) + input_report_abs(dev, ABS_HAT0Y - i, ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1)); - for (i = 0; i < 8; i++) - input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1); + for (i = 0; i < 8; i++) + input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1); - break; - } + for (i = 0; i < 4; i++) + input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1); + } + else if (interact->type == INTERACT_TYPE_PP8D) { + for (i = 0; i < 2; i++) + input_report_abs(dev, interact_abs_pp8d[i], ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); + + for (i = 0; i < 8; i++) + input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1); + + } + else if (interact->type == INTERACT_TYPE_RAIDERPRO) { + int hatRight = (data[0] >> 20) & 0x01; + int hatLeft = (data[0] >> 21) & 0x01; + int hatDown = (data[0] >> 22) & 0x01; + int hatUp = (data[0] >> 23) & 0x01; + + input_report_abs(dev, ABS_HAT0X, hatRight - hatLeft); + input_report_abs(dev, ABS_HAT0Y, hatUp - hatDown); + + input_report_abs(dev, ABS_X, (data[0] >> 8) & 0xff); + input_report_abs(dev, ABS_Y, (data[1] >> 8) & 0xff); + input_report_abs(dev, ABS_THROTTLE, data[1] & 0xff); + + input_report_key(dev, BTN_BASE4, (data[1] >> 16) & 1); + input_report_key(dev, BTN_BASE2, (data[1] >> 19) & 1); + input_report_key(dev, BTN_BASE3, (data[1] >> 20) & 1); + input_report_key(dev, BTN_THUMB, (data[1] >> 21) & 1); + input_report_key(dev, BTN_BASE, (data[1] >> 22) & 1); + input_report_key(dev, BTN_TRIGGER, (data[1] >> 23) & 1); } + /* Queue another read */ input_sync(dev); } @@ -235,7 +288,7 @@ break; if (!interact_type[i].length) { - printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n", + printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x d2 %08x]\n", gameport->phys, i, data[0], data[1], data[2]); err = -ENODEV; goto fail2; @@ -262,6 +315,10 @@ interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + /* This is the one place it's nice to have tables of the axes/buttons, + * since it makes it so easy to report the controller characteristics + * to the kernel's input layer */ + for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) { set_bit(t, interact->dev.absbit); if (i < interact_type[interact->type].b8) {