mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 17:53:56 +08:00
ALSA: usb-audio: Handle discrete rates properly in hw constraints
In the current code, when the device provides the discrete sample rate tables with unusual sample rates, the driver tries to gather the whole values from the audioformat entries and create a hw-constraint rule to restrict with this single rate list. This is rather inefficient and may overlook the rates that are associated only with the certain audioformat entries. This patch improves the hw constraint setup by rewriting the existing hw_rule_rate(). The discrete sample rates (identified by rate_table and nr_rates of format entry) are checked in the existing hw_rule_rate() instead of extra rules; in the case of discrete rates, the function compares with each rate table entry and calculates the min/max values from there. For the contiguous rates, the behavior doesn't change. Along with it, snd_usb_pcm_check_knot() and snb_usb_substream rate_list field become superfluous, thus those are dropped. Tested-by: Keith Milner <kamilner@superlative.org> Tested-by: Dylan Robinson <dylan_robinson@motu.com> Link: https://lore.kernel.org/r/20201123085347.19667-2-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
418baf2c28
commit
bc4e94aa8e
@ -157,7 +157,6 @@ struct snd_usb_substream {
|
|||||||
u64 formats; /* format bitmasks (all or'ed) */
|
u64 formats; /* format bitmasks (all or'ed) */
|
||||||
unsigned int num_formats; /* number of supported audio formats (list) */
|
unsigned int num_formats; /* number of supported audio formats (list) */
|
||||||
struct list_head fmt_list; /* format list */
|
struct list_head fmt_list; /* format list */
|
||||||
struct snd_pcm_hw_constraint_list rate_list; /* limited rates */
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
|
||||||
int last_frame_number; /* stored frame number */
|
int last_frame_number; /* stored frame number */
|
||||||
|
@ -1039,27 +1039,31 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
|
|||||||
struct snd_usb_substream *subs = rule->private;
|
struct snd_usb_substream *subs = rule->private;
|
||||||
struct audioformat *fp;
|
struct audioformat *fp;
|
||||||
struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||||
unsigned int rmin, rmax;
|
unsigned int rmin, rmax, r;
|
||||||
int changed;
|
int changed;
|
||||||
|
int i;
|
||||||
|
|
||||||
hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max);
|
hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max);
|
||||||
changed = 0;
|
rmin = UINT_MAX;
|
||||||
rmin = rmax = 0;
|
rmax = 0;
|
||||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||||
if (!hw_check_valid_format(subs, params, fp))
|
if (!hw_check_valid_format(subs, params, fp))
|
||||||
continue;
|
continue;
|
||||||
if (changed++) {
|
if (fp->rate_table && fp->nr_rates) {
|
||||||
if (rmin > fp->rate_min)
|
for (i = 0; i < fp->nr_rates; i++) {
|
||||||
rmin = fp->rate_min;
|
r = fp->rate_table[i];
|
||||||
if (rmax < fp->rate_max)
|
if (!snd_interval_test(it, r))
|
||||||
rmax = fp->rate_max;
|
continue;
|
||||||
|
rmin = min(rmin, r);
|
||||||
|
rmax = max(rmax, r);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rmin = fp->rate_min;
|
rmin = min(rmin, fp->rate_min);
|
||||||
rmax = fp->rate_max;
|
rmax = max(rmax, fp->rate_max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changed) {
|
if (rmin > rmax) {
|
||||||
hwc_debug(" --> get empty\n");
|
hwc_debug(" --> get empty\n");
|
||||||
it->empty = 1;
|
it->empty = 1;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -1205,50 +1209,6 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params,
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If the device supports unusual bit rates, does the request meet these?
|
|
||||||
*/
|
|
||||||
static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
|
|
||||||
struct snd_usb_substream *subs)
|
|
||||||
{
|
|
||||||
struct audioformat *fp;
|
|
||||||
int *rate_list;
|
|
||||||
int count = 0, needs_knot = 0;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
kfree(subs->rate_list.list);
|
|
||||||
subs->rate_list.list = NULL;
|
|
||||||
|
|
||||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
|
||||||
if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
|
|
||||||
return 0;
|
|
||||||
count += fp->nr_rates;
|
|
||||||
if (fp->rates & SNDRV_PCM_RATE_KNOT)
|
|
||||||
needs_knot = 1;
|
|
||||||
}
|
|
||||||
if (!needs_knot)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
subs->rate_list.list = rate_list =
|
|
||||||
kmalloc_array(count, sizeof(int), GFP_KERNEL);
|
|
||||||
if (!subs->rate_list.list)
|
|
||||||
return -ENOMEM;
|
|
||||||
subs->rate_list.count = count;
|
|
||||||
subs->rate_list.mask = 0;
|
|
||||||
count = 0;
|
|
||||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < fp->nr_rates; i++)
|
|
||||||
rate_list[count++] = fp->rate_table[i];
|
|
||||||
}
|
|
||||||
err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
|
||||||
&subs->rate_list);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set up the runtime hardware information.
|
* set up the runtime hardware information.
|
||||||
@ -1338,9 +1298,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
err = snd_usb_pcm_check_knot(runtime, subs);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return snd_usb_autoresume(subs->stream->chip);
|
return snd_usb_autoresume(subs->stream->chip);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ static void free_substream(struct snd_usb_substream *subs)
|
|||||||
return; /* not initialized */
|
return; /* not initialized */
|
||||||
list_for_each_entry_safe(fp, n, &subs->fmt_list, list)
|
list_for_each_entry_safe(fp, n, &subs->fmt_list, list)
|
||||||
audioformat_free(fp);
|
audioformat_free(fp);
|
||||||
kfree(subs->rate_list.list);
|
|
||||||
kfree(subs->str_pd);
|
kfree(subs->str_pd);
|
||||||
snd_media_stream_delete(subs);
|
snd_media_stream_delete(subs);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user