extractedLnx/linux-2.5.75/sound/pci/ac97/ac97_codec.c_snd_ac97_mixer_build.c
static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
{
snd_kcontrol_t *kctl;
const snd_kcontrol_new_t *knew;
int err;
unsigned int idx;
unsigned char max;
/* build master controls */
/* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_master[0], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_master[1], ac97))) < 0)
return err;
snd_ac97_change_volume_params1(ac97, AC97_MASTER, &max);
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= (int)max << 16;
snd_ac97_write_cache(ac97, AC97_MASTER, 0x8000 | max | (max << 8));
}
ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080;
/* build center controls */
if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97))) < 0)
return err;
snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max);
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= (int)max << 16;
snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max);
}
/* build LFE controls */
if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97))) < 0)
return err;
snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max);
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= (int)max << 16;
snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8);
}
/* build surround controls */
if (snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_surround[0], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_surround[1], ac97))) < 0)
return err;
snd_ac97_change_volume_params2(ac97, AC97_SURROUND_MASTER, 0, &max);
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= (int)max << 16;
snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x8080 | max | (max << 8));
}
/* build headphone controls */
if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE) || ac97->id == AC97_ID_STAC9708) {
knew = ac97->id == AC97_ID_STAC9708 ? snd_ac97_sigmatel_surround : snd_ac97_controls_headphone;
if ((err = snd_ctl_add(card, snd_ac97_cnew(knew, ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(knew + 1, ac97))) < 0)
return err;
snd_ac97_change_volume_params1(ac97, AC97_HEADPHONE, &max);
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= (int)max << 16;
snd_ac97_write_cache(ac97, AC97_HEADPHONE, 0x8000 | max | (max << 8));
}
/* build master mono controls */
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_master_mono[0], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_master_mono[1], ac97))) < 0)
return err;
snd_ac97_change_volume_params1(ac97, AC97_MASTER_MONO, &max);
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= (int)max << 16;
snd_ac97_write_cache(ac97, AC97_MASTER_MONO, 0x8000 | max);
}
/* build master tone controls */
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
for (idx = 0; idx < 2; idx++) {
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
return err;
if (ac97->id == AC97_ID_YMF753) {
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= 7 << 16;
}
}
snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
}
/* build PC Speaker controls */
if ((ac97->flags & AC97_HAS_PC_BEEP) ||
snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP)) {
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
return err;
snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);
}
/* build Phone controls */
if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_phone[0], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_phone[1], ac97))) < 0)
return err;
snd_ac97_change_volume_params3(ac97, AC97_PHONE, &max);
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= (int)max << 16;
snd_ac97_write_cache(ac97, AC97_PHONE, 0x8000 | max);
}
/* build MIC controls */
snd_ac97_change_volume_params3(ac97, AC97_MIC, &max);
for (idx = 0; idx < 3; idx++) {
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0)
return err;
if (idx == 1) { // volume
kctl->private_value &= ~(0xff << 16);
kctl->private_value |= (int)max << 16;
}
}
snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max);
/* build Line controls */
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_line[idx], ac97))) < 0)
return err;
snd_ac97_write_cache(ac97, AC97_LINE, 0x9f1f);
/* build CD controls */
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_cd[idx], ac97))) < 0)
return err;
snd_ac97_write_cache(ac97, AC97_CD, 0x9f1f);
/* build Video controls */
if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_video[idx], ac97))) < 0)
return err;
snd_ac97_write_cache(ac97, AC97_VIDEO, 0x9f1f);
}
/* build Aux controls */
if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_aux[idx], ac97))) < 0)
return err;
snd_ac97_write_cache(ac97, AC97_AUX, 0x9f1f);
}
/* build PCM controls */
if (ac97->flags & AC97_AD_MULTI) {
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0)
return err;
ac97->spec.ad18xx.pcmreg[0] = 0x9f1f;
if (ac97->scaps & AC97_SCAP_SURROUND_DAC) {
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0)
return err;
ac97->spec.ad18xx.pcmreg[1] = 0x9f1f;
}
if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) {
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[0], ac97))) < 0)
return err;
ac97->spec.ad18xx.pcmreg[2] = 0x9f1f;
}
} else {
unsigned int pcm_ctrls = 2;
/* FIXME: C-Media chips have no PCM volume!! */
if (/*ac97->id == 0x434d4941 ||*/
ac97->id == 0x434d4942 ||
ac97->id == 0x434d4961)
pcm_ctrls = 1;
for (idx = 0; idx < pcm_ctrls; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pcm[idx], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f);
/* build Capture controls */
for (idx = 0; idx < 3; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_capture[idx], ac97))) < 0)
return err;
snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000);
snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000);
/* build MIC Capture controls */
if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) {
for (idx = 0; idx < 2; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0)
return err;
snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000);
}
/* build PCM out path & mute control */
if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 15)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_PCM_OUT], ac97))) < 0)
return err;
}
/* build Simulated Stereo Enhancement control */
if (ac97->caps & 0x0008) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_STEREO_ENHANCEMENT], ac97))) < 0)
return err;
}
/* build 3D Stereo Enhancement control */
if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 13)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_3D], ac97))) < 0)
return err;
}
/* build Loudness control */
if (ac97->caps & 0x0020) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOUDNESS], ac97))) < 0)
return err;
}
/* build Mono output select control */
if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 9)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MONO], ac97))) < 0)
return err;
}
/* build Mic select control */
if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 8)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MIC], ac97))) < 0)
return err;
}
/* build ADC/DAC loopback control */
if (enable_loopback && snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 7)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOOPBACK], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x0000);
/* build 3D controls */
switch (ac97->id) {
case AC97_ID_STAC9708:
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
kctl->private_value = AC97_3D_CONTROL | (3 << 16);
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth");
kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
break;
case AC97_ID_STAC9700:
case AC97_ID_STAC9721:
case AC97_ID_STAC9744:
case AC97_ID_STAC9756:
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
kctl->private_value = AC97_3D_CONTROL | (3 << 16);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
break;
case AC97_ID_YMF753:
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
strcpy(kctl->id.name, "3D Control - Wide");
kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0)
return err;
snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00);
break;
default:
if (snd_ac97_try_volume_mix(ac97, AC97_3D_CONTROL)) {
unsigned short val;
val = 0x0707;
snd_ac97_write(ac97, AC97_3D_CONTROL, val);
val = snd_ac97_read(ac97, AC97_3D_CONTROL);
val = val == 0x0606;
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
return err;
if (val)
kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16);
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[1], ac97))) < 0)
return err;
if (val)
kctl->private_value = AC97_3D_CONTROL | (1 << 8) | (7 << 16);
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
}
}
/* build S/PDIF controls */
if (ac97->ext_id & AC97_EI_SPDIF) {
if (ac97->flags & AC97_CS_SPDIF) {
for (idx = 0; idx < 3; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cirrus_controls_spdif[0], ac97))) < 0)
return err;
switch (ac97->id & AC97_ID_CS_MASK) {
case AC97_ID_CS4205:
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cirrus_controls_spdif[1], ac97))) < 0)
return err;
break;
}
/* set default PCM S/PDIF params */
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20);
} else if (ac97->flags & AC97_CX_SPDIF) {
for (idx = 0; idx < 3; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_conexant_controls_spdif[0], ac97))) < 0)
return err;
/* set default PCM S/PDIF params */
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC,
snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK));
} else {
for (idx = 0; idx < 5; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
return err;
switch (ac97->id) {
case AC97_ID_YMF753:
for (idx = 0; idx < 3; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_spdif[idx], ac97))) < 0)
return err;
break;
case AC97_ID_AD1980:
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ad1980_spdif_source, ac97))) < 0)
return err;
break;
case AC97_ID_CM9739:
for (idx = 0; idx < ARRAY_SIZE(snd_ac97_cm9739_controls_spdif); idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9739_controls_spdif[idx], ac97))) < 0)
return err;
break;
}
/* set default PCM S/PDIF params */
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20);
}
ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
}
/* build chip specific controls */
switch (ac97->id) {
case AC97_ID_STAC9700:
case AC97_ID_STAC9708:
case AC97_ID_STAC9721:
case AC97_ID_STAC9744:
case AC97_ID_STAC9756:
snd_ac97_write_cache_test(ac97, AC97_SIGMATEL_ANALOG, snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) & ~0x0003);
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1))
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[0], ac97))) < 0)
return err;
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0))
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[1], ac97))) < 0)
return err;
break;
case AC97_ID_ALC650:
/* detect ALC650 rev.E of later */
for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_alc650); idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_alc650[idx], ac97))) < 0)
return err;
if ((err = snd_ctl_add(card, snd_ac97_cnew(ac97->spec.dev_flags ?
&snd_ac97_control_alc650_mic :
&snd_ac97_control_alc650_mic_gpio, ac97))) < 0)
return err;
if (ac97->ext_id & AC97_EI_SPDIF) {
for (idx = 0; idx < ARRAY_SIZE(snd_ac97_spdif_controls_alc650); idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_spdif_controls_alc650[idx], ac97))) < 0)
return err;
}
break;
case AC97_ID_VT1616:
if (snd_ac97_try_bit(ac97, 0x5a, 9))
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_vt1616[0], ac97))) < 0)
return err;
for (idx = 1; idx < ARRAY_SIZE(snd_ac97_controls_vt1616); idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_vt1616[idx], ac97))) < 0)
return err;
break;
case AC97_ID_CM9739:
for (idx = 1; idx < ARRAY_SIZE(snd_ac97_cm9739_controls); idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9739_controls[idx], ac97))) < 0)
return err;
break;
case AC97_ID_CM9738:
for (idx = 1; idx < ARRAY_SIZE(snd_ac97_cm9738_controls); idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9738_controls[idx], ac97))) < 0)
return err;
break;
default:
/* nothing */
break;
}
if (snd_ac97_try_bit(ac97, AC97_POWERDOWN, 15)) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_eapd, ac97))) < 0)
return err;
}
return 0;
}
Generated by GNU enscript 1.6.4.