mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	Initial version...
This commit is contained in:
		
							parent
							
								
									4518e4ca8e
								
							
						
					
					
						commit
						47b0531d86
					
				
					 3 changed files with 732 additions and 0 deletions
				
			
		
							
								
								
									
										7
									
								
								src/seq/Makefile.am
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/seq/Makefile.am
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
EXTRA_LTLIBRARIES=libseq.la
 | 
			
		||||
 | 
			
		||||
libseq_la_SOURCES = seq.c
 | 
			
		||||
all: libseq.la
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
INCLUDES=-I$(top_srcdir)/include
 | 
			
		||||
							
								
								
									
										670
									
								
								src/seq/seq.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										670
									
								
								src/seq/seq.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,670 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  Sequencer Interface - main file
 | 
			
		||||
 *  Copyright (c) 1998 by Jaroslav Kysela <perex@jcu.cz>
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 *   This library is free software; you can redistribute it and/or modify
 | 
			
		||||
 *   it under the terms of the GNU Library 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 Library General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *   You should have received a copy of the GNU Library General Public
 | 
			
		||||
 *   License along with this library; if not, write to the Free Software
 | 
			
		||||
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include "asoundlib.h"
 | 
			
		||||
 | 
			
		||||
#define SND_FILE_SEQ		"/dev/snd/seq"
 | 
			
		||||
#define SND_SEQ_VERSION_MAX	SND_PROTOCOL_VERSION( 0, 0, 1 )
 | 
			
		||||
#define SND_SEQ_OBUF_SIZE	(16*1024)	/* should be configurable */
 | 
			
		||||
#define SND_SEQ_IBUF_SIZE	(4*1024)	/* should be configurable */
 | 
			
		||||
 | 
			
		||||
typedef struct snd_stru_seq_cell {
 | 
			
		||||
	snd_seq_event_t ev;
 | 
			
		||||
	struct snd_stru_seq_cell *next;
 | 
			
		||||
} snd_seq_cell_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	int client;		/* client number */
 | 
			
		||||
	int fd;
 | 
			
		||||
	/* buffers */
 | 
			
		||||
	char *obuf;		/* output buffer */
 | 
			
		||||
	int obufsize;		/* output buffer size */
 | 
			
		||||
	int obufused;		/* output buffer used size */
 | 
			
		||||
	char *ibuf;		/* input buffer */
 | 
			
		||||
	int ibufsize;		/* input buffer size */
 | 
			
		||||
	/* input queue */
 | 
			
		||||
	int cells;
 | 
			
		||||
	snd_seq_cell_t *head;
 | 
			
		||||
	snd_seq_cell_t *tail;
 | 
			
		||||
} snd_seq_t;
 | 
			
		||||
 | 
			
		||||
