ASoC: SOF: fix an Oops, caused by invalid topology
[sfrench/cifs-2.6.git] / sound / soc / sof / pcm.c
index 9bb6388742e1a35d49052bde9e403a43150f7eef..29435ba2d32927ea6cd4fd2154d5ac59d6eb3483 100644 (file)
@@ -92,7 +92,27 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
 
-/* this may get called several times by oss emulation */
+static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream,
+                               struct snd_sof_dev *sdev,
+                               struct snd_sof_pcm *spcm)
+{
+       struct sof_ipc_stream stream;
+       struct sof_ipc_reply reply;
+       int ret;
+
+       stream.hdr.size = sizeof(stream);
+       stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
+       stream.comp_id = spcm->stream[substream->stream].comp_id;
+
+       /* send IPC to the DSP */
+       ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
+                                sizeof(stream), &reply, sizeof(reply));
+       if (!ret)
+               spcm->prepared[substream->stream] = false;
+
+       return ret;
+}
+
 static int sof_pcm_hw_params(struct snd_soc_component *component,
                             struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
@@ -113,6 +133,16 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
        if (!spcm)
                return -EINVAL;
 
+       /*
+        * Handle repeated calls to hw_params() without free_pcm() in
+        * between. At least ALSA OSS emulation depends on this.
+        */
+       if (spcm->prepared[substream->stream]) {
+               ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
+               if (ret < 0)
+                       return ret;
+       }
+
        dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
                spcm->pcm.pcm_id, substream->stream);
 
@@ -201,27 +231,6 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
        return ret;
 }
 
-static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream,
-                               struct snd_sof_dev *sdev,
-                               struct snd_sof_pcm *spcm)
-{
-       struct sof_ipc_stream stream;
-       struct sof_ipc_reply reply;
-       int ret;
-
-       stream.hdr.size = sizeof(stream);
-       stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
-       stream.comp_id = spcm->stream[substream->stream].comp_id;
-
-       /* send IPC to the DSP */
-       ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
-                                sizeof(stream), &reply, sizeof(reply));
-       if (!ret)
-               spcm->prepared[substream->stream] = false;
-
-       return ret;
-}
-
 static int sof_pcm_hw_free(struct snd_soc_component *component,
                           struct snd_pcm_substream *substream)
 {
@@ -582,6 +591,11 @@ static int sof_pcm_new(struct snd_soc_component *component,
                "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
                caps->name, caps->buffer_size_min, caps->buffer_size_max);
 
+       if (!pcm->streams[stream].substream) {
+               dev_err(component->dev, "error: NULL playback substream!\n");
+               return -EINVAL;
+       }
+
        snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
                                   SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
                                   le32_to_cpu(caps->buffer_size_min),
@@ -600,6 +614,11 @@ capture:
                "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
                caps->name, caps->buffer_size_min, caps->buffer_size_max);
 
+       if (!pcm->streams[stream].substream) {
+               dev_err(component->dev, "error: NULL capture substream!\n");
+               return -EINVAL;
+       }
+
        snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
                                   SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
                                   le32_to_cpu(caps->buffer_size_min),