ALSA: hda - Avoid cast with union data for HDMI audio infoframe
[pandora-kernel.git] / sound / pci / hda / patch_hdmi.c
index f29b97b..bb49304 100644 (file)
@@ -110,6 +110,12 @@ struct dp_audio_infoframe {
        u8 LFEPBL01_LSV36_DM_INH7;
 };
 
+union audio_infoframe {
+       struct hdmi_audio_infoframe hdmi;
+       struct dp_audio_infoframe dp;
+       u8 bytes[0];
+};
+
 /*
  * CEA speaker placement:
  *
@@ -620,8 +626,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
        int channels = substream->runtime->channels;
        int ca;
        int i;
-       u8 ai[max(sizeof(struct hdmi_audio_infoframe),
-                 sizeof(struct dp_audio_infoframe))];
+       union audio_infoframe ai;
 
        ca = hdmi_channel_allocation(codec, nid, channels);
 
@@ -633,24 +638,24 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
 
                pin_nid = spec->pin[i];
 
-               memset(ai, 0, sizeof(ai));
+               memset(&ai, 0, sizeof(ai));
                if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
-                       struct hdmi_audio_infoframe *hdmi_ai;
+                       struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
 
-                       hdmi_ai = (struct hdmi_audio_infoframe *)ai;
                        hdmi_ai->type           = 0x84;
                        hdmi_ai->ver            = 0x01;
                        hdmi_ai->len            = 0x0a;
                        hdmi_ai->CC02_CT47      = channels - 1;
+                       hdmi_ai->CA             = ca;
                        hdmi_checksum_audio_infoframe(hdmi_ai);
                } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
-                       struct dp_audio_infoframe *dp_ai;
+                       struct dp_audio_infoframe *dp_ai = &ai.dp;
 
-                       dp_ai = (struct dp_audio_infoframe *)ai;
                        dp_ai->type             = 0x84;
                        dp_ai->len              = 0x1b;
                        dp_ai->ver              = 0x11 << 2;
                        dp_ai->CC02_CT47        = channels - 1;
+                       dp_ai->CA               = ca;
                } else {
                        snd_printd("HDMI: unknown connection type at pin %d\n",
                                   pin_nid);
@@ -662,7 +667,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
                 * sizeof(*dp_ai) to avoid partial match/update problems when
                 * the user switches between HDMI/DP monitors.
                 */
-               if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) {
+               if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
+                                            sizeof(ai))) {
                        snd_printdd("hdmi_setup_audio_infoframe: "
                                    "cvt=%d pin=%d channels=%d\n",
                                    nid, pin_nid,
@@ -670,7 +676,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
                        hdmi_setup_channel_mapping(codec, pin_nid, ca);
                        hdmi_stop_infoframe_trans(codec, pin_nid);
                        hdmi_fill_audio_infoframe(codec, pin_nid,
-                                                 ai, sizeof(ai));
+                                                 ai.bytes, sizeof(ai));
                        hdmi_start_infoframe_trans(codec, pin_nid);
                }
        }
@@ -817,6 +823,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_eld *eld;
        struct hda_pcm_stream *codec_pars;
+       struct snd_pcm_runtime *runtime = substream->runtime;
        unsigned int idx;
 
        for (idx = 0; idx < spec->num_cvts; idx++)
@@ -844,6 +851,14 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                hinfo->formats = codec_pars->formats;
                hinfo->maxbps = codec_pars->maxbps;
        }
+       /* store the updated parameters */
+       runtime->hw.channels_min = hinfo->channels_min;
+       runtime->hw.channels_max = hinfo->channels_max;
+       runtime->hw.formats = hinfo->formats;
+       runtime->hw.rates = hinfo->rates;
+
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
        return 0;
 }
 
@@ -1238,6 +1253,9 @@ static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
                snd_pcm_hw_constraint_list(substream->runtime, 0,
                                SNDRV_PCM_HW_PARAM_CHANNELS,
                                hw_constraints_channels);
+       } else {
+               snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_CHANNELS, 2);
        }
 
        return snd_hda_multi_out_dig_open(codec, &spec->multiout);