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

📄 sb_mixer.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> *  Routines for Sound Blaster mixer control * * *   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 * */#include <sound/driver.h>#include <asm/io.h>#include <linux/delay.h>#include <linux/time.h>#include <sound/core.h>#include <sound/sb.h>#include <sound/control.h>#undef IO_DEBUGvoid snd_sbmixer_write(sb_t *chip, unsigned char reg, unsigned char data){	outb(reg, SBP(chip, MIXER_ADDR));	udelay(10);	outb(data, SBP(chip, MIXER_DATA));	udelay(10);#ifdef IO_DEBUG	snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data);#endif}unsigned char snd_sbmixer_read(sb_t *chip, unsigned char reg){	unsigned char result;	outb(reg, SBP(chip, MIXER_ADDR));	udelay(10);	result = inb(SBP(chip, MIXER_DATA));	udelay(10);#ifdef IO_DEBUG	snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result);#endif	return result;}/* * Single channel mixer element */static int snd_sbmixer_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	int mask = (kcontrol->private_value >> 24) & 0xff;	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_sbmixer_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 16) & 0xff;	int mask = (kcontrol->private_value >> 24) & 0xff;	unsigned char val;	spin_lock_irqsave(&sb->mixer_lock, flags);	val = (snd_sbmixer_read(sb, reg) >> shift) & mask;	spin_unlock_irqrestore(&sb->mixer_lock, flags);	ucontrol->value.integer.value[0] = val;	return 0;}static int snd_sbmixer_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 16) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	int change;	unsigned char val, oval;	val = (ucontrol->value.integer.value[0] & mask) << shift;	spin_lock_irqsave(&sb->mixer_lock, flags);	oval = snd_sbmixer_read(sb, reg);	val = (oval & ~(mask << shift)) | val;	change = val != oval;	if (change)		snd_sbmixer_write(sb, reg, val);	spin_unlock_irqrestore(&sb->mixer_lock, flags);	return change;}/* * Double channel mixer element */static int snd_sbmixer_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	int mask = (kcontrol->private_value >> 24) & 0xff;	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_sbmixer_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int left_reg = kcontrol->private_value & 0xff;	int right_reg = (kcontrol->private_value >> 8) & 0xff;	int left_shift = (kcontrol->private_value >> 16) & 0x07;	int right_shift = (kcontrol->private_value >> 19) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	unsigned char left, right;	spin_lock_irqsave(&sb->mixer_lock, flags);	left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;	right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;	spin_unlock_irqrestore(&sb->mixer_lock, flags);	ucontrol->value.integer.value[0] = left;	ucontrol->value.integer.value[1] = right;	return 0;}static int snd_sbmixer_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int left_reg = kcontrol->private_value & 0xff;	int right_reg = (kcontrol->private_value >> 8) & 0xff;	int left_shift = (kcontrol->private_value >> 16) & 0x07;	int right_shift = (kcontrol->private_value >> 19) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	int change;	unsigned char left, right, oleft, oright;	left = (ucontrol->value.integer.value[0] & mask) << left_shift;	right = (ucontrol->value.integer.value[1] & mask) << right_shift;	spin_lock_irqsave(&sb->mixer_lock, flags);	if (left_reg == right_reg) {		oleft = snd_sbmixer_read(sb, left_reg);		left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;		change = left != oleft;		if (change)			snd_sbmixer_write(sb, left_reg, left);	} else {		oleft = snd_sbmixer_read(sb, left_reg);		oright = snd_sbmixer_read(sb, right_reg);		left = (oleft & ~(mask << left_shift)) | left;		right = (oright & ~(mask << right_shift)) | right;		change = left != oleft || right != oright;		if (change) {			snd_sbmixer_write(sb, left_reg, left);			snd_sbmixer_write(sb, right_reg, right);		}	}	spin_unlock_irqrestore(&sb->mixer_lock, flags);	return change;}/* * DT-019x / ALS-007 capture/input switch */static int snd_dt019x_input_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	static char *texts[5] = {		"CD", "Mic", "Line", "Synth", "Master"	};	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 5;	if (uinfo->value.enumerated.item > 4)		uinfo->value.enumerated.item = 4;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snd_dt019x_input_sw_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	unsigned char oval;		spin_lock_irqsave(&sb->mixer_lock, flags);	oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);	spin_unlock_irqrestore(&sb->mixer_lock, flags);	switch (oval & 0x07) {	case SB_DT019X_CAP_CD:		ucontrol->value.enumerated.item[0] = 0;		break;	case SB_DT019X_CAP_MIC:		ucontrol->value.enumerated.item[0] = 1;		break;	case SB_DT019X_CAP_LINE:		ucontrol->value.enumerated.item[0] = 2;		break;	case SB_DT019X_CAP_MAIN:		ucontrol->value.enumerated.item[0] = 4;		break;	/* To record the synth on these cards you must record the main.   */	/* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */	/* duplicate case labels if left uncommented. */	/* case SB_DT019X_CAP_SYNTH:	 *	ucontrol->value.enumerated.item[0] = 3;	 *	break;	 */	default:		ucontrol->value.enumerated.item[0] = 4;		break;	}	return 0;}static int snd_dt019x_input_sw_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int change;	unsigned char nval, oval;		if (ucontrol->value.enumerated.item[0] > 4)		return -EINVAL;	switch (ucontrol->value.enumerated.item[0]) {	case 0:		nval = SB_DT019X_CAP_CD;		break;	case 1:		nval = SB_DT019X_CAP_MIC;		break;	case 2:		nval = SB_DT019X_CAP_LINE;		break;	case 3:		nval = SB_DT019X_CAP_SYNTH;		break;	case 4:		nval = SB_DT019X_CAP_MAIN;		break;	default:		nval = SB_DT019X_CAP_MAIN;	}	spin_lock_irqsave(&sb->mixer_lock, flags);	oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);	change = nval != oval;	if (change)		snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);	spin_unlock_irqrestore(&sb->mixer_lock, flags);	return change;}/* * SBPRO input multiplexer */static int snd_sb8mixer_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	static char *texts[3] = {		"Mic", "CD", "Line"	};	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 3;	if (uinfo->value.enumerated.item > 2)		uinfo->value.enumerated.item = 2;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snd_sb8mixer_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	unsigned char oval;		spin_lock_irqsave(&sb->mixer_lock, flags);	oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);	spin_unlock_irqrestore(&sb->mixer_lock, flags);	switch ((oval >> 0x01) & 0x03) {	case SB_DSP_MIXS_CD:		ucontrol->value.enumerated.item[0] = 1;		break;	case SB_DSP_MIXS_LINE:		ucontrol->value.enumerated.item[0] = 2;		break;	default:		ucontrol->value.enumerated.item[0] = 0;		break;	}	return 0;}static int snd_sb8mixer_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int change;	unsigned char nval, oval;		if (ucontrol->value.enumerated.item[0] > 2)		return -EINVAL;	switch (ucontrol->value.enumerated.item[0]) {	case 1:		nval = SB_DSP_MIXS_CD;		break;	case 2:		nval = SB_DSP_MIXS_LINE;		break;	default:		nval = SB_DSP_MIXS_MIC;	}	nval <<= 1;	spin_lock_irqsave(&sb->mixer_lock, flags);	oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);	nval |= oval & ~0x06;	change = nval != oval;	if (change)		snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);	spin_unlock_irqrestore(&sb->mixer_lock, flags);	return change;}/* * SB16 input switch */static int snd_sb16mixer_info_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 4;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int snd_sb16mixer_get_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg1 = kcontrol->private_value & 0xff;	int reg2 = (kcontrol->private_value >> 8) & 0xff;	int left_shift = (kcontrol->private_value >> 16) & 0x0f;	int right_shift = (kcontrol->private_value >> 24) & 0x0f;	unsigned char val1, val2;	spin_lock_irqsave(&sb->mixer_lock, flags);	val1 = snd_sbmixer_read(sb, reg1);	val2 = snd_sbmixer_read(sb, reg2);	spin_unlock_irqrestore(&sb->mixer_lock, flags);	ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;	ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;	ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;	ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;	return 0;}                                                                                                                   static int snd_sb16mixer_put_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	sb_t *sb = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg1 = kcontrol->private_value & 0xff;	int reg2 = (kcontrol->private_value >> 8) & 0xff;	int left_shift = (kcontrol->private_value >> 16) & 0x0f;	int right_shift = (kcontrol->private_value >> 24) & 0x0f;	int change;	unsigned char val1, val2, oval1, oval2;	spin_lock_irqsave(&sb->mixer_lock, flags);	oval1 = snd_sbmixer_read(sb, reg1);	oval2 = snd_sbmixer_read(sb, reg2);	val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));	val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));	val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;	val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;	val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;	val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;	change = val1 != oval1 || val2 != oval2;	if (change) {		snd_sbmixer_write(sb, reg1, val1);		snd_sbmixer_write(sb, reg2, val2);	}	spin_unlock_irqrestore(&sb->mixer_lock, flags);	return change;}/* *//* */int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsigned long value){	static snd_kcontrol_new_t newctls[] = {		[SB_MIX_SINGLE] = {			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,			.info = snd_sbmixer_info_single,			.get = snd_sbmixer_get_single,			.put = snd_sbmixer_put_single,		},		[SB_MIX_DOUBLE] = {			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,

⌨️ 快捷键说明

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