HDMI-Audio: Update process_trigger flag to valid HAD state.
authorVaibhav Agarwal <vaibhav.agarwal@intel.com>
Tue, 28 Feb 2012 11:05:04 +0000 (16:35 +0530)
committerbuildbot <buildbot@intel.com>
Mon, 16 Apr 2012 14:55:15 +0000 (07:55 -0700)
BZ: 24898 24987

During Dummy playback, statement to modifyprocess_trigger flag
is missing. This moves HAD to invalid state in some cases.

The solution is to modify process_trigger flag to valid HAD state.
HAD state is also updated with DISCONNECT, when the device is absent
and prepare is called.

Includes HDMI Klocwork spinlock error correction.

Change-Id: I17f272cca392e329b34ceb595d6fd7f4cfbc9586
Signed-off-by: Vaibhav Agarwal <vaibhav.agarwal@intel.com>
Signed-off-by: Shreyas Neerebailoor <shreyasx.neerebailoor@intel.com>
Reviewed-on: http://android.intel.com:8080/36842
Reviewed-by: Vinnakota, Lakshmi N <lakshmi.n.vinnakota@intel.com>
Reviewed-by: Gupta, ArvindX K <arvindx.k.gupta@intel.com>
Reviewed-by: Hibare, PramodX <pramodx.hibare@intel.com>
Tested-by: Hibare, PramodX <pramodx.hibare@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.c
sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio.h
sound/drivers/intel_mid_hdmi/intel_mid_hdmi_audio_if.c

index d0df3e0..986980f 100644 (file)
@@ -556,16 +556,15 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream)
        pr_debug("snd_intelhad_open called\n");
        intelhaddata = snd_pcm_substream_chip(substream);
        had_stream = intelhaddata->private_data;
-       if (had_stream->process_trigger != NO_TRIGGER) {
-               pr_err("%s:Yet to process some trigger\n", __func__);
-               return -ENODEV;
-       }
 
        if (had_get_hwstate(intelhaddata)) {
                pr_err("%s: HDMI cable plugged-out\n", __func__);
                return -ENODEV;
        }
-
+       if (had_stream->process_trigger != NO_TRIGGER) {
+               pr_err("%s:Yet to process some trigger\n", __func__);
+               return -EAGAIN;
+       }
        runtime = substream->runtime;
 
        /* Check, if device already in use */
@@ -893,6 +892,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream,
                /* Disable local INTRs till register prgmng is done */
                if (had_get_hwstate(intelhaddata)) {
                        pr_err("_START: HDMI cable plugged-out\n");
+                       snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
                        retval = -ENODEV;
                        break;
                }
@@ -913,6 +913,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream,
                had_stream->process_trigger = STOP_TRIGGER;
                /* Send zero filled data */
                if (had_stream->stream_status == HAD_RUNNING_DUMMY) {
+                       had_stream->stream_status = HAD_INIT;
+                       had_stream->process_trigger = NO_TRIGGER;
                        spin_unlock_irqrestore(&intelhaddata->had_spinlock,
                                        flag_irq);
                        cancel_delayed_work(&intelhaddata->dummy_audio);
@@ -955,11 +957,18 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
        runtime = substream->runtime;
        had_stream = intelhaddata->private_data;
 
+       if (had_get_hwstate(intelhaddata)) {
+               pr_err("%s: HDMI cable plugged-out\n", __func__);
+               snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+               retval = -ENODEV;
+               goto prep_end;
+       }
+
        spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
        if (had_stream->process_trigger != NO_TRIGGER) {
                spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
                pr_err("%s:Yet to process some trigger\n", __func__);
-               return -EBUSY;
+               return -EAGAIN;
        }
        spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
 
@@ -983,11 +992,6 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
        if (retval)
                goto prep_end;
 
-       if (had_get_hwstate(intelhaddata)) {
-               pr_err("%s: HDMI cable plugged-out\n", __func__);
-               retval = -ENODEV;
-               goto prep_end;
-       }
 
        /* Get N value in KHz */
        retval = had_get_caps(HAD_GET_SAMPLING_FREQ, &disp_samp_freq);
index be20b26..43df020 100644 (file)
@@ -430,7 +430,7 @@ struct had_stream_pvt {
 };
 
 struct had_pvt_data {
-       enum had_stream_status          stream_status;
+       enum had_status_stream          stream_status;
        enum had_process_trigger        process_trigger;
 };
 
index 0108da9..c8313bd 100644 (file)
@@ -206,7 +206,8 @@ static inline int had_start_dummy_playback(struct snd_intelhad *intelhaddata)
                schedule_delayed_work(
                                &intelhaddata->dummy_audio,
                                intelhaddata->timer);
-       }
+       } else
+               spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
 
        return retval;
 }
