diff options
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/ac97/ac97_codec.c | 16 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_pcm.c | 10 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 17 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 356 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.h | 10 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 4 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 198 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 35 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 1 | ||||
-rw-r--r-- | sound/pci/rme9652/hdspm.c | 382 |
11 files changed, 698 insertions, 332 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 8b0f99688303..d37c683cfd7a 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -299,7 +299,7 @@ EXPORT_SYMBOL(snd_ac97_write); * Reads a value from the given register. This will invoke the read * callback directly after the register check. * - * Returns the read value. + * Return: The read value. */ unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { @@ -352,7 +352,7 @@ EXPORT_SYMBOL(snd_ac97_write_cache); * Compares the value with the register cache and updates the value * only when the value is changed. * - * Returns 1 if the value is changed, 0 if no change, or a negative + * Return: 1 if the value is changed, 0 if no change, or a negative * code on failure. */ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value) @@ -384,7 +384,7 @@ EXPORT_SYMBOL(snd_ac97_update); * Updates the masked-bits on the given register only when the value * is changed. * - * Returns 1 if the bits are changed, 0 if no change, or a negative + * Return: 1 if the bits are changed, 0 if no change, or a negative * code on failure. */ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value) @@ -1836,7 +1836,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m * snd_ac97_get_short_name - retrieve codec name * @ac97: the codec instance * - * Returns the short identifying name of the codec. + * Return: The short identifying name of the codec. */ const char *snd_ac97_get_short_name(struct snd_ac97 *ac97) { @@ -1910,7 +1910,7 @@ static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem) * The AC97 bus instance is registered as a low-level device, so you don't * have to release it manually. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops, void *private_data, struct snd_ac97_bus **rbus) @@ -2006,7 +2006,7 @@ static void do_update_power(struct work_struct *work) * The ac97 instance is registered as a low-level device, so you don't * have to release it manually. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, struct snd_ac97 **rac97) { @@ -2373,6 +2373,8 @@ static struct ac97_power_reg power_regs[PWIDX_SIZE] = { * @powerup: non-zero when power up the part * * Update the AC97 powerdown register bits of the given part. + * + * Return: Zero. */ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) { @@ -2885,7 +2887,7 @@ static int apply_quirk_str(struct snd_ac97 *ac97, const char *typestr) * headphone (true line-out) control as "Master". * The quirk-list must be terminated with a zero-filled entry. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override) diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index f1488fc176d5..eab0fc9ff2e0 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c @@ -253,7 +253,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate) * AC97_SPDIF is accepted as a pseudo register to modify the SPDIF * status bits. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate) { @@ -440,6 +440,8 @@ static unsigned int get_rates(struct ac97_pcm *pcm, unsigned int cidx, unsigned * It assigns available AC97 slots for given PCMs. If none or only * some slots are available, pcm->xxx.slots and pcm->xxx.rslots[] members * are reduced and might be zero. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_assign(struct snd_ac97_bus *bus, unsigned short pcms_count, @@ -562,6 +564,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_assign); * @slots: a subset of allocated slots (snd_ac97_pcm_assign) for this pcm * * It locks the specified slots and sets the given rate to AC97 registers. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, enum ac97_pcm_cfg cfg, unsigned short slots) @@ -644,6 +648,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_open); * @pcm: the ac97 pcm instance * * It frees the locked AC97 slots. + * + * Return: Zero. */ int snd_ac97_pcm_close(struct ac97_pcm *pcm) { @@ -718,6 +724,8 @@ static int double_rate_hw_constraint_channels(struct snd_pcm_hw_params *params, * * Installs the hardware constraint rules to prevent using double rates and * more than two channels at the same time. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime) { diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a9ebcf9e3710..5868c61797bc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1300,8 +1300,6 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); -static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, - unsigned int power_state); /** * snd_hda_codec_new - create a HDA codec @@ -1422,7 +1420,6 @@ int snd_hda_codec_new(struct hda_bus *bus, #endif codec->epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); - codec->power_filter = default_power_filter; /* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); @@ -3770,8 +3767,9 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec, } /* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */ -static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, - unsigned int power_state) +unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) { if (power_state == AC_PWRST_D3 && get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN && @@ -3783,6 +3781,7 @@ static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, } return power_state; } +EXPORT_SYMBOL_HDA(snd_hda_codec_eapd_power_filter); /* * set power state of the codec, and return the power state @@ -3827,8 +3826,8 @@ static void sync_power_up_states(struct hda_codec *codec) hda_nid_t nid = codec->start_nid; int i; - /* don't care if no or standard filter is used */ - if (!codec->power_filter || codec->power_filter == default_power_filter) + /* don't care if no filter is used */ + if (!codec->power_filter) return; for (i = 0; i < codec->num_nodes; i++, nid++) { @@ -5546,14 +5545,12 @@ void *snd_array_new(struct snd_array *array) if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; int size = (num + 1) * array->elem_size; - int oldsize = array->alloced * array->elem_size; void *nlist; if (snd_BUG_ON(num >= 4096)) return NULL; - nlist = krealloc(array->list, size, GFP_KERNEL); + nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO); if (!nlist) return NULL; - memset(nlist + oldsize, 0, size - oldsize); array->list = nlist; array->alloced = num; } diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 78897d05d80f..aae6b1023d69 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -150,15 +150,25 @@ static void parse_user_hints(struct hda_codec *codec) val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input"); if (val >= 0) spec->add_stereo_mix_input = !!val; + /* the following two are just for compatibility */ val = snd_hda_get_bool_hint(codec, "add_out_jack_modes"); if (val >= 0) - spec->add_out_jack_modes = !!val; + spec->add_jack_modes = !!val; val = snd_hda_get_bool_hint(codec, "add_in_jack_modes"); if (val >= 0) - spec->add_in_jack_modes = !!val; + spec->add_jack_modes = !!val; + val = snd_hda_get_bool_hint(codec, "add_jack_modes"); + if (val >= 0) + spec->add_jack_modes = !!val; val = snd_hda_get_bool_hint(codec, "power_down_unused"); if (val >= 0) spec->power_down_unused = !!val; + val = snd_hda_get_bool_hint(codec, "add_hp_mic"); + if (val >= 0) + spec->hp_mic = !!val; + val = snd_hda_get_bool_hint(codec, "hp_mic_detect"); + if (val >= 0) + spec->suppress_hp_mic_detect = !val; if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) spec->mixer_nid = val; @@ -1880,6 +1890,17 @@ static int create_speaker_out_ctls(struct hda_codec *codec) * independent HP controls */ +/* update HP auto-mute state too */ +static void update_hp_automute_hook(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->hp_automute_hook) + spec->hp_automute_hook(codec, NULL); + else + snd_hda_gen_hp_automute(codec, NULL); +} + static int indep_hp_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1940,12 +1961,7 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol, else *dacp = spec->alt_dac_nid; - /* update HP auto-mute state too */ - if (spec->hp_automute_hook) - spec->hp_automute_hook(codec, NULL); - else - snd_hda_gen_hp_automute(codec, NULL); - + update_hp_automute_hook(codec); ret = 1; } unlock: @@ -2194,63 +2210,94 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) static void call_update_outputs(struct hda_codec *codec); /* for shared I/O, change the pin-control accordingly */ -static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) +static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force) { struct hda_gen_spec *spec = codec->spec; + bool as_mic; unsigned int val; - hda_nid_t pin = spec->autocfg.inputs[1].pin; - /* NOTE: this assumes that there are only two inputs, the - * first is the real internal mic and the second is HP/mic jack. - */ + hda_nid_t pin; - val = snd_hda_get_default_vref(codec, pin); + pin = spec->hp_mic_pin; + as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx; - /* This pin does not have vref caps - let's enable vref on pin 0x18 - instead, as suggested by Realtek */ + if (!force) { + val = snd_hda_codec_get_pin_target(codec, pin); + if (as_mic) { + if (val & PIN_IN) + return; + } else { + if (val & PIN_OUT) + return; + } + } + + val = snd_hda_get_default_vref(codec, pin); + /* if the HP pin doesn't support VREF and the codec driver gives an + * alternative pin, set up the VREF on that pin instead + */ if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { const hda_nid_t vref_pin = spec->shared_mic_vref_pin; unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); if (vref_val != AC_PINCTL_VREF_HIZ) snd_hda_set_pin_ctl_cache(codec, vref_pin, - PIN_IN | (set_as_mic ? vref_val : 0)); + PIN_IN | (as_mic ? vref_val : 0)); } - val = set_as_mic ? val | PIN_IN : PIN_HP; - set_pin_target(codec, pin, val, true); - - spec->automute_speaker = !set_as_mic; - call_update_outputs(codec); + if (!spec->hp_mic_jack_modes) { + if (as_mic) + val |= PIN_IN; + else + val = PIN_HP; + set_pin_target(codec, pin, val, true); + update_hp_automute_hook(codec); + } } /* create a shared input with the headphone out */ -static int create_shared_input(struct hda_codec *codec) +static int create_hp_mic(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int defcfg; hda_nid_t nid; - /* only one internal input pin? */ - if (cfg->num_inputs != 1) - return 0; - defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); - if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) + if (!spec->hp_mic) { + if (spec->suppress_hp_mic_detect) + return 0; + /* automatic detection: only if no input or a single internal + * input pin is found, try to detect the shared hp/mic + */ + if (cfg->num_inputs > 1) + return 0; + else if (cfg->num_inputs == 1) { + defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); + if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) + return 0; + } + } + + spec->hp_mic = 0; /* clear once */ + if (cfg->num_inputs >= AUTO_CFG_MAX_INS) return 0; - if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ - else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) - nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ - else - return 0; /* both not available */ + nid = 0; + if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0) + nid = cfg->line_out_pins[0]; + else if (cfg->hp_outs > 0) + nid = cfg->hp_pins[0]; + if (!nid) + return 0; if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) return 0; /* no input */ - cfg->inputs[1].pin = nid; - cfg->inputs[1].type = AUTO_PIN_MIC; - cfg->num_inputs = 2; - spec->shared_mic_hp = 1; + cfg->inputs[cfg->num_inputs].pin = nid; + cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC; + cfg->num_inputs++; + spec->hp_mic = 1; + spec->hp_mic_pin = nid; + /* we can't handle auto-mic together with HP-mic */ + spec->suppress_auto_mic = 1; snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); return 0; } @@ -2258,13 +2305,17 @@ static int create_shared_input(struct hda_codec *codec) /* * output jack mode */ + +static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin); + +static const char * const out_jack_texts[] = { + "Line Out", "Headphone Out", +}; + static int out_jack_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { - "Line Out", "Headphone Out", - }; - return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts); + return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts); } static int out_jack_mode_get(struct snd_kcontrol *kcontrol, @@ -2326,6 +2377,17 @@ static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, ; } +static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->add_jack_modes) { + unsigned int pincap = snd_hda_query_pin_caps(codec, pin); + if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) + return 2; + } + return 1; +} + static int create_out_jack_modes(struct hda_codec *codec, int num_pins, hda_nid_t *pins) { @@ -2334,8 +2396,13 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins, for (i = 0; i < num_pins; i++) { hda_nid_t pin = pins[i]; - unsigned int pincap = snd_hda_query_pin_caps(codec, pin); - if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) { + if (pin == spec->hp_mic_pin) { + int ret = create_hp_mic_jack_mode(codec, pin); + if (ret < 0) + return ret; + continue; + } + if (get_out_jack_num_items(codec, pin) > 1) { struct snd_kcontrol_new *knew; char name[44]; get_jack_mode_name(codec, pin, name, sizeof(name)); @@ -2456,12 +2523,24 @@ static const struct snd_kcontrol_new in_jack_mode_enum = { .put = in_jack_mode_put, }; +static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + int nitems = 0; + if (spec->add_jack_modes) + nitems = hweight32(get_vref_caps(codec, pin)); + return nitems ? nitems : 1; +} + static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) { struct hda_gen_spec *spec = codec->spec; - unsigned int defcfg; struct snd_kcontrol_new *knew; char name[44]; + unsigned int defcfg; + + if (pin == spec->hp_mic_pin) + return 0; /* already done in create_out_jack_mode() */ /* no jack mode for fixed pins */ defcfg = snd_hda_codec_get_pincfg(codec, pin); @@ -2469,7 +2548,7 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) return 0; /* no multiple vref caps? */ - if (hweight32(get_vref_caps(codec, pin)) <= 1) + if (get_in_jack_num_items(codec, pin) <= 1) return 0; get_jack_mode_name(codec, pin, name, sizeof(name)); @@ -2480,6 +2559,132 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) return 0; } +/* + * HP/mic shared jack mode + */ +static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + const char *text = NULL; + int idx; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = out_jacks + in_jacks; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + idx = uinfo->value.enumerated.item; + if (idx < out_jacks) { + if (out_jacks > 1) + text = out_jack_texts[idx]; + else + text = "Headphone Out"; + } else { + idx -= out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + text = vref_texts[get_vref_idx(vref_caps, idx)]; + } else + text = "Mic In"; + } + + strcpy(uinfo->value.enumerated.name, text); + return 0; +} + +static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid) +{ + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + unsigned int val = snd_hda_codec_get_pin_target(codec, nid); + int idx = 0; + + if (val & PIN_OUT) { + if (out_jacks > 1 && val == PIN_HP) + idx = 1; + } else if (val & PIN_IN) { + idx = out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + val &= AC_PINCTL_VREFEN; + idx += cvt_from_vref_idx(vref_caps, val); + } + } + return idx; +} + +static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + ucontrol->value.enumerated.item[0] = + get_cur_hp_mic_jack_mode(codec, nid); + return 0; +} + +static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + unsigned int val, oldval, idx; + + oldval = get_cur_hp_mic_jack_mode(codec, nid); + idx = ucontrol->value.enumerated.item[0]; + if (oldval == idx) + return 0; + + if (idx < out_jacks) { + if (out_jacks > 1) + val = idx ? PIN_HP : PIN_OUT; + else + val = PIN_HP; + } else { + idx -= out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + val = snd_hda_codec_get_pin_target(codec, nid); + val &= ~(AC_PINCTL_VREFEN | PIN_HP); + val |= get_vref_idx(vref_caps, idx) | PIN_IN; + } else + val = snd_hda_get_default_vref(codec, nid); + } + snd_hda_set_pin_ctl_cache(codec, nid, val); + update_hp_automute_hook(codec); + + return 1; +} + +static const struct snd_kcontrol_new hp_mic_jack_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = hp_mic_jack_mode_info, + .get = hp_mic_jack_mode_get, + .put = hp_mic_jack_mode_put, +}; + +static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + + if (get_out_jack_num_items(codec, pin) <= 1 && + get_in_jack_num_items(codec, pin) <= 1) + return 0; /* no need */ + knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode", + &hp_mic_jack_mode_enum); + if (!knew) + return -ENOMEM; + knew->private_value = pin; + spec->hp_mic_jack_modes = 1; + return 0; +} /* * Parse input paths @@ -2602,7 +2807,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec) unsigned int ok_bits; int i, n, nums; - again: nums = 0; ok_bits = 0; for (n = 0; n < spec->num_adc_nids; n++) { @@ -2617,12 +2821,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec) } if (!ok_bits) { - if (spec->shared_mic_hp) { - spec->shared_mic_hp = 0; - imux->num_items = 1; - goto again; - } - /* check whether ADC-switch is possible */ for (i = 0; i < imux->num_items; i++) { for (n = 0; n < spec->num_adc_nids; n++) { @@ -2655,7 +2853,8 @@ static int check_dyn_adc_switch(struct hda_codec *codec) spec->num_adc_nids = nums; } - if (imux->num_items == 1 || spec->shared_mic_hp) { + if (imux->num_items == 1 || + (imux->num_items == 2 && spec->hp_mic)) { snd_printdd("hda-codec: reducing to a single ADC\n"); spec->num_adc_nids = 1; /* reduce to a single ADC */ } @@ -2692,6 +2891,8 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, snd_hda_get_path_idx(codec, path); if (!imux_added) { + if (spec->hp_mic_pin == pin) + spec->hp_mic_mux_idx = imux->num_items; spec->imux_pins[imux->num_items] = pin; snd_hda_add_imux_item(imux, label, cfg_idx, NULL); imux_added = true; @@ -2766,7 +2967,8 @@ static int create_input_ctls(struct hda_codec *codec) val = PIN_IN; if (cfg->inputs[i].type == AUTO_PIN_MIC) val |= snd_hda_get_default_vref(codec, pin); - set_pin_target(codec, pin, val, false); + if (pin != spec->hp_mic_pin) + set_pin_target(codec, pin, val, false); if (mixer) { if (is_reachable_path(codec, pin, mixer)) { @@ -2784,7 +2986,7 @@ static int create_input_ctls(struct hda_codec *codec) if (err < 0) return err; - if (spec->add_in_jack_modes) { + if (spec->add_jack_modes) { err = create_in_jack_mode(codec, pin); if (err < 0) return err; @@ -3416,8 +3618,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx, spec->cur_mux[adc_idx] = idx; - if (spec->shared_mic_hp) - update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); + if (spec->hp_mic) + update_hp_mic(codec, adc_idx, false); if (spec->dyn_adc_switch) dyn_adc_pcm_resetup(codec, idx); @@ -3465,18 +3667,21 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, for (i = 0; i < num_pins; i++) { hda_nid_t nid = pins[i]; - unsigned int val; + unsigned int val, oldval; if (!nid) break; + oldval = snd_hda_codec_get_pin_target(codec, nid); + if (oldval & PIN_IN) + continue; /* no mute for inputs */ /* don't reset VREF value in case it's controlling * the amp (see alc861_fixup_asus_amp_vref_0f()) */ if (spec->keep_vref_in_automute) - val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP; + val = oldval & ~PIN_HP; else val = 0; if (!mute) - val |= snd_hda_codec_get_pin_target(codec, nid); + val |= oldval; /* here we call update_pin_ctl() so that the pinctl is changed * without changing the pinctl target value; * the original target value will be still referred at the @@ -3497,8 +3702,7 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec) * in general, HP pins/amps control should be enabled in all cases, * but currently set only for master_mute, just to be safe */ - if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ - do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), + do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), spec->autocfg.hp_pins, spec->master_mute); if (!spec->automute_speaker) @@ -3603,10 +3807,7 @@ static void update_automute_all(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; - if (spec->hp_automute_hook) - spec->hp_automute_hook(codec, NULL); - else - snd_hda_gen_hp_automute(codec, NULL); + update_hp_automute_hook(codec); if (spec->line_automute_hook) spec->line_automute_hook(codec, NULL); else @@ -3978,7 +4179,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, err = create_loopback_mixing_ctl(codec); if (err < 0) return err; - err = create_shared_input(codec); + err = create_hp_mic(codec); if (err < 0) return err; err = create_input_ctls(codec); @@ -4004,11 +4205,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, if (err < 0) return err; - if (!spec->shared_mic_hp) { - err = check_auto_mic_availability(codec); - if (err < 0) - return err; - } + err = check_auto_mic_availability(codec); + if (err < 0) + return err; err = create_capture_mixers(codec); if (err < 0) @@ -4018,7 +4217,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, if (err < 0) return err; - if (spec->add_out_jack_modes) { + if (spec->add_jack_modes) { if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { err = create_out_jack_modes(codec, cfg->line_outs, cfg->line_out_pins); @@ -4115,9 +4314,9 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) free_kctls(spec); /* no longer needed */ - if (spec->shared_mic_hp) { + if (spec->hp_mic_pin) { int err; - int nid = spec->autocfg.inputs[1].pin; + int nid = spec->hp_mic_pin; err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); if (err < 0) return err; @@ -4780,11 +4979,10 @@ static void init_input_src(struct hda_codec *codec) snd_hda_activate_path(codec, path, active, false); } } + if (spec->hp_mic) + update_hp_mic(codec, c, true); } - if (spec->shared_mic_hp) - update_shared_mic_hp(codec, spec->cur_mux[0]); - if (spec->cap_sync_hook) spec->cap_sync_hook(codec, NULL); } diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 009b57be96d3..094e6af7a107 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -145,7 +145,10 @@ struct hda_gen_spec { hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; + /* shared hp/mic */ hda_nid_t shared_mic_vref_pin; + hda_nid_t hp_mic_pin; + int hp_mic_mux_idx; /* DAC/ADC lists */ int num_all_dacs; @@ -200,7 +203,8 @@ struct hda_gen_spec { /* other parse behavior flags */ unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */ - unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ + unsigned int hp_mic:1; /* Allow HP as a mic-in */ + unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */ unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ @@ -209,8 +213,7 @@ struct hda_gen_spec { unsigned int indep_hp:1; /* independent HP supported */ unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */ unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */ - unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */ - unsigned int add_in_jack_modes:1; /* add input jack mode enum ctls */ + unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */ unsigned int power_down_unused:1; /* power down unused widgets */ /* other internal flags */ @@ -218,6 +221,7 @@ struct hda_gen_spec { unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */ unsigned int indep_hp_enabled:1; /* independent HP enabled */ unsigned int have_aamix_ctl:1; + unsigned int hp_mic_jack_modes:1; /* loopback mixing mode */ bool aamix_mode; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 83b7486c8eff..e0bf7534fa1f 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -670,6 +670,10 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid, return (state != target_state); } +unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state); + /* * AMP control callbacks */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 2a89d1eefeb6..d0100a85e189 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3356,7 +3356,6 @@ static int patch_conexant_auto(struct hda_codec *codec) switch (codec->vendor_id) { case 0x14f15045: codec->single_adc_amp = 1; - codec->power_filter = NULL; /* Needs speaker amp to D3 to avoid click */ break; case 0x14f15047: codec->pin_amp_workaround = 1; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 78e1827d0a95..3e1159dd98c3 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -44,16 +44,6 @@ static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); -/* - * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device - * could support N independent pipes, each of them can be connected to one or - * more ports (DVI, HDMI or DisplayPort). - * - * The HDA correspondence of pipes/ports are converter/pin nodes. - */ -#define MAX_HDMI_CVTS 8 -#define MAX_HDMI_PINS 8 - struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; int assigned; @@ -80,16 +70,17 @@ struct hdmi_spec_per_pin { bool non_pcm; bool chmap_set; /* channel-map override by ALSA API? */ unsigned char chmap[8]; /* ALSA API channel-map */ + char pcm_name[8]; /* filled in build_pcm callbacks */ }; struct hdmi_spec { int num_cvts; - struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS]; - hda_nid_t cvt_nids[MAX_HDMI_CVTS]; + struct snd_array cvts; /* struct hdmi_spec_per_cvt */ + hda_nid_t cvt_nids[4]; /* only for haswell fix */ int num_pins; - struct hdmi_spec_per_pin pins[MAX_HDMI_PINS]; - struct hda_pcm pcm_rec[MAX_HDMI_PINS]; + struct snd_array pins; /* struct hdmi_spec_per_pin */ + struct snd_array pcm_rec; /* struct hda_pcm */ unsigned int channels_max; /* max over all cvts */ struct hdmi_eld temp_eld; @@ -304,12 +295,19 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { * HDMI routines */ +#define get_pin(spec, idx) \ + ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx)) +#define get_cvt(spec, idx) \ + ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx)) +#define get_pcm_rec(spec, idx) \ + ((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx)) + static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid) { int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) - if (spec->pins[pin_idx].pin_nid == pin_nid) + if (get_pin(spec, pin_idx)->pin_nid == pin_nid) return pin_idx; snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid); @@ -322,7 +320,7 @@ static int hinfo_to_pin_index(struct hdmi_spec *spec, int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) - if (&spec->pcm_rec[pin_idx].stream[0] == hinfo) + if (get_pcm_rec(spec, pin_idx)->stream == hinfo) return pin_idx; snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo); @@ -334,7 +332,7 @@ static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid) int cvt_idx; for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) - if (spec->cvts[cvt_idx].cvt_nid == cvt_nid) + if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid) return cvt_idx; snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid); @@ -352,7 +350,7 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; pin_idx = kcontrol->private_value; - eld = &spec->pins[pin_idx].sink_eld; + eld = &get_pin(spec, pin_idx)->sink_eld; mutex_lock(&eld->lock); uinfo->count = eld->eld_valid ? eld->eld_size : 0; @@ -370,7 +368,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, int pin_idx; pin_idx = kcontrol->private_value; - eld = &spec->pins[pin_idx].sink_eld; + eld = &get_pin(spec, pin_idx)->sink_eld; mutex_lock(&eld->lock); if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) { @@ -410,11 +408,11 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx, kctl->private_value = pin_idx; kctl->id.device = device; - err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl); + err = snd_hda_ctl_add(codec, get_pin(spec, pin_idx)->pin_nid, kctl); if (err < 0) return err; - spec->pins[pin_idx].eld_ctl = kctl; + get_pin(spec, pin_idx)->eld_ctl = kctl; return 0; } @@ -875,14 +873,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; int channels = substream->runtime->channels; struct hdmi_eld *eld; int ca; union audio_infoframe ai; - eld = &spec->pins[pin_idx].sink_eld; + eld = &per_pin->sink_eld; if (!eld->monitor_present) return; @@ -977,7 +975,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) if (pin_idx < 0) return; - hdmi_present_sense(&spec->pins[pin_idx], 1); + hdmi_present_sense(get_pin(spec, pin_idx), 1); snd_hda_jack_report_sync(codec); } @@ -1083,12 +1081,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, pin_idx = hinfo_to_pin_index(spec, hinfo); if (snd_BUG_ON(pin_idx < 0)) return -EINVAL; - per_pin = &spec->pins[pin_idx]; + per_pin = get_pin(spec, pin_idx); eld = &per_pin->sink_eld; /* Dynamically assign converter to stream */ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { - per_cvt = &spec->cvts[cvt_idx]; + per_cvt = get_cvt(spec, cvt_idx); /* Must not already be assigned */ if (per_cvt->assigned) @@ -1151,7 +1149,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) { struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { @@ -1275,14 +1273,13 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) return 0; - if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS)) - return -E2BIG; - if (codec->vendor_id == 0x80862807) intel_haswell_fixup_connect_list(codec, pin_nid); pin_idx = spec->num_pins; - per_pin = &spec->pins[pin_idx]; + per_pin = snd_array_new(&spec->pins); + if (!per_pin) + return -ENOMEM; per_pin->pin_nid = pin_nid; per_pin->non_pcm = false; @@ -1299,19 +1296,16 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) { struct hdmi_spec *spec = codec->spec; - int cvt_idx; struct hdmi_spec_per_cvt *per_cvt; unsigned int chans; int err; - if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) - return -E2BIG; - chans = get_wcaps(codec, cvt_nid); chans = get_wcaps_channels(chans); - cvt_idx = spec->num_cvts; - per_cvt = &spec->cvts[cvt_idx]; + per_cvt = snd_array_new(&spec->cvts); + if (!per_cvt) + return -ENOMEM; per_cvt->cvt_nid = cvt_nid; per_cvt->channels_min = 2; @@ -1328,7 +1322,9 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) if (err < 0) return err; - spec->cvt_nids[spec->num_cvts++] = cvt_nid; + if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids)) + spec->cvt_nids[spec->num_cvts] = cvt_nid; + spec->num_cvts++; return 0; } @@ -1384,13 +1380,6 @@ static int hdmi_parse_codec(struct hda_codec *codec) /* */ -static char *get_hdmi_pcm_name(int idx) -{ - static char names[MAX_HDMI_PINS][8]; - sprintf(&names[idx][0], "HDMI %d", idx); - return &names[idx][0]; -} - static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) { struct hda_spdif_out *spdif; @@ -1417,7 +1406,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hda_nid_t cvt_nid = hinfo->nid; struct hdmi_spec *spec = codec->spec; int pin_idx = hinfo_to_pin_index(spec, hinfo); - hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; + hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid; bool non_pcm; non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); @@ -1450,7 +1439,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); if (snd_BUG_ON(cvt_idx < 0)) return -EINVAL; - per_cvt = &spec->cvts[cvt_idx]; + per_cvt = get_cvt(spec, cvt_idx); snd_BUG_ON(!per_cvt->assigned); per_cvt->assigned = 0; @@ -1459,7 +1448,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, pin_idx = hinfo_to_pin_index(spec, hinfo); if (snd_BUG_ON(pin_idx < 0)) return -EINVAL; - per_pin = &spec->pins[pin_idx]; + per_pin = get_pin(spec, pin_idx); snd_hda_spdif_ctls_unassign(codec, pin_idx); per_pin->chmap_set = false; @@ -1553,7 +1542,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; int pin_idx = kcontrol->private_value; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); int i; for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++) @@ -1568,7 +1557,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; int pin_idx = kcontrol->private_value; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); unsigned int ctl_idx; struct snd_pcm_substream *substream; unsigned char chmap[8]; @@ -1613,9 +1602,14 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hda_pcm *info; struct hda_pcm_stream *pstr; - - info = &spec->pcm_rec[pin_idx]; - info->name = get_hdmi_pcm_name(pin_idx); + struct hdmi_spec_per_pin *per_pin; + + per_pin = get_pin(spec, pin_idx); + sprintf(per_pin->pcm_name, "HDMI %d", pin_idx); + info = snd_array_new(&spec->pcm_rec); + if (!info) + return -ENOMEM; + info->name = per_pin->pcm_name; info->pcm_type = HDA_PCM_TYPE_HDMI; info->own_chmap = true; @@ -1626,7 +1620,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) } codec->num_pcms = spec->num_pins; - codec->pcm_info = spec->pcm_rec; + codec->pcm_info = spec->pcm_rec.list; return 0; } @@ -1635,8 +1629,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) { char hdmi_str[32] = "HDMI/DP"; struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - int pcmdev = spec->pcm_rec[pin_idx].device; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + int pcmdev = get_pcm_rec(spec, pin_idx)->device; if (pcmdev > 0) sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); @@ -1654,7 +1648,7 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); err = generic_hdmi_build_jack(codec, pin_idx); if (err < 0) @@ -1669,9 +1663,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) snd_hda_spdif_ctls_unassign(codec, pin_idx); /* add control for ELD Bytes */ - err = hdmi_create_eld_ctl(codec, - pin_idx, - spec->pcm_rec[pin_idx].device); + err = hdmi_create_eld_ctl(codec, pin_idx, + get_pcm_rec(spec, pin_idx)->device); if (err < 0) return err; @@ -1709,7 +1702,7 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec) int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); struct hdmi_eld *eld = &per_pin->sink_eld; per_pin->codec = codec; @@ -1726,7 +1719,7 @@ static int generic_hdmi_init(struct hda_codec *codec) int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; hdmi_init_pin(codec, pin_nid); @@ -1735,13 +1728,27 @@ static int generic_hdmi_init(struct hda_codec *codec) return 0; } +static void hdmi_array_init(struct hdmi_spec *spec, int nums) +{ + snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums); + snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums); + snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums); +} + +static void hdmi_array_free(struct hdmi_spec *spec) +{ + snd_array_free(&spec->pins); + snd_array_free(&spec->cvts); + snd_array_free(&spec->pcm_rec); +} + static void generic_hdmi_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); struct hdmi_eld *eld = &per_pin->sink_eld; cancel_delayed_work(&per_pin->work); @@ -1749,6 +1756,7 @@ static void generic_hdmi_free(struct hda_codec *codec) } flush_workqueue(codec->bus->workq); + hdmi_array_free(spec); kfree(spec); } @@ -1775,6 +1783,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec, /* override pins connection list */ snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid); + nconns = max(spec->num_cvts, 4); snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids); } @@ -1855,6 +1864,7 @@ static int patch_generic_hdmi(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; + hdmi_array_init(spec, 4); snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -1882,24 +1892,30 @@ static int patch_generic_hdmi(struct hda_codec *codec) static int simple_playback_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; + struct hda_pcm *info; unsigned int chans; struct hda_pcm_stream *pstr; + struct hdmi_spec_per_cvt *per_cvt; - codec->num_pcms = 1; - codec->pcm_info = info; - - chans = get_wcaps(codec, spec->cvts[0].cvt_nid); + per_cvt = get_cvt(spec, 0); + chans = get_wcaps(codec, per_cvt->cvt_nid); chans = get_wcaps_channels(chans); - info->name = get_hdmi_pcm_name(0); + info = snd_array_new(&spec->pcm_rec); + if (!info) + return -ENOMEM; + info->name = get_pin(spec, 0)->pcm_name; + sprintf(info->name, "HDMI 0"); info->pcm_type = HDA_PCM_TYPE_HDMI; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; *pstr = spec->pcm_playback; - pstr->nid = spec->cvts[0].cvt_nid; + pstr->nid = per_cvt->cvt_nid; if (pstr->channels_max <= 2 && chans && chans <= 16) pstr->channels_max = chans; + codec->num_pcms = 1; + codec->pcm_info = info; + return 0; } @@ -1919,11 +1935,12 @@ static void simple_hdmi_unsol_event(struct hda_codec *codec, static int simple_playback_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt; int err; - err = snd_hda_create_spdif_out_ctls(codec, - spec->cvts[0].cvt_nid, - spec->cvts[0].cvt_nid); + per_cvt = get_cvt(spec, 0); + err = snd_hda_create_spdif_out_ctls(codec, per_cvt->cvt_nid, + per_cvt->cvt_nid); if (err < 0) return err; return simple_hdmi_build_jack(codec, 0); @@ -1932,7 +1949,8 @@ static int simple_playback_build_controls(struct hda_codec *codec) static int simple_playback_init(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - hda_nid_t pin = spec->pins[0].pin_nid; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0); + hda_nid_t pin = per_pin->pin_nid; snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); @@ -1948,6 +1966,7 @@ static void simple_playback_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; + hdmi_array_free(spec); kfree(spec); } @@ -2111,20 +2130,29 @@ static int patch_simple_hdmi(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid) { struct hdmi_spec *spec; + struct hdmi_spec_per_cvt *per_cvt; + struct hdmi_spec_per_pin *per_pin; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; codec->spec = spec; + hdmi_array_init(spec, 1); spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = cvt_nid; spec->num_cvts = 1; spec->num_pins = 1; - spec->cvts[0].cvt_nid = cvt_nid; - spec->pins[0].pin_nid = pin_nid; + per_pin = snd_array_new(&spec->pins); + per_cvt = snd_array_new(&spec->cvts); + if (!per_pin || !per_cvt) { + simple_playback_free(codec); + return -ENOMEM; + } + per_cvt->cvt_nid = cvt_nid; + per_pin->pin_nid = pin_nid; spec->pcm_playback = simple_pcm_playback; codec->patch_ops = simple_hdmi_patch_ops; @@ -2201,9 +2229,11 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, int i; struct hdmi_spec *spec = codec->spec; struct hda_spdif_out *spdif; + struct hdmi_spec_per_cvt *per_cvt; mutex_lock(&codec->spdif_mutex); - spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid); + per_cvt = get_cvt(spec, 0); + spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid); chs = substream->runtime->channels; @@ -2325,13 +2355,17 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int err = simple_playback_build_pcms(codec); - spec->pcm_rec[0].own_chmap = true; + if (!err) { + struct hda_pcm *info = get_pcm_rec(spec, 0); + info->own_chmap = true; + } return err; } static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info; struct snd_pcm_chmap *chmap; int err; @@ -2340,7 +2374,8 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) return err; /* add channel maps */ - err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm, + info = get_pcm_rec(spec, 0); + err = snd_pcm_add_chmap_ctls(info->pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_alt_chmaps, 8, 0, &chmap); if (err < 0) @@ -2395,6 +2430,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt = get_cvt(spec, 0); int chans = substream->runtime->channels; int i, err; @@ -2402,11 +2438,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, substream); if (err < 0) return err; - snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, + snd_hda_codec_write(codec, per_cvt->cvt_nid, 0, AC_VERB_SET_CVT_CHAN_COUNT, chans - 1); /* FIXME: XXX */ for (i = 0; i < chans; i++) { - snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, + snd_hda_codec_write(codec, per_cvt->cvt_nid, 0, AC_VERB_SET_HDMI_CHAN_SLOT, (i << 4) | i); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 563c24df4d6f..c0bf15554507 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1455,6 +1455,7 @@ enum { ALC260_FIXUP_HP_B1900, ALC260_FIXUP_KN1, ALC260_FIXUP_FSC_S7020, + ALC260_FIXUP_FSC_S7020_JWSE, }; static void alc260_gpio1_automute(struct hda_codec *codec) @@ -1516,14 +1517,17 @@ static void alc260_fixup_fsc_s7020(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - spec->gen.add_out_jack_modes = 1; - break; - case HDA_FIXUP_ACT_PROBE: + if (action == HDA_FIXUP_ACT_PROBE) spec->init_amp = ALC_INIT_NONE; - break; +} + +static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.add_jack_modes = 1; + spec->gen.hp_mic = 1; } } @@ -1586,6 +1590,12 @@ static const struct hda_fixup alc260_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc260_fixup_fsc_s7020, }, + [ALC260_FIXUP_FSC_S7020_JWSE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc260_fixup_fsc_s7020_jwse, + .chained = true, + .chain_id = ALC260_FIXUP_FSC_S7020, + }, }; static const struct snd_pci_quirk alc260_fixup_tbl[] = { @@ -1602,6 +1612,14 @@ static const struct snd_pci_quirk alc260_fixup_tbl[] = { {} }; +static const struct hda_model_fixup alc260_fixup_models[] = { + {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"}, + {.id = ALC260_FIXUP_COEF, .name = "coef"}, + {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"}, + {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"}, + {} +}; + /* */ static int patch_alc260(struct hda_codec *codec) @@ -1620,7 +1638,8 @@ static int patch_alc260(struct hda_codec *codec) */ spec->gen.prefer_hp_amp = 1; - snd_hda_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); + snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl, + alc260_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index dafe04ae8c72..356673106788 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3797,6 +3797,7 @@ static int patch_stac9200(struct hda_codec *codec) spec->gen.own_eapd_ctl = 1; codec->patch_ops = stac_patch_ops; + codec->power_filter = snd_hda_codec_eapd_power_filter; snd_hda_add_verbs(codec, stac9200_eapd_init); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 223c3d9cc69e..9ea05e956474 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -969,6 +969,7 @@ static int snd_hdspm_create_pcm(struct snd_card *card, struct hdspm *hdspm); static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); +static inline int hdspm_get_pll_freq(struct hdspm *hdspm); static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); static int hdspm_autosync_ref(struct hdspm *hdspm); static int snd_hdspm_set_defaults(struct hdspm *hdspm); @@ -1075,6 +1076,20 @@ static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm) return ret; } +/* round arbitary sample rates to commonly known rates */ +static int hdspm_round_frequency(int rate) +{ + if (rate < 38050) + return 32000; + if (rate < 46008) + return 44100; + else + return 48000; +} + +static int hdspm_tco_sync_check(struct hdspm *hdspm); +static int hdspm_sync_in_sync_check(struct hdspm *hdspm); + /* check for external sample rate */ static int hdspm_external_sample_rate(struct hdspm *hdspm) { @@ -1216,22 +1231,45 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) break; } - /* QS and DS rates normally can not be detected - * automatically by the card. Only exception is MADI - * in 96k frame mode. - * - * So if we read SS values (32 .. 48k), check for - * user-provided DS/QS bits in the control register - * and multiply the base frequency accordingly. - */ - if (rate <= 48000) { - if (hdspm->control_register & HDSPM_QuadSpeed) - rate *= 4; - else if (hdspm->control_register & - HDSPM_DoubleSpeed) - rate *= 2; + } /* endif HDSPM_madiLock */ + + /* check sample rate from TCO or SYNC_IN */ + { + bool is_valid_input = 0; + bool has_sync = 0; + + syncref = hdspm_autosync_ref(hdspm); + if (HDSPM_AUTOSYNC_FROM_TCO == syncref) { + is_valid_input = 1; + has_sync = (HDSPM_SYNC_CHECK_SYNC == + hdspm_tco_sync_check(hdspm)); + } else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) { + is_valid_input = 1; + has_sync = (HDSPM_SYNC_CHECK_SYNC == + hdspm_sync_in_sync_check(hdspm)); + } + + if (is_valid_input && has_sync) { + rate = hdspm_round_frequency( + hdspm_get_pll_freq(hdspm)); } } + + /* QS and DS rates normally can not be detected + * automatically by the card. Only exception is MADI + * in 96k frame mode. + * + * So if we read SS values (32 .. 48k), check for + * user-provided DS/QS bits in the control register + * and multiply the base frequency accordingly. + */ + if (rate <= 48000) { + if (hdspm->control_register & HDSPM_QuadSpeed) + rate *= 4; + else if (hdspm->control_register & + HDSPM_DoubleSpeed) + rate *= 2; + } break; } @@ -1979,16 +2017,25 @@ static void hdspm_midi_tasklet(unsigned long arg) /* get the system sample rate which is set */ +static inline int hdspm_get_pll_freq(struct hdspm *hdspm) +{ + unsigned int period, rate; + + period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); + rate = hdspm_calc_dds_value(hdspm, period); + + return rate; +} + /** * Calculate the real sample rate from the * current DDS value. **/ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) { - unsigned int period, rate; + unsigned int rate; - period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); - rate = hdspm_calc_dds_value(hdspm, period); + rate = hdspm_get_pll_freq(hdspm); if (rate > 207000) { /* Unreasonable high sample rate as seen on PCI MADI cards. */ @@ -2128,6 +2175,16 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) return (status >> (idx*4)) & 0xF; } +#define ENUMERATED_CTL_INFO(info, texts) \ +{ \ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \ + uinfo->count = 1; \ + uinfo->value.enumerated.items = ARRAY_SIZE(texts); \ + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \ + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; \ + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \ +} + #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ @@ -2143,14 +2200,7 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 10; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts_freq[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts_freq); return 0; } @@ -2316,15 +2366,7 @@ static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "Master", "AutoSync" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -2888,6 +2930,112 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, return 0; } + + +#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ |\ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_tco_video_input_format, \ + .get = snd_hdspm_get_tco_video_input_format, \ +} + +static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[] = {"No video", "NTSC", "PAL"}; + ENUMERATED_CTL_INFO(uinfo, texts); + return 0; +} + +static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status; + int ret = 0; + + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); + switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC | + HDSPM_TCO1_Video_Input_Format_PAL)) { + case HDSPM_TCO1_Video_Input_Format_NTSC: + /* ntsc */ + ret = 1; + break; + case HDSPM_TCO1_Video_Input_Format_PAL: + /* pal */ + ret = 2; + break; + default: + /* no video */ + ret = 0; + break; + } + ucontrol->value.enumerated.item[0] = ret; + return 0; +} + + + +#define HDSPM_TCO_LTC_FRAMES(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ |\ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_tco_ltc_frames, \ + .get = snd_hdspm_get_tco_ltc_frames, \ +} + +static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", + "30 fps"}; + ENUMERATED_CTL_INFO(uinfo, texts); + return 0; +} + +static int hdspm_tco_ltc_frames(struct hdspm *hdspm) +{ + u32 status; + int ret = 0; + + status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); + if (status & HDSPM_TCO1_LTC_Input_valid) { + switch (status & (HDSPM_TCO1_LTC_Format_LSB | + HDSPM_TCO1_LTC_Format_MSB)) { + case 0: + /* 24 fps */ + ret = 1; + break; + case HDSPM_TCO1_LTC_Format_LSB: + /* 25 fps */ + ret = 2; + break; + case HDSPM_TCO1_LTC_Format_MSB: + /* 25 fps */ + ret = 3; + break; + default: + /* 30 fps */ + ret = 4; + break; + } + } + + return ret; +} + +static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm); + return 0; +} + #define HDSPM_TOGGLE_SETTING(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -2974,17 +3122,7 @@ static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "optical", "coaxial" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3046,17 +3184,7 @@ static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "Single", "Double" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3129,17 +3257,7 @@ static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "Single", "Double", "Quad" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3215,17 +3333,7 @@ static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "Single", "Double", "Quad" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3445,19 +3553,30 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, .get = snd_hdspm_get_sync_check \ } +#define HDSPM_TCO_LOCK_CHECK(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_tco_info_lock_check, \ + .get = snd_hdspm_get_sync_check \ +} + + static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts); + return 0; +} + +static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[] = { "No Lock", "Lock" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3590,6 +3709,14 @@ static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx) return 0; } +static int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask) +{ + u32 status; + status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); + + return (status & mask) ? 1 : 0; +} + static int hdspm_tco_sync_check(struct hdspm *hdspm) { @@ -3697,6 +3824,22 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, } + if (hdspm->tco) { + switch (kcontrol->private_value) { + case 11: + /* Check TCO for lock state of its current input */ + val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock); + break; + case 12: + /* Check TCO for valid time code on LTC input. */ + val = hdspm_tco_input_check(hdspm, + HDSPM_TCO1_LTC_Input_valid); + break; + default: + break; + } + } + if (-1 == val) val = 3; @@ -3813,17 +3956,7 @@ static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "44.1 kHz", "48 kHz" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3869,17 +4002,7 @@ static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3924,17 +4047,7 @@ static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3981,17 +4094,7 @@ static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, { static char *texts[] = { "24 fps", "25 fps", "29.97fps", "29.97 dfps", "30 fps", "30 dfps" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 6; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4037,17 +4140,7 @@ static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static char *texts[] = { "LTC", "Video", "WCK" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4145,6 +4238,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3), HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), + HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX), HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), HDSPM_INPUT_SELECT("Input Select", 0), @@ -4272,7 +4366,11 @@ static struct snd_kcontrol_new snd_hdspm_controls_tco[] = { HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0), HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0), HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0), - HDSPM_TCO_WORD_TERM("TCO Word Term", 0) + HDSPM_TCO_WORD_TERM("TCO Word Term", 0), + HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11), + HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12), + HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0), + HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0) }; |