BACKPORT: ALSA: usb-audio: Move configuration to prepare.
authorDylan Reid <dgreid@chromium.org>
Tue, 18 Sep 2012 21:33:41 +0000 (14:33 -0700)
committerGerrit <chrome-bot@google.com>
Thu, 27 Sep 2012 21:31:03 +0000 (14:31 -0700)
Move interface and endpoint configuration from hw_params to prepare
callback.  During system suspend/resume when the USB device power isn't
cycled the interface and endpoint configuration need to be set before
audio playback can continue.  Resume involves another call to prepare
but not to hw_params, moving it here allows a playing stream to continue
after resume.

This is modified from the version going upstream as the endpoint rework
in 3.5 has changed all of these interfaces.  Same functionality however.

BUG=chrome-os-parnter:12822
TEST=suspend/resume while playing audio to USB speakers.

(Backported from 61a709504b079110cd5b12ea9a4590ffea687a5c)
Change-Id: Ie70d8c4c74014b877b2b6244c5accb81b6fb8d5c
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/33583
Reviewed-by: Chih-Chung Chang <chihchung@chromium.org>
sound/usb/card.h
sound/usb/pcm.c

index da5fa1a..e75e291 100644 (file)
@@ -54,6 +54,8 @@ struct snd_usb_substream {
        int interface;  /* current interface */
        int endpoint;   /* assigned endpoint */
        struct audioformat *cur_audiofmt;       /* current audioformat pointer (for hw_params callback) */
+       snd_pcm_format_t pcm_format;    /* current audio format (for hw_params callback) */
+       unsigned int channels;          /* current number of channels (for hw_params callback) */
        unsigned int cur_rate;          /* current rate (for hw_params callback) */
        unsigned int period_bytes;      /* current period bytes (for hw_params callback) */
        unsigned int altset_idx;     /* USB data format: index of alternate setting */
index 0eed611..b4171e7 100644 (file)
@@ -353,7 +353,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
        struct snd_usb_substream *subs = substream->runtime->private_data;
        struct audioformat *fmt;
        unsigned int channels, rate, format;
-       int ret, changed;
+       int ret;
 
        ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
                                               params_buffer_bytes(hw_params));
@@ -370,34 +370,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       changed = subs->cur_audiofmt != fmt ||
-               subs->period_bytes != params_period_bytes(hw_params) ||
-               subs->cur_rate != rate;
        if ((ret = set_format(subs, fmt)) < 0)
                return ret;
 
-       if (subs->cur_rate != rate) {
-               struct usb_host_interface *alts;
-               struct usb_interface *iface;
-               iface = usb_ifnum_to_if(subs->dev, fmt->iface);
-               alts = &iface->altsetting[fmt->altset_idx];
-               ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface, alts, fmt, rate);
-               if (ret < 0)
-                       return ret;
-               subs->cur_rate = rate;
-       }
-
-       if (changed) {
-               mutex_lock(&subs->stream->chip->shutdown_mutex);
-               /* format changed */
-               snd_usb_release_substream_urbs(subs, 0);
-               /* influenced: period_bytes, channels, rate, format, */
-               ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params),
-                                                 params_rate(hw_params),
-                                                 snd_pcm_format_physical_width(params_format(hw_params)) *
-                                                       params_channels(hw_params));
-               mutex_unlock(&subs->stream->chip->shutdown_mutex);
-       }
+       subs->cur_rate = rate;
+       subs->pcm_format = format;
+       subs->channels = channels;
+       subs->period_bytes = params_period_bytes(hw_params);
 
        return ret;
 }
@@ -429,12 +408,38 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_usb_substream *subs = runtime->private_data;
+       struct usb_host_interface *alts;
+       struct usb_interface *iface;
+       int ret;
 
        if (! subs->cur_audiofmt) {
                snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
                return -ENXIO;
        }
 
+       ret = set_format(subs, subs->cur_audiofmt);
+       if (ret < 0)
+               return ret;
+
+       iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface);
+       alts = &iface->altsetting[subs->cur_audiofmt->altset_idx];
+       ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface,
+                                      alts, subs->cur_audiofmt,
+                                      subs->cur_rate);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&subs->stream->chip->shutdown_mutex);
+       /* format changed */
+       snd_usb_release_substream_urbs(subs, 0);
+       /* influenced: period_bytes, channels, rate, format, */
+       ret = snd_usb_init_substream_urbs(subs, subs->period_bytes,
+                       subs->cur_rate,
+                       snd_pcm_format_physical_width(subs->pcm_format) *
+                       subs->channels);
+       mutex_unlock(&subs->stream->chip->shutdown_mutex);
+
+
        /* some unit conversions in runtime */
        subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
        subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);