⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ac97_codec.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		for (idx = 0; idx < 2; 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;	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 & 0x0004) {		for (idx = 0; idx < 5; idx++)			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)				return err;		/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original */		snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20);		ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;	}		/* build Sigmatel 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;	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;}static int snd_ac97_test_rate(ac97_t *ac97, int reg, int rate){	unsigned short val;	unsigned int tmp;	tmp = ((unsigned int)rate * ac97->clock) / 48000;	snd_ac97_write_cache_test(ac97, reg, tmp & 0xffff);	val = snd_ac97_read(ac97, reg);	return val == (tmp & 0xffff);}static void snd_ac97_determine_rates(ac97_t *ac97, int reg, unsigned int *r_result){	unsigned int result = 0;	/* test a non-standard rate */	if (snd_ac97_test_rate(ac97, reg, 11000))		result |= SNDRV_PCM_RATE_CONTINUOUS;	/* let's try to obtain standard rates */	if (snd_ac97_test_rate(ac97, reg, 8000))		result |= SNDRV_PCM_RATE_8000;	if (snd_ac97_test_rate(ac97, reg, 11025))		result |= SNDRV_PCM_RATE_11025;	if (snd_ac97_test_rate(ac97, reg, 16000))		result |= SNDRV_PCM_RATE_16000;	if (snd_ac97_test_rate(ac97, reg, 22050))		result |= SNDRV_PCM_RATE_22050;	if (snd_ac97_test_rate(ac97, reg, 32000))		result |= SNDRV_PCM_RATE_32000;	if (snd_ac97_test_rate(ac97, reg, 44100))		result |= SNDRV_PCM_RATE_44100;	if (snd_ac97_test_rate(ac97, reg, 48000))		result |= SNDRV_PCM_RATE_48000;	*r_result = result;}static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name){	const ac97_codec_id_t *pid;	sprintf(name, "0x%x %c%c%c", id,		printable(id >> 24),		printable(id >> 16),		printable(id >> 8));	for (pid = snd_ac97_codec_id_vendors; pid->id; pid++)		if (pid->id == (id & pid->mask)) {			strcpy(name, pid->name);			if (ac97 && pid->patch)				pid->patch(ac97);			goto __vendor_ok;		}	return;      __vendor_ok:	for (pid = snd_ac97_codec_ids; pid->id; pid++)		if (pid->id == (id & pid->mask)) {			strcat(name, " ");			strcat(name, pid->name);			if (pid->mask != 0xffffffff)				sprintf(name + strlen(name), " rev %d", id & ~pid->mask);			if (ac97 && pid->patch)				pid->patch(ac97);			return;		}	sprintf(name + strlen(name), " (%x)", id & 0xff);}int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97){	int err;	ac97_t *ac97;	char name[64];	signed long end_time;	static snd_device_ops_t ops = {		dev_free:	snd_ac97_dev_free,	};	snd_assert(rac97 != NULL, return -EINVAL);	*rac97 = NULL;	snd_assert(card != NULL && _ac97 != NULL, return -EINVAL);	ac97 = snd_magic_kcalloc(ac97_t, 0, GFP_KERNEL);	if (ac97 == NULL)		return -ENOMEM;	*ac97 = *_ac97;	ac97->card = card;	spin_lock_init(&ac97->reg_lock);	snd_ac97_write(ac97, AC97_RESET, 0);	/* reset to defaults */	if (ac97->wait)		ac97->wait(ac97);	else {		udelay(50);		/* it's necessary to wait awhile until registers are accessible after RESET */		/* because the PCM or MASTER volume registers can be modified, */		/* the REC_GAIN register is used for tests */		end_time = jiffies + HZ;		do {			/* use preliminary reads to settle the communication */			snd_ac97_read(ac97, AC97_RESET);			snd_ac97_read(ac97, AC97_VENDOR_ID1);			snd_ac97_read(ac97, AC97_VENDOR_ID2);			/* test if we can write to the PCM volume register */			snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05);			if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05)				goto __access_ok;			set_current_state(TASK_UNINTERRUPTIBLE);			schedule_timeout(HZ/100);		} while (end_time - (signed long)jiffies >= 0);		snd_printd("AC'97 %d:%d does not respond - RESET [REC_GAIN = 0x%x]\n", ac97->num, ac97->addr, err);		snd_ac97_free(ac97);		return -ENXIO;	}      __access_ok:	ac97->caps = snd_ac97_read(ac97, AC97_RESET);	ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;	ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);	ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);	if (ac97->ext_id == 0xffff)	/* invalid combination */		ac97->ext_id = 0;	if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) {		snd_printk("AC'97 %d:%d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->addr, ac97->id);		snd_ac97_free(ac97);		return -EIO;	}	/* FIXME: add powerdown control */	/* nothing should be in powerdown mode */	snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);	snd_ac97_write_cache_test(ac97, AC97_RESET, 0);		/* reset to defaults */	udelay(100);	/* nothing should be in powerdown mode */	snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);	snd_ac97_write_cache_test(ac97, AC97_GENERAL_PURPOSE, 0);	end_time = jiffies + (HZ / 10);	do {		if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)			goto __ready_ok;		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(HZ/10);	} while (end_time - (signed long)jiffies >= 0);	snd_printk("AC'97 %d:%d analog subsections not ready\n", ac97->num, ac97->addr);      __ready_ok:	if (ac97->clock == 0)		ac97->clock = 48000;	/* standard value */	if (ac97->ext_id & 0x0189)	/* L/R, MIC, SDAC, LDAC VRA support */		snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, ac97->ext_id & 0x0189);	if (ac97->ext_id & 0x0001) {	/* VRA support */		snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, &ac97->rates_front_dac);		snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, &ac97->rates_adc);	} else {		ac97->rates_front_dac = SNDRV_PCM_RATE_48000;		ac97->rates_adc = SNDRV_PCM_RATE_48000;	}	if (ac97->ext_id & 0x0008) {	/* MIC VRA support */		snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, &ac97->rates_mic_adc);	} else {		ac97->rates_mic_adc = SNDRV_PCM_RATE_48000;	}	if (ac97->ext_id & 0x0080) {	/* SDAC support */		snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, &ac97->rates_surr_dac);		ac97->scaps |= AC97_SCAP_SURROUND_DAC;	}	if (ac97->ext_id & 0x0100) {	/* LDAC support */		snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates_lfe_dac);		ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;	}	if (ac97->init)		ac97->init(ac97);	snd_ac97_get_name(ac97, ac97->id, name);	snd_ac97_get_name(NULL, ac97->id, name);  // ac97->id might be changed in the special setup code	if (card->mixername[0] == '\0') {		strcpy(card->mixername, name);	} else {		if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {			strcat(card->mixername, ",");			strcat(card->mixername, name);		}	}	if ((err = snd_component_add(card, "AC97")) < 0) {		snd_ac97_free(ac97);		return err;	}	if (snd_ac97_mixer_build(card, ac97) < 0) {		snd_ac97_free(ac97);		return -ENOMEM;	}	snd_ac97_proc_init(card, ac97);	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) {		snd_ac97_free(ac97);		return err;	}	*rac97 = ac97;	return 0;}/* */static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx){	char name[64];	unsigned int id;	unsigned short val, tmp, ext;	static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" };	static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" };	id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;	id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);	snd_ac97_get_name(NULL, id, name);	snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name);	val = snd_ac97_read(ac97, AC97_RESET);	snd_iprintf(buffer, "Capabilities     :%s%s%s%s%s%s\n",	    	    val & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",		    val & 0x0002 ? " -reserved1-" : "",		    val & 0x0004 ? " -bass & treble-" : "",		    val & 0x0008 ? " -simulated stereo-" : "",		    val & 0x0010 ? " -headphone out-" : "",		    val & 0x0020 ? " -loudness-" : "");	tmp = ac97->caps & 0x00c0;	snd_iprintf(buffer, "DAC resolution   : %s%s%s%s\n",		    tmp == 0x0000 ? "16-bit" : "",		    tmp == 0x0040 ? "18-bit" : "",		    tmp == 0x0080 ? "20-bit" : "",		    tmp == 0x00c0 ? "???" : "");	tmp = ac97->caps & 0x0300;	snd_iprintf(buffer, "ADC resolution   : %s%s%s%s\n",		    tmp == 0x0000 ? "16-bit" : "",		    tmp == 0x0100 ? "18-bit" : "",		    tmp == 0x0200 ? "20-bit" : "",		    tmp == 0x0300 ? "???" : "");	snd_iprintf(buffer, "3D enhancement   : %s\n",		snd_ac97_stereo_enhancements[(val >> 10) & 0x1f]);	snd_iprintf(buffer, "\nCurrent setup\n");	val = snd_ac97_read(ac97, AC97_MIC);	snd_iprintf(buffer, "Mic gain         : %s [%s]\n", val & 0x0040 ? "+20dB" : "+0dB", ac97->regs[AC97_MIC] & 0x0040 ? "+20dB" : "+0dB");	val = snd_ac97_read(ac97, AC97_GENERAL_PURPOSE);	snd_iprintf(buffer, "POP path         : %s 3D\n"		    "Sim. stereo      : %s\n"		    "3D enhancement   : %s\n"		    "Loudness         : %s\n"		    "Mono output      : %s\n"		    "Mic select       : %s\n"		    "ADC/DAC loopback : %s\n",		    val & 0x8000 ? "post" : "pre",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -