CRYSTAL_VOICE,
        EFFECT_END_NID,
        OUTPUT_SOURCE_ENUM,
-       INPUT_SOURCE_ENUM
+       INPUT_SOURCE_ENUM,
+       XBASS_XOVER,
+       EQ_PRESET_ENUM,
+       SMART_VOLUME_ENUM,
+       MIC_BOOST_ENUM
 #define EFFECTS_COUNT  (EFFECT_END_NID - EFFECT_START_NID)
 };
 
 /* Effects values size*/
 #define EFFECT_VALS_MAX_COUNT 12
 
+/*
+ * Default values for the effect slider controls, they are in order of their
+ * effect NID's. Surround, Crystalizer, Dialog Plus, Smart Volume, and then
+ * X-bass.
+ */
+static const unsigned int effect_slider_defaults[] = {67, 65, 50, 74, 50};
+/* Amount of effect level sliders for ca0132_alt controls. */
+#define EFFECT_LEVEL_SLIDERS 5
+
 /* Latency introduced by DSP blocks in milliseconds. */
 #define DSP_CAPTURE_INIT_LATENCY        0
 #define DSP_CRYSTAL_VOICE_LATENCY       124
        }
 };
 
+/* ca0132 EQ presets, taken from Windows Sound Blaster Z Driver */
+
+#define EQ_PRESET_MAX_PARAM_COUNT 11
+
+struct ct_eq {
+       char *name;
+       hda_nid_t nid;
+       int mid;
+       int reqs[EQ_PRESET_MAX_PARAM_COUNT]; /*effect module request*/
+};
+
+struct ct_eq_preset {
+       char *name; /*preset name*/
+       unsigned int vals[EQ_PRESET_MAX_PARAM_COUNT];
+};
+
+static struct ct_eq ca0132_alt_eq_enum = {
+       .name = "FX: Equalizer Preset Switch",
+       .nid = EQ_PRESET_ENUM,
+       .mid = 0x96,
+       .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+};
+
+
+static struct ct_eq_preset ca0132_alt_eq_presets[] = {
+       { .name = "Flat",
+        .vals = { 0x00000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x00000000            }
+       },
+       { .name = "Acoustic",
+        .vals = { 0x00000000, 0x00000000, 0x3F8CCCCD,
+                  0x40000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x00000000, 0x40000000,
+                  0x40000000, 0x40000000            }
+       },
+       { .name = "Classical",
+        .vals = { 0x00000000, 0x00000000, 0x40C00000,
+                  0x40C00000, 0x40466666, 0x00000000,
+                  0x00000000, 0x00000000, 0x00000000,
+                  0x40466666, 0x40466666            }
+       },
+       { .name = "Country",
+        .vals = { 0x00000000, 0xBF99999A, 0x00000000,
+                  0x3FA66666, 0x3FA66666, 0x3F8CCCCD,
+                  0x00000000, 0x00000000, 0x40000000,
+                  0x40466666, 0x40800000            }
+       },
+       { .name = "Dance",
+        .vals = { 0x00000000, 0xBF99999A, 0x40000000,
+                  0x40466666, 0x40866666, 0xBF99999A,
+                  0xBF99999A, 0x00000000, 0x00000000,
+                  0x40800000, 0x40800000            }
+       },
+       { .name = "Jazz",
+        .vals = { 0x00000000, 0x00000000, 0x00000000,
+                  0x3F8CCCCD, 0x40800000, 0x40800000,
+                  0x40800000, 0x00000000, 0x3F8CCCCD,
+                  0x40466666, 0x40466666            }
+       },
+       { .name = "New Age",
+        .vals = { 0x00000000, 0x00000000, 0x40000000,
+                  0x40000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x3F8CCCCD, 0x40000000,
+                  0x40000000, 0x40000000            }
+       },
+       { .name = "Pop",
+        .vals = { 0x00000000, 0xBFCCCCCD, 0x00000000,
+                  0x40000000, 0x40000000, 0x00000000,
+                  0xBF99999A, 0xBF99999A, 0x00000000,
+                  0x40466666, 0x40C00000            }
+       },
+       { .name = "Rock",
+        .vals = { 0x00000000, 0xBF99999A, 0xBF99999A,
+                  0x3F8CCCCD, 0x40000000, 0xBF99999A,
+                  0xBF99999A, 0x00000000, 0x00000000,
+                  0x40800000, 0x40800000            }
+       },
+       { .name = "Vocal",
+        .vals = { 0x00000000, 0xC0000000, 0xBF99999A,
+                  0xBF99999A, 0x00000000, 0x40466666,
+                  0x40800000, 0x40466666, 0x00000000,
+                  0x00000000, 0x3F8CCCCD            }
+       }
+};
+
 /* DSP command sequences for ca0132_alt_select_out */
 #define ALT_OUT_SET_MAX_COMMANDS 9 /* Max number of commands in sequence */
 struct ca0132_alt_out_set {
        /* ca0132_alt control related values */
        unsigned char in_enum_val;
        unsigned char out_enum_val;
+       unsigned char mic_boost_enum_val;
+       unsigned char smart_volume_setting;
+       long fx_ctl_val[EFFECT_LEVEL_SLIDERS];
+       long xbass_xover_freq;
+       long eq_preset_val;
+       unsigned int tlv[4];
+       struct hda_vmaster_mute_hook vmaster_mute;
+
 
        struct hda_codec *codec;
        struct delayed_work unsol_hp_work;
         * surround sound support.
         */
        bool use_alt_functions;
+
+       /*
+        * Whether or not to use alt controls:  volume effect sliders, EQ
+        * presets, smart volume presets, and new control names with FX prefix.
+        * Renames PlayEnhancement and CrystalVoice too.
+        */
+       bool use_alt_controls;
 };
 
 /*
 0x40C00000, 0x40E00000, 0x41000000, 0x41100000
 };
 
+/*
+ * This table counts from float 0 to 1 in increments of .01, which is
+ * useful for a few different sliders.
+ */
+static const unsigned int float_zero_to_one_lookup[] = {
+0x00000000, 0x3C23D70A, 0x3CA3D70A, 0x3CF5C28F, 0x3D23D70A, 0x3D4CCCCD,
+0x3D75C28F, 0x3D8F5C29, 0x3DA3D70A, 0x3DB851EC, 0x3DCCCCCD, 0x3DE147AE,
+0x3DF5C28F, 0x3E051EB8, 0x3E0F5C29, 0x3E19999A, 0x3E23D70A, 0x3E2E147B,
+0x3E3851EC, 0x3E428F5C, 0x3E4CCCCD, 0x3E570A3D, 0x3E6147AE, 0x3E6B851F,
+0x3E75C28F, 0x3E800000, 0x3E851EB8, 0x3E8A3D71, 0x3E8F5C29, 0x3E947AE1,
+0x3E99999A, 0x3E9EB852, 0x3EA3D70A, 0x3EA8F5C3, 0x3EAE147B, 0x3EB33333,
+0x3EB851EC, 0x3EBD70A4, 0x3EC28F5C, 0x3EC7AE14, 0x3ECCCCCD, 0x3ED1EB85,
+0x3ED70A3D, 0x3EDC28F6, 0x3EE147AE, 0x3EE66666, 0x3EEB851F, 0x3EF0A3D7,
+0x3EF5C28F, 0x3EFAE148, 0x3F000000, 0x3F028F5C, 0x3F051EB8, 0x3F07AE14,
+0x3F0A3D71, 0x3F0CCCCD, 0x3F0F5C29, 0x3F11EB85, 0x3F147AE1, 0x3F170A3D,
+0x3F19999A, 0x3F1C28F6, 0x3F1EB852, 0x3F2147AE, 0x3F23D70A, 0x3F266666,
+0x3F28F5C3, 0x3F2B851F, 0x3F2E147B, 0x3F30A3D7, 0x3F333333, 0x3F35C28F,
+0x3F3851EC, 0x3F3AE148, 0x3F3D70A4, 0x3F400000, 0x3F428F5C, 0x3F451EB8,
+0x3F47AE14, 0x3F4A3D71, 0x3F4CCCCD, 0x3F4F5C29, 0x3F51EB85, 0x3F547AE1,
+0x3F570A3D, 0x3F59999A, 0x3F5C28F6, 0x3F5EB852, 0x3F6147AE, 0x3F63D70A,
+0x3F666666, 0x3F68F5C3, 0x3F6B851F, 0x3F6E147B, 0x3F70A3D7, 0x3F733333,
+0x3F75C28F, 0x3F7851EC, 0x3F7AE148, 0x3F7D70A4, 0x3F800000
+};
+
+/*
+ * This table counts from float 10 to 1000, which is the range of the x-bass
+ * crossover slider in Windows.
+ */
+static const unsigned int float_xbass_xover_lookup[] = {
+0x41200000, 0x41A00000, 0x41F00000, 0x42200000, 0x42480000, 0x42700000,
+0x428C0000, 0x42A00000, 0x42B40000, 0x42C80000, 0x42DC0000, 0x42F00000,
+0x43020000, 0x430C0000, 0x43160000, 0x43200000, 0x432A0000, 0x43340000,
+0x433E0000, 0x43480000, 0x43520000, 0x435C0000, 0x43660000, 0x43700000,
+0x437A0000, 0x43820000, 0x43870000, 0x438C0000, 0x43910000, 0x43960000,
+0x439B0000, 0x43A00000, 0x43A50000, 0x43AA0000, 0x43AF0000, 0x43B40000,
+0x43B90000, 0x43BE0000, 0x43C30000, 0x43C80000, 0x43CD0000, 0x43D20000,
+0x43D70000, 0x43DC0000, 0x43E10000, 0x43E60000, 0x43EB0000, 0x43F00000,
+0x43F50000, 0x43FA0000, 0x43FF0000, 0x44020000, 0x44048000, 0x44070000,
+0x44098000, 0x440C0000, 0x440E8000, 0x44110000, 0x44138000, 0x44160000,
+0x44188000, 0x441B0000, 0x441D8000, 0x44200000, 0x44228000, 0x44250000,
+0x44278000, 0x442A0000, 0x442C8000, 0x442F0000, 0x44318000, 0x44340000,
+0x44368000, 0x44390000, 0x443B8000, 0x443E0000, 0x44408000, 0x44430000,
+0x44458000, 0x44480000, 0x444A8000, 0x444D0000, 0x444F8000, 0x44520000,
+0x44548000, 0x44570000, 0x44598000, 0x445C0000, 0x445E8000, 0x44610000,
+0x44638000, 0x44660000, 0x44688000, 0x446B0000, 0x446D8000, 0x44700000,
+0x44728000, 0x44750000, 0x44778000, 0x447A0000
+};
+
 /* The following are for tuning of products */
 #ifdef ENABLE_TUNING_CONTROLS
 
 static void resume_mic1(struct hda_codec *codec, unsigned int oldval);
 static int stop_mic1(struct hda_codec *codec);
 static int ca0132_cvoice_switch_set(struct hda_codec *codec);
