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

📄 ad1889.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Analog Devices 1889 audio driver * * This is a driver for the AD1889 PCI audio chipset found * on the HP PA-RISC [BCJ]-xxx0 workstations. * * Copyright (C) 2004-2005, Kyle McMartin <kyle@parisc-linux.org> * Copyright (C) 2005, Thibaut Varene <varenet@parisc-linux.org> *   Based on the OSS AD1889 driver by Randolph Chung <tausq@debian.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * TODO: *	Do we need to take care of CCS register? *	Maybe we could use finer grained locking (separate locks for pb/cap)? * Wishlist: *	Control Interface (mixer) support *	Better AC97 support (VSR...)? *	PM support *	MIDI support *	Game Port support *	SG DMA support (this will need *alot* of work) */#include <linux/init.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/compiler.h>#include <linux/delay.h>#include <sound/driver.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/initval.h>#include <sound/ac97_codec.h>#include <asm/io.h>#include "ad1889.h"#include "ac97/ac97_id.h"#define	AD1889_DRVVER	"Version: 1.7"MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>, Thibaut Varene <t-bone@parisc-linux.org>");MODULE_DESCRIPTION("Analog Devices AD1889 ALSA sound driver");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1889}}");static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for the AD1889 soundcard.");static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for the AD1889 soundcard.");static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable AD1889 soundcard.");static char *ac97_quirk[SNDRV_CARDS];module_param_array(ac97_quirk, charp, NULL, 0444);MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");#define DEVNAME "ad1889"#define PFX	DEVNAME ": "/* let's use the global sound debug interfaces */#define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)/* keep track of some hw registers */struct ad1889_register_state {	u16 reg;	/* reg setup */	u32 addr;	/* dma base address */	unsigned long size;	/* DMA buffer size */};struct snd_ad1889 {	struct snd_card *card;	struct pci_dev *pci;	int irq;	unsigned long bar;	void __iomem *iobase;	struct snd_ac97 *ac97;	struct snd_ac97_bus *ac97_bus;	struct snd_pcm *pcm;	struct snd_info_entry *proc;	struct snd_pcm_substream *psubs;	struct snd_pcm_substream *csubs;	/* playback register state */	struct ad1889_register_state wave;	struct ad1889_register_state ramc;	spinlock_t lock;};static inline u16ad1889_readw(struct snd_ad1889 *chip, unsigned reg){	return readw(chip->iobase + reg);}static inline voidad1889_writew(struct snd_ad1889 *chip, unsigned reg, u16 val){	writew(val, chip->iobase + reg);}static inline u32ad1889_readl(struct snd_ad1889 *chip, unsigned reg){	return readl(chip->iobase + reg);}static inline voidad1889_writel(struct snd_ad1889 *chip, unsigned reg, u32 val){	writel(val, chip->iobase + reg);}static inline voidad1889_unmute(struct snd_ad1889 *chip){	u16 st;	st = ad1889_readw(chip, AD_DS_WADA) & 		~(AD_DS_WADA_RWAM | AD_DS_WADA_LWAM);	ad1889_writew(chip, AD_DS_WADA, st);	ad1889_readw(chip, AD_DS_WADA);}static inline voidad1889_mute(struct snd_ad1889 *chip){	u16 st;	st = ad1889_readw(chip, AD_DS_WADA) | AD_DS_WADA_RWAM | AD_DS_WADA_LWAM;	ad1889_writew(chip, AD_DS_WADA, st);	ad1889_readw(chip, AD_DS_WADA);}static inline voidad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address){	ad1889_writel(chip, AD_DMA_ADCBA, address);	ad1889_writel(chip, AD_DMA_ADCCA, address);}static inline voidad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count){	ad1889_writel(chip, AD_DMA_ADCBC, count);	ad1889_writel(chip, AD_DMA_ADCCC, count);}static inline voidad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count){	ad1889_writel(chip, AD_DMA_ADCIB, count);	ad1889_writel(chip, AD_DMA_ADCIC, count);}static inline voidad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32 address){	ad1889_writel(chip, AD_DMA_WAVBA, address);	ad1889_writel(chip, AD_DMA_WAVCA, address);}static inline voidad1889_load_wave_buffer_count(struct snd_ad1889 *chip, u32 count){	ad1889_writel(chip, AD_DMA_WAVBC, count);	ad1889_writel(chip, AD_DMA_WAVCC, count);}static inline voidad1889_load_wave_interrupt_count(struct snd_ad1889 *chip, u32 count){	ad1889_writel(chip, AD_DMA_WAVIB, count);	ad1889_writel(chip, AD_DMA_WAVIC, count);}static voidad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel){	u16 reg;		if (channel & AD_CHAN_WAV) {		/* Disable wave channel */		reg = ad1889_readw(chip, AD_DS_WSMC) & ~AD_DS_WSMC_WAEN;		ad1889_writew(chip, AD_DS_WSMC, reg);		chip->wave.reg = reg;				/* disable IRQs */		reg = ad1889_readw(chip, AD_DMA_WAV);		reg &= AD_DMA_IM_DIS;		reg &= ~AD_DMA_LOOP;		ad1889_writew(chip, AD_DMA_WAV, reg);		/* clear IRQ and address counters and pointers */		ad1889_load_wave_buffer_address(chip, 0x0);		ad1889_load_wave_buffer_count(chip, 0x0);		ad1889_load_wave_interrupt_count(chip, 0x0);		/* flush */		ad1889_readw(chip, AD_DMA_WAV);	}		if (channel & AD_CHAN_ADC) {		/* Disable ADC channel */		reg = ad1889_readw(chip, AD_DS_RAMC) & ~AD_DS_RAMC_ADEN;		ad1889_writew(chip, AD_DS_RAMC, reg);		chip->ramc.reg = reg;		reg = ad1889_readw(chip, AD_DMA_ADC);		reg &= AD_DMA_IM_DIS;		reg &= ~AD_DMA_LOOP;		ad1889_writew(chip, AD_DMA_ADC, reg);			ad1889_load_adc_buffer_address(chip, 0x0);		ad1889_load_adc_buffer_count(chip, 0x0);		ad1889_load_adc_interrupt_count(chip, 0x0);		/* flush */		ad1889_readw(chip, AD_DMA_ADC);	}}static u16snd_ad1889_ac97_read(struct snd_ac97 *ac97, unsigned short reg){	struct snd_ad1889 *chip = ac97->private_data;	return ad1889_readw(chip, AD_AC97_BASE + reg);}static voidsnd_ad1889_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val){	struct snd_ad1889 *chip = ac97->private_data;	ad1889_writew(chip, AD_AC97_BASE + reg, val);}static intsnd_ad1889_ac97_ready(struct snd_ad1889 *chip){	int retry = 400; /* average needs 352 msec */		while (!(ad1889_readw(chip, AD_AC97_ACIC) & AD_AC97_ACIC_ACRDY) 			&& --retry)		mdelay(1);	if (!retry) {		snd_printk(KERN_ERR PFX "[%s] Link is not ready.\n",		       __FUNCTION__);		return -EIO;	}	ad1889_debug("[%s] ready after %d ms\n", __FUNCTION__, 400 - retry);	return 0;}static int snd_ad1889_hw_params(struct snd_pcm_substream *substream,			struct snd_pcm_hw_params *hw_params){	return snd_pcm_lib_malloc_pages(substream, 					params_buffer_bytes(hw_params));}static intsnd_ad1889_hw_free(struct snd_pcm_substream *substream){	return snd_pcm_lib_free_pages(substream);}static struct snd_pcm_hardware snd_ad1889_playback_hw = {	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |		SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER,	.formats = SNDRV_PCM_FMTBIT_S16_LE,	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min = 8000,	/* docs say 7000, but we're lazy */	.rate_max = 48000,	.channels_min = 1,	.channels_max = 2,	.buffer_bytes_max = BUFFER_BYTES_MAX,	.period_bytes_min = PERIOD_BYTES_MIN,	.period_bytes_max = PERIOD_BYTES_MAX,	.periods_min = PERIODS_MIN,	.periods_max = PERIODS_MAX,	/*.fifo_size = 0,*/};static struct snd_pcm_hardware snd_ad1889_capture_hw = {	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |		SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER,	.formats = SNDRV_PCM_FMTBIT_S16_LE,	.rates = SNDRV_PCM_RATE_48000,	.rate_min = 48000,	/* docs say we could to VSR, but we're lazy */	.rate_max = 48000,	.channels_min = 1,	.channels_max = 2,	.buffer_bytes_max = BUFFER_BYTES_MAX,	.period_bytes_min = PERIOD_BYTES_MIN,	.period_bytes_max = PERIOD_BYTES_MAX,	.periods_min = PERIODS_MIN,	.periods_max = PERIODS_MAX,	/*.fifo_size = 0,*/};static intsnd_ad1889_playback_open(struct snd_pcm_substream *ss){	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	struct snd_pcm_runtime *rt = ss->runtime;	chip->psubs = ss;	rt->hw = snd_ad1889_playback_hw;	return 0;}static intsnd_ad1889_capture_open(struct snd_pcm_substream *ss){	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	struct snd_pcm_runtime *rt = ss->runtime;	chip->csubs = ss;	rt->hw = snd_ad1889_capture_hw;	return 0;}static intsnd_ad1889_playback_close(struct snd_pcm_substream *ss){	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	chip->psubs = NULL;	return 0;}static intsnd_ad1889_capture_close(struct snd_pcm_substream *ss){	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	chip->csubs = NULL;	return 0;}static intsnd_ad1889_playback_prepare(struct snd_pcm_substream *ss){	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	struct snd_pcm_runtime *rt = ss->runtime;	unsigned int size = snd_pcm_lib_buffer_bytes(ss);	unsigned int count = snd_pcm_lib_period_bytes(ss);	u16 reg;	ad1889_channel_reset(chip, AD_CHAN_WAV);	reg = ad1889_readw(chip, AD_DS_WSMC);		/* Mask out 16-bit / Stereo */	reg &= ~(AD_DS_WSMC_WA16 | AD_DS_WSMC_WAST);	if (snd_pcm_format_width(rt->format) == 16)		reg |= AD_DS_WSMC_WA16;	if (rt->channels > 1)		reg |= AD_DS_WSMC_WAST;	/* let's make sure we don't clobber ourselves */	spin_lock_irq(&chip->lock);		chip->wave.size = size;	chip->wave.reg = reg;	chip->wave.addr = rt->dma_addr;	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);		/* Set sample rates on the codec */	ad1889_writew(chip, AD_DS_WAS, rt->rate);	/* Set up DMA */	ad1889_load_wave_buffer_address(chip, chip->wave.addr);	ad1889_load_wave_buffer_count(chip, size);	ad1889_load_wave_interrupt_count(chip, count);	/* writes flush */	ad1889_readw(chip, AD_DS_WSMC);		spin_unlock_irq(&chip->lock);		ad1889_debug("prepare playback: addr = 0x%x, count = %u, "			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,			count, size, reg, rt->rate);	return 0;}static intsnd_ad1889_capture_prepare(struct snd_pcm_substream *ss){	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	struct snd_pcm_runtime *rt = ss->runtime;	unsigned int size = snd_pcm_lib_buffer_bytes(ss);	unsigned int count = snd_pcm_lib_period_bytes(ss);	u16 reg;	ad1889_channel_reset(chip, AD_CHAN_ADC);		reg = ad1889_readw(chip, AD_DS_RAMC);	/* Mask out 16-bit / Stereo */	reg &= ~(AD_DS_RAMC_AD16 | AD_DS_RAMC_ADST);	if (snd_pcm_format_width(rt->format) == 16)		reg |= AD_DS_RAMC_AD16;	if (rt->channels > 1)		reg |= AD_DS_RAMC_ADST;	/* let's make sure we don't clobber ourselves */	spin_lock_irq(&chip->lock);		chip->ramc.size = size;	chip->ramc.reg = reg;	chip->ramc.addr = rt->dma_addr;	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);	/* Set up DMA */	ad1889_load_adc_buffer_address(chip, chip->ramc.addr);	ad1889_load_adc_buffer_count(chip, size);	ad1889_load_adc_interrupt_count(chip, count);	/* writes flush */	ad1889_readw(chip, AD_DS_RAMC);		spin_unlock_irq(&chip->lock);		ad1889_debug("prepare capture: addr = 0x%x, count = %u, "			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,			count, size, reg, rt->rate);	return 0;}/* this is called in atomic context with IRQ disabled.   Must be as fast as possible and not sleep.   DMA should be *triggered* by this call.   The WSMC "WAEN" bit triggers DMA Wave On/Off */static intsnd_ad1889_playback_trigger(struct snd_pcm_substream *ss, int cmd){	u16 wsmc;	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);		wsmc = ad1889_readw(chip, AD_DS_WSMC);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		/* enable DMA loop & interrupts */		ad1889_writew(chip, AD_DMA_WAV, AD_DMA_LOOP | AD_DMA_IM_CNT);		wsmc |= AD_DS_WSMC_WAEN;		/* 1 to clear CHSS bit */		ad1889_writel(chip, AD_DMA_CHSS, AD_DMA_CHSS_WAVS);		ad1889_unmute(chip);		break;	case SNDRV_PCM_TRIGGER_STOP:		ad1889_mute(chip);		wsmc &= ~AD_DS_WSMC_WAEN;		break;	default:		snd_BUG();		return -EINVAL;	}		chip->wave.reg = wsmc;	ad1889_writew(chip, AD_DS_WSMC, wsmc);		ad1889_readw(chip, AD_DS_WSMC);	/* flush */	/* reset the chip when STOP - will disable IRQs */	if (cmd == SNDRV_PCM_TRIGGER_STOP)		ad1889_channel_reset(chip, AD_CHAN_WAV);	return 0;}/* this is called in atomic context with IRQ disabled.   Must be as fast as possible and not sleep.   DMA should be *triggered* by this call.   The RAMC "ADEN" bit triggers DMA ADC On/Off */static intsnd_ad1889_capture_trigger(struct snd_pcm_substream *ss, int cmd){	u16 ramc;	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);	ramc = ad1889_readw(chip, AD_DS_RAMC);		switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		/* enable DMA loop & interrupts */		ad1889_writew(chip, AD_DMA_ADC, AD_DMA_LOOP | AD_DMA_IM_CNT);		ramc |= AD_DS_RAMC_ADEN;		/* 1 to clear CHSS bit */		ad1889_writel(chip, AD_DMA_CHSS, AD_DMA_CHSS_ADCS);		break;	case SNDRV_PCM_TRIGGER_STOP:		ramc &= ~AD_DS_RAMC_ADEN;		break;	default:		return -EINVAL;	}		chip->ramc.reg = ramc;	ad1889_writew(chip, AD_DS_RAMC, ramc);		ad1889_readw(chip, AD_DS_RAMC);	/* flush */		/* reset the chip when STOP - will disable IRQs */	if (cmd == SNDRV_PCM_TRIGGER_STOP)		ad1889_channel_reset(chip, AD_CHAN_ADC);			return 0;}/* Called in atomic context with IRQ disabled */

⌨️ 快捷键说明

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