X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=sound%2Fcore%2Fpcm.c;h=6884ae031f6fc4975c52fb4beb026aeaa61f2248;hb=f653398c86a1c104f0992bd788dd4bb065449be4;hp=8e018988551610574daece3988e78d53d1ca9c5d;hpb=4d361285925613516560f81f8c7fc96b89c8b1a8;p=safe%2Fjmp%2Flinux-2.6 diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e01898..6884ae0 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer - * Copyright (c) by Jaroslav Kysela + * Copyright (c) by Jaroslav Kysela * * * This program is free software; you can redistribute it and/or modify @@ -19,7 +19,6 @@ * */ -#include #include #include #include @@ -30,7 +29,7 @@ #include #include -MODULE_AUTHOR("Jaroslav Kysela , Abramo Bagnara "); +MODULE_AUTHOR("Jaroslav Kysela , Abramo Bagnara "); MODULE_DESCRIPTION("Midlevel PCM code for ALSA."); MODULE_LICENSE("GPL"); @@ -43,19 +42,48 @@ 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 struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) +static struct snd_pcm *snd_pcm_get(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; } return NULL; } +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->card == card && pcm->device > device) + return pcm->device; + else if (pcm->card->number > card->number) + return -1; + } + return -1; +} + +static int snd_pcm_add(struct snd_pcm *newpcm) +{ + struct snd_pcm *pcm; + + list_for_each_entry(pcm, &snd_pcm_devices, list) { + if (pcm->card == newpcm->card && pcm->device == newpcm->device) + return -EBUSY; + if (pcm->card->number > newpcm->card->number || + (pcm->card == newpcm->card && + pcm->device > newpcm->device)) { + list_add(&newpcm->list, pcm->list.prev); + return 0; + } + } + list_add_tail(&newpcm->list, &snd_pcm_devices); + return 0; +} + static int snd_pcm_control_ioctl(struct snd_card *card, struct snd_ctl_file *control, unsigned int cmd, unsigned long arg) @@ -68,14 +96,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)arg)) return -EFAULT; mutex_lock(®ister_mutex); - device = device < 0 ? 0 : device + 1; - while (device < SNDRV_PCM_DEVICES) { - if (snd_pcm_search(card, device)) - break; - device++; - } - if (device == SNDRV_PCM_DEVICES) - device = -1; + device = snd_pcm_next(card, device); mutex_unlock(®ister_mutex); if (put_user(device, (int __user *)arg)) return -EFAULT; @@ -101,7 +122,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card, if (get_user(subdevice, &info->subdevice)) return -EFAULT; mutex_lock(®ister_mutex); - pcm = snd_pcm_search(card, device); + pcm = snd_pcm_get(card, device); if (pcm == NULL) { err = -ENXIO; goto _error; @@ -141,18 +162,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card, return -ENOIOCTLCMD; } -#ifdef CONFIG_SND_VERBOSE_PROCFS - -#define STATE(v) [SNDRV_PCM_STATE_##v] = #v -#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v -#define READY(v) [SNDRV_PCM_READY_##v] = #v -#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v -#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v -#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v -#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v -#define START(v) [SNDRV_PCM_START_##v] = #v #define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v -#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v static char *snd_pcm_format_names[] = { FORMAT(S8), @@ -195,10 +205,23 @@ static char *snd_pcm_format_names[] = { FORMAT(U18_3BE), }; -static const char *snd_pcm_format_name(snd_pcm_format_t format) +const char *snd_pcm_format_name(snd_pcm_format_t format) { return snd_pcm_format_names[format]; } +EXPORT_SYMBOL_GPL(snd_pcm_format_name); + +#ifdef CONFIG_SND_VERBOSE_PROCFS + +#define STATE(v) [SNDRV_PCM_STATE_##v] = #v +#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v +#define READY(v) [SNDRV_PCM_READY_##v] = #v +#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v +#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v +#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v +#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v +#define START(v) [SNDRV_PCM_START_##v] = #v +#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v static char *snd_pcm_stream_names[] = { STREAM(PLAYBACK), @@ -230,12 +253,11 @@ static char *snd_pcm_subformat_names[] = { static char *snd_pcm_tstamp_mode_names[] = { TSTAMP(NONE), - TSTAMP(MMAP), + TSTAMP(ENABLE), }; static const char *snd_pcm_stream_name(int stream) { - snd_assert(stream <= SNDRV_PCM_STREAM_LAST, return NULL); return snd_pcm_stream_names[stream]; } @@ -251,7 +273,6 @@ static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat) static const char *snd_pcm_tstamp_mode_name(int mode) { - snd_assert(mode <= SNDRV_PCM_TSTAMP_LAST, return NULL); return snd_pcm_tstamp_mode_names[mode]; } @@ -361,7 +382,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den); snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size); snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size); - snd_iprintf(buffer, "tick_time: %u\n", runtime->tick_time); #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) if (substream->oss.oss) { snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format)); @@ -389,9 +409,7 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, } snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode)); snd_iprintf(buffer, "period_step: %u\n", runtime->period_step); - snd_iprintf(buffer, "sleep_min: %u\n", runtime->sleep_min); snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min); - snd_iprintf(buffer, "xfer_align: %lu\n", runtime->xfer_align); snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold); snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold); snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); @@ -417,6 +435,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, return; } snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); + snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid)); snd_iprintf(buffer, "trigger_time: %ld.%09ld\n", status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec); snd_iprintf(buffer, "tstamp : %ld.%09ld\n", @@ -651,7 +670,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) spin_lock_init(&substream->self_group.lock); INIT_LIST_HEAD(&substream->self_group.substreams); list_add_tail(&substream->link_list, &substream->self_group.substreams); - spin_lock_init(&substream->timer_lock); atomic_set(&substream->mmap_count, 0); prev = substream; } @@ -676,7 +694,7 @@ EXPORT_SYMBOL(snd_pcm_new_stream); * * Returns zero if successful, or a negative error code on failure. */ -int snd_pcm_new(struct snd_card *card, char *id, int device, +int snd_pcm_new(struct snd_card *card, const char *id, int device, int playback_count, int capture_count, struct snd_pcm ** rpcm) { @@ -688,9 +706,10 @@ int snd_pcm_new(struct snd_card *card, char *id, int device, .dev_disconnect = snd_pcm_dev_disconnect, }; - snd_assert(rpcm != NULL, return -EINVAL); - *rpcm = NULL; - snd_assert(card != NULL, return -ENXIO); + if (snd_BUG_ON(!card)) + return -ENXIO; + if (rpcm) + *rpcm = NULL; pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); if (pcm == NULL) { snd_printk(KERN_ERR "Cannot allocate PCM\n"); @@ -714,7 +733,8 @@ int snd_pcm_new(struct snd_card *card, char *id, int device, snd_pcm_free(pcm); return err; } - *rpcm = pcm; + if (rpcm) + *rpcm = pcm; return 0; } @@ -748,7 +768,8 @@ static int snd_pcm_free(struct snd_pcm *pcm) { struct snd_pcm_notify *notify; - snd_assert(pcm != NULL, return -ENXIO); + if (!pcm) + return 0; list_for_each_entry(notify, &snd_pcm_notify_list, list) { notify->n_unregister(pcm); } @@ -767,12 +788,6 @@ static int snd_pcm_dev_free(struct snd_device *device) return snd_pcm_free(pcm); } -static void snd_pcm_tick_timer_func(unsigned long data) -{ - struct snd_pcm_substream *substream = (struct snd_pcm_substream *) data; - snd_pcm_tick_elapsed(substream); -} - int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file, struct snd_pcm_substream **rsubstream) @@ -782,28 +797,26 @@ 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; - snd_assert(rsubstream != NULL, return -EINVAL); + if (snd_BUG_ON(!pcm || !rsubstream)) + return -ENXIO; *rsubstream = NULL; - snd_assert(pcm != NULL, return -ENXIO); pstr = &pcm->streams[stream]; if (pstr->substream == NULL || pstr->substream_count == 0) return -ENODEV; card = pcm->card; - down_read(&card->controls_rwsem); - list_for_each(list, &card->ctl_files) { - kctl = snd_ctl_file(list); - if (kctl->pid == current->pid) { + read_lock(&card->ctl_files_rwlock); + list_for_each_entry(kctl, &card->ctl_files, list) { + if (kctl->pid == task_pid(current)) { prefer_subdevice = kctl->prefer_pcm_subdevice; if (prefer_subdevice != -1) break; } } - up_read(&card->controls_rwsem); + read_unlock(&card->ctl_files_rwlock); switch (stream) { case SNDRV_PCM_STREAM_PLAYBACK: @@ -881,9 +894,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, memset((void*)runtime->control, 0, size); init_waitqueue_head(&runtime->sleep); - init_timer(&runtime->tick_timer); - runtime->tick_timer.function = snd_pcm_tick_timer_func; - runtime->tick_timer.data = (unsigned long) substream; runtime->status->state = SNDRV_PCM_STATE_OPEN; @@ -891,6 +901,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, substream->private_data = pcm->private_data; substream->ref_count = 1; substream->f_flags = file->f_flags; + substream->pid = get_pid(task_pid(current)); pstr->substream_opened++; *rsubstream = substream; return 0; @@ -900,8 +911,9 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; + if (PCM_RUNTIME_CHECK(substream)) + return; runtime = substream->runtime; - snd_assert(runtime != NULL, return); if (runtime->private_free != NULL) runtime->private_free(runtime); snd_free_pages((void*)runtime->status, @@ -911,6 +923,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) kfree(runtime->hw_constraints.rules); kfree(runtime); substream->runtime = NULL; + put_pid(substream->pid); + substream->pid = NULL; substream->pstr->substream_opened--; } @@ -941,17 +955,20 @@ 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 snd_pcm *pcm; + struct device *dev; - snd_assert(pcm != NULL && device != NULL, return -ENXIO); + if (snd_BUG_ON(!device || !device->device_data)) + return -ENXIO; + pcm = device->device_data; mutex_lock(®ister_mutex); - if (snd_pcm_search(pcm->card, pcm->device)) { + err = snd_pcm_add(pcm); + if (err) { mutex_unlock(®ister_mutex); - return -EBUSY; + return err; } - list_add_tail(&pcm->list, &snd_pcm_devices); for (cidx = 0; cidx < 2; cidx++) { int devtype = -1; if (pcm->streams[cidx].substream == NULL) @@ -966,11 +983,18 @@ 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; @@ -980,11 +1004,10 @@ static int snd_pcm_dev_register(struct snd_device *device) 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; } @@ -1027,22 +1050,22 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) 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 && - notify->n_disconnect, return -EINVAL); + if (snd_BUG_ON(!notify || + !notify->n_register || + !notify->n_unregister || + !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; @@ -1058,12 +1081,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)