Blame src/rawmidi/rawmidi_virt.c

Packit Service db8eaa
/*
Packit Service db8eaa
 *  RawMIDI - Virtual (sequencer mode)
Packit Service db8eaa
 *  Copyright (c) 2003 by Takashi Iwai <tiwai@suse.de>
Packit Service db8eaa
 *
Packit Service db8eaa
 *
Packit Service db8eaa
 *   This library is free software; you can redistribute it and/or modify
Packit Service db8eaa
 *   it under the terms of the GNU Lesser General Public License as
Packit Service db8eaa
 *   published by the Free Software Foundation; either version 2.1 of
Packit Service db8eaa
 *   the License, or (at your option) any later version.
Packit Service db8eaa
 *
Packit Service db8eaa
 *   This program is distributed in the hope that it will be useful,
Packit Service db8eaa
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service db8eaa
 *   GNU Lesser General Public License for more details.
Packit Service db8eaa
 *
Packit Service db8eaa
 *   You should have received a copy of the GNU Lesser General Public
Packit Service db8eaa
 *   License along with this library; if not, write to the Free Software
Packit Service db8eaa
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service db8eaa
 *
Packit Service db8eaa
 */
Packit Service db8eaa
Packit Service db8eaa
#include <stdio.h>
Packit Service db8eaa
#include <stdlib.h>
Packit Service db8eaa
#include <unistd.h>
Packit Service db8eaa
#include <string.h>
Packit Service db8eaa
#include <fcntl.h>
Packit Service db8eaa
#include <sys/ioctl.h>
Packit Service db8eaa
#include "rawmidi_local.h"
Packit Service db8eaa
#include "seq.h"
Packit Service db8eaa
#include "seq_midi_event.h"
Packit Service db8eaa
Packit Service db8eaa
#ifndef PIC
Packit Service db8eaa
/* entry for static linking */
Packit Service db8eaa
const char *_snd_module_rawmidi_virt = "";
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
#ifndef DOC_HIDDEN
Packit Service db8eaa
typedef struct {
Packit Service db8eaa
	int open;
Packit Service db8eaa
Packit Service db8eaa
	snd_seq_t *handle;
Packit Service db8eaa
	int port;
Packit Service db8eaa
Packit Service db8eaa
	snd_midi_event_t *midi_event;
Packit Service db8eaa
Packit Service db8eaa
	snd_seq_event_t *in_event;
Packit Service db8eaa
	int in_buf_size;
Packit Service db8eaa
	int in_buf_ofs;
Packit Service db8eaa
	char *in_buf_ptr;
Packit Service db8eaa
	char in_tmp_buf[16];
Packit Service db8eaa
Packit Service db8eaa
	snd_seq_event_t out_event;
Packit Service db8eaa
	int pending;
Packit Service db8eaa
} snd_rawmidi_virtual_t;
Packit Service db8eaa
Packit Service db8eaa
int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name, 
Packit Service db8eaa
			int streams, int mode, snd_config_t *lconf,
Packit Service db8eaa
			snd_config_t *parent_conf);
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
	virt->open--;
Packit Service db8eaa
	if (virt->open)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	snd_seq_close(virt->handle);
Packit Service db8eaa
	if (virt->midi_event)
Packit Service db8eaa
		snd_midi_event_free(virt->midi_event);
Packit Service db8eaa
	free(virt);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_nonblock(snd_rawmidi_t *rmidi, int nonblock)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
Packit Service db8eaa
	return snd_seq_nonblock(virt->handle, nonblock);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info)
