[PATCH] drivers/input/joystick/interact.c ; Linux 2.6.13-1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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) {
--- 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) {

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux