[alsa-devel] [RFC PATCH v2 1/3] ALSA: hda - add DP mst verb support
Takashi Iwai
tiwai at suse.de
Thu Mar 24 10:19:27 CET 2016
On Thu, 24 Mar 2016 09:44:32 +0100,
Yang, Libin wrote:
>
> Hi Takashi,
>
> > -----Original Message-----
> > From: Takashi Iwai [mailto:tiwai at suse.de]
> > Sent: Tuesday, March 22, 2016 7:17 PM
> > To: libin.yang at linux.intel.com
> > Cc: alsa-devel at alsa-project.org; Lin, Mengdong; Yang, Libin
> > Subject: Re: [alsa-devel] [RFC PATCH v2 1/3] ALSA: hda - add DP mst verb
> > support
> >
> > On Mon, 21 Mar 2016 09:37:54 +0100,
> > libin.yang at linux.intel.com wrote:
> > >
> > > From: Libin Yang <libin.yang at linux.intel.com>
> > >
> > > Add snd_hda_get_dev_select() and snd_hda_set_dev_select()
> > functions
> > > for DP MST audio support.
> > >
> > > Signed-off-by: Libin Yang <libin.yang at linux.intel.com>
> > > ---
> > > sound/pci/hda/hda_codec.c | 83
> > ++++++++++++++++++++++++++++++++++++++++++++---
> > > sound/pci/hda/hda_codec.h | 3 ++
> > > 2 files changed, 82 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
> > > index d17e38e..db94a66 100644
> > > --- a/sound/pci/hda/hda_codec.c
> > > +++ b/sound/pci/hda/hda_codec.c
> > > @@ -325,9 +325,16 @@ int snd_hda_get_conn_index(struct
> > hda_codec *codec, hda_nid_t mux,
> > > }
> > > EXPORT_SYMBOL_GPL(snd_hda_get_conn_index);
> > >
> > > -
> > > -/* return DEVLIST_LEN parameter of the given widget */
> > > -static unsigned int get_num_devices(struct hda_codec *codec,
> > hda_nid_t nid)
> > > +/**
> > > + * snd_hda_get_num_devices - get DEVLIST_LEN parameter of the
> > given widget
> > > + * @codec: the HDA codec
> > > + * @nid: NID of the pin to parse
> > > + *
> > > + * Get the device entry number on the given widget.
> > > + * This is a feature of DP MST audio. Each pin can
> > > + * have several device entries in it.
> > > + */
> > > +unsigned int snd_hda_get_num_devices(struct hda_codec *codec,
> > hda_nid_t nid)
> > > {
> > > unsigned int wcaps = get_wcaps(codec, nid);
> > > unsigned int parm;
> > > @@ -341,6 +348,7 @@ static unsigned int get_num_devices(struct
> > hda_codec *codec, hda_nid_t nid)
> > > parm = 0;
> > > return parm & AC_DEV_LIST_LEN_MASK;
> > > }
> > > +EXPORT_SYMBOL_GPL(snd_hda_get_num_devices);
> > >
> > > /**
> > > * snd_hda_get_devices - copy device list without cache
> > > @@ -358,7 +366,7 @@ int snd_hda_get_devices(struct hda_codec
> > *codec, hda_nid_t nid,
> > > unsigned int parm;
> > > int i, dev_len, devices;
> > >
> > > - parm = get_num_devices(codec, nid);
> > > + parm = snd_hda_get_num_devices(codec, nid);
> > > if (!parm) /* not multi-stream capable */
> > > return 0;
> > >
> > > @@ -382,6 +390,73 @@ int snd_hda_get_devices(struct hda_codec
> > *codec, hda_nid_t nid,
> > > return devices;
> > > }
> > >
> > > +/**
> > > + * snd_hda_get_dev_select - get device entry select on the pin
> > > + * @codec: the HDA codec
> > > + * @nid: NID of the pin to get device entry select
> > > + *
> > > + * Get the devcie entry select on the pin. Return the device entry
> > > + * id selected on the pin. Return 0 means the first device entry
> > > + * is selected or MST is not supported.
> > > + */
> > > +int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid)
> > > +{
> > > + /* not support dp_mst will always return 0, using first dev_entry
> > */
> > > + if (!codec->dp_mst)
> > > + return 0;
> > > +
> > > + return snd_hda_codec_read(codec, nid, 0,
> > AC_VERB_GET_DEVICE_SEL, 0);
> > > +}
> > > +EXPORT_SYMBOL_GPL(snd_hda_get_dev_select);
> > > +
> > > +/**
> > > + * snd_hda_set_dev_select - set device entry select on the pin
> > > + * @codec: the HDA codec
> > > + * @nid: NID of the pin to set device entry select
> > > + * @dev_id: device entry id to be set
> > > + *
> > > + * Set the device entry select on the pin nid.
> > > + */
> > > +int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid,
> > int dev_id)
> > > +{
> > > + int ret, dev, num_devices;
> > > + unsigned long timeout;
> > > +
> > > + /* not support dp_mst will always return 0, using first dev_entry
> > */
> > > + if (!codec->dp_mst)
> > > + return 0;
> > > +
> > > + /* AC_PAR_DEVLIST_LEN is 0 based. */
> > > + num_devices = snd_hda_get_num_devices(codec, nid);
> > > + /* If Device List Length is 0, the pin is not multi stream capable.
> > > + */
> > > + if (num_devices == 0)
> > > + return 0;
> > > +
> > > + /* Behavior of setting index being equal to or greater than
> > > + * Device List Length is not predictable
> > > + */
> > > + if (num_devices + 1 <= dev_id)
> > > + return 0;
> >
> > Is this correct? Doesn't num_devices=1 mean that there is only a
> > single device? If dev_id=1 must be invalid, but the check above
> > passes. The standard form of such index check is like
>
> num_device is the return value of the verb AC_PAR_DEVLIST_LEN.
> device number is AC_PAR_DEVLIST_LEN + 1.
>
> >From the spec:
> Device List Length is a 0 based integer value indicating the number
> of sink device that a multi stream capable Digital Display Pin
> Widget can support. If Device List Length is value is 0, there is
> only one sink device connection possible indicating the Pin Widget
> is not multi stream capable, and there is no Device Select control
>
> And dev_id is 0 based.
>
> If dev_id = 1, it means set the second device entry, and
> num_device + 1 (the real number of device entries)
> must be equal to or greater than 2.
> (num_device + 1 > dev_id )
>
> So (num_device + 1 <= dev_id) is wrong situation.
If so, the term "num_devices" is counter-intuitive. It should be
corrected to the natural value, i.e. based on 1, or renamed to a
different one. Readers would assume that the number of devices is 1
if there is a single element, not 0. If this isn't true, it just
confuses readers.
> >
> > if (dev_id >= num_devices)
> > error;
> >
> > And this also leads to the question. Shouldn't we return an error if
> > an invalid dev_id is given?
>
> I'm thinking if the wrong dev_id is given, we just leave as it is before.
> I will return the -EINVAL in next version.
IMO, it's safer to return an error. Since non-zero dev_id is only for
MST, the code path that passes such a value must handle MST properly,
i.e. not through the default code path.
> > > +
> > > + timeout = jiffies + msecs_to_jiffies(500);
> > > +
> > > + /* make sure the device entry selection takes effect */
> > > + do {
> > > + ret = snd_hda_codec_write(codec, nid, 0,
> > > + AC_VERB_SET_DEVICE_SEL, dev_id);
> > > + udelay(20);
> > > +
> > > + dev = snd_hda_get_dev_select(codec, nid);
> > > + if (dev == dev_id)
> > > + break;
> > > + msleep(20);
> > > + } while (time_before(jiffies, timeout));
> >
> > Is this loop needed? Most verbs take effect immediately, and so far,
> > the only exception is the power state.
>
> OK, I will remove the loop.
Well, I don't mean to remove forcibly. Just want to be sure.
If such a loop is needed practically, we must have it, of course.
Let's check.
thanks,
Takashi
More information about the Alsa-devel
mailing list