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

📄 ad1848_lib.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> *  Routines for control of AD1848/AD1847/CS4248 * * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */#define SNDRV_MAIN_OBJECT_FILE#include <sound/driver.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/pm.h>#include <linux/slab.h>#include <linux/ioport.h>#include <sound/core.h>#include <sound/ad1848.h>#include <sound/control.h>#include <sound/pcm_params.h>#include <asm/io.h>#include <asm/dma.h>MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248");MODULE_LICENSE("GPL");#if 0#define SNDRV_DEBUG_MCE#endif/* *  Some variables */static unsigned char freq_bits[14] = {	/* 5510 */	0x00 | AD1848_XTAL2,	/* 6620 */	0x0E | AD1848_XTAL2,	/* 8000 */	0x00 | AD1848_XTAL1,	/* 9600 */	0x0E | AD1848_XTAL1,	/* 11025 */	0x02 | AD1848_XTAL2,	/* 16000 */	0x02 | AD1848_XTAL1,	/* 18900 */	0x04 | AD1848_XTAL2,	/* 22050 */	0x06 | AD1848_XTAL2,	/* 27042 */	0x04 | AD1848_XTAL1,	/* 32000 */	0x06 | AD1848_XTAL1,	/* 33075 */	0x0C | AD1848_XTAL2,	/* 37800 */	0x08 | AD1848_XTAL2,	/* 44100 */	0x0A | AD1848_XTAL2,	/* 48000 */	0x0C | AD1848_XTAL1};static unsigned int rates[14] = {	5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,	27042, 32000, 33075, 37800, 44100, 48000};static snd_pcm_hw_constraint_list_t hw_constraints_rates = {	.count = 14,	.list = rates,	.mask = 0,};static unsigned char snd_ad1848_original_image[16] ={	0x00,			/* 00 - lic */	0x00,			/* 01 - ric */	0x9f,			/* 02 - la1ic */	0x9f,			/* 03 - ra1ic */	0x9f,			/* 04 - la2ic */	0x9f,			/* 05 - ra2ic */	0xbf,			/* 06 - loc */	0xbf,			/* 07 - roc */	0x20,			/* 08 - dfr */	AD1848_AUTOCALIB,	/* 09 - ic */	0x00,			/* 0a - pc */	0x00,			/* 0b - ti */	0x00,			/* 0c - mi */	0x00,			/* 0d - lbc */	0x00,			/* 0e - dru */	0x00,			/* 0f - drl */};/* *  Basic I/O functions */void snd_ad1848_out(ad1848_t *chip,			   unsigned char reg,			   unsigned char value){	int timeout;	for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)		udelay(100);#ifdef CONFIG_SND_DEBUG	if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)		snd_printk(KERN_WARNING "auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);#endif	outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));	outb(chip->image[reg] = value, AD1848P(chip, REG));	mb();#if 0	printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);#endif}static void snd_ad1848_dout(ad1848_t *chip,			    unsigned char reg, unsigned char value){	int timeout;	for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)		udelay(100);	outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));	outb(value, AD1848P(chip, REG));	mb();}static unsigned char snd_ad1848_in(ad1848_t *chip, unsigned char reg){	int timeout;	for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)		udelay(100);#ifdef CONFIG_SND_DEBUG	if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)		snd_printk(KERN_WARNING "auto calibration time out - reg = 0x%x\n", reg);#endif	outb(chip->mce_bit | reg, AD1848P(chip, REGSEL));	mb();	return inb(AD1848P(chip, REG));}#if 0static void snd_ad1848_debug(ad1848_t *chip){	printk("AD1848 REGS:      INDEX = 0x%02x  ", inb(AD1848P(chip, REGSEL)));	printk("                 STATUS = 0x%02x\n", inb(AD1848P(chip, STATUS)));	printk("  0x00: left input      = 0x%02x  ", snd_ad1848_in(chip, 0x00));	printk("  0x08: playback format = 0x%02x\n", snd_ad1848_in(chip, 0x08));	printk("  0x01: right input     = 0x%02x  ", snd_ad1848_in(chip, 0x01));	printk("  0x09: iface (CFIG 1)  = 0x%02x\n", snd_ad1848_in(chip, 0x09));	printk("  0x02: AUXA left       = 0x%02x  ", snd_ad1848_in(chip, 0x02));	printk("  0x0a: pin control     = 0x%02x\n", snd_ad1848_in(chip, 0x0a));	printk("  0x03: AUXA right      = 0x%02x  ", snd_ad1848_in(chip, 0x03));	printk("  0x0b: init & status   = 0x%02x\n", snd_ad1848_in(chip, 0x0b));	printk("  0x04: AUXB left       = 0x%02x  ", snd_ad1848_in(chip, 0x04));	printk("  0x0c: revision & mode = 0x%02x\n", snd_ad1848_in(chip, 0x0c));	printk("  0x05: AUXB right      = 0x%02x  ", snd_ad1848_in(chip, 0x05));	printk("  0x0d: loopback        = 0x%02x\n", snd_ad1848_in(chip, 0x0d));	printk("  0x06: left output     = 0x%02x  ", snd_ad1848_in(chip, 0x06));	printk("  0x0e: data upr count  = 0x%02x\n", snd_ad1848_in(chip, 0x0e));	printk("  0x07: right output    = 0x%02x  ", snd_ad1848_in(chip, 0x07));	printk("  0x0f: data lwr count  = 0x%02x\n", snd_ad1848_in(chip, 0x0f));}#endif/* *  AD1848 detection / MCE routines */static void snd_ad1848_mce_up(ad1848_t *chip){	unsigned long flags;	int timeout;	for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)		udelay(100);#ifdef CONFIG_SND_DEBUG	if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)		snd_printk(KERN_WARNING "mce_up - auto calibration time out (0)\n");#endif	spin_lock_irqsave(&chip->reg_lock, flags);	chip->mce_bit |= AD1848_MCE;	timeout = inb(AD1848P(chip, REGSEL));	if (timeout == 0x80)		snd_printk(KERN_WARNING "mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);	if (!(timeout & AD1848_MCE))		outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL));	spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_ad1848_mce_down(ad1848_t *chip){	unsigned long flags;	int timeout;	signed long time;	spin_lock_irqsave(&chip->reg_lock, flags);	for (timeout = 5; timeout > 0; timeout--)		inb(AD1848P(chip, REGSEL));	/* end of cleanup sequence */	for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)		udelay(100);#if 0	printk("(1) timeout = %i\n", timeout);#endif#ifdef CONFIG_SND_DEBUG	if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)		snd_printk(KERN_WARNING "mce_down [0x%lx] - auto calibration time out (0)\n", AD1848P(chip, REGSEL));#endif	chip->mce_bit &= ~AD1848_MCE;	timeout = inb(AD1848P(chip, REGSEL));	outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL));	if (timeout == 0x80)		snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);	if ((timeout & AD1848_MCE) == 0) {		spin_unlock_irqrestore(&chip->reg_lock, flags);		return;	}	/* calibration process */	for (timeout = 500; timeout > 0 && (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) == 0; timeout--);	if ((snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) == 0) {		snd_printd("mce_down - auto calibration time out (1)\n");		spin_unlock_irqrestore(&chip->reg_lock, flags);		return;	}#if 0	printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);#endif	time = HZ / 4;	while (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) {		spin_unlock_irqrestore(&chip->reg_lock, flags);		if (time <= 0) {			snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n");			return;		}		time = schedule_timeout_interruptible(time);		spin_lock_irqsave(&chip->reg_lock, flags);	}#if 0	printk("(3) jiffies = %li\n", jiffies);#endif	time = HZ / 10;	while (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) {		spin_unlock_irqrestore(&chip->reg_lock, flags);		if (time <= 0) {			snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");			return;		}		time = schedule_timeout_interruptible(time);		spin_lock_irqsave(&chip->reg_lock, flags);	}	spin_unlock_irqrestore(&chip->reg_lock, flags);#if 0	printk("(4) jiffies = %li\n", jiffies);	snd_printk("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL)));#endif}static unsigned int snd_ad1848_get_count(unsigned char format,				         unsigned int size){	switch (format & 0xe0) {	case AD1848_LINEAR_16:		size >>= 1;		break;	}	if (format & AD1848_STEREO)		size >>= 1;	return size;}static int snd_ad1848_trigger(ad1848_t *chip, unsigned char what,			      int channel, int cmd){	int result = 0;#if 0	printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, inb(AD1848P(card, STATUS)));#endif	spin_lock(&chip->reg_lock);	if (cmd == SNDRV_PCM_TRIGGER_START) {		if (chip->image[AD1848_IFACE_CTRL] & what) {			spin_unlock(&chip->reg_lock);			return 0;		}		snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] |= what);		chip->mode |= AD1848_MODE_RUNNING;	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {		if (!(chip->image[AD1848_IFACE_CTRL] & what)) {			spin_unlock(&chip->reg_lock);			return 0;		}		snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] &= ~what);		chip->mode &= ~AD1848_MODE_RUNNING;	} else {		result = -EINVAL;	}	spin_unlock(&chip->reg_lock);	return result;}/* *  CODEC I/O */static unsigned char snd_ad1848_get_rate(unsigned int rate){	int i;	for (i = 0; i < 14; i++)		if (rate == rates[i])			return freq_bits[i];	snd_BUG();	return freq_bits[13];}static int snd_ad1848_ioctl(snd_pcm_substream_t * substream,			    unsigned int cmd, void *arg){	return snd_pcm_lib_ioctl(substream, cmd, arg);}static unsigned char snd_ad1848_get_format(int format, int channels){	unsigned char rformat;	rformat = AD1848_LINEAR_8;	switch (format) {	case SNDRV_PCM_FORMAT_A_LAW:	rformat = AD1848_ALAW_8; break;	case SNDRV_PCM_FORMAT_MU_LAW:	rformat = AD1848_ULAW_8; break;	case SNDRV_PCM_FORMAT_S16_LE:	rformat = AD1848_LINEAR_16; break;	}	if (channels > 1)		rformat |= AD1848_STEREO;#if 0	snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);#endif	return rformat;}static void snd_ad1848_calibrate_mute(ad1848_t *chip, int mute){	unsigned long flags;		mute = mute ? 1 : 0;	spin_lock_irqsave(&chip->reg_lock, flags);	if (chip->calibrate_mute == mute) {		spin_unlock_irqrestore(&chip->reg_lock, flags);		return;	}	if (!mute) {		snd_ad1848_dout(chip, AD1848_LEFT_INPUT, chip->image[AD1848_LEFT_INPUT]);		snd_ad1848_dout(chip, AD1848_RIGHT_INPUT, chip->image[AD1848_RIGHT_INPUT]);	}	snd_ad1848_dout(chip, AD1848_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_LEFT_INPUT]);	snd_ad1848_dout(chip, AD1848_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_RIGHT_INPUT]);	snd_ad1848_dout(chip, AD1848_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_LEFT_INPUT]);	snd_ad1848_dout(chip, AD1848_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_RIGHT_INPUT]);	snd_ad1848_dout(chip, AD1848_LEFT_OUTPUT, mute ? 0x80 : chip->image[AD1848_LEFT_OUTPUT]);	snd_ad1848_dout(chip, AD1848_RIGHT_OUTPUT, mute ? 0x80 : chip->image[AD1848_RIGHT_OUTPUT]);	chip->calibrate_mute = mute;	spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_ad1848_set_data_format(ad1848_t *chip, snd_pcm_hw_params_t *hw_params){	if (hw_params == NULL) {		chip->image[AD1848_DATA_FORMAT] = 0x20;	} else {		chip->image[AD1848_DATA_FORMAT] =		    snd_ad1848_get_format(params_format(hw_params), params_channels(hw_params)) |		    snd_ad1848_get_rate(params_rate(hw_params));	}	// snd_printk(">>> pmode = 0x%x, dfr = 0x%x\n", pstr->mode, chip->image[AD1848_DATA_FORMAT]);}static int snd_ad1848_open(ad1848_t *chip, unsigned int mode){	unsigned long flags;	down(&chip->open_mutex);	if (chip->mode & AD1848_MODE_OPEN) {		up(&chip->open_mutex);		return -EAGAIN;	}	snd_ad1848_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("open: (1)\n");#endif	snd_ad1848_mce_up(chip);	spin_lock_irqsave(&chip->reg_lock, flags);	chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO |			     AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO |			     AD1848_CALIB_MODE);	chip->image[AD1848_IFACE_CTRL] |= AD1848_AUTOCALIB;	snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_ad1848_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("open: (2)\n");#endif	snd_ad1848_set_data_format(chip, NULL);	snd_ad1848_mce_up(chip);	spin_lock_irqsave(&chip->reg_lock, flags);	snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_ad1848_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("open: (3)\n");#endif

⌨️ 快捷键说明

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