diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-02-21 20:54:54 -0800 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-02-21 22:10:01 -0800 |
commit | 0995174dda3e97d70fd9c335c55041b6b5aa11dd (patch) | |
tree | 6915fcaaea6f3f30994c82830d207fbc9cd77b3a | |
parent | 315543fd112ae3b573bc44e7dbfef99c11714610 (diff) | |
download | op-kernel-dev-0995174dda3e97d70fd9c335c55041b6b5aa11dd.zip op-kernel-dev-0995174dda3e97d70fd9c335c55041b6b5aa11dd.tar.gz |
Input: gamecon - simplify pad type handling
Instead of having array bitmasks by type for all gamepads have explicit
type field in every pad structure.
Tested-by: Scott Moreau <oreaus@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/joystick/gamecon.c | 202 |
1 files changed, 123 insertions, 79 deletions
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index d57edd4..e9c6647 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -61,28 +61,36 @@ MODULE_PARM_DESC(map3, "Describes third set of devices"); /* see also gs_psx_delay parameter in PSX support section */ -#define GC_SNES 1 -#define GC_NES 2 -#define GC_NES4 3 -#define GC_MULTI 4 -#define GC_MULTI2 5 -#define GC_N64 6 -#define GC_PSX 7 -#define GC_DDR 8 -#define GC_SNESMOUSE 9 - -#define GC_MAX 9 +enum gc_type { + GC_NONE = 0, + GC_SNES, + GC_NES, + GC_NES4, + GC_MULTI, + GC_MULTI2, + GC_N64, + GC_PSX, + GC_DDR, + GC_SNESMOUSE, + GC_MAX +}; #define GC_REFRESH_TIME HZ/100 +struct gc_pad { + struct input_dev *dev; + enum gc_type type; + char phys[32]; +}; + struct gc { struct pardevice *pd; + struct gc_pad pads[GC_MAX_DEVICES]; struct input_dev *dev[GC_MAX_DEVICES]; struct timer_list timer; - unsigned char pads[GC_MAX + 1]; + int pad_count[GC_MAX]; int used; struct mutex mutex; - char phys[GC_MAX_DEVICES][32]; }; struct gc_subdev { @@ -218,13 +226,13 @@ static void gc_n64_process_packet(struct gc *gc) for (i = 0; i < GC_MAX_DEVICES; i++) { - dev = gc->dev[i]; - if (!dev) + if (gc->pads[i].type != GC_N64) continue; + dev = gc->pads[i].dev; s = gc_status_bit[i]; - if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) { + if (s & ~(data[8] | data[9])) { x = y = 0; @@ -363,39 +371,47 @@ 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_SNESMOUSE_LENGTH]; + struct gc_pad *pad; struct input_dev *dev; 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); + len = gc->pad_count[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH : + (gc->pad_count[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH); gc_nes_read_packet(gc, len, data); for (i = 0; i < GC_MAX_DEVICES; i++) { + pad = &gc->pads[i]; dev = gc->dev[i]; - if (!dev) - continue; - s = gc_status_bit[i]; - if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { + switch (pad->type) { + + case GC_NES: + input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7])); input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5])); - } - if (s & gc->pads[GC_NES]) for (j = 0; j < 4; j++) input_report_key(dev, gc_snes_btn[j], s & data[gc_nes_bytes[j]]); + input_sync(dev); + break; + + case GC_SNES: + + input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7])); + input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5])); - if (s & gc->pads[GC_SNES]) for (j = 0; j < 8; j++) input_report_key(dev, gc_snes_btn[j], s & data[gc_snes_bytes[j]]); + input_sync(dev); + break; - if (s & gc->pads[GC_SNESMOUSE]) { + case GC_SNESMOUSE: /* * The 4 unused bits from SNES controllers appear * to be ID bits so use them to make sure we are @@ -432,9 +448,14 @@ static void gc_nes_process_packet(struct gc *gc) y_rel = -y_rel; input_report_rel(dev, REL_Y, y_rel); } + + input_sync(dev); } + break; + + default: + break; } - input_sync(dev); } } @@ -462,32 +483,35 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) static void gc_multi_process_packet(struct gc *gc) { unsigned char data[GC_MULTI2_LENGTH]; - int data_len = gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH; + int data_len = gc->pad_count[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH; + struct gc_pad *pad; struct input_dev *dev; int i, s; gc_multi_read_packet(gc, data_len, data); for (i = 0; i < GC_MAX_DEVICES; i++) { - - dev = gc->dev[i]; - if (!dev) - continue; - + pad = &gc->pads[i]; + dev = pad->dev; s = gc_status_bit[i]; - if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { + switch (pad->type) { + case GC_MULTI2: + input_report_key(dev, BTN_THUMB, s & data[5]); + /* fall through */ + + case GC_MULTI: input_report_abs(dev, ABS_X, !(s & data[2]) - !(s & data[3])); input_report_abs(dev, ABS_Y, !(s & data[0]) - !(s & data[1])); input_report_key(dev, BTN_TRIGGER, s & data[4]); - } - - if (s & gc->pads[GC_MULTI2]) - input_report_key(dev, BTN_THUMB, s & data[5]); + input_sync(dev); + break; - input_sync(dev); + default: + break; + } } } @@ -548,9 +572,16 @@ static void gc_psx_command(struct gc *gc, int b, unsigned char *data) cmd = (b & 1) ? GC_PSX_COMMAND : 0; parport_write_data(port, cmd | GC_PSX_POWER); udelay(gc_psx_delay); + read = parport_read_status(port) ^ 0x80; - for (j = 0; j < GC_MAX_DEVICES; j++) - data[j] |= (read & gc_status_bit[j] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) ? (1 << i) : 0; + + for (j = 0; j < GC_MAX_DEVICES; j++) { + struct gc_pad *pad = &gc->pads[i]; + + if (pad->type == GC_PSX || pad->type == GC_DDR) + data[j] |= (read & gc_status_bit[j]) ? (1 << i) : 0; + } + parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); udelay(gc_psx_delay); } @@ -561,7 +592,8 @@ static void gc_psx_command(struct gc *gc, int b, unsigned char *data) * device identifier code. */ -static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES], +static void gc_psx_read_packet(struct gc *gc, + unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES], unsigned char id[GC_MAX_DEVICES]) { int i, j, max_len = 0; @@ -582,12 +614,15 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES] gc_psx_command(gc, 0, data2); /* Dump status */ /* Find the longest pad */ - for (i = 0; i < GC_MAX_DEVICES; i++) - if ((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) && + for (i = 0; i < GC_MAX_DEVICES; i++) { + struct gc_pad *pad = &gc->pads[i]; + + if ((pad->type == GC_PSX || pad->type == GC_DDR) && GC_PSX_LEN(id[i]) > max_len && GC_PSX_LEN(id[i]) <= GC_PSX_BYTES) { max_len = GC_PSX_LEN(id[i]); } + } /* Read in all the data */ for (i = 0; i < max_len; i++) { @@ -605,13 +640,13 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES] id[i] = GC_PSX_ID(id[i]); } -static void gc_psx_report_one(struct gc *gc, struct input_dev *dev, - unsigned char pad_type, unsigned char status_bit, +static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type, unsigned char *data) { + struct input_dev *dev = pad->dev; int i; - switch (pad_type) { + switch (psx_type) { case GC_PSX_RUMBLE: @@ -621,7 +656,7 @@ static void gc_psx_report_one(struct gc *gc, struct input_dev *dev, case GC_PSX_NEGCON: case GC_PSX_ANALOG: - if (gc->pads[GC_DDR] & status_bit) { + if (pad->type == GC_DDR) { for (i = 0; i < 4; i++) input_report_key(dev, gc_psx_ddr_btn[i], ~data[0] & (0x10 << i)); @@ -647,7 +682,8 @@ static void gc_psx_report_one(struct gc *gc, struct input_dev *dev, break; case GC_PSX_NORMAL: - if (gc->pads[GC_DDR] & status_bit) { + + if (pad->type == GC_DDR) { for (i = 0; i < 4; i++) input_report_key(dev, gc_psx_ddr_btn[i], ~data[0] & (0x10 << i)); @@ -679,7 +715,7 @@ static void gc_psx_report_one(struct gc *gc, struct input_dev *dev, break; - case 0: /* not a pad, ignore */ + default: /* not a pad, ignore */ break; } } @@ -688,15 +724,15 @@ static void gc_psx_process_packet(struct gc *gc) { unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES]; unsigned char id[GC_MAX_DEVICES]; + struct gc_pad *pad; int i; gc_psx_read_packet(gc, data, id); for (i = 0; i < GC_MAX_DEVICES; i++) { - - if (gc->dev[i]) - gc_psx_report_one(gc, gc->dev[i], - id[i], gc_status_bit[i], data[i]); + pad = &gc->pads[i]; + if (pad->type == GC_PSX || pad->type == GC_DDR) + gc_psx_report_one(pad, id[i], data[i]); } } @@ -712,28 +748,31 @@ static void gc_timer(unsigned long private) * N64 pads - must be read first, any read confuses them for 200 us */ - if (gc->pads[GC_N64]) + if (gc->pad_count[GC_N64]) gc_n64_process_packet(gc); /* * NES and SNES pads or mouse */ - if (gc->pads[GC_NES] || gc->pads[GC_SNES] || gc->pads[GC_SNESMOUSE]) + if (gc->pad_count[GC_NES] || + gc->pad_count[GC_SNES] || + gc->pad_count[GC_SNESMOUSE]) { gc_nes_process_packet(gc); + } /* * Multi and Multi2 joysticks */ - if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) + if (gc->pad_count[GC_MULTI] || gc->pad_count[GC_MULTI2]) gc_multi_process_packet(gc); /* * PSX controllers */ - if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) + if (gc->pad_count[GC_PSX] || gc->pad_count[GC_DDR]) gc_psx_process_packet(gc); mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); @@ -773,26 +812,29 @@ static void gc_close(struct input_dev *dev) static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) { + struct gc_pad *pad = &gc->pads[idx]; struct input_dev *input_dev; int i; int err; - if (!pad_type) - return 0; - if (pad_type < 1 || pad_type > GC_MAX) { printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type); return -EINVAL; } - gc->dev[idx] = input_dev = input_allocate_device(); + pad->dev = input_dev = input_allocate_device(); if (!input_dev) { printk(KERN_ERR "gamecon.c: Not enough memory for input device\n"); return -ENOMEM; } + pad->type = pad_type; + + snprintf(pad->phys, sizeof(pad->phys), + "%s/input%d", gc->pd->port->name, idx); + input_dev->name = gc_names[pad_type]; - input_dev->phys = gc->phys[idx]; + input_dev->phys = pad->phys; input_dev->id.bustype = BUS_PARPORT; input_dev->id.vendor = 0x0001; input_dev->id.product = pad_type; @@ -811,8 +853,7 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) } else input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - gc->pads[0] |= gc_status_bit[idx]; - gc->pads[pad_type] |= gc_status_bit[idx]; + gc->pad_count[pad_type]++; switch (pad_type) { @@ -828,8 +869,7 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) err = gc_n64_init_ff(input_dev, idx); if (err) { printk(KERN_WARNING "gamecon.c: Failed to initiate rumble for N64 device %d\n", idx); - input_free_device(input_dev); - return err; + goto err_free_dev; } break; @@ -873,7 +913,16 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) break; } + err = input_register_device(pad->dev); + if (err) + goto err_free_dev; + return 0; + +err_free_dev: + input_free_device(pad->dev); + pad->dev = NULL; + return err; } static struct gc __init *gc_probe(int parport, int *pads, int n_pads) @@ -882,6 +931,7 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads) struct parport *pp; struct pardevice *pd; int i; + int count = 0; int err; pp = parport_find_number(parport); @@ -913,18 +963,14 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads) if (!pads[i]) continue; - snprintf(gc->phys[i], sizeof(gc->phys[i]), - "%s/input%d", gc->pd->port->name, i); err = gc_setup_pad(gc, i, pads[i]); if (err) goto err_unreg_devs; - err = input_register_device(gc->dev[i]); - if (err) - goto err_free_dev; + count++; } - if (!gc->pads[0]) { + if (count == 0) { printk(KERN_ERR "gamecon.c: No valid devices specified\n"); err = -EINVAL; goto err_free_gc; @@ -933,12 +979,10 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads) parport_put_port(pp); return gc; - err_free_dev: - input_free_device(gc->dev[i]); err_unreg_devs: while (--i >= 0) - if (gc->dev[i]) - input_unregister_device(gc->dev[i]); + if (gc->pads[i].dev) + input_unregister_device(gc->pads[i].dev); err_free_gc: kfree(gc); err_unreg_pardev: @@ -954,8 +998,8 @@ static void gc_remove(struct gc *gc) int i; for (i = 0; i < GC_MAX_DEVICES; i++) - if (gc->dev[i]) - input_unregister_device(gc->dev[i]); + if (gc->pads[i].dev) + input_unregister_device(gc->pads[i].dev); parport_unregister_device(gc->pd); kfree(gc); } |