ALSA: usb-audio: replace hardcoded value with const
[pandora-kernel.git] / sound / usb / pcm.c
index 5c12a3f..f488a49 100644 (file)
@@ -46,6 +46,9 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
        int frame_diff;
        int est_delay;
 
+       if (!subs->last_delay)
+               return 0; /* short path */
+
        current_frame_number = usb_get_current_frame_number(subs->dev);
        /*
         * HCD implementations use different widths, use lower 8 bits.
@@ -75,7 +78,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
                return SNDRV_PCM_POS_XRUN;
        spin_lock(&subs->lock);
        hwptr_done = subs->hwptr_done;
-       substream->runtime->delay = snd_usb_pcm_delay(subs,
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               substream->runtime->delay = snd_usb_pcm_delay(subs,
                                                substream->runtime->rate);
        spin_unlock(&subs->lock);
        return hwptr_done / (substream->runtime->frame_bits >> 3);
@@ -173,11 +177,8 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
 {
        struct usb_device *dev = chip->dev;
        unsigned char data[1];
-       unsigned int ep;
        int err;
 
-       ep = get_endpoint(alts, 0)->bEndpointAddress;
-
        data[0] = 1;
        if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
                                   USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
@@ -214,7 +215,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
        }
 }
 
-static int start_endpoints(struct snd_usb_substream *subs, int can_sleep)
+static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep)
 {
        int err;
 
@@ -266,16 +267,18 @@ static int start_endpoints(struct snd_usb_substream *subs, int can_sleep)
        return 0;
 }
 
-static void stop_endpoints(struct snd_usb_substream *subs,
-                          int force, int can_sleep, int wait)
+static void stop_endpoints(struct snd_usb_substream *subs, bool wait)
 {
        if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags))
-               snd_usb_endpoint_stop(subs->sync_endpoint,
-                                     force, can_sleep, wait);
+               snd_usb_endpoint_stop(subs->sync_endpoint);
 
        if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags))
-               snd_usb_endpoint_stop(subs->data_endpoint,
-                                     force, can_sleep, wait);
+               snd_usb_endpoint_stop(subs->data_endpoint);
+
+       if (wait) {
+               snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint);
+               snd_usb_endpoint_sync_pending_stop(subs->data_endpoint);
+       }
 }
 
 static int deactivate_endpoints(struct snd_usb_substream *subs)
@@ -381,7 +384,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
                /* ... and check descriptor size before accessing bSynchAddress
                   because there is a version of the SB Audigy 2 NX firmware lacking
                   the audio fields in the endpoint descriptors */
-               if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 ||
+               if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC ||
                    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
                     get_endpoint(alts, 1)->bSynchAddress != 0 &&
                     !implicit_fb)) {
@@ -447,7 +450,7 @@ static int configure_endpoint(struct snd_usb_substream *subs)
        int ret;
 
        /* format changed */
-       stop_endpoints(subs, 0, 0, 0);
+       stop_endpoints(subs, true);
        ret = snd_usb_endpoint_set_params(subs->data_endpoint,
                                          subs->pcm_format,
                                          subs->channels,
@@ -459,7 +462,7 @@ static int configure_endpoint(struct snd_usb_substream *subs)
                return ret;
 
        if (subs->sync_endpoint)
-               ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+               ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
                                                  subs->pcm_format,
                                                  subs->channels,
                                                  subs->period_bytes,
@@ -533,7 +536,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
        subs->period_bytes = 0;
        down_read(&subs->stream->chip->shutdown_rwsem);
        if (!subs->stream->chip->shutdown) {
-               stop_endpoints(subs, 0, 1, 1);
+               stop_endpoints(subs, true);
                deactivate_endpoints(subs);
        }
        up_read(&subs->stream->chip->shutdown_rwsem);
@@ -608,7 +611,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
        /* for playback, submit the URBs now; otherwise, the first hwptr_done
         * updates for all URBs would happen at the same time when starting */
        if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
-               ret = start_endpoints(subs, 1);
+               ret = start_endpoints(subs, true);
 
  unlock:
        up_read(&subs->stream->chip->shutdown_rwsem);
@@ -1013,7 +1016,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
        struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
        struct snd_usb_substream *subs = &as->substream[direction];
 
-       stop_endpoints(subs, 0, 0, 0);
+       stop_endpoints(subs, true);
 
        if (!as->chip->shutdown && subs->interface >= 0) {
                usb_set_interface(subs->dev, subs->interface, 0);
@@ -1195,6 +1198,9 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
                return;
 
        spin_lock_irqsave(&subs->lock, flags);
+       if (!subs->last_delay)
+               goto out; /* short path */
+
        est_delay = snd_usb_pcm_delay(subs, runtime->rate);
        /* update delay with exact number of samples played */
        if (processed > subs->last_delay)
@@ -1212,6 +1218,15 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
                snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
                        est_delay, subs->last_delay);
 
+       if (!subs->running) {
+               /* update last_frame_number for delay counting here since
+                * prepare_playback_urb won't be called during pause
+                */
+               subs->last_frame_number =
+                       usb_get_current_frame_number(subs->dev) & 0xff;
+       }
+
+ out:
        spin_unlock_irqrestore(&subs->lock, flags);
 }
 
@@ -1248,12 +1263,13 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
                subs->running = 1;
                return 0;
        case SNDRV_PCM_TRIGGER_STOP:
-               stop_endpoints(subs, 0, 0, 0);
+               stop_endpoints(subs, false);
                subs->running = 0;
                return 0;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                subs->data_endpoint->prepare_data_urb = NULL;
-               subs->data_endpoint->retire_data_urb = NULL;
+               /* keep retire_data_urb for delay calculation */
+               subs->data_endpoint->retire_data_urb = retire_playback_urb;
                subs->running = 0;
                return 0;
        }
@@ -1269,7 +1285,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               err = start_endpoints(subs, 0);
+               err = start_endpoints(subs, false);
                if (err < 0)
                        return err;
 
@@ -1277,7 +1293,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream
                subs->running = 1;
                return 0;
        case SNDRV_PCM_TRIGGER_STOP:
-               stop_endpoints(subs, 0, 0, 0);
+               stop_endpoints(subs, false);
                subs->running = 0;
                return 0;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH: