Merge branch 'linus' into perf/urgent
[cascardo/linux.git] / sound / usb / endpoint.c
index 93e970f..b9ba0fc 100644 (file)
@@ -33,7 +33,6 @@
 #include "pcm.h"
 #include "quirks.h"
 
-#define EP_FLAG_ACTIVATED      0
 #define EP_FLAG_RUNNING                1
 #define EP_FLAG_STOPPING       2
 
@@ -426,9 +425,9 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
        list_for_each_entry(ep, &chip->ep_list, list) {
                if (ep->ep_num == ep_num &&
                    ep->iface == alts->desc.bInterfaceNumber &&
-                   ep->alt_idx == alts->desc.bAlternateSetting) {
+                   ep->altsetting == alts->desc.bAlternateSetting) {
                        snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n",
-                                       ep_num, ep->iface, ep->alt_idx, ep);
+                                       ep_num, ep->iface, ep->altsetting, ep);
                        goto __exit_unlock;
                }
        }
@@ -447,7 +446,7 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
        ep->type = type;
        ep->ep_num = ep_num;
        ep->iface = alts->desc.bInterfaceNumber;
-       ep->alt_idx = alts->desc.bAlternateSetting;
+       ep->altsetting = alts->desc.bAlternateSetting;
        INIT_LIST_HEAD(&ep->ready_playback_urbs);
        ep_num &= USB_ENDPOINT_NUMBER_MASK;
 
@@ -574,11 +573,14 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
                              snd_pcm_format_t pcm_format,
                              unsigned int channels,
                              unsigned int period_bytes,
+                             unsigned int frames_per_period,
+                             unsigned int periods_per_buffer,
                              struct audioformat *fmt,
                              struct snd_usb_endpoint *sync_ep)
 {
-       unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
-       int is_playback = usb_pipeout(ep->pipe);
+       unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb;
+       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;
 
        if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) {
@@ -611,58 +613,67 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
        else
                ep->curpacksize = maxsize;
 
-       if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
+       if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) {
                packs_per_ms = 8 >> ep->datainterval;
-       else
-               packs_per_ms = 1;
-
-       if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
-               urb_packs = max(ep->chip->nrpacks, 1);
-               urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
+               max_packs_per_urb = MAX_PACKS_HS;
        } else {
-               urb_packs = 1;
+               packs_per_ms = 1;
+               max_packs_per_urb = MAX_PACKS;
        }
+       if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
+               max_packs_per_urb = min(max_packs_per_urb,
+                                       1U << sync_ep->syncinterval);
+       max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval);
 
-       urb_packs *= packs_per_ms;
+       /*
+        * Capture endpoints need to use small URBs because there's no way
+        * to tell in advance where the next period will end, and we don't
+        * want the next URB to complete much after the period ends.
+        *
+        * Playback endpoints with implicit sync much use the same parameters
+        * as their corresponding capture endpoint.
+        */
+       if (usb_pipein(ep->pipe) ||
+                       snd_usb_endpoint_implicit_feedback_sink(ep)) {
 
-       if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
-               urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
+               /* make capture URBs <= 1 ms and smaller than a period */
+               urb_packs = min(max_packs_per_urb, packs_per_ms);
+               while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
+                       urb_packs >>= 1;
+               ep->nurbs = MAX_URBS;
 
-       /* decide how many packets to be used */
-       if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
-               unsigned int minsize, maxpacks;
+       /*
+        * Playback endpoints without implicit sync are adjusted so that
+        * a period fits as evenly as possible in the smallest number of
+        * URBs.  The total number of URBs is adjusted to the size of the
+        * ALSA buffer, subject to the MAX_URBS and MAX_QUEUE limits.
+        */
+       } else {
                /* determine how small a packet can be */
-               minsize = (ep->freqn >> (16 - ep->datainterval))
-                         * (frame_bits >> 3);
+               minsize = (ep->freqn >> (16 - ep->datainterval)) *
+                               (frame_bits >> 3);
                /* with sync from device, assume it can be 12% lower */
                if (sync_ep)
                        minsize -= minsize >> 3;
                minsize = max(minsize, 1u);
-               total_packs = (period_bytes + minsize - 1) / minsize;
-               /* we need at least two URBs for queueing */
-               if (total_packs < 2) {
-                       total_packs = 2;
-               } else {
-                       /* and we don't want too long a queue either */
-                       maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
-                       total_packs = min(total_packs, maxpacks);
-               }
-       } else {
-               while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
-                       urb_packs >>= 1;
-               total_packs = MAX_URBS * urb_packs;
-       }
 
