cregit-Linux how code gets into the kernel

Release 4.17 sound/core/rawmidi.c

Directory: sound/core
/*
 *  Abstract layer for MIDI v1.0 stream
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

#include <sound/core.h>
#include <linux/major.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <sound/rawmidi.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/minors.h>
#include <sound/initval.h>

MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
MODULE_LICENSE("GPL");

#ifdef CONFIG_SND_OSSEMUL

static int midi_map[SNDRV_CARDS];

static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
module_param_array(midi_map, int, NULL, 0444);
MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
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);

static LIST_HEAD(snd_rawmidi_devices);
static DEFINE_MUTEX(register_mutex);


#define rmidi_err(rmidi, fmt, args...) \
	dev_err(&(rmidi)->dev, fmt, ##args)

#define rmidi_warn(rmidi, fmt, args...) \
	dev_warn(&(rmidi)->dev, fmt, ##args)

#define rmidi_dbg(rmidi, fmt, args...) \
	dev_dbg(&(rmidi)->dev, fmt, ##args)


static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) { struct snd_rawmidi *rawmidi; list_for_each_entry(rawmidi, &snd_rawmidi_devices, list) if (rawmidi->card == card && rawmidi->device == device) return rawmidi; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Clemens Ladisch4693.88%150.00%
Johannes Berg36.12%150.00%
Total49100.00%2100.00%


static inline unsigned short snd_rawmidi_file_flags(struct file *file) { switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) { case FMODE_WRITE: return SNDRV_RAWMIDI_LFLG_OUTPUT; case FMODE_READ: return SNDRV_RAWMIDI_LFLG_INPUT; default: return SNDRV_RAWMIDI_LFLG_OPEN; } }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela43100.00%1100.00%
Total43100.00%1100.00%


static inline int snd_rawmidi_ready(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime = substream->runtime; return runtime->avail >= runtime->avail_min; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela2686.67%150.00%
Takashi Iwai413.33%150.00%
Total30100.00%2100.00%


static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream, size_t count) { struct snd_rawmidi_runtime *runtime = substream->runtime; return runtime->avail >= runtime->avail_min && (!substream->append || runtime->avail >= count); }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela4291.30%266.67%
Takashi Iwai48.70%133.33%
Total46100.00%3100.00%


static void snd_rawmidi_input_event_work(struct work_struct *work) { struct snd_rawmidi_runtime *runtime = container_of(work, struct snd_rawmidi_runtime, event_work); if (runtime->event) runtime->event(runtime->substream); }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai2356.10%250.00%
Jaroslav Kysela1843.90%250.00%
Total41100.00%4100.00%


static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime; if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL) 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; runtime->buffer_size = PAGE_SIZE; runtime->avail_min = 1; if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) runtime->avail = 0; else runtime->avail = runtime->buffer_size; if ((runtime->buffer = kmalloc(runtime->buffer_size, GFP_KERNEL)) == NULL) { kfree(runtime); return -ENOMEM; } runtime->appl_ptr = runtime->hw_ptr = 0; substream->runtime = runtime; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela14791.30%350.00%
Takashi Iwai148.70%350.00%
Total161100.00%6100.00%


static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime = substream->runtime; kfree(runtime->buffer); kfree(runtime); substream->runtime = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela3790.24%266.67%
Takashi Iwai49.76%133.33%
Total41100.00%3100.00%


static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream,int up) { if (!substream->opened) return; substream->ops->trigger(substream, up); }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela2573.53%240.00%
Takashi Iwai926.47%360.00%
Total34100.00%5100.00%


static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) { if (!substream->opened) return; substream->ops->trigger(substream, up); if (!up) cancel_work_sync(&substream->runtime->event_work); }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela3675.00%240.00%
Takashi Iwai1225.00%360.00%
Total48100.00%5100.00%


int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) { unsigned long flags; struct snd_rawmidi_runtime *runtime = substream->runtime; snd_rawmidi_output_trigger(substream, 0); runtime->drain = 0; spin_lock_irqsave(&runtime->lock, flags); runtime->appl_ptr = runtime->hw_ptr = 0; runtime->avail = runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela7394.81%375.00%
Takashi Iwai45.19%125.00%
Total77100.00%4100.00%

EXPORT_SYMBOL(snd_rawmidi_drop_output);
int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) { int err; long timeout; struct snd_rawmidi_runtime *runtime = substream->runtime; 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; } runtime->drain = 0; if (err != -ERESTARTSYS) { /* we need wait a while to make sure that Tx FIFOs are empty */ if (substream->ops->drain) substream->ops->drain(substream); else msleep(50); snd_rawmidi_drop_output(substream); } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela15194.38%571.43%
Takashi Iwai95.62%228.57%
Total160100.00%7100.00%

