diff options
Diffstat (limited to 'sound/core/rawmidi.c')
| -rw-r--r-- | sound/core/rawmidi.c | 617 |
1 files changed, 341 insertions, 276 deletions
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index f7ea7287c59..6fc71a4c8a5 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -27,7 +27,7 @@ #include <linux/time.h> #include <linux/wait.h> #include <linux/mutex.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/delay.h> #include <sound/rawmidi.h> #include <sound/info.h> @@ -56,6 +56,13 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device); static LIST_HEAD(snd_rawmidi_devices); static DEFINE_MUTEX(register_mutex); +#define rmidi_err(rmidi, fmt, args...) \ + dev_err((rmidi)->card->dev, fmt, ##args) +#define rmidi_warn(rmidi, fmt, args...) \ + dev_warn((rmidi)->card->dev, fmt, ##args) +#define rmidi_dbg(rmidi, fmt, args...) \ + dev_dbg((rmidi)->card->dev, fmt, ##args) + static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) { struct snd_rawmidi *rawmidi; @@ -92,16 +99,12 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre (!substream->append || runtime->avail >= count); } -static void snd_rawmidi_input_event_tasklet(unsigned long data) -{ - struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data; - substream->runtime->event(substream); -} - -static void snd_rawmidi_output_trigger_tasklet(unsigned long data) +static void snd_rawmidi_input_event_work(struct work_struct *work) { - struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data; - substream->ops->trigger(substream, 1); + struct snd_rawmidi_runtime *runtime = + container_of(work, struct snd_rawmidi_runtime, event_work); + if (runtime->event) + runtime->event(runtime->substream); } static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) @@ -110,16 +113,10 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL) return -ENOMEM; + runtime->substream = substream; spin_lock_init(&runtime->lock); init_waitqueue_head(&runtime->sleep); - if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) - tasklet_init(&runtime->tasklet, - snd_rawmidi_input_event_tasklet, - (unsigned long)substream); - else - tasklet_init(&runtime->tasklet, - snd_rawmidi_output_trigger_tasklet, - (unsigned long)substream); + INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); runtime->event = NULL; runtime->buffer_size = PAGE_SIZE; runtime->avail_min = 1; @@ -148,19 +145,18 @@ static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream) static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream,int up) { - if (up) { - tasklet_hi_schedule(&substream->runtime->tasklet); - } else { - tasklet_kill(&substream->runtime->tasklet); - substream->ops->trigger(substream, 0); - } + if (!substream->opened) + return; + substream->ops->trigger(substream, up); } static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) { + if (!substream->opened) + return; substream->ops->trigger(substream, up); - if (!up && substream->runtime->event) - tasklet_kill(&substream->runtime->tasklet); + if (!up) + cancel_work_sync(&substream->runtime->event_work); } int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) @@ -176,6 +172,7 @@ int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) spin_unlock_irqrestore(&runtime->lock, flags); return 0; } +EXPORT_SYMBOL(snd_rawmidi_drop_output); int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) { @@ -191,7 +188,9 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) if (signal_pending(current)) err = -ERESTARTSYS; if (runtime->avail < runtime->buffer_size && !timeout) { - snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size); + rmidi_warn(substream->rmidi, + "rawmidi drain error (avail = %li, buffer_size = %li)\n", + (long)runtime->avail, (long)runtime->buffer_size); err = -EIO; } runtime->drain = 0; @@ -205,6 +204,7 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) } return err; } +EXPORT_SYMBOL(snd_rawmidi_drain_output); int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) { @@ -219,159 +219,145 @@ int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) spin_unlock_irqrestore(&runtime->lock, flags); return 0; } +EXPORT_SYMBOL(snd_rawmidi_drain_input); -int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, - int mode, struct snd_rawmidi_file * rfile) +/* look for an available substream for the given stream direction; + * if a specific subdevice is given, try to assign it + */ +static int assign_substream(struct snd_rawmidi *rmidi, int subdevice, + int stream, int mode, + struct snd_rawmidi_substream **sub_ret) { - struct snd_rawmidi *rmidi; - struct list_head *list1, *list2; - struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; - struct snd_rawmidi_runtime *input = NULL, *output = NULL; - int err; + struct snd_rawmidi_substream *substream; + struct snd_rawmidi_str *s = &rmidi->streams[stream]; + static unsigned int info_flags[2] = { + [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT, + [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT, + }; - if (rfile) - rfile->input = rfile->output = NULL; - mutex_lock(®ister_mutex); - rmidi = snd_rawmidi_search(card, device); - mutex_unlock(®ister_mutex); - if (rmidi == NULL) { - err = -ENODEV; - goto __error1; - } - if (!try_module_get(rmidi->card->module)) { - err = -EFAULT; - goto __error1; - } - if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) - mutex_lock(&rmidi->open_mutex); - if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { - if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) { - err = -ENXIO; - goto __error; - } - if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) { - err = -ENODEV; - goto __error; - } - if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >= - rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) { - err = -EAGAIN; - goto __error; - } - } - if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { - if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) { - err = -ENXIO; - goto __error; - } - if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) { - err = -ENODEV; - goto __error; - } - if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >= - rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) { - err = -EAGAIN; - goto __error; + if (!(rmidi->info_flags & info_flags[stream])) + return -ENXIO; + if (subdevice >= 0 && subdevice >= s->substream_count) + return -ENODEV; + + list_for_each_entry(substream, &s->substreams, list) { + if (substream->opened) { + if (stream == SNDRV_RAWMIDI_STREAM_INPUT || + !(mode & SNDRV_RAWMIDI_LFLG_APPEND) || + !substream->append) + continue; } - } - list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next; - while (1) { - if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { - sinput = NULL; - if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { - err = -EAGAIN; - goto __error; - } - break; + if (subdevice < 0 || subdevice == substream->number) { + *sub_ret = substream; + return 0; } - sinput = list_entry(list1, struct snd_rawmidi_substream, list); - if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened) - goto __nexti; - if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number)) - break; - __nexti: - list1 = list1->next; } - list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next; - while (1) { - if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { - soutput = NULL; - if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { - err = -EAGAIN; - goto __error; - } - break; - } - soutput = list_entry(list2, struct snd_rawmidi_substream, list); - if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { - if (mode & SNDRV_RAWMIDI_LFLG_APPEND) { - if (soutput->opened && !soutput->append) - goto __nexto; - } else { - if (soutput->opened) - goto __nexto; - } + return -EAGAIN; +} + +/* open and do ref-counting for the given substream */ +static int open_substream(struct snd_rawmidi *rmidi, + struct snd_rawmidi_substream *substream, + int mode) +{ + int err; + + if (substream->use_count == 0) { + err = snd_rawmidi_runtime_create(substream); + if (err < 0) + return err; + err = substream->ops->open(substream); + if (err < 0) { + snd_rawmidi_runtime_free(substream); + return err; } - if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number)) - break; - __nexto: - list2 = list2->next; + substream->opened = 1; + substream->active_sensing = 0; + if (mode & SNDRV_RAWMIDI_LFLG_APPEND) + substream->append = 1; + substream->pid = get_pid(task_pid(current)); + rmidi->streams[substream->stream].substream_opened++; } + substream->use_count++; + return 0; +} + +static void close_substream(struct snd_rawmidi *rmidi, + struct snd_rawmidi_substream *substream, + int cleanup); + +static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, + struct snd_rawmidi_file *rfile) +{ + struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; + int err; + + rfile->input = rfile->output = NULL; if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { - if ((err = snd_rawmidi_runtime_create(sinput)) < 0) - goto __error; - input = sinput->runtime; - if ((err = sinput->ops->open(sinput)) < 0) - goto __error; - sinput->opened = 1; - rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++; - } else { - sinput = NULL; + err = assign_substream(rmidi, subdevice, + SNDRV_RAWMIDI_STREAM_INPUT, + mode, &sinput); + if (err < 0) + return err; } if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { - if (soutput->opened) - goto __skip_output; - if ((err = snd_rawmidi_runtime_create(soutput)) < 0) { - if (mode & SNDRV_RAWMIDI_LFLG_INPUT) - sinput->ops->close(sinput); - goto __error; - } - output = soutput->runtime; - if ((err = soutput->ops->open(soutput)) < 0) { - if (mode & SNDRV_RAWMIDI_LFLG_INPUT) - sinput->ops->close(sinput); - goto __error; - } - __skip_output: - soutput->opened = 1; - if (mode & SNDRV_RAWMIDI_LFLG_APPEND) - soutput->append = 1; - if (soutput->use_count++ == 0) - soutput->active_sensing = 1; - rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++; - } else { - soutput = NULL; + err = assign_substream(rmidi, subdevice, + SNDRV_RAWMIDI_STREAM_OUTPUT, + mode, &soutput); + if (err < 0) + return err; } - if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) - mutex_unlock(&rmidi->open_mutex); - if (rfile) { - rfile->rmidi = rmidi; - rfile->input = sinput; - rfile->output = soutput; + + if (sinput) { + err = open_substream(rmidi, sinput, mode); + if (err < 0) + return err; + } + if (soutput) { + err = open_substream(rmidi, soutput, mode); + if (err < 0) { + if (sinput) + close_substream(rmidi, sinput, 0); + return err; + } } + + rfile->rmidi = rmidi; + rfile->input = sinput; + rfile->output = soutput; return 0; +} - __error: - if (input != NULL) - snd_rawmidi_runtime_free(sinput); - if (output != NULL) - snd_rawmidi_runtime_free(soutput); - module_put(rmidi->card->module); - if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) - mutex_unlock(&rmidi->open_mutex); - __error1: +/* called from sound/core/seq/seq_midi.c */ +int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, + int mode, struct snd_rawmidi_file * rfile) +{ + struct snd_rawmidi *rmidi; + int err; + + if (snd_BUG_ON(!rfile)) + return -EINVAL; + + mutex_lock(®ister_mutex); + rmidi = snd_rawmidi_search(card, device); + if (rmidi == NULL) { + mutex_unlock(®ister_mutex); + return -ENODEV; + } + if (!try_module_get(rmidi->card->module)) { + mutex_unlock(®ister_mutex); + return -ENXIO; + } + mutex_unlock(®ister_mutex); + + mutex_lock(&rmidi->open_mutex); + err = rawmidi_open_priv(rmidi, subdevice, mode, rfile); + mutex_unlock(&rmidi->open_mutex); + if (err < 0) + module_put(rmidi->card->module); return err; } +EXPORT_SYMBOL(snd_rawmidi_kernel_open); static int snd_rawmidi_open(struct inode *inode, struct file *file) { @@ -381,10 +367,17 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) unsigned short fflags; int err; struct snd_rawmidi *rmidi; - struct snd_rawmidi_file *rawmidi_file; + struct snd_rawmidi_file *rawmidi_file = NULL; wait_queue_t wait; struct snd_ctl_file *kctl; + if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) + return -EINVAL; /* invalid combination */ + + err = nonseekable_open(inode, file); + if (err < 0) + return err; + if (maj == snd_major) { rmidi = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_RAWMIDI); @@ -398,37 +391,39 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) if (rmidi == NULL) return -ENODEV; - if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) - return -EINVAL; /* invalid combination */ + + if (!try_module_get(rmidi->card->module)) { + snd_card_unref(rmidi->card); + return -ENXIO; + } + + mutex_lock(&rmidi->open_mutex); card = rmidi->card; err = snd_card_file_add(card, file); if (err < 0) - return -ENODEV; + goto __error_card; fflags = snd_rawmidi_file_flags(file); if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */ fflags |= SNDRV_RAWMIDI_LFLG_APPEND; - fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK; rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); if (rawmidi_file == NULL) { - snd_card_file_remove(card, file); - return -ENOMEM; + err = -ENOMEM; + goto __error; } init_waitqueue_entry(&wait, current); add_wait_queue(&rmidi->open_wait, &wait); - mutex_lock(&rmidi->open_mutex); while (1) { subdevice = -1; - down_read(&card->controls_rwsem); + read_lock(&card->ctl_files_rwlock); list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == current->pid) { + if (kctl->pid == task_pid(current)) { subdevice = kctl->prefer_rawmidi_subdevice; if (subdevice != -1) break; } } - up_read(&card->controls_rwsem); - err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device, - subdevice, fflags, rawmidi_file); + read_unlock(&card->ctl_files_rwlock); + err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file); if (err >= 0) break; if (err == -EAGAIN) { @@ -442,89 +437,121 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) mutex_unlock(&rmidi->open_mutex); schedule(); mutex_lock(&rmidi->open_mutex); + if (rmidi->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; } } + remove_wait_queue(&rmidi->open_wait, &wait); + if (err < 0) { + kfree(rawmidi_file); + goto __error; + } #ifdef CONFIG_SND_OSSEMUL if (rawmidi_file->input && rawmidi_file->input->runtime) rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR); if (rawmidi_file->output && rawmidi_file->output->runtime) rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR); #endif - remove_wait_queue(&rmidi->open_wait, &wait); - if (err >= 0) { - file->private_data = rawmidi_file; - } else { - snd_card_file_remove(card, file); - kfree(rawmidi_file); - } + file->private_data = rawmidi_file; mutex_unlock(&rmidi->open_mutex); + snd_card_unref(rmidi->card); + return 0; + + __error: + snd_card_file_remove(card, file); + __error_card: + mutex_unlock(&rmidi->open_mutex); + module_put(rmidi->card->module); + snd_card_unref(rmidi->card); return err; } -int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile) +static void close_substream(struct snd_rawmidi *rmidi, + struct snd_rawmidi_substream *substream, + int cleanup) { - struct snd_rawmidi *rmidi; - struct snd_rawmidi_substream *substream; - struct snd_rawmidi_runtime *runtime; + if (--substream->use_count) + return; - snd_assert(rfile != NULL, return -ENXIO); - snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO); - rmidi = rfile->rmidi; - mutex_lock(&rmidi->open_mutex); - if (rfile->input != NULL) { - substream = rfile->input; - rfile->input = NULL; - runtime = substream->runtime; - snd_rawmidi_input_trigger(substream, 0); - substream->ops->close(substream); - if (runtime->private_free != NULL) - runtime->private_free(substream); - snd_rawmidi_runtime_free(substream); - substream->opened = 0; - rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--; - } - if (rfile->output != NULL) { - substream = rfile->output; - rfile->output = NULL; - if (--substream->use_count == 0) { - runtime = substream->runtime; + if (cleanup) { + if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) + snd_rawmidi_input_trigger(substream, 0); + else { if (substream->active_sensing) { unsigned char buf = 0xfe; - /* sending single active sensing message to shut the device up */ + /* sending single active sensing message + * to shut the device up + */ snd_rawmidi_kernel_write(substream, &buf, 1); } if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) snd_rawmidi_output_trigger(substream, 0); - substream->ops->close(substream); - if (runtime->private_free != NULL) - runtime->private_free(substream); - snd_rawmidi_runtime_free(substream); - substream->opened = 0; - substream->append = 0; } - rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--; } + substream->ops->close(substream); + if (substream->runtime->private_free) + substream->runtime->private_free(substream); + snd_rawmidi_runtime_free(substream); + substream->opened = 0; + substream->append = 0; + put_pid(substream->pid); + substream->pid = NULL; + rmidi->streams[substream->stream].substream_opened--; +} + +static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) +{ + struct snd_rawmidi *rmidi; + + rmidi = rfile->rmidi; + mutex_lock(&rmidi->open_mutex); + if (rfile->input) { + close_substream(rmidi, rfile->input, 1); + rfile->input = NULL; + } + if (rfile->output) { + close_substream(rmidi, rfile->output, 1); + rfile->output = NULL; + } + rfile->rmidi = NULL; mutex_unlock(&rmidi->open_mutex); + wake_up(&rmidi->open_wait); +} + +/* called from sound/core/seq/seq_midi.c */ +int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile) +{ + struct snd_rawmidi *rmidi; + + if (snd_BUG_ON(!rfile)) + return -ENXIO; + + rmidi = rfile->rmidi; + rawmidi_release_priv(rfile); module_put(rmidi->card->module); return 0; } +EXPORT_SYMBOL(snd_rawmidi_kernel_release); static int snd_rawmidi_release(struct inode *inode, struct file *file) { struct snd_rawmidi_file *rfile; struct snd_rawmidi *rmidi; - int err; + struct module *module; rfile = file->private_data; - err = snd_rawmidi_kernel_release(rfile); rmidi = rfile->rmidi; - wake_up(&rmidi->open_wait); + rawmidi_release_priv(rfile); kfree(rfile); + module = rmidi->card->module; snd_card_file_remove(rmidi->card, file); - return err; + module_put(module); + return 0; } static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, @@ -586,6 +613,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info } return -ENXIO; } +EXPORT_SYMBOL(snd_rawmidi_info_select); static int snd_rawmidi_info_select_user(struct snd_card *card, struct snd_rawmidi_info __user *_info) @@ -621,10 +649,10 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = kmalloc(params->buffer_size, GFP_KERNEL); + newbuf = krealloc(runtime->buffer, params->buffer_size, + GFP_KERNEL); if (!newbuf) return -ENOMEM; - kfree(runtime->buffer); runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; @@ -633,6 +661,7 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, substream->active_sensing = !params->no_active_sensing; return 0; } +EXPORT_SYMBOL(snd_rawmidi_output_params); int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) @@ -648,16 +677,17 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = kmalloc(params->buffer_size, GFP_KERNEL); + newbuf = krealloc(runtime->buffer, params->buffer_size, + GFP_KERNEL); if (!newbuf) return -ENOMEM; - kfree(runtime->buffer); runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; } runtime->avail_min = params->avail_min; return 0; } +EXPORT_SYMBOL(snd_rawmidi_input_params); static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, struct snd_rawmidi_status * status) @@ -789,10 +819,9 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long return -EINVAL; } } -#ifdef CONFIG_SND_DEBUG default: - snd_printk(KERN_WARNING "rawmidi: unknown command = 0x%x\n", cmd); -#endif + rmidi_dbg(rfile->rmidi, + "rawmidi: unknown command = 0x%x\n", cmd); } return -ENOTTY; } @@ -811,6 +840,8 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)argp)) return -EFAULT; + if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */ + device = SNDRV_RAWMIDI_DEVICES - 1; mutex_lock(®ister_mutex); device = device < 0 ? 0 : device + 1; while (device < SNDRV_RAWMIDI_DEVICES) { @@ -848,7 +879,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, * * Reads the data from the internal buffer. * - * Returns the size of read data, or a negative error code on failure. + * Return: The size of read data, or a negative error code on failure. */ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, const unsigned char *buffer, int count) @@ -857,8 +888,11 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, int result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; + if (!substream->opened) + return -EBADFD; if (runtime->buffer == NULL) { - snd_printd("snd_rawmidi_receive: input is not active!!!\n"); + rmidi_dbg(substream->rmidi, + "snd_rawmidi_receive: input is not active!!!\n"); return -EINVAL; } spin_lock_irqsave(&runtime->lock, flags); @@ -902,13 +936,14 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, } if (result > 0) { if (runtime->event) - tasklet_hi_schedule(&runtime->tasklet); + schedule_work(&runtime->event_work); else if (snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } spin_unlock_irqrestore(&runtime->lock, flags); return result; } +EXPORT_SYMBOL(snd_rawmidi_receive); static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned char __user *userbuf, @@ -951,6 +986,7 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream, snd_rawmidi_input_trigger(substream, 1); return snd_rawmidi_kernel_read1(substream, NULL/*userbuf*/, buf, count); } +EXPORT_SYMBOL(snd_rawmidi_kernel_read); static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, loff_t *offset) @@ -982,6 +1018,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun spin_unlock_irq(&runtime->lock); schedule(); remove_wait_queue(&runtime->sleep, &wait); + if (rfile->rmidi->card->shutdown) + return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail) @@ -1005,8 +1043,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun /** * snd_rawmidi_transmit_empty - check whether the output buffer is empty * @substream: the rawmidi substream - * - * Returns 1 if the internal output buffer is empty, 0 if not. + * + * Return: 1 if the internal output buffer is empty, 0 if not. */ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) { @@ -1015,7 +1053,8 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) unsigned long flags; if (runtime->buffer == NULL) { - snd_printd("snd_rawmidi_transmit_empty: output is not active!!!\n"); + rmidi_dbg(substream->rmidi, + "snd_rawmidi_transmit_empty: output is not active!!!\n"); return 1; } spin_lock_irqsave(&runtime->lock, flags); @@ -1023,6 +1062,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) spin_unlock_irqrestore(&runtime->lock, flags); return result; } +EXPORT_SYMBOL(snd_rawmidi_transmit_empty); /** * snd_rawmidi_transmit_peek - copy data from the internal buffer @@ -1036,7 +1076,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) * and call snd_rawmidi_transmit_ack() after the transmission is * finished. * - * Returns the size of copied data, or a negative error code on failure. + * Return: The size of copied data, or a negative error code on failure. */ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) @@ -1046,7 +1086,8 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, struct snd_rawmidi_runtime *runtime = substream->runtime; if (runtime->buffer == NULL) { - snd_printd("snd_rawmidi_transmit_peek: output is not active!!!\n"); + rmidi_dbg(substream->rmidi, + "snd_rawmidi_transmit_peek: output is not active!!!\n"); return -EINVAL; } result = 0; @@ -1078,17 +1119,18 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, spin_unlock_irqrestore(&runtime->lock, flags); return result; } +EXPORT_SYMBOL(snd_rawmidi_transmit_peek); /** * snd_rawmidi_transmit_ack - acknowledge the transmission * @substream: the rawmidi substream - * @count: the tranferred count + * @count: the transferred count * * Advances the hardware pointer for the internal output buffer with * the given size and updates the condition. * Call after the transmission is finished. * - * Returns the advanced size if successful, or a negative error code on failure. + * Return: The advanced size if successful, or a negative error code on failure. */ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) { @@ -1096,11 +1138,12 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) struct snd_rawmidi_runtime *runtime = substream->runtime; if (runtime->buffer == NULL) { - snd_printd("snd_rawmidi_transmit_ack: output is not active!!!\n"); + rmidi_dbg(substream->rmidi, + "snd_rawmidi_transmit_ack: output is not active!!!\n"); return -EINVAL; } spin_lock_irqsave(&runtime->lock, flags); - snd_assert(runtime->avail + count <= runtime->buffer_size, ); + snd_BUG_ON(runtime->avail + count > runtime->buffer_size); runtime->hw_ptr += count; runtime->hw_ptr %= runtime->buffer_size; runtime->avail += count; @@ -1112,6 +1155,7 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) spin_unlock_irqrestore(&runtime->lock, flags); return count; } +EXPORT_SYMBOL(snd_rawmidi_transmit_ack); /** * snd_rawmidi_transmit - copy from the buffer to the device @@ -1121,16 +1165,19 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) * * Copies data from the buffer to the device and advances the pointer. * - * Returns the copied size if successful, or a negative error code on failure. + * Return: The copied size if successful, or a negative error code on failure. */ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { + if (!substream->opened) + return -EBADFD; count = snd_rawmidi_transmit_peek(substream, buffer, count); if (count < 0) return count; return snd_rawmidi_transmit_ack(substream, count); } +EXPORT_SYMBOL(snd_rawmidi_transmit); static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, const unsigned char __user *userbuf, @@ -1141,8 +1188,10 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, long count1, result; struct snd_rawmidi_runtime *runtime = substream->runtime; - snd_assert(kernelbuf != NULL || userbuf != NULL, return -EINVAL); - snd_assert(runtime->buffer != NULL, return -EINVAL); + if (snd_BUG_ON(!kernelbuf && !userbuf)) + return -EINVAL; + if (snd_BUG_ON(!runtime->buffer)) + return -EINVAL; result = 0; spin_lock_irqsave(&runtime->lock, flags); @@ -1190,6 +1239,7 @@ long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream, { return snd_rawmidi_kernel_write1(substream, NULL, buf, count); } +EXPORT_SYMBOL(snd_rawmidi_kernel_write); static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) @@ -1221,6 +1271,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, spin_unlock_irq(&runtime->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); + if (rfile->rmidi->card->shutdown) + return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail && !timeout) @@ -1237,7 +1289,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, break; count -= count1; } - if (file->f_flags & O_SYNC) { + if (file->f_flags & O_DSYNC) { spin_lock_irq(&runtime->lock); while (runtime->avail != runtime->buffer_size) { wait_queue_t wait; @@ -1319,6 +1371,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, substream->number, (unsigned long) substream->bytes); if (substream->opened) { + snd_iprintf(buffer, + " Owner PID : %d\n", + pid_vnr(substream->pid)); runtime = substream->runtime; snd_iprintf(buffer, " Mode : %s\n" @@ -1340,6 +1395,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, substream->number, (unsigned long) substream->bytes); if (substream->opened) { + snd_iprintf(buffer, + " Owner PID : %d\n", + pid_vnr(substream->pid)); runtime = substream->runtime; snd_iprintf(buffer, " Buffer size : %lu\n" @@ -1365,6 +1423,7 @@ static const struct file_operations snd_rawmidi_f_ops = .write = snd_rawmidi_write, .open = snd_rawmidi_open, .release = snd_rawmidi_release, + .llseek = no_llseek, .poll = snd_rawmidi_poll, .unlocked_ioctl = snd_rawmidi_ioctl, .compat_ioctl = snd_rawmidi_ioctl_compat, @@ -1381,7 +1440,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, for (idx = 0; idx < count; idx++) { substream = kzalloc(sizeof(*substream), GFP_KERNEL); if (substream == NULL) { - snd_printk(KERN_ERR "rawmidi: cannot allocate substream\n"); + rmidi_err(rmidi, "rawmidi: cannot allocate substream\n"); return -ENOMEM; } substream->stream = direction; @@ -1406,7 +1465,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, * Creates a new rawmidi instance. * Use snd_rawmidi_set_ops() to set the operators to the new instance. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_rawmidi_new(struct snd_card *card, char *id, int device, int output_count, int input_count, @@ -1420,12 +1479,13 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, .dev_disconnect = snd_rawmidi_dev_disconnect, }; - snd_assert(rrawmidi != NULL, return -EINVAL); - *rrawmidi = NULL; - snd_assert(card != NULL, return -ENXIO); + if (snd_BUG_ON(!card)) + return -ENXIO; + if (rrawmidi) + *rrawmidi = NULL; rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); if (rmidi == NULL) { - snd_printk(KERN_ERR "rawmidi: cannot allocate\n"); + dev_err(card->dev, "rawmidi: cannot allocate\n"); return -ENOMEM; } rmidi->card = card; @@ -1455,9 +1515,11 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, snd_rawmidi_free(rmidi); return err; } - *rrawmidi = rmidi; + if (rrawmidi) + *rrawmidi = rmidi; return 0; } +EXPORT_SYMBOL(snd_rawmidi_new); static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) { @@ -1472,7 +1534,8 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) static int snd_rawmidi_free(struct snd_rawmidi *rmidi) { - snd_assert(rmidi != NULL, return -ENXIO); + if (!rmidi) + return 0; snd_info_free_entry(rmidi->proc_entry); rmidi->proc_entry = NULL; @@ -1522,7 +1585,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device) if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device, &snd_rawmidi_f_ops, rmidi, name)) < 0) { - snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device); + rmidi_err(rmidi, "unable to register rawmidi device %i:%i\n", + rmidi->card->number, rmidi->device); list_del(&rmidi->list); mutex_unlock(®ister_mutex); return err; @@ -1539,8 +1603,10 @@ static int snd_rawmidi_dev_register(struct snd_device *device) if ((int)rmidi->device == midi_map[rmidi->card->number]) { if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0, &snd_rawmidi_f_ops, - rmidi, name) < 0) { - snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0); + rmidi) < 0) { + rmidi_err(rmidi, + "unable to register OSS rawmidi device %i:%i\n", + rmidi->card->number, 0); } else { rmidi->ossreg++; #ifdef SNDRV_OSS_INFO_DEV_MIDI @@ -1551,8 +1617,10 @@ static int snd_rawmidi_dev_register(struct snd_device *device) if ((int)rmidi->device == amidi_map[rmidi->card->number]) { if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1, &snd_rawmidi_f_ops, - rmidi, name) < 0) { - snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1); + rmidi) < 0) { + rmidi_err(rmidi, + "unable to register OSS rawmidi device %i:%i\n", + rmidi->card->number, 1); } else { rmidi->ossreg++; } @@ -1586,9 +1654,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device) static int snd_rawmidi_dev_disconnect(struct snd_device *device) { struct snd_rawmidi *rmidi = device->device_data; + int dir; mutex_lock(®ister_mutex); + mutex_lock(&rmidi->open_mutex); + wake_up(&rmidi->open_wait); list_del_init(&rmidi->list); + for (dir = 0; dir < 2; dir++) { + struct snd_rawmidi_substream *s; + list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { + if (s->runtime) + wake_up(&s->runtime->sleep); + } + } + #ifdef CONFIG_SND_OSSEMUL if (rmidi->ossreg) { if ((int)rmidi->device == midi_map[rmidi->card->number]) { @@ -1603,6 +1682,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) } #endif /* CONFIG_SND_OSSEMUL */ snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); + mutex_unlock(&rmidi->open_mutex); mutex_unlock(®ister_mutex); return 0; } @@ -1623,6 +1703,7 @@ void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, list_for_each_entry(substream, &rmidi->streams[stream].substreams, list) substream->ops = ops; } +EXPORT_SYMBOL(snd_rawmidi_set_ops); /* * ENTRY functions @@ -1638,11 +1719,13 @@ static int __init alsa_rawmidi_init(void) /* check device map table */ for (i = 0; i < SNDRV_CARDS; i++) { if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) { - snd_printk(KERN_ERR "invalid midi_map[%d] = %d\n", i, midi_map[i]); + pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n", + i, midi_map[i]); midi_map[i] = 0; } if (amidi_map[i] < 0 || amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) { - snd_printk(KERN_ERR "invalid amidi_map[%d] = %d\n", i, amidi_map[i]); + pr_err("ALSA: rawmidi: invalid amidi_map[%d] = %d\n", + i, amidi_map[i]); amidi_map[i] = 1; } } @@ -1659,21 +1742,3 @@ static void __exit alsa_rawmidi_exit(void) module_init(alsa_rawmidi_init) module_exit(alsa_rawmidi_exit) - -EXPORT_SYMBOL(snd_rawmidi_output_params); -EXPORT_SYMBOL(snd_rawmidi_input_params); -EXPORT_SYMBOL(snd_rawmidi_drop_output); -EXPORT_SYMBOL(snd_rawmidi_drain_output); -EXPORT_SYMBOL(snd_rawmidi_drain_input); -EXPORT_SYMBOL(snd_rawmidi_receive); -EXPORT_SYMBOL(snd_rawmidi_transmit_empty); -EXPORT_SYMBOL(snd_rawmidi_transmit_peek); -EXPORT_SYMBOL(snd_rawmidi_transmit_ack); -EXPORT_SYMBOL(snd_rawmidi_transmit); -EXPORT_SYMBOL(snd_rawmidi_new); -EXPORT_SYMBOL(snd_rawmidi_set_ops); -EXPORT_SYMBOL(snd_rawmidi_info_select); -EXPORT_SYMBOL(snd_rawmidi_kernel_open); -EXPORT_SYMBOL(snd_rawmidi_kernel_release); -EXPORT_SYMBOL(snd_rawmidi_kernel_read); -EXPORT_SYMBOL(snd_rawmidi_kernel_write); |