-       ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
-       if (ep->nurbs > MAX_URBS) {
-               /* too much... */
-               ep->nurbs = MAX_URBS;
-               total_packs = MAX_URBS * urb_packs;
-       } else if (ep->nurbs < 2) {
-               /* too little - we need at least two packets
-                * to ensure contiguous playback/capture
-                */
-               ep->nurbs = 2;
+               /* how many packets will contain an entire ALSA period? */
+               max_packs_per_period = DIV_ROUND_UP(period_bytes, minsize);
+
+               /* how many URBs will contain a period? */
+               urbs_per_period = DIV_ROUND_UP(max_packs_per_period,
+                               max_packs_per_urb);
+               /* how many packets are needed in each URB? */
+               urb_packs = DIV_ROUND_UP(max_packs_per_period, urbs_per_period);
+
+               /* limit the number of frames in a single URB */
+               ep->max_urb_frames = DIV_ROUND_UP(frames_per_period,
+                                       urbs_per_period);
+
+               /* try to use enough URBs to contain an entire ALSA buffer */
+               max_urbs = min((unsigned) MAX_URBS,
+                               MAX_QUEUE * packs_per_ms / urb_packs);
+               ep->nurbs = min(max_urbs, urbs_per_period * periods_per_buffer);
        }
 
        /* allocate and initialize data urbs */
@@ -670,8 +681,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
                struct snd_urb_ctx *u = &ep->urb[i];
                u->index = i;
                u->ep = ep;
-               u->packets = (i + 1) * total_packs / ep->nurbs
-                       - i * total_packs / ep->nurbs;
+               u->packets = urb_packs;
                u->buffer_size = maxsize * u->packets;
 
                if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
@@ -703,8 +713,7 @@ out_of_memory:
 /*
  * configure a sync endpoint
  */
-static int sync_ep_set_params(struct snd_usb_endpoint *ep,
-                             struct audioformat *fmt)
+static int sync_ep_set_params(struct snd_usb_endpoint *ep)
 {
        int i;
 
@@ -748,6 +757,8 @@ out_of_memory:
  * @pcm_format: the audio fomat.
  * @channels: the number of audio channels.
  * @period_bytes: the number of bytes in one alsa period.
+ * @period_frames: the number of frames in one alsa period.
+ * @buffer_periods: the number of periods in one alsa buffer.
  * @rate: the frame rate.
  * @fmt: the USB audio format information
  * @sync_ep: the sync endpoint to use, if any
@@ -760,6 +771,8 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
                                snd_pcm_format_t pcm_format,
                                unsigned int channels,
                                unsigned int period_bytes,
+                               unsigned int period_frames,
+                               unsigned int buffer_periods,
                                unsigned int rate,
                                struct audioformat *fmt,
                                struct snd_usb_endpoint *sync_ep)
@@ -793,10 +806,11 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
        switch (ep->type) {
        case  SND_USB_ENDPOINT_TYPE_DATA:
                err = data_ep_set_params(ep, pcm_format, channels,
-                                        period_bytes, fmt, sync_ep);
+                                        period_bytes, period_frames,
+                                        buffer_periods, fmt, sync_ep);
                break;
        case  SND_USB_ENDPOINT_TYPE_SYNC:
-               err = sync_ep_set_params(ep, fmt);
+               err = sync_ep_set_params(ep);
                break;
        default:
                err = -EINVAL;
@@ -931,28 +945,21 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
  *
  * @ep: the endpoint to deactivate
  *
- * If the endpoint is not currently in use, this functions will select the
- * alternate interface setting 0 for the interface of this endpoint.
+ * If the endpoint is not currently in use, this functions will
+ * deactivate its associated URBs.
  *
  * In case of any active users, this functions does nothing.
- *
- * Returns an error if usb_set_interface() failed, 0 in all other
- * cases.
  */
-int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
+void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
 {
        if (!ep)
-               return -EINVAL;
-
-       deactivate_urbs(ep, true);
-       wait_clear_urbs(ep);
+               return;
 
        if (ep->use_count != 0)
-               return 0;
-
-       clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
+               return;
 
-       return 0;
+       deactivate_urbs(ep, true);
+       wait_clear_urbs(ep);
 }
 
 /**