diff --git a/packages/linux/patches/4.4-rc6/linux-063-xpad-fix_xbox360_wireless.patch b/packages/linux/patches/4.4-rc6/linux-063-xpad-fix_xbox360_wireless.patch index c76ec3895e..a1768287a4 100644 --- a/packages/linux/patches/4.4-rc6/linux-063-xpad-fix_xbox360_wireless.patch +++ b/packages/linux/patches/4.4-rc6/linux-063-xpad-fix_xbox360_wireless.patch @@ -1,6 +1,6 @@ -From f55be5f4acd492f9dd9979e04678fbc1a7e658e0 Mon Sep 17 00:00:00 2001 +From b120facaae7e40a34564c10c1b1341734b2d2247 Mon Sep 17 00:00:00 2001 From: Matt DeVillier -Date: Thu, 17 Dec 2015 15:01:37 -0600 +Date: Sun, 20 Dec 2015 03:15:47 -0600 Subject: [PATCH 1/1] linux/drivers/input/joystick/xpad: fixes for xbox360/one controllers merged from https://github.com/paroj/xpad @@ -14,14 +14,23 @@ merged from https://github.com/paroj/xpad Signed-off-by: Matt DeVillier --- - drivers/input/joystick/xpad.c | 240 ++++++++++++++++++++++++++++++++---------- - 1 file changed, 184 insertions(+), 56 deletions(-) + drivers/input/joystick/xpad.c | 474 +++++++++++++++++++++++++++++------------- + 1 file changed, 328 insertions(+), 146 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c -index fd4100d..301a77a 100644 +index fd4100d..f8452af 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c -@@ -126,6 +126,7 @@ static const struct xpad_device { +@@ -76,6 +76,8 @@ + */ + + #include ++#include ++#include + #include + #include + #include +@@ -126,6 +128,7 @@ static const struct xpad_device { { 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 }, @@ -29,7 +38,7 @@ index fd4100d..301a77a 100644 { 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 }, -@@ -298,6 +299,7 @@ static struct usb_device_id xpad_table[] = { +@@ -298,6 +301,7 @@ static struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ @@ -37,30 +46,55 @@ index fd4100d..301a77a 100644 XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ -@@ -329,9 +331,16 @@ struct usb_xpad { +@@ -317,21 +321,41 @@ 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 *irq_out; /* urb for interrupt out report */ -+ int irq_out_active; /* we must not use an active URB */ ++ bool irq_out_active; /* we must not use an active URB */ unsigned char *odata; /* output data */ ++ u8 odata_serial; /* serial number for xbox one protocol */ dma_addr_t odata_dma; - struct mutex odata_mutex; + spinlock_t odata_lock; + -+ unsigned char rum_odata[XPAD_PKT_LEN]; /* cache for rumble data */ -+ unsigned char led_odata[XPAD_PKT_LEN]; /* cache for led data */ -+ unsigned pend_rum; /* length of cached rumble data */ -+ unsigned pend_led; /* length of cached led data */ -+ int force_led; /* force send led cache next */ ++ struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS]; ++ int last_out_packet; #if defined(CONFIG_JOYSTICK_XPAD_LEDS) struct xpad_led *led; -@@ -343,8 +352,13 @@ struct usb_xpad { +@@ -343,8 +367,12 @@ struct usb_xpad { int xtype; /* type of xbox device */ 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 */ -+ unsigned char odata_serial; /* serial number for xbox one protocol */ }; +static int xpad_init_input(struct usb_xpad *xpad); @@ -69,11 +103,25 @@ index fd4100d..301a77a 100644 /* * xpad_process_packet * -@@ -497,6 +511,22 @@ static void xpad360_process_packet(struct usb_xpad *xpad, +@@ -424,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 xpad_identify_controller(struct usb_xpad *xpad); +-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) */ +@@ -495,7 +521,30 @@ static void xpad360_process_packet(struct usb_xpad *xpad, + input_sync(dev); + } -+static void presence_work_function(struct work_struct *work) +-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; @@ -82,21 +130,30 @@ index fd4100d..301a77a 100644 + 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\n"); ++ 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 - * -@@ -513,21 +543,20 @@ static void xpad_identify_controller(struct usb_xpad *xpad); +@@ -513,24 +562,28 @@ static void xpad_identify_controller(struct usb_xpad *xpad); */ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) { -+ int presence; ++ struct input_dev *dev; ++ bool present; + /* Presence change */ if (data[0] & 0x08) { @@ -109,80 +166,146 @@ index fd4100d..301a77a 100644 - xpad_identify_controller(xpad); - } else - xpad->pad_present = 0; -+ presence = (data[1] & 0x80) != 0; ++ present = (data[1] & 0x80) != 0; + -+ if (xpad->pad_present != presence) { -+ xpad->pad_present = presence; ++ if (xpad->pad_present != present) { ++ xpad->pad_present = present; + schedule_work(&xpad->work); + } } /* Valid pad data */ - if (!(data[1] & 0x1)) -+ if (!(data[1] & 0x1) || data[1] == 0xf) ++ if (data[1] != 0x1) return; - xpad360_process_packet(xpad, cmd, &data[4]); -@@ -683,13 +712,35 @@ static void xpad_irq_out(struct urb *urb) +- 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(); + } + + /* +@@ -659,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); +@@ -678,18 +731,71 @@ exit: + __func__, retval); + } + ++/* Callers must hold xpad->odata_lock spinlock */ ++static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad) ++{ ++ 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; ++ } ++ } ++ ++ 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)) { ++ 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); ++ 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 retval, status; ++ int status = urb->status; ++ int error; + unsigned long flags; - status = urb->status; +- status = urb->status; ++ spin_lock_irqsave(&xpad->odata_lock, flags); switch (status) { case 0: /* success */ - return; -+ if (!xpad->pend_led && !xpad->pend_rum) { -+ xpad->irq_out_active = 0; -+ return; -+ } -+ -+ spin_lock_irqsave(&xpad->odata_lock, flags); -+ -+ if (xpad->pend_led && (!xpad->pend_rum || xpad->force_led)) { -+ xpad->irq_out->transfer_buffer_length = xpad->pend_led; -+ memcpy(xpad->odata, xpad->led_odata, xpad->pend_led); -+ xpad->pend_led = 0; -+ xpad->force_led = 0; -+ dev_dbg(dev, "%s - sending pending led\n", __func__); -+ break; -+ } -+ -+ xpad->irq_out->transfer_buffer_length = xpad->pend_rum; -+ memcpy(xpad->odata, xpad->rum_odata, xpad->pend_rum); -+ xpad->pend_rum = 0; -+ xpad->force_led = 1; -+ dev_dbg(dev, "%s - sending pending rumble\n", __func__); ++ xpad->out_packets[xpad->last_out_packet].pending = false; ++ xpad->irq_out_active = xpad_prepare_next_out_packet(xpad); + break; case -ECONNRESET: case -ENOENT: -@@ -697,16 +748,19 @@ static void xpad_irq_out(struct urb *urb) +@@ -697,26 +803,32 @@ 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); -+ xpad->irq_out_active = 0; - return; +- return; ++ xpad->irq_out_active = false; ++ break; default: dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); - goto exit; -+ -+ spin_lock_irqsave(&xpad->odata_lock, flags); + break; } -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); +- 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) { ++ error = usb_submit_urb(urb, GFP_ATOMIC); ++ if (error) { ++ dev_err(dev, ++ "%s - usb_submit_urb failed with result %d\n", ++ __func__, error); ++ xpad->irq_out_active = false; ++ } ++ } ++ + spin_unlock_irqrestore(&xpad->odata_lock, flags); - if (retval) - dev_err(dev, "%s - usb_submit_urb failed with result %d\n", - __func__, retval); -@@ -716,7 +770,6 @@ 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; int ep_irq_out_idx; @@ -190,7 +313,7 @@ index fd4100d..301a77a 100644 if (xpad->xtype == XTYPE_UNKNOWN) return 0; -@@ -724,16 +777,18 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) +@@ -724,16 +836,15 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN, GFP_KERNEL, &xpad->odata_dma); if (!xpad->odata) { @@ -201,9 +324,6 @@ index fd4100d..301a77a 100644 - mutex_init(&xpad->odata_mutex); + spin_lock_init(&xpad->odata_lock); -+ xpad->pend_led = 0; -+ xpad->pend_rum = 0; -+ xpad->force_led = 0; xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_out) { @@ -214,7 +334,7 @@ index fd4100d..301a77a 100644 } /* Xbox One controller has in/out endpoints swapped. */ -@@ -748,9 +803,6 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) +@@ -748,9 +859,6 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; return 0; @@ -224,47 +344,94 @@ index fd4100d..301a77a 100644 } static void xpad_stop_output(struct usb_xpad *xpad) -@@ -771,8 +823,9 @@ static void xpad_deinit_output(struct usb_xpad *xpad) +@@ -770,27 +878,58 @@ static void xpad_deinit_output(struct usb_xpad *xpad) + static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) { - int retval; ++ struct xpad_output_packet *packet = ++ &xpad->out_packets[XPAD_OUT_CMD_IDX]; + unsigned long flags; + int retval; - mutex_lock(&xpad->odata_mutex); +- +- xpad->odata[0] = 0x08; +- xpad->odata[1] = 0x00; +- xpad->odata[2] = 0x0F; +- xpad->odata[3] = 0xC0; +- 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; + 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; - xpad->odata[0] = 0x08; - xpad->odata[1] = 0x00; -@@ -788,9 +841,16 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) - xpad->odata[11] = 0x00; - xpad->irq_out->transfer_buffer_length = 12; - -- retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL); -+ if (!xpad->irq_out_active) { -+ retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL); -+ xpad->irq_out_active = 1; -+ } else { -+ dev_dbg(&xpad->dev->dev, "%s - dropped, irq_out is active\n", -+ __func__); -+ retval = -EIO; -+ } + retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL); - mutex_unlock(&xpad->odata_mutex); + spin_unlock_irqrestore(&xpad->odata_lock, flags); return retval; } -@@ -801,6 +861,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect +@@ -799,8 +938,11 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) + 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) return 0; -@@ -808,6 +871,8 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect +@@ -808,69 +950,81 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect strong = effect->u.rumble.strong_magnitude; weak = effect->u.rumble.weak_magnitude; @@ -272,65 +439,130 @@ index fd4100d..301a77a 100644 + switch (xpad->xtype) { case XTYPE_XBOX: - xpad->odata[0] = 0x00; -@@ -850,27 +915,48 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect - case XTYPE_XBOXONE: - xpad->odata[0] = 0x09; /* activate rumble */ - xpad->odata[1] = 0x08; +- xpad->odata[0] = 0x00; +- xpad->odata[1] = 0x06; - xpad->odata[2] = 0x00; -+ xpad->odata[2] = xpad->odata_serial++; - 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[3] = strong / 256; /* left actuator */ +- xpad->odata[4] = 0x00; +- xpad->odata[5] = weak / 256; /* right actuator */ +- xpad->irq_out->transfer_buffer_length = 6; ++ 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: +- 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; ++ 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: +- 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; ++ 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: +- 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[8] = strong / 512; /* left actuator */ -+ xpad->odata[9] = weak / 512; /* right actuator */ - xpad->odata[10] = 0x80; /* length of pulse */ - xpad->odata[11] = 0x00; /* stop period of pulse */ +- xpad->odata[10] = 0x80; /* length of pulse */ +- xpad->odata[11] = 0x00; /* stop period of pulse */ - xpad->irq_out->transfer_buffer_length = 12; -+ xpad->odata[12] = 0x00; -+ xpad->irq_out->transfer_buffer_length = 13; ++ 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: -+ spin_unlock_irqrestore(&xpad->odata_lock, flags); dev_dbg(&xpad->dev->dev, "%s - rumble command sent to unsupported xpad type: %d\n", __func__, xpad->xtype); - return -EINVAL; +- return -EINVAL; ++ retval = -EINVAL; ++ goto out; } - return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); -+ if (!xpad->irq_out_active) { -+ retval = usb_submit_urb(xpad->irq_out, GFP_ATOMIC); -+ xpad->irq_out_active = 1; -+ } else { -+ retval = 0; -+ -+ if (xpad->pend_rum) { -+ dev_dbg(&xpad->dev->dev, -+ "%s - overwriting pending\n", __func__); -+ -+ retval = -EIO; -+ } -+ -+ xpad->pend_rum = xpad->irq_out->transfer_buffer_length; -+ memcpy(xpad->rum_odata, xpad->odata, xpad->pend_rum); -+ } ++ 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) -@@ -921,9 +1007,11 @@ struct xpad_led { +@@ -921,36 +1075,44 @@ 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; @@ -340,30 +572,57 @@ index fd4100d..301a77a 100644 switch (xpad->xtype) { case XTYPE_XBOX360: -@@ -949,8 +1037,20 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command) +- 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); -+ if (!xpad->irq_out_active) { -+ usb_submit_urb(xpad->irq_out, GFP_KERNEL); -+ xpad->irq_out_active = 1; -+ } else { -+ if (xpad->pend_led) { -+ dev_dbg(&xpad->dev->dev, -+ "%s - overwriting pending\n", __func__); -+ } -+ -+ xpad->pend_led = xpad->irq_out->transfer_buffer_length; -+ memcpy(xpad->led_odata, xpad->odata, xpad->pend_led); -+ } ++ xpad_try_sending_next_out_packet(xpad); + + spin_unlock_irqrestore(&xpad->odata_lock, flags); } /* -@@ -1001,14 +1101,7 @@ static int xpad_led_probe(struct usb_xpad *xpad) +@@ -1001,14 +1163,7 @@ static int xpad_led_probe(struct usb_xpad *xpad) if (error) goto err_free_id; @@ -379,45 +638,53 @@ index fd4100d..301a77a 100644 return 0; -@@ -1039,6 +1132,9 @@ static void xpad_identify_controller(struct usb_xpad *xpad) { } - static int xpad_open(struct input_dev *dev) - { - struct usb_xpad *xpad = input_get_drvdata(dev); -+ int retval; -+ -+ unsigned long flags; - - /* URB was submitted in probe */ - if (xpad->xtype == XTYPE_XBOX360W) -@@ -1049,11 +1145,17 @@ static int xpad_open(struct input_dev *dev) +@@ -1048,13 +1203,8 @@ static int xpad_open(struct input_dev *dev) + if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) return -EIO; - if (xpad->xtype == XTYPE_XBOXONE) { -+ spin_lock_irqsave(&xpad->odata_lock, flags); - /* Xbox one controller needs to be initialized. */ - xpad->odata[0] = 0x05; - xpad->odata[1] = 0x20; +- 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); -+ xpad->odata[2] = xpad->odata_serial++; /* packet serial */ -+ xpad->odata[3] = 0x01; /* rumble bit enable? */ -+ xpad->odata[4] = 0x00; -+ xpad->irq_out->transfer_buffer_length = 5; -+ retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL); -+ spin_unlock_irqrestore(&xpad->odata_lock, flags); -+ return retval; - } +- } ++ if (xpad->xtype == XTYPE_XBOXONE) ++ return xpad_start_xbox_one(xpad); return 0; -@@ -1241,6 +1343,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id + } +@@ -1097,8 +1247,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) + + static void xpad_deinit_input(struct usb_xpad *xpad) + { +- xpad_led_disconnect(xpad); +- input_unregister_device(xpad->dev); ++ 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) +@@ -1181,6 +1334,7 @@ static int xpad_init_input(struct usb_xpad *xpad) + if (error) + goto err_disconnect_led; + ++ xpad->input_created = true; + return 0; + + err_disconnect_led: +@@ -1241,6 +1395,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->mapping = xpad_device[i].mapping; xpad->xtype = xpad_device[i].xtype; xpad->name = xpad_device[i].name; -+ INIT_WORK(&xpad->work, presence_work_function); ++ INIT_WORK(&xpad->work, xpad_presence_work); if (xpad->xtype == XTYPE_UNKNOWN) { if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { -@@ -1277,10 +1380,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id +@@ -1277,10 +1432,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id usb_set_intfdata(intf, xpad); @@ -428,7 +695,7 @@ index fd4100d..301a77a 100644 if (xpad->xtype == XTYPE_XBOX360W) { /* * Submit the int URB immediately rather than waiting for open -@@ -1292,7 +1391,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id +@@ -1292,7 +1443,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->irq_in->dev = xpad->udev; error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); if (error) @@ -437,12 +704,11 @@ index fd4100d..301a77a 100644 /* * Send presence packet. -@@ -1304,13 +1403,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id +@@ -1304,13 +1455,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id error = xpad_inquiry_pad_presence(xpad); if (error) goto err_kill_in_urb; + } else { -+ xpad->pad_present = 1; + error = xpad_init_input(xpad); + if (error) + goto err_deinit_output; @@ -456,7 +722,7 @@ index fd4100d..301a77a 100644 err_deinit_output: xpad_deinit_output(xpad); err_free_in_urb: -@@ -1323,17 +1425,27 @@ err_free_mem: +@@ -1323,30 +1476,59 @@ err_free_mem: } @@ -478,18 +744,23 @@ index fd4100d..301a77a 100644 + +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_stop_communication(xpad); -+ xpad_deinit_output(xpad); ++ if (xpad->xtype == XTYPE_XBOX360W) ++ usb_kill_urb(xpad->irq_in); + -+ if (xpad->pad_present) -+ xpad_deinit_input(xpad); ++ cancel_work_sync(&xpad->work); ++ ++ xpad_deinit_input(xpad); + usb_free_urb(xpad->irq_in); usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); -@@ -1343,10 +1455,26 @@ static void xpad_disconnect(struct usb_interface *intf) + ++ xpad_deinit_output(xpad); ++ + kfree(xpad); + usb_set_intfdata(intf, NULL); }