EXPORT_SYMBOL(snd_rawmidi_drain_output);
int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) { unsigned long flags; struct snd_rawmidi_runtime *runtime = substream->runtime; snd_rawmidi_input_trigger(substream, 0); runtime->drain = 0; spin_lock_irqsave(&runtime->lock, flags); runtime->appl_ptr = runtime->hw_ptr = 0; runtime->avail = 0; spin_unlock_irqrestore(&runtime->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela7194.67%375.00%
Takashi Iwai45.33%125.00%
Total75100.00%4100.00%

EXPORT_SYMBOL(snd_rawmidi_drain_input); /* 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_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 (!(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; } if (subdevice < 0 || subdevice == substream->number) { *sub_ret = substream; return 0; } } return -EAGAIN; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai10061.35%342.86%
Jaroslav Kysela5533.74%228.57%
Clemens Ladisch84.91%228.57%
Total163100.00%7100.00%

/* 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; } 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; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai5945.04%111.11%
Jaroslav Kysela3728.24%333.33%
Clemens Ladisch3526.72%555.56%
Total131100.00%9100.00%

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) { err = assign_substream(rmidi, subdevice, SNDRV_RAWMIDI_STREAM_INPUT, mode, &sinput); if (err < 0) return err; } if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { err = assign_substream(rmidi, subdevice, SNDRV_RAWMIDI_STREAM_OUTPUT, mode, &soutput); if (err < 0) return err; } 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; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai11356.22%125.00%
Jaroslav Kysela7637.81%250.00%
Clemens Ladisch125.97%125.00%
Total201100.00%4100.00%

/* 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(&register_mutex); rmidi = snd_rawmidi_search(card, device); if (rmidi == NULL) { mutex_unlock(&register_mutex); return -ENODEV; } if (!try_module_get(rmidi->card->module)) { mutex_unlock(&register_mutex); return -ENXIO; } mutex_unlock(&register_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; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai13788.96%240.00%
Jaroslav Kysela1610.39%240.00%
Ingo Molnar10.65%120.00%
Total154100.00%5100.00%

EXPORT_SYMBOL(snd_rawmidi_kernel_open);
static int snd_rawmidi_open(struct inode *inode, struct file *file) { int maj = imajor(inode); struct snd_card *card; int subdevice; unsigned short fflags; int err; struct snd_rawmidi *rmidi; struct snd_rawmidi_file *rawmidi_file = NULL; wait_queue_entry_t wait; 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); #ifdef CONFIG_SND_OSSEMUL } else if (maj == SOUND_MAJOR) { rmidi = snd_lookup_oss_minor_data(iminor(inode), SNDRV_OSS_DEVICE_TYPE_MIDI); #endif } else return -ENXIO; if (rmidi == NULL) return -ENODEV; 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) 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; rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); if (rawmidi_file == NULL) { err = -ENOMEM; goto __error; } init_waitqueue_entry(&wait, current); add_wait_queue(&rmidi->open_wait, &wait); while (1) { subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_RAWMIDI); err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file); if (err >= 0) break; if (err == -EAGAIN) { if (file->f_flags & O_NONBLOCK) { err = -EBUSY; break; } } else break; set_current_state(TASK_INTERRUPTIBLE); 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 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; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela35464.25%631.58%
Takashi Iwai16529.95%631.58%
Clemens Ladisch244.36%210.53%
Ingo Molnar40.73%210.53%
Al Viro30.54%210.53%
Johannes Berg10.18%15.26%
Total551100.00%19100.00%


static void close_substream(struct snd_rawmidi *rmidi, struct snd_rawmidi_substream *substream, int cleanup) { if (--substream->use_count) return; 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 */ 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 (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--; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela9559.01%350.00%
Takashi Iwai4125.47%116.67%
Clemens Ladisch2515.53%233.33%
Total161100.00%6100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai9088.24%133.33%
Jaroslav Kysela1110.78%133.33%
Ingo Molnar10.98%133.33%
Total102100.00%3100.00%

/* 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; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai3774.00%133.33%
Jaroslav Kysela1224.00%133.33%
Christoph Hellwig12.00%133.33%
Total50100.00%3100.00%

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; struct module *module; rfile = file->private_data; rmidi = rfile->rmidi; rawmidi_release_priv(rfile); kfree(rfile); module = rmidi->card->module; snd_card_file_remove(rmidi->card, file); module_put(module); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela5367.95%350.00%
Clemens Ladisch1316.67%116.67%
Takashi Iwai1215.38%233.33%
Total78100.00%6100.00%


static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, struct snd_rawmidi_info *info) { struct snd_rawmidi *rmidi; if (substream == NULL) return -ENODEV; rmidi = substream->rmidi; memset(info, 0, sizeof(*info)); info->card = rmidi->card->number; info->device = rmidi->device; 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); info->subdevices_count = substream->pstr->substream_count; info->subdevices_avail = (substream->pstr->substream_count - substream->pstr->substream_opened); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela14995.51%250.00%
Takashi Iwai63.85%125.00%
Adrian Bunk10.64%125.00%
Total156100.00%4100.00%


static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream, struct snd_rawmidi_info __user * _info) { struct snd_rawmidi_info info; int err; if ((err = snd_rawmidi_info(substream, &info)) < 0) return err; if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info))) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela5786.36%133.33%
Takashi Iwai812.12%133.33%
Al Viro11.52%133.33%
Total66100.00%3100.00%


static int __snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info) { struct snd_rawmidi *rmidi; struct snd_rawmidi_str *pstr; struct snd_rawmidi_substream *substream; rmidi = snd_rawmidi_search(card, info->device); if (!rmidi) return -ENXIO; if (info->stream < 0 || info->stream > 1) return -EINVAL; pstr = &rmidi->streams[info->stream]; if (pstr->substream_count == 0) return -ENOENT; if (info->subdevice >= pstr->substream_count) return -ENXIO; list_for_each_entry(substream, &pstr->substreams, list) { if ((unsigned int)substream->number == info->subdevice) return snd_rawmidi_info(substream, info); } return -ENXIO; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela11379.02%228.57%
Clemens Ladisch149.79%228.57%
Takashi Iwai128.39%228.57%
Johannes Berg42.80%114.29%
Total143100.00%7100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai42100.00%1100.00%
Total42100.00%1100.00%

EXPORT_SYMBOL(snd_rawmidi_info_select);
static int snd_rawmidi_info_select_user(struct snd_card *card, struct snd_rawmidi_info __user *_info) { int err; struct snd_rawmidi_info info; if (get_user(info.device, &_info->device)) return -EFAULT; if (get_user(info.stream, &_info->stream)) return -EFAULT; if (get_user(info.subdevice, &_info->subdevice)) return -EFAULT; if ((err = snd_rawmidi_info_select(card, &info)) < 0) return err; if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info))) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela11192.50%133.33%
Takashi Iwai86.67%133.33%
Al Viro10.83%133.33%
Total120100.00%3100.00%


int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { char *newbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; if (substream->append && substream->use_count > 1) return -EBUSY; snd_rawmidi_drain_output(substream); if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { return -EINVAL; } if (params->avail_min < 1 || params->avail_min > params->buffer_size) { return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { newbuf = krealloc(runtime->buffer, params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; } runtime->avail_min = params->avail_min; substream->active_sensing = !params->no_active_sensing; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela14785.96%120.00%
Takashi Iwai116.43%240.00%
Clemens Ladisch84.68%120.00%
Jesper Juhl52.92%120.00%
Total171100.00%5100.00%

EXPORT_SYMBOL(snd_rawmidi_output_params);
int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { char *newbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; snd_rawmidi_drain_input(substream); if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { return -EINVAL; } if (params->avail_min < 1 || params->avail_min > params->buffer_size) { return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { newbuf = krealloc(runtime->buffer, params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; } runtime->avail_min = params->avail_min; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela12288.41%125.00%
Takashi Iwai117.97%250.00%
Jesper Juhl53.62%125.00%
Total138100.00%4100.00%

EXPORT_SYMBOL(snd_rawmidi_input_params);
static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, struct snd_rawmidi_status * status) { struct snd_rawmidi_runtime *runtime = substream->runtime; memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; spin_lock_irq(&runtime->lock); status->avail = runtime->avail; spin_unlock_irq(&runtime->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela6591.55%150.00%
Takashi Iwai68.45%150.00%
Total71100.00%2100.00%


static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, struct snd_rawmidi_status * status) { struct snd_rawmidi_runtime *runtime = substream->runtime; memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_INPUT; spin_lock_irq(&runtime->lock); status->avail = runtime->avail; status->xruns = runtime->xruns; runtime->xruns = 0; spin_unlock_irq(&runtime->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela7992.94%150.00%
Takashi Iwai67.06%150.00%
Total85100.00%2100.00%


static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_rawmidi_file *rfile; void __user *argp = (void __user *)arg; rfile = file->private_data; if (((cmd >> 8) & 0xff) != 'W') return -ENOTTY; switch (cmd) { case SNDRV_RAWMIDI_IOCTL_PVERSION: return put_user(SNDRV_RAWMIDI_VERSION, (int __user *)argp) ? -EFAULT : 0; case SNDRV_RAWMIDI_IOCTL_INFO: { int stream; struct snd_rawmidi_info __user *info = argp; if (get_user(stream, &info->stream)) return -EFAULT; switch (stream) { case SNDRV_RAWMIDI_STREAM_INPUT: return snd_rawmidi_info_user(rfile->input, info); case SNDRV_RAWMIDI_STREAM_OUTPUT: return snd_rawmidi_info_user(rfile->output, info); default: return -EINVAL; } } case SNDRV_RAWMIDI_IOCTL_PARAMS: { struct snd_rawmidi_params params; if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params))) return -EFAULT; switch (params.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: if (rfile->output == NULL) return -EINVAL; return snd_rawmidi_output_params(rfile->output, &params); case SNDRV_RAWMIDI_STREAM_INPUT: if (rfile->input == NULL) return -EINVAL; return snd_rawmidi_input_params(rfile->input, &params); default: return -EINVAL; } } case SNDRV_RAWMIDI_IOCTL_STATUS: { int err = 0; struct snd_rawmidi_status status; if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status))) return -EFAULT; switch (status.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: if (rfile->output == NULL) return -EINVAL; err = snd_rawmidi_output_status(rfile->output, &status); break; case SNDRV_RAWMIDI_STREAM_INPUT: if (rfile->input == NULL) return -EINVAL; err = snd_rawmidi_input_status(rfile->input, &status); break; default: return -EINVAL; } if (err < 0) return err; if (copy_to_user(argp, &status, sizeof(struct snd_rawmidi_status))) return -EFAULT; return 0; } case SNDRV_RAWMIDI_IOCTL_DROP: { int val; if (get_user(val, (int __user *) argp)) return -EFAULT; switch (val) { case SNDRV_RAWMIDI_STREAM_OUTPUT: if (rfile->output == NULL) return -EINVAL; return snd_rawmidi_drop_output(rfile->output); default: return -EINVAL; } } case SNDRV_RAWMIDI_IOCTL_DRAIN: { int val; if (get_user(val, (int __user *) argp)) return -EFAULT; switch (val) { case SNDRV_RAWMIDI_STREAM_OUTPUT: if (rfile->output == NULL) return -EINVAL; return snd_rawmidi_drain_output(rfile->output); case SNDRV_RAWMIDI_STREAM_INPUT: if (rfile->input == NULL) return -EINVAL; return snd_rawmidi_drain_input(rfile->input); default: return -EINVAL; } } default: rmidi_dbg(rfile->rmidi, "rawmidi: unknown command = 0x%x\n", cmd); } return -ENOTTY; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela50192.10%457.14%
Al Viro234.23%114.29%
Takashi Iwai203.68%228.57%
Total544100.00%7100.00%


static int snd_rawmidi_control_ioctl(struct snd_card *card, struct snd_ctl_file *control, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; 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; } case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: { int val; if (get_user(val, (int __user *)argp)) return -EFAULT; control->preferred_subdevice[SND_CTL_SUBDEV_RAWMIDI] = val; return 0; } case SNDRV_CTL_IOCTL_RAWMIDI_INFO: return snd_rawmidi_info_select_user(card, argp); } return -ENOIOCTLCMD; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela15472.99%225.00%
Al Viro199.00%112.50%
Clemens Ladisch157.11%112.50%
Dan Carpenter136.16%112.50%
Takashi Iwai83.79%225.00%
Ingo Molnar20.95%112.50%
Total211100.00%8100.00%

/** * snd_rawmidi_receive - receive the input data from the device * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: the data size to read * * Reads the data from the internal buffer. * * 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) { unsigned long flags; int result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; if (!substream->opened) return -EBADFD; if (runtime->buffer == NULL) { 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 */ substream->bytes++; if (runtime->avail < runtime->buffer_size) { runtime->buffer[runtime->hw_ptr++] = buffer[0]; runtime->hw_ptr %= runtime->buffer_size; runtime->avail++; result++; } else { runtime->xruns++; } } else { substream->bytes += count; count1 = runtime->buffer_size - runtime->hw_ptr; if (count1 > count) count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) count1 = runtime->buffer_size - runtime->avail; memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1); runtime->hw_ptr += count1; runtime->hw_ptr %= runtime->buffer_size; runtime->avail += count1; count -= count1; result += count1; if (count > 0) { buffer += count1; count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) { count1 = runtime->buffer_size - runtime->avail; runtime->xruns += count - count1; } if (count1 > 0) { memcpy(runtime->buffer, buffer, count1); runtime->hw_ptr = count1; runtime->avail += count1; result += count1; } } } if (result > 0) { if (runtime->event) schedule_work(&runtime->event_work); else if (snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } spin_unlock_irqrestore(&runtime->lock, flags); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela36494.30%555.56%
Takashi Iwai225.70%444.44%
Total386100.00%9100.00%

EXPORT_SYMBOL(snd_rawmidi_receive);
static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned char __user *userbuf, unsigned char *kernelbuf, long count) { unsigned long flags; long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; unsigned long appl_ptr; spin_lock_irqsave(&runtime->lock, flags); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count; if (count1 > (int)runtime->avail) count1 = runtime->avail; /* update runtime->appl_ptr before unlocking for userbuf */ appl_ptr = runtime->appl_ptr; runtime->appl_ptr += count1; runtime->appl_ptr %= runtime->buffer_size; runtime->avail -= count1; if (kernelbuf) memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, runtime->buffer + appl_ptr, count1)) { return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); } result += count1; count -= count1; } spin_unlock_irqrestore(&runtime->lock, flags); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela16873.04%350.00%
Takashi Iwai4820.87%233.33%
Marcin Ślusarz146.09%116.67%
Total230100.00%6100.00%


