* [PATCH] azx/realtek: Unify and parameterize code for ALC880/260 codecs, take 2
@ 2004-12-16 21:11 Stephen Warren
2004-12-17 14:18 ` Takashi Iwai
0 siblings, 1 reply; 2+ messages in thread
From: Stephen Warren @ 2004-12-16 21:11 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 1487 bytes --]
This patch updates the HD-Audio ALC880/260 code driver such
that all board-specific decisions are made in a single function,
which sets variables that all other code simply uses directly
without decision making.
Also, tweak snd_hda_add_new_ctls and snd_hda_resume_ctls so they
use a sentinel value in the array of controls, and hence don't have
to be passed an explicit array-size argument.
This has the benefits of:
* Isolating board-specific code to a single location
* Simplifying the rest of the code
* Unifying the code for ALC880/ALC260, which was previously separate.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
Note: This patch was generated by "cvs diff -u". Hopefully, that's a
useful format - there are some extra lines of gunk that single-file
regular "diff -u" doesn't generate...
This is an updated version of the patch I sent yesterday, that also
tweaks the tweak snd_hda_add_new_ctls/snd_hda_resume_ctls API.
For now, I think I'm done with generic changes to the AZX codec, so the
patch is complete, unless you find any problems with it.
I'm punting on making patch_alc880/260 use pre-initialized data
structures for codec->spec for now - the code isn't too hairy yet, and
it'll be something very easily added later on if we decide to do it.
--
Stephen Warren, Software Engineer, NVIDIA, Fort Collins, CO
swarren@nvidia.com http://www.nvidia.com/
swarren@wwwdotorg.org http://www.wwwdotorg.org/pgp.html
[-- Attachment #2: realtek.cvs.7.diff --]
[-- Type: application/octet-stream, Size: 32392 bytes --]
? patch_realtek.c.0
? patch_realtek.c.1
? patch_realtek.c.2
? patch_realtek.c.3
? patch_realtek.c.4
? patch_realtek.c.5
? patch_realtek.c.6
? patch_realtek.c.6.w810
? patch_realtek.c.7
? patch_realtek.c.7.w810
? realtek.1.diff
? realtek.2.diff
? realtek.3.diff
? realtek.4.diff
? realtek.5.diff
? realtek.cvs.7.diff
? realtek.full.6.diff
? xxx
Index: hda_codec.c
===================================================================
RCS file: /cvsroot/alsa/alsa-driver/pci/azx/hda_codec.c,v
retrieving revision 1.5
diff -u -r1.5 hda_codec.c
--- hda_codec.c 15 Dec 2004 15:42:39 -0000 1.5
+++ hda_codec.c 16 Dec 2004 21:05:55 -0000
@@ -89,7 +89,7 @@
* @direct: direct flag
* @verb: the verb to send
* @parm: the parameter for the verb
- *
+ *
* Send a single command without waiting for response.
*
* Returns 0 if successful, or a negative error code.
@@ -121,7 +121,7 @@
/**
* snd_hda_get_sub_nodes - get the range of sub nodes
* @codec: the HDA codec
- * @nid: NID to parse
+ * @nid: NID to parse
* @start_id: the pointer to store the start NID
*
* Parse the NID and store the start NID of its sub-nodes.
@@ -139,7 +139,7 @@
/**
* snd_hda_get_connections - get connection list
* @codec: the HDA codec
- * @nid: NID to parse
+ * @nid: NID to parse
* @conn_list: connection list array
* @max_conns: max. number of connections to store
*
@@ -398,7 +398,7 @@
snd_printk(KERN_ERR "can't allocate struct hda_codec\n");
return -ENOMEM;
}
-
+
codec->bus = bus;
codec->addr = codec_addr;
init_MUTEX(&codec->spdif_mutex);
@@ -431,7 +431,7 @@
snd_hda_codec_free(codec);
return err;
}
-
+
snd_hda_codec_proc_new(codec);
sprintf(component, "HDA%08x", codec->vendor_id);
@@ -569,7 +569,7 @@
get_vol_mute(codec, info, nid, ch, direction, index);
return info->vol[ch];
}
-
+
int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val)
{
struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
@@ -730,7 +730,7 @@
IEC958_AES1_CON_ORIGINAL;
return 0;
}
-
+
static int snd_hda_spdif_pmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |
@@ -750,7 +750,7 @@
return 0;
}
-
+
static int snd_hda_spdif_default_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -812,7 +812,7 @@
ucontrol->value.integer.value[0] = codec->spdif_status & 1;
return 0;
-}
+}
static int snd_hda_spdif_out_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
@@ -863,6 +863,7 @@
.get = snd_hda_spdif_out_switch_get,
.put = snd_hda_spdif_out_switch_put,
},
+ { } /* end */
};
/**
@@ -900,7 +901,7 @@
* @bus: the BUS
*
* Creates mixer controls for each codec included in the bus.
- *
+ *
* Returns 0 if successful, otherwise a negative error code.
*/
int snd_hda_build_controls(struct hda_bus *bus)
@@ -1027,7 +1028,7 @@
unsigned int val, streams;
val = 0;
- if (nid != codec->afg &&
+ if (nid != codec->afg &&
snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) {
val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
if (val == -1)
@@ -1119,7 +1120,7 @@
int i;
unsigned int val = 0, rate;
- if (nid != codec->afg &&
+ if (nid != codec->afg &&
snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) {
val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
if (val == -1)
@@ -1261,7 +1262,7 @@
* ops.prepare should be called in the prepare or hw_params callback
* with the proper parameters for set up.
* ops.cleanup should be called in hw_free for clean up of streams.
- *
+ *
* This function returns 0 if successfull, or a negative error code.
*/
int snd_hda_build_pcms(struct hda_bus *bus)
@@ -1340,12 +1341,12 @@
* This helper function creates and add new controls in the given array.
* Returns 0 if successful, or a negative error code.
*/
-int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew, int num_counts)
+int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew)
{
- int i, err;
+ int err;
- for (i = 0; i < num_counts; i++) {
- err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew[i], codec));
+ for (; knew->name; knew++) {
+ err = snd_ctl_add(codec->bus->card, snd_ctl_new1(knew, codec));
if (err < 0)
return err;
}
@@ -1551,16 +1552,15 @@
* This function resumes the mixer controls in the snd_kcontrol_new_t array,
* originally for snd_hda_add_new_ctls().
*/
-int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew, int num_counts)
+int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew)
{
- int i;
snd_ctl_elem_value_t *val;
val = kmalloc(sizeof(*val), GFP_KERNEL);
if (! val)
return -ENOMEM;
codec->in_resume = 1;
- for (i = 0; i < num_counts; i++) {
+ for (; knew->name; knew++) {
int i, count;
count = knew->count ? knew->count : 1;
for (i = 0; i < count; i++) {
@@ -1589,7 +1589,7 @@
*/
int snd_hda_resume_spdif_out(struct hda_codec *codec)
{
- return snd_hda_resume_ctls(codec, dig_mixes, ARRAY_SIZE(dig_mixes));
+ return snd_hda_resume_ctls(codec, dig_mixes);
}
#endif
Index: hda_local.h
===================================================================
RCS file: /cvsroot/alsa/alsa-driver/pci/azx/hda_local.h,v
retrieving revision 1.1
diff -u -r1.1 hda_local.h
--- hda_local.h 15 Dec 2004 15:42:39 -0000 1.1
+++ hda_local.h 16 Dec 2004 21:05:55 -0000
@@ -2,7 +2,7 @@
* Universal Interface for Intel High Definition Audio Codec
*
* Local helper functions
- *
+ *
* Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify it
@@ -130,13 +130,13 @@
};
int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl);
-int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew, int num_counts);
+int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew);
/*
* power management
*/
#ifdef CONFIG_PM
-int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew, int num_counts);
+int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew);
int snd_hda_resume_spdif_out(struct hda_codec *codec);
#endif
Index: patch_cmedia.c
===================================================================
RCS file: /cvsroot/alsa/alsa-driver/pci/azx/patch_cmedia.c,v
retrieving revision 1.3
diff -u -r1.3 patch_cmedia.c
--- patch_cmedia.c 15 Dec 2004 15:42:40 -0000 1.3
+++ patch_cmedia.c 16 Dec 2004 21:05:59 -0000
@@ -1,10 +1,10 @@
/*
* 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
@@ -214,6 +214,7 @@
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 */
};
/*
@@ -227,6 +228,7 @@
.get = cmi_ch_mode_get,
.put = cmi_ch_mode_put,
},
+ { } /* end */
};
/* AUD-in selections:
@@ -241,7 +243,7 @@
{ "CD", 0x7 },
}
};
-
+
static struct hda_input_mux cmi9880_no_line_mux = {
.num_items = 3,
.items = {
@@ -250,7 +252,7 @@
{ "CD", 0x7 },
}
};
-
+
/* front, rear, clfe, rear_surr */
static hda_nid_t cmi9880_dac_nids[4] = {
0x03, 0x04, 0x05, 0x06
@@ -324,13 +326,11 @@
struct cmi_spec *spec = codec->spec;
int err;
- err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer,
- ARRAY_SIZE(cmi9880_basic_mixer));
+ err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
if (err < 0)
return err;
if (spec->surr_switch) {
- err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer,
- ARRAY_SIZE(cmi9880_ch_mode_mixer));
+ err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer);
if (err < 0)
return err;
}
@@ -362,9 +362,9 @@
struct cmi_spec *spec = codec->spec;
cmi9880_init(codec);
- snd_hda_resume_ctls(codec, cmi9880_basic_mixer, ARRAY_SIZE(cmi9880_basic_mixer));
+ snd_hda_resume_ctls(codec, cmi9880_basic_mixer);
if (spec->surr_switch)
- snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer, ARRAY_SIZE(cmi9880_ch_mode_mixer));
+ snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer);
if (spec->multiout.dig_out_nid)
snd_hda_resume_spdif_out(codec);
Index: patch_realtek.c
===================================================================
RCS file: /cvsroot/alsa/alsa-driver/pci/azx/patch_realtek.c,v
retrieving revision 1.3
diff -u -r1.3 patch_realtek.c
--- patch_realtek.c 15 Dec 2004 15:42:40 -0000 1.3
+++ patch_realtek.c 16 Dec 2004 21:06:00 -0000
@@ -1,6 +1,6 @@
/*
* Universal Interface for Intel High Definition Audio Codec
- *
+ *
* HD audio interface patch for ALC 260/880 codecs
*
* Copyright (c) 2004 PeiSen Hou <pshou@realtek.com.tw>
@@ -38,13 +38,26 @@
ALC880_3ST_DIG,
ALC880_5ST,
ALC880_5ST_DIG,
+ ALC880_W810,
};
struct alc_spec {
- int board_config;
- unsigned int five_stack: 1;
+ /* codec parameterization */
unsigned int front_panel: 1;
+ snd_kcontrol_new_t* mixers[2];
+ unsigned int num_mixers;
+
+ struct hda_verb *init_verbs;
+
+ char* stream_name_analog;
+ struct hda_pcm_stream *stream_analog_playback;
+ struct hda_pcm_stream *stream_analog_capture;
+
+ char* stream_name_digital;
+ struct hda_pcm_stream *stream_digital_playback;
+ struct hda_pcm_stream *stream_digital_capture;
+
/* playback */
struct hda_multi_out multiout;
@@ -59,15 +72,24 @@
/* channel model */
const struct alc_channel_mode *channel_mode;
+ int num_channel_mode;
- struct hda_pcm pcm_rec[2]; /* PCM information */
+ /* PCM information */
+ struct hda_pcm pcm_rec[2];
};
/* DAC/ADC assignment */
+
static hda_nid_t alc880_dac_nids[4] = {
/* front, rear, clfe, rear_surr */
0x02, 0x05, 0x04, 0x03
};
+
+static hda_nid_t alc880_w810_dac_nids[4] = {
+ /* front, rear/surround, clfe */
+ 0x02, 0x03, 0x04
+};
+
static hda_nid_t alc880_adc_nids[3] = {
/* ADC0-2 */
0x07, 0x08, 0x09,
@@ -76,12 +98,11 @@
#define ALC880_DIGOUT_NID 0x06
#define ALC880_DIGIN_NID 0x0a
-#if 0
static hda_nid_t alc260_dac_nids[1] = {
/* front */
0x02,
};
-#endif
+
static hda_nid_t alc260_adc_nids[2] = {
/* ADC0-1 */
0x04, 0x05,
@@ -118,7 +139,7 @@
struct alc_spec *spec = codec->spec;
return snd_hda_input_mux_info(spec->input_mux, uinfo);
}
-
+
static int alc_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -155,7 +176,7 @@
* set the path ways for 2 channel output
* need to set the codec line out and mic 1 pin widgets to inputs
*/
-static struct hda_verb threestack_ch2_init[] = {
+static struct hda_verb alc880_threestack_ch2_init[] = {
/* set pin widget 1Ah (line in) for input */
{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
/* set pin widget 18h (mic1) for input, for mic also enable the vref */
@@ -171,7 +192,7 @@
* 6ch mode
* need to set the codec line out and mic 1 pin widgets to outputs
*/
-static struct hda_verb threestack_ch6_init[] = {
+static struct hda_verb alc880_threestack_ch6_init[] = {
/* set pin widget 1Ah (line in) for output */
{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
/* set pin widget 18h (mic1) for output */
@@ -211,9 +232,9 @@
{ } /* end */
};
-static struct alc_channel_mode threestack_modes[2] = {
- { 2, threestack_ch2_init },
- { 6, threestack_ch6_init },
+static struct alc_channel_mode alc880_threestack_modes[2] = {
+ { 2, alc880_threestack_ch2_init },
+ { 6, alc880_threestack_ch6_init },
};
@@ -224,7 +245,7 @@
/* set the path ways for 6 channel output
* need to set the codec line out and mic 1 pin widgets to inputs
*/
-static struct hda_verb fivestack_ch6_init[] = {
+static struct hda_verb alc880_fivestack_ch6_init[] = {
/* set pin widget 1Ah (line in) for input */
{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
/* mute the output for Line In PW */
@@ -233,7 +254,7 @@
};
/* need to set the codec line out and mic 1 pin widgets to outputs */
-static struct hda_verb fivestack_ch8_init[] = {
+static struct hda_verb alc880_fivestack_ch8_init[] = {
/* set pin widget 1Ah (line in) for output */
{ 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
/* unmute the output for Line In PW */
@@ -250,10 +271,31 @@
{ 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
{ } /* end */
};
-
-static struct alc_channel_mode fivestack_modes[2] = {
- { 6, fivestack_ch6_init },
- { 8, fivestack_ch8_init },
+
+static struct alc_channel_mode alc880_fivestack_modes[2] = {
+ { 6, alc880_fivestack_ch6_init },
+ { 8, alc880_fivestack_ch8_init },
+};
+
+/*
+ * channel source setting (6/8 channel selection for W810)
+ *
+ * W810 has rear IO for:
+ * Front (DAC 02)
+ * Surround (DAC 03)
+ * Center/LFE (DAC 04)
+ * Digital out (06)
+ *
+ * It also has a pair of internal speakers, and a headphone jack,
+ * both connected to Line2 on the codec. This output has a hardware
+ * volume control (variable resistor - no software API).
+ *
+ * For input, there's a microphone jack, and an "audio in" jack.
+ * These may not do anything useful with this driver yet.
+ */
+
+static struct alc_channel_mode alc880_w810_modes[2] = {
+ { 6, 0 }
};
/*
@@ -353,30 +395,60 @@
.get = alc880_ch_mode_get,
.put = alc880_ch_mode_put,
},
+ { } /* end */
};
static snd_kcontrol_new_t alc880_side_mixer[] = {
HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Side Playback Switch", 0x19, 0x0, HDA_OUTPUT),
+ { } /* end */
+};
+
+static snd_kcontrol_new_t alc880_w810_base_mixer[] = {
+ HDA_CODEC_VOLUME("PCM Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("PCM Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
+ {
+ .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 = 3,
+ .info = alc_mux_enum_info,
+ .get = alc_mux_enum_get,
+ .put = alc_mux_enum_put,
+ },
+ { } /* end */
};
/*
*/
-static int alc880_build_controls(struct hda_codec *codec)
+static int alc_build_controls(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int err;
+ int i;
- err = snd_hda_add_new_ctls(codec, alc880_base_mixer,
- ARRAY_SIZE(alc880_base_mixer));
- if (err < 0)
- return err;
- if (spec->five_stack) {
- err = snd_hda_add_new_ctls(codec, alc880_side_mixer,
- ARRAY_SIZE(alc880_side_mixer));
+ for (i = 0; i < spec->num_mixers; i++) {
+ err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
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)
@@ -389,7 +461,7 @@
* initialize the codec volumes, etc
*/
-static struct hda_verb alc880_three_stack_volume[] = {
+static struct hda_verb alc880_init_verbs_three_stack[] = {
/* Line In pin widget(nid=0x14) for input */
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
/* CD pin widget(nid=0x1C) for input */
@@ -464,7 +536,7 @@
{ }
};
-static struct hda_verb alc880_five_stack_volume[] = {
+static struct hda_verb alc880_init_verbs_five_stack[] = {
/* Line In pin widget(nid=0x14) for input */
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
/* CD pin widget(nid=0x1C) for input */
@@ -540,13 +612,83 @@
{ }
};
-static int alc880_init(struct hda_codec *codec)
+static struct hda_verb alc880_w810_init_verbs[] = {
+ /* front channel selector/amp: input 0: DAC: Unmuted, (no volume selection) */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+ /* front channel selector/amp: input 1: Capture mix: Unmuted, (no volume selection) */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+ /* front channel selector/amp: output 0: Unmuted, max volume */
+ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb040},
+
+ /* front out pin: unmuted, (no volume selection) */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+ /* front out pin: headphone enable, out enable, vref disabled */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+ /* surround channel selector/amp: input 0: DAC: Unmuted, (no volume selection) */
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+ /* surround channel selector/amp: input 1: Capture mix: Unmuted, (no volume selection) */
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+ /* surround channel selector/amp: output 0: Unmuted, max volume */
+ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb040},
+
+ /* surround out pin: unmuted, (no volume selection) */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+ /* surround out pin: headphone enable, out enable, vref disabled */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+ /* c/lfe channel selector/amp: input 0: DAC: Unmuted, (no volume selection) */
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
+
+ /* c/lfe channel selector/amp: input 1: Capture mix: Unmuted, (no volume selection) */
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180},
+
+ /* c/lfe channel selector/amp: output 0: Unmuted, max volume */
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb040},
+
+ /* c/lfe out pin: unmuted, (no volume selection) */
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+ /* c/lfe out pin: NOT headphone enable, out enable, vref disabled */
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+ /* hphone/speaker input selector: front DAC */
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+ /* hphone/speaker out pin: unmuted, (no volume selection) */
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+
+ /* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+
+#if 0
+ /* gpio direction: gpio0 input, gpio1 output */
+ {0x01, 0x717, 2},
+
+ /* gpio data: gpio0: 0, gpio1: 1 */
+ {0x01, 0x715, 2},
+
+ /* gpio enable: gpio0 no, gpio1 yes */
+ {0x01, 0x716, 2},
+#endif
+
+ { }
+};
+
+static int alc_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- if (spec->five_stack)
- snd_hda_sequence_write(codec, alc880_five_stack_volume);
- else
- snd_hda_sequence_write(codec, alc880_three_stack_volume);
+ snd_hda_sequence_write(codec, spec->init_verbs);
return 0;
}
@@ -554,14 +696,15 @@
/*
* resume
*/
-static int alc880_resume(struct hda_codec *codec, unsigned int state)
+static int alc_resume(struct hda_codec *codec, unsigned int state)
{
struct alc_spec *spec = codec->spec;
+ int i;
- alc880_init(codec);
- snd_hda_resume_ctls(codec, alc880_base_mixer, ARRAY_SIZE(alc880_base_mixer));
- if (spec->five_stack)
- snd_hda_resume_ctls(codec, alc880_side_mixer, ARRAY_SIZE(alc880_side_mixer));
+ alc_init(codec);
+ for (i = 0; i < spec->num_mixers; i++) {
+ snd_hda_resume_ctls(codec, spec->mixers[i]);
+ }
if (spec->multiout.dig_out_nid)
snd_hda_resume_spdif_out(codec);
@@ -674,7 +817,7 @@
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
- /* NID is set in alc880_build_pcms */
+ /* NID is set in alc_build_pcms */
.ops = {
.open = alc880_dig_playback_pcm_open,
.close = alc880_dig_playback_pcm_close
@@ -685,36 +828,39 @@
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
- /* NID is set in alc880_build_pcms */
+ /* NID is set in alc_build_pcms */
};
-static int alc880_build_pcms(struct hda_codec *codec)
+static int alc_build_pcms(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec;
+ int i;
codec->num_pcms = 1;
codec->pcm_info = info;
- info->name = "ALC880 Analog";
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc880_pcm_analog_playback;
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = alc880_pcm_analog_capture;
-
- if (spec->five_stack)
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 8;
- else
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 6;
+ info->name = spec->stream_name_analog;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
+ for (i = 0; i < spec->num_channel_mode; i++) {
+ if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
+ }
+ }
if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
codec->num_pcms++;
info++;
- info->name = "ALC880 Digital";
+ info->name = spec->stream_name_digital;
if (spec->multiout.dig_out_nid) {
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc880_pcm_digital_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
}
if (spec->dig_in_nid) {
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = alc880_pcm_digital_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
}
}
@@ -722,20 +868,20 @@
return 0;
}
-static void alc880_free(struct hda_codec *codec)
+static void alc_free(struct hda_codec *codec)
{
kfree(codec->spec);
}
/*
*/
-static struct hda_codec_ops alc880_patch_ops = {
- .build_controls = alc880_build_controls,
- .build_pcms = alc880_build_pcms,
- .init = alc880_init,
- .free = alc880_free,
+static struct hda_codec_ops alc_patch_ops = {
+ .build_controls = alc_build_controls,
+ .build_pcms = alc_build_pcms,
+ .init = alc_init,
+ .free = alc_free,
#ifdef CONFIG_PM
- .resume = alc880_resume,
+ .resume = alc_resume,
#endif
};
@@ -748,19 +894,19 @@
{ .pci_vendor = 0x8086, .pci_device = 0xe200, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe201, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe202, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST },
+ { .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe204, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe205, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe206, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST },
+ { .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe208, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe209, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe20a, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST },
+ { .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe20c, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe20d, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe20e, .config = ALC880_3ST },
- { .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST },
+ { .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe210, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe211, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xe214, .config = ALC880_3ST },
@@ -772,11 +918,11 @@
{ .pci_vendor = 0x8086, .pci_device = 0xe404, .config = ALC880_3ST },
{ .pci_vendor = 0x8086, .pci_device = 0xa101, .config = ALC880_3ST },
{ .pci_vendor = 0x107b, .pci_device = 0x3031, .config = ALC880_3ST },
- { .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST },
+ { .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST },
{ .pci_vendor = 0x107b, .pci_device = 0x4037, .config = ALC880_3ST },
{ .pci_vendor = 0x107b, .pci_device = 0x4038, .config = ALC880_3ST },
{ .pci_vendor = 0x107b, .pci_device = 0x4040, .config = ALC880_3ST },
- { .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST },
+ { .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST },
/* Back 3 jack, front 2 jack (Internal add Aux-In) */
{ .pci_vendor = 0x1025, .pci_device = 0xe310, .config = ALC880_3ST },
@@ -807,61 +953,128 @@
{ .pci_vendor = 0x8086, .pci_device = 0xa100, .config = ALC880_5ST_DIG },
{ .pci_vendor = 0x1565, .pci_device = 0x8202, .config = ALC880_5ST_DIG },
+ { .modelname = "w810", .config = ALC880_W810 },
+ { .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 },
+
{}
};
static int patch_alc880(struct hda_codec *codec)
{
struct alc_spec *spec;
+ int board_config;
spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
codec->spec = spec;
- spec->board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
- if (spec->board_config < 0) {
+
+ board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
+ if (board_config < 0) {
snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n");
- spec->board_config = ALC880_MINIMAL;
+ board_config = ALC880_MINIMAL;
+ }
+
+ switch (board_config) {
+ case ALC880_W810:
+ spec->mixers[spec->num_mixers] = alc880_w810_base_mixer;
+ spec->num_mixers++;
+ break;
+ default:
+ spec->mixers[spec->num_mixers] = alc880_base_mixer;
+ spec->num_mixers++;
+ break;
}
- switch (spec->board_config) {
+
+ switch (board_config) {
case ALC880_3ST_DIG:
case ALC880_5ST_DIG:
spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
- spec->front_panel = 1;
break;
+ default:
+ break;
+ }
+
+ switch (board_config) {
case ALC880_3ST:
+ case ALC880_3ST_DIG:
case ALC880_5ST:
+ case ALC880_5ST_DIG:
+ case ALC880_W810:
spec->front_panel = 1;
break;
+ default:
+ break;
}
- if (spec->board_config == ALC880_5ST || spec->board_config == ALC880_5ST_DIG) {
- spec->five_stack = 1;
- spec->multiout.max_channels = 6;
- spec->channel_mode = fivestack_modes;
- } else {
- spec->multiout.max_channels = 2;
- spec->channel_mode = threestack_modes;
+
+ switch (board_config) {
+ case ALC880_5ST:
+ case ALC880_5ST_DIG:
+ spec->mixers[spec->num_mixers] = alc880_side_mixer;
+ spec->num_mixers++;
+ spec->init_verbs = alc880_init_verbs_five_stack;
+ spec->channel_mode = alc880_fivestack_modes;
+ spec->num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes);
+ break;
+ case ALC880_W810:
+ spec->init_verbs = alc880_w810_init_verbs;
+ spec->channel_mode = alc880_w810_modes;
+ spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes);
+ break;
+ default:
+ spec->init_verbs = alc880_init_verbs_three_stack;
+ spec->channel_mode = alc880_threestack_modes;
+ spec->num_channel_mode = ARRAY_SIZE(alc880_threestack_modes);
+ break;
}
- spec->multiout.num_dacs = 4;
- spec->multiout.dac_nids = alc880_dac_nids;
- spec->multiout.hp_nid = 0x03; /* rear-surround NID */
+ spec->stream_name_analog = "ALC880 Analog";
+ spec->stream_analog_playback = &alc880_pcm_analog_playback;
+ spec->stream_analog_capture = &alc880_pcm_analog_capture;
+
+ spec->stream_name_digital = "ALC880 Digital";
+ spec->stream_digital_playback = &alc880_pcm_digital_playback;
+ spec->stream_digital_capture = &alc880_pcm_digital_capture;
+
+ spec->multiout.max_channels = spec->channel_mode[0].channels;
+
+ switch (board_config) {
+ case ALC880_W810:
+ spec->multiout.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids);
+ spec->multiout.dac_nids = alc880_w810_dac_nids;
+ // No dedicated headphone socket - it's shared with built-in speakers.
+ break;
+ default:
+ spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids);
+ spec->multiout.dac_nids = alc880_dac_nids;
+ spec->multiout.hp_nid = 0x03; /* rear-surround NID */
+ break;
+ }
spec->input_mux = &alc880_capture_source;
spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
spec->adc_nids = alc880_adc_nids;
- codec->patch_ops = alc880_patch_ops;
+ codec->patch_ops = alc_patch_ops;
return 0;
}
-
/*
* ALC260 support
*/
+/*
+ * This is just place-holder, so there's something for alc_build_pcms to look
+ * at when it calculates the maximum number of channels. ALC260 has no mixer
+ * element which allows changing the channel mode, so the verb list is
+ * never used.
+ */
+static struct alc_channel_mode alc260_modes[1] = {
+ { 2, 0 },
+};
+
snd_kcontrol_new_t alc260_base_mixer[] = {
HDA_CODEC_VOLUME("PCM Playback Volume", 0x08, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("PCM Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
@@ -884,14 +1097,9 @@
.get = alc_mux_enum_get,
.put = alc_mux_enum_put,
},
+ { } /* end */
};
-static int alc260_build_controls(struct hda_codec *codec)
-{
- return snd_hda_add_new_ctls(codec, alc260_base_mixer,
- ARRAY_SIZE(alc260_base_mixer));
-}
-
static struct hda_verb alc260_init_verbs[] = {
/* Line In pin widget(nid=0x14) for input */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
@@ -930,21 +1138,6 @@
{ }
};
-static int alc260_init(struct hda_codec *codec)
-{
- snd_hda_sequence_write(codec, alc260_init_verbs);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int alc260_resume(struct hda_codec *codec, unsigned int state)
-{
- alc260_init(codec);
- snd_hda_resume_ctls(codec, alc260_base_mixer, ARRAY_SIZE(alc260_base_mixer));
- return 0;
-}
-#endif
-
static struct hda_pcm_stream alc260_pcm_analog_playback = {
.substreams = 1,
.channels_min = 2,
@@ -959,38 +1152,6 @@
.nid = 0x4,
};
-static int alc260_build_pcms(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
-
- codec->num_pcms = 1;
- codec->pcm_info = info;
-
- info->name = "ALC260 Analog";
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc260_pcm_analog_playback;
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = alc260_pcm_analog_capture;
-
- /* any boards with digital I/O ? */
-
- return 0;
-}
-
-static void alc260_free(struct hda_codec *codec)
-{
- kfree(codec->spec);
-}
-
-static struct hda_codec_ops alc260_patch_ops = {
- .build_controls = alc260_build_controls,
- .build_pcms = alc260_build_pcms,
- .init = alc260_init,
- .free = alc260_free,
-#ifdef CONFIG_PM
- .resume = alc260_resume,
-#endif
-};
-
static int patch_alc260(struct hda_codec *codec)
{
struct alc_spec *spec;
@@ -1000,13 +1161,27 @@
return -ENOMEM;
codec->spec = spec;
- spec->multiout.max_channels = 2;
+
+ spec->mixers[spec->num_mixers] = alc260_base_mixer;
+ spec->num_mixers++;
+
+ spec->init_verbs = alc260_init_verbs;
+ spec->channel_mode = alc260_modes;
+ spec->num_channel_mode = ARRAY_SIZE(alc260_modes);
+
+ spec->stream_name_analog = "ALC260 Analog";
+ spec->stream_analog_playback = &alc260_pcm_analog_playback;
+ spec->stream_analog_capture = &alc260_pcm_analog_capture;
+
+ spec->multiout.max_channels = spec->channel_mode[0].channels;
+ spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids);
+ spec->multiout.dac_nids = alc260_dac_nids;
spec->input_mux = &alc260_capture_source;
spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
spec->adc_nids = alc260_adc_nids;
- codec->patch_ops = alc260_patch_ops;
+ codec->patch_ops = alc_patch_ops;
return 0;
}
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] azx/realtek: Unify and parameterize code for ALC880/260 codecs, take 2
2004-12-16 21:11 [PATCH] azx/realtek: Unify and parameterize code for ALC880/260 codecs, take 2 Stephen Warren
@ 2004-12-17 14:18 ` Takashi Iwai
0 siblings, 0 replies; 2+ messages in thread
From: Takashi Iwai @ 2004-12-17 14:18 UTC (permalink / raw)
To: Stephen Warren; +Cc: alsa-devel
At Thu, 16 Dec 2004 13:11:06 -0800,
Stephen Warren wrote:
>
> This patch updates the HD-Audio ALC880/260 code driver such
> that all board-specific decisions are made in a single function,
> which sets variables that all other code simply uses directly
> without decision making.
>
> Also, tweak snd_hda_add_new_ctls and snd_hda_resume_ctls so they
> use a sentinel value in the array of controls, and hence don't have
> to be passed an explicit array-size argument.
>
> This has the benefits of:
>
> * Isolating board-specific code to a single location
> * Simplifying the rest of the code
> * Unifying the code for ALC880/ALC260, which was previously separate.
>
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> ---
>
> Note: This patch was generated by "cvs diff -u". Hopefully, that's a
> useful format - there are some extra lines of gunk that single-file
> regular "diff -u" doesn't generate...
Thanks for the patch. That's no problem. Patch is clever enough ;)
> This is an updated version of the patch I sent yesterday, that also
> tweaks the tweak snd_hda_add_new_ctls/snd_hda_resume_ctls API.
>
> For now, I think I'm done with generic changes to the AZX codec, so the
> patch is complete, unless you find any problems with it.
I applied to CVS now. Additionally, I put new comments about the
array termination for snd_hda_add_new_ctls() and
snd_hda_resume_ctls().
>
> I'm punting on making patch_alc880/260 use pre-initialized data
> structures for codec->spec for now - the code isn't too hairy yet, and
> it'll be something very easily added later on if we decide to do it.
This sounds nice.
Also, we can merge many codes between patch_realtek.c and
patch_cmedia.c. It would help for codecs from other vendors in
future.
Takashi
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2004-12-17 14:18 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-12-16 21:11 [PATCH] azx/realtek: Unify and parameterize code for ALC880/260 codecs, take 2 Stephen Warren
2004-12-17 14:18 ` Takashi Iwai
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.