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

📄 ac97_codec.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	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(ac97_t *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(ac97_t *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 ac97_codec_id_t *look_for_codec_id(const ac97_codec_id_t *table,						unsigned int id){	const ac97_codec_id_t *pid;	for (pid = table; pid->id; pid++)		if (pid->id == (id & pid->mask))			return pid;	return NULL;}void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem){	const ac97_codec_id_t *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(ac97_t *ac97){	const ac97_codec_id_t *pid;	for (pid = snd_ac97_codec_ids; pid->id; pid++)		if (pid->id == (ac97->id & pid->mask))			return pid->name;	return "unknown codec";}/* wait for a while until registers are accessible after RESET * return 0 if ok, negative not ready */static int ac97_reset_wait(ac97_t *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 ac97_bus_t 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(snd_card_t *card, int num, ac97_bus_ops_t *ops,		 void *private_data, ac97_bus_t **rbus){	int err;	ac97_bus_t *bus;	static snd_device_ops_t 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;}/* stop no dev release warning */static void ac97_device_release(struct device * dev){}/* register ac97 codec to bus */static int snd_ac97_dev_register(snd_device_t *device){	ac97_t *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, "card%d-%d", ac97->bus->card->number, ac97->num);	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;}/* unregister ac97 codec */static int snd_ac97_dev_unregister(snd_device_t *device){	ac97_t *ac97 = device->device_data;	if (ac97->dev.bus)		device_unregister(&ac97->dev);	return snd_ac97_free(ac97);}/* build_ops to do nothing */static struct snd_ac97_build_ops null_build_ops;/** * snd_ac97_mixer - create an Codec97 component * @bus: the AC97 bus which codec is attached to * @template: the template of ac97, including index, callbacks and *         the private data. * @rac97: the pointer to store the new ac97 instance. * * Creates an Codec97 component.  An ac97_t instance is newly * allocated and initialized from the template.  The codec * is then initialized by the standard procedure. * * The template must include the codec number (num) and address (addr), * and the private data (private_data). *  * The ac97 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_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97){	int err;	ac97_t *ac97;	snd_card_t *card;	char name[64];	unsigned long end_time;	unsigned int reg;	const ac97_codec_id_t *pid;	static snd_device_ops_t ops = {		.dev_free =	snd_ac97_dev_free,		.dev_register =	snd_ac97_dev_register,		.dev_unregister =	snd_ac97_dev_unregister,	};	snd_assert(rac97 != NULL, return -EINVAL);	*rac97 = NULL;	snd_assert(bus != NULL && template != NULL, return -EINVAL);	snd_assert(template->num < 4 && bus->codec[template->num] == NULL, return -EINVAL);	card = bus->card;	ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL);	if (ac97 == NULL)		return -ENOMEM;	ac97->private_data = template->private_data;	ac97->private_free = template->private_free;	ac97->bus = bus;	ac97->pci = template->pci;	ac97->num = template->num;	ac97->addr = template->addr;	ac97->scaps = template->scaps;	ac97->limited_regs = template->limited_regs;	memcpy(ac97->reg_accessed, template->reg_accessed, sizeof(ac97->reg_accessed));	bus->codec[ac97->num] = ac97;	init_MUTEX(&ac97->reg_mutex);	init_MUTEX(&ac97->page_mutex);	if (ac97->pci) {		pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor);		pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device);	}	if (bus->ops->reset) {		bus->ops->reset(ac97);		goto __access_ok;	}	ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;	ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);	if (ac97->id && ac97->id != (unsigned int)-1) {		pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id);		if (pid && (pid->flags & AC97_DEFAULT_POWER_OFF))			goto __access_ok;	}	/* reset to defaults */	if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO))		snd_ac97_write(ac97, AC97_RESET, 0);	if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM))		snd_ac97_write(ac97, AC97_EXTENDED_MID, 0);	if (bus->ops->wait)		bus->ops->wait(ac97);	else {		udelay(50);		if (ac97->scaps & AC97_SCAP_SKIP_AUDIO)			err = ac97_reset_wait(ac97, HZ/2, 1);		else {			err = ac97_reset_wait(ac97, HZ/2, 0);			if (err < 0)				err = ac97_reset_wait(ac97, HZ/2, 1);		}		if (err < 0) {			snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num);			/* proceed anyway - it's often non-critical */		}	}      __access_ok:	ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;	ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);	if (! (ac97->scaps & AC97_SCAP_DETECT_BY_VENDOR) &&	    (ac97->id == 0x00000000 || ac97->id == 0xffffffff)) {		snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id);		snd_ac97_free(ac97);		return -EIO;	}	pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id);	if (pid)		ac97->flags |= pid->flags;		/* test for AC'97 */	if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) {		/* test if we can write to the record gain volume register */		snd_ac97_write_ca

⌨️ 快捷键说明

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