]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - sound/usb/endpoint.c
Merge remote-tracking branch 'kgdb/kgdb-next'
[karo-tx-linux.git] / sound / usb / endpoint.c
index e6f71894ecdc950117776d2ef9e2cc4df4661904..7b1cb365ffab74d6028206adb8012226da963bac 100644 (file)
@@ -183,13 +183,53 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,
                ep->retire_data_urb(ep->data_subs, urb);
 }
 
+static void prepare_silent_urb(struct snd_usb_endpoint *ep,
+                              struct snd_urb_ctx *ctx)
+{
+       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])
+                       counts = ctx->packet_size[i];
+               else
+                       counts = snd_usb_endpoint_next_packet_size(ep);
+
+               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 + ctx->packets * extra;
+}
+
 /*
  * Prepare a PLAYBACK urb for submission to the bus.
  */
 static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
                                 struct snd_urb_ctx *ctx)
 {
-       int i;
        struct urb *urb = ctx->urb;
        unsigned char *cp = urb->transfer_buffer;
 
@@ -201,24 +241,7 @@ static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
                        ep->prepare_data_urb(ep->data_subs, urb);
                } else {
                        /* no data provider, so send silence */
-                       unsigned int offs = 0;
-                       for (i = 0; i < ctx->packets; ++i) {
-                               int counts;
-
-                               if (ctx->packet_size[i])
-                                       counts = ctx->packet_size[i];
-                               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;
-                               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);
+                       prepare_silent_urb(ep, ctx);
                }
                break;
 
@@ -594,6 +617,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
        unsigned int max_packs_per_period, urbs_per_period, urb_packs;
        unsigned int max_urbs, i;
        int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
+       int tx_length_quirk = (ep->chip->tx_length_quirk &&
+                              usb_pipeout(ep->pipe));
 
        if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) {
                /*
@@ -610,13 +635,34 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
 
        /* assume max. frequency is 25% higher than nominal */
        ep->freqmax = ep->freqn + (ep->freqn >> 2);
-       maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
-                               >> (16 - ep->datainterval);
+       /* Round up freqmax to nearest integer in order to calculate maximum
+        * packet size, which must represent a whole number of frames.
+        * This is accomplished by adding 0x0.ffff before converting the
+        * Q16.16 format into integer.
+        * In order to accurately calculate the maximum packet size when
+        * the data interval is more than 1 (i.e. ep->datainterval > 0),
+        * multiply by the data interval prior to rounding. For instance,
+        * a freqmax of 41 kHz will result in a max packet size of 6 (5.125)
+        * frames with a data interval of 1, but 11 (10.25) frames with a
+        * data interval of 2.
+        * (ep->freqmax << ep->datainterval overflows at 8.192 MHz for the
+        * maximum datainterval value of 3, at USB full speed, higher for
+        * USB high speed, noting that ep->freqmax is in units of
+        * frames per packet in Q16.16 format.)
+        */
+       maxsize = (((ep->freqmax << ep->datainterval) + 0xffff) >> 16) *
+                        (frame_bits >> 3);
+       if (tx_length_quirk)
+               maxsize += sizeof(__le32); /* Space for length descriptor */
        /* but wMaxPacketSize might reduce this */
        if (ep->maxpacksize && ep->maxpacksize < maxsize) {
                /* whatever fits into a max. size packet */
-               maxsize = ep->maxpacksize;
-               ep->freqmax = (maxsize / (frame_bits >> 3))
+               unsigned int data_maxsize = maxsize = ep->maxpacksize;
+
+               if (tx_length_quirk)
+                       /* Need to remove the length descriptor to calc freq */
+                       data_maxsize -= sizeof(__le32);
+               ep->freqmax = (data_maxsize / (frame_bits >> 3))
                                << (16 - ep->datainterval);
        }