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

📄 patch_cmedia.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Universal Interface for Intel High Definition Audio Codec * * HD audio interface patch for C-Media CMI9880 * * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> * * *  This driver 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 driver 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 <linux/init.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/pci.h>#include <sound/core.h>#include "hda_codec.h"#include "hda_local.h"#define NUM_PINS	11/* board config type */enum {	CMI_MINIMAL,	/* back 3-jack */	CMI_MIN_FP,	/* back 3-jack + front-panel 2-jack */	CMI_FULL,	/* back 6-jack + front-panel 2-jack */	CMI_FULL_DIG,	/* back 6-jack + front-panel 2-jack + digital I/O */	CMI_ALLOUT,	/* back 5-jack + front-panel 2-jack + digital out */	CMI_AUTO,	/* let driver guess it */};struct cmi_spec {	int board_config;	unsigned int no_line_in: 1;	/* no line-in (5-jack) */	unsigned int front_panel: 1;	/* has front-panel 2-jack */	/* playback */	struct hda_multi_out multiout;	hda_nid_t dac_nids[4];		/* NID for each DAC */	int num_dacs;	/* capture */	hda_nid_t *adc_nids;	hda_nid_t dig_in_nid;	/* capture source */	const struct hda_input_mux *input_mux;	unsigned int cur_mux[2];	/* channel mode */	int num_channel_modes;	const struct hda_channel_mode *channel_modes;	struct hda_pcm pcm_rec[2];	/* PCM information */	/* pin deafault configuration */	hda_nid_t pin_nid[NUM_PINS];	unsigned int def_conf[NUM_PINS];	unsigned int pin_def_confs;	/* multichannel pins */	hda_nid_t multich_pin[4];	/* max 8-channel */	struct hda_verb multi_init[9];	/* 2 verbs for each pin + terminator */};/* * input MUX */static int cmi_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct cmi_spec *spec = codec->spec;	return snd_hda_input_mux_info(spec->input_mux, uinfo);}static int cmi_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct cmi_spec *spec = codec->spec;	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];	return 0;}static int cmi_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct cmi_spec *spec = codec->spec;	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,				     spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);}/* * shared line-in, mic for surrounds *//* 3-stack / 2 channel */static struct hda_verb cmi9880_ch2_init[] = {	/* set line-in PIN for input */	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },	/* set mic PIN for input, also enable vref */	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* route front PCM (DAC1) to HP */	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },	{}};/* 3-stack / 6 channel */static struct hda_verb cmi9880_ch6_init[] = {	/* set line-in PIN for output */	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* set mic PIN for output */	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* route front PCM (DAC1) to HP */	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },	{}};/* 3-stack+front / 8 channel */static struct hda_verb cmi9880_ch8_init[] = {	/* set line-in PIN for output */	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* set mic PIN for output */	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },	/* route rear-surround PCM (DAC4) to HP */	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 },	{}};static struct hda_channel_mode cmi9880_channel_modes[3] = {	{ 2, cmi9880_ch2_init },	{ 6, cmi9880_ch6_init },	{ 8, cmi9880_ch8_init },};static int cmi_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct cmi_spec *spec = codec->spec;	return snd_hda_ch_mode_info(codec, uinfo, spec->channel_modes,				    spec->num_channel_modes);}static int cmi_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct cmi_spec *spec = codec->spec;	return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_modes,				   spec->num_channel_modes, spec->multiout.max_channels);}static int cmi_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);	struct cmi_spec *spec = codec->spec;	return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_modes,				   spec->num_channel_modes, &spec->multiout.max_channels);}/* */static struct snd_kcontrol_new cmi9880_basic_mixer[] = {	/* CMI9880 has no playback volumes! */	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */	HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT),	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),	HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT),	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		/* The multiple "Capture Source" controls confuse alsamixer		 * So call somewhat different..		 * FIXME: the controls appear in the "playback" view!		 */		/* .name = "Capture Source", */		.name = "Input Source",		.count = 2,		.info = cmi_mux_enum_info,		.get = cmi_mux_enum_get,		.put = cmi_mux_enum_put,	},	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT),	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT),	HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT),	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT),	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT),	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT),	{ } /* end */};/* * shared I/O pins */static struct snd_kcontrol_new cmi9880_ch_mode_mixer[] = {	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = "Channel Mode",		.info = cmi_ch_mode_info,		.get = cmi_ch_mode_get,		.put = cmi_ch_mode_put,	},	{ } /* end */};/* AUD-in selections: * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 */static struct hda_input_mux cmi9880_basic_mux = {	.num_items = 4,	.items = {		{ "Front Mic", 0x5 },		{ "Rear Mic", 0x2 },		{ "Line", 0x1 },		{ "CD", 0x7 },	}};static struct hda_input_mux cmi9880_no_line_mux = {	.num_items = 3,	.items = {		{ "Front Mic", 0x5 },		{ "Rear Mic", 0x2 },		{ "CD", 0x7 },	}};/* front, rear, clfe, rear_surr */static hda_nid_t cmi9880_dac_nids[4] = {	0x03, 0x04, 0x05, 0x06};/* ADC0, ADC1 */static hda_nid_t cmi9880_adc_nids[2] = {	0x08, 0x09};#define CMI_DIG_OUT_NID	0x07#define CMI_DIG_IN_NID	0x0a/* */static struct hda_verb cmi9880_basic_init[] = {	/* port-D for line out (rear panel) */	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* port-E for HP out (front panel) */	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* route front PCM to HP */	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },	/* port-A for surround (rear panel) */	{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* port-G for CLFE (rear panel) */	{ 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	{ 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 },	/* port-H for side (rear panel) */	{ 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 },	/* port-C for line-in (rear panel) */	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },	/* port-B for mic-in (rear panel) with vref */	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* port-F for mic-in (front panel) with vref */	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* CD-in */	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },	/* route front mic to ADC1/2 */	{ 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },	{ 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },	{} /* terminator */};static struct hda_verb cmi9880_allout_init[] = {	/* port-D for line out (rear panel) */	{ 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* port-E for HP out (front panel) */	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* route front PCM to HP */	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },	/* port-A for side (rear panel) */	{ 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* port-G for CLFE (rear panel) */	{ 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	{ 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 },	/* port-H for side (rear panel) */	{ 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 },	/* port-C for surround (rear panel) */	{ 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },	/* port-B for mic-in (rear panel) with vref */	{ 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* port-F for mic-in (front panel) with vref */	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },	/* CD-in */	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },	/* route front mic to ADC1/2 */	{ 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 },	{ 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 },	{} /* terminator */};/* */static int cmi9880_build_controls(struct hda_codec *codec){	struct cmi_spec *spec = codec->spec;	int err;	err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);	if (err < 0)		return err;	if (spec->channel_modes) {		err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer);		if (err < 0)			return err;	}	if (spec->multiout.dig_out_nid) {		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);		if (err < 0)			return err;	}	if (spec->dig_in_nid) {		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);		if (err < 0)			return err;	}	return 0;}/* fill in the multi_dac_nids table, which will decide   which audio widget to use for each channel */static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg){	struct cmi_spec *spec = codec->spec;	hda_nid_t nid;	int assigned[4];	int i, j;	/* clear the table, only one c-media dac assumed here */	memset(spec->dac_nids, 0, sizeof(spec->dac_nids));	memset(assigned, 0, sizeof(assigned));	/* check the pins we found */	for (i = 0; i < cfg->line_outs; i++) {		nid = cfg->line_out_pins[i];		/* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */		if (nid >= 0x0b && nid <= 0x0e) {			spec->dac_nids[i] = (nid - 0x0b) + 0x03;			assigned[nid - 0x0b] = 1;		}	}	/* left pin can be connect to any audio widget */	for (i = 0; i < cfg->line_outs; i++) {		nid = cfg->line_out_pins[i];		if (nid <= 0x0e)			continue;		/* search for an empty channel */		for (j = 0; j < cfg->line_outs; j++) {			if (! assigned[j]) {				spec->dac_nids[i] = j + 0x03;

⌨️ 快捷键说明

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