[alsa-devel] [PATCH sound-unstable] usb-audio: sync ep init fix for audioformat mistmatch
Takashi Iwai
tiwai at suse.de
Mon Dec 3 10:43:07 CET 2012
At Mon, 03 Dec 2012 10:34:29 +0100,
Daniel Mack wrote:
>
> On 01.12.2012 23:50, Eldad Zack wrote:
> > Commit 947d299686aa9cc8aecf749d54e8475c6e498956 , "ALSA: snd-usb:
> > properly initialize the sync endpoint", while correcting the
> > initialization of the sync endpoint when opening just the data
> > endpoint, prevents devices that has a sync endpoint with a channel
> > number different than the data endpoint channel from functioning.
> > Due to a different channel and period bytes count. attempting to
> > initialize the sync endpoint will fail at the usb host driver:
> > (example, when using xhci:)
> >
> > cannot submit urb 0, error -90: internal error
> >
> > With this patch, if a sync endpoint has multiple audioformats, a
> > matching audioformat is perferred. An audioformat must be found
> > with at least one channel and support the requested sample rate
> > and PCM format, otherwise the stream will not be opened.
> >
> > If the number of channels differ between the selected audioformat
> > and the requested format, adjust the period bytes count accordingly.
> > It is safe to perform the calculation on the basis of the channel
> > count, since the PCM audio format and the rate must be supported by
> > the selected audioformat.
>
> Thanks for fixing this up, and sorry for the late response on this.
>
> >
> > Cc: Jeffrey Barish <jeff_barish at earthlink.net>
> > Cc: Daniel Mack <zonque at gmail.com>
> > Signed-off-by: Eldad Zack <eldad at fogrefinery.com>
> > ---
> > sound/usb/pcm.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++----
> > 1 files changed, 99 insertions(+), 7 deletions(-)
> >
> > diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
> > index 5d3cf85..e539a5a 100644
> > --- a/sound/usb/pcm.c
> > +++ b/sound/usb/pcm.c
> > @@ -451,6 +451,103 @@ add_sync_ep:
> > }
> >
> > /*
> > + * Return the score of matching two audioformats.
> > + * Veto the audioformat if:
> > + * - It has no channels for some reason.
> > + * - Requested PCM format is not supported.
> > + * - Requested sample rate is not supported.
> > + */
> > +static int match_endpoint_audioformats(struct audioformat *fp,
> > + struct audioformat *match, int rate,
> > + snd_pcm_format_t pcm_format)
> > +{
> > + int i;
> > + int score = 0;
> > +
> > + if (fp->channels < 1) {
> > + snd_printdd("%s: (fmt @%p) no channels\n", __func__, fp);
> > + return 0;
> > + }
> > +
> > + if (!(fp->formats && pcm_format)) {
>
> That should be a binary &, no?
Oh yeah, this must be
if (!(fp->formats && (1ULL << pcm_format)))
Takashi
>
> Otherwise, together with the fix Takashi suggested, looks good to me as
> well.
>
>
> Thanks,
> Daniel
>
>
> > + snd_printdd("%s: (fmt @%p) no match for format %d\n", __func__,
> > + fp, pcm_format);
> > + return 0;
> > + }
> > +
> > + for (i = 0; i < 4; i++) {
> > + if (fp->rate_table[i] == rate) {
> > + score++;
> > + break;
> > + }
> > + }
> > + if (!score) {
> > + snd_printdd("%s: (fmt @%p) no match for rate %d\n", __func__,
> > + fp, rate);
> > + return 0;
> > + }
> > +
> > + if (fp->channels == match->channels)
> > + score++;
> > +
> > + snd_printdd("%s: (fmt @%p) score %d\n", __func__, fp, score);
> > +
> > + return score;
> > +}
> > +
> > +/*
> > + * Configure the sync ep using the rate and pcm format of the data ep.
> > + */
> > +static int configure_sync_endpoint(struct snd_usb_substream *subs)
> > +{
> > + int ret;
> > + struct audioformat *fp;
> > + struct audioformat *sync_fp = NULL;
> > + int cur_score = 0;
> > + int sync_period_bytes = subs->period_bytes;
> > + struct snd_usb_substream *sync_subs =
> > + &subs->stream->substream[subs->direction ^ 1];
> > +
> > + /* Try to find the best matching audioformat. */
> > + list_for_each_entry(fp, &sync_subs->fmt_list, list) {
> > + int score = match_endpoint_audioformats(fp, subs->cur_audiofmt,
> > + subs->cur_rate, subs->pcm_format);
> > +
> > + if (score > cur_score) {
> > + sync_fp = fp;
> > + cur_score = score;
> > + }
> > + }
> > +
> > + if (unlikely(sync_fp == NULL)) {
> > + snd_printk(KERN_ERR "%s: no valid audioformat for sync ep %x found\n",
> > + __func__, sync_subs->ep_num);
> > + return -EINVAL;
> > + }
> > +
> > + /*
> > + * Recalculated the period bytes if channel number differ between
> > + * data and sync ep audioformat.
> > + */
> > + if (sync_fp->channels != subs->channels) {
> > + sync_period_bytes = (subs->period_bytes / subs->channels) *
> > + sync_fp->channels;
> > + snd_printdd("%s: adjusted sync ep period bytes (%d -> %d)\n",
> > + __func__, subs->period_bytes, sync_period_bytes);
> > + }
> > +
> > + ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
> > + subs->pcm_format,
> > + sync_fp->channels,
> > + sync_period_bytes,
> > + subs->cur_rate,
> > + sync_fp,
> > + NULL);
> > +
> > + return ret;
> > +}
> > +
> > +/*
> > * configure endpoint params
> > *
> > * called during initial setup and upon resume
> > @@ -472,13 +569,8 @@ static int configure_endpoint(struct snd_usb_substream *subs)
> > return ret;
> >
> > if (subs->sync_endpoint)
> > - ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
> > - subs->pcm_format,
> > - subs->channels,
> > - subs->period_bytes,
> > - subs->cur_rate,
> > - subs->cur_audiofmt,
> > - NULL);
> > + ret = configure_sync_endpoint(subs);
> > +
> > return ret;
> > }
> >
> >
>
More information about the Alsa-devel
mailing list