long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream, unsigned char *buf, long count) { snd_rawmidi_input_trigger(substream, 1); return snd_rawmidi_kernel_read1(substream, NULL/*userbuf*/, buf, count); }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela3386.84%250.00%
Marcin Ślusarz37.89%125.00%
Takashi Iwai25.26%125.00%
Total38100.00%4100.00%

EXPORT_SYMBOL(snd_rawmidi_kernel_read);
static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { long result; int count1; struct snd_rawmidi_file *rfile; struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; rfile = file->private_data; substream = rfile->input; if (substream == NULL) return -EIO; runtime = substream->runtime; snd_rawmidi_input_trigger(substream, 1); result = 0; while (count > 0) { spin_lock_irq(&runtime->lock); while (!snd_rawmidi_ready(substream)) { wait_queue_entry_t wait; if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { spin_unlock_irq(&runtime->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); 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) return result > 0 ? result : -EIO; spin_lock_irq(&runtime->lock); } spin_unlock_irq(&runtime->lock); count1 = snd_rawmidi_kernel_read1(substream, (unsigned char __user *)buf, NULL/*kernelbuf*/, count); if (count1 < 0) return result > 0 ? result : count1; result += count1; buf += count1; count -= count1; } return result; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela28291.56%758.33%
Takashi Iwai206.49%216.67%
Marcin Ślusarz41.30%18.33%
Al Viro10.32%18.33%
Ingo Molnar10.32%18.33%
Total308100.00%12100.00%

/** * snd_rawmidi_transmit_empty - check whether the output buffer is empty * @substream: the rawmidi substream * * Return: 1 if the internal output buffer is empty, 0 if not. */
int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; if (runtime->buffer == NULL) { 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; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela7288.89%133.33%
Takashi Iwai911.11%266.67%
Total81100.00%3100.00%

EXPORT_SYMBOL(snd_rawmidi_transmit_empty); /** * __snd_rawmidi_transmit_peek - copy data from the internal buffer * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: data size to transfer * * 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) { int result, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; if (runtime->buffer == NULL) { rmidi_dbg(substream->rmidi, "snd_rawmidi_transmit_peek: output is not active!!!\n"); return -EINVAL; } result = 0; if (runtime->avail >= runtime->buffer_size) { /* warning: lowlevel layer MUST trigger down the hardware */ goto __skip; } if (count == 1) { /* special case, faster code */ *buffer = runtime->buffer[runtime->hw_ptr]; result++; } else { count1 = runtime->buffer_size - runtime->hw_ptr; if (count1 > count) count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) count1 = runtime->buffer_size - runtime->avail; 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; memcpy(buffer + count1, runtime->buffer, count); result += count; } } __skip: return result; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela21993.99%350.00%
Takashi Iwai146.01%350.00%
Total233100.00%6100.00%

EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); /** * snd_rawmidi_transmit_peek - copy data from the internal buffer * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: data size to transfer * * Copies data from the internal output buffer to the given buffer. * * Call this in the interrupt handler when the midi output is ready, * and call snd_rawmidi_transmit_ack() after the transmission is * finished. * * 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) { 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; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai5479.41%150.00%
Jaroslav Kysela1420.59%150.00%
Total68100.00%2100.00%

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) { struct snd_rawmidi_runtime *runtime = substream->runtime; if (runtime->buffer == NULL) { rmidi_dbg(substream->rmidi, "snd_rawmidi_transmit_ack: output is not active!!!\n"); return -EINVAL; } snd_BUG_ON(runtime->avail + count > runtime->buffer_size); 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)) wake_up(&runtime->sleep); } return count; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela9785.09%233.33%
Takashi Iwai1714.91%466.67%
Total114100.00%6100.00%

EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); /** * snd_rawmidi_transmit_ack - acknowledge the transmission * @substream: the rawmidi substream * @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. * * 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) { 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; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai4878.69%150.00%
Jaroslav Kysela1321.31%150.00%
Total61100.00%2100.00%

EXPORT_SYMBOL(snd_rawmidi_transmit_ack); /** * snd_rawmidi_transmit - copy from the buffer to the device * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: the data size to transfer * * Copies data from the buffer to the device and advances the pointer. * * 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) { struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; spin_lock_irqsave(&runtime->lock, flags); 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; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai6563.11%375.00%
Jaroslav Kysela3836.89%125.00%
Total103100.00%4100.00%

EXPORT_SYMBOL(snd_rawmidi_transmit);
static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, const unsigned char __user *userbuf, const unsigned char *kernelbuf, long count) { unsigned long flags; long count1, result; struct snd_rawmidi_runtime *runtime = substream->runtime; unsigned long appl_ptr; if (!kernelbuf && !userbuf) return -EINVAL; if (snd_BUG_ON(!runtime->buffer)) return -EINVAL; result = 0; spin_lock_irqsave(&runtime->lock, flags); if (substream->append) { if ((long)runtime->avail < count) { spin_unlock_irqrestore(&runtime->lock, flags); return -EAGAIN; } } while (count > 0 && runtime->avail > 0) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count; if (count1 > (long)runtime->avail) count1 = runtime->avail; /* update runtime->appl_ptr before unlocking for userbuf */ appl_ptr = runtime->appl_ptr; runtime->appl_ptr += count1; runtime->appl_ptr %= runtime->buffer_size; runtime->avail -= count1; if (kernelbuf) memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { spin_lock_irqsave(&runtime->lock, flags); result = result > 0 ? result : -EFAULT; goto __end; } spin_lock_irqsave(&runtime->lock, flags); } result += count1; count -= count1; } __end: count1 = runtime->avail < runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); if (count1) snd_rawmidi_output_trigger(substream, 1); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela25676.42%555.56%
Takashi Iwai5917.61%333.33%
Marcin Ślusarz205.97%111.11%
Total335100.00%9100.00%


