3.18-stable review patch. If anyone has any objections, please let me know.
------------------
[ Upstream commit e3b651745a03810efffd7ebf2a9b5be65fb70ec3 ]
The pad_nr corresponds to the lit up LED on the controller. Therefore there should be no gaps when enumerating. Currently a LED is only re-assigned after a controller is re-connected 4 times.
This patch uses ida to track connected pads - this way we can re-assign freed up pad number immediately.
Consider the following case: 1. pad A is connected and gets pad_nr = 0 2. pad B is connected and gets pad_nr = 1 3. pad A is disconnected 4. pad A is connected again
using ida_simple_get() controller A now correctly gets pad_nr = 0 again.
Signed-off-by: Pavel Rojtberg rojtberg@gmail.com Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/input/joystick/xpad.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 60ebd78a49a6..a395980bb816 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -244,7 +244,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 */ @@ -347,7 +346,7 @@ struct usb_xpad {
int mapping; /* map d-pad to buttons or to axes */ int xtype; /* type of xbox device */ - unsigned long pad_nr; /* the order x360 pads were attached */ + int pad_nr; /* the order x360 pads were attached */ };
/* @@ -883,6 +882,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]; @@ -964,7 +966,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; @@ -976,9 +977,13 @@ static int xpad_led_probe(struct usb_xpad *xpad) if (!led) return -ENOMEM;
- xpad->pad_nr = 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->pad_nr); + snprintf(led->name, sizeof(led->name), "xpad%d", xpad->pad_nr); led->xpad = xpad;
led_cdev = &led->led_cdev; @@ -986,16 +991,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) @@ -1004,6 +1012,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); } } @@ -1013,7 +1022,6 @@ 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) { struct usb_xpad *xpad = input_get_drvdata(dev);