diff options
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 97 |
1 files changed, 67 insertions, 30 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e2cf02387289..20f7762f7144 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -432,22 +432,26 @@ void snd_hda_get_codec_name(struct hda_codec *codec, | |||
432 | } | 432 | } |
433 | 433 | ||
434 | /* | 434 | /* |
435 | * look for an AFG node | 435 | * look for an AFG and MFG nodes |
436 | * | ||
437 | * return 0 if not found | ||
438 | */ | 436 | */ |
439 | static int look_for_afg_node(struct hda_codec *codec) | 437 | static void setup_fg_nodes(struct hda_codec *codec) |
440 | { | 438 | { |
441 | int i, total_nodes; | 439 | int i, total_nodes; |
442 | hda_nid_t nid; | 440 | hda_nid_t nid; |
443 | 441 | ||
444 | total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); | 442 | total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); |
445 | for (i = 0; i < total_nodes; i++, nid++) { | 443 | for (i = 0; i < total_nodes; i++, nid++) { |
446 | if ((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff) == | 444 | switch((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff)) { |
447 | AC_GRP_AUDIO_FUNCTION) | 445 | case AC_GRP_AUDIO_FUNCTION: |
448 | return nid; | 446 | codec->afg = nid; |
447 | break; | ||
448 | case AC_GRP_MODEM_FUNCTION: | ||
449 | codec->mfg = nid; | ||
450 | break; | ||
451 | default: | ||
452 | break; | ||
453 | } | ||
449 | } | 454 | } |
450 | return 0; | ||
451 | } | 455 | } |
452 | 456 | ||
453 | /* | 457 | /* |
@@ -507,10 +511,9 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
507 | codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID); | 511 | codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID); |
508 | codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID); | 512 | codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID); |
509 | 513 | ||
510 | /* FIXME: support for multiple AFGs? */ | 514 | setup_fg_nodes(codec); |
511 | codec->afg = look_for_afg_node(codec); | 515 | if (! codec->afg && ! codec->mfg) { |
512 | if (! codec->afg) { | 516 | snd_printdd("hda_codec: no AFG or MFG node found\n"); |
513 | snd_printdd("hda_codec: no AFG node found\n"); | ||
514 | snd_hda_codec_free(codec); | 517 | snd_hda_codec_free(codec); |
515 | return -ENODEV; | 518 | return -ENODEV; |
516 | } | 519 | } |
@@ -749,12 +752,14 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
749 | long *valp = ucontrol->value.integer.value; | 752 | long *valp = ucontrol->value.integer.value; |
750 | int change = 0; | 753 | int change = 0; |
751 | 754 | ||
752 | if (chs & 1) | 755 | if (chs & 1) { |
753 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, | 756 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
754 | 0x7f, *valp); | 757 | 0x7f, *valp); |
758 | valp++; | ||
759 | } | ||
755 | if (chs & 2) | 760 | if (chs & 2) |
756 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, | 761 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
757 | 0x7f, valp[1]); | 762 | 0x7f, *valp); |
758 | return change; | 763 | return change; |
759 | } | 764 | } |
760 | 765 | ||
@@ -796,12 +801,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
796 | long *valp = ucontrol->value.integer.value; | 801 | long *valp = ucontrol->value.integer.value; |
797 | int change = 0; | 802 | int change = 0; |
798 | 803 | ||
799 | if (chs & 1) | 804 | if (chs & 1) { |
800 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, | 805 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
801 | 0x80, *valp ? 0 : 0x80); | 806 | 0x80, *valp ? 0 : 0x80); |
807 | valp++; | ||
808 | } | ||
802 | if (chs & 2) | 809 | if (chs & 2) |
803 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, | 810 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
804 | 0x80, valp[1] ? 0 : 0x80); | 811 | 0x80, *valp ? 0 : 0x80); |
812 | |||
805 | return change; | 813 | return change; |
806 | } | 814 | } |
807 | 815 | ||
@@ -1155,8 +1163,16 @@ int snd_hda_build_controls(struct hda_bus *bus) | |||
1155 | /* | 1163 | /* |
1156 | * stream formats | 1164 | * stream formats |
1157 | */ | 1165 | */ |
1158 | static unsigned int rate_bits[][3] = { | 1166 | struct hda_rate_tbl { |
1167 | unsigned int hz; | ||
1168 | unsigned int alsa_bits; | ||
1169 | unsigned int hda_fmt; | ||
1170 | }; | ||
1171 | |||
1172 | static struct hda_rate_tbl rate_bits[] = { | ||
1159 | /* rate in Hz, ALSA rate bitmask, HDA format value */ | 1173 | /* rate in Hz, ALSA rate bitmask, HDA format value */ |
1174 | |||
1175 | /* autodetected value used in snd_hda_query_supported_pcm */ | ||
1160 | { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */ | 1176 | { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */ |
1161 | { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */ | 1177 | { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */ |
1162 | { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */ | 1178 | { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */ |
@@ -1168,7 +1184,11 @@ static unsigned int rate_bits[][3] = { | |||
1168 | { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */ | 1184 | { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */ |
1169 | { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */ | 1185 | { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */ |
1170 | { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */ | 1186 | { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */ |
1171 | { 0 } | 1187 | |
1188 | /* not autodetected value */ | ||
1189 | { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */ | ||
1190 | |||
1191 | { 0 } /* terminator */ | ||
1172 | }; | 1192 | }; |
1173 | 1193 | ||
1174 | /** | 1194 | /** |
@@ -1190,12 +1210,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, | |||
1190 | int i; | 1210 | int i; |
1191 | unsigned int val = 0; | 1211 | unsigned int val = 0; |
1192 | 1212 | ||
1193 | for (i = 0; rate_bits[i][0]; i++) | 1213 | for (i = 0; rate_bits[i].hz; i++) |
1194 | if (rate_bits[i][0] == rate) { | 1214 | if (rate_bits[i].hz == rate) { |
1195 | val = rate_bits[i][2]; | 1215 | val = rate_bits[i].hda_fmt; |
1196 | break; | 1216 | break; |
1197 | } | 1217 | } |
1198 | if (! rate_bits[i][0]) { | 1218 | if (! rate_bits[i].hz) { |
1199 | snd_printdd("invalid rate %d\n", rate); | 1219 | snd_printdd("invalid rate %d\n", rate); |
1200 | return 0; | 1220 | return 0; |
1201 | } | 1221 | } |
@@ -1258,9 +1278,9 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
1258 | 1278 | ||
1259 | if (ratesp) { | 1279 | if (ratesp) { |
1260 | u32 rates = 0; | 1280 | u32 rates = 0; |
1261 | for (i = 0; rate_bits[i][0]; i++) { | 1281 | for (i = 0; rate_bits[i].hz; i++) { |
1262 | if (val & (1 << i)) | 1282 | if (val & (1 << i)) |
1263 | rates |= rate_bits[i][1]; | 1283 | rates |= rate_bits[i].alsa_bits; |
1264 | } | 1284 | } |
1265 | *ratesp = rates; | 1285 | *ratesp = rates; |
1266 | } | 1286 | } |
@@ -1352,13 +1372,13 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
1352 | } | 1372 | } |
1353 | 1373 | ||
1354 | rate = format & 0xff00; | 1374 | rate = format & 0xff00; |
1355 | for (i = 0; rate_bits[i][0]; i++) | 1375 | for (i = 0; rate_bits[i].hz; i++) |
1356 | if (rate_bits[i][2] == rate) { | 1376 | if (rate_bits[i].hda_fmt == rate) { |
1357 | if (val & (1 << i)) | 1377 | if (val & (1 << i)) |
1358 | break; | 1378 | break; |
1359 | return 0; | 1379 | return 0; |
1360 | } | 1380 | } |
1361 | if (! rate_bits[i][0]) | 1381 | if (! rate_bits[i].hz) |
1362 | return 0; | 1382 | return 0; |
1363 | 1383 | ||
1364 | stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | 1384 | stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); |
@@ -1541,8 +1561,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_c | |||
1541 | for (c = tbl; c->modelname || c->pci_subvendor; c++) { | 1561 | for (c = tbl; c->modelname || c->pci_subvendor; c++) { |
1542 | if (c->pci_subvendor == subsystem_vendor && | 1562 | if (c->pci_subvendor == subsystem_vendor && |
1543 | (! c->pci_subdevice /* all match */|| | 1563 | (! c->pci_subdevice /* all match */|| |
1544 | (c->pci_subdevice == subsystem_device))) | 1564 | (c->pci_subdevice == subsystem_device))) { |
1565 | snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n", | ||
1566 | subsystem_vendor, subsystem_device, c->config); | ||
1545 | return c->config; | 1567 | return c->config; |
1568 | } | ||
1546 | } | 1569 | } |
1547 | } | 1570 | } |
1548 | return -1; | 1571 | return -1; |
@@ -1803,11 +1826,25 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c | |||
1803 | cfg->line_out_pins[j] = nid; | 1826 | cfg->line_out_pins[j] = nid; |
1804 | } | 1827 | } |
1805 | 1828 | ||
1806 | /* Swap surround and CLFE: the association order is front/CLFE/surr/back */ | 1829 | /* Reorder the surround channels |
1807 | if (cfg->line_outs >= 3) { | 1830 | * ALSA sequence is front/surr/clfe/side |
1831 | * HDA sequence is: | ||
1832 | * 4-ch: front/surr => OK as it is | ||
1833 | * 6-ch: front/clfe/surr | ||
1834 | * 8-ch: front/clfe/side/surr | ||
1835 | */ | ||
1836 | switch (cfg->line_outs) { | ||
1837 | case 3: | ||
1808 | nid = cfg->line_out_pins[1]; | 1838 | nid = cfg->line_out_pins[1]; |
1809 | cfg->line_out_pins[1] = cfg->line_out_pins[2]; | 1839 | cfg->line_out_pins[1] = cfg->line_out_pins[2]; |
1810 | cfg->line_out_pins[2] = nid; | 1840 | cfg->line_out_pins[2] = nid; |
1841 | break; | ||
1842 | case 4: | ||
1843 | nid = cfg->line_out_pins[1]; | ||
1844 | cfg->line_out_pins[1] = cfg->line_out_pins[3]; | ||
1845 | cfg->line_out_pins[3] = cfg->line_out_pins[2]; | ||
1846 | cfg->line_out_pins[2] = nid; | ||
1847 | break; | ||
1811 | } | 1848 | } |
1812 | 1849 | ||
1813 | return 0; | 1850 | return 0; |