summaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorRaphael Assenat <raph@raphnet.net>2006-04-02 07:10:05 +0200
committerDmitry Torokhov <dtor_core@ameritech.net>2006-04-02 07:10:05 +0200
commitb157d55eef38f014015b8058a9f733d1c1c49cb4 (patch)
treead1a04c9be6aa67b11fd40686d06fc5d8d271b6b /drivers/input
parentInput: make modalias code respect allowed buffer size (diff)
downloadlinux-b157d55eef38f014015b8058a9f733d1c1c49cb4.tar.xz
linux-b157d55eef38f014015b8058a9f733d1c1c49cb4.zip
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>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/joystick/gamecon.c83
1 files changed, 70 insertions, 13 deletions
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);