At Wed, 3 Sep 2008 15:58:17 +0800, peerchen wrote:
Add the nvidia HDMI codec driver for MCP77/79. The patch based on kernel 2.6.27-rc5.
Signed-off-by: Wei Ni wni@nvidia.com Signed-off-by: Peer Chen peerchen@gmail.com
Thanks for the patch. Some comments below.
diff -uprN -X linux-2.6.26-Orig/Documentation/dontdiff linux-2.6.26-Orig/sound/pci/hda/hda_intel.c linux-2.6.26-New/sound/pci/hda/hda_intel.c --- linux-2.6.26-Orig/sound/pci/hda/hda_intel.c 2008-08-28 13:47:20.000000000 +0800 +++ linux-2.6.26-New/sound/pci/hda/hda_intel.c 2008-08-28 15:33:51.000000000 +0800 @@ -223,8 +223,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO #define RIRB_INT_MASK 0x05
/* STATESTS int mask: SD2,SD1,SD0 */ -#define AZX_MAX_CODECS 3 -#define STATESTS_INT_MASK 0x07 +#define AZX_MAX_CODECS 4 +#define STATESTS_INT_MASK 0x0f
This may break other platforms. Expanding STATESTS_INT_MASK is OK and would be harmless, but AZX_MAX_CODECS is not. AZX_MAX_CODECS is the default number of max codecs. The chipset specific max number of codecs is defined in azx_max_codecs[]. If Nvidia chipsets supports properly more than 3, change azx_max_codecs[AZX_DRIVER_NVIDIA] to 4.
+static unsigned short convert_from_spdif_status_nv(unsigned int sbits) +{
unsigned short val = 0;if (sbits & IEC958_AES0_PROFESSIONAL)val |= AC_DIG1_PROFESSIONAL;if (sbits & IEC958_AES0_NONAUDIO)val |= AC_DIG1_NONAUDIO;if (sbits & IEC958_AES0_PROFESSIONAL) {if ((sbits & IEC958_AES0_PRO_EMPHASIS) ==IEC958_AES0_PRO_EMPHASIS_5015)val |= AC_DIG1_EMPHASIS;} else {if ((sbits & IEC958_AES0_CON_EMPHASIS) ==IEC958_AES0_CON_EMPHASIS_5015)val |= AC_DIG1_EMPHASIS;if (!(sbits & IEC958_AES0_CON_NOT_COPYRIGHT))val |= AC_DIG1_COPYRIGHT;if (sbits & (IEC958_AES1_CON_ORIGINAL << 8))val |= AC_DIG1_LEVEL;val |= sbits & (IEC958_AES1_CON_CATEGORY << 8);}return val;+}
+static unsigned int convert_to_spdif_status_nv(unsigned short val) +{
unsigned int sbits = 0;if (val & AC_DIG1_NONAUDIO)sbits |= IEC958_AES0_NONAUDIO;if (val & AC_DIG1_PROFESSIONAL)sbits |= IEC958_AES0_PROFESSIONAL;if (sbits & IEC958_AES0_PROFESSIONAL) {if (sbits & AC_DIG1_EMPHASIS)sbits |= IEC958_AES0_PRO_EMPHASIS_5015;} else {if (val & AC_DIG1_EMPHASIS)sbits |= IEC958_AES0_CON_EMPHASIS_5015;if (!(val & AC_DIG1_COPYRIGHT))sbits |= IEC958_AES0_CON_NOT_COPYRIGHT;if (val & AC_DIG1_LEVEL)sbits |= (IEC958_AES1_CON_ORIGINAL << 8);sbits |= val & (0x7f << 8);}return sbits;+}
+static int snd_hda_hdmi_cmask_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)+{
ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |IEC958_AES0_NONAUDIO |IEC958_AES0_CON_EMPHASIS_5015 |IEC958_AES0_CON_NOT_COPYRIGHT;ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY |IEC958_AES1_CON_ORIGINAL;return 0;+}
+static int snd_hda_hdmi_pmask_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)+{
ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL |IEC958_AES0_NONAUDIO |IEC958_AES0_PRO_EMPHASIS_5015;return 0;+}
+static int snd_hda_hdmi_mask_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)+{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;uinfo->count = 1;return 0;+}
+static int snd_hda_hdmi_default_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)+{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff;ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff;ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff;ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff;return 0;+}
+static int snd_hda_hdmi_default_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;unsigned short val;int change;mutex_lock(&codec->spdif_mutex);codec->spdif_status = ucontrol->value.iec958.status[0] |((unsigned int)ucontrol->value.iec958.status[1] << 8) |((unsigned int)ucontrol->value.iec958.status[2] << 16) |((unsigned int)ucontrol->value.iec958.status[3] << 24);val = convert_from_spdif_status_nv(codec->spdif_status);val |= codec->spdif_ctls & 1;change = codec->spdif_ctls != val;codec->spdif_ctls = val;if (change) {snd_hda_codec_write_cache(codec, nid, 0,AC_VERB_SET_DIGI_CONVERT_1,val & 0xff);snd_hda_codec_write_cache(codec, nid, 0,AC_VERB_SET_DIGI_CONVERT_2,val >> 8);}mutex_unlock(&codec->spdif_mutex);return change;+}
+#define snd_hda_hdmi_out_switch_info snd_ctl_boolean_mono_info
+static int snd_hda_hdmi_out_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)+{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);ucontrol->value.integer.value[0] = codec->spdif_ctls & AC_DIG1_ENABLE;return 0;+}
+static int snd_hda_hdmi_out_switch_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;unsigned short val;int change;mutex_lock(&codec->spdif_mutex);val = codec->spdif_ctls & ~AC_DIG1_ENABLE;if (ucontrol->value.integer.value[0])val |= AC_DIG1_ENABLE;change = codec->spdif_ctls != val;if (change) {codec->spdif_ctls = val;snd_hda_codec_write_cache(codec, nid, 0,AC_VERB_SET_DIGI_CONVERT_1,val & 0xff);/* unmute amp switch (if any) */if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&(val & AC_DIG1_ENABLE))snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,HDA_AMP_MUTE, 0);}mutex_unlock(&codec->spdif_mutex);return change;+}
These are almost identical with the functions in hda_codec.c. Is your intention to allow a different set of IEC958 status bits controls for HDMI *in addition* to SPDIF? If so, we should change the codes in hda_codec.c to allow other control names.
+struct snd_kcontrol_new hdmi_mixes[] = {
- {
.access = SNDRV_CTL_ELEM_ACCESS_READ,.iface = SNDRV_CTL_ELEM_IFACE_MIXER,.name = "IEC958 Playback Con Mask HDMI",.info = snd_hda_hdmi_mask_info,.get = snd_hda_hdmi_cmask_get,- },
These have also different names from the standard ones. Any reason?
+static struct hda_pcm_stream nvhdmi_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x4, /* NID to query formats and rates and setup streams */
.rates = SNDRV_PCM_RATE_48000,.maxbps = 16,.formats = SNDRV_PCM_FMTBIT_S16_LE,
Use tabs please.
+static int nvhdmi_build_pcms(struct hda_codec *codec) +{
- struct nvhdmi_spec *spec = codec->spec;
- struct hda_pcm *info = &spec->pcm_rec;
- codec->num_pcms = 1;
- codec->pcm_info = info;
- info->name = "NVIDIA HDMI";
info->pcm_type = HDA_PCM_TYPE_HDMI
Ditto.
thanks,
Takashi