Input: gamecon - add SNES mouse support

SNES gamepads and mice share the same type of interface so they both can be
connected to the parallel port using a simple interface.  Adding mouse
support to a gamepad driver may sound funny at first, but doing so in this
case makes it possible to connect and SNES gamepads and mice at the same
time, on the same port.

Signed-off-by: Raphael Assenat <raph@raphnet.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index aa3ef89..ecbdb6b 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -7,6 +7,7 @@
  *  Based on the work of:
  *	Andree Borrmann		John Dahlstrom
  *	David Kuder		Nathan Hand
+ *	Raphael Assenat
  */
 
 /*
@@ -73,8 +74,9 @@
 #define GC_N64		6
 #define GC_PSX		7
 #define GC_DDR		8
+#define GC_SNESMOUSE	9
 
-#define GC_MAX		8
+#define GC_MAX		9
 
 #define GC_REFRESH_TIME	HZ/100
 
@@ -94,7 +96,7 @@
 
 static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
 				"Multisystem 2-button joystick", "N64 controller", "PSX controller",
-				"PSX DDR controller" };
+				"PSX DDR controller", "SNES mouse" };
 /*
  * N64 support.
  */
@@ -206,9 +208,12 @@
  * NES/SNES support.
  */
 
-#define GC_NES_DELAY	6	/* Delay between bits - 6us */
-#define GC_NES_LENGTH	8	/* The NES pads use 8 bits of data */
-#define GC_SNES_LENGTH	12	/* The SNES true length is 16, but the last 4 bits are unused */
+#define GC_NES_DELAY		6	/* Delay between bits - 6us */
+#define GC_NES_LENGTH		8	/* The NES pads use 8 bits of data */
+#define GC_SNES_LENGTH		12	/* The SNES true length is 16, but the
+					   last 4 bits are unused */
+#define GC_SNESMOUSE_LENGTH	32	/* The SNES mouse uses 32 bits, the first
+					   16 bits are equivalent to a gamepad */
 
 #define GC_NES_POWER	0xfc
 #define GC_NES_CLOCK	0x01
@@ -243,11 +248,15 @@
 
 static void gc_nes_process_packet(struct gc *gc)
 {
-	unsigned char data[GC_SNES_LENGTH];
+	unsigned char data[GC_SNESMOUSE_LENGTH];
 	struct input_dev *dev;
-	int i, j, s;
+	int i, j, s, len;
+	char x_rel, y_rel;
 
-	gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
+	len = gc->pads[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
+			(gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
+
+	gc_nes_read_packet(gc, len, data);
 
 	for (i = 0; i < GC_MAX_DEVICES; i++) {
 
@@ -270,6 +279,44 @@
 			for (j = 0; j < 8; j++)
 				input_report_key(dev, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
 
+		if (s & gc->pads[GC_SNESMOUSE]) {
+			/*
+			 * The 4 unused bits from SNES controllers appear to be ID bits
+			 * so use them to make sure iwe are dealing with a mouse.
+			 * gamepad is connected. This is important since
+			 * my SNES gamepad sends 1's for bits 16-31, which
+			 * cause the mouse pointer to quickly move to the
+			 * upper left corner of the screen.
+			 */
+			if (!(s & data[12]) && !(s & data[13]) &&
+			    !(s & data[14]) && (s & data[15])) {
+				input_report_key(dev, BTN_LEFT, s & data[9]);
+				input_report_key(dev, BTN_RIGHT, s & data[8]);
+
+				x_rel = y_rel = 0;
+				for (j = 0; j < 7; j++) {
+					x_rel <<= 1;
+					if (data[25 + j] & s)
+						x_rel |= 1;
+
+					y_rel <<= 1;
+					if (data[17 + j] & s)
+						y_rel |= 1;
+				}
+
+				if (x_rel) {
+					if (data[24] & s)
+						x_rel = -x_rel;
+					input_report_rel(dev, REL_X, x_rel);
+				}
+
+				if (y_rel) {
+					if (data[16] & s)
+						y_rel = -y_rel;
+					input_report_rel(dev, REL_Y, y_rel);
+				}
+			}
+		}
 		input_sync(dev);
 	}
 }
@@ -525,10 +572,10 @@
 		gc_n64_process_packet(gc);
 
 /*
- * NES and SNES pads
+ * NES and SNES pads or mouse
  */
 
-	if (gc->pads[GC_NES] || gc->pads[GC_SNES])
+	if (gc->pads[GC_NES] || gc->pads[GC_SNES] || gc->pads[GC_SNESMOUSE])
 		gc_nes_process_packet(gc);
 
 /*
@@ -610,10 +657,13 @@
 	input_dev->open = gc_open;
 	input_dev->close = gc_close;
 
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	if (pad_type != GC_SNESMOUSE) {
+		input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-	for (i = 0; i < 2; i++)
-		input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0);
+		for (i = 0; i < 2; i++)
+			input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0);
+	} else
+		input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 
 	gc->pads[0] |= gc_status_bit[idx];
 	gc->pads[pad_type] |= gc_status_bit[idx];
@@ -631,6 +681,13 @@
 
 			break;
 
+		case GC_SNESMOUSE:
+			set_bit(BTN_LEFT, input_dev->keybit);
+			set_bit(BTN_RIGHT, input_dev->keybit);
+			set_bit(REL_X, input_dev->relbit);
+			set_bit(REL_Y, input_dev->relbit);
+			break;
+
 		case GC_SNES:
 			for (i = 4; i < 8; i++)
 				set_bit(gc_snes_btn[i], input_dev->keybit);