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

📄 ac97_codec.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* 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_update_bits(ac97, AC97_GENERAL_PURPOSE, ~AC97_GP_DRSS_MASK, 0x0000);	/* build 3D controls */	if (ac97->build_ops->build_3d) {		ac97->build_ops->build_3d(ac97);	} else {		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 */	/* Hack for ASUS P5P800-VM, which does not indicate S/PDIF capability */	if (ac97->subsystem_vendor == 0x1043 &&	    ac97->subsystem_device == 0x810f)		ac97->ext_id |= AC97_EI_SPDIF;	if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) {		if (ac97->build_ops->build_spdif) {			if ((err = ac97->build_ops->build_spdif(ac97)) < 0)				return err;		} 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;			if (ac97->build_ops->build_post_spdif) {				if ((err = ac97->build_ops->build_post_spdif(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_SPDIF, 0x2a20);			ac97->rates[AC97_RATES_SPDIF] = snd_ac97_determine_spdif_rates(ac97);		}		ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;	}		/* build chip specific controls */	if (ac97->build_ops->build_specific)		if ((err = ac97->build_ops->build_specific(ac97)) < 0)			return err;	if (snd_ac97_try_bit(ac97, AC97_POWERDOWN, 15)) {		kctl = snd_ac97_cnew(&snd_ac97_control_eapd, ac97);		if (! kctl)			return -ENOMEM;		if (ac97->scaps & AC97_SCAP_INV_EAPD)			set_inv_eapd(ac97, kctl);		if ((err = snd_ctl_add(card, kctl)) < 0)			return err;	}	return 0;}static int snd_ac97_modem_build(struct snd_card *card, struct snd_ac97 * ac97){	int err, idx;	//printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG));	snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH));	snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH));	snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff);	snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0);	snd_ac97_write(ac97, AC97_MISC_AFE, 0x0);	/* build modem switches */	for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++)		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ac97_controls_modem_switches[idx], ac97))) < 0)			return err;	/* build chip specific controls */	if (ac97->build_ops->build_specific)		if ((err = ac97->build_ops->build_specific(ac97)) < 0)			return err;	return 0;}static int snd_ac97_test_rate(struct snd_ac97 *ac97, int reg, int shadow_reg, int rate){	unsigned short val;	unsigned int tmp;	tmp = ((unsigned int)rate * ac97->bus->clock) / 48000;	snd_ac97_write_cache(ac97, reg, tmp & 0xffff);	if (shadow_reg)		snd_ac97_write_cache(ac97, shadow_reg, tmp & 0xffff);	val = snd_ac97_read(ac97, reg);	return val == (tmp & 0xffff);}static void snd_ac97_determine_rates(struct snd_ac97 *ac97, int reg, int shadow_reg, unsigned int *r_result){	unsigned int result = 0;	unsigned short saved;	if (ac97->bus->no_vra) {		*r_result = SNDRV_PCM_RATE_48000;		if ((ac97->flags & AC97_DOUBLE_RATE) &&		    reg == AC97_PCM_FRONT_DAC_RATE)			*r_result |= SNDRV_PCM_RATE_96000;		return;	}	saved = snd_ac97_read(ac97, reg);	if ((ac97->ext_id & AC97_EI_DRA) && reg == AC97_PCM_FRONT_DAC_RATE)		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,				     AC97_EA_DRA, 0);	/* test a non-standard rate */	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11000))		result |= SNDRV_PCM_RATE_CONTINUOUS;	/* let's try to obtain standard rates */	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 8000))		result |= SNDRV_PCM_RATE_8000;	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11025))		result |= SNDRV_PCM_RATE_11025;	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 16000))		result |= SNDRV_PCM_RATE_16000;	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 22050))		result |= SNDRV_PCM_RATE_22050;	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 32000))		result |= SNDRV_PCM_RATE_32000;	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 44100))		result |= SNDRV_PCM_RATE_44100;	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 48000))		result |= SNDRV_PCM_RATE_48000;	if ((ac97->flags & AC97_DOUBLE_RATE) &&	    reg == AC97_PCM_FRONT_DAC_RATE) {		/* test standard double rates */		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,				     AC97_EA_DRA, AC97_EA_DRA);		if (snd_ac97_test_rate(ac97, reg, shadow_reg, 64000 / 2))			result |= SNDRV_PCM_RATE_64000;		if (snd_ac97_test_rate(ac97, reg, shadow_reg, 88200 / 2))			result |= SNDRV_PCM_RATE_88200;		if (snd_ac97_test_rate(ac97, reg, shadow_reg, 96000 / 2))			result |= SNDRV_PCM_RATE_96000;		/* some codecs don't support variable double rates */		if (!snd_ac97_test_rate(ac97, reg, shadow_reg, 76100 / 2))			result &= ~SNDRV_PCM_RATE_CONTINUOUS;		snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,				     AC97_EA_DRA, 0);	}	/* restore the default value */	snd_ac97_write_cache(ac97, reg, saved);	if (shadow_reg)		snd_ac97_write_cache(ac97, shadow_reg, saved);	*r_result = result;}/* check AC97_SPDIF register to accept which sample rates */static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97){	unsigned int result = 0;	int i;	static unsigned short ctl_bits[] = {		AC97_SC_SPSR_44K, AC97_SC_SPSR_32K, AC97_SC_SPSR_48K	};	static unsigned int rate_bits[] = {		SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_32000, SNDRV_PCM_RATE_48000	};	for (i = 0; i < (int)ARRAY_SIZE(ctl_bits); i++) {		snd_ac97_update_bits(ac97, AC97_SPDIF, AC97_SC_SPSR_MASK, ctl_bits[i]);		if ((snd_ac97_read(ac97, AC97_SPDIF) & AC97_SC_SPSR_MASK) == ctl_bits[i])			result |= rate_bits[i];	}	return result;}/* look for the codec id table matching with the given id */static const struct ac97_codec_id *look_for_codec_id(const struct ac97_codec_id *table,						     unsigned int id){	const struct ac97_codec_id *pid;	for (pid = table; pid->id; pid++)		if (pid->id == (id & pid->mask))			return pid;	return NULL;}void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int modem){	const struct ac97_codec_id *pid;	sprintf(name, "0x%x %c%c%c", id,		printable(id >> 24),		printable(id >> 16),		printable(id >> 8));	pid = look_for_codec_id(snd_ac97_codec_id_vendors, id);	if (! pid)		return;	strcpy(name, pid->name);	if (ac97 && pid->patch) {		if ((modem && (pid->flags & AC97_MODEM_PATCH)) ||		    (! modem && ! (pid->flags & AC97_MODEM_PATCH)))			pid->patch(ac97);	} 	pid = look_for_codec_id(snd_ac97_codec_ids, id);	if (pid) {		strcat(name, " ");		strcat(name, pid->name);		if (pid->mask != 0xffffffff)			sprintf(name + strlen(name), " rev %d", id & ~pid->mask);		if (ac97 && pid->patch) {			if ((modem && (pid->flags & AC97_MODEM_PATCH)) ||			    (! modem && ! (pid->flags & AC97_MODEM_PATCH)))				pid->patch(ac97);		}	} else		sprintf(name + strlen(name), " id %x", id & 0xff);}/** * snd_ac97_get_short_name - retrieve codec name * @ac97: the codec instance * * Returns the short identifying name of the codec. */const char *snd_ac97_get_short_name(struct snd_ac97 *ac97){	const struct ac97_codec_id *pid;	for (pid = snd_ac97_codec_ids; pid->id; pid++)		if (pid->id == (ac97->id & pid->mask))			return pid->name;	return "unknown codec";}EXPORT_SYMBOL(snd_ac97_get_short_name);/* wait for a while until registers are accessible after RESET * return 0 if ok, negative not ready */static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem){	unsigned long end_time;	unsigned short val;	end_time = jiffies + timeout;	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);		/* modem? */		if (with_modem) {			val = snd_ac97_read(ac97, AC97_EXTENDED_MID);			if (val != 0xffff && (val & 1) != 0)				return 0;		}		if (ac97->scaps & AC97_SCAP_DETECT_BY_VENDOR) {			/* probably only Xbox issue - all registers are read as zero */			val = snd_ac97_read(ac97, AC97_VENDOR_ID1);			if (val != 0 && val != 0xffff)				return 0;		} else {			/* because the PCM or MASTER volume registers can be modified,			 * the REC_GAIN register is used for tests			 */			/* test if we can write to the record gain volume register */			snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05);			if ((snd_ac97_read(ac97, AC97_REC_GAIN) & 0x7fff) == 0x0a05)				return 0;		}		schedule_timeout_uninterruptible(1);	} while (time_after_eq(end_time, jiffies));	return -ENODEV;}/** * snd_ac97_bus - create an AC97 bus component * @card: the card instance * @num: the bus number * @ops: the bus callbacks table * @private_data: private data pointer for the new instance * @rbus: the pointer to store the new AC97 bus instance. * * Creates an AC97 bus component.  An struct snd_ac97_bus instance is newly * allocated and initialized. * * The ops table must include valid callbacks (at least read and * write).  The other callbacks, wait and reset, are not mandatory. *  * The clock is set to 48000.  If another clock is needed, set * (*rbus)->clock manually. * * The AC97 bus instance is registered as a low-level device, so you don't * have to release it manually. * * Returns zero if successful, or a negative error code on failure. */int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops,		 void *private_data, struct snd_ac97_bus **rbus){	int err;	struct snd_ac97_bus *bus;	static struct snd_device_ops dev_ops = {		.dev_free =	snd_ac97_bus_dev_free,	};	snd_assert(card != NULL, return -EINVAL);	snd_assert(rbus != NULL, return -EINVAL);	bus = kzalloc(sizeof(*bus), GFP_KERNEL);	if (bus == NULL)		return -ENOMEM;	bus->card = card;	bus->num = num;	bus->ops = ops;	bus->private_data = private_data;	bus->clock = 48000;	spin_lock_init(&bus->bus_lock);	snd_ac97_bus_proc_init(bus);	if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) {		snd_ac97_bus_free(bus);		return err;	}	*rbus = bus;	return 0;}EXPORT_SYMBOL(snd_ac97_bus);/* stop no dev release warning */static void ac97_device_release(struct device * dev){}/* register ac97 codec to bus */static int snd_ac97_dev_register(struct snd_device *device){	struct snd_ac97 *ac97 = device->device_data;	int err;	ac97->dev.bus = &ac97_bus_type;	ac97->dev.parent = ac97->bus->card->dev;	ac97->dev.release = ac97_device_release;	snprintf(ac97->dev.bus_id, BUS_ID_SIZE, "%d-%d:%s",		 ac97->bus->card->number, ac97->num,		 snd_ac97_get_short_name(ac97));	if ((err = device_register(&ac97->dev)) < 0) {		snd_printk(KERN_ERR "Can't register ac97 bus\n");		ac97->dev.bus = NULL;		return err;	}	return 0;}/* disconnect ac97 codec */static int snd_ac97_dev_disconnect(struct snd_device *device){	struct snd_ac97 *ac97 = device->device_data;	if (ac97->dev.bus)		device_unregister(&ac97->dev);	return 0;}/* build_ops to do nothing */static struct snd_ac97_build_ops null_build_ops;#ifdef CONFIG_SND_AC97_POWER_SAVEstatic void do_update_power(struct work_struct *work){	update_power_regs(		container_of

⌨️ 快捷键说明

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