Loading sound/pci/hda/hda_codec.c +37 −8 Original line number Diff line number Diff line Loading @@ -1119,6 +1119,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, u16 nid = get_amp_nid(kcontrol); u8 chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); u32 caps; caps = query_amp_caps(codec, nid, dir); Loading @@ -1130,6 +1131,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, kcontrol->id.name); return -EINVAL; } if (ofs < caps) caps -= ofs; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = chs == 3 ? 2 : 1; uinfo->value.integer.min = 0; Loading @@ -1138,6 +1141,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); static inline unsigned int read_amp_value(struct hda_codec *codec, hda_nid_t nid, int ch, int dir, int idx, unsigned int ofs) { unsigned int val; val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx); val &= HDA_AMP_VOLMASK; if (val >= ofs) val -= ofs; else val = 0; return val; } static inline int update_amp_value(struct hda_codec *codec, hda_nid_t nid, int ch, int dir, int idx, unsigned int ofs, unsigned int val) { if (val > 0) val += ofs; return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val); } int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { Loading @@ -1146,14 +1175,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); long *valp = ucontrol->value.integer.value; if (chs & 1) *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & HDA_AMP_VOLMASK; *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs); if (chs & 2) *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & HDA_AMP_VOLMASK; *valp = read_amp_value(codec, nid, 1, dir, idx, ofs); return 0; } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); Loading @@ -1166,18 +1194,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); long *valp = ucontrol->value.integer.value; int change = 0; snd_hda_power_up(codec); if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 0x7f, *valp); change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); valp++; } if (chs & 2) change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, 0x7f, *valp); change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); snd_hda_power_down(codec); return change; } Loading @@ -1189,6 +1216,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = get_amp_nid(kcontrol); int dir = get_amp_direction(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); u32 caps, val1, val2; if (size < 4 * sizeof(unsigned int)) Loading @@ -1197,6 +1225,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; val2 = (val2 + 1) * 25; val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); val1 += ofs; val1 = ((int)val1) * ((int)val2); if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) return -EFAULT; Loading sound/pci/hda/hda_local.h +4 −1 Original line number Diff line number Diff line Loading @@ -26,8 +26,10 @@ /* * for mixer controls */ #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \ ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23)) #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0) /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ Loading Loading @@ -458,6 +460,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) /* * CEA Short Audio Descriptor data Loading sound/pci/hda/patch_sigmatel.c +33 −8 Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ struct sigmatel_spec { unsigned int alt_switch: 1; unsigned int hp_detect: 1; unsigned int spdif_mute: 1; unsigned int check_volume_offset:1; /* gpio lines */ unsigned int eapd_mask; Loading Loading @@ -202,6 +203,8 @@ struct sigmatel_spec { hda_nid_t hp_dacs[5]; hda_nid_t speaker_dacs[5]; int volume_offset; /* capture */ hda_nid_t *adc_nids; unsigned int num_adcs; Loading Loading @@ -1293,6 +1296,8 @@ static int stac92xx_build_controls(struct hda_codec *codec) unsigned int vmaster_tlv[4]; snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], HDA_OUTPUT, vmaster_tlv); /* correct volume offset */ vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; err = snd_hda_add_vmaster(codec, "Master Playback Volume", vmaster_tlv, slave_vols); if (err < 0) Loading Loading @@ -2976,14 +2981,34 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec) } /* create volume control/switch for the given prefx type */ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) static int create_controls(struct hda_codec *codec, const char *pfx, hda_nid_t nid, int chs) { struct sigmatel_spec *spec = codec->spec; char name[32]; int err; if (!spec->check_volume_offset) { unsigned int caps, step, nums, db_scale; caps = query_amp_caps(codec, nid, HDA_OUTPUT); step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; step = (step + 1) * 25; /* in .01dB unit */ nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; db_scale = nums * step; /* if dB scale is over -64dB, and finer enough, * let's reduce it to half */ if (db_scale > 6400 && nums >= 0x1f) spec->volume_offset = nums / 2; spec->check_volume_offset = 1; } sprintf(name, "%s Playback Volume", pfx); err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT, spec->volume_offset)); if (err < 0) return err; sprintf(name, "%s Playback Switch", pfx); Loading Loading @@ -3049,10 +3074,10 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, nid = spec->multiout.dac_nids[i]; if (i == 2) { /* Center/LFE */ err = create_controls(spec, "Center", nid, 1); err = create_controls(codec, "Center", nid, 1); if (err < 0) return err; err = create_controls(spec, "LFE", nid, 2); err = create_controls(codec, "LFE", nid, 2); if (err < 0) return err; Loading Loading @@ -3080,7 +3105,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, break; } } err = create_controls(spec, name, nid, 3); err = create_controls(codec, name, nid, 3); if (err < 0) return err; } Loading Loading @@ -3135,7 +3160,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, nid = spec->hp_dacs[i]; if (!nid) continue; err = create_controls(spec, pfxs[nums++], nid, 3); err = create_controls(codec, pfxs[nums++], nid, 3); if (err < 0) return err; } Loading @@ -3149,7 +3174,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, nid = spec->speaker_dacs[i]; if (!nid) continue; err = create_controls(spec, pfxs[nums++], nid, 3); err = create_controls(codec, pfxs[nums++], nid, 3); if (err < 0) return err; } Loading Loading @@ -3725,7 +3750,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, } if (lfe_pin) { err = create_controls(spec, "LFE", lfe_pin, 1); err = create_controls(codec, "LFE", lfe_pin, 1); if (err < 0) return err; } Loading Loading
sound/pci/hda/hda_codec.c +37 −8 Original line number Diff line number Diff line Loading @@ -1119,6 +1119,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, u16 nid = get_amp_nid(kcontrol); u8 chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); u32 caps; caps = query_amp_caps(codec, nid, dir); Loading @@ -1130,6 +1131,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, kcontrol->id.name); return -EINVAL; } if (ofs < caps) caps -= ofs; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = chs == 3 ? 2 : 1; uinfo->value.integer.min = 0; Loading @@ -1138,6 +1141,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); static inline unsigned int read_amp_value(struct hda_codec *codec, hda_nid_t nid, int ch, int dir, int idx, unsigned int ofs) { unsigned int val; val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx); val &= HDA_AMP_VOLMASK; if (val >= ofs) val -= ofs; else val = 0; return val; } static inline int update_amp_value(struct hda_codec *codec, hda_nid_t nid, int ch, int dir, int idx, unsigned int ofs, unsigned int val) { if (val > 0) val += ofs; return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val); } int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { Loading @@ -1146,14 +1175,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); long *valp = ucontrol->value.integer.value; if (chs & 1) *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & HDA_AMP_VOLMASK; *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs); if (chs & 2) *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & HDA_AMP_VOLMASK; *valp = read_amp_value(codec, nid, 1, dir, idx, ofs); return 0; } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); Loading @@ -1166,18 +1194,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); long *valp = ucontrol->value.integer.value; int change = 0; snd_hda_power_up(codec); if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 0x7f, *valp); change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); valp++; } if (chs & 2) change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, 0x7f, *valp); change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); snd_hda_power_down(codec); return change; } Loading @@ -1189,6 +1216,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = get_amp_nid(kcontrol); int dir = get_amp_direction(kcontrol); unsigned int ofs = get_amp_offset(kcontrol); u32 caps, val1, val2; if (size < 4 * sizeof(unsigned int)) Loading @@ -1197,6 +1225,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; val2 = (val2 + 1) * 25; val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); val1 += ofs; val1 = ((int)val1) * ((int)val2); if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) return -EFAULT; Loading
sound/pci/hda/hda_local.h +4 −1 Original line number Diff line number Diff line Loading @@ -26,8 +26,10 @@ /* * for mixer controls */ #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \ ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23)) #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0) /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ Loading Loading @@ -458,6 +460,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) /* * CEA Short Audio Descriptor data Loading
sound/pci/hda/patch_sigmatel.c +33 −8 Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ struct sigmatel_spec { unsigned int alt_switch: 1; unsigned int hp_detect: 1; unsigned int spdif_mute: 1; unsigned int check_volume_offset:1; /* gpio lines */ unsigned int eapd_mask; Loading Loading @@ -202,6 +203,8 @@ struct sigmatel_spec { hda_nid_t hp_dacs[5]; hda_nid_t speaker_dacs[5]; int volume_offset; /* capture */ hda_nid_t *adc_nids; unsigned int num_adcs; Loading Loading @@ -1293,6 +1296,8 @@ static int stac92xx_build_controls(struct hda_codec *codec) unsigned int vmaster_tlv[4]; snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], HDA_OUTPUT, vmaster_tlv); /* correct volume offset */ vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; err = snd_hda_add_vmaster(codec, "Master Playback Volume", vmaster_tlv, slave_vols); if (err < 0) Loading Loading @@ -2976,14 +2981,34 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec) } /* create volume control/switch for the given prefx type */ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) static int create_controls(struct hda_codec *codec, const char *pfx, hda_nid_t nid, int chs) { struct sigmatel_spec *spec = codec->spec; char name[32]; int err; if (!spec->check_volume_offset) { unsigned int caps, step, nums, db_scale; caps = query_amp_caps(codec, nid, HDA_OUTPUT); step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; step = (step + 1) * 25; /* in .01dB unit */ nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; db_scale = nums * step; /* if dB scale is over -64dB, and finer enough, * let's reduce it to half */ if (db_scale > 6400 && nums >= 0x1f) spec->volume_offset = nums / 2; spec->check_volume_offset = 1; } sprintf(name, "%s Playback Volume", pfx); err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT, spec->volume_offset)); if (err < 0) return err; sprintf(name, "%s Playback Switch", pfx); Loading Loading @@ -3049,10 +3074,10 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, nid = spec->multiout.dac_nids[i]; if (i == 2) { /* Center/LFE */ err = create_controls(spec, "Center", nid, 1); err = create_controls(codec, "Center", nid, 1); if (err < 0) return err; err = create_controls(spec, "LFE", nid, 2); err = create_controls(codec, "LFE", nid, 2); if (err < 0) return err; Loading Loading @@ -3080,7 +3105,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, break; } } err = create_controls(spec, name, nid, 3); err = create_controls(codec, name, nid, 3); if (err < 0) return err; } Loading Loading @@ -3135,7 +3160,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, nid = spec->hp_dacs[i]; if (!nid) continue; err = create_controls(spec, pfxs[nums++], nid, 3); err = create_controls(codec, pfxs[nums++], nid, 3); if (err < 0) return err; } Loading @@ -3149,7 +3174,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, nid = spec->speaker_dacs[i]; if (!nid) continue; err = create_controls(spec, pfxs[nums++], nid, 3); err = create_controls(codec, pfxs[nums++], nid, 3); if (err < 0) return err; } Loading Loading @@ -3725,7 +3750,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, } if (lfe_pin) { err = create_controls(spec, "LFE", lfe_pin, 1); err = create_controls(codec, "LFE", lfe_pin, 1); if (err < 0) return err; } Loading