diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-05-12 08:51:12 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-05-29 04:08:36 -0400 |
commit | 2fa522bed875cf0bde9e9fdb8fdd852c9d74d67d (patch) | |
tree | b366a3f37c9f422a563817f78322823f933297a0 /sound/pci | |
parent | dfc0ff62a1d24e987205b41fbf322a4377626481 (diff) |
[ALSA] Add test model for debugging ALC880 devices
HDA Codec driver
Added 'test' model for testing/debugging the devices with ALC880 codec.
This model is built only when CONFIG_SND_DEBUG is set.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 271 |
1 files changed, 270 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c106e1fe01cf..75ec1970cc0a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -40,6 +40,7 @@ enum { | |||
40 | ALC880_5ST_DIG, | 40 | ALC880_5ST_DIG, |
41 | ALC880_W810, | 41 | ALC880_W810, |
42 | ALC880_Z71V, | 42 | ALC880_Z71V, |
43 | ALC880_TEST, | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | struct alc_spec { | 46 | struct alc_spec { |
@@ -1012,6 +1013,248 @@ static struct hda_codec_ops alc_patch_ops = { | |||
1012 | #endif | 1013 | #endif |
1013 | }; | 1014 | }; |
1014 | 1015 | ||
1016 | |||
1017 | /* | ||
1018 | * Test configuration for debugging | ||
1019 | * | ||
1020 | * Almost all inputs/outputs are enabled. I/O pins can be configured via | ||
1021 | * enum controls. | ||
1022 | */ | ||
1023 | #ifdef CONFIG_SND_DEBUG | ||
1024 | static hda_nid_t alc880_test_dac_nids[4] = { | ||
1025 | 0x02, 0x03, 0x04, 0x05 | ||
1026 | }; | ||
1027 | |||
1028 | static struct hda_input_mux alc880_test_capture_source = { | ||
1029 | .num_items = 5, | ||
1030 | .items = { | ||
1031 | { "In-1", 0x0 }, | ||
1032 | { "In-2", 0x1 }, | ||
1033 | { "In-3", 0x2 }, | ||
1034 | { "In-4", 0x3 }, | ||
1035 | { "CD", 0x4 }, | ||
1036 | }, | ||
1037 | }; | ||
1038 | |||
1039 | static struct alc_channel_mode alc880_test_modes[2] = { | ||
1040 | { 2, NULL }, | ||
1041 | { 6, NULL }, | ||
1042 | }; | ||
1043 | |||
1044 | static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
1045 | { | ||
1046 | static char *texts[] = { | ||
1047 | "N/A", "Line Out", "HP Out", | ||
1048 | "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" | ||
1049 | }; | ||
1050 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1051 | uinfo->count = 1; | ||
1052 | uinfo->value.enumerated.items = 8; | ||
1053 | if (uinfo->value.enumerated.item >= 8) | ||
1054 | uinfo->value.enumerated.item = 7; | ||
1055 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | static int alc_test_pin_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1060 | { | ||
1061 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1062 | hda_nid_t nid = (hda_nid_t)kcontrol->private_value; | ||
1063 | unsigned int pin_ctl, item = 0; | ||
1064 | |||
1065 | pin_ctl = snd_hda_codec_read(codec, nid, 0, | ||
1066 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
1067 | if (pin_ctl & AC_PINCTL_OUT_EN) { | ||
1068 | if (pin_ctl & AC_PINCTL_HP_EN) | ||
1069 | item = 2; | ||
1070 | else | ||
1071 | item = 1; | ||
1072 | } else if (pin_ctl & AC_PINCTL_IN_EN) { | ||
1073 | switch (pin_ctl & AC_PINCTL_VREFEN) { | ||
1074 | case AC_PINCTL_VREF_HIZ: item = 3; break; | ||
1075 | case AC_PINCTL_VREF_50: item = 4; break; | ||
1076 | case AC_PINCTL_VREF_GRD: item = 5; break; | ||
1077 | case AC_PINCTL_VREF_80: item = 6; break; | ||
1078 | case AC_PINCTL_VREF_100: item = 7; break; | ||
1079 | } | ||
1080 | } | ||
1081 | ucontrol->value.enumerated.item[0] = item; | ||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | static int alc_test_pin_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1086 | { | ||
1087 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1088 | hda_nid_t nid = (hda_nid_t)kcontrol->private_value; | ||
1089 | static unsigned int ctls[] = { | ||
1090 | 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, | ||
1091 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, | ||
1092 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, | ||
1093 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, | ||
1094 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, | ||
1095 | AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, | ||
1096 | }; | ||
1097 | unsigned int old_ctl, new_ctl; | ||
1098 | |||
1099 | old_ctl = snd_hda_codec_read(codec, nid, 0, | ||
1100 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
1101 | new_ctl = ctls[ucontrol->value.enumerated.item[0]]; | ||
1102 | if (old_ctl != new_ctl) { | ||
1103 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); | ||
1104 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1105 | ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000); | ||
1106 | return 1; | ||
1107 | } | ||
1108 | return 0; | ||
1109 | } | ||
1110 | |||
1111 | static int alc_test_pin_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
1112 | { | ||
1113 | static char *texts[] = { | ||
1114 | "Front", "Surround", "CLFE", "Side" | ||
1115 | }; | ||
1116 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1117 | uinfo->count = 1; | ||
1118 | uinfo->value.enumerated.items = 4; | ||
1119 | if (uinfo->value.enumerated.item >= 4) | ||
1120 | uinfo->value.enumerated.item = 3; | ||
1121 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1122 | return 0; | ||
1123 | } | ||
1124 | |||
1125 | static int alc_test_pin_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1126 | { | ||
1127 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1128 | hda_nid_t nid = (hda_nid_t)kcontrol->private_value; | ||
1129 | unsigned int sel; | ||
1130 | |||
1131 | sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); | ||
1132 | ucontrol->value.enumerated.item[0] = sel & 3; | ||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1137 | { | ||
1138 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1139 | hda_nid_t nid = (hda_nid_t)kcontrol->private_value; | ||
1140 | unsigned int sel; | ||
1141 | |||
1142 | sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; | ||
1143 | if (ucontrol->value.enumerated.item[0] != sel) { | ||
1144 | sel = ucontrol->value.enumerated.item[0] & 3; | ||
1145 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); | ||
1146 | return 1; | ||
1147 | } | ||
1148 | return 0; | ||
1149 | } | ||
1150 | |||
1151 | #define PIN_CTL_TEST(xname,nid) { \ | ||
1152 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1153 | .name = xname, \ | ||
1154 | .info = alc_test_pin_ctl_info, \ | ||
1155 | .get = alc_test_pin_ctl_get, \ | ||
1156 | .put = alc_test_pin_ctl_put, \ | ||
1157 | .private_value = nid \ | ||
1158 | } | ||
1159 | |||
1160 | #define PIN_SRC_TEST(xname,nid) { \ | ||
1161 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1162 | .name = xname, \ | ||
1163 | .info = alc_test_pin_src_info, \ | ||
1164 | .get = alc_test_pin_src_get, \ | ||
1165 | .put = alc_test_pin_src_put, \ | ||
1166 | .private_value = nid \ | ||
1167 | } | ||
1168 | |||
1169 | static snd_kcontrol_new_t alc880_test_mixer[] = { | ||
1170 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1171 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
1172 | HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), | ||
1173 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
1174 | PIN_CTL_TEST("Front Pin Mode", 0x14), | ||
1175 | PIN_CTL_TEST("Surround Pin Mode", 0x15), | ||
1176 | PIN_CTL_TEST("CLFE Pin Mode", 0x16), | ||
1177 | PIN_CTL_TEST("Side Pin Mode", 0x17), | ||
1178 | PIN_CTL_TEST("In-1 Pin Mode", 0x18), | ||
1179 | PIN_CTL_TEST("In-2 Pin Mode", 0x19), | ||
1180 | PIN_CTL_TEST("In-3 Pin Mode", 0x1a), | ||
1181 | PIN_CTL_TEST("In-4 Pin Mode", 0x1b), | ||
1182 | PIN_SRC_TEST("In-1 Pin Source", 0x18), | ||
1183 | PIN_SRC_TEST("In-2 Pin Source", 0x19), | ||
1184 | PIN_SRC_TEST("In-3 Pin Source", 0x1a), | ||
1185 | PIN_SRC_TEST("In-4 Pin Source", 0x1b), | ||
1186 | HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
1187 | HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
1188 | HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
1189 | HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
1190 | HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), | ||
1191 | HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), | ||
1192 | HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), | ||
1193 | HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), | ||
1194 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), | ||
1195 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), | ||
1196 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
1197 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
1198 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
1199 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
1200 | { | ||
1201 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1202 | .name = "Input Source", | ||
1203 | .count = 2, | ||
1204 | .info = alc_mux_enum_info, | ||
1205 | .get = alc_mux_enum_get, | ||
1206 | .put = alc_mux_enum_put, | ||
1207 | }, | ||
1208 | { | ||
1209 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1210 | .name = "Channel Mode", | ||
1211 | .info = alc880_ch_mode_info, | ||
1212 | .get = alc880_ch_mode_get, | ||
1213 | .put = alc880_ch_mode_put, | ||
1214 | }, | ||
1215 | { } /* end */ | ||
1216 | }; | ||
1217 | |||
1218 | static struct hda_verb alc880_test_init_verbs[] = { | ||
1219 | /* Unmute inputs of 0x0c - 0x0f */ | ||
1220 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
1221 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, | ||
1222 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
1223 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, | ||
1224 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
1225 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, | ||
1226 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
1227 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, | ||
1228 | /* Vol output for 0x0c-0x0f */ | ||
1229 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1230 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1231 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1232 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1233 | /* Set output pins 0x14-0x17 */ | ||
1234 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1235 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1236 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1237 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1238 | /* Unmute output pins 0x14-0x17 */ | ||
1239 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1240 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1241 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1242 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1243 | /* Set input pins 0x18-0x1c */ | ||
1244 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* vref 80% */ | ||
1245 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
1246 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1247 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1248 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1249 | /* Mute input pins 0x18-0x1b */ | ||
1250 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1251 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1252 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1253 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1254 | { } | ||
1255 | }; | ||
1256 | #endif | ||
1257 | |||
1015 | /* | 1258 | /* |
1016 | */ | 1259 | */ |
1017 | 1260 | ||
@@ -1087,6 +1330,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
1087 | { .modelname = "z71v", .config = ALC880_Z71V }, | 1330 | { .modelname = "z71v", .config = ALC880_Z71V }, |
1088 | { .pci_vendor = 0x1043, .pci_device = 0x1964, .config = ALC880_Z71V }, | 1331 | { .pci_vendor = 0x1043, .pci_device = 0x1964, .config = ALC880_Z71V }, |
1089 | 1332 | ||
1333 | #ifdef CONFIG_SND_DEBUG | ||
1334 | { .modelname = "test", .config = ALC880_TEST }, | ||
1335 | #endif | ||
1336 | |||
1090 | {} | 1337 | {} |
1091 | }; | 1338 | }; |
1092 | 1339 | ||
@@ -1121,6 +1368,12 @@ static int patch_alc880(struct hda_codec *codec) | |||
1121 | spec->mixers[spec->num_mixers] = alc880_z71v_mixer; | 1368 | spec->mixers[spec->num_mixers] = alc880_z71v_mixer; |
1122 | spec->num_mixers++; | 1369 | spec->num_mixers++; |
1123 | break; | 1370 | break; |
1371 | #ifdef CONFIG_SND_DEBUG | ||
1372 | case ALC880_TEST: | ||
1373 | spec->mixers[spec->num_mixers] = alc880_test_mixer; | ||
1374 | spec->num_mixers++; | ||
1375 | break; | ||
1376 | #endif | ||
1124 | default: | 1377 | default: |
1125 | spec->mixers[spec->num_mixers] = alc880_base_mixer; | 1378 | spec->mixers[spec->num_mixers] = alc880_base_mixer; |
1126 | spec->num_mixers++; | 1379 | spec->num_mixers++; |
@@ -1132,6 +1385,7 @@ static int patch_alc880(struct hda_codec *codec) | |||
1132 | case ALC880_5ST_DIG: | 1385 | case ALC880_5ST_DIG: |
1133 | case ALC880_W810: | 1386 | case ALC880_W810: |
1134 | case ALC880_Z71V: | 1387 | case ALC880_Z71V: |
1388 | case ALC880_TEST: | ||
1135 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; | 1389 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; |
1136 | break; | 1390 | break; |
1137 | default: | 1391 | default: |
@@ -1167,6 +1421,13 @@ static int patch_alc880(struct hda_codec *codec) | |||
1167 | spec->channel_mode = alc880_z71v_modes; | 1421 | spec->channel_mode = alc880_z71v_modes; |
1168 | spec->num_channel_mode = ARRAY_SIZE(alc880_z71v_modes); | 1422 | spec->num_channel_mode = ARRAY_SIZE(alc880_z71v_modes); |
1169 | break; | 1423 | break; |
1424 | #ifdef CONFIG_SND_DEBUG | ||
1425 | case ALC880_TEST: | ||
1426 | spec->init_verbs = alc880_test_init_verbs; | ||
1427 | spec->channel_mode = alc880_test_modes; | ||
1428 | spec->num_channel_mode = ARRAY_SIZE(alc880_test_modes); | ||
1429 | break; | ||
1430 | #endif | ||
1170 | default: | 1431 | default: |
1171 | spec->init_verbs = alc880_init_verbs_three_stack; | 1432 | spec->init_verbs = alc880_init_verbs_three_stack; |
1172 | spec->channel_mode = alc880_threestack_modes; | 1433 | spec->channel_mode = alc880_threestack_modes; |
@@ -1195,6 +1456,13 @@ static int patch_alc880(struct hda_codec *codec) | |||
1195 | spec->multiout.dac_nids = alc880_z71v_dac_nids; | 1456 | spec->multiout.dac_nids = alc880_z71v_dac_nids; |
1196 | spec->multiout.hp_nid = 0x03; | 1457 | spec->multiout.hp_nid = 0x03; |
1197 | break; | 1458 | break; |
1459 | #ifdef CONFIG_SND_DEBUG | ||
1460 | case ALC880_TEST: | ||
1461 | spec->multiout.num_dacs = ARRAY_SIZE(alc880_test_dac_nids); | ||
1462 | spec->multiout.dac_nids = alc880_test_dac_nids; | ||
1463 | spec->input_mux = &alc880_test_capture_source; | ||
1464 | break; | ||
1465 | #endif | ||
1198 | default: | 1466 | default: |
1199 | spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); | 1467 | spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); |
1200 | spec->multiout.dac_nids = alc880_dac_nids; | 1468 | spec->multiout.dac_nids = alc880_dac_nids; |
@@ -1202,7 +1470,8 @@ static int patch_alc880(struct hda_codec *codec) | |||
1202 | break; | 1470 | break; |
1203 | } | 1471 | } |
1204 | 1472 | ||
1205 | spec->input_mux = &alc880_capture_source; | 1473 | if (! spec->input_mux) |
1474 | spec->input_mux = &alc880_capture_source; | ||
1206 | spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); | 1475 | spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); |
1207 | spec->adc_nids = alc880_adc_nids; | 1476 | spec->adc_nids = alc880_adc_nids; |
1208 | 1477 | ||