Re: [PATCH v2 0/1] Input: xpad - Implement wireless controller LED setting and fix connect time LED setting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 10 Dec 2012 05:24:02 -0800
Chris Moeller <kode54@xxxxxxxxx> wrote:

> On Mon, 10 Dec 2012 04:43:54 -0800
> Chris Moeller <kode54@xxxxxxxxx> wrote:
> 
> > On Mon, 10 Dec 2012 02:58:25 -0800
> > Chris Moeller <kode54@xxxxxxxxx> wrote:
> > 
> > > On Sun, 2 Dec 2012 23:43:18 -0800
> > > Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx> wrote:
> > > 
> > > > On Fri, Nov 30, 2012 at 08:13:29PM -0800, Chris Moeller wrote:
> > > > > On Fri, 30 Nov 2012 14:30:23 -0800
> > > > > Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx> wrote:
> > > > > 
> > > > > > Hi Chris,
> > > > > > 
> > > > > > On Friday, November 30, 2012 01:54:06 PM Chris Moeller
> > > > > > wrote:
> > > > > > > I've submitted versions of this with prior patch sets, and
> > > > > > > this part was never accepted, possibly because it depended
> > > > > > > on other patches to work, or possibly because it wasn't so
> > > > > > > cleanly organized. This time, I've split the LED setting
> > > > > > > command off into its own static function, then call that
> > > > > > > on controller connect and optionally on LED setting
> > > > > > > commands. The static function does not include any
> > > > > > > locking, because locking inside the function which
> > > > > > > receives the incoming packets deadlocks the driver, and
> > > > > > > does not appear to be necessary anyway.
> > > > > > > 
> > > > > > > It also removes all traces of the original bulk out
> > > > > > > function which was designed for the purpose of setting
> > > > > > > the LED status on connect, as I found that it actually
> > > > > > > does not work at all. It appears to try to send the data,
> > > > > > > but nothing actually happens to the controller LEDs.
> > > > > > 
> > > > > > Attached is a reply I sent to on 7/4/11 to which you
> > > > > > unfortunately never responded. The issue is that of force
> > > > > > feedback (rumble) and LED share the same URB then access to
> > > > > > that URB should be arbitrated. The attached message
> > > > > > contains a patch that attempts to implement that
> > > > > > arbitration, could you please try it out and see what
> > > > > > changes are needed to make it work?
> > > > > > 
> > > > > > Thanks.
> > > > > > 
> > > > > 
> > > > > So sorry I missed your reply. That's what I get for filtering
> > > > > the mailing list messages past my inbox, then never following
> > > > > up on my filter/folder set for replies to my own messages. I
> > > > > recall you mentioned that potential race condition when I
> > > > > first submitted, but I forgot to do anything about it. I'm
> > > > > glad at least one of us has our stuff together. It seems to
> > > > > work just fine, but there may be a force feedback issue with
> > > > > the following test program, where it leaves the effect playing
> > > > > indefinitely after the program terminates, and then the
> > > > > controller itself ceases to respond until the module is
> > > > > removed and reloaded.
> > > > 
> > > > Just to confirm, you see this problem only with the patch being
> > > > discussed and do not see it without it, right?
> > > > 
> > > 
> > > Yeah, the problem only happens with this patch. Here's a silly
> > > mess which fixes it. If you can think of a better way to handle
> > > pending commands outside of the IRQ, be my guest. The problem
> > > seems to be that it doesn't like sending further commands from
> > > inside the output irq callback, so further commands are not sent,
> > > and the spinlock is left locked or something. So it seems that it
> > > needs to be such that the callback merely signals when the packet
> > > has completed sending, and the actual queue must be handled
> > > outside of the irq, and somehow kindly wait for the irq to
> > > complete for each command. Unless, you know, there's some other
> > > way to queue up multiple commands without waiting on each one to
> > > complete. I know bulk out doesn't work for the LED setting
> > > command, at least. Anyway, here goes.
> > 
> > Disregard this patch, it locks up frequently. I'm working on
> > something else instead.
> 
> Okay, this one seems to work. LED setting doesn't lock up like the old
> mutex regulated LED setting mode, and I can successfully power off and
> on the controller while that previously posted test program is still
> running on the event device, without the LED setting clobbering the
> rumble packets, and vice versa.
> 
> ---
> diff -urpN a/drivers/input/joystick/xpad.c
> b/drivers/input/joystick/xpad.c ---
> a/drivers/input/joystick/xpad.c	2012-12-10 03:59:14.407669714
> -0800 +++ b/drivers/input/joystick/xpad.c	2012-12-10
> 05:13:22.835479280 -0800 @@ -259,19 +259,17 @@ struct usb_xpad
> { struct usb_interface *intf;	/* usb interface */ 
>  	int pad_present;
> +	int interface_number;
>  
>  	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;
> -
>  #if defined(CONFIG_JOYSTICK_XPAD_FF) ||
> defined(CONFIG_JOYSTICK_XPAD_LEDS) struct urb
> *irq_out;		/* urb for interrupt out report */ unsigned
> char *odata;		/* output data */ dma_addr_t odata_dma;
> -	struct mutex odata_mutex;
> +	spinlock_t odata_lock;
>  #endif
>  
>  #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
> @@ -441,13 +439,15 @@ static void xpad360_process_packet(struc
>   *
>   */
>  
> +static void xpad_send_led_command(struct usb_xpad *xpad, int
> command); +
>  static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd,
> unsigned char *data) {
>  	/* Presence change */
>  	if (data[0] & 0x08) {
>  		if (data[1] & 0x80) {
>  			xpad->pad_present = 1;
> -			usb_submit_urb(xpad->bulk_out, GFP_ATOMIC);
> +			xpad_send_led_command(xpad, 16);
>  		} else
>  			xpad->pad_present = 0;
>  	}
> @@ -502,29 +502,6 @@ exit:
>  			__func__, retval);
>  }
>  
> -static void xpad_bulk_out(struct urb *urb)
> -{
> -	struct usb_xpad *xpad = urb->context;
> -	struct device *dev = &xpad->intf->dev;
> -
> -	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 defined(CONFIG_JOYSTICK_XPAD_FF) ||
> defined(CONFIG_JOYSTICK_XPAD_LEDS) static void xpad_irq_out(struct
> urb *urb) {
>  	struct usb_xpad *xpad = urb->context;
> @@ -574,7 +551,7 @@ static int xpad_init_output(struct usb_i
>  		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) {
> @@ -610,15 +587,12 @@ static void xpad_deinit_output(struct us
>  				xpad->odata, xpad->odata_dma);
>  	}
>  }
> -#else
> -static int xpad_init_output(struct usb_interface *intf, struct
> usb_xpad *xpad) { return 0; } -static void xpad_deinit_output(struct
> usb_xpad *xpad) {} -static void xpad_stop_output(struct usb_xpad
> *xpad) {} -#endif
>  
>  #ifdef CONFIG_JOYSTICK_XPAD_FF
>  static int xpad_play_effect(struct input_dev *dev, void *data,
> struct ff_effect *effect) {
> +	int retval;
> +	unsigned long flags;
>  	struct usb_xpad *xpad = input_get_drvdata(dev);
>  
>  	if (effect->type == FF_RUMBLE) {
> @@ -628,6 +602,7 @@ static int xpad_play_effect(struct input
>  		switch (xpad->xtype) {
>  
>  		case XTYPE_XBOX:
> +			spin_lock_irqsave(&xpad->odata_lock, flags);
>  			xpad->odata[0] = 0x00;
>  			xpad->odata[1] = 0x06;
>  			xpad->odata[2] = 0x00;
> @@ -636,9 +611,13 @@ static int xpad_play_effect(struct input
>  			xpad->odata[5] = weak / 256;	/* right
> actuator */ xpad->irq_out->transfer_buffer_length = 6;
>  
> -			return usb_submit_urb(xpad->irq_out,
> GFP_ATOMIC);
> +			retval = usb_submit_urb(xpad->irq_out,
> GFP_ATOMIC);
> +			spin_unlock_irqrestore(&xpad->odata_lock,
> flags); +
> +			return retval;
>  
>  		case XTYPE_XBOX360:
> +			spin_lock_irqsave(&xpad->odata_lock, flags);
>  			xpad->odata[0] = 0x00;
>  			xpad->odata[1] = 0x08;
>  			xpad->odata[2] = 0x00;
> @@ -649,9 +628,13 @@ static int xpad_play_effect(struct input
>  			xpad->odata[7] = 0x00;
>  			xpad->irq_out->transfer_buffer_length = 8;
>  
> -			return usb_submit_urb(xpad->irq_out,
> GFP_ATOMIC);
> +			retval = usb_submit_urb(xpad->irq_out,
> GFP_ATOMIC);
> +			spin_unlock_irqrestore(&xpad->odata_lock,
> flags); +
> +			return retval;
>  
>  		case XTYPE_XBOX360W:
> +			spin_lock_irqsave(&xpad->odata_lock, flags);
>  			xpad->odata[0] = 0x00;
>  			xpad->odata[1] = 0x01;
>  			xpad->odata[2] = 0x0F;
> @@ -666,7 +649,10 @@ static int xpad_play_effect(struct input
>  			xpad->odata[11] = 0x00;
>  			xpad->irq_out->transfer_buffer_length = 12;
>  
> -			return usb_submit_urb(xpad->irq_out,
> GFP_ATOMIC);
> +			retval = usb_submit_urb(xpad->irq_out,
> GFP_ATOMIC);
> +			spin_unlock_irqrestore(&xpad->odata_lock,
> flags); +
> +			return retval;
>  
>  		default:
>  			dev_dbg(&xpad->dev->dev,
> @@ -693,6 +679,43 @@ static int xpad_init_ff(struct usb_xpad
>  static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
>  #endif
>  
> +static void xpad_send_led_command(struct usb_xpad *xpad, int command)
> +{
> +	unsigned long flags;
> +	if (xpad->xtype == XTYPE_XBOX360) {
> +		if (command >= 0 && command < 14) {
> +			spin_lock_irqsave(&xpad->odata_lock, flags);
> +			xpad->odata[0] = 0x01;
> +			xpad->odata[1] = 0x03;
> +			xpad->odata[2] = command;
> +			xpad->irq_out->transfer_buffer_length = 3;
> +			usb_submit_urb(xpad->irq_out, GFP_KERNEL);
> +			spin_unlock_irqrestore(&xpad->odata_lock,
> flags);
> +		}
> +	} else if (xpad->xtype == XTYPE_XBOX360W) {
> +		if (command >= 0 && command < 17) {
> +			if (command == 16)
> +				command = 0x02 +
> xpad->interface_number;
> +			spin_lock_irqsave(&xpad->odata_lock, flags);
> +			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;
> +			usb_submit_urb(xpad->irq_out, GFP_KERNEL);
> +			spin_unlock_irqrestore(&xpad->odata_lock,
> flags);
> +		}
> +	}
> +}
> +
>  #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
>  #include <linux/leds.h>
>  
> @@ -702,19 +725,6 @@ struct xpad_led {
>  	struct usb_xpad *xpad;
>  };
>  
> -static void xpad_send_led_command(struct usb_xpad *xpad, int command)
> -{
> -	if (command >= 0 && command < 14) {
> -		mutex_lock(&xpad->odata_mutex);
> -		xpad->odata[0] = 0x01;
> -		xpad->odata[1] = 0x03;
> -		xpad->odata[2] = command;
> -		xpad->irq_out->transfer_buffer_length = 3;
> -		usb_submit_urb(xpad->irq_out, GFP_KERNEL);
> -		mutex_unlock(&xpad->odata_mutex);
> -	}
> -}
> -
>  static void xpad_led_set(struct led_classdev *led_cdev,
>  			 enum led_brightness value)
>  {
> @@ -732,7 +742,7 @@ static int xpad_led_probe(struct usb_xpa
>  	struct led_classdev *led_cdev;
>  	int error;
>  
> -	if (xpad->xtype != XTYPE_XBOX360)
> +	if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype !=
> XTYPE_XBOX360W) return 0;
>  
>  	xpad->led = led = kzalloc(sizeof(struct xpad_led),
> GFP_KERNEL); @@ -758,7 +768,8 @@ static int xpad_led_probe(struct
> usb_xpa /*
>  	 * Light up the segment corresponding to controller number
>  	 */
> -	xpad_send_led_command(xpad, (led_no % 4) + 2);
> +	if (xpad->xtype == XTYPE_XBOX360)
> +		xpad_send_led_command(xpad, (led_no % 4) + 2);
>  
>  	return 0;
>  }
> @@ -960,42 +971,7 @@ static int xpad_probe(struct usb_interfa
>  	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;
> -		usb_fill_bulk_urb(xpad->bulk_out, udev,
> -				usb_sndbulkpipe(udev,
> ep_irq_in->bEndpointAddress),
> -				xpad->bdata, XPAD_PKT_LEN,
> xpad_bulk_out, xpad); -
> +		xpad->interface_number =
> intf->cur_altsetting->desc.bInterfaceNumber / 2; /*
>  		 * Submit the int URB immediately rather than
> waiting for open
>  		 * because we get status messages from the device
> whether @@ -1006,13 +982,11 @@ static int xpad_probe(struct
> usb_interfa xpad->irq_in->dev = xpad->udev;
>  		error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
>  		if (error)
> -			goto fail9;
> +			goto fail7;
>  	}
>  
>  	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);
> @@ -1036,8 +1010,6 @@ static void xpad_disconnect(struct usb_i
>  	xpad_deinit_output(xpad);
>  
>  	if (xpad->xtype == XTYPE_XBOX360W) {
> -		usb_kill_urb(xpad->bulk_out);
> -		usb_free_urb(xpad->bulk_out);
>  		usb_kill_urb(xpad->irq_in);
>  	}
>  
> @@ -1045,9 +1017,6 @@ static void xpad_disconnect(struct usb_i
>  	usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
>  			xpad->idata, xpad->idata_dma);
>  
> -	kfree(xpad->bdata);
> -	kfree(xpad);
> -
>  	usb_set_intfdata(intf, NULL);
>  }
>  

Has anything been done regarding this patch yet? I'm not seeing a whole
lot of activity on this front.
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux