ALSA: hda - Don't assume non-NULL PCM ops
authorTakashi Iwai <tiwai@suse.de>
Fri, 27 Feb 2015 16:57:55 +0000 (17:57 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 3 Mar 2015 10:26:27 +0000 (11:26 +0100)
The PCM ops might be set NULL, or cleared to NULL when the driver is
unbound.  Give a proper NULL check at each place to be more robust.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_controller.c

index 20283bead10af231f8981d4cfd6369e8f43f66a8..3bd9158addc2b87ba526cf4afafa01c6d34f69a0 100644 (file)
@@ -4525,7 +4525,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
 {
        int ret;
        mutex_lock(&codec->bus->prepare_mutex);
-       ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream);
+       if (hinfo->ops.prepare)
+               ret = hinfo->ops.prepare(hinfo, codec, stream, format,
+                                        substream);
+       else
+               ret = -ENODEV;
        if (ret >= 0)
                purify_inactive_streams(codec);
        mutex_unlock(&codec->bus->prepare_mutex);
@@ -4546,7 +4550,8 @@ void snd_hda_codec_cleanup(struct hda_codec *codec,
                           struct snd_pcm_substream *substream)
 {
        mutex_lock(&codec->bus->prepare_mutex);
-       hinfo->ops.cleanup(hinfo, codec, substream);
+       if (hinfo->ops.cleanup)
+               hinfo->ops.cleanup(hinfo, codec, substream);
        mutex_unlock(&codec->bus->prepare_mutex);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup);
index be02bca6f7e6bc6268ee07ff6c2828555578a556..ad85f9bfaf57bb82d2c33ae086673832d03c9be4 100644 (file)
@@ -416,7 +416,8 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
        azx_dev->running = 0;
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        azx_release_device(azx_dev);
-       hinfo->ops.close(hinfo, apcm->codec, substream);
+       if (hinfo->ops.close)
+               hinfo->ops.close(hinfo, apcm->codec, substream);
        snd_hda_power_down(apcm->codec);
        mutex_unlock(&chip->open_mutex);
        return 0;
@@ -808,8 +809,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        mutex_lock(&chip->open_mutex);
        azx_dev = azx_assign_device(chip, substream);
        if (azx_dev == NULL) {
-               mutex_unlock(&chip->open_mutex);
-               return -EBUSY;
+               err = -EBUSY;
+               goto unlock;
        }
        runtime->hw = azx_pcm_hw;
        runtime->hw.channels_min = hinfo->channels_min;
@@ -844,12 +845,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
                                   buff_step);
        snd_hda_power_up(apcm->codec);
-       err = hinfo->ops.open(hinfo, apcm->codec, substream);
+       if (hinfo->ops.open)
+               err = hinfo->ops.open(hinfo, apcm->codec, substream);
+       else
+               err = -ENODEV;
        if (err < 0) {
                azx_release_device(azx_dev);
-               snd_hda_power_down(apcm->codec);
-               mutex_unlock(&chip->open_mutex);
-               return err;
+               goto powerdown;
        }
        snd_pcm_limit_hw_rates(runtime);
        /* sanity check */
@@ -858,10 +860,10 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
            snd_BUG_ON(!runtime->hw.formats) ||
            snd_BUG_ON(!runtime->hw.rates)) {
                azx_release_device(azx_dev);
-               hinfo->ops.close(hinfo, apcm->codec, substream);
-               snd_hda_power_down(apcm->codec);
-               mutex_unlock(&chip->open_mutex);
-               return -EINVAL;
+               if (hinfo->ops.close)
+                       hinfo->ops.close(hinfo, apcm->codec, substream);
+               err = -EINVAL;
+               goto powerdown;
        }
 
        /* disable LINK_ATIME timestamps for capture streams
@@ -880,6 +882,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
        return 0;
+
+ powerdown:
+       snd_hda_power_down(apcm->codec);
+ unlock:
+       mutex_unlock(&chip->open_mutex);
+       return err;
 }
 
 static int azx_pcm_mmap(struct snd_pcm_substream *substream,