sound/hda/codecs/hdmi/hdmi.c

Source file repositories/reference/linux-study-clean/sound/hda/codecs/hdmi/hdmi.c

File Facts

System
Linux kernel
Corpus path
sound/hda/codecs/hdmi/hdmi.c
Extension
.c
Size
64965 bytes
Lines
2372
Domain
Driver Families
Bucket
sound/hda
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (conn_type == 0) { /* HDMI */
			hdmi_ai->type		= 0x84;
			hdmi_ai->ver		= 0x01;
			hdmi_ai->len		= 0x0a;
		} else {/* Nvidia DP */
			hdmi_ai->type		= 0x84;
			hdmi_ai->ver		= 0x1b;
			hdmi_ai->len		= 0x11 << 2;
		}
		hdmi_ai->CC02_CT47	= active_channels - 1;
		hdmi_ai->CA		= ca;
		hdmi_checksum_audio_infoframe(hdmi_ai);
	} else if (conn_type == 1) { /* DisplayPort */
		struct dp_audio_infoframe *dp_ai = &ai.dp;

		dp_ai->type		= 0x84;
		dp_ai->len		= 0x1b;
		dp_ai->ver		= 0x11 << 2;
		dp_ai->CC02_CT47	= active_channels - 1;
		dp_ai->CA		= ca;
	} else {
		codec_dbg(codec, "HDMI: unknown connection type at pin NID 0x%x\n", pin_nid);
		return;
	}

	snd_hda_set_dev_select(codec, pin_nid, dev_id);

	/*
	 * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
	 * sizeof(*dp_ai) to avoid partial match/update problems when
	 * the user switches between HDMI/DP monitors.
	 */
	if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
					sizeof(ai))) {
		codec_dbg(codec, "%s: pin NID=0x%x channels=%d ca=0x%02x\n",
			  __func__, pin_nid, active_channels, ca);
		hdmi_stop_infoframe_trans(codec, pin_nid);
		hdmi_fill_audio_infoframe(codec, pin_nid,
					    ai.bytes, sizeof(ai));
		hdmi_start_infoframe_trans(codec, pin_nid);
	}
}

void snd_hda_hdmi_setup_audio_infoframe(struct hda_codec *codec,
					struct hdmi_spec_per_pin *per_pin,
					bool non_pcm)
{
	struct hdmi_spec *spec = codec->spec;
	struct hdac_chmap *chmap = &spec->chmap;
	hda_nid_t pin_nid = per_pin->pin_nid;
	int dev_id = per_pin->dev_id;
	int channels = per_pin->channels;
	int active_channels;
	struct hdmi_eld *eld;
	int ca;

	if (!channels)
		return;

	snd_hda_set_dev_select(codec, pin_nid, dev_id);

	/* some HW (e.g. HSW+) needs reprogramming the amp at each time */
	if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
		snd_hda_codec_write(codec, pin_nid, 0,
					    AC_VERB_SET_AMP_GAIN_MUTE,
					    AMP_OUT_UNMUTE);

	eld = &per_pin->sink_eld;

	ca = snd_hdac_channel_allocation(&codec->core,
			eld->info.spk_alloc, channels,
			per_pin->chmap_set, non_pcm, per_pin->chmap);

	active_channels = snd_hdac_get_active_channels(ca);

	chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid,
						active_channels);

	/*
	 * always configure channel mapping, it may have been changed by the
	 * user in the meantime
	 */
	snd_hdac_setup_channel_mapping(&spec->chmap,
				pin_nid, non_pcm, ca, channels,
				per_pin->chmap, per_pin->chmap_set);

	spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id,
				      ca, active_channels, eld->info.conn_type);

	per_pin->non_pcm = non_pcm;

Annotation

Implementation Notes