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

📄 uda1341.c

📁 基于linux kernel 2.6.20的UDA1341声音芯片的声卡驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Philips UDA1341 mixer device driver * * Copyright (c) 2000 Nicolas Pitre <nico@cam.org> * * Portions are Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License. * * History: * * 2000-05-21	Nicolas Pitre	Initial release. * * 2000-08-19	Erik Bunce	More inline w/ OSS API and UDA1341 docs * 				including fixed AGC and audio source handling * * 2000-11-30	Nicolas Pitre	- More mixer functionalities. * * 2001-06-03	Nicolas Pitre	Made this file a separate module, based on * 				the former sa1100-uda1341.c driver. * * 2001-08-13	Russell King	Re-written as part of the L3 interface *///#define DEBUG 1#include "debug.h"#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/err.h>#include "l3.h"#include "uda1341.h"#include <sound/driver.h>#include <sound/core.h>#include <sound/control.h>#ifdef DEBUG#undef pr_debug#define pr_debug(fmt,arg...) printk(fmt,##arg)#endif/* * UDA1341 L3 address and command types */#define UDA1341_L3ADDR		5#define UDA1341_DATA0		(UDA1341_L3ADDR << 2 | 0)#define UDA1341_DATA1		(UDA1341_L3ADDR << 2 | 1)#define UDA1341_STATUS		(UDA1341_L3ADDR << 2 | 2)struct uda1341_regs {	unsigned char	stat0;	char            dirty0;#define STAT0			0x00#define STAT0_RST		(1 << 6)#define STAT0_SC_MASK		(3 << 4)#define STAT0_SC_512FS		(0 << 4)#define STAT0_SC_384FS		(1 << 4)#define STAT0_SC_256FS		(2 << 4)#define STAT0_IF_MASK		(7 << 1)#define STAT0_IF_I2S		(0 << 1)#define STAT0_IF_LSB16		(1 << 1)#define STAT0_IF_LSB18		(2 << 1)#define STAT0_IF_LSB20		(3 << 1)#define STAT0_IF_MSB		(4 << 1)#define STAT0_IF_LSB16MSB	(5 << 1)#define STAT0_IF_LSB18MSB	(6 << 1)#define STAT0_IF_LSB20MSB	(7 << 1)#define STAT0_DC_FILTER		(1 << 0)	unsigned char	stat1;	char            dirty1;#define STAT1			0x80#define STAT1_DAC_GAIN		(1 << 6)	/* gain of DAC */#define STAT1_ADC_GAIN		(1 << 5)	/* gain of ADC */#define STAT1_ADC_POL		(1 << 4)	/* polarity of ADC */#define STAT1_DAC_POL		(1 << 3)	/* polarity of DAC */#define STAT1_DBL_SPD		(1 << 2)	/* double speed playback */#define STAT1_ADC_ON		(1 << 1)	/* ADC powered */#define STAT1_DAC_ON		(1 << 0)	/* DAC powered */	unsigned char	data0[9];	char            dirty[9];#define REGDIR0	0#define REGDIR1	1#define REGDIR2	2#define REGEXT0	3#define REGEXT1	4#define REGEXT2	5#define REGEXT4	6#define REGEXT5	7#define REGEXT6	8#define DIR0			0x00#define DATA0_VOLUME_MASK	0x3f#define DATA0_VOLUME(x)		(x)#define DIR1			0x40#define DATA1_BASS(x)		((x) << 2)#define DATA1_BASS_MASK		(15 << 2)#define DATA1_TREBLE(x)		((x))#define DATA1_TREBLE_MASK	(3)#define DIR2			0x80#define DATA2_PEAKAFTER		(1 << 5)#define DATA2_DEEMP_NONE	(0 << 3)#define DATA2_DEEMP_32KHz	(1 << 3)#define DATA2_DEEMP_44KHz	(2 << 3)#define DATA2_DEEMP_48KHz	(3 << 3)#define DATA2_MUTE		(1 << 2)#define DATA2_FILTER_FLAT	(0 << 0)#define DATA2_FILTER_MIN	(1 << 0)#define DATA2_FILTER_MAX	(3 << 0)#define EXTADDR(n)		(0xc0 | (n))#define EXTDATA(d)		(0xe0 | (d))#define EXT0			0#define EXT0_CH1_GAIN(x)	(x)#define EXT1			1#define EXT1_CH2_GAIN(x)	(x)#define EXT2			2#define EXT2_MIC_GAIN_MASK	(7 << 2)#define EXT2_MIC_GAIN(x)	((x) << 2)#define EXT2_MIXMODE_DOUBLEDIFF	(0)#define EXT2_MIXMODE_CH1	(1)#define EXT2_MIXMODE_CH2	(2)#define EXT2_MIXMODE_MIX	(3)#define EXT4			4#define EXT4_AGC_ENABLE		(1 << 4)#define EXT4_INPUT_GAIN_MASK	(3)#define EXT4_INPUT_GAIN(x)	((x) & 3)#define EXT5			5#define EXT5_INPUT_GAIN(x)	((x) >> 2)#define EXT6			6#define EXT6_AGC_CONSTANT_MASK	(7 << 2)#define EXT6_AGC_CONSTANT(x)	((x) << 2)#define EXT6_AGC_LEVEL_MASK	(3)#define EXT6_AGC_LEVEL(x)	(x)};struct uda1341 {	spinlock_t		lock;	int			active;	struct l3_adapter	*l3_bus;	struct uda1341_regs	regs;};static const unsigned char regv[] = {	[REGDIR0] = DIR0,	[REGDIR1] = DIR1,	[REGDIR2] = DIR2,	[REGEXT0] = EXT0,	[REGEXT1] = EXT1,	[REGEXT2] = EXT2,	[REGEXT4] = EXT4,	[REGEXT5] = EXT5,	[REGEXT6] = EXT6};static inline unsigned char *uda1341_add_reg(struct uda1341 *uda, unsigned char *p, int ctl){	pr_debug("--- %s\n", __FUNCTION__);	if (ctl < REGEXT0) {		*p++ = regv[ctl] | uda->regs.data0[ctl];	} else {		*p++ = regv[ctl] | 0xc0;		*p++ = uda->regs.data0[ctl] | 0xe0;	}	return p;}static void uda1341_sync(struct uda1341 *uda){	unsigned char buf[24], *p = buf;	int i;	pr_debug(">>> %s\n", __FUNCTION__);	if (uda->regs.dirty0) {		*p++ = STAT0 | uda->regs.stat0;		uda->regs.dirty0 = 0;	}	if (uda->regs.dirty1) {		*p++ = STAT1 | uda->regs.stat1;		uda->regs.dirty1 = 0;	}	if (p != buf)		l3_write(uda->l3_bus, UDA1341_STATUS, buf, p - buf);		p = buf;	for(i=REGDIR0; i<=REGEXT6; i++) {		if (uda->regs.dirty[i]) {			p = uda1341_add_reg(uda, p, i);			uda->regs.dirty[i] = 0;		}	}	if (p != buf)		l3_write(uda->l3_bus, UDA1341_DATA0, buf, p - buf);}int uda1341_configure(struct uda1341 *uda, struct uda1341_cfg *conf){	int ret = 0;	pr_debug(">>> %s\n", __FUNCTION__);	uda->regs.stat0 &= ~(STAT0_SC_MASK | STAT0_IF_MASK);	switch (conf->fs) {	case 512: uda->regs.stat0 |= STAT0_SC_512FS;	break;	case 384: uda->regs.stat0 |= STAT0_SC_384FS;	break;	case 256: uda->regs.stat0 |= STAT0_SC_256FS;	break;	default:  ret = -EINVAL;			break;	}	switch (conf->format) {	case FMT_I2S:		uda->regs.stat0 |= STAT0_IF_I2S;	break;	case FMT_LSB16:		uda->regs.stat0 |= STAT0_IF_LSB16;	break;	case FMT_LSB18:		uda->regs.stat0 |= STAT0_IF_LSB18;	break;	case FMT_LSB20:		uda->regs.stat0 |= STAT0_IF_LSB20;	break;	case FMT_MSB:		uda->regs.stat0 |= STAT0_IF_MSB;	break;	case FMT_LSB16MSB:	uda->regs.stat0 |= STAT0_IF_LSB16MSB;	break;	case FMT_LSB18MSB:	uda->regs.stat0 |= STAT0_IF_LSB18MSB;	break;	case FMT_LSB20MSB:	uda->regs.stat0 |= STAT0_IF_LSB20MSB;	break;	default:		ret = -EINVAL;				break;	}	if (ret == 0) {		unsigned char buf[2] ;		buf[0] = uda->regs.stat0 | STAT0 | STAT0_DC_FILTER; //| STAT0_RST;		buf[1] = uda->regs.stat1 | STAT1;		if (conf->record) {			buf[1] |= STAT1_ADC_ON;		}		if (conf->play) {			buf[1] |= STAT1_DAC_ON;		}		pr_debug(">>> %s %d 0x%02x 0x%02x\n", __FUNCTION__, 1, buf[0], buf[1]);		l3_write(uda->l3_bus, UDA1341_STATUS, buf, 2);	}		return ret;}EXPORT_SYMBOL(uda1341_configure);struct uda1341_ctl {	const char *name;	snd_kcontrol_new_t *ctl;	unsigned char min;	unsigned char max;	unsigned char def;	unsigned char reg;	unsigned char mask;	unsigned char off;};static int uda1341_ctl_simple_info(snd_kcontrol_t *kc, snd_ctl_elem_info_t *ei){	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;	pr_debug("--- %s\n", __FUNCTION__);	ei->type = ctl->mask > 1 ? SNDRV_CTL_ELEM_TYPE_INTEGER :				  SNDRV_CTL_ELEM_TYPE_BOOLEAN;	ei->count = 1;	if (ctl->min > ctl->max) {		ei->value.integer.min = ctl->mask - ctl->min;		ei->value.integer.max = ctl->mask - ctl->max;	} else {		ei->value.integer.min = ctl->min;		ei->value.integer.max = ctl->max;	}	return 0;}static int uda1341_ctl_simple_get(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev){	struct uda1341 *uda = kc->private_data;	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;	unsigned int val;	pr_debug("--- %s\n", __FUNCTION__);	val = (uda->regs.data0[ctl->reg] >> ctl->off) & ctl->mask;	if (ctl->min > ctl->max)		val = ctl->mask - val;	ev->value.integer.value[0] = val;	return 0;}static int uda1341_ctl_simple_put(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev){	struct uda1341 *uda = kc->private_data;	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;	unsigned int val = ev->value.integer.value[0] & ctl->mask;	pr_debug(">>> %s: %s\n", __FUNCTION__, ctl->name);	if (ctl->reg == 0xff) {	  printk("BUG @ %s: %s ... plaease report!\n", __FUNCTION__, ctl->name);	}	if (ctl->min > ctl->max)		val = ctl->mask - val;	spin_lock(&uda->lock);	uda->regs.data0[ctl->reg] &= ~(ctl->mask << ctl->off);	uda->regs.data0[ctl->reg] |= val << ctl->off;	spin_unlock(&uda->lock);	if (uda->active) {		unsigned char buf[2], *p = buf;		p = uda1341_add_reg(uda, buf, ctl->reg);		pr_debug(">>> %s %d 0x%08x\n", __FUNCTION__, p-buf, buf[0]);		l3_write(uda->l3_bus, UDA1341_DATA0, buf, p - buf);	}	else {		uda->regs.dirty[ctl->reg] = 1;	}	return 0;}static int uda1341_ctl_stat1_get(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev){	struct uda1341 *uda = kc->private_data;	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;	unsigned int val;	pr_debug("--- %s\n", __FUNCTION__);	val = (uda->regs.stat1 >> ctl->off) & ctl->mask;	if (ctl->min > ctl->max)		val = ctl->mask - val;	ev->value.integer.value[0] = val;	return 0;}static int uda1341_ctl_stat1_put(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev){	struct uda1341 *uda = kc->private_data;	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;	unsigned int val = ev->value.integer.value[0] & ctl->mask;	pr_debug(">>> %s\n", __FUNCTION__);	if (ctl->min > ctl->max)		val = ctl->mask - val;	spin_lock(&uda->lock);	uda->regs.stat1 &= ~(ctl->mask << ctl->off);	uda->regs.stat1 |= val << ctl->off;	uda->regs.dirty1 = 1;	spin_unlock(&uda->lock);	return 0;}static int uda1341_ctl_ch2ig_get(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev){	struct uda1341 *uda = kc->private_data;	struct uda1341_ctl *ctl = (struct uda1341_ctl *)kc->private_value;	unsigned int val;	pr_debug("--- %s\n", __FUNCTION__);	val = uda->regs.data0[REGEXT4] | 		((uda->regs.data0[REGEXT5] & 31) << 2) ;	if (ctl->min > ctl->max)		val = ctl->mask - val;	ev->value.integer.value[0] = val;	return 0;}static int uda1341_ctl_ch2ig_put(snd_kcontrol_t *kc, snd_ctl_elem_value_t *ev){	struct uda1341 *uda = kc->private_data;

⌨️ 快捷键说明

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