summaryrefslogtreecommitdiff
path: root/sound/core/rawmidi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/rawmidi.c')
-rw-r--r--sound/core/rawmidi.c497
1 files changed, 262 insertions, 235 deletions
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 7147fda66d93..8969ee2757f1 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 *rmidi);
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;
@@ -102,13 +105,8 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime)
static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
- bool ready;
-
- spin_lock_irqsave(&substream->lock, flags);
- ready = __snd_rawmidi_ready(substream->runtime);
- spin_unlock_irqrestore(&substream->lock, flags);
- return ready;
+ guard(spinlock_irqsave)(&substream->lock);
+ return __snd_rawmidi_ready(substream->runtime);
}
static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream,
@@ -181,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;
@@ -221,12 +233,9 @@ 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(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
if (substream->opened && substream->runtime)
__reset_runtime_ptrs(substream->runtime, is_input);
- spin_unlock_irqrestore(&substream->lock, flags);
}
int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
@@ -243,33 +252,29 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
long timeout;
struct snd_rawmidi_runtime *runtime;
- spin_lock_irq(&substream->lock);
- runtime = substream->runtime;
- if (!substream->opened || !runtime || !runtime->buffer) {
- err = -EINVAL;
- } else {
+ 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;
}
- spin_unlock_irq(&substream->lock);
- if (err < 0)
- return err;
timeout = wait_event_interruptible_timeout(runtime->sleep,
(runtime->avail >= runtime->buffer_size),
10*HZ);
- spin_lock_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;
+ 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;
- spin_unlock_irq(&substream->lock);
if (err != -ERESTARTSYS) {
/* we need wait a while to make sure that Tx FIFOs are empty */
@@ -280,9 +285,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
snd_rawmidi_drop_output(substream);
}
- spin_lock_irq(&substream->lock);
- snd_rawmidi_buffer_unref(runtime);
- spin_unlock_irq(&substream->lock);
+ scoped_guard(spinlock_irq, &substream->lock)
+ snd_rawmidi_buffer_unref(runtime);
return err;
}
@@ -346,14 +350,13 @@ static int open_substream(struct snd_rawmidi *rmidi,
snd_rawmidi_runtime_free(substream);
return err;
}
- spin_lock_irq(&substream->lock);
+ guard(spinlock_irq)(&substream->lock);
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++;
- spin_unlock_irq(&substream->lock);
}
substream->use_count++;
return 0;
@@ -406,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(&register_mutex);
- rmidi = snd_rawmidi_search(card, device);
- if (!rmidi)
- err = -ENODEV;
- else if (!try_module_get(rmidi->card->module))
- err = -ENXIO;
- mutex_unlock(&register_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;
@@ -560,10 +553,10 @@ static void close_substream(struct snd_rawmidi *rmidi,
}
snd_rawmidi_buffer_ref_sync(substream);
}
- spin_lock_irq(&substream->lock);
- substream->opened = 0;
- substream->append = 0;
- spin_unlock_irq(&substream->lock);
+ 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);
@@ -578,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;
@@ -588,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);
}
@@ -637,12 +629,15 @@ static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,
info->subdevice = substream->number;
info->stream = substream->stream;
info->flags = rmidi->info_flags;
- strcpy(info->id, rmidi->id);
- strcpy(info->name, rmidi->name);
- strcpy(info->subname, substream->name);
+ if (substream->inactive)
+ info->flags |= SNDRV_RAWMIDI_INFO_STREAM_INACTIVE;
+ strscpy(info->id, rmidi->id);
+ strscpy(info->name, rmidi->name);
+ strscpy(info->subname, substream->name);
info->subdevices_count = substream->pstr->substream_count;
info->subdevices_avail = (substream->pstr->substream_count -
substream->pstr->substream_opened);
+ info->tied_device = rmidi->tied_device;
return 0;
}
@@ -687,12 +682,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(&register_mutex);
- ret = __snd_rawmidi_info_select(card, info);
- mutex_unlock(&register_mutex);
- return ret;
+ guard(mutex)(&register_mutex);
+ return __snd_rawmidi_info_select(card, info);
}
EXPORT_SYMBOL(snd_rawmidi_info_select);
@@ -730,6 +721,8 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
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)
@@ -757,15 +750,12 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
int err;
snd_rawmidi_drain_output(substream);
- mutex_lock(&substream->rmidi->open_mutex);
+ guard(mutex)(&substream->rmidi->open_mutex);
if (substream->append && substream->use_count > 1)
- err = -EBUSY;
- else
- err = resize_runtime_buffer(substream, params, false);
-
+ return -EBUSY;
+ err = resize_runtime_buffer(substream, params, false);
if (!err)
substream->active_sensing = !params->no_active_sensing;
- mutex_unlock(&substream->rmidi->open_mutex);
return err;
}
EXPORT_SYMBOL(snd_rawmidi_output_params);
@@ -778,7 +768,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
int err;
snd_rawmidi_drain_input(substream);
- mutex_lock(&substream->rmidi->open_mutex);
+ 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)
@@ -792,7 +782,6 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
substream->framing = framing;
substream->clock_type = clock_type;
}
- mutex_unlock(&substream->rmidi->open_mutex);
return 0;
}
EXPORT_SYMBOL(snd_rawmidi_input_params);
@@ -804,9 +793,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(&substream->lock);
+ guard(spinlock_irq)(&substream->lock);
status->avail = runtime->avail;
- spin_unlock_irq(&substream->lock);
return 0;
}
@@ -817,11 +805,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(&substream->lock);
+ guard(spinlock_irq)(&substream->lock);
status->avail = runtime->avail;
status->xruns = runtime->xruns;
runtime->xruns = 0;
- spin_unlock_irq(&substream->lock);
return 0;
}
@@ -902,6 +889,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;
@@ -993,12 +981,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, &register_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)(&register_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,
@@ -1008,27 +1049,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(&register_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(&register_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;
@@ -1052,12 +1081,13 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
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 > 0) {
+ while (src_count > align) {
if ((int)(runtime->buffer_size - runtime->avail) < frame_size) {
runtime->xruns += src_count;
break;
@@ -1065,7 +1095,9 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH)
frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH;
else {
- frame.length = src_count;
+ 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);
@@ -1111,24 +1143,24 @@ static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substr
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;
- spin_lock_irqsave(&substream->lock, flags);
- if (!substream->opened) {
- result = -EBADFD;
- goto unlock;
- }
+ guard(spinlock_irqsave)(&substream->lock);
+ if (!substream->opened)
+ return -EBADFD;
runtime = substream->runtime;
if (!runtime || !runtime->buffer) {
rmidi_dbg(substream->rmidi,
"snd_rawmidi_receive: input is not active!!!\n");
- result = -EINVAL;
- goto unlock;
+ return -EINVAL;
}
+ 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 */
@@ -1148,6 +1180,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;
@@ -1175,8 +1210,6 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
else if (__snd_rawmidi_ready(runtime))
wake_up(&runtime->sleep);
}
- unlock:
- spin_unlock_irqrestore(&substream->lock, flags);
return result;
}
EXPORT_SYMBOL(snd_rawmidi_receive);
@@ -1298,20 +1331,15 @@ 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;
- int result;
- unsigned long flags;
- spin_lock_irqsave(&substream->lock, flags);
+ 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");
- result = 1;
- } else {
- result = runtime->avail >= runtime->buffer_size;
+ return 1;
}
- spin_unlock_irqrestore(&substream->lock, flags);
- return result;
+ return (runtime->avail >= runtime->buffer_size);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
@@ -1348,12 +1376,18 @@ static 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;
}
@@ -1379,16 +1413,10 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
unsigned char *buffer, int count)
{
- int result;
- unsigned long flags;
-
- spin_lock_irqsave(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened || !substream->runtime)
- result = -EBADFD;
- else
- result = __snd_rawmidi_transmit_peek(substream, buffer, count);
- spin_unlock_irqrestore(&substream->lock, flags);
- return result;
+ return -EBADFD;
+ return __snd_rawmidi_transmit_peek(substream, buffer, count);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
@@ -1410,6 +1438,7 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
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;
@@ -1434,16 +1463,10 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
*/
int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
{
- int result;
- unsigned long flags;
-
- spin_lock_irqsave(&substream->lock, flags);
+ guard(spinlock_irqsave)(&substream->lock);
if (!substream->opened || !substream->runtime)
- result = -EBADFD;
- else
- result = __snd_rawmidi_transmit_ack(substream, count);
- spin_unlock_irqrestore(&substream->lock, flags);
- return result;
+ return -EBADFD;
+ return __snd_rawmidi_transmit_ack(substream, count);
}
EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
@@ -1460,21 +1483,13 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
unsigned char *buffer, int count)
{
- int result;
- unsigned long flags;
-
- spin_lock_irqsave(&substream->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(&substream->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);
@@ -1487,17 +1502,15 @@ EXPORT_SYMBOL(snd_rawmidi_transmit);
int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime;
- unsigned long flags;
int count = 0;
- spin_lock_irqsave(&substream->lock, flags);
+ 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(&substream->lock, flags);
return count;
}
EXPORT_SYMBOL(snd_rawmidi_proceed);
@@ -1696,7 +1709,12 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
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,
@@ -1711,10 +1729,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
" Owner PID : %d\n",
pid_vnr(substream->pid));
runtime = substream->runtime;
- spin_lock_irq(&substream->lock);
- buffer_size = runtime->buffer_size;
- avail = runtime->avail;
- spin_unlock_irq(&substream->lock);
+ scoped_guard(spinlock_irq, &substream->lock) {
+ buffer_size = runtime->buffer_size;
+ avail = runtime->avail;
+ }
snd_iprintf(buffer,
" Mode : %s\n"
" Buffer size : %lu\n"
@@ -1738,11 +1756,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
" Owner PID : %d\n",
pid_vnr(substream->pid));
runtime = substream->runtime;
- spin_lock_irq(&substream->lock);
- buffer_size = runtime->buffer_size;
- avail = runtime->avail;
- xruns = runtime->xruns;
- spin_unlock_irq(&substream->lock);
+ 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"
@@ -1759,7 +1777,6 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
}
}
}
- mutex_unlock(&rmidi->open_mutex);
}
/*
@@ -1772,7 +1789,6 @@ 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,
@@ -1801,30 +1817,12 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
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,
@@ -1832,50 +1830,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)
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);
@@ -1890,7 +1917,8 @@ 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;
@@ -1904,9 +1932,11 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
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)
{
@@ -1934,18 +1964,18 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
return -ENOMEM;
err = 0;
- mutex_lock(&register_mutex);
- if (snd_rawmidi_search(rmidi->card, rmidi->device))
- err = -EBUSY;
- else
- list_add_tail(&rmidi->list, &snd_rawmidi_devices);
- mutex_unlock(&register_mutex);
+ scoped_guard(mutex, &register_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;
@@ -1957,7 +1987,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) {
@@ -1971,7 +2002,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) {
@@ -1995,7 +2027,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;
@@ -2007,11 +2040,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(&register_mutex);
- list_del(&rmidi->list);
- mutex_unlock(&register_mutex);
+ scoped_guard(mutex, &register_mutex)
+ list_del(&rmidi->list);
return err;
}
@@ -2020,8 +2052,8 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
struct snd_rawmidi *rmidi = device->device_data;
int dir;
- mutex_lock(&register_mutex);
- mutex_lock(&rmidi->open_mutex);
+ guard(mutex)(&register_mutex);
+ guard(mutex)(&rmidi->open_mutex);
wake_up(&rmidi->open_wait);
list_del_init(&rmidi->list);
for (dir = 0; dir < 2; dir++) {
@@ -2046,9 +2078,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(&register_mutex);
+ snd_unregister_device(rmidi->dev);
return 0;
}
@@ -2076,13 +2106,11 @@ EXPORT_SYMBOL(snd_rawmidi_set_ops);
static int __init alsa_rawmidi_init(void)
{
-
snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
#ifdef CONFIG_SND_OSSEMUL
- { int i;
/* check device map table */
- for (i = 0; i < SNDRV_CARDS; i++) {
+ for (int i = 0; i < SNDRV_CARDS; i++) {
if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
i, midi_map[i]);
@@ -2094,7 +2122,6 @@ static int __init alsa_rawmidi_init(void)
amidi_map[i] = 1;
}
}
- }
#endif /* CONFIG_SND_OSSEMUL */
return 0;
}