sound/x86/intel_hdmi_audio.c

Source file repositories/reference/linux-study-clean/sound/x86/intel_hdmi_audio.c

File Facts

System
Linux kernel
Corpus path
sound/x86/intel_hdmi_audio.c
Extension
.c
Size
50232 bytes
Lines
1829
Domain
Driver Families
Bucket
sound/x86
Inferred role
Driver Families: implementation source
Status
source 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 (p->speakers[j]) {
				p->channels++;
				p->spk_mask |= p->speakers[j];
			}
	}
}

/*
 * The transformation takes two steps:
 *
 *      eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
 *            spk_mask => (channel_allocations[])         => ai->CA
 *
 * TODO: it could select the wrong CA from multiple candidates.
 */
static int had_channel_allocation(struct snd_intelhad *intelhaddata,
				  int channels)
{
	int i;
	int ca = 0;
	int spk_mask = 0;

	/*
	 * CA defaults to 0 for basic stereo audio
	 */
	if (channels <= 2)
		return 0;

	/*
	 * expand ELD's speaker allocation mask
	 *
	 * ELD tells the speaker mask in a compact(paired) form,
	 * expand ELD's notions to match the ones used by Audio InfoFrame.
	 */

	for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
		if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
			spk_mask |= eld_speaker_allocation_bits[i];
	}

	/* search for the first working match in the CA table */
	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
		if (channels == channel_allocations[i].channels &&
		(spk_mask & channel_allocations[i].spk_mask) ==
				channel_allocations[i].spk_mask) {
			ca = channel_allocations[i].ca_index;
			break;
		}
	}

	dev_dbg(intelhaddata->dev, "select CA 0x%x for %d\n", ca, channels);

	return ca;
}

/* from speaker bit mask to ALSA API channel position */
static int spk_to_chmap(int spk)
{
	const struct channel_map_table *t = map_tables;

	for (; t->map; t++) {
		if (t->spk_mask == spk)
			return t->map;
	}
	return 0;
}

static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
{
	int i, c;
	int spk_mask = 0;
	struct snd_pcm_chmap_elem *chmap;
	u8 eld_high, eld_high_mask = 0xF0;
	u8 high_msb;

	kfree(intelhaddata->chmap->chmap);
	intelhaddata->chmap->chmap = NULL;

	chmap = kzalloc_obj(*chmap);
	if (!chmap)
		return;

	dev_dbg(intelhaddata->dev, "eld speaker = %x\n",
		intelhaddata->eld[DRM_ELD_SPEAKER]);

	/* WA: Fix the max channel supported to 8 */

	/*
	 * Sink may support more than 8 channels, if eld_high has more than
	 * one bit set. SOC supports max 8 channels.

Annotation

Implementation Notes