aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/input/joystick-parport.txt11
-rw-r--r--drivers/input/joystick/gamecon.c83
2 files changed, 76 insertions, 18 deletions
diff --git a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt
index 88a011c9f985..d537c48cc6d0 100644
--- a/Documentation/input/joystick-parport.txt
+++ b/Documentation/input/joystick-parport.txt
@@ -36,12 +36,12 @@ with them.
All NES and SNES use the same synchronous serial protocol, clocked from
the computer's side (and thus timing insensitive). To allow up to 5 NES
-and/or SNES gamepads connected to the parallel port at once, the output
-lines of the parallel port are shared, while one of 5 available input lines
-is assigned to each gamepad.
+and/or SNES gamepads and/or SNES mice connected to the parallel port at once,
+the output lines of the parallel port are shared, while one of 5 available
+input lines is assigned to each gamepad.
This protocol is handled by the gamecon.c driver, so that's the one
-you'll use for NES and SNES gamepads.
+you'll use for NES, SNES gamepads and SNES mice.
The main problem with PC parallel ports is that they don't have +5V power
source on any of their pins. So, if you want a reliable source of power
@@ -106,7 +106,7 @@ A, Turbo B, Select and Start, and is connected through 5 wires, then it is
either a NES or NES clone and will work with this connection. SNES gamepads
also use 5 wires, but have more buttons. They will work as well, of course.
-Pinout for NES gamepads Pinout for SNES gamepads
+Pinout for NES gamepads Pinout for SNES gamepads and mice
+----> Power +-----------------------\
| 7 | o o o o | x x o | 1
@@ -454,6 +454,7 @@ uses the following kernel/module command line:
6 | N64 pad
7 | Sony PSX controller
8 | Sony PSX DDR controller
+ 9 | SNES mouse
The exact type of the PSX controller type is autoprobed when used so
hot swapping should work (but is not recomended).
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index aa3ef89d8188..ecbdb6b9bbd6 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 @@ __obsolete_setup("gc_3=");
#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 int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
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 @@ static void gc_n64_process_packet(struct gc *gc)
* 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_read_packet(struct gc *gc, int length, unsigned char *data)
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;
+
+ len = gc->pads[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
+ (gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
- gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
+ gc_nes_read_packet(gc, len, data);
for (i = 0; i < GC_MAX_DEVICES; i++) {
@@ -270,6 +279,44 @@ static void gc_nes_process_packet(struct gc *gc)
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 @@ static void gc_timer(unsigned long private)
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 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
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 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
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);