X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=sound%2Fcore%2Fpcm.c;h=2743414fc8fa8ac7fbf14d9b49dc38be622eea0a;hb=b942cf815b5775288550f99f3790e29815bb70cb;hp=b8602471f7e52d326e5a919eb900ef2d03303ea7;hpb=746d4a02e68499fc6c1f8d0c43d2271853ade181;p=safe%2Fjmp%2Flinux-2.6 diff --git a/sound/core/pcm.c b/sound/core/pcm.c index b860247..2743414 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -42,15 +42,12 @@ 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) { - struct list_head *p; struct snd_pcm *pcm; - list_for_each(p, &snd_pcm_devices) { - pcm = list_entry(p, struct snd_pcm, list); + list_for_each_entry(pcm, &snd_pcm_devices, list) { if (pcm->card == card && pcm->device == device) return pcm; } @@ -630,6 +627,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; @@ -638,6 +638,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; } @@ -680,7 +684,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); @@ -724,6 +727,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; @@ -740,7 +744,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); @@ -771,7 +780,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct snd_pcm_runtime *runtime; struct snd_ctl_file *kctl; struct snd_card *card; - struct list_head *list; int prefer_subdevice = -1; size_t size; @@ -784,11 +792,11 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, card = pcm->card; down_read(&card->controls_rwsem); - list_for_each(list, &card->ctl_files) { - kctl = snd_ctl_file(list); + list_for_each_entry(kctl, &card->ctl_files, list) { if (kctl->pid == current->pid) { prefer_subdevice = kctl->prefer_pcm_subdevice; - break; + if (prefer_subdevice != -1) + break; } } up_read(&card->controls_rwsem); @@ -902,13 +910,37 @@ 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; struct snd_pcm_substream *substream; - struct list_head *list; + struct snd_pcm_notify *notify; char str[16]; struct snd_pcm *pcm = device->device_data; + struct device *dev; snd_assert(pcm != NULL && device != NULL, return -ENXIO); mutex_lock(®ister_mutex); @@ -931,23 +963,31 @@ static int snd_pcm_dev_register(struct snd_device *device) devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; break; } - if ((err = snd_register_device(devtype, pcm->card, - pcm->device, - &snd_pcm_f_ops[cidx], - pcm, str)) < 0) - { + /* device pointer to use, pcm->dev takes precedence if + * it is assigned, otherwise fall back to card's device + * if possible */ + dev = pcm->dev; + if (!dev) + dev = snd_card_get_device_link(pcm->card); + /* register pcm */ + err = snd_register_device_for_dev(devtype, pcm->card, + pcm->device, + &snd_pcm_f_ops[cidx], + pcm, str, dev); + if (err < 0) { list_del(&pcm->list); mutex_unlock(®ister_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); } - 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_register(pcm); - } + mutex_unlock(®ister_mutex); return 0; } @@ -955,35 +995,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(®ister_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(®ister_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(®ister_mutex); - list_del(&pcm->list); for (cidx = 0; cidx < 2; cidx++) { devtype = -1; switch (cidx) { @@ -995,33 +1022,29 @@ 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(®ister_mutex); - return snd_pcm_free(pcm); + return 0; } int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) { - struct list_head *p; + struct snd_pcm *pcm; - 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(®ister_mutex); if (nfree) { list_del(¬ify->list); - list_for_each(p, &snd_pcm_devices) - notify->n_unregister(list_entry(p, - struct snd_pcm, list)); + list_for_each_entry(pcm, &snd_pcm_devices, list) + notify->n_unregister(pcm); } else { list_add_tail(¬ify->list, &snd_pcm_notify_list); - list_for_each(p, &snd_pcm_devices) - notify->n_register(list_entry(p, struct snd_pcm, list)); + list_for_each_entry(pcm, &snd_pcm_devices, list) + notify->n_register(pcm); } mutex_unlock(®ister_mutex); return 0; @@ -1037,12 +1060,10 @@ EXPORT_SYMBOL(snd_pcm_notify); static void snd_pcm_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct list_head *p; struct snd_pcm *pcm; mutex_lock(®ister_mutex); - list_for_each(p, &snd_pcm_devices) { - pcm = list_entry(p, struct snd_pcm, list); + list_for_each_entry(pcm, &snd_pcm_devices, list) { snd_iprintf(buffer, "%02i-%02i: %s : %s", pcm->card->number, pcm->device, pcm->id, pcm->name); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)