[alsa-devel] [PATCH 0/7] HDA patch_via.c update
Hi!
As part of my work for VIA I have stumbled upon their current internal HDA codec driver and it's various differences against the current mainline driver.
I have spent the better part of two days separating the individual changesets out of the big diff between VIA's driver and current mainline linux-2.6 (which is identical to alsa-kernel.git).
After this merge, I will work with product management and R&D inside VIA that all individual changesets (bugfixes / enhancements) will be sent ASAP for mainline inclusion to prevent any large differencees betwee the two trees.
If you have any questions regarding VIA's hardware or need access to data sheets or the like, I am happy to assist.
[ALSA] HDA VIA: various cleanup
* add extra parenthesis to make code more readable * use kzalloc() for alloc+zero rather than kcalloc() * ensure that AUTO_SEQ_* starts at 0
Signed-off-by: Harald Welte HaraldWelte@viatech.com
Index: linux-2.6/sound/pci/hda/patch_via.c =================================================================== --- linux-2.6.orig/sound/pci/hda/patch_via.c +++ linux-2.6/sound/pci/hda/patch_via.c @@ -77,7 +77,7 @@ };
enum { - AUTO_SEQ_FRONT, + AUTO_SEQ_FRONT = 0, AUTO_SEQ_SURROUND, AUTO_SEQ_CENLFE, AUTO_SEQ_SIDE @@ -283,11 +283,11 @@ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 0x18, &spec->cur_mux[adc_idx]); else if ((IS_VT1709_10CH_VENDORID(vendor_id) || - IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0) + IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0)) return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 0x19, &spec->cur_mux[adc_idx]); else if ((IS_VT1708B_8CH_VENDORID(vendor_id) || - IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0) + IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0)) return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 0x17, &spec->cur_mux[adc_idx]); else @@ -897,7 +898,7 @@ int err;
/* create a codec specific record */ - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM;
@@ -1360,7 +1362,7 @@ int err;
/* create a codec specific record */ - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM;
@@ -1451,7 +1453,7 @@ int err;
/* create a codec specific record */ - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM;
@@ -1890,7 +1893,7 @@ int err;
/* create a codec specific record */ - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM;
@@ -1939,7 +1942,7 @@ int err;
/* create a codec specific record */ - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM;
[ALSA] HDA VIA: Add HP and CD pin connect config
Signed-off-by: Harald Welte HaraldWelte@viatech.com
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e7e4352..ad8eeb5 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -3,8 +3,8 @@ * * HD audio interface patch for VIA VT1708 codec * - * Copyright (c) 2006 Lydia Wang lydiawang@viatech.com - * Takashi Iwai tiwai@suse.de + * Copyright (c) 2006-2008 Lydia Wang lydiawang@viatech.com + * 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 @@ -29,6 +29,7 @@ /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ /* 2007-09-17 Lydia Wang Add VT1708B codec support */ +/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -53,6 +54,8 @@ #define VT1708_DIGOUT_NID 0x14 #define VT1708_DIGIN_NID 0x16 #define VT1708_DIGIN_PIN 0x26 +#define VT1708_HP_PIN_NID 0x20 +#define VT1708_CD_PIN_NID 0x24
#define VT1709_HP_DAC_NID 0x28 #define VT1709_DIGOUT_NID 0x13 @@ -840,11 +843,36 @@ static struct hda_amp_list vt1708_loopbacks[] = { }; #endif
+static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int def_conf; + unsigned char seqassoc; + + def_conf = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + seqassoc = (unsigned char) get_defcfg_association(def_conf); + seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) { + if (seqassoc == 0xff) { + def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, + def_conf >> 24); + } + } + + return; +} + static int vt1708_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err;
+ /* Add HP and CD pin config connect bit re-config action */ + vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); + vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); if (err < 0) return err;
[ALSA] HDA VIA: Fix inversion of Surround and Side Channels
In the current driver, there is a consistent mistake between the SURROUND and the SIDE channels. This patch fixes it.
Signed-off-by: Harald Welte HaraldWelte@viatech.com
Index: linux-2.6/sound/pci/hda/patch_via.c =================================================================== --- linux-2.6.orig/sound/pci/hda/patch_via.c +++ linux-2.6/sound/pci/hda/patch_via.c @@ -30,6 +30,7 @@ /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ /* 2007-09-17 Lydia Wang Add VT1708B codec support */ /* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ +/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -661,10 +662,10 @@ spec->multiout.dac_nids[i] = 0x12; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x13; + spec->multiout.dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x11; + spec->multiout.dac_nids[i] = 0x13; break; } } @@ -689,7 +690,7 @@ continue; if (i != AUTO_SEQ_FRONT) - nid_vol = 0x1b - i + 1; + nid_vol = 0x18 + i;
if (i == AUTO_SEQ_CENLFE) { /* Center/LFE */ @@ -1120,11 +1121,11 @@ break; case AUTO_SEQ_SURROUND: /* AOW3 */ - spec->multiout.dac_nids[i] = 0x27; + spec->multiout.dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: /* AOW1 */ - spec->multiout.dac_nids[i] = 0x11; + spec->multiout.dac_nids[i] = 0x27; break; default: break; @@ -1233,26 +1234,26 @@ } else if (i == AUTO_SEQ_SURROUND) { sprintf(name, "%s Playback Volume", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x29, 3, 0, + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); if (err < 0) return err; sprintf(name, "%s Playback Switch", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x29, 3, 0, + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); if (err < 0) return err; } else if (i == AUTO_SEQ_SIDE) { sprintf(name, "%s Playback Volume", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, + HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); if (err < 0) return err; sprintf(name, "%s Playback Switch", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, + HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -1693,10 +1694,10 @@ spec->multiout.dac_nids[i] = 0x24; break; case AUTO_SEQ_SURROUND: - spec->multiout.dac_nids[i] = 0x25; + spec->multiout.dac_nids[i] = 0x11; break; case AUTO_SEQ_SIDE: - spec->multiout.dac_nids[i] = 0x11; + spec->multiout.dac_nids[i] = 0x25; break; } } @@ -1711,7 +1712,7 @@ { char name[32]; static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; - hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18}; + hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27}; hda_nid_t nid, nid_vol = 0; int i, err;
[ALSA] HDA VIA: Add support vor VIA VT1708S and VT1702 codec
The VT1702 and VT1708S codecs are new HDA codecs by VIA.
This patch adds support for them to the patch_via.c file for HDA
Signed-off-by: Harald Welte HaraldWelte@viatech.com
Index: linux-2.6/sound/pci/hda/patch_via.c =================================================================== --- linux-2.6.orig/sound/pci/hda/patch_via.c +++ linux-2.6/sound/pci/hda/patch_via.c @@ -1,7 +1,7 @@ /* * Universal Interface for Intel High Definition Audio Codec * - * HD audio interface patch for VIA VT1708 codec + * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec * * Copyright (c) 2006-2008 Lydia Wang lydiawang@viatech.com * Takashi Iwai tiwai@suse.de @@ -31,6 +31,7 @@ /* 2007-09-17 Lydia Wang Add VT1708B codec support */ /* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ /* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ +/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -55,8 +56,8 @@ #define VT1708_DIGOUT_NID 0x14 #define VT1708_DIGIN_NID 0x16 #define VT1708_DIGIN_PIN 0x26 -#define VT1708_HP_PIN_NID 0x20 -#define VT1708_CD_PIN_NID 0x24 +#define VT1708_HP_PIN_NID 0x20 +#define VT1708_CD_PIN_NID 0x24
#define VT1709_HP_DAC_NID 0x28 #define VT1709_DIGOUT_NID 0x13 @@ -68,12 +69,19 @@ #define VT1708B_DIGIN_NID 0x15 #define VT1708B_DIGIN_PIN 0x21
+#define VT1708S_HP_NID 0x25 +#define VT1708S_DIGOUT_NID 0x12 + +#define VT1702_HP_NID 0x17 +#define VT1702_DIGOUT_NID 0x11 + #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) #define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) #define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) - +#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397) +#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398)
enum { VIA_CTL_WIDGET_VOL, @@ -150,6 +158,16 @@ 0x13, 0x14 };
+static hda_nid_t vt1708S_adc_nids[2] = { + /* ADC1-2 */ + 0x13, 0x14 +}; + +static hda_nid_t vt1702_adc_nids[3] = { + /* ADC1-2 */ + 0x12, 0x20, 0x1F +}; + /* add dynamic controls */ static int via_add_control(struct via_spec *spec, int type, const char *name, unsigned long val) @@ -294,6 +312,9 @@ IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0)) return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 0x17, &spec->cur_mux[adc_idx]); + else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0)) + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + 0x13, &spec->cur_mux[adc_idx]); else return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, spec->adc_nids[adc_idx], @@ -2011,6 +2032,707 @@ return 0; }
+/* Patch for VT1708S */ + +/* capture mixer elements */ +static struct snd_kcontrol_new vt1708S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x1E, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static struct hda_verb vt1708S_volume_init_verbs[] = { + /* Unmute ADC0-1 and set the default input to mic-in */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the + * analog-loopback mixer widget */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + /* Setup default input of PW4 to MW0 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* PW9 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; + +static struct hda_pcm_stream vt1708S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 8, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_pcm_prepare, + .cleanup = via_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1708S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x13, /* NID to query formats and rates */ + .ops = { + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1708S_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->multiout.dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->multiout.dac_nids[i] = 0x24; + break; + case AUTO_SEQ_SURROUND: + spec->multiout.dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + spec->multiout.dac_nids[i] = 0x25; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25}; + hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27}; + hda_nid_t nid, nid_vol, nid_mute; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + + nid_vol = nid_vols[i]; + nid_mute = nid_mutes[i]; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, + 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, + 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, + HDA_INPUT)); + if (err < 0) + return err; + + /* Front */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, + 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, + 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + + return 0; +} + +static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */ + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; + struct hda_input_mux *imux = &spec->private_imux; + int i, err, idx = 0; + + /* for internal loopback recording select */ + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = 5; + imux->num_items++; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!cfg->input_pins[i]) + continue; + + switch (cfg->input_pins[i]) { + case 0x1a: /* Mic */ + idx = 2; + break; + + case 0x1b: /* Line In */ + idx = 3; + break; + + case 0x1e: /* Front Mic */ + idx = 4; + break; + + case 0x1f: /* CD */ + idx = 1; + break; + } + err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], + idx, 0x16); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = idx-1; + imux->num_items++; + } + return 0; +} + +static int vt1708S_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + static hda_nid_t vt1708s_ignore[] = {0x21, 0}; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + vt1708s_ignore); + if (err < 0) + return err; + err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID; + + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->input_mux = &spec->private_imux; + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1708S_loopbacks[] = { + { 0x16, HDA_INPUT, 1 }, + { 0x16, HDA_INPUT, 2 }, + { 0x16, HDA_INPUT, 3 }, + { 0x16, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +static int patch_vt1708S(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + /* automatic parse from the BIOS config */ + err = vt1708S_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs = vt1708S_volume_init_verbs; + + spec->stream_name_analog = "VT1708S Analog"; + spec->stream_analog_playback = &vt1708S_pcm_analog_playback; + spec->stream_analog_capture = &vt1708S_pcm_analog_capture; + + spec->stream_name_digital = "VT1708S Digital"; + spec->stream_digital_playback = &vt1708S_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1708S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids); + spec->mixers[spec->num_mixers] = vt1708S_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708S_loopbacks; +#endif + + return 0; +} + +/* Patch for VT1702 */ + +/* capture mixer elements */ +static struct snd_kcontrol_new vt1702_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static struct hda_verb vt1702_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */ + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* Setup default input of PW4 to MW0 */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* PW6 PW7 Output enable */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; + +static struct hda_pcm_stream vt1702_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_pcm_prepare, + .cleanup = via_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1702_pcm_analog_capture = { + .substreams = 3, + .channels_min = 2, + .channels_max = 2, + .nid = 0x12, /* NID to query formats and rates */ + .ops = { + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream vt1702_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .open = via_dig_playback_pcm_open, + .close = via_dig_playback_pcm_close, + .prepare = via_dig_playback_pcm_prepare + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1702_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + + if (cfg->line_out_pins[0]) { + /* config dac list */ + spec->multiout.dac_nids[0] = 0x10; + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1702_auto_create_line_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + + if (!cfg->line_out_pins[0]) + return -1; + + /* add control to mixer index 0 */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + + /* Front */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x1D; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; + struct hda_input_mux *imux = &spec->private_imux; + int i, err, idx = 0; + + /* for internal loopback recording select */ + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = 3; + imux->num_items++; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!cfg->input_pins[i]) + continue; + + switch (cfg->input_pins[i]) { + case 0x14: /* Mic */ + idx = 1; + break; + + case 0x15: /* Line In */ + idx = 2; + break; + + case 0x18: /* Front Mic */ + idx = 3; + break; + } + err = via_new_analog_input(spec, cfg->input_pins[i], + labels[i], idx, 0x1A); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = idx-1; + imux->num_items++; + } + return 0; +} + +static int vt1702_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + static hda_nid_t vt1702_ignore[] = {0x1C, 0}; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + vt1702_ignore); + if (err < 0) + return err; + err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = VT1702_DIGOUT_NID; + + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->input_mux = &spec->private_imux; + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1702_loopbacks[] = { + { 0x1A, HDA_INPUT, 1 }, + { 0x1A, HDA_INPUT, 2 }, + { 0x1A, HDA_INPUT, 3 }, + { 0x1A, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +static int patch_vt1702(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + unsigned int response; + unsigned char control; + + /* create a codec specific record */ + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + /* automatic parse from the BIOS config */ + err = vt1702_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs = vt1702_volume_init_verbs; + + spec->stream_name_analog = "VT1702 Analog"; + spec->stream_analog_playback = &vt1702_pcm_analog_playback; + spec->stream_analog_capture = &vt1702_pcm_analog_capture; + + spec->stream_name_digital = "VT1702 Digital"; + spec->stream_digital_playback = &vt1702_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1702_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids); + spec->mixers[spec->num_mixers] = vt1702_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1702_loopbacks; +#endif + + /* Open backdoor */ + response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0); + control = (unsigned char)(response & 0xff); + control |= 0x3; + snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control); + + /* Enable GPIO 0&1 for volume&mute control */ + /* Enable GPIO 2 for DMIC-DATA */ + response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0); + control = (unsigned char)((response >> 16) & 0x3f); + snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control); + + return 0; +} + /* * patch entries */ @@ -2051,5 +2773,37 @@ .patch = patch_vt1708B_4ch}, { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, + { .id = 0x11060397, .name = "VIA VT1708S", + .patch = patch_vt1708S}, + { .id = 0x11061397, .name = "VIA VT1708S", + .patch = patch_vt1708S}, + { .id = 0x11062397, .name = "VIA VT1708S", + .patch = patch_vt1708S}, + { .id = 0x11063397, .name = "VIA VT1708S", + .patch = patch_vt1708S}, + { .id = 0x11064397, .name = "VIA VT1708S", + .patch = patch_vt1708S}, + { .id = 0x11065397, .name = "VIA VT1708S", + .patch = patch_vt1708S}, + { .id = 0x11066397, .name = "VIA VT1708S", + .patch = patch_vt1708S}, + { .id = 0x11067397, .name = "VIA VT1708S", + .patch = patch_vt1708S}, + { .id = 0x11060398, .name = "VIA VT1702", + .patch = patch_vt1702}, + { .id = 0x11061398, .name = "VIA VT1702", + .patch = patch_vt1702}, + { .id = 0x11062398, .name = "VIA VT1702", + .patch = patch_vt1702}, + { .id = 0x11063398, .name = "VIA VT1702", + .patch = patch_vt1702}, + { .id = 0x11064398, .name = "VIA VT1702", + .patch = patch_vt1702}, + { .id = 0x11065398, .name = "VIA VT1702", + .patch = patch_vt1702}, + { .id = 0x11066398, .name = "VIA VT1702", + .patch = patch_vt1702}, + { .id = 0x11067398, .name = "VIA VT1702", + .patch = patch_vt1702}, {} /* terminator */ };
[ALSA] HDA VIA: Automatically mute front speaker on headphone plug-in
Signed-off-by: Harald Welte HaraldWelte@viatech.com
Index: linux-2.6/sound/pci/hda/patch_via.c =================================================================== --- linux-2.6.orig/sound/pci/hda/patch_via.c +++ linux-2.6/sound/pci/hda/patch_via.c @@ -32,6 +32,7 @@ /* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ /* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ /* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ +/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -83,6 +84,9 @@ #define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397) #define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398)
+#define VIA_HP_EVENT 0x01 +#define VIA_GPIO_EVENT 0x02 + enum { VIA_CTL_WIDGET_VOL, VIA_CTL_WIDGET_MUTE, @@ -106,7 +110,8 @@ struct snd_kcontrol_new *mixers[3]; unsigned int num_mixers;
- struct hda_verb *init_verbs; + struct hda_verb *init_verbs[5]; + unsigned int num_iverbs;
char *stream_name_analog; struct hda_pcm_stream *stream_analog_playback; @@ -606,10 +611,85 @@ kfree(codec->spec); }
+/* mute internal speaker if HP is plugged */ +static void via_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + struct via_spec *spec = codec->spec; + + present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], + HDA_OUTPUT, 0, HDA_AMP_MUTE, + present ? HDA_AMP_MUTE : 0); +} + +static void via_gpio_control(struct hda_codec *codec) +{ + unsigned int gpio_data; + unsigned int vol_counter; + unsigned int vol; + unsigned int master_vol; + + struct via_spec *spec = codec->spec; + + gpio_data = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0) & 0x03; + + vol_counter = (snd_hda_codec_read(codec, codec->afg, 0, + 0xF84, 0) & 0x3F0000) >> 16; + + vol = vol_counter & 0x1F; + master_vol = snd_hda_codec_read(codec, 0x1A, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT); + + if (gpio_data == 0x02) { + /* unmute line out */ + snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + + if (vol_counter & 0x20) { + /* decrease volume */ + if (vol > master_vol) + vol = master_vol; + snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, + 0, HDA_AMP_VOLMASK, + master_vol-vol); + } else { + /* increase volume */ + snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0, + HDA_AMP_VOLMASK, + ((master_vol+vol) > 0x2A) ? 0x2A : + (master_vol+vol)); + } + } else if (!(gpio_data & 0x02)) { + /* mute line out */ + snd_hda_codec_amp_stereo(codec, + spec->autocfg.line_out_pins[0], + HDA_OUTPUT, 0, HDA_AMP_MUTE, + HDA_AMP_MUTE); + } +} + +/* unsolicited event for jack sensing */ +static void via_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + res >>= 26; + if (res == VIA_HP_EVENT) + via_hp_automute(codec); + else if (res == VIA_GPIO_EVENT) + via_gpio_control(codec); +} + static int via_init(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - snd_hda_sequence_write(codec, spec->init_verbs); + int i; + for (i = 0; i < spec->num_iverbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); + /* Lydia Add for EAPD enable */ if (!spec->dig_in_nid) { /* No Digital In connection */ if (IS_VT1708_VENDORID(codec->vendor_id)) { @@ -925,7 +1005,7 @@ if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
- spec->init_verbs = vt1708_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
spec->input_mux = &spec->private_imux;
@@ -1018,6 +1098,11 @@ { } /* end */ };
+static struct hda_verb vt1709_uniwill_init_verbs[] = { + {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, + { } +}; + /* * generic initialization of ADC, input mixers and output mixers */ @@ -1427,7 +1512,8 @@ "Using genenic mode...\n"); }
- spec->init_verbs = vt1709_10ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
spec->stream_name_analog = "VT1709 Analog"; spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; @@ -1448,6 +1534,7 @@ codec->patch_ops = via_patch_ops;
codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1709_loopbacks; #endif @@ -1518,7 +1605,8 @@ "Using genenic mode...\n"); }
- spec->init_verbs = vt1709_6ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
spec->stream_name_analog = "VT1709 Analog"; spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; @@ -1539,6 +1627,7 @@ codec->patch_ops = via_patch_ops;
codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1709_loopbacks; #endif @@ -1639,6 +1728,11 @@ { } };
+static struct hda_verb vt1708B_uniwill_init_verbs[] = { + {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, + { } +}; + static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -1959,7 +2053,8 @@ "from BIOS. Using genenic mode...\n"); }
- spec->init_verbs = vt1708B_8ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
spec->stream_name_analog = "VT1708B Analog"; spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; @@ -1979,6 +2074,7 @@ codec->patch_ops = via_patch_ops;
codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1708B_loopbacks; #endif @@ -2008,7 +2104,8 @@ "from BIOS. Using genenic mode...\n"); }
- spec->init_verbs = vt1708B_4ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
spec->stream_name_analog = "VT1708B Analog"; spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; @@ -2028,6 +2125,7 @@ codec->patch_ops = via_patch_ops;
codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1708B_loopbacks; #endif @@ -2082,6 +2180,11 @@ { } };
+static struct hda_verb vt1708S_uniwill_init_verbs[] = { + {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, + { } +}; + static struct hda_pcm_stream vt1708S_pcm_analog_playback = { .substreams = 2, .channels_min = 2, @@ -2391,7 +2494,8 @@ "from BIOS. Using genenic mode...\n"); }
- spec->init_verbs = vt1708S_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
spec->stream_name_analog = "VT1708S Analog"; spec->stream_analog_playback = &vt1708S_pcm_analog_playback; @@ -2410,7 +2514,7 @@ codec->patch_ops = via_patch_ops;
codec->patch_ops.init = via_auto_init; - + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1708S_loopbacks; #endif @@ -2473,6 +2577,12 @@ { } };
+static struct hda_verb vt1702_uniwill_init_verbs[] = { + {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT}, + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, + { } +}; + static struct hda_pcm_stream vt1702_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -2699,7 +2809,8 @@ "from BIOS. Using genenic mode...\n"); }
- spec->init_verbs = vt1702_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
spec->stream_name_analog = "VT1702 Analog"; spec->stream_analog_playback = &vt1702_pcm_analog_playback; @@ -2718,7 +2829,7 @@ codec->patch_ops = via_patch_ops;
codec->patch_ops.init = via_auto_init; - + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1702_loopbacks; #endif
[ALSA] HDA VIA: Add "Independent Headphone" mode
This mode allows an output stream to have two substreams, one for the speakers and one for the headphone. Each of the substreams has independent PCM data and uses a different DAC.
Signed-off-by: Harald Welte HaraldWelte@viatech.com
Index: linux-2.6/sound/pci/hda/patch_via.c =================================================================== --- linux-2.6.orig/sound/pci/hda/patch_via.c +++ linux-2.6/sound/pci/hda/patch_via.c @@ -33,6 +33,7 @@ /* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ /* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ /* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ +/* 2008-04-09 Lydia Wang Add Independent HP feature */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -41,6 +42,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <sound/core.h> +#include <sound/asoundef.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_patch.h" @@ -140,9 +142,13 @@ struct auto_pin_cfg autocfg; unsigned int num_kctl_alloc, num_kctl_used; struct snd_kcontrol_new *kctl_alloc; - struct hda_input_mux private_imux; + struct hda_input_mux private_imux[2]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+ /* HP mode source */ + const struct hda_input_mux *hp_mux; + unsigned int hp_independent_mode; + #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif @@ -326,6 +332,92 @@ &spec->cur_mux[adc_idx]); }
+static int via_independent_hp_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->hp_mux, uinfo); +} + +static int via_independent_hp_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + hda_nid_t nid = spec->autocfg.hp_pins[0]; + unsigned int pinsel = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, + 0x00); + + ucontrol->value.enumerated.item[0] = pinsel; + + return 0; +} + +static int via_independent_hp_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct via_spec *spec = codec->spec; + hda_nid_t nid = spec->autocfg.hp_pins[0]; + unsigned int pinsel = ucontrol->value.enumerated.item[0]; + unsigned int con_nid = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_LIST, 0) & 0xff; + + if (con_nid == spec->multiout.hp_nid) { + if (pinsel == 0) { + if (!spec->hp_independent_mode) { + if (spec->multiout.num_dacs > 1) + spec->multiout.num_dacs -= 1; + spec->hp_independent_mode = 1; + } + } else if (pinsel == 1) { + if (spec->hp_independent_mode) { + if (spec->multiout.num_dacs > 1) + spec->multiout.num_dacs += 1; + spec->hp_independent_mode = 0; + } + } + } else { + if (pinsel == 0) { + if (spec->hp_independent_mode) { + if (spec->multiout.num_dacs > 1) + spec->multiout.num_dacs += 1; + spec->hp_independent_mode = 0; + } + } else if (pinsel == 1) { + if (!spec->hp_independent_mode) { + if (spec->multiout.num_dacs > 1) + spec->multiout.num_dacs -= 1; + spec->hp_independent_mode = 1; + } + } + } + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, + pinsel); + + if (spec->multiout.hp_nid && + spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT]) + snd_hda_codec_setup_stream(codec, + spec->multiout.hp_nid, + 0, 0, 0); + + return 0; +} + +static struct snd_kcontrol_new via_hp_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Independent HP", + .count = 1, + .info = via_independent_hp_info, + .get = via_independent_hp_get, + .put = via_independent_hp_put, + }, + { } /* end */ +}; + /* capture mixer elements */ static struct snd_kcontrol_new vt1708_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), @@ -411,6 +503,138 @@ return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); }
+ +static void playback_multi_pcm_prep_0(struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + hda_nid_t *nids = mout->dac_nids; + int chs = substream->runtime->channels; + int i; + + mutex_lock(&codec->spdif_mutex); + if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { + if (chs == 2 && + snd_hda_is_supported_format(codec, mout->dig_out_nid, + format) && + !(codec->spdif_status & IEC958_AES0_NONAUDIO)) { + mout->dig_out_used = HDA_DIG_ANALOG_DUP; + /* turn off SPDIF once; otherwise the IEC958 bits won't + * be updated */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, mout->dig_out_nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & + ~AC_DIG1_ENABLE & 0xff); + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + stream_tag, 0, format); + /* turn on again (if needed) */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, mout->dig_out_nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); + } else { + mout->dig_out_used = 0; + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + 0, 0, 0); + } + } + mutex_unlock(&codec->spdif_mutex); + + /* front */ + snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, + 0, format); + + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && + !spec->hp_independent_mode) + /* headphone out will just decode front left/right (stereo) */ + snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, + 0, format); + + /* extra outputs copied from front */ + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) + if (mout->extra_out_nid[i]) + snd_hda_codec_setup_stream(codec, + mout->extra_out_nid[i], + stream_tag, 0, format); + + /* surrounds */ + for (i = 1; i < mout->num_dacs; i++) { + if (chs >= (i + 1) * 2) /* independent out */ + snd_hda_codec_setup_stream(codec, nids[i], stream_tag, + i * 2, format); + else /* copy front */ + snd_hda_codec_setup_stream(codec, nids[i], stream_tag, + 0, format); + } +} + +static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + hda_nid_t *nids = mout->dac_nids; + + if (substream->number == 0) + playback_multi_pcm_prep_0(codec, stream_tag, format, + substream); + else { + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && + spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + stream_tag, 0, format); + } + + return 0; +} + +static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + struct hda_multi_out *mout = &spec->multiout; + hda_nid_t *nids = mout->dac_nids; + int i; + + if (substream->number == 0) { + for (i = 0; i < mout->num_dacs; i++) + snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); + + if (mout->hp_nid && !spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + 0, 0, 0); + + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) + if (mout->extra_out_nid[i]) + snd_hda_codec_setup_stream(codec, + mout->extra_out_nid[i], + 0, 0, 0); + mutex_lock(&codec->spdif_mutex); + if (mout->dig_out_nid && + mout->dig_out_used == HDA_DIG_ANALOG_DUP) { + snd_hda_codec_setup_stream(codec, mout->dig_out_nid, + 0, 0, 0); + mout->dig_out_used = 0; + } + mutex_unlock(&codec->spdif_mutex); + } else { + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && + spec->hp_independent_mode) + snd_hda_codec_setup_stream(codec, mout->hp_nid, + 0, 0, 0); + } + + return 0; +} + /* * Digital out */ @@ -467,14 +691,14 @@ }
static struct hda_pcm_stream vt1708_pcm_analog_playback = { - .substreams = 1, + .substreams = 2, .channels_min = 2, .channels_max = 8, .nid = 0x10, /* NID to query formats and rates */ .ops = { .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup }, };
@@ -866,6 +1090,24 @@ return 0; }
+static void create_hp_imux(struct via_spec *spec) +{ + int i; + struct hda_input_mux *imux = &spec->private_imux[1]; + static const char *texts[] = { "OFF", "ON", NULL}; + + /* for hp mode select */ + i = 0; + while (texts[i] != NULL) { + imux->items[imux->num_items].label = texts[i]; + imux->items[imux->num_items].index = i; + imux->num_items++; + i++; + } + + spec->hp_mux = &spec->private_imux[1]; +} + static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) { int err; @@ -886,6 +1128,8 @@ if (err < 0) return err;
+ create_hp_imux(spec); + return 0; }
@@ -896,7 +1140,7 @@ static char *labels[] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL }; - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx = 0;
/* for internal loopback recording select */ @@ -1007,7 +1251,9 @@
spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
- spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; + + spec->mixers[spec->num_mixers++] = via_hp_mixer;
return 1; } @@ -1402,7 +1648,7 @@ static char *labels[] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL }; - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx = 0;
/* for internal loopback recording select */ @@ -1476,7 +1722,7 @@ if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
- spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0];
return 1; } @@ -1734,26 +1980,26 @@ };
static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { - .substreams = 1, + .substreams = 2, .channels_min = 2, .channels_max = 8, .nid = 0x10, /* NID to query formats and rates */ .ops = { .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup }, };
static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { - .substreams = 1, + .substreams = 2, .channels_min = 2, .channels_max = 4, .nid = 0x10, /* NID to query formats and rates */ .ops = { .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup }, };
@@ -1932,6 +2178,8 @@ if (err < 0) return err;
+ create_hp_imux(spec); + return 0; }
@@ -1942,7 +2190,7 @@ static char *labels[] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL }; - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx = 0;
/* for internal loopback recording select */ @@ -2016,7 +2264,9 @@ if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
- spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; + + spec->mixers[spec->num_mixers++] = via_hp_mixer;
return 1; } @@ -2373,6 +2623,8 @@ if (err < 0) return err;
+ create_hp_imux(spec); + return 0; }
@@ -2383,7 +2635,7 @@ static char *labels[] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL }; - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx = 0;
/* for internal loopback recording select */ @@ -2457,7 +2709,9 @@ if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
- spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; + + spec->mixers[spec->num_mixers++] = via_hp_mixer;
return 1; } @@ -2584,14 +2838,14 @@ };
static struct hda_pcm_stream vt1702_pcm_analog_playback = { - .substreams = 1, + .substreams = 2, .channels_min = 2, .channels_max = 2, .nid = 0x10, /* NID to query formats and rates */ .ops = { .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup }, };
@@ -2690,6 +2944,8 @@ if (err < 0) return err;
+ create_hp_imux(spec); + return 0; }
@@ -2700,7 +2956,7 @@ static char *labels[] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL }; - struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx = 0;
/* for internal loopback recording select */ @@ -2770,7 +3026,9 @@ if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
- spec->input_mux = &spec->private_imux; + spec->input_mux = &spec->private_imux[0]; + + spec->mixers[spec->num_mixers++] = via_hp_mixer;
return 1; }
At Tue, 9 Sep 2008 15:58:27 +0800, Harald Welte wrote:
[ALSA] HDA VIA: Add "Independent Headphone" mode
This mode allows an output stream to have two substreams, one for the speakers and one for the headphone. Each of the substreams has independent PCM data and uses a different DAC.
Signed-off-by: Harald Welte HaraldWelte@viatech.com
Index: linux-2.6/sound/pci/hda/patch_via.c
--- linux-2.6.orig/sound/pci/hda/patch_via.c +++ linux-2.6/sound/pci/hda/patch_via.c @@ -33,6 +33,7 @@ /* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ /* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ /* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ +/* 2008-04-09 Lydia Wang Add Independent HP feature */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -41,6 +42,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <sound/core.h> +#include <sound/asoundef.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_patch.h" @@ -140,9 +142,13 @@ struct auto_pin_cfg autocfg; unsigned int num_kctl_alloc, num_kctl_used; struct snd_kcontrol_new *kctl_alloc;
- struct hda_input_mux private_imux;
struct hda_input_mux private_imux[2]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
/* HP mode source */
const struct hda_input_mux *hp_mux;
unsigned int hp_independent_mode;
#ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif @@ -326,6 +332,92 @@ &spec->cur_mux[adc_idx]); }
+static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
+{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct via_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->hp_mux, uinfo);
+}
Usually this kind of "switch" is implemented as a boolean switch since some mixer apps aren't capable to handle enum controls.
If you'd like to change to that, please send an additional patch as I already committed these.
thanks,
Takashi
[ALSA] HDA VIA: Add second S/PDIF output support for VT1702 and VT1708S
The VT1702 and VT1708S have a second S/PDIF output which is used to connect to a HDMI transmitter. This patch adds support for it.
Signed-off-by: Harald Welte HaraldWelte@viatech.com
Index: linux-2.6/sound/pci/hda/patch_via.c =================================================================== --- linux-2.6.orig/sound/pci/hda/patch_via.c +++ linux-2.6/sound/pci/hda/patch_via.c @@ -34,6 +34,7 @@ /* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ /* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ /* 2008-04-09 Lydia Wang Add Independent HP feature */ +/* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -122,9 +123,11 @@ char *stream_name_digital; struct hda_pcm_stream *stream_digital_playback; struct hda_pcm_stream *stream_digital_capture; + struct hda_pcm_stream *stream_extra_digital_playback;
/* playback */ struct hda_multi_out multiout; + hda_nid_t extra_dig_out_nid;
/* capture */ unsigned int num_adc_nids; @@ -136,7 +139,7 @@ unsigned int cur_mux[3];
/* PCM information */ - struct hda_pcm pcm_rec[2]; + struct hda_pcm pcm_rec[3];
/* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; @@ -665,6 +668,36 @@ stream_tag, format, substream); }
+/* setup SPDIF output stream */ +static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid, + unsigned int stream_tag, unsigned int format) +{ + /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); + /* turn on again (if needed) */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); +} + +static int via_extra_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + + mutex_lock(&codec->spdif_mutex); + setup_dig_playback_stream(codec, spec->extra_dig_out_nid, stream_tag, + format); + mutex_unlock(&codec->spdif_mutex); + return 0; +} + /* * Analog capture */ @@ -765,6 +798,13 @@ if (err < 0) return err; spec->multiout.share_spdif = 1; + + if (spec->extra_dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, + spec->extra_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); @@ -815,6 +849,17 @@ } }
+ if (spec->extra_dig_out_nid) { + codec->num_pcms++; + info++; + info->name = spec->stream_name_digital; + info->pcm_type = HDA_PCM_TYPE_HDMI; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + *(spec->stream_extra_digital_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->extra_dig_out_nid; + } + return 0; }
@@ -2470,6 +2515,16 @@ }, };
+static struct hda_pcm_stream vt1708S_pcm_extra_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .prepare = via_extra_dig_playback_pcm_prepare + }, +}; + /* fill in the dac_nids table from the parsed pin configuration */ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, const struct auto_pin_cfg *cfg) @@ -2706,6 +2761,8 @@ if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
+ spec->extra_dig_out_nid = 0x15; + if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
@@ -2757,6 +2814,8 @@
spec->stream_name_digital = "VT1708S Digital"; spec->stream_digital_playback = &vt1708S_pcm_digital_playback; + spec->stream_extra_digital_playback = + &vt1708S_pcm_extra_digital_playback;
if (!spec->adc_nids && spec->input_mux) { spec->adc_nids = vt1708S_adc_nids; @@ -2872,6 +2931,16 @@ }, };
+static struct hda_pcm_stream vt1702_pcm_extra_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in via_build_pcms */ + .ops = { + .prepare = via_extra_dig_playback_pcm_prepare + }, +}; + /* fill in the dac_nids table from the parsed pin configuration */ static int vt1702_auto_fill_dac_nids(struct via_spec *spec, const struct auto_pin_cfg *cfg) @@ -3023,6 +3092,8 @@ if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
+ spec->extra_dig_out_nid = 0x1B; + if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
@@ -3076,6 +3147,8 @@
spec->stream_name_digital = "VT1702 Digital"; spec->stream_digital_playback = &vt1702_pcm_digital_playback; + spec->stream_extra_digital_playback = + &vt1702_pcm_extra_digital_playback;
if (!spec->adc_nids && spec->input_mux) { spec->adc_nids = vt1702_adc_nids;
At Tue, 9 Sep 2008 15:37:17 +0800, Harald Welte wrote:
Hi!
As part of my work for VIA I have stumbled upon their current internal HDA codec driver and it's various differences against the current mainline driver.
I have spent the better part of two days separating the individual changesets out of the big diff between VIA's driver and current mainline linux-2.6 (which is identical to alsa-kernel.git).
Thanks! I merged all of them now to my git tree: git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git The HD-audio related patches are usually stored in topic/hda branch.
After this merge, I will work with product management and R&D inside VIA that all individual changesets (bugfixes / enhancements) will be sent ASAP for mainline inclusion to prevent any large differencees betwee the two trees.
If you have any questions regarding VIA's hardware or need access to data sheets or the like, I am happy to assist.
Can these be on the public place like ftp on alsa-project.org?
Takashi
2008/9/9 Harald Welte HaraldWelte@viatech.com:
If you have any questions regarding VIA's hardware or need access to data sheets or the like, I am happy to assist.
Yes... I (and probably many others) would like to know if there is any Envy24-II hardware out (besides MEDIASTATION[1])? This chip has been out for a while.
[1] http://www.lionstracs.com/store/-c-154.html?osCsid=f8a60622bf5ba667b9c536916...
Hallo Vedran,
On Tue, Sep 09, 2008 at 04:08:04PM +0200, Vedran Miletić wrote:
2008/9/9 Harald Welte HaraldWelte@viatech.com:
If you have any questions regarding VIA's hardware or need access to data sheets or the like, I am happy to assist.
Yes... I (and probably many others) would like to know if there is any Envy24-II hardware out (besides MEDIASTATION[1])? This chip has been out for a while.
I can ask, but I am not sure if VIA can or want to disclose informations about their customers. Usually there are two-way NDA's, so VIA cannot say anything about what their customers do and vice versa.
Oh, sorry, I meant it more like from a position of pure curiosity as a customer, not to break any NDAs. If you can find out if any of the manafacturers are offering Envy24-II hardware or they are likely to offer it in the future, that would be interesting. I'm not interested in companies which bought the chips from VIA if they aren't releasing mainstream hardware based on it.
If you can get this information, it certainly would be interesting.
Thanks for your effort.
2008/9/9 Harald Welte HaraldWelte@viatech.com:
Hallo Vedran,
On Tue, Sep 09, 2008 at 04:08:04PM +0200, Vedran Miletić wrote:
2008/9/9 Harald Welte HaraldWelte@viatech.com:
If you have any questions regarding VIA's hardware or need access to data sheets or the like, I am happy to assist.
Yes... I (and probably many others) would like to know if there is any Envy24-II hardware out (besides MEDIASTATION[1])? This chip has been out for a while.
I can ask, but I am not sure if VIA can or want to disclose informations about their customers. Usually there are two-way NDA's, so VIA cannot say anything about what their customers do and vice versa.
--
- Harald Welte HaraldWelte@viatech.com http://linux.via.com.tw/
============================================================================ VIA Open Source Liaison
On Tue, Sep 09, 2008 at 04:08:04PM +0200, Vedran Miletić wrote:
2008/9/9 Harald Welte HaraldWelte@viatech.com:
If you have any questions regarding VIA's hardware or need access to data sheets or the like, I am happy to assist.
Yes... I (and probably many others) would like to know if there is any Envy24-II hardware out (besides MEDIASTATION[1])? This chip has been out for a while.
I have received a response from the Envy24-II product manager, so I now know who is the major customer.
Unfortunately the infortmation is, as I expected, confidential. So VIA, including me, cannot disclose information about who is the customer and who is the product. sigh.
Sorry.
On Tue, Sep 16, 2008 at 11:23:26PM +0800, Harald Welte wrote:
On Tue, Sep 09, 2008 at 04:08:04PM +0200, Vedran Miletić wrote:
2008/9/9 Harald Welte HaraldWelte@viatech.com:
If you have any questions regarding VIA's hardware or need access to data sheets or the like, I am happy to assist.
Yes... I (and probably many others) would like to know if there is any Envy24-II hardware out (besides MEDIASTATION[1])? This chip has been out for a while.
I have received a response from the Envy24-II product manager, so I now know who is the major customer.
Unfortunately the infortmation is, as I expected, confidential. So VIA, including me, cannot disclose information about who is the customer and who is the product. sigh.
However, I can still tell you what I just found in a public revision control system ;->
http://mercurial.opensound.com/?file/a4db8c571ba7/kernel/drv/oss_envy24/oss_...
static card_spec models[] = { 41 {0xd6301412, "M Audio Delta 1010", 8, 8, 43 {0xd6311412, "M Audio Delta DiO 2496", 2, 0, 45 {0xd6321412, "M Audio Delta 66", 4, 4, 47 {0xd6331412, "M Audio Delta 44", 4, 4, 49 {0xd6341412, "M Audio Audiophile 2496", 2, 2, 51 {0xd6381412, "M Audio Delta 410", 8, 2, MF_D410 | MF_SPDIF | MF_MEEPROM, 53 {0xd63b1412, "M Audio Delta 1010LT", 8, 8, 55 {0xd6351412, "M Audio Delta TDIF", 8, 8, MF_SPDIF | MF_MEEPROM | MF_WCLOCK, 57 {0x1115153b, "Terratec EWS88MT", 8, 8, 59 {0x112b153b, "Terratec EWS88D", 8, 8, 61 {0x1130153b, "Terratec EWX 24/96", 2, 2, MF_SPDIF | MF_EWX2496, 63 {0x1138153b, "Terratec DMX6fire 24/96", 6, 6, 65 {0x17121412, "Generic Envy24 based card", 8, 8,
participants (4)
-
Harald Welte
-
Harald Welte
-
Takashi Iwai
-
Vedran Miletić