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

📄 awacs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		return 1;	}	return 0;}#define AMP_CH_SPK	0#define AMP_CH_HD	1static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = {	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "PC Speaker Playback Volume",	  .info = snd_pmac_awacs_info_volume_amp,	  .get = snd_pmac_awacs_get_volume_amp,	  .put = snd_pmac_awacs_put_volume_amp,	  .private_value = AMP_CH_SPK,	},	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Headphone Playback Volume",	  .info = snd_pmac_awacs_info_volume_amp,	  .get = snd_pmac_awacs_get_volume_amp,	  .put = snd_pmac_awacs_put_volume_amp,	  .private_value = AMP_CH_HD,	},	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Tone Control - Bass",	  .info = snd_pmac_awacs_info_tone_amp,	  .get = snd_pmac_awacs_get_tone_amp,	  .put = snd_pmac_awacs_put_tone_amp,	  .private_value = 0,	},	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Tone Control - Treble",	  .info = snd_pmac_awacs_info_tone_amp,	  .get = snd_pmac_awacs_get_tone_amp,	  .put = snd_pmac_awacs_put_tone_amp,	  .private_value = 1,	},	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Amp Master Playback Volume",	  .info = snd_pmac_awacs_info_master_amp,	  .get = snd_pmac_awacs_get_master_amp,	  .put = snd_pmac_awacs_put_master_amp,	},};static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Headphone Playback Switch",	.info = snd_pmac_boolean_stereo_info,	.get = snd_pmac_awacs_get_switch_amp,	.put = snd_pmac_awacs_put_switch_amp,	.private_value = AMP_CH_HD,};static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __initdata = {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "PC Speaker Playback Switch",	.info = snd_pmac_boolean_stereo_info,	.get = snd_pmac_awacs_get_switch_amp,	.put = snd_pmac_awacs_put_switch_amp,	.private_value = AMP_CH_SPK,};#endif /* PMAC_AMP_AVAIL *//* * mic boost for screamer */static int snd_pmac_screamer_mic_boost_info(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 = 2;	return 0;}static int snd_pmac_screamer_mic_boost_get(struct snd_kcontrol *kcontrol,					   struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int val;	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	if (chip->awacs_reg[6] & MASK_MIC_BOOST)		val = 2;	else if (chip->awacs_reg[0] & MASK_GAINLINE)		val = 1;	else		val = 0;	spin_unlock_irqrestore(&chip->reg_lock, flags);	ucontrol->value.integer.value[0] = val;	return 0;}static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol,					   struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	int changed = 0;	int val0, val6;	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	val0 = chip->awacs_reg[0] & ~MASK_GAINLINE;	val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST;	if (ucontrol->value.integer.value[0] > 0) {		val0 |= MASK_GAINLINE;		if (ucontrol->value.integer.value[0] > 1)			val6 |= MASK_MIC_BOOST;	}	if (val0 != chip->awacs_reg[0]) {		snd_pmac_awacs_write_reg(chip, 0, val0);		changed = 1;	}	if (val6 != chip->awacs_reg[6]) {		snd_pmac_awacs_write_reg(chip, 6, val6);		changed = 1;	}	spin_unlock_irqrestore(&chip->reg_lock, flags);	return changed;}/* * lists of mixer elements */static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __initdata = {	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),	AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0),	AWACS_VOLUME("Capture Volume", 0, 4, 0),	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),};/* FIXME: is this correct order? * screamer (powerbook G3 pismo) seems to have different bits... */static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __initdata = {	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0),	AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0),};static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __initdata = {	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),	AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0),};static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata =AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = {	AWACS_SWITCH("Mic Boost", 0, SHIFT_GAINLINE, 0),};static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = {	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Mic Boost",	  .info = snd_pmac_screamer_mic_boost_info,	  .get = snd_pmac_screamer_mic_boost_get,	  .put = snd_pmac_screamer_mic_boost_put,	},};static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __initdata = {	AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1),};static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata =AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);/* * add new mixer elements to the card */static int build_mixers(struct snd_pmac *chip, int nums, struct snd_kcontrol_new *mixers){	int i, err;	for (i = 0; i < nums; i++) {		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixers[i], chip))) < 0)			return err;	}	return 0;}/* * restore all registers */static void awacs_restore_all_regs(struct snd_pmac *chip){	snd_pmac_awacs_write_noreg(chip, 0, chip->awacs_reg[0]);	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);	snd_pmac_awacs_write_noreg(chip, 2, chip->awacs_reg[2]);	snd_pmac_awacs_write_noreg(chip, 4, chip->awacs_reg[4]);	if (chip->model == PMAC_SCREAMER) {		snd_pmac_awacs_write_noreg(chip, 5, chip->awacs_reg[5]);		snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);		snd_pmac_awacs_write_noreg(chip, 7, chip->awacs_reg[7]);	}}#ifdef CONFIG_PMstatic void snd_pmac_awacs_suspend(struct snd_pmac *chip){	snd_pmac_awacs_write_noreg(chip, 1, (chip->awacs_reg[1]					     | MASK_AMUTE | MASK_CMUTE));}static void snd_pmac_awacs_resume(struct snd_pmac *chip){	if (machine_is_compatible("PowerBook3,1")	    || machine_is_compatible("PowerBook3,2")) {		msleep(100);		snd_pmac_awacs_write_reg(chip, 1,			chip->awacs_reg[1] & ~MASK_PAROUT);		msleep(300);	}	awacs_restore_all_regs(chip);	if (chip->model == PMAC_SCREAMER) {		/* reset power bits in reg 6 */		mdelay(5);		snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);	}	screamer_recalibrate(chip);#ifdef PMAC_AMP_AVAIL	if (chip->mixer_data) {		struct awacs_amp *amp = chip->mixer_data;		awacs_amp_set_vol(amp, 0, amp->amp_vol[0][0], amp->amp_vol[0][1], 0);		awacs_amp_set_vol(amp, 1, amp->amp_vol[1][0], amp->amp_vol[1][1], 0);		awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);		awacs_amp_set_master(amp, amp->amp_master);	}#endif}#endif /* CONFIG_PM */#ifdef PMAC_SUPPORT_AUTOMUTE/* * auto-mute stuffs */static int snd_pmac_awacs_detect_headphone(struct snd_pmac *chip){	return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0;}#ifdef PMAC_AMP_AVAILstatic int toggle_amp_mute(struct awacs_amp *amp, int index, int mute){	int vol[2];	vol[0] = amp->amp_vol[index][0] & 31;	vol[1] = amp->amp_vol[index][1] & 31;	if (mute) {		vol[0] |= 32;		vol[1] |= 32;	}	return awacs_amp_set_vol(amp, index, vol[0], vol[1], 1);}#endifstatic void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify){	if (chip->auto_mute) {#ifdef PMAC_AMP_AVAIL		if (chip->mixer_data) {			struct awacs_amp *amp = chip->mixer_data;			int changed;			if (snd_pmac_awacs_detect_headphone(chip)) {				changed = toggle_amp_mute(amp, AMP_CH_HD, 0);				changed |= toggle_amp_mute(amp, AMP_CH_SPK, 1);			} else {				changed = toggle_amp_mute(amp, AMP_CH_HD, 1);				changed |= toggle_amp_mute(amp, AMP_CH_SPK, 0);			}			if (do_notify && ! changed)				return;		} else#endif		{			int reg = chip->awacs_reg[1] | (MASK_HDMUTE|MASK_SPKMUTE);			if (snd_pmac_awacs_detect_headphone(chip))				reg &= ~MASK_HDMUTE;			else				reg &= ~MASK_SPKMUTE;			if (do_notify && reg == chip->awacs_reg[1])				return;			snd_pmac_awacs_write_reg(chip, 1, reg);		}		if (do_notify) {			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,				       &chip->master_sw_ctl->id);			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,				       &chip->speaker_sw_ctl->id);			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,				       &chip->hp_detect_ctl->id);		}	}}#endif /* PMAC_SUPPORT_AUTOMUTE *//* * initialize chip */int __initsnd_pmac_awacs_init(struct snd_pmac *chip){	int err, vol;	/* looks like MASK_GAINLINE triggers something, so we set here	 * as start-up	 */	chip->awacs_reg[0] = MASK_MUX_CD | 0xff | MASK_GAINLINE;	chip->awacs_reg[1] = MASK_CMUTE | MASK_AMUTE;	/* FIXME: Only machines with external SRS module need MASK_PAROUT */	if (chip->has_iic || chip->device_id == 0x5 ||	    /*chip->_device_id == 0x8 || */	    chip->device_id == 0xb)		chip->awacs_reg[1] |= MASK_PAROUT;	/* get default volume from nvram */	// vol = (~nvram_read_byte(0x1308) & 7) << 1;	// vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 );	vol = 0x0f; /* no, on alsa, muted as default */	vol = vol + (vol << 6);	chip->awacs_reg[2] = vol;	chip->awacs_reg[4] = vol;	if (chip->model == PMAC_SCREAMER) {		chip->awacs_reg[5] = vol; /* FIXME: screamer has loopthru vol control */		chip->awacs_reg[6] = MASK_MIC_BOOST; /* FIXME: maybe should be vol << 3 for PCMCIA speaker */		chip->awacs_reg[7] = 0;	}	awacs_restore_all_regs(chip);	chip->manufacturer = (in_le32(&chip->awacs->codec_stat) >> 8) & 0xf;	screamer_recalibrate(chip);	chip->revision = (in_le32(&chip->awacs->codec_stat) >> 12) & 0xf;#ifdef PMAC_AMP_AVAIL	if (chip->revision == 3 && chip->has_iic && CHECK_CUDA_AMP()) {		struct awacs_amp *amp = kzalloc(sizeof(*amp), GFP_KERNEL);		if (! amp)			return -ENOMEM;		chip->mixer_data = amp;		chip->mixer_free = awacs_amp_free;		awacs_amp_set_vol(amp, 0, 63, 63, 0); /* mute and zero vol */		awacs_amp_set_vol(amp, 1, 63, 63, 0);		awacs_amp_set_tone(amp, 7, 7); /* 0 dB */		awacs_amp_set_master(amp, 79); /* 0 dB */	}#endif /* PMAC_AMP_AVAIL */	if (chip->hp_stat_mask == 0) {		/* set headphone-jack detection bit */		switch (chip->model) {		case PMAC_AWACS:			chip->hp_stat_mask = 0x04;			break;		case PMAC_SCREAMER:			switch (chip->device_id) {			case 0x08:				/* 1 = side jack, 2 = front jack */				chip->hp_stat_mask = 0x03;				break;			case 0x00:			case 0x05:				chip->hp_stat_mask = 0x04;				break;			default:				chip->hp_stat_mask = 0x08;				break;			}			break;		default:			snd_BUG();			break;		}	}	/*	 * build mixers	 */	strcpy(chip->card->mixername, "PowerMac AWACS");	if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),				snd_pmac_awacs_mixers)) < 0)		return err;	if (chip->model == PMAC_SCREAMER)		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2),				   snd_pmac_screamer_mixers2);	else		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers2),				   snd_pmac_awacs_mixers2);	if (err < 0)		return err;	chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_master_sw, chip);	if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)		return err;#ifdef PMAC_AMP_AVAIL	if (chip->mixer_data) {		/* use amplifier.  the signal is connected from route A		 * to the amp.  the amp has its headphone and speaker		 * volumes and mute switches, so we use them instead of		 * screamer registers.		 * in this case, it seems the route C is not used.		 */		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol),					snd_pmac_awacs_amp_vol)) < 0)			return err;		/* overwrite */		chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_hp_sw, chip);		if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)			return err;		chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_amp_spk_sw, chip);		if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)			return err;	} else#endif /* PMAC_AMP_AVAIL */	{		/* route A = headphone, route C = speaker */		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_speaker_vol),					snd_pmac_awacs_speaker_vol)) < 0)			return err;		chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_speaker_sw, chip);		if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)			return err;	}	if (chip->model == PMAC_SCREAMER) {		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mic_boost),					snd_pmac_screamer_mic_boost)) < 0)			return err;	} else {		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost),					snd_pmac_awacs_mic_boost)) < 0)			return err;	}	/*	 * set lowlevel callbacks	 */	chip->set_format = snd_pmac_awacs_set_format;#ifdef CONFIG_PM	chip->suspend = snd_pmac_awacs_suspend;	chip->resume = snd_pmac_awacs_resume;#endif#ifdef PMAC_SUPPORT_AUTOMUTE	if ((err = snd_pmac_add_automute(chip)) < 0)		return err;	chip->detect_headphone = snd_pmac_awacs_detect_headphone;	chip->update_automute = snd_pmac_awacs_update_automute;	snd_pmac_awacs_update_automute(chip, 0); /* update the status only */#endif	if (chip->model == PMAC_SCREAMER) {		snd_pmac_awacs_write_noreg(chip, 6, chip->awacs_reg[6]);		snd_pmac_awacs_write_noreg(chip, 0, chip->awacs_reg[0]);	}	return 0;}

⌨️ 快捷键说明

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