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

📄 ad1889.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
static snd_pcm_uframes_tsnd_ad1889_playback_pointer(struct snd_pcm_substream *ss){	size_t ptr = 0;	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	if (unlikely(!(chip->wave.reg & AD_DS_WSMC_WAEN)))		return 0;	ptr = ad1889_readl(chip, AD_DMA_WAVCA);	ptr -= chip->wave.addr;		snd_assert((ptr >= 0) && (ptr < chip->wave.size), return 0);		return bytes_to_frames(ss->runtime, ptr);}/* Called in atomic context with IRQ disabled */static snd_pcm_uframes_tsnd_ad1889_capture_pointer(struct snd_pcm_substream *ss){	size_t ptr = 0;	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	if (unlikely(!(chip->ramc.reg & AD_DS_RAMC_ADEN)))		return 0;	ptr = ad1889_readl(chip, AD_DMA_ADCCA);	ptr -= chip->ramc.addr;	snd_assert((ptr >= 0) && (ptr < chip->ramc.size), return 0);		return bytes_to_frames(ss->runtime, ptr);}static struct snd_pcm_ops snd_ad1889_playback_ops = {	.open = snd_ad1889_playback_open,	.close = snd_ad1889_playback_close,	.ioctl = snd_pcm_lib_ioctl,	.hw_params = snd_ad1889_hw_params,	.hw_free = snd_ad1889_hw_free,	.prepare = snd_ad1889_playback_prepare,	.trigger = snd_ad1889_playback_trigger,	.pointer = snd_ad1889_playback_pointer, };static struct snd_pcm_ops snd_ad1889_capture_ops = {	.open = snd_ad1889_capture_open,	.close = snd_ad1889_capture_close,	.ioctl = snd_pcm_lib_ioctl,	.hw_params = snd_ad1889_hw_params,	.hw_free = snd_ad1889_hw_free,	.prepare = snd_ad1889_capture_prepare,	.trigger = snd_ad1889_capture_trigger,	.pointer = snd_ad1889_capture_pointer, };static irqreturn_tsnd_ad1889_interrupt(int irq, void *dev_id){	unsigned long st;	struct snd_ad1889 *chip = dev_id;	st = ad1889_readl(chip, AD_DMA_DISR);	/* clear ISR */	ad1889_writel(chip, AD_DMA_DISR, st);	st &= AD_INTR_MASK;	if (unlikely(!st))		return IRQ_NONE;	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))		ad1889_debug("Unexpected master or target abort interrupt!\n");	if ((st & AD_DMA_DISR_WAVI) && chip->psubs)		snd_pcm_period_elapsed(chip->psubs);	if ((st & AD_DMA_DISR_ADCI) && chip->csubs)		snd_pcm_period_elapsed(chip->csubs);	return IRQ_HANDLED;}static int __devinitsnd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm){	int err;	struct snd_pcm *pcm;	if (rpcm)		*rpcm = NULL;	err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 			&snd_ad1889_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,			&snd_ad1889_capture_ops);	pcm->private_data = chip;	pcm->info_flags = 0;	strcpy(pcm->name, chip->card->shortname);		chip->pcm = pcm;	chip->psubs = NULL;	chip->csubs = NULL;	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,						snd_dma_pci_data(chip->pci),						BUFFER_BYTES_MAX / 2,						BUFFER_BYTES_MAX);	if (err < 0) {		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);		return err;	}		if (rpcm)		*rpcm = pcm;		return 0;}static voidsnd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){	struct snd_ad1889 *chip = entry->private_data;	u16 reg;	int tmp;	reg = ad1889_readw(chip, AD_DS_WSMC);	snd_iprintf(buffer, "Wave output: %s\n",			(reg & AD_DS_WSMC_WAEN) ? "enabled" : "disabled");	snd_iprintf(buffer, "Wave Channels: %s\n",			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");	snd_iprintf(buffer, "Wave Quality: %d-bit linear\n",			(reg & AD_DS_WSMC_WA16) ? 16 : 8);		/* WARQ is at offset 12 */	tmp = (reg & AD_DS_WSMC_WARQ) ?			(((reg & AD_DS_WSMC_WARQ >> 12) & 0x01) ? 12 : 18) : 4;	tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;		snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp,			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");						snd_iprintf(buffer, "Synthesis output: %s\n",			reg & AD_DS_WSMC_SYEN ? "enabled" : "disabled");		/* SYRQ is at offset 4 */	tmp = (reg & AD_DS_WSMC_SYRQ) ?			(((reg & AD_DS_WSMC_SYRQ >> 4) & 0x01) ? 12 : 18) : 4;	tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;		snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp,			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");	reg = ad1889_readw(chip, AD_DS_RAMC);	snd_iprintf(buffer, "ADC input: %s\n",			(reg & AD_DS_RAMC_ADEN) ? "enabled" : "disabled");	snd_iprintf(buffer, "ADC Channels: %s\n",			(reg & AD_DS_RAMC_ADST) ? "stereo" : "mono");	snd_iprintf(buffer, "ADC Quality: %d-bit linear\n",			(reg & AD_DS_RAMC_AD16) ? 16 : 8);		/* ACRQ is at offset 4 */	tmp = (reg & AD_DS_RAMC_ACRQ) ?			(((reg & AD_DS_RAMC_ACRQ >> 4) & 0x01) ? 12 : 18) : 4;	tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;		snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp,			(reg & AD_DS_RAMC_ADST) ? "stereo" : "mono");		snd_iprintf(buffer, "Resampler input: %s\n",			reg & AD_DS_RAMC_REEN ? "enabled" : "disabled");				/* RERQ is at offset 12 */	tmp = (reg & AD_DS_RAMC_RERQ) ?			(((reg & AD_DS_RAMC_RERQ >> 12) & 0x01) ? 12 : 18) : 4;	tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;		snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp,			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");						/* doc says LSB represents -1.5dB, but the max value (-94.5dB)	suggests that LSB is -3dB, which is more coherent with the logarithmic	nature of the dB scale */	reg = ad1889_readw(chip, AD_DS_WADA);	snd_iprintf(buffer, "Left: %s, -%d dB\n",			(reg & AD_DS_WADA_LWAM) ? "mute" : "unmute",			((reg & AD_DS_WADA_LWAA) >> 8) * 3);	reg = ad1889_readw(chip, AD_DS_WADA);	snd_iprintf(buffer, "Right: %s, -%d dB\n",			(reg & AD_DS_WADA_RWAM) ? "mute" : "unmute",			((reg & AD_DS_WADA_RWAA) >> 8) * 3);		reg = ad1889_readw(chip, AD_DS_WAS);	snd_iprintf(buffer, "Wave samplerate: %u Hz\n", reg);	reg = ad1889_readw(chip, AD_DS_RES);	snd_iprintf(buffer, "Resampler samplerate: %u Hz\n", reg);}static void __devinitsnd_ad1889_proc_init(struct snd_ad1889 *chip){	struct snd_info_entry *entry;	if (!snd_card_proc_new(chip->card, chip->card->driver, &entry))		snd_info_set_text_ops(entry, chip, snd_ad1889_proc_read);}static struct ac97_quirk ac97_quirks[] = {	{		.subvendor = 0x11d4,	/* AD */		.subdevice = 0x1889,	/* AD1889 */		.codec_id = AC97_ID_AD1819,		.name = "AD1889",		.type = AC97_TUNE_HP_ONLY	},	{ } /* terminator */};static void __devinitsnd_ad1889_ac97_xinit(struct snd_ad1889 *chip){	u16 reg;	reg = ad1889_readw(chip, AD_AC97_ACIC);	reg |= AD_AC97_ACIC_ACRD;		/* Reset Disable */	ad1889_writew(chip, AD_AC97_ACIC, reg);	ad1889_readw(chip, AD_AC97_ACIC);	/* flush posted write */	udelay(10);	/* Interface Enable */	reg |= AD_AC97_ACIC_ACIE;	ad1889_writew(chip, AD_AC97_ACIC, reg);		snd_ad1889_ac97_ready(chip);	/* Audio Stream Output | Variable Sample Rate Mode */	reg = ad1889_readw(chip, AD_AC97_ACIC);	reg |= AD_AC97_ACIC_ASOE | AD_AC97_ACIC_VSRM;	ad1889_writew(chip, AD_AC97_ACIC, reg);	ad1889_readw(chip, AD_AC97_ACIC); /* flush posted write */}static voidsnd_ad1889_ac97_bus_free(struct snd_ac97_bus *bus){	struct snd_ad1889 *chip = bus->private_data;	chip->ac97_bus = NULL;}static voidsnd_ad1889_ac97_free(struct snd_ac97 *ac97){	struct snd_ad1889 *chip = ac97->private_data;	chip->ac97 = NULL;}static int __devinitsnd_ad1889_ac97_init(struct snd_ad1889 *chip, const char *quirk_override){	int err;	struct snd_ac97_template ac97;	static struct snd_ac97_bus_ops ops = {		.write = snd_ad1889_ac97_write,		.read = snd_ad1889_ac97_read,	};	/* doing that here, it works. */	snd_ad1889_ac97_xinit(chip);	err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus);	if (err < 0)		return err;		chip->ac97_bus->private_free = snd_ad1889_ac97_bus_free;	memset(&ac97, 0, sizeof(ac97));	ac97.private_data = chip;	ac97.private_free = snd_ad1889_ac97_free;	ac97.pci = chip->pci;	err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97);	if (err < 0)		return err;			snd_ac97_tune_hardware(chip->ac97, ac97_quirks, quirk_override);		return 0;}static intsnd_ad1889_free(struct snd_ad1889 *chip){	if (chip->irq < 0)		goto skip_hw;	spin_lock_irq(&chip->lock);	ad1889_mute(chip);	/* Turn off interrupt on count and zero DMA registers */	ad1889_channel_reset(chip, AD_CHAN_WAV | AD_CHAN_ADC);	/* clear DISR. If we don't, we'd better jump off the Eiffel Tower */	ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PTAI | AD_DMA_DISR_PMAI);	ad1889_readl(chip, AD_DMA_DISR);	/* flush, dammit! */	spin_unlock_irq(&chip->lock);	synchronize_irq(chip->irq);		if (chip->irq >= 0)		free_irq(chip->irq, chip);skip_hw:	if (chip->iobase)		iounmap(chip->iobase);	pci_release_regions(chip->pci);	pci_disable_device(chip->pci);	kfree(chip);	return 0;}static intsnd_ad1889_dev_free(struct snd_device *device) {	struct snd_ad1889 *chip = device->device_data;	return snd_ad1889_free(chip);}static int __devinitsnd_ad1889_init(struct snd_ad1889 *chip) {	ad1889_writew(chip, AD_DS_CCS, AD_DS_CCS_CLKEN); /* turn on clock */	ad1889_readw(chip, AD_DS_CCS);	/* flush posted write */	mdelay(10);	/* enable Master and Target abort interrupts */	ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PMAE | AD_DMA_DISR_PTAE);	return 0;}static int __devinitsnd_ad1889_create(struct snd_card *card,		  struct pci_dev *pci,		  struct snd_ad1889 **rchip){	int err;	struct snd_ad1889 *chip;	static struct snd_device_ops ops = {		.dev_free = snd_ad1889_dev_free,	};	*rchip = NULL;	if ((err = pci_enable_device(pci)) < 0)		return err;	/* check PCI availability (32bit DMA) */	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 ||	    pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) {		printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n");		pci_disable_device(pci);		return -ENXIO;	}	/* allocate chip specific data with zero-filled memory */	if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) {		pci_disable_device(pci);		return -ENOMEM;	}	chip->card = card;	card->private_data = chip;	chip->pci = pci;	chip->irq = -1;	/* (1) PCI resource allocation */	if ((err = pci_request_regions(pci, card->driver)) < 0)		goto free_and_ret;	chip->bar = pci_resource_start(pci, 0);	chip->iobase = ioremap_nocache(chip->bar, pci_resource_len(pci, 0));	if (chip->iobase == NULL) {		printk(KERN_ERR PFX "unable to reserve region.\n");		err = -EBUSY;		goto free_and_ret;	}		pci_set_master(pci);	spin_lock_init(&chip->lock);	/* only now can we call ad1889_free */	if (request_irq(pci->irq, snd_ad1889_interrupt,			IRQF_SHARED, card->driver, chip)) {		printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);		snd_ad1889_free(chip);		return -EBUSY;	}	chip->irq = pci->irq;	synchronize_irq(chip->irq);	/* (2) initialization of the chip hardware */	if ((err = snd_ad1889_init(chip)) < 0) {		snd_ad1889_free(chip);		return err;	}	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {		snd_ad1889_free(chip);		return err;	}	snd_card_set_dev(card, &pci->dev);	*rchip = chip;	return 0;free_and_ret:	kfree(chip);	pci_disable_device(pci);	return err;}static int __devinitsnd_ad1889_probe(struct pci_dev *pci,		 const struct pci_device_id *pci_id){	int err;	static int devno;	struct snd_card *card;	struct snd_ad1889 *chip;	/* (1) */	if (devno >= SNDRV_CARDS)		return -ENODEV;	if (!enable[devno]) {		devno++;		return -ENOENT;	}	/* (2) */	card = snd_card_new(index[devno], id[devno], THIS_MODULE, 0);	/* XXX REVISIT: we can probably allocate chip in this call */	if (card == NULL)		return -ENOMEM;	strcpy(card->driver, "AD1889");	strcpy(card->shortname, "Analog Devices AD1889");	/* (3) */	err = snd_ad1889_create(card, pci, &chip);	if (err < 0)		goto free_and_ret;	/* (4) */	sprintf(card->longname, "%s at 0x%lx irq %i",		card->shortname, chip->bar, chip->irq);	/* (5) */	/* register AC97 mixer */	err = snd_ad1889_ac97_init(chip, ac97_quirk[devno]);	if (err < 0)		goto free_and_ret;		err = snd_ad1889_pcm_init(chip, 0, NULL);	if (err < 0)		goto free_and_ret;	/* register proc interface */	snd_ad1889_proc_init(chip);	/* (6) */	err = snd_card_register(card);	if (err < 0)		goto free_and_ret;	/* (7) */	pci_set_drvdata(pci, card);	devno++;	return 0;free_and_ret:	snd_card_free(card);	return err;}static void __devexitsnd_ad1889_remove(struct pci_dev *pci){	snd_card_free(pci_get_drvdata(pci));	pci_set_drvdata(pci, NULL);}static struct pci_device_id snd_ad1889_ids[] = {	{ PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) },	{ 0, },};MODULE_DEVICE_TABLE(pci, snd_ad1889_ids);static struct pci_driver ad1889_pci = {	.name = "AD1889 Audio",	.id_table = snd_ad1889_ids,	.probe = snd_ad1889_probe,	.remove = __devexit_p(snd_ad1889_remove),};static int __initalsa_ad1889_init(void){	return pci_register_driver(&ad1889_pci);}static void __exitalsa_ad1889_fini(void){	pci_unregister_driver(&ad1889_pci);}module_init(alsa_ad1889_init);module_exit(alsa_ad1889_fini);

⌨️ 快捷键说明

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