Packit Service db8eaa
{
Packit Service db8eaa
	// snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
Packit Service db8eaa
	info->stream = rmidi->stream;
Packit Service db8eaa
	/* FIXME: what values should be there? */
Packit Service db8eaa
	info->card = 0;
Packit Service db8eaa
	info->device = 0;
Packit Service db8eaa
	info->subdevice = 0;
Packit Service db8eaa
	info->flags = 0;
Packit Service db8eaa
	strcpy((char *)info->id, "Virtual");
Packit Service db8eaa
	strcpy((char *)info->name, "Virtual RawMIDI");
Packit Service db8eaa
	strcpy((char *)info->subname, "Virtual RawMIDI");
Packit Service db8eaa
	info->subdevices_count = 1;
Packit Service db8eaa
	info->subdevices_avail = 0;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_input_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	// snd_rawmidi_drain_input(substream);
Packit Service db8eaa
	if (params->buffer_size < sizeof(snd_seq_event_t) ||
Packit Service db8eaa
	    params->buffer_size > 1024L * 1024L) {
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (params->buffer_size != snd_seq_get_input_buffer_size(virt->handle)) {
Packit Service db8eaa
		err = snd_seq_set_input_buffer_size(virt->handle, params->buffer_size);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		params->buffer_size = snd_seq_get_input_buffer_size(virt->handle);
Packit Service db8eaa
		/* FIXME: input pool size? */
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_output_params(snd_rawmidi_virtual_t *virt, snd_rawmidi_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	// snd_rawmidi_drain_output(substream);
Packit Service db8eaa
	if (params->buffer_size < sizeof(snd_seq_event_t) ||
Packit Service db8eaa
	    params->buffer_size > 1024L * 1024L) {
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (params->buffer_size != snd_seq_get_output_buffer_size(virt->handle)) {
Packit Service db8eaa
		err = snd_seq_set_output_buffer_size(virt->handle, params->buffer_size);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		params->buffer_size = snd_seq_get_output_buffer_size(virt->handle);
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
	params->stream = rmidi->stream;
Packit Service db8eaa
Packit Service db8eaa
	if (rmidi->stream == SND_RAWMIDI_STREAM_INPUT)
Packit Service db8eaa
		return snd_rawmidi_virtual_input_params(virt, params);
Packit Service db8eaa
	else
Packit Service db8eaa
		return snd_rawmidi_virtual_output_params(virt, params);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status)
Packit Service db8eaa
{
Packit Service db8eaa
	// snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
	memset(status, 0, sizeof(*status));
Packit Service db8eaa
	status->stream = rmidi->stream;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_drop(snd_rawmidi_t *rmidi)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
	if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) {
Packit Service db8eaa
		snd_seq_drop_output(virt->handle);
Packit Service db8eaa
		snd_midi_event_reset_encode(virt->midi_event);
Packit Service db8eaa
		virt->pending = 0;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		snd_seq_drop_input(virt->handle);
Packit Service db8eaa
		snd_midi_event_reset_decode(virt->midi_event);
Packit Service db8eaa
		virt->in_buf_ofs = 0;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_rawmidi_virtual_drain(snd_rawmidi_t *rmidi)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (rmidi->stream == SND_RAWMIDI_STREAM_OUTPUT) {
Packit Service db8eaa
		if (virt->pending) {
Packit Service db8eaa
			err = snd_seq_event_output(virt->handle, &virt->out_event);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
			virt->pending = 0;
Packit Service db8eaa
		}
Packit Service db8eaa
		snd_seq_drain_output(virt->handle);
Packit Service db8eaa
		snd_seq_sync_output_queue(virt->handle);
Packit Service db8eaa
	}
Packit Service db8eaa
	return snd_rawmidi_virtual_drop(rmidi);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static ssize_t snd_rawmidi_virtual_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
	ssize_t result = 0;
Packit Service db8eaa
	ssize_t size1;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (virt->pending) {
Packit Service db8eaa
		err = snd_seq_event_output(virt->handle, &virt->out_event);
Packit Service db8eaa
		if (err < 0) {
Packit Service db8eaa
			if (err != -EAGAIN)
Packit Service db8eaa
				/* we got some fatal error. removing this event
Packit Service db8eaa
				 * at the next time
Packit Service db8eaa
				 */
Packit Service db8eaa
				virt->pending = 0;
Packit Service db8eaa
			return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		virt->pending = 0;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	while (size > 0) {
Packit Service db8eaa
		size1 = snd_midi_event_encode(virt->midi_event, buffer, size, &virt->out_event);
Packit Service db8eaa
		if (size1 <= 0)
Packit Service db8eaa
			break;
Packit Service db8eaa
		size -= size1;
Packit Service db8eaa
		result += size1;
Packit Service db8eaa
		buffer += size1;
Packit Service db8eaa
		if (virt->out_event.type == SND_SEQ_EVENT_NONE)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		snd_seq_ev_set_subs(&virt->out_event);
Packit Service db8eaa
		snd_seq_ev_set_source(&virt->out_event, virt->port);
Packit Service db8eaa
		snd_seq_ev_set_direct(&virt->out_event);
Packit Service db8eaa
		err = snd_seq_event_output(virt->handle, &virt->out_event);
Packit Service db8eaa
		if (err < 0) {
Packit Service db8eaa
			virt->pending = 1;
Packit Service db8eaa
			return result > 0 ? result : err;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (result > 0)
Packit Service db8eaa
		snd_seq_drain_output(virt->handle);
Packit Service db8eaa
Packit Service db8eaa
	return result;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static ssize_t snd_rawmidi_virtual_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_rawmidi_virtual_t *virt = rmidi->private_data;
Packit Service db8eaa
	ssize_t result = 0;
Packit Service db8eaa
	int size1, err;
Packit Service db8eaa
Packit Service db8eaa
	while (size > 0) {
Packit Service db8eaa
		if (! virt->in_buf_ofs) {
Packit Service db8eaa
			err = snd_seq_event_input_pending(virt->handle, 1);
Packit Service db8eaa
			if (err <= 0 && result > 0)
Packit Service db8eaa
				return result;
Packit Service db8eaa
			err = snd_seq_event_input(virt->handle, &virt->in_event);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return result > 0 ? result : err;
Packit Service db8eaa
Packit Service db8eaa
			if (virt->in_event->type == SND_SEQ_EVENT_SYSEX) {
Packit Service db8eaa
				virt->in_buf_ptr = virt->in_event->data.ext.ptr;
Packit Service db8eaa
				virt->in_buf_size = virt->in_event->data.ext.len;
Packit Service db8eaa
			} else {
Packit Service db8eaa
				virt->in_buf_ptr = virt->in_tmp_buf;
Packit Service db8eaa
				virt->in_buf_size = snd_midi_event_decode(virt->midi_event,
Packit Service db8eaa
									  (unsigned char *)virt->in_tmp_buf,
Packit Service db8eaa
									  sizeof(virt->in_tmp_buf),
Packit Service db8eaa
									  virt->in_event);
Packit Service db8eaa
			}
Packit Service db8eaa
			if (virt->in_buf_size <= 0)
Packit Service db8eaa
				continue;
Packit Service db8eaa
		}
Packit Service db8eaa
		size1 = virt->in_buf_size - virt->in_buf_ofs;
Packit Service db8eaa
		if ((size_t)size1 > size) {
Packit Service db8eaa
			memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size);
Packit Service db8eaa
			virt->in_buf_ofs += size;
Packit Service db8eaa
			result += size;
Packit Service db8eaa
			break;
Packit Service db8eaa
		}
Packit Service db8eaa
		memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size1);
Packit Service db8eaa
		size -= size1;
Packit Service db8eaa
		result += size1;
Packit Service db8eaa
		buffer += size1;
Packit Service db8eaa
		virt->in_buf_ofs = 0;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return result;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static const snd_rawmidi_ops_t snd_rawmidi_virtual_ops = {
Packit Service db8eaa
	.close = snd_rawmidi_virtual_close,
Packit Service db8eaa
	.nonblock = snd_rawmidi_virtual_nonblock,
Packit Service db8eaa
	.info = snd_rawmidi_virtual_info,
Packit Service db8eaa
	.params = snd_rawmidi_virtual_params,
Packit Service db8eaa
	.status = snd_rawmidi_virtual_status,
Packit Service db8eaa
	.drop = snd_rawmidi_virtual_drop,
Packit Service db8eaa
	.drain = snd_rawmidi_virtual_drain,
Packit Service db8eaa
	.write = snd_rawmidi_virtual_write,
Packit Service db8eaa
	.read = snd_rawmidi_virtual_read,
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
/*! \page rawmidi RawMidi interface
Packit Service db8eaa
Packit Service db8eaa
\section rawmidi_virt Virtual RawMidi interface
Packit Service db8eaa
Packit Service db8eaa
The "virtual" plugin creates a virtual RawMidi instance on the ALSA
Packit Service db8eaa
sequencer, which can be accessed through the connection of the sequencer
Packit Service db8eaa
ports.
Packit Service db8eaa
There is no connection established as default.
Packit Service db8eaa
Packit Service db8eaa
For creating a virtual RawMidi instance, pass "virtual" as its name at
Packit Service db8eaa
creation.
Packit Service db8eaa
Packit Service db8eaa
Example:
Packit Service db8eaa
\code
Packit Service db8eaa
snd_rawmidi_open(&read_handle, &write_handle, "virtual", 0);
Packit Service db8eaa
\endcode
Packit Service db8eaa
Packit Service db8eaa
*/
Packit Service db8eaa
Packit Service db8eaa
int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
Packit Service db8eaa
			     const char *name, snd_seq_t *seq_handle, int port,
Packit Service db8eaa
			     int merge, int mode)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service 45dc4a
	snd_rawmidi_t *rmidi;
Packit Service db8eaa
	snd_rawmidi_virtual_t *virt = NULL;
Packit Service db8eaa
	struct pollfd pfd;
Packit Service db8eaa
Packit Service db8eaa
	if (inputp)
Packit Service db8eaa
		*inputp = 0;
Packit Service db8eaa
	if (outputp)
Packit Service db8eaa
		*outputp = 0;
Packit Service db8eaa
Packit Service db8eaa
	virt = calloc(1, sizeof(*virt));
Packit Service db8eaa
	if (virt == NULL) {
Packit Service db8eaa
		err = -ENOMEM;
Packit Service db8eaa
		goto _err;
Packit Service db8eaa
	}
Packit Service db8eaa
	virt->handle = seq_handle;
Packit Service db8eaa
	virt->port = port;
Packit Service db8eaa
	err = snd_midi_event_new(256, &virt->midi_event);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		goto _err;
Packit Service db8eaa
	snd_midi_event_init(virt->midi_event);
Packit Service db8eaa
	snd_midi_event_no_status(virt->midi_event, !merge);
Packit Service db8eaa
Packit Service db8eaa
	if (inputp) {
Packit Service db8eaa
		rmidi = calloc(1, sizeof(*rmidi));
Packit Service db8eaa
		if (rmidi == NULL) {
Packit Service db8eaa
			err = -ENOMEM;
Packit Service db8eaa
			goto _err;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (name)
Packit Service db8eaa
			rmidi->name = strdup(name);
Packit Service db8eaa
		rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL;
Packit Service db8eaa
		rmidi->stream = SND_RAWMIDI_STREAM_INPUT;
Packit Service db8eaa
		rmidi->mode = mode;
Packit Service db8eaa
		err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLIN);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto _err;
Packit Service db8eaa
		rmidi->poll_fd = pfd.fd;
Packit Service db8eaa
		rmidi->ops = &snd_rawmidi_virtual_ops;
Packit Service db8eaa
		rmidi->private_data = virt;
Packit Service db8eaa
		virt->open++;
Packit Service db8eaa
		*inputp = rmidi;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (outputp) {
Packit Service db8eaa
		rmidi = calloc(1, sizeof(*rmidi));
Packit Service db8eaa
		if (rmidi == NULL) {
Packit Service db8eaa
			err = -ENOMEM;
Packit Service db8eaa
			goto _err;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (name)
Packit Service db8eaa
			rmidi->name = strdup(name);
Packit Service db8eaa
		rmidi->type = SND_RAWMIDI_TYPE_VIRTUAL;
Packit Service db8eaa
		rmidi->stream = SND_RAWMIDI_STREAM_OUTPUT;
Packit Service db8eaa
		rmidi->mode = mode;
Packit Service db8eaa
		err = snd_seq_poll_descriptors(seq_handle, &pfd, 1, POLLOUT);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto _err;
Packit Service db8eaa
		rmidi->poll_fd = pfd.fd;
Packit Service db8eaa
		rmidi->ops = &snd_rawmidi_virtual_ops;
Packit Service db8eaa
		rmidi->private_data = virt;
Packit Service db8eaa
		virt->open++;
Packit Service db8eaa
		*outputp = rmidi;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
Packit Service db8eaa
 _err:
Packit Service db8eaa
	if (seq_handle)
Packit Service db8eaa
		snd_seq_close(seq_handle);
Packit Service db8eaa
	if (virt) {
Packit Service db8eaa
		if (virt->midi_event)
Packit Service db8eaa
			snd_midi_event_free(virt->midi_event);
Packit Service db8eaa
		free(virt);
Packit Service db8eaa
	}
Packit Service db8eaa
	if (inputp)
Packit Service db8eaa
		free(*inputp);
Packit Service db8eaa
	if (outputp)
Packit Service db8eaa
		free(*outputp);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
Packit Service db8eaa
			   char *name, snd_config_t *root ATTRIBUTE_UNUSED,
Packit Service db8eaa
			   snd_config_t *conf, int mode)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	const char *slave_str = NULL;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	int streams, seq_mode;
Packit Service db8eaa
	int merge = 1;
Packit Service db8eaa
	int port;
Packit Service db8eaa
	unsigned int caps;
Packit Service db8eaa
	snd_seq_t *seq_handle;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, conf) {
Packit Service db8eaa
		snd_config_t *n = snd_config_iterator_entry(i);
Packit Service db8eaa
		const char *id;
Packit Service db8eaa
		if (snd_config_get_id(n, &id) < 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (snd_rawmidi_conf_generic_id(id))
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (strcmp(id, "slave") == 0) {
Packit Service db8eaa
			err = snd_config_get_string(n, &slave_str);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (strcmp(id, "merge") == 0) {
Packit Service db8eaa
			merge = snd_config_get_bool(n);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	streams = 0;
Packit Service db8eaa
	if (inputp)
Packit Service db8eaa
		streams |= SND_SEQ_OPEN_INPUT;
Packit Service db8eaa
	if (outputp)
Packit Service db8eaa
		streams |= SND_SEQ_OPEN_OUTPUT;
Packit Service db8eaa
	if (! streams)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
	seq_mode = 0;
Packit Service db8eaa
	if (mode & SND_RAWMIDI_NONBLOCK)
Packit Service db8eaa
		seq_mode |= SND_SEQ_NONBLOCK;
Packit Service db8eaa
Packit Service db8eaa
	if (! slave_str)
Packit Service db8eaa
		slave_str = "default";
Packit Service db8eaa
	err = _snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode,
Packit Service db8eaa
				  root, conf);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
Packit Service db8eaa
	caps = 0;
Packit Service db8eaa
	if (inputp)
Packit Service db8eaa
		caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SYNC_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
Packit Service db8eaa
	if (outputp)
Packit Service db8eaa
		caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SYNC_READ | SND_SEQ_PORT_CAP_SUBS_READ;
Packit Service db8eaa
	if (inputp && outputp)
Packit Service db8eaa
		caps |= SNDRV_SEQ_PORT_CAP_DUPLEX;
Packit Service db8eaa
Packit Service db8eaa
	port = snd_seq_create_simple_port(seq_handle, "Virtual RawMIDI",
Packit Service db8eaa
					  caps, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC);
Packit Service db8eaa
	if (port < 0) {
Packit Service db8eaa
		snd_seq_close(seq_handle);
Packit Service db8eaa
		return port;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return snd_rawmidi_virtual_open(inputp, outputp, name, seq_handle, port,
Packit Service db8eaa
				     merge, mode);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#ifndef DOC_HIDDEN
Packit Service db8eaa
SND_DLSYM_BUILD_VERSION(_snd_rawmidi_virtual_open, SND_RAWMIDI_DLSYM_VERSION);
Packit Service db8eaa
#endif