| From fb92dfbc2fd4f5c5ec05f52261ab8e808ce7572d Mon Sep 17 00:00:00 2001 |
| From: Cameron Gutman <aicommander@gmail.com> |
| Date: Tue, 3 Jan 2017 22:40:38 -0800 |
| Subject: Input: xpad - don't depend on endpoint order |
| |
| [ Upstream commit c01b5e7464f0cf20936d7467c7528163c4e2782d ] |
| |
| The order of endpoints is well defined on official Xbox pads, but |
| we have found at least one 3rd-party pad that doesn't follow the |
| standard ("Titanfall 2 Xbox One controller" 0e6f:0165). |
| |
| Fortunately, we get lucky with this specific pad because it uses |
| endpoint addresses that differ only by direction. We know that |
| there are other pads out where this is not true, so let's go |
| ahead and fix this. |
| |
| Signed-off-by: Cameron Gutman <aicommander@gmail.com> |
| Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/input/joystick/xpad.c | 35 +++++++++++++++++++++-------------- |
| 1 file changed, 21 insertions(+), 14 deletions(-) |
| |
| diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c |
| index d837900d609e..dd0503562b1c 100644 |
| --- a/drivers/input/joystick/xpad.c |
| +++ b/drivers/input/joystick/xpad.c |
| @@ -838,10 +838,9 @@ static void xpad_irq_out(struct urb *urb) |
| spin_unlock_irqrestore(&xpad->odata_lock, flags); |
| } |
| |
| -static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) |
| +static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad, |
| + struct usb_endpoint_descriptor *ep_irq_out) |
| { |
| - struct usb_endpoint_descriptor *ep_irq_out; |
| - int ep_irq_out_idx; |
| int error; |
| |
| if (xpad->xtype == XTYPE_UNKNOWN) |
| @@ -862,10 +861,6 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) |
| goto err_free_coherent; |
| } |
| |
| - /* Xbox One controller has in/out endpoints swapped. */ |
| - ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1; |
| - ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc; |
| - |
| usb_fill_int_urb(xpad->irq_out, xpad->udev, |
| usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress), |
| xpad->odata, XPAD_PKT_LEN, |
| @@ -1455,8 +1450,7 @@ 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 usb_endpoint_descriptor *ep_irq_in; |
| - int ep_irq_in_idx; |
| + struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out; |
| int i, error; |
| |
| if (intf->cur_altsetting->desc.bNumEndpoints != 2) |
| @@ -1526,13 +1520,26 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id |
| goto err_free_in_urb; |
| } |
| |
| - error = xpad_init_output(intf, xpad); |
| - if (error) |
| + ep_irq_in = ep_irq_out = NULL; |
| + |
| + for (i = 0; i < 2; i++) { |
| + struct usb_endpoint_descriptor *ep = |
| + &intf->cur_altsetting->endpoint[i].desc; |
| + |
| + if (usb_endpoint_dir_in(ep)) |
| + ep_irq_in = ep; |
| + else |
| + ep_irq_out = ep; |
| + } |
| + |
| + if (!ep_irq_in || !ep_irq_out) { |
| + error = -ENODEV; |
| goto err_free_in_urb; |
| + } |
| |
| - /* Xbox One controller has in/out endpoints swapped. */ |
| - ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0; |
| - ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc; |
| + error = xpad_init_output(intf, xpad, ep_irq_out); |
| + if (error) |
| + goto err_free_in_urb; |
| |
| usb_fill_int_urb(xpad->irq_in, udev, |
| usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), |
| -- |
| 2.17.1 |
| |