+static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val);
 
 /*
  * Select the active VIP source
                        chipio_write(codec, 0x18B098, 0x0000000C);
                        chipio_write(codec, 0x18B09C, 0x0000000C);
                }
+               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
                break;
        case REAR_LINE_IN:
                ca0132_mic_boost_set(codec, 0);
                        chipio_write(codec, 0x18B098, 0x0000000C);
                        chipio_write(codec, 0x18B09C, 0x000000CC);
                }
+               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
                break;
        }
        ca0132_cvoice_switch_set(codec);
        return ret;
 }
 
+static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int ret = 0;
+
+       ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
+                               HDA_INPUT, 0, HDA_AMP_VOLMASK, val);
+       return ret;
+}
+
 static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
        return ret;
 }
 /* End of control change helpers. */
+/*
+ * Below I've added controls to mess with the effect levels, I've only enabled
+ * them on the Sound Blaster Z, but they would probably also work on the
+ * Chromebook. I figured they were probably tuned specifically for it, and left
+ * out for a reason.
+ */
+
+/* Sets DSP effect level from the sliders above the controls */
+static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid,
+                         const unsigned int *lookup, int idx)
+{
+       int i = 0;
+       unsigned int y;
+       /*
+        * For X_BASS, req 2 is actually crossover freq instead of
+        * effect level
+        */
+       if (nid == X_BASS)
+               y = 2;
+       else
+               y = 1;
+
+       snd_hda_power_up(codec);
+       if (nid == XBASS_XOVER) {
+               for (i = 0; i < OUT_EFFECTS_COUNT; i++)
+                       if (ca0132_effects[i].nid == X_BASS)
+                               break;
+
+               dspio_set_param(codec, ca0132_effects[i].mid, 0x20,
+                               ca0132_effects[i].reqs[1],
+                               &(lookup[idx - 1]), sizeof(unsigned int));
+       } else {
+               /* Find the actual effect structure */
+               for (i = 0; i < OUT_EFFECTS_COUNT; i++)
+                       if (nid == ca0132_effects[i].nid)
+                               break;
+
+               dspio_set_param(codec, ca0132_effects[i].mid, 0x20,
+                               ca0132_effects[i].reqs[y],
+                               &(lookup[idx]), sizeof(unsigned int));
+       }
+
+       snd_hda_power_down(codec);
+
+       return 0;
+}
+
+static int ca0132_alt_xbass_xover_slider_ctl_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       long *valp = ucontrol->value.integer.value;
+
+       *valp = spec->xbass_xover_freq;
+       return 0;
+}
+
+static int ca0132_alt_slider_ctl_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx = nid - OUT_EFFECT_START_NID;
+
+       *valp = spec->fx_ctl_val[idx];
+       return 0;
+}
+
+/*
+ * The X-bass crossover starts at 10hz, so the min is 1. The
+ * frequency is set in multiples of 10.
+ */
+static int ca0132_alt_xbass_xover_slider_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 1;
+       uinfo->value.integer.max = 100;
+       uinfo->value.integer.step = 1;
+
+       return 0;
+}
+
+static int ca0132_alt_effect_slider_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       int chs = get_amp_channels(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = chs == 3 ? 2 : 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 100;
+       uinfo->value.integer.step = 1;
+
+       return 0;
+}
+
+static int ca0132_alt_xbass_xover_slider_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx;
+
+       /* any change? */
+       if (spec->xbass_xover_freq == *valp)
+               return 0;
+
+       spec->xbass_xover_freq = *valp;
+
+       idx = *valp;
+       ca0132_alt_slider_ctl_set(codec, nid, float_xbass_xover_lookup, idx);
+
+       return 0;
+}
+
+static int ca0132_alt_effect_slider_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx;
+
+       idx = nid - EFFECT_START_NID;
+       /* any change? */
+       if (spec->fx_ctl_val[idx] == *valp)
+               return 0;
+
+       spec->fx_ctl_val[idx] = *valp;
+
+       idx = *valp;
+       ca0132_alt_slider_ctl_set(codec, nid, float_zero_to_one_lookup, idx);
+
+       return 0;
+}
+
+
+/*
+ * Mic Boost Enum for alternative ca0132 codecs. I didn't like that the original
+ * only has off or full 30 dB, and didn't like making a volume slider that has
+ * traditional 0-100 in alsamixer that goes in big steps. I like enum better.
+ */
+#define MIC_BOOST_NUM_OF_STEPS 4
+#define MIC_BOOST_ENUM_MAX_STRLEN 10
+
+static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       char *sfx = "dB";
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = MIC_BOOST_NUM_OF_STEPS;
+       if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS)
+               uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1;
+       sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx);
+       strcpy(uinfo->value.enumerated.name, namestr);
+       return 0;
+}
+
+static int ca0132_alt_mic_boost_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->mic_boost_enum_val;
+       return 0;
+}
+
+static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = MIC_BOOST_NUM_OF_STEPS;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ca0132_alt_mic_boost: boost=%d\n",
+                   sel);
+
+       spec->mic_boost_enum_val = sel;
+
+       if (spec->in_enum_val != REAR_LINE_IN)
+               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
+
+       return 1;
+}
+
 
 /*
  * Input Select Control for alternative ca0132 codecs. This exists because
        return 1;
 }
 
+/*
+ * Smart Volume output setting control. Three different settings, Normal,
+ * which takes the value from the smart volume slider. The two others, loud
+ * and night, disregard the slider value and have uneditable values.
+ */
+#define NUM_OF_SVM_SETTINGS 3
+static const char *out_svm_set_enum_str[3] = {"Normal", "Loud", "Night" };
+
+static int ca0132_alt_svm_setting_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = NUM_OF_SVM_SETTINGS;
+       if (uinfo->value.enumerated.item >= NUM_OF_SVM_SETTINGS)
+               uinfo->value.enumerated.item = NUM_OF_SVM_SETTINGS - 1;
+       strcpy(uinfo->value.enumerated.name,
+                       out_svm_set_enum_str[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int ca0132_alt_svm_setting_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->smart_volume_setting;
+       return 0;
+}
+
+static int ca0132_alt_svm_setting_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = NUM_OF_SVM_SETTINGS;
+       unsigned int idx = SMART_VOLUME - EFFECT_START_NID;
+       unsigned int tmp;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ca0132_alt_svm_setting: sel=%d, preset=%s\n",
+                   sel, out_svm_set_enum_str[sel]);
+
+       spec->smart_volume_setting = sel;
+
+       switch (sel) {
+       case 0:
+               tmp = FLOAT_ZERO;
+               break;
+       case 1:
+               tmp = FLOAT_ONE;
+               break;
+       case 2:
+               tmp = FLOAT_TWO;
+               break;
+       default:
+               tmp = FLOAT_ZERO;
+               break;
+       }
+       /* Req 2 is the Smart Volume Setting req. */
+       dspio_set_uint_param(codec, ca0132_effects[idx].mid,
+                       ca0132_effects[idx].reqs[2], tmp);
+       return 1;
+}
+
+/* Sound Blaster Z EQ preset controls */
+static int ca0132_alt_eq_preset_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int items = sizeof(ca0132_alt_eq_presets)
+                               / sizeof(struct ct_eq_preset);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = items;
+       if (uinfo->value.enumerated.item >= items)
+               uinfo->value.enumerated.item = items - 1;
+       strcpy(uinfo->value.enumerated.name,
+               ca0132_alt_eq_presets[uinfo->value.enumerated.item].name);
+       return 0;
+}
+
+static int ca0132_alt_eq_preset_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->eq_preset_val;
+       return 0;
+}
+
+static int ca0132_alt_eq_preset_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int i, err = 0;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = sizeof(ca0132_alt_eq_presets)
+                               / sizeof(struct ct_eq_preset);
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "%s: sel=%d, preset=%s\n", __func__, sel,
+                       ca0132_alt_eq_presets[sel].name);
+       /*
+        * Idx 0 is default.
+        * Default needs to qualify with CrystalVoice state.
+        */
+       for (i = 0; i < EQ_PRESET_MAX_PARAM_COUNT; i++) {
+               err = dspio_set_uint_param(codec, ca0132_alt_eq_enum.mid,
+                               ca0132_alt_eq_enum.reqs[i],
+                               ca0132_alt_eq_presets[sel].vals[i]);
+               if (err < 0)
+                       break;
+       }
+
+       if (err >= 0)
+               spec->eq_preset_val = sel;
+
+       return 1;
+}
+
 static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_info *uinfo)
 {
        return err;
 }
 
