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

📄 awacs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * PMac AWACS lowlevel functions * * Copyright (c) by Takashi Iwai <tiwai@suse.de> * code based on dmasound.c. * *   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 <asm/nvram.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/slab.h>#include <sound/core.h>#include "pmac.h"#ifdef CONFIG_ADB_CUDA#define PMAC_AMP_AVAIL#endif#ifdef PMAC_AMP_AVAILstruct awacs_amp {	unsigned char amp_master;	unsigned char amp_vol[2][2];	unsigned char amp_tone[2];};#define CHECK_CUDA_AMP() (sys_ctrler == SYS_CTRLER_CUDA)#endif /* PMAC_AMP_AVAIL */static void snd_pmac_screamer_wait(struct snd_pmac *chip){	long timeout = 2000;	while (!(in_le32(&chip->awacs->codec_stat) & MASK_VALID)) {		mdelay(1);		if (! --timeout) {			snd_printd("snd_pmac_screamer_wait timeout\n");			break;		}	}}/* * write AWACS register */static voidsnd_pmac_awacs_write(struct snd_pmac *chip, int val){	long timeout = 5000000;	if (chip->model == PMAC_SCREAMER)		snd_pmac_screamer_wait(chip);	out_le32(&chip->awacs->codec_ctrl, val | (chip->subframe << 22));	while (in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) {		if (! --timeout) {			snd_printd("snd_pmac_awacs_write timeout\n");			break;		}	}}static voidsnd_pmac_awacs_write_reg(struct snd_pmac *chip, int reg, int val){	snd_pmac_awacs_write(chip, val | (reg << 12));	chip->awacs_reg[reg] = val;}static voidsnd_pmac_awacs_write_noreg(struct snd_pmac *chip, int reg, int val){	snd_pmac_awacs_write(chip, val | (reg << 12));}#ifdef CONFIG_PM/* Recalibrate chip */static void screamer_recalibrate(struct snd_pmac *chip){	if (chip->model != PMAC_SCREAMER)		return;	/* Sorry for the horrible delays... I hope to get that improved	 * by making the whole PM process asynchronous in a future version	 */	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);	if (chip->manufacturer == 0x1)		/* delay for broken crystal part */		msleep(750);	snd_pmac_awacs_write_noreg(chip, 1,				   chip->awacs_reg[1] | MASK_RECALIBRATE |				   MASK_CMUTE | MASK_AMUTE);	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);	snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);}#else#define screamer_recalibrate(chip) /* NOP */#endif/* * additional callback to set the pcm format */static void snd_pmac_awacs_set_format(struct snd_pmac *chip){	chip->awacs_reg[1] &= ~MASK_SAMPLERATE;	chip->awacs_reg[1] |= chip->rate_index << 3;	snd_pmac_awacs_write_reg(chip, 1, chip->awacs_reg[1]);}/* * AWACS volume callbacks *//* * volumes: 0-15 stereo */static int snd_pmac_awacs_info_volume(struct snd_kcontrol *kcontrol,				      struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 15;	return 0;} static int snd_pmac_awacs_get_volume(struct snd_kcontrol *kcontrol,				     struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int lshift = (kcontrol->private_value >> 8) & 0xff;	int inverted = (kcontrol->private_value >> 16) & 1;	unsigned long flags;	int vol[2];	spin_lock_irqsave(&chip->reg_lock, flags);	vol[0] = (chip->awacs_reg[reg] >> lshift) & 0xf;	vol[1] = chip->awacs_reg[reg] & 0xf;	spin_unlock_irqrestore(&chip->reg_lock, flags);	if (inverted) {		vol[0] = 0x0f - vol[0];		vol[1] = 0x0f - vol[1];	}	ucontrol->value.integer.value[0] = vol[0];	ucontrol->value.integer.value[1] = vol[1];	return 0;}static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol,				     struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int lshift = (kcontrol->private_value >> 8) & 0xff;	int inverted = (kcontrol->private_value >> 16) & 1;	int val, oldval;	unsigned long flags;	int vol[2];	vol[0] = ucontrol->value.integer.value[0];	vol[1] = ucontrol->value.integer.value[1];	if (inverted) {		vol[0] = 0x0f - vol[0];		vol[1] = 0x0f - vol[1];	}	vol[0] &= 0x0f;	vol[1] &= 0x0f;	spin_lock_irqsave(&chip->reg_lock, flags);	oldval = chip->awacs_reg[reg];	val = oldval & ~(0xf | (0xf << lshift));	val |= vol[0] << lshift;	val |= vol[1];	if (oldval != val)		snd_pmac_awacs_write_reg(chip, reg, val);	spin_unlock_irqrestore(&chip->reg_lock, flags);	return oldval != reg;}#define AWACS_VOLUME(xname, xreg, xshift, xinverted) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \  .info = snd_pmac_awacs_info_volume, \  .get = snd_pmac_awacs_get_volume, \  .put = snd_pmac_awacs_put_volume, \  .private_value = (xreg) | ((xshift) << 8) | ((xinverted) << 16) }/* * mute master/ogain for AWACS: mono */static int snd_pmac_awacs_get_switch(struct snd_kcontrol *kcontrol,				     struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int invert = (kcontrol->private_value >> 16) & 1;	int val;	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	val = (chip->awacs_reg[reg] >> shift) & 1;	spin_unlock_irqrestore(&chip->reg_lock, flags);	if (invert)		val = 1 - val;	ucontrol->value.integer.value[0] = val;	return 0;}static int snd_pmac_awacs_put_switch(struct snd_kcontrol *kcontrol,				     struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int invert = (kcontrol->private_value >> 16) & 1;	int mask = 1 << shift;	int val, changed;	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	val = chip->awacs_reg[reg] & ~mask;	if (ucontrol->value.integer.value[0] != invert)		val |= mask;	changed = chip->awacs_reg[reg] != val;	if (changed)		snd_pmac_awacs_write_reg(chip, reg, val);	spin_unlock_irqrestore(&chip->reg_lock, flags);	return changed;}#define AWACS_SWITCH(xname, xreg, xshift, xinvert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \  .info = snd_pmac_boolean_mono_info, \  .get = snd_pmac_awacs_get_switch, \  .put = snd_pmac_awacs_put_switch, \  .private_value = (xreg) | ((xshift) << 8) | ((xinvert) << 16) }#ifdef PMAC_AMP_AVAIL/* * controls for perch/whisper extension cards, e.g. G3 desktop * * TDA7433 connected via i2c address 0x45 (= 0x8a), * accessed through cuda */static void awacs_set_cuda(int reg, int val){	struct adb_request req;	cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, reg, val);	while (! req.complete)		cuda_poll();}/* * level = 0 - 14, 7 = 0 dB */static void awacs_amp_set_tone(struct awacs_amp *amp, int bass, int treble){	amp->amp_tone[0] = bass;	amp->amp_tone[1] = treble;	if (bass > 7)		bass = (14 - bass) + 8;	if (treble > 7)		treble = (14 - treble) + 8;	awacs_set_cuda(2, (bass << 4) | treble);}/* * vol = 0 - 31 (attenuation), 32 = mute bit, stereo */static int awacs_amp_set_vol(struct awacs_amp *amp, int index, int lvol, int rvol,			     int do_check){	if (do_check && amp->amp_vol[index][0] == lvol &&	    amp->amp_vol[index][1] == rvol)		return 0;	awacs_set_cuda(3 + index, lvol);	awacs_set_cuda(5 + index, rvol);	amp->amp_vol[index][0] = lvol;	amp->amp_vol[index][1] = rvol;	return 1;}/* * 0 = -79 dB, 79 = 0 dB, 99 = +20 dB */static void awacs_amp_set_master(struct awacs_amp *amp, int vol){	amp->amp_master = vol;	if (vol <= 79)		vol = 32 + (79 - vol);	else		vol = 32 - (vol - 79);	awacs_set_cuda(1, vol);}static void awacs_amp_free(struct snd_pmac *chip){	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return);	kfree(amp);	chip->mixer_data = NULL;	chip->mixer_free = NULL;}/* * mixer controls */static int snd_pmac_awacs_info_volume_amp(struct snd_kcontrol *kcontrol,					  struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 31;	return 0;} static int snd_pmac_awacs_get_volume_amp(struct snd_kcontrol *kcontrol,					 struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int index = kcontrol->private_value;	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return -EINVAL);	snd_assert(index >= 0 && index <= 1, return -EINVAL);	ucontrol->value.integer.value[0] = 31 - (amp->amp_vol[index][0] & 31);	ucontrol->value.integer.value[1] = 31 - (amp->amp_vol[index][1] & 31);	return 0;}static int snd_pmac_awacs_put_volume_amp(struct snd_kcontrol *kcontrol,					 struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int index = kcontrol->private_value;	int vol[2];	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return -EINVAL);	snd_assert(index >= 0 && index <= 1, return -EINVAL);	vol[0] = (31 - (ucontrol->value.integer.value[0] & 31)) | (amp->amp_vol[index][0] & 32);	vol[1] = (31 - (ucontrol->value.integer.value[1] & 31)) | (amp->amp_vol[index][1] & 32);	return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);}static int snd_pmac_awacs_get_switch_amp(struct snd_kcontrol *kcontrol,					 struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int index = kcontrol->private_value;	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return -EINVAL);	snd_assert(index >= 0 && index <= 1, return -EINVAL);	ucontrol->value.integer.value[0] = (amp->amp_vol[index][0] & 32) ? 0 : 1;	ucontrol->value.integer.value[1] = (amp->amp_vol[index][1] & 32) ? 0 : 1;	return 0;}static int snd_pmac_awacs_put_switch_amp(struct snd_kcontrol *kcontrol,					 struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int index = kcontrol->private_value;	int vol[2];	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return -EINVAL);	snd_assert(index >= 0 && index <= 1, return -EINVAL);	vol[0] = (ucontrol->value.integer.value[0] ? 0 : 32) | (amp->amp_vol[index][0] & 31);	vol[1] = (ucontrol->value.integer.value[1] ? 0 : 32) | (amp->amp_vol[index][1] & 31);	return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);}static int snd_pmac_awacs_info_tone_amp(struct snd_kcontrol *kcontrol,					struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 14;	return 0;} static int snd_pmac_awacs_get_tone_amp(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int index = kcontrol->private_value;	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return -EINVAL);	snd_assert(index >= 0 && index <= 1, return -EINVAL);	ucontrol->value.integer.value[0] = amp->amp_tone[index];	return 0;}static int snd_pmac_awacs_put_tone_amp(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int index = kcontrol->private_value;	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return -EINVAL);	snd_assert(index >= 0 && index <= 1, return -EINVAL);	if (ucontrol->value.integer.value[0] != amp->amp_tone[index]) {		amp->amp_tone[index] = ucontrol->value.integer.value[0];		awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);		return 1;	}	return 0;}static int snd_pmac_awacs_info_master_amp(struct snd_kcontrol *kcontrol,					  struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 99;	return 0;} static int snd_pmac_awacs_get_master_amp(struct snd_kcontrol *kcontrol,					 struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return -EINVAL);	ucontrol->value.integer.value[0] = amp->amp_master;	return 0;}static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol,					 struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct awacs_amp *amp = chip->mixer_data;	snd_assert(amp, return -EINVAL);	if (ucontrol->value.integer.value[0] != amp->amp_master) {		amp->amp_master = ucontrol->value.integer.value[0];		awacs_amp_set_master(amp, amp->amp_master);

⌨️ 快捷键说明

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