Merge tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[cascardo/linux.git] / sound / core / pcm.c
index 0345e53..b25bcf5 100644 (file)
@@ -49,8 +49,6 @@ static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
        struct snd_pcm *pcm;
 
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
-               if (pcm->internal)
-                       continue;
                if (pcm->card == card && pcm->device == device)
                        return pcm;
        }
@@ -62,8 +60,6 @@ static int snd_pcm_next(struct snd_card *card, int device)
        struct snd_pcm *pcm;
 
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
-               if (pcm->internal)
-                       continue;
                if (pcm->card == card && pcm->device > device)
                        return pcm->device;
                else if (pcm->card->number > card->number)
@@ -76,6 +72,9 @@ static int snd_pcm_add(struct snd_pcm *newpcm)
 {
        struct snd_pcm *pcm;
 
+       if (newpcm->internal)
+               return 0;
+
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
                if (pcm->card == newpcm->card && pcm->device == newpcm->device)
                        return -EBUSY;
@@ -344,11 +343,8 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
                return;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (! info) {
-               pcm_dbg(substream->pcm,
-                       "snd_pcm_proc_info_read: cannot malloc\n");
+       if (!info)
                return;
-       }
 
        err = snd_pcm_info(substream, info);
        if (err < 0) {
@@ -718,10 +714,8 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
        prev = NULL;
        for (idx = 0, prev = NULL; idx < substream_count; idx++) {
                substream = kzalloc(sizeof(*substream), GFP_KERNEL);
-               if (substream == NULL) {
-                       pcm_err(pcm, "Cannot allocate PCM substream\n");
+               if (!substream)
                        return -ENOMEM;
-               }
                substream->pcm = pcm;
                substream->pstr = pstr;
                substream->number = idx;
@@ -775,13 +769,14 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
        if (rpcm)
                *rpcm = NULL;
        pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
-       if (pcm == NULL) {
-               dev_err(card->dev, "Cannot allocate PCM\n");
+       if (!pcm)
                return -ENOMEM;
-       }
        pcm->card = card;
        pcm->device = device;
        pcm->internal = internal;
+       mutex_init(&pcm->open_mutex);
+       init_waitqueue_head(&pcm->open_wait);
+       INIT_LIST_HEAD(&pcm->list);
        if (id)
                strlcpy(pcm->id, id, sizeof(pcm->id));
        if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
@@ -792,8 +787,6 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
                snd_pcm_free(pcm);
                return err;
        }
-       mutex_init(&pcm->open_mutex);
-       init_waitqueue_head(&pcm->open_wait);
        if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
                snd_pcm_free(pcm);
                return err;
@@ -888,8 +881,9 @@ static int snd_pcm_free(struct snd_pcm *pcm)
 
        if (!pcm)
                return 0;
-       list_for_each_entry(notify, &snd_pcm_notify_list, list) {
-               notify->n_unregister(pcm);
+       if (!pcm->internal) {
+               list_for_each_entry(notify, &snd_pcm_notify_list, list)
+                       notify->n_unregister(pcm);
        }
        if (pcm->private_free)
                pcm->private_free(pcm);
@@ -919,6 +913,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 
        if (snd_BUG_ON(!pcm || !rsubstream))
                return -ENXIO;
+       if (snd_BUG_ON(stream != SNDRV_PCM_STREAM_PLAYBACK &&
+                      stream != SNDRV_PCM_STREAM_CAPTURE))
+               return -EINVAL;
        *rsubstream = NULL;
        pstr = &pcm->streams[stream];
        if (pstr->substream == NULL || pstr->substream_count == 0)
@@ -927,25 +924,14 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        card = pcm->card;
        prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
 
-       switch (stream) {
-       case SNDRV_PCM_STREAM_PLAYBACK:
-               if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
-                       for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) {
-                               if (SUBSTREAM_BUSY(substream))
-                                       return -EAGAIN;
-                       }
-               }
-               break;
-       case SNDRV_PCM_STREAM_CAPTURE:
-               if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
-                       for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) {
-                               if (SUBSTREAM_BUSY(substream))
-                                       return -EAGAIN;
-                       }
+       if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
+               int opposite = !stream;
+
+               for (substream = pcm->streams[opposite].substream; substream;
+                    substream = substream->next) {
+                       if (SUBSTREAM_BUSY(substream))
+                               return -EAGAIN;
                }
-               break;
-       default:
-               return -EINVAL;
        }
 
        if (file->f_flags & O_APPEND) {
@@ -968,15 +954,12 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                return 0;
        }
 
-       if (prefer_subdevice >= 0) {
-               for (substream = pstr->substream; substream; substream = substream->next)
-                       if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
-                               goto __ok;
-       }
-       for (substream = pstr->substream; substream; substream = substream->next)
-               if (!SUBSTREAM_BUSY(substream))
+       for (substream = pstr->substream; substream; substream = substream->next) {
+               if (!SUBSTREAM_BUSY(substream) &&
+                   (prefer_subdevice == -1 ||
+                    substream->number == prefer_subdevice))
                        break;
-      __ok:
+       }
        if (substream == NULL)
                return -EAGAIN;
 
@@ -1086,15 +1069,16 @@ static int snd_pcm_dev_register(struct snd_device *device)
        if (snd_BUG_ON(!device || !device->device_data))
                return -ENXIO;
        pcm = device->device_data;
+       if (pcm->internal)
+               return 0;
+
        mutex_lock(&register_mutex);
        err = snd_pcm_add(pcm);
-       if (err) {
-               mutex_unlock(&register_mutex);
-               return err;
-       }
+       if (err)
+               goto unlock;
        for (cidx = 0; cidx < 2; cidx++) {
                int devtype = -1;
-               if (pcm->streams[cidx].substream == NULL || pcm->internal)
+               if (pcm->streams[cidx].substream == NULL)
                        continue;
                switch (cidx) {
                case SNDRV_PCM_STREAM_PLAYBACK:
@@ -1109,9 +1093,8 @@ static int snd_pcm_dev_register(struct snd_device *device)
                                          &snd_pcm_f_ops[cidx], pcm,
                                          &pcm->streams[cidx].dev);
                if (err < 0) {
-                       list_del(&pcm->list);
-                       mutex_unlock(&register_mutex);
-                       return err;
+                       list_del_init(&pcm->list);
+                       goto unlock;
                }
 
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -1121,8 +1104,9 @@ static int snd_pcm_dev_register(struct snd_device *device)
        list_for_each_entry(notify, &snd_pcm_notify_list, list)
                notify->n_register(pcm);
 
+ unlock:
        mutex_unlock(&register_mutex);
-       return 0;
+       return err;
 }
 
 static int snd_pcm_dev_disconnect(struct snd_device *device)
@@ -1133,13 +1117,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
        int cidx;
 
        mutex_lock(&register_mutex);
-       if (list_empty(&pcm->list))
-               goto unlock;
-
        mutex_lock(&pcm->open_mutex);
        wake_up(&pcm->open_wait);
        list_del_init(&pcm->list);
-       for (cidx = 0; cidx < 2; cidx++)
+       for (cidx = 0; cidx < 2; cidx++) {
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
                        snd_pcm_stream_lock_irq(substream);
                        if (substream->runtime) {
@@ -1149,18 +1130,20 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
                        }
                        snd_pcm_stream_unlock_irq(substream);
                }
-       list_for_each_entry(notify, &snd_pcm_notify_list, list) {
-               notify->n_disconnect(pcm);
+       }
+       if (!pcm->internal) {
+               list_for_each_entry(notify, &snd_pcm_notify_list, list)
+                       notify->n_disconnect(pcm);
        }
        for (cidx = 0; cidx < 2; cidx++) {
-               snd_unregister_device(&pcm->streams[cidx].dev);
+               if (!pcm->internal)
+                       snd_unregister_device(&pcm->streams[cidx].dev);
                if (pcm->streams[cidx].chmap_kctl) {
                        snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
                        pcm->streams[cidx].chmap_kctl = NULL;
                }
        }
        mutex_unlock(&pcm->open_mutex);
- unlock:
        mutex_unlock(&register_mutex);
        return 0;
 }