[alsa-devel] [RFC V2 PATCH 3/5] ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug

Takashi Iwai tiwai at suse.de
Mon Nov 23 16:59:30 CET 2015


On Mon, 23 Nov 2015 15:09:32 +0100,
libin.yang at linux.intel.com wrote:
> 
> From: Libin Yang <libin.yang at linux.intel.com>
> 
> Dynamically bind/unbind the PCM to pin when HDMI/DP monitor hotplug.
> 
> When monitor is connected, find a proper PCM for the monitor.
> When monitor is disconnected, unbind the PCM from the pin.

You must have some strategy about binding.  Please tell the story
behind the scene, too.

> 
> Signed-off-by: Libin Yang <libin.yang at linux.intel.com>
> ---
>  sound/pci/hda/patch_hdmi.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 82 insertions(+)
> 
> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> index de22ac2..bcc2a90 100644
> --- a/sound/pci/hda/patch_hdmi.c
> +++ b/sound/pci/hda/patch_hdmi.c
> @@ -72,6 +72,8 @@ struct hdmi_spec_per_cvt {
>  
>  struct hdmi_spec_per_pin {
>  	hda_nid_t pin_nid;
> +	/* pin idx, different device entries on the same pin use the same idx */
> +	int pin_nid_idx;
>  	int num_mux_nids;
>  	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
>  	int mux_idx;
> @@ -83,6 +85,7 @@ struct hdmi_spec_per_pin {
>  	struct delayed_work work;
>  	struct snd_kcontrol *eld_ctl;
>  	struct hda_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
> +	int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
>  	int repoll_count;
>  	bool setup; /* the stream has been set up by prepare callback */
>  	int channels; /* current number of channels */
> @@ -136,6 +139,7 @@ struct hdmi_spec {
>  	struct snd_array pins; /* struct hdmi_spec_per_pin */
>  	struct hda_pcm *pcm_rec[16];
>  	struct mutex pcm_lock;
> +	unsigned long pcm_bitmap;
>  	int pcm_used;	/* counter of pcm_rec[] */
>  	unsigned int channels_max; /* max over all cvts */
>  
> @@ -1663,6 +1667,70 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
>  	return 0;
>  }
>  
> +static int get_preferred_pcm_slot(struct hdmi_spec *spec,
> +				struct hdmi_spec_per_pin *per_pin)
> +{
> +	if ((spec->pcm_bitmap & (1 << per_pin->pin_nid_idx)) == 0)

Use test_bit().

> +		return per_pin->pin_nid_idx;
> +	return -1;
> +}
> +
> +static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
> +				struct hdmi_spec_per_pin *per_pin)
> +{
> +	int slot;
> +	int i;
> +
> +	/* try the prefer PCM */
> +	slot = get_preferred_pcm_slot(spec, per_pin);
> +	if (slot != -1)
> +		return slot;
> +
> +	/* have a second try */
> +	for (i = spec->num_pins; i < spec->pcm_used; i++) {
> +		if ((spec->pcm_bitmap & (1 << i)) == 0)

Ditto.

> +			return i;
> +	}
> +
> +	/* the last try */
> +	for (i = 0; i < spec->pcm_used; i++) {
> +		if ((spec->pcm_bitmap & (1 << i)) == 0)

Ditto.

> +			return i;
> +	}
> +	return -ENODEV;

I think you don't need to split get_preferred_pcm_slot().
It's a function that is called only from here, and it's even better to
be open-coded.  Then you can see the code flow more easily.
(Also, you may notice that the last loop doesn't go all, but just up
 to num_pins, by looking through the code closely.)

static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
				struct hdmi_spec_per_pin *per_pin)
{
	int i;

	/* try the prefer PCM */
	if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap))
		return per_pin->pin_nid_idx;

	/* have a second try; check the "reserved area" over num_pins */
	for (i = spec->num_pins; i < spec->pcm_used; i++)
		if (!test_bit(i, &spec->pcm_bitmap))
			return i;

	/* the last try; check the empty slots in pins */
	for (i = 0; i < spec->num_pins; i++)
		if (!test_bit(i, &spec->pcm_bitmap))
			return i;

	return -EBUSY;
}



Takashi


More information about the Alsa-devel mailing list