@@ -303,7 +304,6 @@ static inline int had_process_stop_trigger(struct snd_intelhad *intelhaddata)
        struct had_pvt_data *had_stream;
        enum intel_had_aud_buf_type buf_id;
        u32 buf_addr;
-       unsigned long flag_irqs;
 
        had_stream = intelhaddata->private_data;
 
@@ -311,6 +311,7 @@ static inline int had_process_stop_trigger(struct snd_intelhad *intelhaddata)
        /* If device disconnected, ignore this interrupt */
        if (had_stream->stream_status == HAD_RUNNING_DUMMY) {
                had_stream->stream_status = HAD_INIT;
+               had_stream->process_trigger = NO_TRIGGER;
                return retval;
        }
 
@@ -327,7 +328,6 @@ static inline int had_process_stop_trigger(struct snd_intelhad *intelhaddata)
                intelhaddata->curr_buf = HAD_BUF_TYPE_D;
        else
                intelhaddata->curr_buf = HAD_BUF_TYPE_C;
-       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
 
        /* _STOP -> _START -> _STOP occured
         * invalidate Buff_A, Buff_B
@@ -347,7 +347,6 @@ static inline int had_process_stop_trigger(struct snd_intelhad *intelhaddata)
        pr_debug("buf[%d] addr=%#x  and size=%d\n", i,
                        intelhaddata->buf_info[i].buf_addr,
                        intelhaddata->buf_info[i].buf_size);
-       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
 
        return retval;
 }
@@ -377,7 +376,6 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata)
        buf_size = intelhaddata->buf_info[buf_id].buf_size;
        stream_status = had_stream->stream_status;
        process_trigger = had_stream->process_trigger;
-       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
 
        pr_debug("Enter:%s buf_id=%d", __func__, buf_id);
 
@@ -387,9 +385,10 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata)
         */
 
        /* Check for any intr_miss in case of active playback */
-       if ((stream_status == HAD_RUNNING_STREAM) &&
-                       (process_trigger == NO_TRIGGER) &&
+       if ((had_stream->stream_status == HAD_RUNNING_STREAM) &&
+                       (had_stream->process_trigger == NO_TRIGGER) &&
                        !flag_en_allbufs) {
+               spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
                intr_count = had_chk_intrmiss(intelhaddata, buf_id);
                if (!intr_count || (intr_count > 3)) {
                        pr_err("HAD SW state in non-recoverable!!! mode\n");
@@ -398,9 +397,9 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata)
                }
                buf_id += (intr_count - 1);
                buf_id = buf_id % 4;
+               spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
        }
 
-       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
        /* Acknowledge _START trigger recieved */
        if (had_stream->process_trigger == PRE_START) {
                spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
@@ -627,6 +626,12 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata)
                return retval;
        }
 
+       /* Safety check */
+       if (!substream) {
+               pr_err("PANIC!!! Should never come here\n");
+               return retval;
+       }
+
        if (stream_status == HAD_RUNNING_DUMMY) {
                spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
                had_stream->stream_status = HAD_RUNNING_STREAM;