Blame src/rawmidi/rawmidi_virt.c

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