fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / sound / core / pcm.c
index 7581edd..8e01898 100644 (file)
@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm);
 static int snd_pcm_dev_free(struct snd_device *device);
 static int snd_pcm_dev_register(struct snd_device *device);
 static int snd_pcm_dev_disconnect(struct snd_device *device);
-static int snd_pcm_dev_unregister(struct snd_device *device);
 
 static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
 {
@@ -494,19 +493,13 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
 static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
 {
 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
-       if (pstr->proc_xrun_debug_entry) {
-               snd_info_unregister(pstr->proc_xrun_debug_entry);
-               pstr->proc_xrun_debug_entry = NULL;
-       }
+       snd_info_free_entry(pstr->proc_xrun_debug_entry);
+       pstr->proc_xrun_debug_entry = NULL;
 #endif
-       if (pstr->proc_info_entry) {
-               snd_info_unregister(pstr->proc_info_entry);
-               pstr->proc_info_entry = NULL;
-       }
-       if (pstr->proc_root) {
-               snd_info_unregister(pstr->proc_root);
-               pstr->proc_root = NULL;
-       }
+       snd_info_free_entry(pstr->proc_info_entry);
+       pstr->proc_info_entry = NULL;
+       snd_info_free_entry(pstr->proc_root);
+       pstr->proc_root = NULL;
        return 0;
 }
 
@@ -570,29 +563,19 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
 
        return 0;
 }
-               
+
 static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
 {
-       if (substream->proc_info_entry) {
-               snd_info_unregister(substream->proc_info_entry);
-               substream->proc_info_entry = NULL;
-       }
-       if (substream->proc_hw_params_entry) {
-               snd_info_unregister(substream->proc_hw_params_entry);
-               substream->proc_hw_params_entry = NULL;
-       }
-       if (substream->proc_sw_params_entry) {
-               snd_info_unregister(substream->proc_sw_params_entry);
-               substream->proc_sw_params_entry = NULL;
-       }
-       if (substream->proc_status_entry) {
-               snd_info_unregister(substream->proc_status_entry);
-               substream->proc_status_entry = NULL;
-       }
-       if (substream->proc_root) {
-               snd_info_unregister(substream->proc_root);
-               substream->proc_root = NULL;
-       }
+       snd_info_free_entry(substream->proc_info_entry);
+       substream->proc_info_entry = NULL;
+       snd_info_free_entry(substream->proc_hw_params_entry);
+       substream->proc_hw_params_entry = NULL;
+       snd_info_free_entry(substream->proc_sw_params_entry);
+       substream->proc_sw_params_entry = NULL;
+       snd_info_free_entry(substream->proc_status_entry);
+       substream->proc_status_entry = NULL;
+       snd_info_free_entry(substream->proc_root);
+       substream->proc_root = NULL;
        return 0;
 }
 #else /* !CONFIG_SND_VERBOSE_PROCFS */
@@ -646,6 +629,9 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
                substream->number = idx;
                substream->stream = stream;
                sprintf(substream->name, "subdevice #%i", idx);
+               snprintf(substream->latency_id, sizeof(substream->latency_id),
+                        "ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device,
+                        (stream ? 'c' : 'p'), idx);
                substream->buffer_bytes_max = UINT_MAX;
                if (prev == NULL)
                        pstr->substream = substream;
@@ -654,6 +640,10 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
                err = snd_pcm_substream_proc_init(substream);
                if (err < 0) {
                        snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
+                       if (prev == NULL)
+                               pstr->substream = NULL;
+                       else
+                               prev->next = NULL;
                        kfree(substream);
                        return err;
                }
@@ -696,7 +686,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
                .dev_free = snd_pcm_dev_free,
                .dev_register = snd_pcm_dev_register,
                .dev_disconnect = snd_pcm_dev_disconnect,
-               .dev_unregister = snd_pcm_dev_unregister
        };
 
        snd_assert(rpcm != NULL, return -EINVAL);
