summaryrefslogtreecommitdiff
path: root/drivers/input/joystick
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/joystick')
-rw-r--r--drivers/input/joystick/db9.c114
-rw-r--r--drivers/input/joystick/gamecon.c104
-rw-r--r--drivers/input/joystick/turbografx.c105
-rw-r--r--drivers/input/joystick/walkera0701.c69
-rw-r--r--drivers/input/joystick/xpad.c931
5 files changed, 817 insertions, 506 deletions
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 8e7de5c77..da326090c 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -48,7 +48,7 @@ struct db9_config {
};
#define DB9_MAX_PORTS 3
-static struct db9_config db9_cfg[DB9_MAX_PORTS] __initdata;
+static struct db9_config db9_cfg[DB9_MAX_PORTS];
module_param_array_named(dev, db9_cfg[0].args, int, &db9_cfg[0].nargs, 0);
MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)");
@@ -106,6 +106,7 @@ struct db9 {
struct pardevice *pd;
int mode;
int used;
+ int parportno;
struct mutex mutex;
char phys[DB9_MAX_DEVICES][32];
};
@@ -553,54 +554,61 @@ static void db9_close(struct input_dev *dev)
mutex_unlock(&db9->mutex);
}
-static struct db9 __init *db9_probe(int parport, int mode)
+static void db9_attach(struct parport *pp)
{
struct db9 *db9;
const struct db9_mode_data *db9_mode;
- struct parport *pp;
struct pardevice *pd;
struct input_dev *input_dev;
- int i, j;
- int err;
+ int i, j, port_idx;
+ int mode;
+ struct pardev_cb db9_parport_cb;
+
+ for (port_idx = 0; port_idx < DB9_MAX_PORTS; port_idx++) {
+ if (db9_cfg[port_idx].nargs == 0 ||
+ db9_cfg[port_idx].args[DB9_ARG_PARPORT] < 0)
+ continue;
+
+ if (db9_cfg[port_idx].args[DB9_ARG_PARPORT] == pp->number)
+ break;
+ }
+
+ if (port_idx == DB9_MAX_PORTS) {
+ pr_debug("Not using parport%d.\n", pp->number);
+ return;
+ }
+
+ mode = db9_cfg[port_idx].args[DB9_ARG_MODE];
if (mode < 1 || mode >= DB9_MAX_PAD || !db9_modes[mode].n_buttons) {
printk(KERN_ERR "db9.c: Bad device type %d\n", mode);
- err = -EINVAL;
- goto err_out;
+ return;
}
db9_mode = &db9_modes[mode];
- pp = parport_find_number(parport);
- if (!pp) {
- printk(KERN_ERR "db9.c: no such parport\n");
- err = -ENODEV;
- goto err_out;
- }
-
if (db9_mode->bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
- err = -EINVAL;
- goto err_put_pp;
+ return;
}
- pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+ memset(&db9_parport_cb, 0, sizeof(db9_parport_cb));
+ db9_parport_cb.flags = PARPORT_FLAG_EXCL;
+
+ pd = parport_register_dev_model(pp, "db9", &db9_parport_cb, port_idx);
if (!pd) {
printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
- err = -EBUSY;
- goto err_put_pp;
+ return;
}
db9 = kzalloc(sizeof(struct db9), GFP_KERNEL);
- if (!db9) {
- printk(KERN_ERR "db9.c: Not enough memory\n");
- err = -ENOMEM;
+ if (!db9)
goto err_unreg_pardev;
- }
mutex_init(&db9->mutex);
db9->pd = pd;
db9->mode = mode;
+ db9->parportno = pp->number;
init_timer(&db9->timer);
db9->timer.data = (long) db9;
db9->timer.function = db9_timer;
@@ -610,7 +618,6 @@ static struct db9 __init *db9_probe(int parport, int mode)
db9->dev[i] = input_dev = input_allocate_device();
if (!input_dev) {
printk(KERN_ERR "db9.c: Not enough memory for input device\n");
- err = -ENOMEM;
goto err_unreg_devs;
}
@@ -639,13 +646,12 @@ static struct db9 __init *db9_probe(int parport, int mode)
input_set_abs_params(input_dev, db9_abs[j], 1, 255, 0, 0);
}
- err = input_register_device(input_dev);
- if (err)
+ if (input_register_device(input_dev))
goto err_free_dev;
}
- parport_put_port(pp);
- return db9;
+ db9_base[port_idx] = db9;
+ return;
err_free_dev:
input_free_device(db9->dev[i]);
@@ -655,15 +661,23 @@ static struct db9 __init *db9_probe(int parport, int mode)
kfree(db9);
err_unreg_pardev:
parport_unregister_device(pd);
- err_put_pp:
- parport_put_port(pp);
- err_out:
- return ERR_PTR(err);
}
-static void db9_remove(struct db9 *db9)
+static void db9_detach(struct parport *port)
{
int i;
+ struct db9 *db9;
+
+ for (i = 0; i < DB9_MAX_PORTS; i++) {
+ if (db9_base[i] && db9_base[i]->parportno == port->number)
+ break;
+ }
+
+ if (i == DB9_MAX_PORTS)
+ return;
+
+ db9 = db9_base[i];
+ db9_base[i] = NULL;
for (i = 0; i < min(db9_modes[db9->mode].n_pads, DB9_MAX_DEVICES); i++)
input_unregister_device(db9->dev[i]);
@@ -671,11 +685,17 @@ static void db9_remove(struct db9 *db9)
kfree(db9);
}
+static struct parport_driver db9_parport_driver = {
+ .name = "db9",
+ .match_port = db9_attach,
+ .detach = db9_detach,
+ .devmodel = true,
+};
+
static int __init db9_init(void)
{
int i;
int have_dev = 0;
- int err = 0;
for (i = 0; i < DB9_MAX_PORTS; i++) {
if (db9_cfg[i].nargs == 0 || db9_cfg[i].args[DB9_ARG_PARPORT] < 0)
@@ -683,37 +703,21 @@ static int __init db9_init(void)
if (db9_cfg[i].nargs < 2) {
printk(KERN_ERR "db9.c: Device type must be specified.\n");
- err = -EINVAL;
- break;
- }
-
- db9_base[i] = db9_probe(db9_cfg[i].args[DB9_ARG_PARPORT],
- db9_cfg[i].args[DB9_ARG_MODE]);
- if (IS_ERR(db9_base[i])) {
- err = PTR_ERR(db9_base[i]);
- break;
+ return -EINVAL;
}
have_dev = 1;
}
- if (err) {
- while (--i >= 0)
- if (db9_base[i])
- db9_remove(db9_base[i]);
- return err;
- }
+ if (!have_dev)
+ return -ENODEV;
- return have_dev ? 0 : -ENODEV;
+ return parport_register_driver(&db9_parport_driver);
}
static void __exit db9_exit(void)
{
- int i;
-
- for (i = 0; i < DB9_MAX_PORTS; i++)
- if (db9_base[i])
- db9_remove(db9_base[i]);
+ parport_unregister_driver(&db9_parport_driver);
}
module_init(db9_init);
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index e68e49786..eae14d512 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -53,7 +53,7 @@ struct gc_config {
unsigned int nargs;
};
-static struct gc_config gc_cfg[GC_MAX_PORTS] __initdata;
+static struct gc_config gc_cfg[GC_MAX_PORTS];
module_param_array_named(map, gc_cfg[0].args, int, &gc_cfg[0].nargs, 0);
MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)");
@@ -92,6 +92,7 @@ struct gc {
struct timer_list timer;
int pad_count[GC_MAX];
int used;
+ int parportno;
struct mutex mutex;
};
@@ -304,7 +305,7 @@ static int gc_n64_play_effect(struct input_dev *dev, void *data,
return 0;
}
-static int __init gc_n64_init_ff(struct input_dev *dev, int i)
+static int gc_n64_init_ff(struct input_dev *dev, int i)
{
struct gc_subdev *sdev;
int err;
@@ -811,7 +812,7 @@ static void gc_close(struct input_dev *dev)
mutex_unlock(&gc->mutex);
}
-static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
+static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
{
struct gc_pad *pad = &gc->pads[idx];
struct input_dev *input_dev;
@@ -926,46 +927,56 @@ err_free_dev:
return err;
}
-static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
+static void gc_attach(struct parport *pp)
{
struct gc *gc;
- struct parport *pp;
struct pardevice *pd;
- int i;
+ int i, port_idx;
int count = 0;
- int err;
+ int *pads, n_pads;
+ struct pardev_cb gc_parport_cb;
+
+ for (port_idx = 0; port_idx < GC_MAX_PORTS; port_idx++) {
+ if (gc_cfg[port_idx].nargs == 0 || gc_cfg[port_idx].args[0] < 0)
+ continue;
+
+ if (gc_cfg[port_idx].args[0] == pp->number)
+ break;
+ }
- pp = parport_find_number(parport);
- if (!pp) {
- pr_err("no such parport %d\n", parport);
- err = -EINVAL;
- goto err_out;
+ if (port_idx == GC_MAX_PORTS) {
+ pr_debug("Not using parport%d.\n", pp->number);
+ return;
}
+ pads = gc_cfg[port_idx].args + 1;
+ n_pads = gc_cfg[port_idx].nargs - 1;
- pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+ memset(&gc_parport_cb, 0, sizeof(gc_parport_cb));
+ gc_parport_cb.flags = PARPORT_FLAG_EXCL;
+
+ pd = parport_register_dev_model(pp, "gamecon", &gc_parport_cb,
+ port_idx);
if (!pd) {
pr_err("parport busy already - lp.o loaded?\n");
- err = -EBUSY;
- goto err_put_pp;
+ return;
}
gc = kzalloc(sizeof(struct gc), GFP_KERNEL);
if (!gc) {
pr_err("Not enough memory\n");
- err = -ENOMEM;
goto err_unreg_pardev;
}
mutex_init(&gc->mutex);
gc->pd = pd;
+ gc->parportno = pp->number;
setup_timer(&gc->timer, gc_timer, (long) gc);
for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) {
if (!pads[i])
continue;
- err = gc_setup_pad(gc, i, pads[i]);
- if (err)
+ if (gc_setup_pad(gc, i, pads[i]))
goto err_unreg_devs;
count++;
@@ -973,12 +984,11 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
if (count == 0) {
pr_err("No valid devices specified\n");
- err = -EINVAL;
goto err_free_gc;
}
- parport_put_port(pp);
- return gc;
+ gc_base[port_idx] = gc;
+ return;
err_unreg_devs:
while (--i >= 0)
@@ -988,15 +998,23 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
kfree(gc);
err_unreg_pardev:
parport_unregister_device(pd);
- err_put_pp:
- parport_put_port(pp);
- err_out:
- return ERR_PTR(err);
}
-static void gc_remove(struct gc *gc)
+static void gc_detach(struct parport *port)
{
int i;
+ struct gc *gc;
+
+ for (i = 0; i < GC_MAX_PORTS; i++) {
+ if (gc_base[i] && gc_base[i]->parportno == port->number)
+ break;
+ }
+
+ if (i == GC_MAX_PORTS)
+ return;
+
+ gc = gc_base[i];
+ gc_base[i] = NULL;
for (i = 0; i < GC_MAX_DEVICES; i++)
if (gc->pads[i].dev)
@@ -1005,11 +1023,17 @@ static void gc_remove(struct gc *gc)
kfree(gc);
}
+static struct parport_driver gc_parport_driver = {
+ .name = "gamecon",
+ .match_port = gc_attach,
+ .detach = gc_detach,
+ .devmodel = true,
+};
+
static int __init gc_init(void)
{
int i;
int have_dev = 0;
- int err = 0;
for (i = 0; i < GC_MAX_PORTS; i++) {
if (gc_cfg[i].nargs == 0 || gc_cfg[i].args[0] < 0)
@@ -1017,37 +1041,21 @@ static int __init gc_init(void)
if (gc_cfg[i].nargs < 2) {
pr_err("at least one device must be specified\n");
- err = -EINVAL;
- break;
- }
-
- gc_base[i] = gc_probe(gc_cfg[i].args[0],
- gc_cfg[i].args + 1, gc_cfg[i].nargs - 1);
- if (IS_ERR(gc_base[i])) {
- err = PTR_ERR(gc_base[i]);
- break;
+ return -EINVAL;
}
have_dev = 1;
}
- if (err) {
- while (--i >= 0)
- if (gc_base[i])
- gc_remove(gc_base[i]);
- return err;
- }
+ if (!have_dev)
+ return -ENODEV;
- return have_dev ? 0 : -ENODEV;
+ return parport_register_driver(&gc_parport_driver);
}
static void __exit gc_exit(void)
{
- int i;
-
- for (i = 0; i < GC_MAX_PORTS; i++)
- if (gc_base[i])
- gc_remove(gc_base[i]);
+ parport_unregister_driver(&gc_parport_driver);
}
module_init(gc_init);
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 891797ad7..77f575dd0 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -49,7 +49,7 @@ struct tgfx_config {
unsigned int nargs;
};
-static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS] __initdata;
+static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS];
module_param_array_named(map, tgfx_cfg[0].args, int, &tgfx_cfg[0].nargs, 0);
MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>");
@@ -81,6 +81,7 @@ static struct tgfx {
char phys[TGFX_MAX_DEVICES][32];
int sticks;
int used;
+ int parportno;
struct mutex sem;
} *tgfx_base[TGFX_MAX_PORTS];
@@ -156,38 +157,49 @@ static void tgfx_close(struct input_dev *dev)
* tgfx_probe() probes for tg gamepads.
*/
-static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
+static void tgfx_attach(struct parport *pp)
{
struct tgfx *tgfx;
struct input_dev *input_dev;
- struct parport *pp;
struct pardevice *pd;
- int i, j;
- int err;
+ int i, j, port_idx;
+ int *n_buttons, n_devs;
+ struct pardev_cb tgfx_parport_cb;
+
+ for (port_idx = 0; port_idx < TGFX_MAX_PORTS; port_idx++) {
+ if (tgfx_cfg[port_idx].nargs == 0 ||
+ tgfx_cfg[port_idx].args[0] < 0)
+ continue;
+ if (tgfx_cfg[port_idx].args[0] == pp->number)
+ break;
+ }
- pp = parport_find_number(parport);
- if (!pp) {
- printk(KERN_ERR "turbografx.c: no such parport\n");
- err = -EINVAL;
- goto err_out;
+ if (port_idx == TGFX_MAX_PORTS) {
+ pr_debug("Not using parport%d.\n", pp->number);
+ return;
}
+ n_buttons = tgfx_cfg[port_idx].args + 1;
+ n_devs = tgfx_cfg[port_idx].nargs - 1;
+
+ memset(&tgfx_parport_cb, 0, sizeof(tgfx_parport_cb));
+ tgfx_parport_cb.flags = PARPORT_FLAG_EXCL;
- pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+ pd = parport_register_dev_model(pp, "turbografx", &tgfx_parport_cb,
+ port_idx);
if (!pd) {
- printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n");
- err = -EBUSY;
- goto err_put_pp;
+ pr_err("parport busy already - lp.o loaded?\n");
+ return;
}
tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL);
if (!tgfx) {
printk(KERN_ERR "turbografx.c: Not enough memory\n");
- err = -ENOMEM;
goto err_unreg_pardev;
}
mutex_init(&tgfx->sem);
tgfx->pd = pd;
+ tgfx->parportno = pp->number;
init_timer(&tgfx->timer);
tgfx->timer.data = (long) tgfx;
tgfx->timer.function = tgfx_timer;
@@ -198,14 +210,12 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) {
printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]);
- err = -EINVAL;
goto err_unreg_devs;
}
tgfx->dev[i] = input_dev = input_allocate_device();
if (!input_dev) {
printk(KERN_ERR "turbografx.c: Not enough memory for input device\n");
- err = -ENOMEM;
goto err_unreg_devs;
}
@@ -234,19 +244,17 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
for (j = 0; j < n_buttons[i]; j++)
set_bit(tgfx_buttons[j], input_dev->keybit);
- err = input_register_device(tgfx->dev[i]);
- if (err)
+ if (input_register_device(tgfx->dev[i]))
goto err_free_dev;
}
if (!tgfx->sticks) {
printk(KERN_ERR "turbografx.c: No valid devices specified\n");
- err = -EINVAL;
goto err_free_tgfx;
}
- parport_put_port(pp);
- return tgfx;
+ tgfx_base[port_idx] = tgfx;
+ return;
err_free_dev:
input_free_device(tgfx->dev[i]);
@@ -258,15 +266,23 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
kfree(tgfx);
err_unreg_pardev:
parport_unregister_device(pd);
- err_put_pp:
- parport_put_port(pp);
- err_out:
- return ERR_PTR(err);
}
-static void tgfx_remove(struct tgfx *tgfx)
+static void tgfx_detach(struct parport *port)
{
int i;
+ struct tgfx *tgfx;
+
+ for (i = 0; i < TGFX_MAX_PORTS; i++) {
+ if (tgfx_base[i] && tgfx_base[i]->parportno == port->number)
+ break;
+ }
+
+ if (i == TGFX_MAX_PORTS)
+ return;
+
+ tgfx = tgfx_base[i];
+ tgfx_base[i] = NULL;
for (i = 0; i < TGFX_MAX_DEVICES; i++)
if (tgfx->dev[i])
@@ -275,11 +291,17 @@ static void tgfx_remove(struct tgfx *tgfx)
kfree(tgfx);
}
+static struct parport_driver tgfx_parport_driver = {
+ .name = "turbografx",
+ .match_port = tgfx_attach,
+ .detach = tgfx_detach,
+ .devmodel = true,
+};
+
static int __init tgfx_init(void)
{
int i;
int have_dev = 0;
- int err = 0;
for (i = 0; i < TGFX_MAX_PORTS; i++) {
if (tgfx_cfg[i].nargs == 0 || tgfx_cfg[i].args[0] < 0)
@@ -287,38 +309,21 @@ static int __init tgfx_init(void)
if (tgfx_cfg[i].nargs < 2) {
printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n");
- err = -EINVAL;
- break;
- }
-
- tgfx_base[i] = tgfx_probe(tgfx_cfg[i].args[0],
- tgfx_cfg[i].args + 1,
- tgfx_cfg[i].nargs - 1);
- if (IS_ERR(tgfx_base[i])) {
- err = PTR_ERR(tgfx_base[i]);
- break;
+ return -EINVAL;
}
have_dev = 1;
}
- if (err) {
- while (--i >= 0)
- if (tgfx_base[i])
- tgfx_remove(tgfx_base[i]);
- return err;
- }
+ if (!have_dev)
+ return -ENODEV;
- return have_dev ? 0 : -ENODEV;
+ return parport_register_driver(&tgfx_parport_driver);
}
static void __exit tgfx_exit(void)
{
- int i;
-
- for (i = 0; i < TGFX_MAX_PORTS; i++)
- if (tgfx_base[i])
- tgfx_remove(tgfx_base[i]);
+ parport_unregister_driver(&tgfx_parport_driver);
}
module_init(tgfx_init);
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
index a8bc2fe17..70a893a17 100644
--- a/drivers/input/joystick/walkera0701.c
+++ b/drivers/input/joystick/walkera0701.c
@@ -150,7 +150,7 @@ static void walkera0701_irq_handler(void *handler_data)
if (w->counter == 24) { /* full frame */
walkera0701_parse_frame(w);
w->counter = NO_SYNC;
- if (abs64(pulse_time - SYNC_PULSE) < RESERVE) /* new frame sync */
+ if (abs(pulse_time - SYNC_PULSE) < RESERVE) /* new frame sync */
w->counter = 0;
} else {
if ((pulse_time > (ANALOG_MIN_PULSE - RESERVE)
@@ -161,7 +161,7 @@ static void walkera0701_irq_handler(void *handler_data)
} else
w->counter = NO_SYNC;
}
- } else if (abs64(pulse_time - SYNC_PULSE - BIN0_PULSE) <
+ } else if (abs(pulse_time - SYNC_PULSE - BIN0_PULSE) <
RESERVE + BIN1_PULSE - BIN0_PULSE) /* frame sync .. */
w->counter = 0;
@@ -200,35 +200,39 @@ static void walkera0701_close(struct input_dev *dev)
parport_release(w->pardevice);
}
-static int walkera0701_connect(struct walkera_dev *w, int parport)
+static void walkera0701_attach(struct parport *pp)
{
- int error;
+ struct pardev_cb walkera0701_parport_cb;
+ struct walkera_dev *w = &w_dev;
- w->parport = parport_find_number(parport);
- if (!w->parport) {
- pr_err("parport %d does not exist\n", parport);
- return -ENODEV;
+ if (pp->number != walkera0701_pp_no) {
+ pr_debug("Not using parport%d.\n", pp->number);
+ return;
}
- if (w->parport->irq == -1) {
+ if (pp->irq == -1) {
pr_err("parport %d does not have interrupt assigned\n",
- parport);
- error = -EINVAL;
- goto err_put_parport;
+ pp->number);
+ return;
}
- w->pardevice = parport_register_device(w->parport, "walkera0701",
- NULL, NULL, walkera0701_irq_handler,
- PARPORT_DEV_EXCL, w);
+ w->parport = pp;
+
+ memset(&walkera0701_parport_cb, 0, sizeof(walkera0701_parport_cb));
+ walkera0701_parport_cb.flags = PARPORT_FLAG_EXCL;
+ walkera0701_parport_cb.irq_func = walkera0701_irq_handler;
+ walkera0701_parport_cb.private = w;
+
+ w->pardevice = parport_register_dev_model(pp, "walkera0701",
+ &walkera0701_parport_cb, 0);
+
if (!w->pardevice) {
pr_err("failed to register parport device\n");
- error = -EIO;
- goto err_put_parport;
+ return;
}
if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT)) {
pr_err("failed to negotiate parport mode\n");
- error = -EIO;
goto err_unregister_device;
}
@@ -238,7 +242,6 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
w->input_dev = input_allocate_device();
if (!w->input_dev) {
pr_err("failed to allocate input device\n");
- error = -ENOMEM;
goto err_unregister_device;
}
@@ -265,38 +268,46 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0);
input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0);
- error = input_register_device(w->input_dev);
- if (error) {
+ if (input_register_device(w->input_dev)) {
pr_err("failed to register input device\n");
goto err_free_input_dev;
}
- return 0;
+ return;
err_free_input_dev:
input_free_device(w->input_dev);
err_unregister_device:
parport_unregister_device(w->pardevice);
-err_put_parport:
- parport_put_port(w->parport);
- return error;
}
-static void walkera0701_disconnect(struct walkera_dev *w)
+static void walkera0701_detach(struct parport *port)
{
+ struct walkera_dev *w = &w_dev;
+
+ if (!w->pardevice || w->parport->number != port->number)
+ return;
+
input_unregister_device(w->input_dev);
parport_unregister_device(w->pardevice);
- parport_put_port(w->parport);
+ w->parport = NULL;
}
+static struct parport_driver walkera0701_parport_driver = {
+ .name = "walkera0701",
+ .match_port = walkera0701_attach,
+ .detach = walkera0701_detach,
+ .devmodel = true,
+};
+
static int __init walkera0701_init(void)
{
- return walkera0701_connect(&w_dev, walkera0701_pp_no);
+ return parport_register_driver(&walkera0701_parport_driver);
}
static void __exit walkera0701_exit(void)
{
- walkera0701_disconnect(&w_dev);
+ parport_unregister_driver(&walkera0701_parport_driver);
}
module_init(walkera0701_init);
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index f8850f9cb..22e62056c 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -76,10 +76,13 @@
*/
#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/rcupdate.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/usb/input.h>
+#include <linux/usb/quirks.h>
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver"
@@ -125,6 +128,7 @@ static const struct xpad_device {
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
+ { 0x045e, 0x02dd, "Microsoft X-Box One pad (Covert Forces)", 0, XTYPE_XBOXONE },
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -204,7 +208,7 @@ static const struct xpad_device {
{ 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 },
- { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", 0, XTYPE_XBOX360 },
+ { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 },
@@ -242,7 +246,6 @@ static const signed short xpad_btn_triggers[] = {
-1
};
-
static const signed short xpad360_btn[] = { /* buttons for x360 controller */
BTN_TL, BTN_TR, /* Button LB/RB */
BTN_MODE, /* The big X button */
@@ -317,24 +320,42 @@ static struct usb_device_id xpad_table[] = {
MODULE_DEVICE_TABLE(usb, xpad_table);
+struct xpad_output_packet {
+ u8 data[XPAD_PKT_LEN];
+ u8 len;
+ bool pending;
+};
+
+#define XPAD_OUT_CMD_IDX 0
+#define XPAD_OUT_FF_IDX 1
+#define XPAD_OUT_LED_IDX (1 + IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF))
+#define XPAD_NUM_OUT_PACKETS (1 + \
+ IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF) + \
+ IS_ENABLED(CONFIG_JOYSTICK_XPAD_LEDS))
+
struct usb_xpad {
struct input_dev *dev; /* input device interface */
+ struct input_dev __rcu *x360w_dev;
struct usb_device *udev; /* usb device */
struct usb_interface *intf; /* usb interface */
- int pad_present;
+ bool pad_present;
+ bool input_created;
struct urb *irq_in; /* urb for interrupt in report */
unsigned char *idata; /* input data */
dma_addr_t idata_dma;
- struct urb *bulk_out;
- unsigned char *bdata;
-
struct urb *irq_out; /* urb for interrupt out report */
+ struct usb_anchor irq_out_anchor;
+ bool irq_out_active; /* we must not use an active URB */
+ u8 odata_serial; /* serial number for xbox one protocol */
unsigned char *odata; /* output data */
dma_addr_t odata_dma;
- struct mutex odata_mutex;
+ spinlock_t odata_lock;
+
+ struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS];
+ int last_out_packet;
#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct xpad_led *led;
@@ -344,9 +365,14 @@ struct usb_xpad {
int mapping; /* map d-pad to buttons or to axes */
int xtype; /* type of xbox device */
- unsigned long led_no; /* led to lit on xbox360 controllers */
+ int pad_nr; /* the order x360 pads were attached */
+ const char *name; /* name of the device */
+ struct work_struct work; /* init/remove device from callback */
};
+static int xpad_init_input(struct usb_xpad *xpad);
+static void xpad_deinit_input(struct usb_xpad *xpad);
+
/*
* xpad_process_packet
*
@@ -356,7 +382,6 @@ struct usb_xpad {
* The used report descriptor was taken from ITO Takayukis website:
* http://euc.jp/periphs/xbox-controller.ja.html
*/
-
static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
{
struct input_dev *dev = xpad->dev;
@@ -427,11 +452,9 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
* http://www.free60.org/wiki/Gamepad
*/
-static void xpad360_process_packet(struct usb_xpad *xpad,
+static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
u16 cmd, unsigned char *data)
{
- struct input_dev *dev = xpad->dev;
-
/* digital pad */
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (left, right, up, down) */
@@ -439,7 +462,16 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
- } else {
+ }
+
+ /*
+ * This should be a simple else block. However historically
+ * xbox360w has mapped DPAD to buttons while xbox360 did not. This
+ * made no sense, but now we can not just switch back and have to
+ * support both behaviors.
+ */
+ if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) ||
+ xpad->xtype == XTYPE_XBOX360W) {
input_report_abs(dev, ABS_HAT0X,
!!(data[2] & 0x08) - !!(data[2] & 0x04));
input_report_abs(dev, ABS_HAT0Y,
@@ -489,7 +521,30 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_sync(dev);
}
-static void xpad_identify_controller(struct usb_xpad *xpad);
+static void xpad_presence_work(struct work_struct *work)
+{
+ struct usb_xpad *xpad = container_of(work, struct usb_xpad, work);
+ int error;
+
+ if (xpad->pad_present) {
+ error = xpad_init_input(xpad);
+ if (error) {
+ /* complain only, not much else we can do here */
+ dev_err(&xpad->dev->dev,
+ "unable to init device: %d\n", error);
+ } else {
+ rcu_assign_pointer(xpad->x360w_dev, xpad->dev);
+ }
+ } else {
+ RCU_INIT_POINTER(xpad->x360w_dev, NULL);
+ synchronize_rcu();
+ /*
+ * Now that we are sure xpad360w_process_packet is not
+ * using input device we can get rid of it.
+ */
+ xpad_deinit_input(xpad);
+ }
+}
/*
* xpad360w_process_packet
@@ -505,28 +560,30 @@ static void xpad_identify_controller(struct usb_xpad *xpad);
* 01.1 - Pad state (Bytes 4+) valid
*
*/
-
static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
{
+ struct input_dev *dev;
+ bool present;
+
/* Presence change */
if (data[0] & 0x08) {
- if (data[1] & 0x80) {
- xpad->pad_present = 1;
- usb_submit_urb(xpad->bulk_out, GFP_ATOMIC);
- /*
- * Light up the segment corresponding to
- * controller number.
- */
- xpad_identify_controller(xpad);
- } else
- xpad->pad_present = 0;
+ present = (data[1] & 0x80) != 0;
+
+ if (xpad->pad_present != present) {
+ xpad->pad_present = present;
+ schedule_work(&xpad->work);
+ }
}
/* Valid pad data */
- if (!(data[1] & 0x1))
+ if (data[1] != 0x1)
return;
- xpad360_process_packet(xpad, cmd, &data[4]);
+ rcu_read_lock();
+ dev = rcu_dereference(xpad->x360w_dev);
+ if (dev)
+ xpad360_process_packet(xpad, dev, cmd, &data[4]);
+ rcu_read_unlock();
}
/*
@@ -655,7 +712,7 @@ static void xpad_irq_in(struct urb *urb)
switch (xpad->xtype) {
case XTYPE_XBOX360:
- xpad360_process_packet(xpad, 0, xpad->idata);
+ xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata);
break;
case XTYPE_XBOX360W:
xpad360w_process_packet(xpad, 0, xpad->idata);
@@ -674,40 +731,73 @@ exit:
__func__, retval);
}
-static void xpad_bulk_out(struct urb *urb)
+/* Callers must hold xpad->odata_lock spinlock */
+static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad)
{
- struct usb_xpad *xpad = urb->context;
- struct device *dev = &xpad->intf->dev;
+ struct xpad_output_packet *pkt, *packet = NULL;
+ int i;
+
+ for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) {
+ if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS)
+ xpad->last_out_packet = 0;
+
+ pkt = &xpad->out_packets[xpad->last_out_packet];
+ if (pkt->pending) {
+ dev_dbg(&xpad->intf->dev,
+ "%s - found pending output packet %d\n",
+ __func__, xpad->last_out_packet);
+ packet = pkt;
+ break;
+ }
+ }
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dev_dbg(dev, "%s - urb shutting down with status: %d\n",
- __func__, urb->status);
- break;
- default:
- dev_dbg(dev, "%s - nonzero urb status received: %d\n",
- __func__, urb->status);
+ if (packet) {
+ memcpy(xpad->odata, packet->data, packet->len);
+ xpad->irq_out->transfer_buffer_length = packet->len;
+ return true;
+ }
+
+ return false;
+}
+
+/* Callers must hold xpad->odata_lock spinlock */
+static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad)
+{
+ int error;
+
+ if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) {
+ usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor);
+ error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+ if (error) {
+ dev_err(&xpad->intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, error);
+ usb_unanchor_urb(xpad->irq_out);
+ return -EIO;
+ }
+
+ xpad->irq_out_active = true;
}
+
+ return 0;
}
static void xpad_irq_out(struct urb *urb)
{
struct usb_xpad *xpad = urb->context;
struct device *dev = &xpad->intf->dev;
- int retval, status;
+ int status = urb->status;
+ int error;
+ unsigned long flags;
- status = urb->status;
+ spin_lock_irqsave(&xpad->odata_lock, flags);
switch (status) {
case 0:
/* success */
- return;
+ xpad->out_packets[xpad->last_out_packet].pending = false;
+ xpad->irq_out_active = xpad_prepare_next_out_packet(xpad);
+ break;
case -ECONNRESET:
case -ENOENT:
@@ -715,19 +805,28 @@ static void xpad_irq_out(struct urb *urb)
/* this urb is terminated, clean up */
dev_dbg(dev, "%s - urb shutting down with status: %d\n",
__func__, status);
- return;
+ xpad->irq_out_active = false;
+ break;
default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, status);
- goto exit;
+ break;
}
-exit:
- retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval)
- dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
- __func__, retval);
+ if (xpad->irq_out_active) {
+ usb_anchor_urb(urb, &xpad->irq_out_anchor);
+ error = usb_submit_urb(urb, GFP_ATOMIC);
+ if (error) {
+ dev_err(dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, error);
+ usb_unanchor_urb(urb);
+ xpad->irq_out_active = false;
+ }
+ }
+
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
}
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
@@ -739,6 +838,8 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
if (xpad->xtype == XTYPE_UNKNOWN)
return 0;
+ init_usb_anchor(&xpad->irq_out_anchor);
+
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->odata_dma);
if (!xpad->odata) {
@@ -746,7 +847,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
goto fail1;
}
- mutex_init(&xpad->odata_mutex);
+ spin_lock_init(&xpad->odata_lock);
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_out) {
@@ -773,8 +874,14 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
static void xpad_stop_output(struct usb_xpad *xpad)
{
- if (xpad->xtype != XTYPE_UNKNOWN)
- usb_kill_urb(xpad->irq_out);
+ if (xpad->xtype != XTYPE_UNKNOWN) {
+ if (!usb_wait_anchor_empty_timeout(&xpad->irq_out_anchor,
+ 5000)) {
+ dev_warn(&xpad->intf->dev,
+ "timed out waiting for output URB to complete, killing\n");
+ usb_kill_anchored_urbs(&xpad->irq_out_anchor);
+ }
+ }
}
static void xpad_deinit_output(struct usb_xpad *xpad)
@@ -786,84 +893,157 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
}
}
+static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
+{
+ struct xpad_output_packet *packet =
+ &xpad->out_packets[XPAD_OUT_CMD_IDX];
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&xpad->odata_lock, flags);
+
+ packet->data[0] = 0x08;
+ packet->data[1] = 0x00;
+ packet->data[2] = 0x0F;
+ packet->data[3] = 0xC0;
+ packet->data[4] = 0x00;
+ packet->data[5] = 0x00;
+ packet->data[6] = 0x00;
+ packet->data[7] = 0x00;
+ packet->data[8] = 0x00;
+ packet->data[9] = 0x00;
+ packet->data[10] = 0x00;
+ packet->data[11] = 0x00;
+ packet->len = 12;
+ packet->pending = true;
+
+ /* Reset the sequence so we send out presence first */
+ xpad->last_out_packet = -1;
+ retval = xpad_try_sending_next_out_packet(xpad);
+
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
+
+ return retval;
+}
+
+static int xpad_start_xbox_one(struct usb_xpad *xpad)
+{
+ struct xpad_output_packet *packet =
+ &xpad->out_packets[XPAD_OUT_CMD_IDX];
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&xpad->odata_lock, flags);
+
+ /* Xbox one controller needs to be initialized. */
+ packet->data[0] = 0x05;
+ packet->data[1] = 0x20;
+ packet->data[2] = xpad->odata_serial++; /* packet serial */
+ packet->data[3] = 0x01; /* rumble bit enable? */
+ packet->data[4] = 0x00;
+ packet->len = 5;
+ packet->pending = true;
+
+ /* Reset the sequence so we send out start packet first */
+ xpad->last_out_packet = -1;
+ retval = xpad_try_sending_next_out_packet(xpad);
+
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
+
+ return retval;
+}
+
#ifdef CONFIG_JOYSTICK_XPAD_FF
static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
+ struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX];
+ __u16 strong;
+ __u16 weak;
+ int retval;
+ unsigned long flags;
- if (effect->type == FF_RUMBLE) {
- __u16 strong = effect->u.rumble.strong_magnitude;
- __u16 weak = effect->u.rumble.weak_magnitude;
-
- switch (xpad->xtype) {
-
- case XTYPE_XBOX:
- xpad->odata[0] = 0x00;
- xpad->odata[1] = 0x06;
- xpad->odata[2] = 0x00;
- xpad->odata[3] = strong / 256; /* left actuator */
- xpad->odata[4] = 0x00;
- xpad->odata[5] = weak / 256; /* right actuator */
- xpad->irq_out->transfer_buffer_length = 6;
-
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
- case XTYPE_XBOX360:
- xpad->odata[0] = 0x00;
- xpad->odata[1] = 0x08;
- xpad->odata[2] = 0x00;
- xpad->odata[3] = strong / 256; /* left actuator? */
- xpad->odata[4] = weak / 256; /* right actuator? */
- xpad->odata[5] = 0x00;
- xpad->odata[6] = 0x00;
- xpad->odata[7] = 0x00;
- xpad->irq_out->transfer_buffer_length = 8;
-
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
- case XTYPE_XBOX360W:
- xpad->odata[0] = 0x00;
- xpad->odata[1] = 0x01;
- xpad->odata[2] = 0x0F;
- xpad->odata[3] = 0xC0;
- xpad->odata[4] = 0x00;
- xpad->odata[5] = strong / 256;
- xpad->odata[6] = weak / 256;
- xpad->odata[7] = 0x00;
- xpad->odata[8] = 0x00;
- xpad->odata[9] = 0x00;
- xpad->odata[10] = 0x00;
- xpad->odata[11] = 0x00;
- xpad->irq_out->transfer_buffer_length = 12;
-
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
- case XTYPE_XBOXONE:
- xpad->odata[0] = 0x09; /* activate rumble */
- xpad->odata[1] = 0x08;
- xpad->odata[2] = 0x00;
- xpad->odata[3] = 0x08; /* continuous effect */
- xpad->odata[4] = 0x00; /* simple rumble mode */
- xpad->odata[5] = 0x03; /* L and R actuator only */
- xpad->odata[6] = 0x00; /* TODO: LT actuator */
- xpad->odata[7] = 0x00; /* TODO: RT actuator */
- xpad->odata[8] = strong / 256; /* left actuator */
- xpad->odata[9] = weak / 256; /* right actuator */
- xpad->odata[10] = 0x80; /* length of pulse */
- xpad->odata[11] = 0x00; /* stop period of pulse */
- xpad->irq_out->transfer_buffer_length = 12;
-
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
- default:
- dev_dbg(&xpad->dev->dev,
- "%s - rumble command sent to unsupported xpad type: %d\n",
- __func__, xpad->xtype);
- return -1;
- }
+ if (effect->type != FF_RUMBLE)
+ return 0;
+
+ strong = effect->u.rumble.strong_magnitude;
+ weak = effect->u.rumble.weak_magnitude;
+
+ spin_lock_irqsave(&xpad->odata_lock, flags);
+
+ switch (xpad->xtype) {
+ case XTYPE_XBOX:
+ packet->data[0] = 0x00;
+ packet->data[1] = 0x06;
+ packet->data[2] = 0x00;
+ packet->data[3] = strong / 256; /* left actuator */
+ packet->data[4] = 0x00;
+ packet->data[5] = weak / 256; /* right actuator */
+ packet->len = 6;
+ packet->pending = true;
+ break;
+
+ case XTYPE_XBOX360:
+ packet->data[0] = 0x00;
+ packet->data[1] = 0x08;
+ packet->data[2] = 0x00;
+ packet->data[3] = strong / 256; /* left actuator? */
+ packet->data[4] = weak / 256; /* right actuator? */
+ packet->data[5] = 0x00;
+ packet->data[6] = 0x00;
+ packet->data[7] = 0x00;
+ packet->len = 8;
+ packet->pending = true;
+ break;
+
+ case XTYPE_XBOX360W:
+ packet->data[0] = 0x00;
+ packet->data[1] = 0x01;
+ packet->data[2] = 0x0F;
+ packet->data[3] = 0xC0;
+ packet->data[4] = 0x00;
+ packet->data[5] = strong / 256;
+ packet->data[6] = weak / 256;
+ packet->data[7] = 0x00;
+ packet->data[8] = 0x00;
+ packet->data[9] = 0x00;
+ packet->data[10] = 0x00;
+ packet->data[11] = 0x00;
+ packet->len = 12;
+ packet->pending = true;
+ break;
+
+ case XTYPE_XBOXONE:
+ packet->data[0] = 0x09; /* activate rumble */
+ packet->data[1] = 0x08;
+ packet->data[2] = xpad->odata_serial++;
+ packet->data[3] = 0x08; /* continuous effect */
+ packet->data[4] = 0x00; /* simple rumble mode */
+ packet->data[5] = 0x03; /* L and R actuator only */
+ packet->data[6] = 0x00; /* TODO: LT actuator */
+ packet->data[7] = 0x00; /* TODO: RT actuator */
+ packet->data[8] = strong / 512; /* left actuator */
+ packet->data[9] = weak / 512; /* right actuator */
+ packet->data[10] = 0x80; /* length of pulse */
+ packet->data[11] = 0x00; /* stop period of pulse */
+ packet->data[12] = 0x00;
+ packet->len = 13;
+ packet->pending = true;
+ break;
+
+ default:
+ dev_dbg(&xpad->dev->dev,
+ "%s - rumble command sent to unsupported xpad type: %d\n",
+ __func__, xpad->xtype);
+ retval = -EINVAL;
+ goto out;
}
- return 0;
+ retval = xpad_try_sending_next_out_packet(xpad);
+
+out:
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
+ return retval;
}
static int xpad_init_ff(struct usb_xpad *xpad)
@@ -882,6 +1062,9 @@ static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
#include <linux/leds.h>
+#include <linux/idr.h>
+
+static DEFINE_IDA(xpad_pad_seq);
struct xpad_led {
char name[16];
@@ -890,6 +1073,7 @@ struct xpad_led {
};
/**
+ * set the LEDs on Xbox360 / Wireless Controllers
* @param command
* 0: off
* 1: all blink, then previous setting
@@ -910,42 +1094,53 @@ struct xpad_led {
*/
static void xpad_send_led_command(struct usb_xpad *xpad, int command)
{
+ struct xpad_output_packet *packet =
+ &xpad->out_packets[XPAD_OUT_LED_IDX];
+ unsigned long flags;
+
command %= 16;
- mutex_lock(&xpad->odata_mutex);
+ spin_lock_irqsave(&xpad->odata_lock, flags);
switch (xpad->xtype) {
case XTYPE_XBOX360:
- xpad->odata[0] = 0x01;
- xpad->odata[1] = 0x03;
- xpad->odata[2] = command;
- xpad->irq_out->transfer_buffer_length = 3;
+ packet->data[0] = 0x01;
+ packet->data[1] = 0x03;
+ packet->data[2] = command;
+ packet->len = 3;
+ packet->pending = true;
break;
+
case XTYPE_XBOX360W:
- xpad->odata[0] = 0x00;
- xpad->odata[1] = 0x00;
- xpad->odata[2] = 0x08;
- xpad->odata[3] = 0x40 + command;
- xpad->odata[4] = 0x00;
- xpad->odata[5] = 0x00;
- xpad->odata[6] = 0x00;
- xpad->odata[7] = 0x00;
- xpad->odata[8] = 0x00;
- xpad->odata[9] = 0x00;
- xpad->odata[10] = 0x00;
- xpad->odata[11] = 0x00;
- xpad->irq_out->transfer_buffer_length = 12;
+ packet->data[0] = 0x00;
+ packet->data[1] = 0x00;
+ packet->data[2] = 0x08;
+ packet->data[3] = 0x40 + command;
+ packet->data[4] = 0x00;
+ packet->data[5] = 0x00;
+ packet->data[6] = 0x00;
+ packet->data[7] = 0x00;
+ packet->data[8] = 0x00;
+ packet->data[9] = 0x00;
+ packet->data[10] = 0x00;
+ packet->data[11] = 0x00;
+ packet->len = 12;
+ packet->pending = true;
break;
}
- usb_submit_urb(xpad->irq_out, GFP_KERNEL);
- mutex_unlock(&xpad->odata_mutex);
+ xpad_try_sending_next_out_packet(xpad);
+
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
}
+/*
+ * Light up the segment corresponding to the pad number on
+ * Xbox 360 Controllers.
+ */
static void xpad_identify_controller(struct usb_xpad *xpad)
{
- /* Light up the segment corresponding to controller number */
- xpad_send_led_command(xpad, (xpad->led_no % 4) + 2);
+ led_set_brightness(&xpad->led->led_cdev, (xpad->pad_nr % 4) + 2);
}
static void xpad_led_set(struct led_classdev *led_cdev,
@@ -959,7 +1154,6 @@ static void xpad_led_set(struct led_classdev *led_cdev,
static int xpad_led_probe(struct usb_xpad *xpad)
{
- static atomic_t led_seq = ATOMIC_INIT(-1);
struct xpad_led *led;
struct led_classdev *led_cdev;
int error;
@@ -971,9 +1165,13 @@ static int xpad_led_probe(struct usb_xpad *xpad)
if (!led)
return -ENOMEM;
- xpad->led_no = atomic_inc_return(&led_seq);
+ xpad->pad_nr = ida_simple_get(&xpad_pad_seq, 0, 0, GFP_KERNEL);
+ if (xpad->pad_nr < 0) {
+ error = xpad->pad_nr;
+ goto err_free_mem;
+ }
- snprintf(led->name, sizeof(led->name), "xpad%lu", xpad->led_no);
+ snprintf(led->name, sizeof(led->name), "xpad%d", xpad->pad_nr);
led->xpad = xpad;
led_cdev = &led->led_cdev;
@@ -981,16 +1179,19 @@ static int xpad_led_probe(struct usb_xpad *xpad)
led_cdev->brightness_set = xpad_led_set;
error = led_classdev_register(&xpad->udev->dev, led_cdev);
- if (error) {
- kfree(led);
- xpad->led = NULL;
- return error;
- }
+ if (error)
+ goto err_free_id;
- /* Light up the segment corresponding to controller number */
xpad_identify_controller(xpad);
return 0;
+
+err_free_id:
+ ida_simple_remove(&xpad_pad_seq, xpad->pad_nr);
+err_free_mem:
+ kfree(led);
+ xpad->led = NULL;
+ return error;
}
static void xpad_led_disconnect(struct usb_xpad *xpad)
@@ -999,6 +1200,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
if (xpad_led) {
led_classdev_unregister(&xpad_led->led_cdev);
+ ida_simple_remove(&xpad_pad_seq, xpad->pad_nr);
kfree(xpad_led);
}
}
@@ -1008,38 +1210,73 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) { }
static void xpad_identify_controller(struct usb_xpad *xpad) { }
#endif
-
-static int xpad_open(struct input_dev *dev)
+static int xpad_start_input(struct usb_xpad *xpad)
{
- struct usb_xpad *xpad = input_get_drvdata(dev);
-
- /* URB was submitted in probe */
- if (xpad->xtype == XTYPE_XBOX360W)
- return 0;
+ int error;
- xpad->irq_in->dev = xpad->udev;
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
return -EIO;
if (xpad->xtype == XTYPE_XBOXONE) {
- /* Xbox one controller needs to be initialized. */
- xpad->odata[0] = 0x05;
- xpad->odata[1] = 0x20;
- xpad->irq_out->transfer_buffer_length = 2;
- return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ error = xpad_start_xbox_one(xpad);
+ if (error) {
+ usb_kill_urb(xpad->irq_in);
+ return error;
+ }
}
return 0;
}
-static void xpad_close(struct input_dev *dev)
+static void xpad_stop_input(struct usb_xpad *xpad)
{
- struct usb_xpad *xpad = input_get_drvdata(dev);
+ usb_kill_urb(xpad->irq_in);
+}
- if (xpad->xtype != XTYPE_XBOX360W)
+static int xpad360w_start_input(struct usb_xpad *xpad)
+{
+ int error;
+
+ error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
+ if (error)
+ return -EIO;
+
+ /*
+ * Send presence packet.
+ * This will force the controller to resend connection packets.
+ * This is useful in the case we activate the module after the
+ * adapter has been plugged in, as it won't automatically
+ * send us info about the controllers.
+ */
+ error = xpad_inquiry_pad_presence(xpad);
+ if (error) {
usb_kill_urb(xpad->irq_in);
+ return error;
+ }
- xpad_stop_output(xpad);
+ return 0;
+}
+
+static void xpad360w_stop_input(struct usb_xpad *xpad)
+{
+ usb_kill_urb(xpad->irq_in);
+
+ /* Make sure we are done with presence work if it was scheduled */
+ flush_work(&xpad->work);
+}
+
+static int xpad_open(struct input_dev *dev)
+{
+ struct usb_xpad *xpad = input_get_drvdata(dev);
+
+ return xpad_start_input(xpad);
+}
+
+static void xpad_close(struct input_dev *dev)
+{
+ struct usb_xpad *xpad = input_get_drvdata(dev);
+
+ xpad_stop_input(xpad);
}
static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
@@ -1068,11 +1305,113 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
}
}
+static void xpad_deinit_input(struct usb_xpad *xpad)
+{
+ if (xpad->input_created) {
+ xpad->input_created = false;
+ xpad_led_disconnect(xpad);
+ input_unregister_device(xpad->dev);
+ }
+}
+
+static int xpad_init_input(struct usb_xpad *xpad)
+{
+ struct input_dev *input_dev;
+ int i, error;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
+
+ xpad->dev = input_dev;
+ input_dev->name = xpad->name;
+ input_dev->phys = xpad->phys;
+ usb_to_input_id(xpad->udev, &input_dev->id);
+ input_dev->dev.parent = &xpad->intf->dev;
+
+ input_set_drvdata(input_dev, xpad);
+
+ if (xpad->xtype != XTYPE_XBOX360W) {
+ input_dev->open = xpad_open;
+ input_dev->close = xpad_close;
+ }
+
+ __set_bit(EV_KEY, input_dev->evbit);
+
+ if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+ __set_bit(EV_ABS, input_dev->evbit);
+ /* set up axes */
+ for (i = 0; xpad_abs[i] >= 0; i++)
+ xpad_set_up_abs(input_dev, xpad_abs[i]);
+ }
+
+ /* set up standard buttons */
+ for (i = 0; xpad_common_btn[i] >= 0; i++)
+ __set_bit(xpad_common_btn[i], input_dev->keybit);
+
+ /* set up model-specific ones */
+ if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
+ xpad->xtype == XTYPE_XBOXONE) {
+ for (i = 0; xpad360_btn[i] >= 0; i++)
+ __set_bit(xpad360_btn[i], input_dev->keybit);
+ } else {
+ for (i = 0; xpad_btn[i] >= 0; i++)
+ __set_bit(xpad_btn[i], input_dev->keybit);
+ }
+
+ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+ for (i = 0; xpad_btn_pad[i] >= 0; i++)
+ __set_bit(xpad_btn_pad[i], input_dev->keybit);
+ }
+
+ /*
+ * This should be a simple else block. However historically
+ * xbox360w has mapped DPAD to buttons while xbox360 did not. This
+ * made no sense, but now we can not just switch back and have to
+ * support both behaviors.
+ */
+ if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) ||
+ xpad->xtype == XTYPE_XBOX360W) {
+ for (i = 0; xpad_abs_pad[i] >= 0; i++)
+ xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+ }
+
+ if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+ for (i = 0; xpad_btn_triggers[i] >= 0; i++)
+ __set_bit(xpad_btn_triggers[i], input_dev->keybit);
+ } else {
+ for (i = 0; xpad_abs_triggers[i] >= 0; i++)
+ xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
+ }
+
+ error = xpad_init_ff(xpad);
+ if (error)
+ goto err_free_input;
+
+ error = xpad_led_probe(xpad);
+ if (error)
+ goto err_destroy_ff;
+
+ error = input_register_device(xpad->dev);
+ if (error)
+ goto err_disconnect_led;
+
+ xpad->input_created = true;
+ return 0;
+
+err_disconnect_led:
+ xpad_led_disconnect(xpad);
+err_destroy_ff:
+ input_ff_destroy(input_dev);
+err_free_input:
+ input_free_device(input_dev);
+ return error;
+}
+
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_xpad *xpad;
- struct input_dev *input_dev;
struct usb_endpoint_descriptor *ep_irq_in;
int ep_irq_in_idx;
int i, error;
@@ -1094,29 +1433,31 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
}
xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!xpad || !input_dev) {
- error = -ENOMEM;
- goto fail1;
- }
+ if (!xpad)
+ return -ENOMEM;
+
+ usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
+ strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->idata_dma);
if (!xpad->idata) {
error = -ENOMEM;
- goto fail1;
+ goto err_free_mem;
}
xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_in) {
error = -ENOMEM;
- goto fail2;
+ goto err_free_idata;
}
xpad->udev = udev;
xpad->intf = intf;
xpad->mapping = xpad_device[i].mapping;
xpad->xtype = xpad_device[i].xtype;
+ xpad->name = xpad_device[i].name;
+ INIT_WORK(&xpad->work, xpad_presence_work);
if (xpad->xtype == XTYPE_UNKNOWN) {
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
@@ -1124,8 +1465,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->xtype = XTYPE_XBOX360W;
else
xpad->xtype = XTYPE_XBOX360;
- } else
+ } else {
xpad->xtype = XTYPE_XBOX;
+ }
if (dpad_to_buttons)
xpad->mapping |= MAP_DPAD_TO_BUTTONS;
@@ -1135,70 +1477,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->mapping |= MAP_STICKS_TO_NULL;
}
- xpad->dev = input_dev;
- usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
- strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
-
- input_dev->name = xpad_device[i].name;
- input_dev->phys = xpad->phys;
- usb_to_input_id(udev, &input_dev->id);
- input_dev->dev.parent = &intf->dev;
-
- input_set_drvdata(input_dev, xpad);
-
- input_dev->open = xpad_open;
- input_dev->close = xpad_close;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
-
- if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
- input_dev->evbit[0] |= BIT_MASK(EV_ABS);
- /* set up axes */
- for (i = 0; xpad_abs[i] >= 0; i++)
- xpad_set_up_abs(input_dev, xpad_abs[i]);
- }
-
- /* set up standard buttons */
- for (i = 0; xpad_common_btn[i] >= 0; i++)
- __set_bit(xpad_common_btn[i], input_dev->keybit);
-
- /* set up model-specific ones */
- if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
- xpad->xtype == XTYPE_XBOXONE) {
- for (i = 0; xpad360_btn[i] >= 0; i++)
- __set_bit(xpad360_btn[i], input_dev->keybit);
- } else {
- for (i = 0; xpad_btn[i] >= 0; i++)
- __set_bit(xpad_btn[i], input_dev->keybit);
- }
-
- if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
- for (i = 0; xpad_btn_pad[i] >= 0; i++)
- __set_bit(xpad_btn_pad[i], input_dev->keybit);
- } else {
- for (i = 0; xpad_abs_pad[i] >= 0; i++)
- xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
- }
-
- if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
- for (i = 0; xpad_btn_triggers[i] >= 0; i++)
- __set_bit(xpad_btn_triggers[i], input_dev->keybit);
- } else {
- for (i = 0; xpad_abs_triggers[i] >= 0; i++)
- xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
- }
-
error = xpad_init_output(intf, xpad);
if (error)
- goto fail3;
-
- error = xpad_init_ff(xpad);
- if (error)
- goto fail4;
-
- error = xpad_led_probe(xpad);
- if (error)
- goto fail5;
+ goto err_free_in_urb;
/* Xbox One controller has in/out endpoints swapped. */
ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0;
@@ -1211,118 +1492,120 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->irq_in->transfer_dma = xpad->idata_dma;
xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- error = input_register_device(xpad->dev);
- if (error)
- goto fail6;
-
usb_set_intfdata(intf, xpad);
if (xpad->xtype == XTYPE_XBOX360W) {
/*
- * Setup the message to set the LEDs on the
- * controller when it shows up
- */
- xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
- if (!xpad->bulk_out) {
- error = -ENOMEM;
- goto fail7;
- }
-
- xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
- if (!xpad->bdata) {
- error = -ENOMEM;
- goto fail8;
- }
-
- xpad->bdata[2] = 0x08;
- switch (intf->cur_altsetting->desc.bInterfaceNumber) {
- case 0:
- xpad->bdata[3] = 0x42;
- break;
- case 2:
- xpad->bdata[3] = 0x43;
- break;
- case 4:
- xpad->bdata[3] = 0x44;
- break;
- case 6:
- xpad->bdata[3] = 0x45;
- }
-
- ep_irq_in = &intf->cur_altsetting->endpoint[1].desc;
- if (usb_endpoint_is_bulk_out(ep_irq_in)) {
- usb_fill_bulk_urb(xpad->bulk_out, udev,
- usb_sndbulkpipe(udev,
- ep_irq_in->bEndpointAddress),
- xpad->bdata, XPAD_PKT_LEN,
- xpad_bulk_out, xpad);
- } else {
- usb_fill_int_urb(xpad->bulk_out, udev,
- usb_sndintpipe(udev,
- ep_irq_in->bEndpointAddress),
- xpad->bdata, XPAD_PKT_LEN,
- xpad_bulk_out, xpad, 0);
- }
-
- /*
* Submit the int URB immediately rather than waiting for open
* because we get status messages from the device whether
* or not any controllers are attached. In fact, it's
* exactly the message that a controller has arrived that
* we're waiting for.
*/
- xpad->irq_in->dev = xpad->udev;
- error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
+ error = xpad360w_start_input(xpad);
if (error)
- goto fail9;
+ goto err_deinit_output;
+ /*
+ * Wireless controllers require RESET_RESUME to work properly
+ * after suspend. Ideally this quirk should be in usb core
+ * quirk list, but we have too many vendors producing these
+ * controllers and we'd need to maintain 2 identical lists
+ * here in this driver and in usb core.
+ */
+ udev->quirks |= USB_QUIRK_RESET_RESUME;
+ } else {
+ error = xpad_init_input(xpad);
+ if (error)
+ goto err_deinit_output;
}
-
return 0;
- fail9: kfree(xpad->bdata);
- fail8: usb_free_urb(xpad->bulk_out);
- fail7: input_unregister_device(input_dev);
- input_dev = NULL;
- fail6: xpad_led_disconnect(xpad);
- fail5: if (input_dev)
- input_ff_destroy(input_dev);
- fail4: xpad_deinit_output(xpad);
- fail3: usb_free_urb(xpad->irq_in);
- fail2: usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
- fail1: input_free_device(input_dev);
+err_deinit_output:
+ xpad_deinit_output(xpad);
+err_free_in_urb:
+ usb_free_urb(xpad->irq_in);
+err_free_idata:
+ usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
+err_free_mem:
kfree(xpad);
return error;
-
}
static void xpad_disconnect(struct usb_interface *intf)
{
- struct usb_xpad *xpad = usb_get_intfdata (intf);
+ struct usb_xpad *xpad = usb_get_intfdata(intf);
- xpad_led_disconnect(xpad);
- input_unregister_device(xpad->dev);
- xpad_deinit_output(xpad);
+ if (xpad->xtype == XTYPE_XBOX360W)
+ xpad360w_stop_input(xpad);
- if (xpad->xtype == XTYPE_XBOX360W) {
- usb_kill_urb(xpad->bulk_out);
- usb_free_urb(xpad->bulk_out);
- usb_kill_urb(xpad->irq_in);
- }
+ xpad_deinit_input(xpad);
+
+ /*
+ * Now that both input device and LED device are gone we can
+ * stop output URB.
+ */
+ xpad_stop_output(xpad);
+
+ xpad_deinit_output(xpad);
usb_free_urb(xpad->irq_in);
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
xpad->idata, xpad->idata_dma);
- kfree(xpad->bdata);
kfree(xpad);
usb_set_intfdata(intf, NULL);
}
+static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_xpad *xpad = usb_get_intfdata(intf);
+ struct input_dev *input = xpad->dev;
+
+ if (xpad->xtype == XTYPE_XBOX360W) {
+ /*
+ * Wireless controllers always listen to input so
+ * they are notified when controller shows up
+ * or goes away.
+ */
+ xpad360w_stop_input(xpad);
+ } else {
+ mutex_lock(&input->mutex);
+ if (input->users)
+ xpad_stop_input(xpad);
+ mutex_unlock(&input->mutex);
+ }
+
+ xpad_stop_output(xpad);
+
+ return 0;
+}
+
+static int xpad_resume(struct usb_interface *intf)
+{
+ struct usb_xpad *xpad = usb_get_intfdata(intf);
+ struct input_dev *input = xpad->dev;
+ int retval = 0;
+
+ if (xpad->xtype == XTYPE_XBOX360W) {
+ retval = xpad360w_start_input(xpad);
+ } else {
+ mutex_lock(&input->mutex);
+ if (input->users)
+ retval = xpad_start_input(xpad);
+ mutex_unlock(&input->mutex);
+ }
+
+ return retval;
+}
+
static struct usb_driver xpad_driver = {
.name = "xpad",
.probe = xpad_probe,
.disconnect = xpad_disconnect,
+ .suspend = xpad_suspend,
+ .resume = xpad_resume,
+ .reset_resume = xpad_resume,
.id_table = xpad_table,
};