diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 05efd4835000..a7d3405cd572 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -42,7 +42,6 @@ struct snd_usb_clock_ref { unsigned char clock; atomic_t locked; int rate; - bool need_setup; struct list_head list; }; @@ -768,8 +767,7 @@ bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, * The endpoint needs to be closed via snd_usb_endpoint_close() later. * * Note that this function doesn't configure the endpoint. The substream - * needs to set it up later via snd_usb_endpoint_set_params() and - * snd_usb_endpoint_prepare(). + * needs to set it up later via snd_usb_endpoint_configure(). */ struct snd_usb_endpoint * snd_usb_endpoint_open(struct snd_usb_audio *chip, @@ -1302,39 +1300,15 @@ out_of_memory: return -ENOMEM; } -/* update the rate of the referred clock; return the actual rate */ -static int update_clock_ref_rate(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep) -{ - struct snd_usb_clock_ref *clock = ep->clock_ref; - int rate = ep->cur_rate; - - if (!clock || clock->rate == rate) - return rate; - if (clock->rate) { - if (atomic_read(&clock->locked)) - return clock->rate; - if (clock->rate != rate) { - usb_audio_err(chip, "Mismatched sample rate %d vs %d for EP 0x%x\n", - clock->rate, rate, ep->ep_num); - return clock->rate; - } - } - clock->rate = rate; - clock->need_setup = true; - return rate; -} - /* * snd_usb_endpoint_set_params: configure an snd_usb_endpoint * - * It's called either from hw_params callback. * Determine the number of URBs to be used on this endpoint. * An endpoint must be configured before it can be started. * An endpoint that is already running can not be reconfigured. */ -int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep) +static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) { const struct audioformat *fmt = ep->cur_audiofmt; int err; @@ -1386,46 +1360,49 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, ep->maxframesize = ep->maxpacksize / ep->cur_frame_bytes; ep->curframesize = ep->curpacksize / ep->cur_frame_bytes; - return update_clock_ref_rate(chip, ep); + return 0; } static int init_sample_rate(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep) { struct snd_usb_clock_ref *clock = ep->clock_ref; - int rate, err; + int err; - rate = update_clock_ref_rate(chip, ep); - if (rate < 0) - return rate; - if (clock && !clock->need_setup) - return 0; - - err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, rate); - if (err < 0) { - if (clock) - clock->rate = 0; /* reset rate */ - return err; + if (clock) { + if (atomic_read(&clock->locked)) + return 0; + if (clock->rate == ep->cur_rate) + return 0; + if (clock->rate && clock->rate != ep->cur_rate) { + usb_audio_dbg(chip, "Mismatched sample rate %d vs %d for EP 0x%x\n", + clock->rate, ep->cur_rate, ep->ep_num); + return -EINVAL; + } } + err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, ep->cur_rate); + if (err < 0) + return err; + if (clock) - clock->need_setup = false; + clock->rate = ep->cur_rate; return 0; } /* - * snd_usb_endpoint_prepare: Prepare the endpoint + * snd_usb_endpoint_configure: Configure the endpoint * * This function sets up the EP to be fully usable state. - * It's called either from prepare callback. + * It's called either from hw_params or prepare callback. * The function checks need_setup flag, and performs nothing unless needed, * so it's safe to call this multiple times. * * This returns zero if unchanged, 1 if the configuration has changed, * or a negative error code. */ -int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep) +int snd_usb_endpoint_configure(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep) { bool iface_first; int err = 0; @@ -1446,6 +1423,9 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, if (err < 0) goto unlock; } + err = snd_usb_endpoint_set_params(chip, ep); + if (err < 0) + goto unlock; goto done; } @@ -1473,6 +1453,10 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, if (err < 0) goto unlock; + err = snd_usb_endpoint_set_params(chip, ep); + if (err < 0) + goto unlock; + err = snd_usb_select_mode_quirk(chip, ep->cur_audiofmt); if (err < 0) goto unlock; diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index b972f7899d57..daa7ba063d85 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -17,10 +17,8 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, bool is_sync_ep); void snd_usb_endpoint_close(struct snd_usb_audio *chip, struct snd_usb_endpoint *ep); -int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep); -int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, - struct snd_usb_endpoint *ep); +int snd_usb_endpoint_configure(struct snd_usb_audio *chip, + struct snd_usb_endpoint *ep); int snd_usb_endpoint_get_clock_rate(struct snd_usb_audio *chip, int clock); bool snd_usb_endpoint_compatible(struct snd_usb_audio *chip, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index f5ee6f2cf34a..2e65911e0597 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -442,6 +442,35 @@ static void close_endpoints(struct snd_usb_audio *chip, } } +static int configure_endpoints(struct snd_usb_audio *chip, + struct snd_usb_substream *subs) +{ + int err; + + if (subs->data_endpoint->need_setup) { + /* stop any running stream beforehand */ + if (stop_endpoints(subs, false)) + sync_pending_stops(subs); + if (subs->sync_endpoint) { + err = snd_usb_endpoint_configure(chip, subs->sync_endpoint); + if (err < 0) + return err; + } + err = snd_usb_endpoint_configure(chip, subs->data_endpoint); + if (err < 0) + return err; + snd_usb_set_format_quirk(subs, subs->cur_audiofmt); + } else { + if (subs->sync_endpoint) { + err = snd_usb_endpoint_configure(chip, subs->sync_endpoint); + if (err < 0) + return err; + } + } + + return 0; +} + /* * hw_params callback * @@ -533,16 +562,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, subs->cur_audiofmt = fmt; mutex_unlock(&chip->mutex); - if (!subs->data_endpoint->need_setup) - goto unlock; - - if (subs->sync_endpoint) { - ret = snd_usb_endpoint_set_params(chip, subs->sync_endpoint); - if (ret < 0) - goto unlock; - } - - ret = snd_usb_endpoint_set_params(chip, subs->data_endpoint); + ret = configure_endpoints(chip, subs); unlock: if (ret < 0) @@ -625,18 +645,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; } - if (subs->sync_endpoint) { - ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); - if (ret < 0) - goto unlock; - } - - ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); + ret = configure_endpoints(chip, subs); if (ret < 0) goto unlock; - else if (ret > 0) - snd_usb_set_format_quirk(subs, subs->cur_audiofmt); - ret = 0; /* reset the pointer */ subs->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size);