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

📄 echoaudio.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static int snd_echo_automute_get(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct echoaudio *chip = snd_kcontrol_chip(kcontrol);	ucontrol->value.integer.value[0] = chip->digital_in_automute;	return 0;}static int snd_echo_automute_put(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct echoaudio *chip = snd_kcontrol_chip(kcontrol);	int automute, changed = 0;	automute = !!ucontrol->value.integer.value[0];	if (chip->digital_in_automute != automute) {		spin_lock_irq(&chip->lock);		changed = set_input_auto_mute(chip, automute);		spin_unlock_irq(&chip->lock);		if (changed == 0)			changed = 1;	/* no errors */	}	return changed;}static struct snd_kcontrol_new snd_echo_automute_switch __devinitdata = {	.name = "Digital Capture Switch (automute)",	.iface = SNDRV_CTL_ELEM_IFACE_CARD,	.info = snd_echo_automute_info,	.get = snd_echo_automute_get,	.put = snd_echo_automute_put,};#endif /* ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE *//******************* VU-meters switch *******************/#define snd_echo_vumeters_switch_info		snd_ctl_boolean_mono_infostatic int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol,					struct snd_ctl_elem_value *ucontrol){	struct echoaudio *chip;	chip = snd_kcontrol_chip(kcontrol);	spin_lock_irq(&chip->lock);	set_meters_on(chip, ucontrol->value.integer.value[0]);	spin_unlock_irq(&chip->lock);	return 1;}static struct snd_kcontrol_new snd_echo_vumeters_switch __devinitdata = {	.name = "VU-meters Switch",	.iface = SNDRV_CTL_ELEM_IFACE_CARD,	.access = SNDRV_CTL_ELEM_ACCESS_WRITE,	.info = snd_echo_vumeters_switch_info,	.put = snd_echo_vumeters_switch_put,};/***** Read VU-meters (input, output, analog and digital together) *****/static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol,				  struct snd_ctl_elem_info *uinfo){	struct echoaudio *chip;	chip = snd_kcontrol_chip(kcontrol);	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 96;	uinfo->value.integer.min = ECHOGAIN_MINOUT;	uinfo->value.integer.max = 0;#ifdef ECHOCARD_HAS_VMIXER	uinfo->dimen.d[0] = 3;	/* Out, In, Virt */#else	uinfo->dimen.d[0] = 2;	/* Out, In */#endif	uinfo->dimen.d[1] = 16;	/* 16 channels */	uinfo->dimen.d[2] = 2;	/* 0=level, 1=peak */	return 0;}static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct echoaudio *chip;	chip = snd_kcontrol_chip(kcontrol);	get_audio_meters(chip, ucontrol->value.integer.value);	return 0;}static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {	.name = "VU-meters",	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.access = SNDRV_CTL_ELEM_ACCESS_READ |		  SNDRV_CTL_ELEM_ACCESS_VOLATILE |		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,	.info = snd_echo_vumeters_info,	.get = snd_echo_vumeters_get,	.tlv = {.p = db_scale_output_gain},};/*** Channels info - it exports informations about the number of channels ***/static int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_info *uinfo){	struct echoaudio *chip;	chip = snd_kcontrol_chip(kcontrol);	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 6;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1 << ECHO_CLOCK_NUMBER;	return 0;}static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol,				      struct snd_ctl_elem_value *ucontrol){	struct echoaudio *chip;	int detected, clocks, bit, src;	chip = snd_kcontrol_chip(kcontrol);	ucontrol->value.integer.value[0] = num_busses_in(chip);	ucontrol->value.integer.value[1] = num_analog_busses_in(chip);	ucontrol->value.integer.value[2] = num_busses_out(chip);	ucontrol->value.integer.value[3] = num_analog_busses_out(chip);	ucontrol->value.integer.value[4] = num_pipes_out(chip);	/* Compute the bitmask of the currently valid input clocks */	detected = detect_input_clocks(chip);	clocks = 0;	src = chip->num_clock_sources - 1;	for (bit = ECHO_CLOCK_NUMBER - 1; bit >= 0; bit--)		if (detected & (1 << bit))			for (; src >= 0; src--)				if (bit == chip->clock_source_list[src]) {					clocks |= 1 << src;					break;				}	ucontrol->value.integer.value[5] = clocks;	return 0;}static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = {	.name = "Channels info",	.iface = SNDRV_CTL_ELEM_IFACE_HWDEP,	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,	.info = snd_echo_channels_info_info,	.get = snd_echo_channels_info_get,};/******************************************************************************	IRQ Handler******************************************************************************/static irqreturn_t snd_echo_interrupt(int irq, void *dev_id){	struct echoaudio *chip = dev_id;	struct snd_pcm_substream *substream;	int period, ss, st;	spin_lock(&chip->lock);	st = service_irq(chip);	if (st < 0) {		spin_unlock(&chip->lock);		return IRQ_NONE;	}	/* The hardware doesn't tell us which substream caused the irq,	thus we have to check all running substreams. */	for (ss = 0; ss < DSP_MAXPIPES; ss++) {		if ((substream = chip->substream[ss])) {			period = pcm_pointer(substream) /				substream->runtime->period_size;			if (period != chip->last_period[ss]) {				chip->last_period[ss] = period;				spin_unlock(&chip->lock);				snd_pcm_period_elapsed(substream);				spin_lock(&chip->lock);			}		}	}	spin_unlock(&chip->lock);#ifdef ECHOCARD_HAS_MIDI	if (st > 0 && chip->midi_in) {		snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st);		DE_MID(("rawmidi_iread=%d\n", st));	}#endif	return IRQ_HANDLED;}/******************************************************************************	Module construction / destruction******************************************************************************/static int snd_echo_free(struct echoaudio *chip){	DE_INIT(("Stop DSP...\n"));	if (chip->comm_page) {		rest_in_peace(chip);		snd_dma_free_pages(&chip->commpage_dma_buf);	}	DE_INIT(("Stopped.\n"));	if (chip->irq >= 0)		free_irq(chip->irq, chip);	if (chip->dsp_registers)		iounmap(chip->dsp_registers);	if (chip->iores)		release_and_free_resource(chip->iores);	DE_INIT(("MMIO freed.\n"));	pci_disable_device(chip->pci);	/* release chip data */	kfree(chip);	DE_INIT(("Chip freed.\n"));	return 0;}static int snd_echo_dev_free(struct snd_device *device){	struct echoaudio *chip = device->device_data;	DE_INIT(("snd_echo_dev_free()...\n"));	return snd_echo_free(chip);}/* <--snd_echo_probe() */static __devinit int snd_echo_create(struct snd_card *card,				     struct pci_dev *pci,				     struct echoaudio **rchip){	struct echoaudio *chip;	int err;	size_t sz;	static struct snd_device_ops ops = {		.dev_free = snd_echo_dev_free,	};	*rchip = NULL;	pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0xC0);	if ((err = pci_enable_device(pci)) < 0)		return err;	pci_set_master(pci);	/* allocate a chip-specific data */	chip = kzalloc(sizeof(*chip), GFP_KERNEL);	if (!chip) {		pci_disable_device(pci);		return -ENOMEM;	}	DE_INIT(("chip=%p\n", chip));	spin_lock_init(&chip->lock);	chip->card = card;	chip->pci = pci;	chip->irq = -1;	/* PCI resource allocation */	chip->dsp_registers_phys = pci_resource_start(pci, 0);	sz = pci_resource_len(pci, 0);	if (sz > PAGE_SIZE)		sz = PAGE_SIZE;		/* We map only the required part */	if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz,					      ECHOCARD_NAME)) == NULL) {		snd_echo_free(chip);		snd_printk(KERN_ERR "cannot get memory region\n");		return -EBUSY;	}	chip->dsp_registers = (volatile u32 __iomem *)		ioremap_nocache(chip->dsp_registers_phys, sz);	if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,			ECHOCARD_NAME, chip)) {		snd_echo_free(chip);		snd_printk(KERN_ERR "cannot grab irq\n");		return -EBUSY;	}	chip->irq = pci->irq;	DE_INIT(("pci=%p irq=%d subdev=%04x Init hardware...\n",		 chip->pci, chip->irq, chip->pci->subsystem_device));	/* Create the DSP comm page - this is the area of memory used for most	of the communication with the DSP, which accesses it via bus mastering */	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),				sizeof(struct comm_page),				&chip->commpage_dma_buf) < 0) {		snd_echo_free(chip);		snd_printk(KERN_ERR "cannot allocate the comm page\n");		return -ENOMEM;	}	chip->comm_page_phys = chip->commpage_dma_buf.addr;	chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area;	err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);	if (err) {		DE_INIT(("init_hw err=%d\n", err));		snd_echo_free(chip);		return err;	}	DE_INIT(("Card init OK\n"));	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {		snd_echo_free(chip);		return err;	}	atomic_set(&chip->opencount, 0);	init_MUTEX(&chip->mode_mutex);	chip->can_set_rate = 1;	*rchip = chip;	/* Init done ! */	return 0;}/* constructor */static int __devinit snd_echo_probe(struct pci_dev *pci,				    const struct pci_device_id *pci_id){	static int dev;	struct snd_card *card;	struct echoaudio *chip;	char *dsp;	int i, err;	if (dev >= SNDRV_CARDS)		return -ENODEV;	if (!enable[dev]) {		dev++;		return -ENOENT;	}	DE_INIT(("Echoaudio driver starting...\n"));	i = 0;	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);	if (card == NULL)		return -ENOMEM;	snd_card_set_dev(card, &pci->dev);	if ((err = snd_echo_create(card, pci, &chip)) < 0) {		snd_card_free(card);		return err;	}	strcpy(card->driver, "Echo_" ECHOCARD_NAME);	strcpy(card->shortname, chip->card_name);	dsp = "56301";	if (pci_id->device == 0x3410)		dsp = "56361";	sprintf(card->longname, "%s rev.%d (DSP%s) at 0x%lx irq %i",		card->shortname, pci_id->subdevice & 0x000f, dsp,		chip->dsp_registers_phys, chip->irq);	if ((err = snd_echo_new_pcm(chip)) < 0) {		snd_printk(KERN_ERR "new pcm error %d\n", err);		snd_card_free(card);		return err;	}#ifdef ECHOCARD_HAS_MIDI	if (chip->has_midi) {	/* Some Mia's do not have midi */		if ((err = snd_echo_midi_create(card, chip)) < 0) {			snd_printk(KERN_ERR "new midi error %d\n", err);			snd_card_free(card);			return err;		}	}#endif#ifdef ECHOCARD_HAS_VMIXER	snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip);	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_output_gain, chip))) < 0)		goto ctl_error;	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0)		goto ctl_error;#else	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_pcm_output_gain, chip))) < 0)		goto ctl_error;#endif#ifdef ECHOCARD_HAS_INPUT_GAIN	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip))) < 0)		goto ctl_error;#endif#ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL	if (!chip->hasnt_input_nominal_level)		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip))) < 0)			goto ctl_error;#endif#ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip))) < 0)		goto ctl_error;#endif	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip))) < 0)		goto ctl_error;	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip))) < 0)		goto ctl_error;#ifdef ECHOCARD_HAS_MONITOR	snd_echo_monitor_mixer.count = num_busses_in(chip) * num_busses_out(chip);	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip))) < 0)		goto ctl_error;#endif#ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip))) < 0)		goto ctl_error;#endif	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip))) < 0)		goto ctl_error;#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH	/* Creates a list of available digital modes */	chip->num_digital_modes = 0;	for (i = 0; i < 6; i++)		if (chip->digital_modes & (1 << i))			chip->digital_mode_list[chip->num_digital_modes++] = i;	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip))) < 0)		goto ctl_error;#endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK	/* Creates a list of available clock sources */	chip->num_clock_sources = 0;	for (i = 0; i < 10; i++)		if (chip->input_clock_types & (1 << i))			chip->clock_source_list[chip->num_clock_sources++] = i;	if (chip->num_clock_sources > 1) {		chip->clock_src_ctl = snd_ctl_new1(&snd_echo_clock_source_switch, chip);		if ((err = snd_ctl_add(chip->card, chip->clock_src_ctl)) < 0)			goto ctl_error;	}#endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */#ifdef ECHOCARD_HAS_DIGITAL_IO	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip))) < 0)		goto ctl_error;#endif#ifdef ECHOCARD_HAS_PHANTOM_POWER	if (chip->has_phantom_power)		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip))) < 0)			goto ctl_error;#endif	if ((err = snd_card_register(card)) < 0) {		snd_card_free(card);		goto ctl_error;	}	snd_printk(KERN_INFO "Card registered: %s\n", card->longname);	pci_set_drvdata(pci, chip);	dev++;	return 0;ctl_error:	snd_printk(KERN_ERR "new control error %d\n", err);	snd_card_free(card);	return err;}static void __devexit snd_echo_remove(struct pci_dev *pci){	struct echoaudio *chip;	chip = pci_get_drvdata(pci);	if (chip)		snd_card_free(chip->card);	pci_set_drvdata(pci, NULL);}/******************************************************************************	Everything starts and ends here******************************************************************************//* pci_driver definition */static struct pci_driver driver = {	.name = "Echoaudio " ECHOCARD_NAME,	.id_table = snd_echo_ids,	.probe = snd_echo_probe,	.remove = __devexit_p(snd_echo_remove),};/* initialization of the module */static int __init alsa_card_echo_init(void){	return pci_register_driver(&driver);}/* clean up the module */static void __exit alsa_card_echo_exit(void){	pci_unregister_driver(&driver);}module_init(alsa_card_echo_init)module_exit(alsa_card_echo_exit)

⌨️ 快捷键说明

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