[alsa-devel] [PATCH] ALSA: snd-usb: Add quirks for Playback Designs devices

Takashi Iwai tiwai at suse.de
Tue Sep 4 11:32:14 CEST 2012


At Tue,  4 Sep 2012 10:23:07 +0200,
Daniel Mack wrote:
> 
> Playback Designs' USB devices have some hardware limitations on their
> USB interface. In particular:
> 
>  - They need a 20ms delay after each class compliant request as the
>    hardware ACKs the USB packets before the device is actually ready
>    for the next command. Sending data immediately will result in buffer
>    overflows in the hardware.
>  - The devices send bogus feedback data at the start of each stream
>    which confuse the feedback format auto-detection.
> 
> This patch introduces a new quirks hook that is called after each
> control packet and which adds a delay for all devices that match
> Playback Designs' USB VID for now.
> 
> In addition, it adds a counter to snd_usb_endpoint to drop received
> packets on the floor. Another new quirks function that is called once
> an endpoint is started initializes that counter for these devices on
> their sync endpoint.
> 
> Signed-off-by: Daniel Mack <zonque at gmail.com>
> Reported-and-tested-by: Andreas Koch <andreas at akdesigninc.com>
> Supported-by: Demian Martin <demianm_1 at yahoo.com>

Thanks, applied.


Takashi


> ---
>  sound/usb/card.h     |  2 ++
>  sound/usb/endpoint.c |  8 ++++++++
>  sound/usb/helper.c   |  5 +++++
>  sound/usb/quirks.c   | 24 ++++++++++++++++++++++++
>  sound/usb/quirks.h   | 10 ++++++++++
>  5 files changed, 49 insertions(+)
> 
> diff --git a/sound/usb/card.h b/sound/usb/card.h
> index 2b9ffff..d9d2b5a 100644
> --- a/sound/usb/card.h
> +++ b/sound/usb/card.h
> @@ -92,6 +92,8 @@ struct snd_usb_endpoint {
>  	unsigned char silence_value;
>  	unsigned int stride;
>  	int iface, alt_idx;
> +	int skip_packets;		/* quirks for devices to ignore the first n packets
> +					   in a stream */
>  
>  	spinlock_t lock;
>  	struct list_head list;
> diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
> index d6e2bb4..a83a18d 100644
> --- a/sound/usb/endpoint.c
> +++ b/sound/usb/endpoint.c
> @@ -31,6 +31,7 @@
>  #include "card.h"
>  #include "endpoint.h"
>  #include "pcm.h"
> +#include "quirks.h"
>  
>  #define EP_FLAG_ACTIVATED	0
>  #define EP_FLAG_RUNNING		1
> @@ -170,6 +171,11 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,
>  {
>  	struct urb *urb = urb_ctx->urb;
>  
> +	if (unlikely(ep->skip_packets > 0)) {
> +		ep->skip_packets--;
> +		return;
> +	}
> +
>  	if (ep->sync_slave)
>  		snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
>  
> @@ -822,6 +828,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)
>  	ep->unlink_mask = 0;
>  	ep->phase = 0;
>  
> +	snd_usb_endpoint_start_quirk(ep);
> +
>  	/*
>  	 * If this endpoint has a data endpoint as implicit feedback source,
>  	 * don't start the urbs here. Instead, mark them all as available,
> diff --git a/sound/usb/helper.c b/sound/usb/helper.c
> index 9eed8f4..c1db28f 100644
> --- a/sound/usb/helper.c
> +++ b/sound/usb/helper.c
> @@ -21,6 +21,7 @@
>  
>  #include "usbaudio.h"
>  #include "helper.h"
> +#include "quirks.h"
>  
>  /*
>   * combine bytes and get an integer value
> @@ -97,6 +98,10 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
>  		memcpy(data, buf, size);
>  		kfree(buf);
>  	}
> +
> +	snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype,
> +			      value, index, data, size);
> +
>  	return err;
>  }
>  
> diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
> index 2781726..1eaacf1 100644
> --- a/sound/usb/quirks.c
> +++ b/sound/usb/quirks.c
> @@ -761,3 +761,27 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
>  	}
>  }
>  
> +void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
> +{
> +	/*
> +	 * "Playback Design" products send bogus feedback data at the start
> +	 * of the stream. Ignore them.
> +	 */
> +	if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) &&
> +	    ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
> +		ep->skip_packets = 4;
> +}
> +
> +void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
> +			   __u8 request, __u8 requesttype, __u16 value,
> +			   __u16 index, void *data, __u16 size)
> +{
> +	/*
> +	 * "Playback Design" products need a 20ms delay after each
> +	 * class compliant request
> +	 */
> +	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) &&
> +	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
> +			mdelay(20);
> +}
> +
> diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
> index 03e5e94..0ca9e91 100644
> --- a/sound/usb/quirks.h
> +++ b/sound/usb/quirks.h
> @@ -1,6 +1,10 @@
>  #ifndef __USBAUDIO_QUIRKS_H
>  #define __USBAUDIO_QUIRKS_H
>  
> +struct audioformat;
> +struct snd_usb_endpoint;
> +struct snd_usb_substream;
> +
>  int snd_usb_create_quirk(struct snd_usb_audio *chip,
>  			 struct usb_interface *iface,
>  			 struct usb_driver *driver,
> @@ -20,4 +24,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
>  int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
>  				 struct audioformat *fp);
>  
> +void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep);
> +
> +void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
> +			   __u8 request, __u8 requesttype, __u16 value,
> +			   __u16 index, void *data, __u16 size);
> +
>  #endif /* __USBAUDIO_QUIRKS_H */
> -- 
> 1.7.11.4
> 


More information about the Alsa-devel mailing list