Summarize information about connected analog pins and EDID-like data received

from HDMI/DisplayPort devices in form of general connection status and
sound(4)-style channel matrix.  Now that information is only reported in
readable form to verbose logs, but potentially could be used by sound(4)
to correctly choose default devices and configure vchans.

Fix rear and side channels swap on analog 7.1 outputs.  As soon as there is
a huge mess in industry about naming and using of these channels, duplicate
rear channels of 4 and 5.1 streams to both read and side speakers.
This commit is contained in:
Alexander Motin 2012-11-17 06:33:13 +00:00
parent f447c9bf87
commit 6d36c821ad
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=243181

View File

@ -238,6 +238,142 @@ hdaa_audio_ctl_amp_get(struct hdaa_devinfo *devinfo, nid_t nid, int dir,
return (NULL);
}
static const struct matrix {
struct pcmchan_matrix m;
int analog;
} matrixes[] = {
{ SND_CHN_MATRIX_MAP_1_0, 1 },
{ SND_CHN_MATRIX_MAP_2_0, 1 },
{ SND_CHN_MATRIX_MAP_2_1, 0 },
{ SND_CHN_MATRIX_MAP_3_0, 0 },
{ SND_CHN_MATRIX_MAP_3_1, 0 },
{ SND_CHN_MATRIX_MAP_4_0, 1 },
{ SND_CHN_MATRIX_MAP_4_1, 0 },
{ SND_CHN_MATRIX_MAP_5_0, 0 },
{ SND_CHN_MATRIX_MAP_5_1, 1 },
{ SND_CHN_MATRIX_MAP_6_0, 0 },
{ SND_CHN_MATRIX_MAP_6_1, 0 },
{ SND_CHN_MATRIX_MAP_7_0, 0 },
{ SND_CHN_MATRIX_MAP_7_1, 1 },
};
static const char *channel_names[] = SND_CHN_T_NAMES;
/*
* Connected channels change handler.
*/
static void
hdaa_channels_handler(struct hdaa_audio_as *as)
{
struct hdaa_pcm_devinfo *pdevinfo = as->pdevinfo;
struct hdaa_devinfo *devinfo = pdevinfo->devinfo;
struct hdaa_chan *ch = &devinfo->chans[as->chans[0]];
struct hdaa_widget *w;
uint8_t *eld;
int i, total, sub, assume, channels;
uint16_t cpins, upins, tpins;
cpins = upins = 0;
eld = NULL;
for (i = 0; i < 16; i++) {
if (as->pins[i] <= 0)
continue;
w = hdaa_widget_get(devinfo, as->pins[i]);
if (w == NULL)
continue;
if (w->wclass.pin.connected == 1)
cpins |= (1 << i);
else if (w->wclass.pin.connected != 0)
upins |= (1 << i);
if (w->eld != NULL && w->eld_len >= 8)
eld = w->eld;
}
tpins = cpins | upins;
if (as->hpredir >= 0)
tpins &= 0x7fff;
if (tpins == 0)
tpins = as->pinset;
total = sub = assume = channels = 0;
if (eld) {
/* Map CEA speakers to sound(4) channels. */
if (eld[7] & 0x01) /* Front Left/Right */
channels |= SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FR;
if (eld[7] & 0x02) /* Low Frequency Effect */
channels |= SND_CHN_T_MASK_LF;
if (eld[7] & 0x04) /* Front Center */
channels |= SND_CHN_T_MASK_FC;
if (eld[7] & 0x08) { /* Rear Left/Right */
/* If we have both RLR and RLRC, report RLR as side. */
if (eld[7] & 0x40) /* Rear Left/Right Center */
channels |= SND_CHN_T_MASK_SL | SND_CHN_T_MASK_SR;
else
channels |= SND_CHN_T_MASK_BL | SND_CHN_T_MASK_BR;
}
if (eld[7] & 0x10) /* Rear center */
channels |= SND_CHN_T_MASK_BC;
if (eld[7] & 0x20) /* Front Left/Right Center */
channels |= SND_CHN_T_MASK_FLC | SND_CHN_T_MASK_FRC;
if (eld[7] & 0x40) /* Rear Left/Right Center */
channels |= SND_CHN_T_MASK_BL | SND_CHN_T_MASK_BR;
} else if (as->pinset != 0 && (tpins & 0xffe0) == 0) {
/* Map UAA speakers to sound(4) channels. */
if (tpins & 0x0001)
channels |= SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FR;
if (tpins & 0x0002)
channels |= SND_CHN_T_MASK_FC | SND_CHN_T_MASK_LF;
if (tpins & 0x0004)
channels |= SND_CHN_T_MASK_BL | SND_CHN_T_MASK_BR;
if (tpins & 0x0008)
channels |= SND_CHN_T_MASK_FLC | SND_CHN_T_MASK_FRC;
if (tpins & 0x0010) {
/* If there is no back pin, report side as back. */
if ((as->pinset & 0x0004) == 0)
channels |= SND_CHN_T_MASK_BL | SND_CHN_T_MASK_BR;
else
channels |= SND_CHN_T_MASK_SL | SND_CHN_T_MASK_SR;
}
} else if (as->mixed) {
/* Mixed assoc can be only stereo or theoretically mono. */
if (ch->channels == 1)
channels |= SND_CHN_T_MASK_FC;
else
channels |= SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FR;
}
if (channels) { /* We have some usable channels info. */
HDA_BOOTVERBOSE(
device_printf(pdevinfo->dev, "%s channel set is: ",
as->dir == HDAA_CTL_OUT ? "Playback" : "Recording");
for (i = 0; i < SND_CHN_T_MAX; i++)
if (channels & (1 << i))
printf("%s, ", channel_names[i]);
printf("\n");
);
/* Look for maximal fitting matrix. */
for (i = 0; i < sizeof(matrixes) / sizeof(struct matrix); i++) {
if (as->pinset != 0 && matrixes[i].analog == 0)
continue;
if ((matrixes[i].m.mask & ~channels) == 0) {
total = matrixes[i].m.channels;
sub = matrixes[i].m.ext;
}
}
}
if (total == 0) {
assume = 1;
total = ch->channels;
sub = (total == 6 || total == 8) ? 1 : 0;
}
HDA_BOOTVERBOSE(
device_printf(pdevinfo->dev,
"%s channel matrix is: %s%d.%d (%s)\n",
as->dir == HDAA_CTL_OUT ? "Playback" : "Recording",
assume ? "unknown, assuming " : "", total - sub, sub,
cpins != 0 ? "connected" :
(upins != 0 ? "unknown" : "disconnected"));
);
}
/*
* Headphones redirection change handler.
*/
@ -431,6 +567,8 @@ hdaa_presence_handler(struct hdaa_widget *w)
hdaa_hpredir_handler(w);
if (as->dir == HDAA_CTL_IN && old != 2)
hdaa_autorecsrc_handler(as, w);
if (old != 2)
hdaa_channels_handler(as);
}
/*
@ -598,6 +736,7 @@ hdaa_eld_handler(struct hdaa_widget *w)
HDA_BOOTVERBOSE(
hdaa_eld_dump(w);
);
hdaa_channels_handler(&devinfo->as[w->bindas]);
}
/*
@ -1455,14 +1594,17 @@ hdaa_audio_setup(struct hdaa_chan *ch)
uint16_t fmt, dfmt;
/* Mapping channel pairs to codec pins/converters. */
const static uint16_t convmap[2][5] =
{{ 0x0010, 0x0001, 0x0201, 0x0231, 0x0231 }, /* 5.1 */
{ 0x0010, 0x0001, 0x2001, 0x2031, 0x2431 }};/* 7.1 */
/* 1.0 2.0 4.0 5.1 7.1 */
{{ 0x0010, 0x0001, 0x0201, 0x0231, 0x4231 }, /* no dup. */
{ 0x0010, 0x0001, 0x2201, 0x2231, 0x4231 }}; /* side dup. */
/* Mapping formats to HDMI channel allocations. */
const static uint8_t hdmica[2][8] =
/* 1 2 3 4 5 6 7 8 */
{{ 0x02, 0x00, 0x04, 0x08, 0x0a, 0x0e, 0x12, 0x12 }, /* x.0 */
{ 0x01, 0x03, 0x01, 0x03, 0x09, 0x0b, 0x0f, 0x13 }}; /* x.1 */
/* Mapping formats to HDMI channels order. */
const static uint32_t hdmich[2][8] =
/* 1 / 5 2 / 6 3 / 7 4 / 8 */
{{ 0xFFFF0F00, 0xFFFFFF10, 0xFFF2FF10, 0xFF32FF10,
0xFF324F10, 0xF5324F10, 0x54326F10, 0x54326F10 }, /* x.0 */
{ 0xFFFFF000, 0xFFFF0100, 0xFFFFF210, 0xFFFF2310,
@ -1482,10 +1624,9 @@ hdaa_audio_setup(struct hdaa_chan *ch)
fmt = hdaa_stream_format(ch);
/* Set channels to I/O converters mapping for known speaker setups. */
if ((as->pinset == 0x0007 || as->pinset == 0x0013)) /* Standard 5.1 */
convmapid = 0;
else if (as->pinset == 0x0017) /* Standard 7.1 */
convmapid = 1;
if ((as->pinset == 0x0007 || as->pinset == 0x0013) || /* Standard 5.1 */
(as->pinset == 0x0017)) /* Standard 7.1 */
convmapid = (ch->dir == PCMDIR_PLAY);
dfmt = HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN;
if (ch->fmt & AFMT_AC3)
@ -6750,12 +6891,17 @@ hdaa_pcm_attach(device_t dev)
if (pdevinfo->mixer != NULL) {
hdaa_audio_ctl_set_defaults(pdevinfo);
hdaa_lock(devinfo);
if (pdevinfo->playas >= 0) {
as = &devinfo->as[pdevinfo->playas];
hdaa_channels_handler(as);
}
if (pdevinfo->recas >= 0) {
as = &devinfo->as[pdevinfo->recas];
hdaa_lock(devinfo);
hdaa_autorecsrc_handler(as, NULL);
hdaa_unlock(devinfo);
hdaa_channels_handler(as);
}
hdaa_unlock(devinfo);
}
snprintf(status, SND_STATUSLEN, "on %s %s",