long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream, const unsigned char *buf, long count) { return snd_rawmidi_kernel_write1(substream, NULL, buf, count); }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela2787.10%133.33%
Marcin Ślusarz26.45%133.33%
Takashi Iwai26.45%133.33%
Total31100.00%3100.00%

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) { long result, timeout; int count1; struct snd_rawmidi_file *rfile; struct snd_rawmidi_runtime *runtime; struct snd_rawmidi_substream *substream; rfile = file->private_data; substream = rfile->output; runtime = substream->runtime; /* we cannot put an atomic message to our buffer */ if (substream->append && count > runtime->buffer_size) return -EIO; result = 0; while (count > 0) { spin_lock_irq(&runtime->lock); while (!snd_rawmidi_ready_append(substream, count)) { wait_queue_entry_t wait; if (file->f_flags & O_NONBLOCK) { spin_unlock_irq(&runtime->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); 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) return result > 0 ? result : -EIO; spin_lock_irq(&runtime->lock); } spin_unlock_irq(&runtime->lock); count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count); if (count1 < 0) return result > 0 ? result : count1; result += count1; buf += count1; if ((size_t)count1 < count && (file->f_flags & O_NONBLOCK)) break; count -= count1; } if (file->f_flags & O_DSYNC) { spin_lock_irq(&runtime->lock); while (runtime->avail != runtime->buffer_size) { wait_queue_entry_t wait; unsigned int last_avail = runtime->avail; init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(&runtime->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_unlock_irq(&runtime->lock); } return result; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela44694.49%545.45%
Takashi Iwai204.24%218.18%
Ingo Molnar20.42%19.09%
Marcin Ślusarz20.42%19.09%
Al Viro10.21%19.09%
Christoph Hellwig10.21%19.09%
Total472100.00%11100.00%


static __poll_t snd_rawmidi_poll(struct file *file, poll_table * wait) { struct snd_rawmidi_file *rfile; struct snd_rawmidi_runtime *runtime; __poll_t mask; rfile = file->private_data; if (rfile->input != NULL) { runtime = rfile->input->runtime; snd_rawmidi_input_trigger(rfile->input, 1); poll_wait(file, &runtime->sleep, wait); } if (rfile->output != NULL) { runtime = rfile->output->runtime; poll_wait(file, &runtime->sleep, wait); } mask = 0; if (rfile->input != NULL) { if (snd_rawmidi_ready(rfile->input)) mask |= EPOLLIN | EPOLLRDNORM; } if (rfile->output != NULL) { if (snd_rawmidi_ready(rfile->output)) mask |= EPOLLOUT | EPOLLWRNORM; } return mask; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela15093.75%350.00%
Linus Torvalds42.50%116.67%
Takashi Iwai42.50%116.67%
Al Viro21.25%116.67%
Total160100.00%6100.00%

/* */ #ifdef CONFIG_COMPAT #include "rawmidi_compat.c" #else #define snd_rawmidi_ioctl_compat NULL #endif /* */
static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); mutex_lock(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { list_for_each_entry(substream, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, list) { snd_iprintf(buffer, "Output %d\n" " Tx bytes : %lu\n", 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" " Buffer size : %lu\n" " Avail : %lu\n", runtime->oss ? "OSS compatible" : "native", (unsigned long) runtime->buffer_size, (unsigned long) runtime->avail); } } } if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) { list_for_each_entry(substream, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams, list) { snd_iprintf(buffer, "Input %d\n" " Rx bytes : %lu\n", 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" " Avail : %lu\n" " Overruns : %lu\n", (unsigned long) runtime->buffer_size, (unsigned long) runtime->avail, (unsigned long) runtime->xruns); } } } mutex_unlock(&rmidi->open_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela21881.95%233.33%
Clemens Ladisch2810.53%116.67%
Takashi Iwai103.76%116.67%
Johannes Berg83.01%116.67%
Ingo Molnar20.75%116.67%
Total266100.00%6100.00%

/* * Register functions */ static const struct file_operations snd_rawmidi_f_ops = { .owner = THIS_MODULE, .read = snd_rawmidi_read, .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, };
static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, struct snd_rawmidi_str *stream, int direction, int count) { struct snd_rawmidi_substream *substream; int idx; for (idx = 0; idx < count; idx++) { substream = kzalloc(sizeof(*substream), GFP_KERNEL); if (!substream) return -ENOMEM; substream->stream = direction; substream->number = idx; substream->rmidi = rmidi; substream->pstr = stream; list_add_tail(&substream->list, &stream->substreams); stream->substream_count++; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela10492.86%240.00%
Takashi Iwai87.14%360.00%
Total112100.00%5100.00%


static void release_rawmidi_device(struct device *dev) { kfree(container_of(dev, struct snd_rawmidi, dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai24100.00%1100.00%
Total24100.00%1100.00%

/** * 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 struct snd_device_ops ops = { .dev_free = snd_rawmidi_dev_free, .dev_register = snd_rawmidi_dev_register, .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); if (id != NULL) strlcpy(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); if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], SNDRV_RAWMIDI_STREAM_INPUT, input_count)) < 0) { snd_rawmidi_free(rmidi); return err; } if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], SNDRV_RAWMIDI_STREAM_OUTPUT, output_count)) < 0) { snd_rawmidi_free(rmidi); return err; } if ((err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops)) < 0) { snd_rawmidi_free(rmidi); return err; } if (rrawmidi) *rrawmidi = rmidi; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela23371.91%430.77%
Takashi Iwai6319.44%646.15%
Akinobu Mita268.02%17.69%
Ingo Molnar10.31%17.69%
Benjamin Collins10.31%17.69%
Total324100.00%13100.00%

EXPORT_SYMBOL(snd_rawmidi_new);
static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) { struct snd_rawmidi_substream *substream; while (!list_empty(&stream->substreams)) { substream = list_entry(stream->substreams.next, struct snd_rawmidi_substream, list); list_del(&substream->list); kfree(substream); } }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela5289.66%150.00%
Takashi Iwai610.34%150.00%
Total58100.00%2100.00%


static 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(&register_mutex); if (rmidi->ops && rmidi->ops->dev_unregister) rmidi->ops->dev_unregister(rmidi); mutex_unlock(&register_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); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Takashi Iwai6054.05%480.00%
Jaroslav Kysela5145.95%120.00%
Total111100.00%5100.00%


static int snd_rawmidi_dev_free(struct snd_device *device) { struct snd_rawmidi *rmidi = device->device_data; return snd_rawmidi_free(rmidi); }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela2284.62%266.67%
Takashi Iwai415.38%133.33%
Total26100.00%3100.00%

#if IS_ENABLED(CONFIG_SND_SEQUENCER)
static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device) { struct snd_rawmidi *rmidi = device->private_data; rmidi->seq_dev = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela2284.62%266.67%
Takashi Iwai415.38%133.33%
Total26100.00%3100.00%

#endif
static int snd_rawmidi_dev_register(struct snd_device *device) { int err; struct snd_info_entry *entry; char name[16]; struct snd_rawmidi *rmidi = device->device_data; if (rmidi->device >= SNDRV_RAWMIDI_DEVICES) return -ENOMEM; mutex_lock(&register_mutex); if (snd_rawmidi_search(rmidi->card, rmidi->device)) { mutex_unlock(&register_mutex); return -EBUSY; } list_add_tail(&rmidi->list, &snd_rawmidi_devices); mutex_unlock(&register_mutex); err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device, &snd_rawmidi_f_ops, rmidi, &rmidi->dev); if (err < 0) { rmidi_err(rmidi, "unable to register\n"); mutex_lock(&register_mutex); list_del(&rmidi->list); mutex_unlock(&register_mutex); return err; } if (rmidi->ops && rmidi->ops->dev_register && (err = rmidi->ops->dev_register(rmidi)) < 0) { snd_unregister_device(&rmidi->dev); mutex_lock(&register_mutex); list_del(&rmidi->list); mutex_unlock(&register_mutex); return err; } #ifdef CONFIG_SND_OSSEMUL rmidi->ossreg = 0; 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) < 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 snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number, rmidi->name); #endif } } 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) < 0) { rmidi_err(rmidi, "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1); } else { rmidi->ossreg++; } } #endif /* CONFIG_SND_OSSEMUL */ sprintf(name, "midi%d", rmidi->device); entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root); if (entry) { entry->private_data = rmidi; entry->c.text.read = snd_rawmidi_proc_info_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; } } rmidi->proc_entry = entry; #if IS_ENABLED(CONFIG_SND_SEQUENCER) if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ 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; sprintf(rmidi->seq_dev->name, "MIDI %d-%d", rmidi->card->number, rmidi->device); snd_device_register(rmidi->card, rmidi->seq_dev); } } #endif return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela47184.56%535.71%
Takashi Iwai468.26%642.86%
Clemens Ladisch366.46%214.29%
Ingo Molnar40.72%17.14%
Total557100.00%14100.00%


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); 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]) { snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0); #ifdef SNDRV_OSS_INFO_DEV_MIDI snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number); #endif } if ((int)rmidi->device == amidi_map[rmidi->card->number]) snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1); rmidi->ossreg = 0; } #endif /* CONFIG_SND_OSSEMUL */ snd_unregister_device(&rmidi->dev); mutex_unlock(&rmidi->open_mutex); mutex_unlock(&register_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela13360.45%650.00%
Takashi Iwai8036.36%433.33%
Clemens Ladisch52.27%18.33%
Ingo Molnar20.91%18.33%
Total220100.00%12100.00%

/** * snd_rawmidi_set_ops - set the rawmidi operators * @rmidi: the rawmidi instance * @stream: the stream direction, SNDRV_RAWMIDI_STREAM_XXX * @ops: the operator table * * Sets the rawmidi operators for the given stream direction. */
void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, const struct snd_rawmidi_ops *ops) { struct snd_rawmidi_substream *substream; list_for_each_entry(substream, &rmidi->streams[stream].substreams, list) substream->ops = ops; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela2976.32%125.00%
Takashi Iwai615.79%250.00%
Johannes Berg37.89%125.00%
Total38100.00%4100.00%

EXPORT_SYMBOL(snd_rawmidi_set_ops); /* * ENTRY functions */
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++) { 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]); midi_map[i] = 0; } if (amidi_map[i] < 0 || amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) { pr_err("ALSA: rawmidi: invalid amidi_map[%d] = %d\n", i, amidi_map[i]); amidi_map[i] = 1; } } } #endif /* CONFIG_SND_OSSEMUL */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela11996.75%480.00%
Takashi Iwai43.25%120.00%
Total123100.00%5100.00%


static void __exit alsa_rawmidi_exit(void) { snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl); snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl); }

Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela19100.00%2100.00%
Total19100.00%2100.00%

module_init(alsa_rawmidi_init) module_exit(alsa_rawmidi_exit)

Overall Contributors

PersonTokensPropCommitsCommitProp
Jaroslav Kysela677274.40%3436.96%
Takashi Iwai185220.35%2527.17%
Clemens Ladisch2733.00%1213.04%
Al Viro510.56%44.35%
Marcin Ślusarz450.49%11.09%
Akinobu Mita260.29%11.09%
Ingo Molnar250.27%33.26%
Johannes Berg190.21%11.09%
Dan Carpenter130.14%11.09%
Jesper Juhl100.11%11.09%
Linus Torvalds40.04%11.09%
Yacine Belkadi40.04%11.09%
Rusty Russell20.02%11.09%
Christoph Hellwig20.02%22.17%
Benjamin Collins10.01%11.09%
Arjan van de Ven10.01%11.09%
Paul Gortmaker10.01%11.09%
Adrian Bunk10.01%11.09%
Total9102100.00%92100.00%
Directory: sound/core
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.