+/* Add volume slider control for effect level */
+static int ca0132_alt_add_effect_slider(struct hda_codec *codec, hda_nid_t nid,
+                                       const char *pfx, int dir)
+{
+       char *fx = "FX:";
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       int type = dir ? HDA_INPUT : HDA_OUTPUT;
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
+
+       sprintf(namestr, "%s %s %s Volume", fx, pfx, dirstr[dir]);
+
+       knew.tlv.c = 0;
+       knew.tlv.p = 0;
+
+       switch (nid) {
+       case XBASS_XOVER:
+               knew.info = ca0132_alt_xbass_xover_slider_info;
+               knew.get = ca0132_alt_xbass_xover_slider_ctl_get;
+               knew.put = ca0132_alt_xbass_xover_slider_put;
+               break;
+       default:
+               knew.info = ca0132_alt_effect_slider_info;
+               knew.get = ca0132_alt_slider_ctl_get;
+               knew.put = ca0132_alt_effect_slider_put;
+               knew.private_value =
+                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, type);
+               break;
+       }
+
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Added FX: prefix for the alternative codecs, because otherwise the surround
+ * effect would conflict with the Surround sound volume control. Also seems more
+ * clear as to what the switches do. Left alone for others.
+ */
 static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
                         const char *pfx, int dir)
 {
+       struct ca0132_spec *spec = codec->spec;
+       char *fx = "FX:";
        char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int type = dir ? HDA_INPUT : HDA_OUTPUT;
        struct snd_kcontrol_new knew =
                CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type);