int snd_seq_open(void **handle, int mode)
 | 
			
		||||
{
 | 
			
		||||
	int fd, ver, client, flg;
 | 
			
		||||
	char filename[32];
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	*handle = NULL;
 | 
			
		||||
	sprintf(filename, SND_FILE_SEQ);
 | 
			
		||||
	if ((fd = open(filename, mode)) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	if (ioctl(fd, SND_SEQ_IOCTL_PVERSION, &ver) < 0) {
 | 
			
		||||
		close(fd);
 | 
			
		||||
		return -errno;
 | 
			
		||||
	}
 | 
			
		||||
	if (SND_PROTOCOL_UNCOMPATIBLE(ver, SND_SEQ_VERSION_MAX)) {
 | 
			
		||||
		close(fd);
 | 
			
		||||
		return -SND_ERROR_UNCOMPATIBLE_VERSION;
 | 
			
		||||
	}
 | 
			
		||||
	if (ioctl(fd, SND_SEQ_IOCTL_CLIENT_ID, &client) < 0) {
 | 
			
		||||
		close(fd);
 | 
			
		||||
		return -errno;
 | 
			
		||||
	}
 | 
			
		||||
	seq = (snd_seq_t *) calloc(1, sizeof(snd_seq_t));
 | 
			
		||||
	if (seq == NULL) {
 | 
			
		||||
		close(fd);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	seq->client = client;
 | 
			
		||||
	seq->fd = fd;
 | 
			
		||||
	flg = 3;
 | 
			
		||||
	if (mode == SND_SEQ_OPEN_OUT || mode == SND_SEQ_OPEN)
 | 
			
		||||
		seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE);
 | 
			
		||||
	else
 | 
			
		||||
		flg &= ~1;
 | 
			
		||||
	if (mode == SND_SEQ_OPEN_IN || mode == SND_SEQ_OPEN)
 | 
			
		||||
		seq->ibuf = (char *) malloc(seq->ibufsize = SND_SEQ_IBUF_SIZE);
 | 
			
		||||
	else
 | 
			
		||||
		flg &= ~2;
 | 
			
		||||
	if ((!seq->obuf && (flg & 1)) || (!seq->ibuf && (flg & 2))) {
 | 
			
		||||
		if (seq->obuf)
 | 
			
		||||
			free(seq->obuf);
 | 
			
		||||
		if (seq->ibuf)
 | 
			
		||||
			free(seq->ibuf);
 | 
			
		||||
		free(seq);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	*handle = seq;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_close(void *handle)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	res = close(seq->fd) < 0 ? -errno : 0;
 | 
			
		||||
	free(seq);
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_file_descriptor(void *handle)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	return seq->fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_block_mode(void *handle, int enable)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
	long flags;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (fcntl(seq->fd, F_GETFL, &flags) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	if (enable)
 | 
			
		||||
		flags |= O_NONBLOCK;
 | 
			
		||||
	else
 | 
			
		||||
		flags &= ~O_NONBLOCK;
 | 
			
		||||
	if (fcntl(seq->fd, F_SETFL, &flags) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_client_id(void *handle)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	return seq->client;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_system_info(void *handle, snd_seq_system_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_SYSTEM_INFO, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_get_client_info(void *handle, snd_seq_client_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	return snd_seq_get_any_client_info(handle, seq->client, info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_get_any_client_info(void *handle, int client, snd_seq_client_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info || client < 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	bzero(info, sizeof(snd_seq_client_info_t));
 | 
			
		||||
	info->client = client;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_set_client_info(void *handle, snd_seq_client_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_create_port(void *handle, snd_seq_port_info_t * port)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !port)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	port->client = seq->client;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_CREATE_PORT, port) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_delete_port(void *handle, snd_seq_port_info_t * port)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !port)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	port->client = seq->client;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_DELETE_PORT, port) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_get_port_info(void *handle, int port, snd_seq_port_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info || port < 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	return snd_seq_get_any_port_info(handle, seq->client, port, info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_get_any_port_info(void *handle, int client, int port, snd_seq_port_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info || client < 0 || port < 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	bzero(info, sizeof(snd_seq_port_info_t));
 | 
			
		||||
	info->client = client;
 | 
			
		||||
	info->port = port;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_PORT_INFO, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_set_port_info(void *handle, int port, snd_seq_port_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info || port < 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	info->port = port;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_PORT_INFO, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_subscribe_port(void *handle, snd_seq_port_subscribe_t * sub)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !sub)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_unsubscribe_port(void *handle, snd_seq_port_subscribe_t * sub)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !sub)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_get_queue_info(void *handle, int q, snd_seq_queue_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	bzero(info, sizeof(snd_seq_queue_info_t));
 | 
			
		||||
	info->queue = q;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_set_queue_info(void *handle, int q, snd_seq_queue_info_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	info->queue = q;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_get_queue_client(void *handle, int q, snd_seq_queue_client_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	bzero(info, sizeof(snd_seq_queue_client_t));
 | 
			
		||||
	info->queue = q;
 | 
			
		||||
	info->client = seq->client;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_set_queue_client(void *handle, int q, snd_seq_queue_client_t * info)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !info)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	info->queue = q;
 | 
			
		||||
	info->client = seq->client;
 | 
			
		||||
	if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_alloc_queue(void *handle, snd_seq_queue_info_t *info)
 | 
			
		||||
{
 | 
			
		||||
	int i, err;
 | 
			
		||||
	snd_seq_system_info_t sysinfo;
 | 
			
		||||
	snd_seq_queue_info_t inf;
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;	
 | 
			
		||||
	if ((err = snd_seq_system_info(handle, &sysinfo))<0)
 | 
			
		||||
		return err;
 | 
			
		||||
	for (i = 0; i < sysinfo.queues; i++) {
 | 
			
		||||
		if ((err = snd_seq_get_queue_info(handle, i, &inf))<0)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (inf.locked)
 | 
			
		||||
			continue;
 | 
			
		||||
		inf.locked = 1;
 | 
			
		||||
		inf.owner = seq->client;
 | 
			
		||||
		if ((err = snd_seq_set_queue_info(handle, i, &inf))<0)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (info)
 | 
			
		||||
			memcpy(info, &inf, sizeof(snd_seq_queue_info_t));
 | 
			
		||||
		return i;
 | 
			
		||||
	}
 | 
			
		||||
	return -EBUSY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_free_queue(void *handle, int q)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
	snd_seq_queue_info_t inf;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;	
 | 
			
		||||
	if ((err = snd_seq_get_queue_info(handle, q, &inf))<0)
 | 
			
		||||
		return err;
 | 
			
		||||
	if (inf.locked && inf.owner == seq->client) {
 | 
			
		||||
		inf.locked = 0;
 | 
			
		||||
		inf.owner = -1;
 | 
			
		||||
		if ((err = snd_seq_set_queue_info(handle, q, &inf))<0)
 | 
			
		||||
			return err;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
snd_seq_event_t *snd_seq_create_event(void)
 | 
			
		||||
{
 | 
			
		||||
	return (snd_seq_event_t *) calloc(1, sizeof(snd_seq_event_t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_seq_free_event_static(snd_seq_event_t *ev)
 | 
			
		||||
{
 | 
			
		||||
	if (!ev)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	switch (ev->flags & SND_SEQ_EVENT_LENGTH_MASK) {
 | 
			
		||||
	case SND_SEQ_EVENT_LENGTH_VARIABLE:
 | 
			
		||||
		if (ev->data.ext.ptr)
 | 
			
		||||
			free(ev->data.ext.ptr);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_free_event(snd_seq_event_t *ev)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if ((err = snd_seq_free_event_static(ev))<0)
 | 
			
		||||
		return err;
 | 
			
		||||
	free(ev);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_event_length(snd_seq_event_t *ev)
 | 
			
		||||
{
 | 
			
		||||
	int len = sizeof(snd_seq_event_t);
 | 
			
		||||
 | 
			
		||||
	if (!ev)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	switch (ev->flags & SND_SEQ_EVENT_LENGTH_MASK) {
 | 
			
		||||
	case SND_SEQ_EVENT_LENGTH_VARIABLE:
 | 
			
		||||
		len += ev->data.ext.len;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_event_output(void *handle, snd_seq_event_t *ev)
 | 
			
		||||
{
 | 
			
		||||
	int len;
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq || !ev)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	len = snd_seq_event_length(ev);
 | 
			
		||||
	if ((seq->obufsize - seq->obufused) < len) {
 | 
			
		||||
		snd_seq_flush_output(handle);
 | 
			
		||||
		if ((seq->obufsize - seq->obufused) < len)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(seq->obuf + seq->obufused, ev, sizeof(snd_seq_event_t));
 | 
			
		||||
	seq->obufused += sizeof(snd_seq_event_t);
 | 
			
		||||
	switch (ev->flags & SND_SEQ_EVENT_LENGTH_MASK) {
 | 
			
		||||
	case SND_SEQ_EVENT_LENGTH_VARIABLE:
 | 
			
		||||
		memcpy(seq->obuf + seq->obufused, ev->data.ext.ptr, ev->data.ext.len);
 | 
			
		||||
		seq->obufused += ev->data.ext.len;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return seq->obufused;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_seq_cell_t *snd_seq_create_cell(snd_seq_event_t *ev)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_cell_t *cell;
 | 
			
		||||
 | 
			
		||||
	cell = (snd_seq_cell_t *) calloc(1, sizeof(snd_seq_cell_t));
 | 
			
		||||
	if (!cell)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	if (ev)
 | 
			
		||||
		memcpy(&cell->ev, ev, sizeof(snd_seq_event_t));
 | 
			
		||||
	return cell;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_seq_free_cell(snd_seq_cell_t *cell)
 | 
			
		||||
{
 | 
			
		||||
	if (!cell)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	snd_seq_free_event_static(&cell->ev);
 | 
			
		||||
	free(cell);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_seq_cell_t *snd_seq_input_cell_out(snd_seq_t *seq)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_cell_t *cell;
 | 
			
		||||
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	if (seq->head) {
 | 
			
		||||
		cell = seq->head;
 | 
			
		||||
		seq->head = cell->next;
 | 
			
		||||
		seq->cells--;
 | 
			
		||||
		if (!seq->head)
 | 
			
		||||
			seq->tail = NULL;
 | 
			
		||||
		return cell;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_seq_input_cell_in(snd_seq_t *seq, snd_seq_cell_t *cell)
 | 
			
		||||
{
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	cell->next = NULL;
 | 
			
		||||
	if (!seq->tail) {
 | 
			
		||||
		seq->head = seq->tail = cell;
 | 
			
		||||
	} else {
 | 
			
		||||
		seq->tail->next = cell;
 | 
			
		||||
		seq->tail = cell;
 | 
			
		||||
	}
 | 
			
		||||
	seq->cells++;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_seq_input_cell_available(snd_seq_t *seq)
 | 
			
		||||
{
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	return seq->cells > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_seq_decode_event(char **buf, int *len, snd_seq_event_t *ev)
 | 
			
		||||
{
 | 
			
		||||
	if (!ev || !buf || !*buf || !len )
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (*len < sizeof(snd_seq_event_t)) {
 | 
			
		||||
		*len = 0;
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(ev, *buf, sizeof(snd_seq_event_t));
 | 
			
		||||
	*buf += sizeof(snd_seq_event_t);
 | 
			
		||||
	*len -= sizeof(snd_seq_event_t);
 | 
			
		||||
	switch (ev->flags & SND_SEQ_EVENT_LENGTH_MASK) {
 | 
			
		||||
	case SND_SEQ_EVENT_LENGTH_VARIABLE:
 | 
			
		||||
		if (*len < ev->data.ext.len) {
 | 
			
		||||
			*len = 0;
 | 
			
		||||
			return -ENOENT;
 | 
			
		||||
		}
 | 
			
		||||
		if (ev->data.ext.len > 0) {
 | 
			
		||||
			ev->data.ext.ptr = (char *) malloc(ev->data.ext.len);
 | 
			
		||||
			if (!(ev->data.ext.ptr)) {
 | 
			
		||||
				*buf += ev->data.ext.len;
 | 
			
		||||
				*len -= ev->data.ext.len;
 | 
			
		||||
				return -ENOENT;
 | 
			
		||||
			}
 | 
			
		||||
			memcpy(ev->data.ext.ptr, *buf, ev->data.ext.len);
 | 
			
		||||
			*buf += ev->data.ext.len;
 | 
			
		||||
			*len -= ev->data.ext.len;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  Current implementation uses FIFO cache.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int snd_seq_event_input(void *handle, snd_seq_event_t **ev)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
	snd_seq_cell_t *cell;
 | 
			
		||||
	char *buf;
 | 
			
		||||
	int count;
 | 
			
		||||
 | 
			
		||||
	*ev = NULL;
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (snd_seq_input_cell_available(seq)) {
 | 
			
		||||
		*ev = snd_seq_create_event();
 | 
			
		||||
		if (*ev == NULL)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		cell = snd_seq_input_cell_out(seq);
 | 
			
		||||
		memcpy(*ev, &cell->ev, sizeof(snd_seq_event_t));
 | 
			
		||||
		return seq->cells;
 | 
			
		||||
	}
 | 
			
		||||
	count = read(seq->fd, seq->ibuf, seq->ibufsize);
 | 
			
		||||
	if (count < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	buf = seq->ibuf;
 | 
			
		||||
	while (count > 0) {
 | 
			
		||||
		if (*ev == NULL) {	/* first event */
 | 
			
		||||
			*ev = snd_seq_create_event();
 | 
			
		||||
			if (*ev == NULL)
 | 
			
		||||
				return -ENOMEM;
 | 
			
		||||
			if (snd_seq_decode_event(&buf, &count, *ev)<0) {
 | 
			
		||||
				snd_seq_free_event(*ev);
 | 
			
		||||
				*ev = NULL;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			cell = snd_seq_create_cell(NULL);
 | 
			
		||||
			if (cell == NULL)
 | 
			
		||||
				return -ENOMEM;
 | 
			
		||||
			if (snd_seq_decode_event(&buf, &count, &cell->ev)<0) {
 | 
			
		||||
				snd_seq_free_cell(cell);
 | 
			
		||||
			} else {
 | 
			
		||||
				snd_seq_input_cell_in(seq, cell);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return seq->cells;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_flush_output(void *handle)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (seq->obufused <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
	result = write(seq->fd, seq->obuf, seq->obufused);
 | 
			
		||||
	if (result < 0)	{
 | 
			
		||||
		snd_seq_drain_output(handle);
 | 
			
		||||
		return -errno;
 | 
			
		||||
	}
 | 
			
		||||
	if (result < seq->obufused)
 | 
			
		||||
		memmove(seq->obuf, seq->obuf + result, seq->obufused - result);
 | 
			
		||||
	seq->obufused -= result;
 | 
			
		||||
	return seq->obufused;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_drain_output(void *handle)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	seq->obufused = 0;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_drain_input(void *handle)
 | 
			
		||||
{
 | 
			
		||||
	snd_seq_t *seq;
 | 
			
		||||
 | 
			
		||||
	seq = (snd_seq_t *) handle;
 | 
			
		||||
	if (!seq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	while (snd_seq_input_cell_available(seq))
 | 
			
		||||
		snd_seq_free_cell(snd_seq_input_cell_out(seq));
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void snd_seq_set_bit(int nr, void *array)
 | 
			
		||||
{
 | 
			
		||||
	((unsigned int *)array)[nr >> 5] |= 1UL << (nr & 31);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_change_bit(int nr, void *array)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	result = ((((unsigned int *)array)[nr >> 5]) & (1UL << (nr & 31))) ? 1 : 0;
 | 
			
		||||
	((unsigned int *)array)[nr >> 5] |= 1UL << (nr & 31);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_seq_get_bit(int nr, void *array)
 | 
			
		||||
{
 | 
			
		||||
	return ((((unsigned int *)array)[nr >> 5]) & (1UL << (nr & 31))) ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue