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

📄 tumbler.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		vol = info->max - 1;	vol = info->table[vol];	for (i = 0; i < info->bytes; i++)		block[i] = (vol >> ((info->bytes - i - 1) * 8)) & 0xff;	if (i2c_smbus_write_i2c_block_data(mix->i2c.client, info->reg,					   info->bytes, block) < 0) {		snd_printk("failed to set mono volume %d\n", info->index);		return -EINVAL;	}	return 0;}static int tumbler_info_mono(struct snd_kcontrol *kcontrol,			     struct snd_ctl_elem_info *uinfo){	struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value;	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = info->max - 1;	return 0;}static int tumbler_get_mono(struct snd_kcontrol *kcontrol,			    struct snd_ctl_elem_value *ucontrol){	struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value;	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct pmac_tumbler *mix;	if (! (mix = chip->mixer_data))		return -ENODEV;	ucontrol->value.integer.value[0] = mix->mono_vol[info->index];	return 0;}static int tumbler_put_mono(struct snd_kcontrol *kcontrol,			    struct snd_ctl_elem_value *ucontrol){	struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value;	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct pmac_tumbler *mix;	int change;	if (! (mix = chip->mixer_data))		return -ENODEV;	change = mix->mono_vol[info->index] != ucontrol->value.integer.value[0];	if (change) {		mix->mono_vol[info->index] = ucontrol->value.integer.value[0];		tumbler_set_mono_volume(mix, info);	}	return change;}/* TAS3001c mono volumes */static struct tumbler_mono_vol tumbler_pcm_vol_info = {	.index = VOL_IDX_PCM_MONO,	.reg = TAS_REG_PCM,	.bytes = 3,	.max = ARRAY_SIZE(mixer_volume_table),	.table = mixer_volume_table,};static struct tumbler_mono_vol tumbler_bass_vol_info = {	.index = VOL_IDX_BASS,	.reg = TAS_REG_BASS,	.bytes = 1,	.max = ARRAY_SIZE(bass_volume_table),	.table = bass_volume_table,};static struct tumbler_mono_vol tumbler_treble_vol_info = {	.index = VOL_IDX_TREBLE,	.reg = TAS_REG_TREBLE,	.bytes = 1,	.max = ARRAY_SIZE(treble_volume_table),	.table = treble_volume_table,};/* TAS3004 mono volumes */static struct tumbler_mono_vol snapper_bass_vol_info = {	.index = VOL_IDX_BASS,	.reg = TAS_REG_BASS,	.bytes = 1,	.max = ARRAY_SIZE(snapper_bass_volume_table),	.table = snapper_bass_volume_table,};static struct tumbler_mono_vol snapper_treble_vol_info = {	.index = VOL_IDX_TREBLE,	.reg = TAS_REG_TREBLE,	.bytes = 1,	.max = ARRAY_SIZE(snapper_treble_volume_table),	.table = snapper_treble_volume_table,};#define DEFINE_MONO(xname,type) { \	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\	.name = xname, \	.info = tumbler_info_mono, \	.get = tumbler_get_mono, \	.put = tumbler_put_mono, \	.private_value = (unsigned long)(&tumbler_##type##_vol_info), \}#define DEFINE_SNAPPER_MONO(xname,type) { \	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\	.name = xname, \	.info = tumbler_info_mono, \	.get = tumbler_get_mono, \	.put = tumbler_put_mono, \	.private_value = (unsigned long)(&snapper_##type##_vol_info), \}/* * snapper mixer volumes */static int snapper_set_mix_vol1(struct pmac_tumbler *mix, int idx, int ch, int reg){	int i, j, vol;	unsigned char block[9];	vol = mix->mix_vol[idx][ch];	if (vol >= ARRAY_SIZE(mixer_volume_table)) {		vol = ARRAY_SIZE(mixer_volume_table) - 1;		mix->mix_vol[idx][ch] = vol;	}	for (i = 0; i < 3; i++) {		vol = mix->mix_vol[i][ch];		vol = mixer_volume_table[vol];		for (j = 0; j < 3; j++)			block[i * 3 + j] = (vol >> ((2 - j) * 8)) & 0xff;	}	if (i2c_smbus_write_i2c_block_data(mix->i2c.client, reg,					   9, block) < 0) {		snd_printk("failed to set mono volume %d\n", reg);		return -EINVAL;	}	return 0;}static int snapper_set_mix_vol(struct pmac_tumbler *mix, int idx){	if (! mix->i2c.client)		return -ENODEV;	if (snapper_set_mix_vol1(mix, idx, 0, TAS_REG_LMIX) < 0 ||	    snapper_set_mix_vol1(mix, idx, 1, TAS_REG_RMIX) < 0)		return -EINVAL;	return 0;}static int snapper_info_mix(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 = ARRAY_SIZE(mixer_volume_table) - 1;	return 0;}static int snapper_get_mix(struct snd_kcontrol *kcontrol,			   struct snd_ctl_elem_value *ucontrol){	int idx = (int)kcontrol->private_value;	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct pmac_tumbler *mix;	if (! (mix = chip->mixer_data))		return -ENODEV;	ucontrol->value.integer.value[0] = mix->mix_vol[idx][0];	ucontrol->value.integer.value[1] = mix->mix_vol[idx][1];	return 0;}static int snapper_put_mix(struct snd_kcontrol *kcontrol,			   struct snd_ctl_elem_value *ucontrol){	int idx = (int)kcontrol->private_value;	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct pmac_tumbler *mix;	int change;	if (! (mix = chip->mixer_data))		return -ENODEV;	change = mix->mix_vol[idx][0] != ucontrol->value.integer.value[0] ||		mix->mix_vol[idx][1] != ucontrol->value.integer.value[1];	if (change) {		mix->mix_vol[idx][0] = ucontrol->value.integer.value[0];		mix->mix_vol[idx][1] = ucontrol->value.integer.value[1];		snapper_set_mix_vol(mix, idx);	}	return change;}/* * mute switches. FIXME: Turn that into software mute when both outputs are muted * to avoid codec reset on ibook M7 */enum { TUMBLER_MUTE_HP, TUMBLER_MUTE_AMP, TUMBLER_MUTE_LINE };static int tumbler_get_mute_switch(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct pmac_tumbler *mix;	struct pmac_gpio *gp;	if (! (mix = chip->mixer_data))		return -ENODEV;	switch(kcontrol->private_value) {	case TUMBLER_MUTE_HP:		gp = &mix->hp_mute;	break;	case TUMBLER_MUTE_AMP:		gp = &mix->amp_mute;	break;	case TUMBLER_MUTE_LINE:		gp = &mix->line_mute;	break;	default:		gp = NULL;	}	if (gp == NULL)		return -EINVAL;	ucontrol->value.integer.value[0] = !check_audio_gpio(gp);	return 0;}static int tumbler_put_mute_switch(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct pmac_tumbler *mix;	struct pmac_gpio *gp;	int val;#ifdef PMAC_SUPPORT_AUTOMUTE	if (chip->update_automute && chip->auto_mute)		return 0; /* don't touch in the auto-mute mode */#endif		if (! (mix = chip->mixer_data))		return -ENODEV;	switch(kcontrol->private_value) {	case TUMBLER_MUTE_HP:		gp = &mix->hp_mute;	break;	case TUMBLER_MUTE_AMP:		gp = &mix->amp_mute;	break;	case TUMBLER_MUTE_LINE:		gp = &mix->line_mute;	break;	default:		gp = NULL;	}	if (gp == NULL)		return -EINVAL;	val = ! check_audio_gpio(gp);	if (val != ucontrol->value.integer.value[0]) {		write_audio_gpio(gp, ! ucontrol->value.integer.value[0]);		return 1;	}	return 0;}static int snapper_set_capture_source(struct pmac_tumbler *mix){	if (! mix->i2c.client)		return -ENODEV;	if (mix->capture_source)		mix->acs = mix->acs |= 2;	else		mix->acs &= ~2;	return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);}static int snapper_info_capture_source(struct snd_kcontrol *kcontrol,				       struct snd_ctl_elem_info *uinfo){	static char *texts[2] = {		"Line", "Mic"	};	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 2;	if (uinfo->value.enumerated.item > 1)		uinfo->value.enumerated.item = 1;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snapper_get_capture_source(struct snd_kcontrol *kcontrol,				      struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct pmac_tumbler *mix = chip->mixer_data;	snd_assert(mix, return -ENODEV);	ucontrol->value.integer.value[0] = mix->capture_source;	return 0;}static int snapper_put_capture_source(struct snd_kcontrol *kcontrol,				      struct snd_ctl_elem_value *ucontrol){	struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);	struct pmac_tumbler *mix = chip->mixer_data;	int change;	snd_assert(mix, return -ENODEV);	change = ucontrol->value.integer.value[0] != mix->capture_source;	if (change) {		mix->capture_source = !!ucontrol->value.integer.value[0];		snapper_set_capture_source(mix);	}	return change;}#define DEFINE_SNAPPER_MIX(xname,idx,ofs) { \	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\	.name = xname, \	.info = snapper_info_mix, \	.get = snapper_get_mix, \	.put = snapper_put_mix, \	.index = idx,\	.private_value = ofs, \}/* */static struct snd_kcontrol_new tumbler_mixers[] __initdata = {	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Master Playback Volume",	  .info = tumbler_info_master_volume,	  .get = tumbler_get_master_volume,	  .put = tumbler_put_master_volume	},	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Master Playback Switch",	  .info = snd_pmac_boolean_stereo_info,	  .get = tumbler_get_master_switch,	  .put = tumbler_put_master_switch	},	DEFINE_MONO("Tone Control - Bass", bass),	DEFINE_MONO("Tone Control - Treble", treble),	DEFINE_MONO("PCM Playback Volume", pcm),	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "DRC Range",	  .info = tumbler_info_drc_value,	  .get = tumbler_get_drc_value,	  .put = tumbler_put_drc_value	},};static struct snd_kcontrol_new snapper_mixers[] __initdata = {	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Master Playback Volume",	  .info = tumbler_info_master_volume,	  .get = tumbler_get_master_volume,	  .put = tumbler_put_master_volume	},	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Master Playback Switch",	  .info = snd_pmac_boolean_stereo_info,	  .get = tumbler_get_master_switch,	  .put = tumbler_put_master_switch	},	DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM),	DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2),	DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC),	DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),	DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "DRC Range",	  .info = tumbler_info_drc_value,	  .get = tumbler_get_drc_value,	  .put = tumbler_put_drc_value	},	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,	  .name = "Input Source", /* FIXME: "Capture Source" doesn't work properly */	  .info = snapper_info_capture_source,	  .get = snapper_get_capture_source,	  .put = snapper_put_capture_source	},};static struct snd_kcontrol_new tumbler_hp_sw __initdata = {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Headphone Playback Switch",	.info = snd_pmac_boolean_mono_info,	.get = tumbler_get_mute_switch,	.put = tumbler_put_mute_switch,	.private_value = TUMBLER_MUTE_HP,};static struct snd_kcontrol_new tumbler_speaker_sw __initdata = {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "PC Speaker Playback Switch",	.info = snd_pmac_boolean_mono_info,	.get = tumbler_get_mute_switch,	.put = tumbler_put_mute_switch,	.private_value = TUMBLER_MUTE_AMP,};static struct snd_kcontrol_new tumbler_lineout_sw __initdata = {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Line Out Playback Switch",	.info = snd_pmac_boolean_mono_info,	.get = tumbler_get_mute_switch,	.put = tumbler_put_mute_switch,	.private_value = TUMBLER_MUTE_LINE,};static struct snd_kcontrol_new tumbler_drc_sw __initdata = {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "DRC Switch",	.info = snd_pmac_boolean_mono_info,	.get = tumbler_get_drc_switch,	.put = tumbler_put_drc_switch};#ifdef PMAC_SUPPORT_AUTOMUTE/* * auto-mute stuffs */static int tumbler_detect_headphone(struct snd_pmac *chip){	struct pmac_tumbler *mix = chip->mixer_data;	int detect = 0;	if (mix->hp_detect.addr)		detect |= read_audio_gpio(&mix->hp_detect);	return detect;}static int tumbler_detect_lineout(struct snd_pmac *chip){	struct pmac_tumbler *mix = chip->mixer_data;	int detect = 0;	if (mix->line_detect.addr)		detect |= read_audio_gpio(&mix->line_detect);	return detect;}static void check_mute(struct snd_pmac *chip, struct pmac_gpio *gp, int val, int do_notify,		       struct snd_kcontrol *sw){	if (check_audio_gpio(gp) != val) {		write_audio_gpio(gp, val);		if (do_notify)			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,				       &sw->id);	}}static struct work_struct device_change;static struct snd_pmac *device_change_chip;static void device_change_handler(struct work_struct *work){	struct snd_pmac *chip = device_change_chip;	struct pmac_tumbler *mix;	int headphone, lineout;	if (!chip)		return;	mix = chip->mixer_data;	snd_assert(mix, return);	headphone = tumbler_detect_headphone(chip);	lineout = tumbler_detect_lineout(chip);	DBG("headphone: %d, lineout: %d\n", headphone, lineout);	if (headphone || lineout) {		/* unmute headphone/lineout & mute speaker */		if (headphone)			check_mute(chip, &mix->hp_mute, 0, mix->auto_mute_notify,				   chip->master_sw_ctl);		if (lineout && mix->line_mute.addr != 0)			check_mute(chip, &mix->line_mute, 0, mix->auto_mute_notify,				   chip->lineout_sw_ctl);		if (mix->anded_reset)			msleep(10);		check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,			   chip->speaker_sw_ctl);	} else {		/* unmute speaker, mute others */		check_mute(chip, &mix->amp_mute, 0, mix->auto_mute_notify,			   chip->speaker_sw_ctl);		if (mix->anded_reset)

⌨️ 快捷键说明

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