aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorDaniel Mack <zonque@gmail.com>2012-09-04 04:23:07 -0400
committerTakashi Iwai <tiwai@suse.de>2012-09-04 05:31:14 -0400
commit2b58fd5b3193fd3af3d15114d95706087d25a7fe (patch)
tree929c51bd48ee1637f963fa520bf31eee04927861 /sound
parentc05fce586d4da2dfe0309bef3795a8586e967bc3 (diff)
ALSA: snd-usb: Add quirks for Playback Designs devices
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@gmail.com> Reported-and-tested-by: Andreas Koch <andreas@akdesigninc.com> Supported-by: Demian Martin <demianm_1@yahoo.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/endpoint.c8
-rw-r--r--sound/usb/helper.c5
-rw-r--r--sound/usb/quirks.c24
-rw-r--r--sound/usb/quirks.h10
5 files changed, 49 insertions, 0 deletions
diff --git a/sound/usb/card.h b/sound/usb/card.h
index bcb5267a02e8..23b6f23bd36a 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -92,6 +92,8 @@ struct snd_usb_endpoint {
92 unsigned char silence_value; 92 unsigned char silence_value;
93 unsigned int stride; 93 unsigned int stride;
94 int iface, alt_idx; 94 int iface, alt_idx;
95 int skip_packets; /* quirks for devices to ignore the first n packets
96 in a stream */
95 97
96 spinlock_t lock; 98 spinlock_t lock;
97 struct list_head list; 99 struct list_head list;
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index c41181202688..94b08a6087a3 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -31,6 +31,7 @@
31#include "card.h" 31#include "card.h"
32#include "endpoint.h" 32#include "endpoint.h"
33#include "pcm.h" 33#include "pcm.h"
34#include "quirks.h"
34 35
35#define EP_FLAG_ACTIVATED 0 36#define EP_FLAG_ACTIVATED 0
36#define EP_FLAG_RUNNING 1 37#define EP_FLAG_RUNNING 1
@@ -170,6 +171,11 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,
170{ 171{
171 struct urb *urb = urb_ctx->urb; 172 struct urb *urb = urb_ctx->urb;
172 173
174 if (unlikely(ep->skip_packets > 0)) {
175 ep->skip_packets--;
176 return;
177 }
178
173 if (ep->sync_slave) 179 if (ep->sync_slave)
174 snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); 180 snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
175 181
@@ -825,6 +831,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
825 ep->unlink_mask = 0; 831 ep->unlink_mask = 0;
826 ep->phase = 0; 832 ep->phase = 0;
827 833
834 snd_usb_endpoint_start_quirk(ep);
835
828 /* 836 /*
829 * If this endpoint has a data endpoint as implicit feedback source, 837 * If this endpoint has a data endpoint as implicit feedback source,
830 * don't start the urbs here. Instead, mark them all as available, 838 * 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 9eed8f40b179..c1db28f874c2 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -21,6 +21,7 @@
21 21
22#include "usbaudio.h" 22#include "usbaudio.h"
23#include "helper.h" 23#include "helper.h"
24#include "quirks.h"
24 25
25/* 26/*
26 * combine bytes and get an integer value 27 * 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,
97 memcpy(data, buf, size); 98 memcpy(data, buf, size);
98 kfree(buf); 99 kfree(buf);
99 } 100 }
101
102 snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype,
103 value, index, data, size);
104
100 return err; 105 return err;
101} 106}
102 107
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 27817266867a..0f58b4b6d702 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,
761 } 761 }
762} 762}
763 763
764void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
765{
766 /*
767 * "Playback Design" products send bogus feedback data at the start
768 * of the stream. Ignore them.
769 */
770 if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) &&
771 ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
772 ep->skip_packets = 4;
773}
774
775void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
776 __u8 request, __u8 requesttype, __u16 value,
777 __u16 index, void *data, __u16 size)
778{
779 /*
780 * "Playback Design" products need a 20ms delay after each
781 * class compliant request
782 */
783 if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) &&
784 (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
785 mdelay(20);
786}
787
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 03e5e94098cd..0ca9e91067a6 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -1,6 +1,10 @@
1#ifndef __USBAUDIO_QUIRKS_H 1#ifndef __USBAUDIO_QUIRKS_H
2#define __USBAUDIO_QUIRKS_H 2#define __USBAUDIO_QUIRKS_H
3 3
4struct audioformat;
5struct snd_usb_endpoint;
6struct snd_usb_substream;
7
4int snd_usb_create_quirk(struct snd_usb_audio *chip, 8int snd_usb_create_quirk(struct snd_usb_audio *chip,
5 struct usb_interface *iface, 9 struct usb_interface *iface,
6 struct usb_driver *driver, 10 struct usb_driver *driver,
@@ -20,4 +24,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
20int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, 24int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
21 struct audioformat *fp); 25 struct audioformat *fp);
22 26
27void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep);
28
29void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
30 __u8 request, __u8 requesttype, __u16 value,
31 __u16 index, void *data, __u16 size);
32
23#endif /* __USBAUDIO_QUIRKS_H */ 33#endif /* __USBAUDIO_QUIRKS_H */