@@ -329,9 +329,10 @@ struct usb_xpad {
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 */
unsigned char *odata; /* output data */
dma_addr_t odata_dma;
- struct mutex odata_mutex;
+ spinlock_t odata_lock;
#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct xpad_led *led;
@@ -708,6 +709,7 @@ static void xpad_irq_out(struct urb *urb)
switch (status) {
case 0:
/* success */
+ xpad->irq_out_active = 0;
return;
case -ECONNRESET:
@@ -716,6 +718,7 @@ 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;
default:
@@ -747,7 +750,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) {
@@ -790,8 +793,9 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
{
int retval;
+ unsigned long flags;
- mutex_lock(&xpad->odata_mutex);
+ spin_lock_irqsave(&xpad->odata_lock, flags);
xpad->odata[0] = 0x08;
xpad->odata[1] = 0x00;
@@ -807,9 +811,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;
+ }
- mutex_unlock(&xpad->odata_mutex);
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
return retval;
}
@@ -820,6 +831,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
struct usb_xpad *xpad = input_get_drvdata(dev);
__u16 strong;
__u16 weak;
+ int retval;
+
+ unsigned long flags;
if (effect->type != FF_RUMBLE)
return 0;
@@ -827,6 +841,8 @@ 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;
+ spin_lock_irqsave(&xpad->odata_lock, flags);
+
switch (xpad->xtype) {
case XTYPE_XBOX:
xpad->odata[0] = 0x00;
@@ -883,13 +899,25 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
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 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 = -EIO;
+ dev_dbg(&xpad->dev->dev, "%s - dropped, irq_out is active\n",
+ __func__);
+ }
+
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
+
+ return retval;
}
static int xpad_init_ff(struct usb_xpad *xpad)
@@ -940,9 +968,11 @@ struct xpad_led {
*/
static void xpad_send_led_command(struct usb_xpad *xpad, int command)
{
+ unsigned long flags;
+
command %= 16;
- mutex_lock(&xpad->odata_mutex);
+ spin_lock_irqsave(&xpad->odata_lock, flags);
switch (xpad->xtype) {
case XTYPE_XBOX360:
@@ -968,8 +998,14 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
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
+ dev_dbg(&xpad->dev->dev, "%s - dropped, irq_out is active\n",
+ __func__);
+
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
}
/*
@@ -1051,6 +1087,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)
@@ -1061,11 +1100,14 @@ static int xpad_open(struct input_dev *dev)
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;
xpad->irq_out->transfer_buffer_length = 2;
- return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
+ return retval;
}
return 0;