Skip to content

Commit

Permalink
ALSA: hda - hdmi eld control created based on pcm
Browse files Browse the repository at this point in the history
eld control is created based on pcm now.
When monitor is connected, eld control will be bound to
pin automatically.

Signed-off-by: Libin Yang <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
libinyang authored and tiwai committed Feb 23, 2016
1 parent fe0d128 commit fb087ea
Showing 1 changed file with 48 additions and 26 deletions.
74 changes: 48 additions & 26 deletions sound/pci/hda/patch_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ struct hdmi_spec_per_pin {
struct hdmi_eld sink_eld;
struct mutex lock;
struct delayed_work work;
struct snd_kcontrol *eld_ctl;
struct hdmi_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;
Expand Down Expand Up @@ -136,6 +135,7 @@ struct hdmi_ops {
struct hdmi_pcm {
struct hda_pcm *pcm;
struct snd_jack *jack;
struct snd_kcontrol *eld_ctl;
};

struct hdmi_spec {
Expand Down Expand Up @@ -471,17 +471,22 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin;
struct hdmi_eld *eld;
int pin_idx;
int pcm_idx;

uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;

pin_idx = kcontrol->private_value;
per_pin = get_pin(spec, pin_idx);
pcm_idx = kcontrol->private_value;
mutex_lock(&spec->pcm_lock);
per_pin = pcm_idx_to_pin(spec, pcm_idx);
if (!per_pin) {
/* no pin is bound to the pcm */
uinfo->count = 0;
mutex_unlock(&spec->pcm_lock);
return 0;
}
eld = &per_pin->sink_eld;

mutex_lock(&per_pin->lock);
uinfo->count = eld->eld_valid ? eld->eld_size : 0;
mutex_unlock(&per_pin->lock);
mutex_unlock(&spec->pcm_lock);

return 0;
}
Expand All @@ -493,16 +498,23 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin;
struct hdmi_eld *eld;
int pin_idx;
int pcm_idx;

pin_idx = kcontrol->private_value;
per_pin = get_pin(spec, pin_idx);
pcm_idx = kcontrol->private_value;
mutex_lock(&spec->pcm_lock);
per_pin = pcm_idx_to_pin(spec, pcm_idx);
if (!per_pin) {
/* no pin is bound to the pcm */
memset(ucontrol->value.bytes.data, 0,
ARRAY_SIZE(ucontrol->value.bytes.data));
mutex_unlock(&spec->pcm_lock);
return 0;
}
eld = &per_pin->sink_eld;

mutex_lock(&per_pin->lock);
if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
eld->eld_size > ELD_MAX_SIZE) {
mutex_unlock(&per_pin->lock);
mutex_unlock(&spec->pcm_lock);
snd_BUG();
return -EINVAL;
}
Expand All @@ -512,7 +524,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
if (eld->eld_valid)
memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
eld->eld_size);
mutex_unlock(&per_pin->lock);
mutex_unlock(&spec->pcm_lock);

return 0;
}
Expand All @@ -525,7 +537,7 @@ static struct snd_kcontrol_new eld_bytes_ctl = {
.get = hdmi_eld_ctl_get,
};

static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
static int hdmi_create_eld_ctl(struct hda_codec *codec, int pcm_idx,
int device)
{
struct snd_kcontrol *kctl;
Expand All @@ -535,14 +547,17 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
kctl = snd_ctl_new1(&eld_bytes_ctl, codec);
if (!kctl)
return -ENOMEM;
kctl->private_value = pin_idx;
kctl->private_value = pcm_idx;
kctl->id.device = device;

err = snd_hda_ctl_add(codec, get_pin(spec, pin_idx)->pin_nid, kctl);
/* no pin nid is associated with the kctl now
* tbd: associate pin nid to eld ctl later
*/
err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0)
return err;

get_pin(spec, pin_idx)->eld_ctl = kctl;
get_hdmi_pcm(spec, pcm_idx)->eld_ctl = kctl;
return 0;
}

Expand Down Expand Up @@ -1841,7 +1856,10 @@ static void update_eld(struct hda_codec *codec,
struct hdmi_spec *spec = codec->spec;
bool old_eld_valid = pin_eld->eld_valid;
bool eld_changed;
int pcm_idx = -1;

/* for monitor disconnection, save pcm_idx firstly */
pcm_idx = per_pin->pcm_idx;
if (spec->dyn_pcm_assign) {
if (eld->eld_valid) {
hdmi_attach_hda_pcm(spec, per_pin);
Expand All @@ -1851,6 +1869,11 @@ static void update_eld(struct hda_codec *codec,
hdmi_detach_hda_pcm(spec, per_pin);
}
}
/* if pcm_idx == -1, it means this is in monitor connection event
* we can get the correct pcm_idx now.
*/
if (pcm_idx == -1)
pcm_idx = per_pin->pcm_idx;

if (eld->eld_valid)
snd_hdmi_show_eld(codec, &eld->info);
Expand Down Expand Up @@ -1884,11 +1907,11 @@ static void update_eld(struct hda_codec *codec,
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
}

if (eld_changed)
if (eld_changed && pcm_idx >= 0)
snd_ctl_notify(codec->card,
SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO,
&per_pin->eld_ctl->id);
&get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
}

/* update ELD and jack state via HD-audio verbs */
Expand Down Expand Up @@ -2629,17 +2652,16 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
snd_hda_spdif_ctls_unassign(codec, pcm_idx);
}

for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);

/* add control for ELD Bytes */
err = hdmi_create_eld_ctl(codec, pin_idx,
get_pcm_rec(spec, pin_idx)->device);

err = hdmi_create_eld_ctl(codec, pcm_idx,
get_pcm_rec(spec, pcm_idx)->device);
if (err < 0)
return err;
}

for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);

hdmi_present_sense(per_pin, 0);
}
Expand Down

0 comments on commit fb087ea

Please sign in to comment.