summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/usb/card.h1
-rw-r--r--sound/usb/endpoint.c25
-rw-r--r--sound/usb/pcm.c32
-rw-r--r--sound/usb/quirks-table.h7
-rw-r--r--sound/usb/quirks.c3
-rw-r--r--sound/usb/stream.c1
-rw-r--r--sound/usb/usbaudio.h1
7 files changed, 61 insertions, 9 deletions
diff --git a/sound/usb/card.h b/sound/usb/card.h
index ef580b43f1e3..71778ca4b26a 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -122,6 +122,7 @@ struct snd_usb_substream {
unsigned int buffer_periods; /* current periods per buffer */
unsigned int altset_idx; /* USB data format: index of alternate setting */
unsigned int txfr_quirk:1; /* allow sub-frame alignment */
+ unsigned int tx_length_quirk:1; /* add length specifier to transfers */
unsigned int fmt_type; /* USB audio format type (1-3) */
unsigned int pkt_offset_adj; /* Bytes to drop from beginning of packets (for non-compliant devices) */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 825a06ce83a9..0cc64bd4d0a4 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -188,9 +188,17 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
{
struct urb *urb = ctx->urb;
unsigned int offs = 0;
+ unsigned int extra = 0;
+ __le32 packet_length;
int i;
+ /* For tx_length_quirk, put packet length at start of packet */
+ if (ep->chip->tx_length_quirk)
+ extra = sizeof(packet_length);
+
for (i = 0; i < ctx->packets; ++i) {
+ unsigned int offset;
+ unsigned int length;
int counts;
if (ctx->packet_size[i])
@@ -198,15 +206,22 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
else
counts = snd_usb_endpoint_next_packet_size(ep);
- urb->iso_frame_desc[i].offset = offs * ep->stride;
- urb->iso_frame_desc[i].length = counts * ep->stride;
+ length = counts * ep->stride; /* number of silent bytes */
+ offset = offs * ep->stride + extra * i;
+ urb->iso_frame_desc[i].offset = offset;
+ urb->iso_frame_desc[i].length = length + extra;
+ if (extra) {
+ packet_length = cpu_to_le32(length);
+ memcpy(urb->transfer_buffer + offset,
+ &packet_length, sizeof(packet_length));
+ }
+ memset(urb->transfer_buffer + offset + extra,
+ ep->silence_value, length);
offs += counts;
}
urb->number_of_packets = ctx->packets;
- urb->transfer_buffer_length = offs * ep->stride;
- memset(urb->transfer_buffer, ep->silence_value,
- offs * ep->stride);
+ urb->transfer_buffer_length = offs * ep->stride + ctx->packets * extra;
}
/*
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index e3c5bc0df69d..9245f52d43bd 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1409,6 +1409,32 @@ static void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb,
subs->hwptr_done -= runtime->buffer_size * stride;
}
+static unsigned int copy_to_urb_quirk(struct snd_usb_substream *subs,
+ struct urb *urb, int stride,
+ unsigned int bytes)
+{
+ __le32 packet_length;
+ int i;
+
+ /* Put __le32 length descriptor at start of each packet. */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned int length = urb->iso_frame_desc[i].length;
+ unsigned int offset = urb->iso_frame_desc[i].offset;
+
+ packet_length = cpu_to_le32(length);
+ offset += i * sizeof(packet_length);
+ urb->iso_frame_desc[i].offset = offset;
+ urb->iso_frame_desc[i].length += sizeof(packet_length);
+ memcpy(urb->transfer_buffer + offset,
+ &packet_length, sizeof(packet_length));
+ copy_to_urb(subs, urb, offset + sizeof(packet_length),
+ stride, length);
+ }
+ /* Adjust transfer size accordingly. */
+ bytes += urb->number_of_packets * sizeof(packet_length);
+ return bytes;
+}
+
static void prepare_playback_urb(struct snd_usb_substream *subs,
struct urb *urb)
{
@@ -1488,7 +1514,11 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
subs->hwptr_done -= runtime->buffer_size * stride;
} else {
/* usual PCM */
- copy_to_urb(subs, urb, 0, stride, bytes);
+ if (!subs->tx_length_quirk)
+ copy_to_urb(subs, urb, 0, stride, bytes);
+ else
+ bytes = copy_to_urb_quirk(subs, urb, stride, bytes);
+ /* bytes is now amount of outgoing data */
}
/* update delay with exact number of samples queued */
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 99de06100395..4d3848ce4cff 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3193,8 +3193,9 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
* ZOOM R16/24 in audio interface mode.
* Mixer descriptors are garbage, further quirks will be needed
* to make any of it functional, thus disabled for now.
- * Playback stream appears to start and run fine but no sound
- * is produced, so also disabled for now.
+ * Playback requires an extra four byte LE length indicator
+ * at the start of each isochronous packet. This quirk is
+ * enabled in create_standard_audio_quirk().
*/
USB_DEVICE(0x1686, 0x00dd),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
@@ -3209,7 +3210,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
{
/* Playback */
.ifnum = 1,
- .type = QUIRK_IGNORE_INTERFACE,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE,
},
{
/* Capture */
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 00ebc0ca008e..4897ea171194 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -115,6 +115,9 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
struct usb_interface_descriptor *altsd;
int err;
+ if (chip->usb_id == USB_ID(0x1686, 0x00dd)) /* Zoom R16/24 */
+ chip->tx_length_quirk = 1;
+
alts = &iface->altsetting[0];
altsd = get_iface_desc(alts);
err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 970086015cde..8ee14f2365e7 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -92,6 +92,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
subs->direction = stream;
subs->dev = as->chip->dev;
subs->txfr_quirk = as->chip->txfr_quirk;
+ subs->tx_length_quirk = as->chip->tx_length_quirk;
subs->speed = snd_usb_get_speed(subs->dev);
subs->pkt_offset_adj = 0;
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 33a176437e2e..15a12715bd05 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -43,6 +43,7 @@ struct snd_usb_audio {
atomic_t usage_count;
wait_queue_head_t shutdown_wait;
unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
+ unsigned int tx_length_quirk:1; /* Put length specifier in transfers */
int num_interfaces;
int num_suspended_intf;