Enscript Output

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.