From: roy wood <roy.wood@gmail.com>
To: linux-kernel@vger.kernel.org
Subject: [PATCH] drivers/input/joystick/interact.c ; Linux 2.6.13-1
Date: Tue, 13 Sep 2005 11:36:06 -0400 [thread overview]
Message-ID: <e778aab0050913083656dc8c8f@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 9372 bytes --]
This patch to the Interact joystick driver adds support for the
"RaiderPro Digital" model of joystick from Interact. The patch is
made against kernel version 2.6.13-1.
I've tested this using a RaiderPro and it works perfectly. I do not
have versions of the other supported Interact controllers that this
driver supports, so I cannot attest to whether I've broken things or
not (hopefully not).
This is my first patch submission, so please don't jump on my head too
hard if I missed something in the LKML FAQ (I did read it!).
Assuming anyone's read this far, I'd appreciate direct feedback via
email on this patch, since I'm not a regular LKML subscriber. I'll
poll the archive for a week or so to keep an eye on the thread, but
direct email would guarantee I don't miss anything.
Also, apparently I need to send this directly to Linus to get this
into the tree. Anyone care to tell me the best email address to use
to do that? I promise not to foreward it to recruiters at MS. :-)
--- 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) {
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: interact.diff --]
[-- Type: text/x-patch; name="interact.diff", Size: 8117 bytes --]
--- 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) {
next reply other threads:[~2005-09-13 15:36 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-09-13 15:36 roy wood [this message]
2005-09-13 18:41 ` [PATCH] drivers/input/joystick/interact.c ; Linux 2.6.13-1 Dmitry Torokhov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e778aab0050913083656dc8c8f@mail.gmail.com \
--to=roy.wood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.