@@ -740,6 +729,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
        substream = pstr->substream;
        while (substream) {
                substream_next = substream->next;
+               snd_pcm_timer_done(substream);
                snd_pcm_substream_proc_done(substream);
                kfree(substream);
                substream = substream_next;
@@ -756,7 +746,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
 
 static int snd_pcm_free(struct snd_pcm *pcm)
 {
+       struct snd_pcm_notify *notify;
+
        snd_assert(pcm != NULL, return -ENXIO);
+       list_for_each_entry(notify, &snd_pcm_notify_list, list) {
+               notify->n_unregister(pcm);
+       }
        if (pcm->private_free)
                pcm->private_free(pcm);
        snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -804,7 +799,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                kctl = snd_ctl_file(list);
                if (kctl->pid == current->pid) {
                        prefer_subdevice = kctl->prefer_pcm_subdevice;
-                       break;
+                       if (prefer_subdevice != -1)
+                               break;
                }
        }
        up_read(&card->controls_rwsem);
@@ -918,6 +914,29 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
        substream->pstr->substream_opened--;
 }
 
+static ssize_t show_pcm_class(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct snd_pcm *pcm;
+       const char *str;
+       static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
+               [SNDRV_PCM_CLASS_GENERIC] = "generic",
+               [SNDRV_PCM_CLASS_MULTI] = "multi",
+               [SNDRV_PCM_CLASS_MODEM] = "modem",
+               [SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
+       };
+
+       if (! (pcm = dev_get_drvdata(dev)) ||
+           pcm->dev_class > SNDRV_PCM_CLASS_LAST)
+               str = "none";
+       else
+               str = strs[pcm->dev_class];
+        return snprintf(buf, PAGE_SIZE, "%s\n", str);
+}
+
+static struct device_attribute pcm_attrs =
+       __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
+
 static int snd_pcm_dev_register(struct snd_device *device)
 {
        int cidx, err;
@@ -956,6 +975,8 @@ static int snd_pcm_dev_register(struct snd_device *device)
                        mutex_unlock(&register_mutex);
                        return err;
                }
+               snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,
+                                         &pcm_attrs);
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
                        snd_pcm_timer_init(substream);
        }
@@ -971,35 +992,22 @@ static int snd_pcm_dev_register(struct snd_device *device)
 static int snd_pcm_dev_disconnect(struct snd_device *device)
 {
        struct snd_pcm *pcm = device->device_data;
-       struct list_head *list;
+       struct snd_pcm_notify *notify;
        struct snd_pcm_substream *substream;
-       int cidx;
+       int cidx, devtype;
 
        mutex_lock(&register_mutex);
+       if (list_empty(&pcm->list))
+               goto unlock;
+
        list_del_init(&pcm->list);
        for (cidx = 0; cidx < 2; cidx++)
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
                        if (substream->runtime)
                                substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
-       list_for_each(list, &snd_pcm_notify_list) {
-               struct snd_pcm_notify *notify;
-               notify = list_entry(list, struct snd_pcm_notify, list);
+       list_for_each_entry(notify, &snd_pcm_notify_list, list) {
                notify->n_disconnect(pcm);
        }
-       mutex_unlock(&register_mutex);
-       return 0;
-}
-
-static int snd_pcm_dev_unregister(struct snd_device *device)
-{
-       int cidx, devtype;
-       struct snd_pcm_substream *substream;
-       struct list_head *list;
-       struct snd_pcm *pcm = device->device_data;
-
-       snd_assert(pcm != NULL, return -ENXIO);
-       mutex_lock(&register_mutex);
-       list_del(&pcm->list);
        for (cidx = 0; cidx < 2; cidx++) {
                devtype = -1;
                switch (cidx) {
@@ -1011,23 +1019,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device)
                        break;
                }
                snd_unregister_device(devtype, pcm->card, pcm->device);
-               for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
-                       snd_pcm_timer_done(substream);
-       }
-       list_for_each(list, &snd_pcm_notify_list) {
-               struct snd_pcm_notify *notify;
-               notify = list_entry(list, struct snd_pcm_notify, list);
-               notify->n_unregister(pcm);
        }
+ unlock:
        mutex_unlock(&register_mutex);
-       return snd_pcm_free(pcm);
+       return 0;
 }
 
 int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
 {
        struct list_head *p;
 
-       snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
+       snd_assert(notify != NULL &&
+                  notify->n_register != NULL &&
+                  notify->n_unregister != NULL &&
+                  notify->n_disconnect, return -EINVAL);
        mutex_lock(&register_mutex);
        if (nfree) {
                list_del(&notify->list);
@@ -1090,8 +1095,7 @@ static void snd_pcm_proc_init(void)
 
 static void snd_pcm_proc_done(void)
 {
-       if (snd_pcm_proc_entry)
-               snd_info_unregister(snd_pcm_proc_entry);
+       snd_info_free_entry(snd_pcm_proc_entry);
 }
 
 #else /* !CONFIG_PROC_FS */