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

📄 uda1341.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Philips UDA1341 mixer device driver * Copyright (c) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz> * * 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: * * 2002-03-13   Tomas Kasparek  initial release - based on uda1341.c from OSS * 2002-03-28   Tomas Kasparek  basic mixer is working (volume, bass, treble) * 2002-03-30   Tomas Kasparek  proc filesystem support, complete mixer and DSP *                              features support * 2002-04-12	Tomas Kasparek	proc interface update, code cleanup * 2002-05-12   Tomas Kasparek  another code cleanup *//* $Id: uda1341.c,v 1.18 2005/11/17 14:17:21 tiwai Exp $ */#include <sound/driver.h>#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/ioctl.h>#include <asm/uaccess.h>#include <sound/core.h>#include <sound/control.h>#include <sound/initval.h>#include <sound/info.h>#include <linux/l3/l3.h>#include <sound/uda1341.h>/* {{{ HW regs definition */#define STAT0                   0x00#define STAT1			0x80#define STAT_MASK               0x80#define DATA0_0			0x00#define DATA0_1			0x40#define DATA0_2			0x80#define DATA_MASK               0xc0#define IS_DATA0(x)     ((x) >= data0_0 && (x) <= data0_2)#define IS_DATA1(x)     ((x) == data1)#define IS_STATUS(x)    ((x) == stat0 || (x) == stat1)#define IS_EXTEND(x)   ((x) >= ext0 && (x) <= ext6)/* }}} */static const char *peak_names[] = {	"before",	"after",};static const char *filter_names[] = {	"flat",	"min",	"min",	"max",};static const char *mixer_names[] = {	"double differential",	"input channel 1 (line in)",	"input channel 2 (microphone)",	"digital mixer",};static const char *deemp_names[] = {	"none",	"32 kHz",	"44.1 kHz",	"48 kHz",        };enum uda1341_regs_names {	stat0,	stat1,	data0_0,	data0_1,	data0_2,	data1,	ext0,	ext1,	ext2,	empty,	ext4,	ext5,	ext6,	uda1341_reg_last,};static const char *uda1341_reg_names[] = {	"stat 0 ",	"stat 1 ",	"data 00",	"data 01",	"data 02",	"data 1 ",	"ext 0",	"ext 1",	"ext 2",	"empty",	"ext 4",	"ext 5",	"ext 6",};static const int uda1341_enum_items[] = {	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	2, //peak - before/after	4, //deemp - none/32/44.1/48	0,	4, //filter - flat/min/min/max	0, 0, 0,	4, //mixer - differ/line/mic/mixer	0, 0, 0, 0, 0,};static const char ** uda1341_enum_names[] = {	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,	peak_names, //peak - before/after	deemp_names, //deemp - none/32/44.1/48	NULL,	filter_names, //filter - flat/min/min/max	NULL, NULL, NULL,	mixer_names, //mixer - differ/line/mic/mixer	NULL, NULL, NULL, NULL, NULL,};typedef int uda1341_cfg[CMD_LAST];struct uda1341 {	int (*write) (struct l3_client *uda1341, unsigned short reg, unsigned short val);	int (*read) (struct l3_client *uda1341, unsigned short reg);        	unsigned char regs[uda1341_reg_last];	int active;	spinlock_t reg_lock;	struct snd_card *card;	uda1341_cfg cfg;#ifdef CONFIG_PM	unsigned char suspend_regs[uda1341_reg_last];	uda1341_cfg suspend_cfg;#endif};/* transfer 8bit integer into string with binary representation */static void int2str_bin8(uint8_t val, char *buf){	const int size = sizeof(val) * 8;	int i;	for (i= 0; i < size; i++){		*(buf++) = (val >> (size - 1)) ? '1' : '0';		val <<= 1;	}	*buf = '\0'; //end the string with zero}/* {{{ HW manipulation routines */static int snd_uda1341_codec_write(struct l3_client *clnt, unsigned short reg, unsigned short val){	struct uda1341 *uda = clnt->driver_data;	unsigned char buf[2] = { 0xc0, 0xe0 }; // for EXT addressing	int err = 0;	uda->regs[reg] = val;	if (uda->active) {		if (IS_DATA0(reg)) {			err = l3_write(clnt, UDA1341_DATA0, (const unsigned char *)&val, 1);		} else if (IS_DATA1(reg)) {			err = l3_write(clnt, UDA1341_DATA1, (const unsigned char *)&val, 1);		} else if (IS_STATUS(reg)) {			err = l3_write(clnt, UDA1341_STATUS, (const unsigned char *)&val, 1);		} else if (IS_EXTEND(reg)) {			buf[0] |= (reg - ext0) & 0x7;   //EXT address			buf[1] |= val;                  //EXT data			err = l3_write(clnt, UDA1341_DATA0, (const unsigned char *)buf, 2);		}	} else		printk(KERN_ERR "UDA1341 codec not active!\n");	return err;}static int snd_uda1341_codec_read(struct l3_client *clnt, unsigned short reg){	unsigned char val;	int err;	err = l3_read(clnt, reg, &val, 1);	if (err == 1)		// use just 6bits - the rest is address of the reg		return val & 63;	return err < 0 ? err : -EIO;}static inline int snd_uda1341_valid_reg(struct l3_client *clnt, unsigned short reg){	return reg < uda1341_reg_last;}static int snd_uda1341_update_bits(struct l3_client *clnt, unsigned short reg,				   unsigned short mask, unsigned short shift,				   unsigned short value, int flush){	int change;	unsigned short old, new;	struct uda1341 *uda = clnt->driver_data;#if 0	printk(KERN_DEBUG "update_bits: reg: %s mask: %d shift: %d val: %d\n",	       uda1341_reg_names[reg], mask, shift, value);#endif        	if (!snd_uda1341_valid_reg(clnt, reg))		return -EINVAL;	spin_lock(&uda->reg_lock);	old = uda->regs[reg];	new = (old & ~(mask << shift)) | (value << shift);	change = old != new;	if (change) {		if (flush) uda->write(clnt, reg, new);		uda->regs[reg] = new;	}	spin_unlock(&uda->reg_lock);	return change;}static int snd_uda1341_cfg_write(struct l3_client *clnt, unsigned short what,				 unsigned short value, int flush){	struct uda1341 *uda = clnt->driver_data;	int ret = 0;#ifdef CONFIG_PM	int reg;#endif#if 0	printk(KERN_DEBUG "cfg_write what: %d value: %d\n", what, value);#endif	uda->cfg[what] = value;        	switch(what) {	case CMD_RESET:		ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, 1, flush);	// MUTE		ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 1, flush);	// RESET		ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 0, flush);	// RESTORE		uda->cfg[CMD_RESET]=0;		break;	case CMD_FS:		ret = snd_uda1341_update_bits(clnt, stat0, 3, 4, value, flush);		break;	case CMD_FORMAT:		ret = snd_uda1341_update_bits(clnt, stat0, 7, 1, value, flush);		break;	case CMD_OGAIN:		ret = snd_uda1341_update_bits(clnt, stat1, 1, 6, value, flush);		break;	case CMD_IGAIN:		ret = snd_uda1341_update_bits(clnt, stat1, 1, 5, value, flush);		break;	case CMD_DAC:		ret = snd_uda1341_update_bits(clnt, stat1, 1, 0, value, flush);		break;	case CMD_ADC:		ret = snd_uda1341_update_bits(clnt, stat1, 1, 1, value, flush);		break;	case CMD_VOLUME:		ret = snd_uda1341_update_bits(clnt, data0_0, 63, 0, value, flush);		break;	case CMD_BASS:		ret = snd_uda1341_update_bits(clnt, data0_1, 15, 2, value, flush);		break;	case CMD_TREBBLE:		ret = snd_uda1341_update_bits(clnt, data0_1, 3, 0, value, flush);		break;	case CMD_PEAK:		ret = snd_uda1341_update_bits(clnt, data0_2, 1, 5, value, flush);		break;	case CMD_DEEMP:		ret = snd_uda1341_update_bits(clnt, data0_2, 3, 3, value, flush);		break;	case CMD_MUTE:		ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, value, flush);		break;	case CMD_FILTER:		ret = snd_uda1341_update_bits(clnt, data0_2, 3, 0, value, flush);		break;	case CMD_CH1:		ret = snd_uda1341_update_bits(clnt, ext0, 31, 0, value, flush);		break;	case CMD_CH2:		ret = snd_uda1341_update_bits(clnt, ext1, 31, 0, value, flush);		break;	case CMD_MIC:		ret = snd_uda1341_update_bits(clnt, ext2, 7, 2, value, flush);		break;	case CMD_MIXER:		ret = snd_uda1341_update_bits(clnt, ext2, 3, 0, value, flush);		break;	case CMD_AGC:		ret = snd_uda1341_update_bits(clnt, ext4, 1, 4, value, flush);		break;	case CMD_IG:		ret = snd_uda1341_update_bits(clnt, ext4, 3, 0, value & 0x3, flush);		ret = snd_uda1341_update_bits(clnt, ext5, 31, 0, value >> 2, flush);		break;	case CMD_AGC_TIME:		ret = snd_uda1341_update_bits(clnt, ext6, 7, 2, value, flush);		break;	case CMD_AGC_LEVEL:		ret = snd_uda1341_update_bits(clnt, ext6, 3, 0, value, flush);		break;#ifdef CONFIG_PM			case CMD_SUSPEND:		for (reg = stat0; reg < uda1341_reg_last; reg++)			uda->suspend_regs[reg] = uda->regs[reg];		for (reg = 0; reg < CMD_LAST; reg++)			uda->suspend_cfg[reg] = uda->cfg[reg];		break;	case CMD_RESUME:		for (reg = stat0; reg < uda1341_reg_last; reg++)			snd_uda1341_codec_write(clnt, reg, uda->suspend_regs[reg]);		for (reg = 0; reg < CMD_LAST; reg++)			uda->cfg[reg] = uda->suspend_cfg[reg];		break;#endif	default:		ret = -EINVAL;		break;	}                	if (!uda->active)		printk(KERN_ERR "UDA1341 codec not active!\n");                	return ret;}/* }}} *//* {{{ Proc interface */#ifdef CONFIG_PROC_FSstatic const char *format_names[] = {	"I2S-bus",	"LSB 16bits",	"LSB 18bits",	"LSB 20bits",	"MSB",	"in LSB 16bits/out MSB",	"in LSB 18bits/out MSB",	"in LSB 20bits/out MSB",        };static const char *fs_names[] = {	"512*fs",	"384*fs",	"256*fs",	"Unused - bad value!",};static const char* bass_values[][16] = {	{"0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB",	 "0 dB", "0 dB", "0 dB", "0 dB", "undefined", }, //flat	{"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "18 dB",	 "18 dB", "18 dB", "18 dB", "18 dB", "undefined",}, // min	{"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "18 dB",	 "18 dB", "18 dB", "18 dB", "18 dB", "undefined",}, // min	{"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "20 dB",	 "22 dB", "24 dB", "24 dB", "24 dB", "undefined",}, // max};static const char *mic_sens_value[] = {	"-3 dB", "0 dB", "3 dB", "9 dB", "15 dB", "21 dB", "27 dB", "not used",};static const unsigned short AGC_atime[] = {	11, 16, 11, 16, 21, 11, 16, 21,};static const unsigned short AGC_dtime[] = {	100, 100, 200, 200, 200, 400, 400, 400,};static const char *AGC_level[] = {	"-9.0", "-11.5", "-15.0", "-17.5",};static const char *ig_small_value[] = {	"-3.0", "-2.5", "-2.0", "-1.5", "-1.0", "-0.5",};/* * this was computed as peak_value[i] = pow((63-i)*1.42,1.013) * * UDA1341 datasheet on page 21: Peak value (dB) = (Peak level - 63.5)*5*log2 * There is an table with these values [level]=value: [3]=-90.31, [7]=-84.29 * [61]=-2.78, [62] = -1.48, [63] = 0.0 * I tried to compute it, but using but even using logarithm with base either 10 or 2 * i was'n able to get values in the table from the formula. So I constructed another * formula (see above) to interpolate the values as good as possible. If there is some * mistake, please contact me on tomas.kasparek@seznam.cz. Thanks. * UDA1341TS datasheet is available at: *   http://www-us9.semiconductors.com/acrobat/datasheets/UDA1341TS_3.pdf  */static const char *peak_value[] = {	"-INF dB", "N.A.", "N.A", "90.31 dB", "N.A.", "N.A.", "N.A.", "-84.29 dB",	"-82.65 dB", "-81.13 dB", "-79.61 dB", "-78.09 dB", "-76.57 dB", "-75.05 dB", "-73.53 dB",	"-72.01 dB", "-70.49 dB", "-68.97 dB", "-67.45 dB", "-65.93 dB", "-64.41 dB", "-62.90 dB",	"-61.38 dB", "-59.86 dB", "-58.35 dB", "-56.83 dB", "-55.32 dB", "-53.80 dB", "-52.29 dB",	"-50.78 dB", "-49.26 dB", "-47.75 dB", "-46.24 dB", "-44.73 dB", "-43.22 dB", "-41.71 dB",	"-40.20 dB", "-38.69 dB", "-37.19 dB", "-35.68 dB", "-34.17 dB", "-32.67 dB", "-31.17 dB",	"-29.66 dB", "-28.16 dB", "-26.66 dB", "-25.16 dB", "-23.66 dB", "-22.16 dB", "-20.67 dB",	"-19.17 dB", "-17.68 dB", "-16.19 dB", "-14.70 dB", "-13.21 dB", "-11.72 dB", "-10.24 dB",	"-8.76 dB", "-7.28 dB", "-5.81 dB", "-4.34 dB", "-2.88 dB", "-1.43 dB", "0.00 dB",};static void snd_uda1341_proc_read(struct snd_info_entry *entry, 				  struct snd_info_buffer *buffer){	struct l3_client *clnt = entry->private_data;	struct uda1341 *uda = clnt->driver_data;	int peak;	peak = snd_uda1341_codec_read(clnt, UDA1341_DATA1);	if (peak < 0)		peak = 0;		snd_iprintf(buffer, "%s\n\n", uda->card->longname);	// for information about computed values see UDA1341TS datasheet pages 15 - 21	snd_iprintf(buffer, "DAC power           : %s\n", uda->cfg[CMD_DAC] ? "on" : "off");	snd_iprintf(buffer, "ADC power           : %s\n", uda->cfg[CMD_ADC] ? "on" : "off"); 	snd_iprintf(buffer, "Clock frequency     : %s\n", fs_names[uda->cfg[CMD_FS]]);	snd_iprintf(buffer, "Data format         : %s\n\n", format_names[uda->cfg[CMD_FORMAT]]);	snd_iprintf(buffer, "Filter mode         : %s\n", filter_names[uda->cfg[CMD_FILTER]]);	snd_iprintf(buffer, "Mixer mode          : %s\n", mixer_names[uda->cfg[CMD_MIXER]]);	snd_iprintf(buffer, "De-emphasis         : %s\n", deemp_names[uda->cfg[CMD_DEEMP]]);		snd_iprintf(buffer, "Peak detection pos. : %s\n", uda->cfg[CMD_PEAK] ? "after" : "before");	snd_iprintf(buffer, "Peak value          : %s\n\n", peak_value[peak]);				snd_iprintf(buffer, "Automatic Gain Ctrl : %s\n", uda->cfg[CMD_AGC] ? "on" : "off");	snd_iprintf(buffer, "AGC attack time     : %d ms\n", AGC_atime[uda->cfg[CMD_AGC_TIME]]);	snd_iprintf(buffer, "AGC decay time      : %d ms\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]);	snd_iprintf(buffer, "AGC output level    : %s dB\n\n", AGC_level[uda->cfg[CMD_AGC_LEVEL]]);	snd_iprintf(buffer, "Mute                : %s\n", uda->cfg[CMD_MUTE] ? "on" : "off");	if (uda->cfg[CMD_VOLUME] == 0)		snd_iprintf(buffer, "Volume              : 0 dB\n");	else if (uda->cfg[CMD_VOLUME] < 62)		snd_iprintf(buffer, "Volume              : %d dB\n", -1*uda->cfg[CMD_VOLUME] +1);	else		snd_iprintf(buffer, "Volume              : -INF dB\n");	snd_iprintf(buffer, "Bass                : %s\n", bass_values[uda->cfg[CMD_FILTER]][uda->cfg[CMD_BASS]]);	snd_iprintf(buffer, "Trebble             : %d dB\n", uda->cfg[CMD_FILTER] ? 2*uda->cfg[CMD_TREBBLE] : 0);

⌨️ 快捷键说明

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