|
@@ -82,8 +82,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
|
|
|
/*
|
|
|
* find a matching audio format
|
|
|
*/
|
|
|
-static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format,
|
|
|
- unsigned int rate, unsigned int channels)
|
|
|
+static struct audioformat *find_format(struct snd_usb_substream *subs)
|
|
|
{
|
|
|
struct list_head *p;
|
|
|
struct audioformat *found = NULL;
|
|
@@ -92,16 +91,17 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned
|
|
|
list_for_each(p, &subs->fmt_list) {
|
|
|
struct audioformat *fp;
|
|
|
fp = list_entry(p, struct audioformat, list);
|
|
|
- if (!(fp->formats & (1uLL << format)))
|
|
|
+ if (!(fp->formats & (1uLL << subs->pcm_format)))
|
|
|
continue;
|
|
|
- if (fp->channels != channels)
|
|
|
+ if (fp->channels != subs->channels)
|
|
|
continue;
|
|
|
- if (rate < fp->rate_min || rate > fp->rate_max)
|
|
|
+ if (subs->cur_rate < fp->rate_min ||
|
|
|
+ subs->cur_rate > fp->rate_max)
|
|
|
continue;
|
|
|
if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) {
|
|
|
unsigned int i;
|
|
|
for (i = 0; i < fp->nr_rates; i++)
|
|
|
- if (fp->rate_table[i] == rate)
|
|
|
+ if (fp->rate_table[i] == subs->cur_rate)
|
|
|
break;
|
|
|
if (i >= fp->nr_rates)
|
|
|
continue;
|
|
@@ -435,6 +435,42 @@ add_sync_ep:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * configure endpoint params
|
|
|
+ *
|
|
|
+ * called during initial setup and upon resume
|
|
|
+ */
|
|
|
+static int configure_endpoint(struct snd_usb_substream *subs)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ mutex_lock(&subs->stream->chip->shutdown_mutex);
|
|
|
+ /* format changed */
|
|
|
+ stop_endpoints(subs, 0, 0, 0);
|
|
|
+ ret = snd_usb_endpoint_set_params(subs->data_endpoint,
|
|
|
+ subs->pcm_format,
|
|
|
+ subs->channels,
|
|
|
+ subs->period_bytes,
|
|
|
+ subs->cur_rate,
|
|
|
+ subs->cur_audiofmt,
|
|
|
+ subs->sync_endpoint);
|
|
|
+ if (ret < 0)
|
|
|
+ goto unlock;
|
|
|
+
|
|
|
+ if (subs->sync_endpoint)
|
|
|
+ ret = snd_usb_endpoint_set_params(subs->data_endpoint,
|
|
|
+ subs->pcm_format,
|
|
|
+ subs->channels,
|
|
|
+ subs->period_bytes,
|
|
|
+ subs->cur_rate,
|
|
|
+ subs->cur_audiofmt,
|
|
|
+ NULL);
|
|
|
+
|
|
|
+unlock:
|
|
|
+ mutex_unlock(&subs->stream->chip->shutdown_mutex);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* hw_params callback
|
|
|
*
|
|
@@ -450,75 +486,32 @@ 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));
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
- format = params_format(hw_params);
|
|
|
- rate = params_rate(hw_params);
|
|
|
- channels = params_channels(hw_params);
|
|
|
- fmt = find_format(subs, format, rate, channels);
|
|
|
+ subs->pcm_format = params_format(hw_params);
|
|
|
+ subs->period_bytes = params_period_bytes(hw_params);
|
|
|
+ subs->channels = params_channels(hw_params);
|
|
|
+ subs->cur_rate = params_rate(hw_params);
|
|
|
+
|
|
|
+ fmt = find_format(subs);
|
|
|
if (!fmt) {
|
|
|
snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
|
|
|
- format, rate, channels);
|
|
|
+ subs->pcm_format, subs->cur_rate, subs->channels);
|
|
|
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, fmt->iface, alts, fmt, rate);
|
|
|
- if (ret < 0)
|
|
|
- return ret;
|
|
|
- subs->cur_rate = rate;
|
|
|
- }
|
|
|
-
|
|
|
- if (changed) {
|
|
|
- subs->period_bytes = params_period_bytes(hw_params);
|
|
|
+ subs->interface = fmt->iface;
|
|
|
+ subs->altset_idx = fmt->altset_idx;
|
|
|
|
|
|
- mutex_lock(&subs->stream->chip->shutdown_mutex);
|
|
|
- /* format changed */
|
|
|
- stop_endpoints(subs, 0, 0, 0);
|
|
|
- ret = snd_usb_endpoint_set_params(subs->data_endpoint,
|
|
|
- format,
|
|
|
- channels,
|
|
|
- subs->period_bytes,
|
|
|
- rate,
|
|
|
- fmt,
|
|
|
- subs->sync_endpoint);
|
|
|
- if (ret < 0)
|
|
|
- goto unlock;
|
|
|
-
|
|
|
- if (subs->sync_endpoint)
|
|
|
- ret = snd_usb_endpoint_set_params(subs->data_endpoint,
|
|
|
- format,
|
|
|
- channels,
|
|
|
- subs->period_bytes,
|
|
|
- rate,
|
|
|
- fmt,
|
|
|
- NULL);
|
|
|
-unlock:
|
|
|
- mutex_unlock(&subs->stream->chip->shutdown_mutex);
|
|
|
- }
|
|
|
-
|
|
|
- if (ret == 0) {
|
|
|
- subs->interface = fmt->iface;
|
|
|
- subs->altset_idx = fmt->altset_idx;
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -549,6 +542,9 @@ 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");
|
|
@@ -558,6 +554,24 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
|
|
|
if (snd_BUG_ON(!subs->data_endpoint))
|
|
|
return -EIO;
|
|
|
|
|
|
+ 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->cur_audiofmt->iface,
|
|
|
+ alts,
|
|
|
+ subs->cur_audiofmt,
|
|
|
+ subs->cur_rate);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = configure_endpoint(subs);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
/* some unit conversions in runtime */
|
|
|
subs->data_endpoint->maxframesize =
|
|
|
bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
|