-       sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
+       /* If using alt_controls, add FX: prefix. But, don't add FX:
+        * prefix to OutFX or InFX enable controls.
+        */
+       if ((spec->use_alt_controls) && (nid <= IN_EFFECT_END_NID))
+               sprintf(namestr, "%s %s %s Switch", fx, pfx, dirstr[dir]);
+       else
+               sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
+
        return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
 }
 
        return snd_hda_ctl_add(codec, VOICEFX, snd_ctl_new1(&knew, codec));
 }
 
+/* Create the EQ Preset control */
+static int add_ca0132_alt_eq_presets(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO(ca0132_alt_eq_enum.name,
+                                   EQ_PRESET_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ca0132_alt_eq_preset_info;
+       knew.get = ca0132_alt_eq_preset_get;
+       knew.put = ca0132_alt_eq_preset_put;
+       return snd_hda_ctl_add(codec, EQ_PRESET_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Add enumerated control for the three different settings of the smart volume
+ * output effect. Normal just uses the slider value, and loud and night are
+ * their own things that ignore that value.
+ */
+static int ca0132_alt_add_svm_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("FX: Smart Volume Setting",
+                                   SMART_VOLUME_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ca0132_alt_svm_setting_info;
+       knew.get = ca0132_alt_svm_setting_get;
+       knew.put = ca0132_alt_svm_setting_put;
+       return snd_hda_ctl_add(codec, SMART_VOLUME_ENUM,
+                               snd_ctl_new1(&knew, codec));
+
+}
+
 /*
  * Create an Output Select enumerated control for codecs with surround
  * out capabilities.
                                snd_ctl_new1(&knew, codec));
 }
 
+/*
+ * Add mic boost enumerated control. Switches through 0dB to 30dB. This adds
+ * more control than the original mic boost, which is either full 30dB or off.
+ */
+static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("Mic Boost Capture Switch",
+                                   MIC_BOOST_ENUM, 1, 0, HDA_INPUT);
+       knew.info = ca0132_alt_mic_boost_info;
+       knew.get = ca0132_alt_mic_boost_get;
+       knew.put = ca0132_alt_mic_boost_put;
+       return snd_hda_ctl_add(codec, MIC_BOOST_ENUM,
+                               snd_ctl_new1(&knew, codec));
+
+}
+
+/*
+ * Need to create slave controls for the alternate codecs that have surround
+ * capabilities.
+ */
+static const char * const ca0132_alt_slave_pfxs[] = {
+       "Front", "Surround", "Center", "LFE", NULL,
+};
+
+/*
+ * Also need special channel map, because the default one is incorrect.
+ * I think this has to do with the pin for rear surround being 0x11,
+ * and the center/lfe being 0x10. Usually the pin order is the opposite.
+ */
+const struct snd_pcm_chmap_elem ca0132_alt_chmaps[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+       { .channels = 4,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { .channels = 6,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { }
+};
+
+/* Add the correct chmap for streams with 6 channels. */
+static void ca0132_alt_add_chmap_ctls(struct hda_codec *codec)
+{
+       int err = 0;
+       struct hda_pcm *pcm;
+
+       list_for_each_entry(pcm, &codec->pcm_list_head, list) {
+               struct hda_pcm_stream *hinfo =
+                       &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
+               struct snd_pcm_chmap *chmap;
+               const struct snd_pcm_chmap_elem *elem;
+
+               elem = ca0132_alt_chmaps;
+               if (hinfo->channels_max == 6) {
+                       err = snd_pcm_add_chmap_ctls(pcm->pcm,
+                                       SNDRV_PCM_STREAM_PLAYBACK,
+                                       elem, hinfo->channels_max, 0, &chmap);
+                       if (err < 0)
+                               codec_dbg(codec, "snd_pcm_add_chmap_ctls failed!");
+               }
+       }
+}
+
 /*
  * When changing Node IDs for Mixer Controls below, make sure to update
  * Node IDs in ca0132_config() as well.
 static struct snd_kcontrol_new sbz_mixer[] = {
        CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
        CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT),
        CA0132_ALT_CODEC_VOL("Capture Volume", 0x07, HDA_INPUT),
        CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
        HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
 static struct snd_kcontrol_new r3di_mixer[] = {
        CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
        CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT),
        CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT),
        CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
        HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
 static int ca0132_build_controls(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
-       int i, num_fx;
+       int i, num_fx, num_sliders;
        int err = 0;
 
        /* Add Mixer controls */
                if (err < 0)
                        return err;
        }
+       /* Setup vmaster with surround slaves for desktop ca0132 devices */
+       if (spec->use_alt_functions) {
+               snd_hda_set_vmaster_tlv(codec, spec->dacs[0], HDA_OUTPUT,
+                                       spec->tlv);
+               snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                       spec->tlv, ca0132_alt_slave_pfxs,
+                                       "Playback Volume");
+               err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                           NULL, ca0132_alt_slave_pfxs,
+                                           "Playback Switch",
+                                           true, &spec->vmaster_mute.sw_kctl);
+
+       }
 
        /* Add in and out effects controls.
         * VoiceFX, PE and CrystalVoice are added separately.
         */
        num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
        for (i = 0; i < num_fx; i++) {
+               /* SBZ breaks if Echo Cancellation is used */
+               if (spec->quirk == QUIRK_SBZ) {
+                       if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
+                                               OUT_EFFECTS_COUNT))
+                               continue;
+               }
+
                err = add_fx_switch(codec, ca0132_effects[i].nid,
                                    ca0132_effects[i].name,
                                    ca0132_effects[i].direct);
                if (err < 0)
                        return err;
        }
