diff options
Diffstat (limited to 'sound/core/rawmidi.c')
-rw-r--r-- | sound/core/rawmidi.c | 698 |
1 files changed, 452 insertions, 246 deletions
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 2a688b711a9a..7accf9a1ddf4 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -21,6 +21,7 @@ #include <sound/control.h> #include <sound/minors.h> #include <sound/initval.h> +#include <sound/ump.h> MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA."); @@ -35,7 +36,6 @@ module_param_array(amidi_map, int, NULL, 0444); MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device."); #endif /* CONFIG_SND_OSSEMUL */ -static int snd_rawmidi_free(struct snd_rawmidi *rawmidi); static int snd_rawmidi_dev_free(struct snd_device *device); static int snd_rawmidi_dev_register(struct snd_device *device); static int snd_rawmidi_dev_disconnect(struct snd_device *device); @@ -44,11 +44,11 @@ static LIST_HEAD(snd_rawmidi_devices); static DEFINE_MUTEX(register_mutex); #define rmidi_err(rmidi, fmt, args...) \ - dev_err(&(rmidi)->dev, fmt, ##args) + dev_err((rmidi)->dev, fmt, ##args) #define rmidi_warn(rmidi, fmt, args...) \ - dev_warn(&(rmidi)->dev, fmt, ##args) + dev_warn((rmidi)->dev, fmt, ##args) #define rmidi_dbg(rmidi, fmt, args...) \ - dev_dbg(&(rmidi)->dev, fmt, ##args) + dev_dbg((rmidi)->dev, fmt, ##args) struct snd_rawmidi_status32 { s32 stream; @@ -73,6 +73,9 @@ struct snd_rawmidi_status64 { #define SNDRV_RAWMIDI_IOCTL_STATUS64 _IOWR('W', 0x20, struct snd_rawmidi_status64) +#define rawmidi_is_ump(rmidi) \ + (IS_ENABLED(CONFIG_SND_UMP) && ((rmidi)->info_flags & SNDRV_RAWMIDI_INFO_UMP)) + static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) { struct snd_rawmidi *rawmidi; @@ -95,13 +98,17 @@ static inline unsigned short snd_rawmidi_file_flags(struct file *file) } } -static inline int snd_rawmidi_ready(struct snd_rawmidi_substream *substream) +static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime) { - struct snd_rawmidi_runtime *runtime = substream->runtime; - return runtime->avail >= runtime->avail_min; } +static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream) +{ + guard(spinlock_irqsave)(&substream->lock); + return __snd_rawmidi_ready(substream->runtime); +} + static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream, size_t count) { @@ -120,7 +127,7 @@ static void snd_rawmidi_input_event_work(struct work_struct *work) runtime->event(runtime->substream); } -/* buffer refcount management: call with runtime->lock held */ +/* buffer refcount management: call with substream->lock held */ static inline void snd_rawmidi_buffer_ref(struct snd_rawmidi_runtime *runtime) { runtime->buffer_ref++; @@ -131,6 +138,23 @@ static inline void snd_rawmidi_buffer_unref(struct snd_rawmidi_runtime *runtime) runtime->buffer_ref--; } +static void snd_rawmidi_buffer_ref_sync(struct snd_rawmidi_substream *substream) +{ + int loop = HZ; + + spin_lock_irq(&substream->lock); + while (substream->runtime->buffer_ref) { + spin_unlock_irq(&substream->lock); + if (!--loop) { + rmidi_err(substream->rmidi, "Buffer ref sync timeout\n"); + return; + } + schedule_timeout_uninterruptible(1); + spin_lock_irq(&substream->lock); + } + spin_unlock_irq(&substream->lock); +} + static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime; @@ -139,7 +163,6 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) if (!runtime) return -ENOMEM; runtime->substream = substream; - spin_lock_init(&runtime->lock); init_waitqueue_head(&runtime->sleep); INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); runtime->event = NULL; @@ -156,9 +179,23 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) } runtime->appl_ptr = runtime->hw_ptr = 0; substream->runtime = runtime; + if (rawmidi_is_ump(substream->rmidi)) + runtime->align = 3; return 0; } +/* get the current alignment (either 0 or 3) */ +static inline int get_align(struct snd_rawmidi_runtime *runtime) +{ + if (IS_ENABLED(CONFIG_SND_UMP)) + return runtime->align; + else + return 0; +} + +/* get the trimmed size with the current alignment */ +#define get_aligned_size(runtime, size) ((size) & ~get_align(runtime)) + static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -193,44 +230,52 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, runtime->avail = is_input ? 0 : runtime->buffer_size; } -static void reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, +static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream, bool is_input) { - unsigned long flags; - - spin_lock_irqsave(&runtime->lock, flags); - __reset_runtime_ptrs(runtime, is_input); - spin_unlock_irqrestore(&runtime->lock, flags); + guard(spinlock_irqsave)(&substream->lock); + if (substream->opened && substream->runtime) + __reset_runtime_ptrs(substream->runtime, is_input); } int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) { snd_rawmidi_output_trigger(substream, 0); - reset_runtime_ptrs(substream->runtime, false); + reset_runtime_ptrs(substream, false); return 0; } EXPORT_SYMBOL(snd_rawmidi_drop_output); int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) { - int err; + int err = 0; long timeout; - struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_runtime *runtime; + + scoped_guard(spinlock_irq, &substream->lock) { + runtime = substream->runtime; + if (!substream->opened || !runtime || !runtime->buffer) + return -EINVAL; + snd_rawmidi_buffer_ref(runtime); + runtime->drain = 1; + } - err = 0; - runtime->drain = 1; timeout = wait_event_interruptible_timeout(runtime->sleep, (runtime->avail >= runtime->buffer_size), 10*HZ); - if (signal_pending(current)) - err = -ERESTARTSYS; - if (runtime->avail < runtime->buffer_size && !timeout) { - rmidi_warn(substream->rmidi, - "rawmidi drain error (avail = %li, buffer_size = %li)\n", - (long)runtime->avail, (long)runtime->buffer_size); - err = -EIO; + + scoped_guard(spinlock_irq, &substream->lock) { + if (signal_pending(current)) + err = -ERESTARTSYS; + if (runtime->avail < runtime->buffer_size && !timeout) { + 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; } - runtime->drain = 0; + if (err != -ERESTARTSYS) { /* we need wait a while to make sure that Tx FIFOs are empty */ if (substream->ops->drain) @@ -239,6 +284,10 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) msleep(50); snd_rawmidi_drop_output(substream); } + + scoped_guard(spinlock_irq, &substream->lock) + snd_rawmidi_buffer_unref(runtime); + return err; } EXPORT_SYMBOL(snd_rawmidi_drain_output); @@ -246,7 +295,7 @@ EXPORT_SYMBOL(snd_rawmidi_drain_output); int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) { snd_rawmidi_input_trigger(substream, 0); - reset_runtime_ptrs(substream->runtime, true); + reset_runtime_ptrs(substream, true); return 0; } EXPORT_SYMBOL(snd_rawmidi_drain_input); @@ -301,6 +350,7 @@ static int open_substream(struct snd_rawmidi *rmidi, snd_rawmidi_runtime_free(substream); return err; } + guard(spinlock_irq)(&substream->lock); substream->opened = 1; substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) @@ -359,28 +409,18 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, } /* called from sound/core/seq/seq_midi.c */ -int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, +int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice, int mode, struct snd_rawmidi_file *rfile) { - struct snd_rawmidi *rmidi; - int err = 0; + int err; if (snd_BUG_ON(!rfile)) return -EINVAL; + if (!try_module_get(rmidi->card->module)) + return -ENXIO; - mutex_lock(®ister_mutex); - rmidi = snd_rawmidi_search(card, device); - if (!rmidi) - err = -ENODEV; - else if (!try_module_get(rmidi->card->module)) - err = -ENXIO; - mutex_unlock(®ister_mutex); - if (err < 0) - return err; - - mutex_lock(&rmidi->open_mutex); + guard(mutex)(&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; @@ -437,6 +477,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) err = -ENOMEM; goto __error; } + rawmidi_file->user_pversion = 0; init_waitqueue_entry(&wait, current); add_wait_queue(&rmidi->open_wait, &wait); while (1) { @@ -510,13 +551,16 @@ static void close_substream(struct snd_rawmidi *rmidi, if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) snd_rawmidi_output_trigger(substream, 0); } + snd_rawmidi_buffer_ref_sync(substream); + } + scoped_guard(spinlock_irq, &substream->lock) { + substream->opened = 0; + substream->append = 0; } 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--; @@ -527,7 +571,7 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) struct snd_rawmidi *rmidi; rmidi = rfile->rmidi; - mutex_lock(&rmidi->open_mutex); + guard(mutex)(&rmidi->open_mutex); if (rfile->input) { close_substream(rmidi, rfile->input, 1); rfile->input = NULL; @@ -537,7 +581,6 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) rfile->output = NULL; } rfile->rmidi = NULL; - mutex_unlock(&rmidi->open_mutex); wake_up(&rmidi->open_wait); } @@ -636,12 +679,8 @@ static int __snd_rawmidi_info_select(struct snd_card *card, int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info) { - int ret; - - mutex_lock(®ister_mutex); - ret = __snd_rawmidi_info_select(card, info); - mutex_unlock(®ister_mutex); - return ret; + guard(mutex)(®ister_mutex); + return __snd_rawmidi_info_select(card, info); } EXPORT_SYMBOL(snd_rawmidi_info_select); @@ -665,23 +704,28 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, return 0; } -static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, +static int resize_runtime_buffer(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params *params, bool is_input) { + struct snd_rawmidi_runtime *runtime = substream->runtime; char *newbuf, *oldbuf; + unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) return -EINVAL; + if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP && (params->buffer_size & 0x1f) != 0) + return -EINVAL; if (params->avail_min < 1 || params->avail_min > params->buffer_size) return -EINVAL; + if (params->buffer_size & get_align(runtime)) + return -EINVAL; if (params->buffer_size != runtime->buffer_size) { newbuf = kvzalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; - spin_lock_irq(&runtime->lock); + guard(spinlock_irq)(&substream->lock); if (runtime->buffer_ref) { - spin_unlock_irq(&runtime->lock); kvfree(newbuf); return -EBUSY; } @@ -689,7 +733,6 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; __reset_runtime_ptrs(runtime, is_input); - spin_unlock_irq(&runtime->lock); kvfree(oldbuf); } runtime->avail_min = params->avail_min; @@ -699,19 +742,42 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params *params) { + int err; + + snd_rawmidi_drain_output(substream); + guard(mutex)(&substream->rmidi->open_mutex); if (substream->append && substream->use_count > 1) return -EBUSY; - snd_rawmidi_drain_output(substream); - substream->active_sensing = !params->no_active_sensing; - return resize_runtime_buffer(substream->runtime, params, false); + err = resize_runtime_buffer(substream, params, false); + if (!err) + substream->active_sensing = !params->no_active_sensing; + return err; } EXPORT_SYMBOL(snd_rawmidi_output_params); int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params *params) { + unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; + unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK; + int err; + snd_rawmidi_drain_input(substream); - return resize_runtime_buffer(substream->runtime, params, true); + guard(mutex)(&substream->rmidi->open_mutex); + if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE) + err = -EINVAL; + else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW) + err = -EINVAL; + else if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) + err = -EINVAL; + else + err = resize_runtime_buffer(substream, params, true); + + if (!err) { + substream->framing = framing; + substream->clock_type = clock_type; + } + return 0; } EXPORT_SYMBOL(snd_rawmidi_input_params); @@ -722,9 +788,8 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; - spin_lock_irq(&runtime->lock); + guard(spinlock_irq)(&substream->lock); status->avail = runtime->avail; - spin_unlock_irq(&runtime->lock); return 0; } @@ -735,11 +800,10 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_INPUT; - spin_lock_irq(&runtime->lock); + guard(spinlock_irq)(&substream->lock); status->avail = runtime->avail; status->xruns = runtime->xruns; runtime->xruns = 0; - spin_unlock_irq(&runtime->lock); return 0; } @@ -820,6 +884,7 @@ static int snd_rawmidi_ioctl_status64(struct snd_rawmidi_file *rfile, static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_rawmidi_file *rfile; + struct snd_rawmidi *rmidi; void __user *argp = (void __user *)arg; rfile = file->private_data; @@ -844,12 +909,21 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long return -EINVAL; } } + case SNDRV_RAWMIDI_IOCTL_USER_PVERSION: + if (get_user(rfile->user_pversion, (unsigned int __user *)arg)) + return -EFAULT; + return 0; + case SNDRV_RAWMIDI_IOCTL_PARAMS: { struct snd_rawmidi_params params; if (copy_from_user(¶ms, argp, sizeof(struct snd_rawmidi_params))) return -EFAULT; + if (rfile->user_pversion < SNDRV_PROTOCOL_VERSION(2, 0, 2)) { + params.mode = 0; + memset(params.reserved, 0, sizeof(params.reserved)); + } switch (params.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: if (rfile->output == NULL) @@ -902,12 +976,65 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long } } default: - rmidi_dbg(rfile->rmidi, - "rawmidi: unknown command = 0x%x\n", cmd); + rmidi = rfile->rmidi; + if (rmidi->ops && rmidi->ops->ioctl) + return rmidi->ops->ioctl(rmidi, cmd, argp); + rmidi_dbg(rmidi, "rawmidi: unknown command = 0x%x\n", cmd); } return -ENOTTY; } +/* ioctl to find the next device; either legacy or UMP depending on @find_ump */ +static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp, + bool find_ump) + +{ + struct snd_rawmidi *rmidi; + int device; + bool is_ump; + + if (get_user(device, argp)) + return -EFAULT; + if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */ + device = SNDRV_RAWMIDI_DEVICES - 1; + scoped_guard(mutex, ®ister_mutex) { + device = device < 0 ? 0 : device + 1; + for (; device < SNDRV_RAWMIDI_DEVICES; device++) { + rmidi = snd_rawmidi_search(card, device); + if (!rmidi) + continue; + is_ump = rawmidi_is_ump(rmidi); + if (find_ump == is_ump) + break; + } + if (device == SNDRV_RAWMIDI_DEVICES) + device = -1; + } + if (put_user(device, argp)) + return -EFAULT; + return 0; +} + +#if IS_ENABLED(CONFIG_SND_UMP) +/* inquiry of UMP endpoint and block info via control API */ +static int snd_rawmidi_call_ump_ioctl(struct snd_card *card, int cmd, + void __user *argp) +{ + struct snd_ump_endpoint_info __user *info = argp; + struct snd_rawmidi *rmidi; + int device; + + if (get_user(device, &info->device)) + return -EFAULT; + guard(mutex)(®ister_mutex); + rmidi = snd_rawmidi_search(card, device); + if (rmidi && rmidi->ops && rmidi->ops->ioctl) + return rmidi->ops->ioctl(rmidi, cmd, argp); + else + return -ENXIO; +} +#endif + static int snd_rawmidi_control_ioctl(struct snd_card *card, struct snd_ctl_file *control, unsigned int cmd, @@ -917,27 +1044,15 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, switch (cmd) { case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE: - { - int device; - - 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) { - if (snd_rawmidi_search(card, device)) - break; - device++; - } - if (device == SNDRV_RAWMIDI_DEVICES) - device = -1; - mutex_unlock(®ister_mutex); - if (put_user(device, (int __user *)argp)) - return -EFAULT; - return 0; - } + return snd_rawmidi_next_device(card, argp, false); +#if IS_ENABLED(CONFIG_SND_UMP) + case SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE: + return snd_rawmidi_next_device(card, argp, true); + case SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO: + return snd_rawmidi_call_ump_ioctl(card, SNDRV_UMP_IOCTL_ENDPOINT_INFO, argp); + case SNDRV_CTL_IOCTL_UMP_BLOCK_INFO: + return snd_rawmidi_call_ump_ioctl(card, SNDRV_UMP_IOCTL_BLOCK_INFO, argp); +#endif case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: { int val; @@ -953,6 +1068,63 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, return -ENOIOCTLCMD; } +static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream, + const unsigned char *buffer, int src_count, const struct timespec64 *tstamp) +{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_framing_tstamp *dest_ptr; + struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec }; + int orig_count = src_count; + int frame_size = sizeof(struct snd_rawmidi_framing_tstamp); + int align = get_align(runtime); + + BUILD_BUG_ON(frame_size != 0x20); + if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0)) + return -EINVAL; + + while (src_count > align) { + if ((int)(runtime->buffer_size - runtime->avail) < frame_size) { + runtime->xruns += src_count; + break; + } + if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH) + frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH; + else { + frame.length = get_aligned_size(runtime, src_count); + if (!frame.length) + break; + memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH); + } + memcpy(frame.data, buffer, frame.length); + buffer += frame.length; + src_count -= frame.length; + dest_ptr = (struct snd_rawmidi_framing_tstamp *) (runtime->buffer + runtime->hw_ptr); + *dest_ptr = frame; + runtime->avail += frame_size; + runtime->hw_ptr += frame_size; + runtime->hw_ptr %= runtime->buffer_size; + } + return orig_count - src_count; +} + +static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substream) +{ + struct timespec64 ts64 = {0, 0}; + + switch (substream->clock_type) { + case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW: + ktime_get_raw_ts64(&ts64); + break; + case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC: + ktime_get_ts64(&ts64); + break; + case SNDRV_RAWMIDI_MODE_CLOCK_REALTIME: + ktime_get_real_ts64(&ts64); + break; + } + return ts64; +} + /** * snd_rawmidi_receive - receive the input data from the device * @substream: the rawmidi substream @@ -966,19 +1138,27 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, const unsigned char *buffer, int count) { - unsigned long flags; + struct timespec64 ts64 = get_framing_tstamp(substream); int result = 0, count1; - struct snd_rawmidi_runtime *runtime = substream->runtime; + struct snd_rawmidi_runtime *runtime; + guard(spinlock_irqsave)(&substream->lock); if (!substream->opened) return -EBADFD; - if (runtime->buffer == NULL) { + runtime = substream->runtime; + if (!runtime || !runtime->buffer) { rmidi_dbg(substream->rmidi, "snd_rawmidi_receive: input is not active!!!\n"); return -EINVAL; } - spin_lock_irqsave(&runtime->lock, flags); - if (count == 1) { /* special case, faster code */ + + count = get_aligned_size(runtime, count); + if (!count) + return result; + + if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { + result = receive_with_tstamp_framing(substream, buffer, count, &ts64); + } else if (count == 1) { /* special case, faster code */ substream->bytes++; if (runtime->avail < runtime->buffer_size) { runtime->buffer[runtime->hw_ptr++] = buffer[0]; @@ -995,6 +1175,9 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) count1 = runtime->buffer_size - runtime->avail; + count1 = get_aligned_size(runtime, count1); + if (!count1) + return result; memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1); runtime->hw_ptr += count1; runtime->hw_ptr %= runtime->buffer_size; @@ -1019,10 +1202,9 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, if (result > 0) { if (runtime->event) schedule_work(&runtime->event_work); - else if (snd_rawmidi_ready(substream)) + else if (__snd_rawmidi_ready(runtime)) wake_up(&runtime->sleep); } - spin_unlock_irqrestore(&runtime->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_receive); @@ -1037,7 +1219,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned long appl_ptr; int err = 0; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); snd_rawmidi_buffer_ref(runtime); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; @@ -1055,11 +1237,11 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, if (kernelbuf) memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (copy_to_user(userbuf + result, runtime->buffer + appl_ptr, count1)) err = -EFAULT; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (err) goto out; } @@ -1068,7 +1250,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, } out: snd_rawmidi_buffer_unref(runtime); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result > 0 ? result : err; } @@ -1097,29 +1279,31 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun snd_rawmidi_input_trigger(substream, 1); result = 0; while (count > 0) { - spin_lock_irq(&runtime->lock); - while (!snd_rawmidi_ready(substream)) { + spin_lock_irq(&substream->lock); + while (!__snd_rawmidi_ready(runtime)) { wait_queue_entry_t wait; if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EAGAIN; } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->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) + spin_lock_irq(&substream->lock); + if (!runtime->avail) { + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EIO; - spin_lock_irq(&runtime->lock); + } } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); count1 = snd_rawmidi_kernel_read1(substream, (unsigned char __user *)buf, NULL/*kernelbuf*/, @@ -1141,23 +1325,20 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun */ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) { - struct snd_rawmidi_runtime *runtime = substream->runtime; - int result; - unsigned long flags; + struct snd_rawmidi_runtime *runtime; - if (runtime->buffer == NULL) { + guard(spinlock_irqsave)(&substream->lock); + runtime = substream->runtime; + if (!substream->opened || !runtime || !runtime->buffer) { rmidi_dbg(substream->rmidi, "snd_rawmidi_transmit_empty: output is not active!!!\n"); return 1; } - spin_lock_irqsave(&runtime->lock, flags); - result = runtime->avail >= runtime->buffer_size; - spin_unlock_irqrestore(&runtime->lock, flags); - return result; + return (runtime->avail >= runtime->buffer_size); } EXPORT_SYMBOL(snd_rawmidi_transmit_empty); -/** +/* * __snd_rawmidi_transmit_peek - copy data from the internal buffer * @substream: the rawmidi substream * @buffer: the buffer pointer @@ -1165,8 +1346,8 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_empty); * * This is a variant of snd_rawmidi_transmit_peek() without spinlock. */ -int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, - unsigned char *buffer, int count) +static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, + unsigned char *buffer, int count) { int result, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -1190,12 +1371,18 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) count1 = runtime->buffer_size - runtime->avail; + count1 = get_aligned_size(runtime, count1); + if (!count1) + goto __skip; memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1); count -= count1; result += count1; if (count > 0) { if (count > (int)(runtime->buffer_size - runtime->avail - count1)) count = runtime->buffer_size - runtime->avail - count1; + count = get_aligned_size(runtime, count); + if (!count) + goto __skip; memcpy(buffer + count1, runtime->buffer, count); result += count; } @@ -1203,7 +1390,6 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, __skip: return result; } -EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); /** * snd_rawmidi_transmit_peek - copy data from the internal buffer @@ -1222,25 +1408,22 @@ EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; - int result; - unsigned long flags; - - spin_lock_irqsave(&runtime->lock, flags); - result = __snd_rawmidi_transmit_peek(substream, buffer, count); - spin_unlock_irqrestore(&runtime->lock, flags); - return result; + guard(spinlock_irqsave)(&substream->lock); + if (!substream->opened || !substream->runtime) + return -EBADFD; + return __snd_rawmidi_transmit_peek(substream, buffer, count); } EXPORT_SYMBOL(snd_rawmidi_transmit_peek); -/** +/* * __snd_rawmidi_transmit_ack - acknowledge the transmission * @substream: the rawmidi substream * @count: the transferred count * * This is a variant of __snd_rawmidi_transmit_ack() without spinlock. */ -int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) +static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, + int count) { struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -1250,17 +1433,17 @@ int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int coun return -EINVAL; } snd_BUG_ON(runtime->avail + count > runtime->buffer_size); + count = get_aligned_size(runtime, count); runtime->hw_ptr += count; runtime->hw_ptr %= runtime->buffer_size; runtime->avail += count; substream->bytes += count; if (count > 0) { - if (runtime->drain || snd_rawmidi_ready(substream)) + if (runtime->drain || __snd_rawmidi_ready(runtime)) wake_up(&runtime->sleep); } return count; } -EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); /** * snd_rawmidi_transmit_ack - acknowledge the transmission @@ -1275,14 +1458,10 @@ EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); */ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; - int result; - unsigned long flags; - - spin_lock_irqsave(&runtime->lock, flags); - result = __snd_rawmidi_transmit_ack(substream, count); - spin_unlock_irqrestore(&runtime->lock, flags); - return result; + guard(spinlock_irqsave)(&substream->lock); + if (!substream->opened || !substream->runtime) + return -EBADFD; + return __snd_rawmidi_transmit_ack(substream, count); } EXPORT_SYMBOL(snd_rawmidi_transmit_ack); @@ -1299,22 +1478,13 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack); int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; - int result; - unsigned long flags; - - spin_lock_irqsave(&runtime->lock, flags); + guard(spinlock_irqsave)(&substream->lock); if (!substream->opened) - result = -EBADFD; - else { - count = __snd_rawmidi_transmit_peek(substream, buffer, count); - if (count <= 0) - result = count; - else - result = __snd_rawmidi_transmit_ack(substream, count); - } - spin_unlock_irqrestore(&runtime->lock, flags); - return result; + 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); @@ -1326,16 +1496,16 @@ EXPORT_SYMBOL(snd_rawmidi_transmit); */ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) { - struct snd_rawmidi_runtime *runtime = substream->runtime; - unsigned long flags; + struct snd_rawmidi_runtime *runtime; int count = 0; - spin_lock_irqsave(&runtime->lock, flags); - if (runtime->avail < runtime->buffer_size) { + guard(spinlock_irqsave)(&substream->lock); + runtime = substream->runtime; + if (substream->opened && runtime && + runtime->avail < runtime->buffer_size) { count = runtime->buffer_size - runtime->avail; __snd_rawmidi_transmit_ack(substream, count); } - spin_unlock_irqrestore(&runtime->lock, flags); return count; } EXPORT_SYMBOL(snd_rawmidi_proceed); @@ -1356,10 +1526,10 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, return -EINVAL; result = 0; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (substream->append) { if ((long)runtime->avail < count) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return -EAGAIN; } } @@ -1381,14 +1551,14 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); result = result > 0 ? result : -EFAULT; goto __end; } - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); } result += count1; count -= count1; @@ -1396,7 +1566,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, __end: count1 = runtime->avail < runtime->buffer_size; snd_rawmidi_buffer_unref(runtime); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (count1) snd_rawmidi_output_trigger(substream, 1); return result; @@ -1426,29 +1596,31 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, return -EIO; result = 0; while (count > 0) { - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); while (!snd_rawmidi_ready_append(substream, count)) { wait_queue_entry_t wait; if (file->f_flags & O_NONBLOCK) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EAGAIN; } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->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) + spin_lock_irq(&substream->lock); + if (!runtime->avail && !timeout) { + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EIO; - spin_lock_irq(&runtime->lock); + } } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count); if (count1 < 0) return result > 0 ? result : count1; @@ -1459,7 +1631,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, count -= count1; } if (file->f_flags & O_DSYNC) { - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); while (runtime->avail != runtime->buffer_size) { wait_queue_entry_t wait; unsigned int last_avail = runtime->avail; @@ -1467,16 +1639,16 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (runtime->avail == last_avail && !timeout) return result > 0 ? result : -EIO; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); } return result; } @@ -1526,10 +1698,18 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; + unsigned long buffer_size, avail, xruns; + unsigned int clock_type; + static const char *clock_names[4] = { "none", "realtime", "monotonic", "monotonic raw" }; rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); - mutex_lock(&rmidi->open_mutex); + if (IS_ENABLED(CONFIG_SND_UMP)) + snd_iprintf(buffer, "Type: %s\n", + rawmidi_is_ump(rmidi) ? "UMP" : "Legacy"); + if (rmidi->ops && rmidi->ops->proc_read) + rmidi->ops->proc_read(entry, buffer); + guard(mutex)(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { list_for_each_entry(substream, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, @@ -1544,13 +1724,16 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; + scoped_guard(spinlock_irq, &substream->lock) { + buffer_size = runtime->buffer_size; + avail = runtime->avail; + } snd_iprintf(buffer, " Mode : %s\n" " Buffer size : %lu\n" " Avail : %lu\n", runtime->oss ? "OSS compatible" : "native", - (unsigned long) runtime->buffer_size, - (unsigned long) runtime->avail); + buffer_size, avail); } } } @@ -1568,17 +1751,27 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; + scoped_guard(spinlock_irq, &substream->lock) { + buffer_size = runtime->buffer_size; + avail = runtime->avail; + xruns = runtime->xruns; + } snd_iprintf(buffer, " Buffer size : %lu\n" " Avail : %lu\n" " Overruns : %lu\n", - (unsigned long) runtime->buffer_size, - (unsigned long) runtime->avail, - (unsigned long) runtime->xruns); + buffer_size, avail, xruns); + if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { + clock_type = substream->clock_type >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT; + if (!snd_BUG_ON(clock_type >= ARRAY_SIZE(clock_names))) + snd_iprintf(buffer, + " Framing : tstamp\n" + " Clock type : %s\n", + clock_names[clock_type]); + } } } } - mutex_unlock(&rmidi->open_mutex); } /* @@ -1613,36 +1806,19 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, substream->number = idx; substream->rmidi = rmidi; substream->pstr = stream; + spin_lock_init(&substream->lock); list_add_tail(&substream->list, &stream->substreams); stream->substream_count++; } return 0; } -static void release_rawmidi_device(struct device *dev) +/* used for both rawmidi and ump */ +int snd_rawmidi_init(struct snd_rawmidi *rmidi, + struct snd_card *card, char *id, int device, + int output_count, int input_count, + unsigned int info_flags) { - kfree(container_of(dev, struct snd_rawmidi, dev)); -} - -/** - * snd_rawmidi_new - create a rawmidi instance - * @card: the card instance - * @id: the id string - * @device: the device index - * @output_count: the number of output streams - * @input_count: the number of input streams - * @rrawmidi: the pointer to store the new rawmidi instance - * - * Creates a new rawmidi instance. - * Use snd_rawmidi_set_ops() to set the operators to the new instance. - * - * 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, - struct snd_rawmidi **rrawmidi) -{ - struct snd_rawmidi *rmidi; int err; static const struct snd_device_ops ops = { .dev_free = snd_rawmidi_dev_free, @@ -1650,50 +1826,79 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, .dev_disconnect = snd_rawmidi_dev_disconnect, }; - if (snd_BUG_ON(!card)) - return -ENXIO; - if (rrawmidi) - *rrawmidi = NULL; - rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); - if (!rmidi) - return -ENOMEM; rmidi->card = card; rmidi->device = device; mutex_init(&rmidi->open_mutex); init_waitqueue_head(&rmidi->open_wait); INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams); INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams); + rmidi->info_flags = info_flags; if (id != NULL) - strlcpy(rmidi->id, id, sizeof(rmidi->id)); + strscpy(rmidi->id, id, sizeof(rmidi->id)); - snd_device_initialize(&rmidi->dev, card); - rmidi->dev.release = release_rawmidi_device; - dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device); + err = snd_device_alloc(&rmidi->dev, card); + if (err < 0) + return err; + if (rawmidi_is_ump(rmidi)) + dev_set_name(rmidi->dev, "umpC%iD%i", card->number, device); + else + dev_set_name(rmidi->dev, "midiC%iD%i", card->number, device); err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], SNDRV_RAWMIDI_STREAM_INPUT, input_count); if (err < 0) - goto error; + return err; err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], SNDRV_RAWMIDI_STREAM_OUTPUT, output_count); if (err < 0) - goto error; + return err; err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops); if (err < 0) - goto error; + return err; + return 0; +} +EXPORT_SYMBOL_GPL(snd_rawmidi_init); +/** + * snd_rawmidi_new - create a rawmidi instance + * @card: the card instance + * @id: the id string + * @device: the device index + * @output_count: the number of output streams + * @input_count: the number of input streams + * @rrawmidi: the pointer to store the new rawmidi instance + * + * Creates a new rawmidi instance. + * Use snd_rawmidi_set_ops() to set the operators to the new instance. + * + * 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, + struct snd_rawmidi **rrawmidi) +{ + struct snd_rawmidi *rmidi; + int err; + + if (rrawmidi) + *rrawmidi = NULL; + rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); + if (!rmidi) + return -ENOMEM; + err = snd_rawmidi_init(rmidi, card, id, device, + output_count, input_count, 0); + if (err < 0) { + snd_rawmidi_free(rmidi); + return err; + } if (rrawmidi) *rrawmidi = rmidi; return 0; - - error: - snd_rawmidi_free(rmidi); - return err; } EXPORT_SYMBOL(snd_rawmidi_new); @@ -1708,25 +1913,26 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) } } -static int snd_rawmidi_free(struct snd_rawmidi *rmidi) +/* called from ump.c, too */ +int snd_rawmidi_free(struct snd_rawmidi *rmidi) { if (!rmidi) return 0; snd_info_free_entry(rmidi->proc_entry); rmidi->proc_entry = NULL; - mutex_lock(®ister_mutex); if (rmidi->ops && rmidi->ops->dev_unregister) rmidi->ops->dev_unregister(rmidi); - mutex_unlock(®ister_mutex); snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); if (rmidi->private_free) rmidi->private_free(rmidi); - put_device(&rmidi->dev); + put_device(rmidi->dev); + kfree(rmidi); return 0; } +EXPORT_SYMBOL_GPL(snd_rawmidi_free); static int snd_rawmidi_dev_free(struct snd_device *device) { @@ -1754,18 +1960,18 @@ static int snd_rawmidi_dev_register(struct snd_device *device) if (rmidi->device >= SNDRV_RAWMIDI_DEVICES) return -ENOMEM; err = 0; - mutex_lock(®ister_mutex); - if (snd_rawmidi_search(rmidi->card, rmidi->device)) - err = -EBUSY; - else - list_add_tail(&rmidi->list, &snd_rawmidi_devices); - mutex_unlock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) { + if (snd_rawmidi_search(rmidi->card, rmidi->device)) + err = -EBUSY; + else + list_add_tail(&rmidi->list, &snd_rawmidi_devices); + } if (err < 0) return err; err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device, - &snd_rawmidi_f_ops, rmidi, &rmidi->dev); + &snd_rawmidi_f_ops, rmidi, rmidi->dev); if (err < 0) { rmidi_err(rmidi, "unable to register\n"); goto error; @@ -1777,7 +1983,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } #ifdef CONFIG_SND_OSSEMUL rmidi->ossreg = 0; - if ((int)rmidi->device == midi_map[rmidi->card->number]) { + if (!rawmidi_is_ump(rmidi) && + (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) < 0) { @@ -1791,7 +1998,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device) #endif } } - if ((int)rmidi->device == amidi_map[rmidi->card->number]) { + if (!rawmidi_is_ump(rmidi) && + (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) < 0) { @@ -1815,7 +2023,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } rmidi->proc_entry = entry; #if IS_ENABLED(CONFIG_SND_SEQUENCER) - if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ + /* no own registration mechanism? */ + if (!rmidi->ops || !rmidi->ops->dev_register) { if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { rmidi->seq_dev->private_data = rmidi; rmidi->seq_dev->private_free = snd_rawmidi_dev_seq_free; @@ -1827,11 +2036,10 @@ static int snd_rawmidi_dev_register(struct snd_device *device) return 0; error_unregister: - snd_unregister_device(&rmidi->dev); + snd_unregister_device(rmidi->dev); error: - mutex_lock(®ister_mutex); - list_del(&rmidi->list); - mutex_unlock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) + list_del(&rmidi->list); return err; } @@ -1840,8 +2048,8 @@ 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); + guard(mutex)(®ister_mutex); + guard(mutex)(&rmidi->open_mutex); wake_up(&rmidi->open_wait); list_del_init(&rmidi->list); for (dir = 0; dir < 2; dir++) { @@ -1866,9 +2074,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) rmidi->ossreg = 0; } #endif /* CONFIG_SND_OSSEMUL */ - snd_unregister_device(&rmidi->dev); - mutex_unlock(&rmidi->open_mutex); - mutex_unlock(®ister_mutex); + snd_unregister_device(rmidi->dev); return 0; } |