]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - sound/usb/pcm.c
Merge remote-tracking branch 'sound-current/for-linus'
[karo-tx-linux.git] / sound / usb / pcm.c
index cdac5179db3f349f8ac61e010a8a9ff05c2e93ae..9245f52d43bdecfeb710b6cfc6ae99b3202aae90 100644 (file)
@@ -1383,6 +1383,56 @@ static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs,
                        subs->hwptr_done++;
                }
        }
+       if (subs->hwptr_done >= runtime->buffer_size * stride)
+               subs->hwptr_done -= runtime->buffer_size * stride;
+}
+
+static void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb,
+                       int offset, int stride, unsigned int bytes)
+{
+       struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+
+       if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
+               /* err, the transferred area goes over buffer boundary. */
+               unsigned int bytes1 =
+                       runtime->buffer_size * stride - subs->hwptr_done;
+               memcpy(urb->transfer_buffer + offset,
+                      runtime->dma_area + subs->hwptr_done, bytes1);
+               memcpy(urb->transfer_buffer + offset + bytes1,
+                      runtime->dma_area, bytes - bytes1);
+       } else {
+               memcpy(urb->transfer_buffer + offset,
+                      runtime->dma_area + subs->hwptr_done, bytes);
+       }
+       subs->hwptr_done += bytes;
+       if (subs->hwptr_done >= runtime->buffer_size * stride)
+               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,
@@ -1460,27 +1510,17 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
                }
 
                subs->hwptr_done += bytes;
+               if (subs->hwptr_done >= runtime->buffer_size * stride)
+                       subs->hwptr_done -= runtime->buffer_size * stride;
        } else {
                /* usual PCM */
-               if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
-                       /* err, the transferred area goes over buffer boundary. */
-                       unsigned int bytes1 =
-                               runtime->buffer_size * stride - subs->hwptr_done;
-                       memcpy(urb->transfer_buffer,
-                              runtime->dma_area + subs->hwptr_done, bytes1);
-                       memcpy(urb->transfer_buffer + bytes1,
-                              runtime->dma_area, bytes - bytes1);
-               } else {
-                       memcpy(urb->transfer_buffer,
-                              runtime->dma_area + subs->hwptr_done, bytes);
-               }
-
-               subs->hwptr_done += 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 */
        }
 
-       if (subs->hwptr_done >= runtime->buffer_size * stride)
-               subs->hwptr_done -= runtime->buffer_size * stride;
-
        /* update delay with exact number of samples queued */
        runtime->delay = subs->last_delay;
        runtime->delay += frames;