+       /*
+        * If codec has use_alt_controls set to true, add effect level sliders,
+        * EQ presets, and Smart Volume presets. Also, change names to add FX
+        * prefix, and change PlayEnhancement and CrystalVoice to match.
+        */
+       if (spec->use_alt_controls) {
+               ca0132_alt_add_svm_enum(codec);
+               add_ca0132_alt_eq_presets(codec);
+               err = add_fx_switch(codec, PLAY_ENHANCEMENT,
+                                       "Enable OutFX", 0);
+               if (err < 0)
+                       return err;
 
-       err = add_fx_switch(codec, PLAY_ENHANCEMENT, "PlayEnhancement", 0);
-       if (err < 0)
-               return err;
+               err = add_fx_switch(codec, CRYSTAL_VOICE,
+                                       "Enable InFX", 1);
+               if (err < 0)
+                       return err;
 
-       err = add_fx_switch(codec, CRYSTAL_VOICE, "CrystalVoice", 1);
-       if (err < 0)
-               return err;
+               num_sliders = OUT_EFFECTS_COUNT - 1;
+               for (i = 0; i < num_sliders; i++) {
+                       err = ca0132_alt_add_effect_slider(codec,
+                                           ca0132_effects[i].nid,
+                                           ca0132_effects[i].name,
+                                           ca0132_effects[i].direct);
+                       if (err < 0)
+                               return err;
+               }
+
+               err = ca0132_alt_add_effect_slider(codec, XBASS_XOVER,
+                                       "X-Bass Crossover", EFX_DIR_OUT);
+
+               if (err < 0)
+                       return err;
+       } else {
+               err = add_fx_switch(codec, PLAY_ENHANCEMENT,
+                                       "PlayEnhancement", 0);
+               if (err < 0)
+                       return err;
 
+               err = add_fx_switch(codec, CRYSTAL_VOICE,
+                                       "CrystalVoice", 1);
+               if (err < 0)
+                       return err;
+       }
        add_voicefx(codec);
 
        /*
        if (spec->use_alt_functions) {
                ca0132_alt_add_output_enum(codec);
                ca0132_alt_add_input_enum(codec);
+               ca0132_alt_add_mic_boost_enum(codec);
        }
 #ifdef ENABLE_TUNING_CONTROLS
        add_tuning_ctls(codec);
                if (err < 0)
                        return err;
        }
+
+       if (spec->use_alt_functions)
+               ca0132_alt_add_chmap_ctls(codec);
+
        return 0;
 }
 
        info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
        if (!info)
                return -ENOMEM;
+       if (spec->use_alt_functions) {
+               info->own_chmap = true;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap
+                       = ca0132_alt_chmaps;
+       }
        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
        info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
                on = (unsigned int)ca0132_effects[i].reqs[0];
                spec->effects_switch[i] = on ? 1 : 0;
        }
+       /*
+        * Sets defaults for the effect slider controls, only for alternative
+        * ca0132 codecs. Also sets x-bass crossover frequency to 80hz.
+        */
+       if (spec->use_alt_controls) {
+               spec->xbass_xover_freq = 8;
+               for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++)
+                       spec->fx_ctl_val[i] = effect_slider_defaults[i];
+       }
 
        spec->voicefx_val = 0;
        spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1;
                break;
        }
 
-       /* Setup whether or not to use alt functions */
+       /* Setup whether or not to use alt functions/controls */
        switch (spec->quirk) {
        case QUIRK_SBZ:
        case QUIRK_R3DI:
+               spec->use_alt_controls = true;
                spec->use_alt_functions = true;
                break;
        default:
+               spec->use_alt_controls = false;
                spec->use_alt_functions = false;
                break;
        }