/* * Sequencer Interface - main file * Copyright (c) 2000 by Jaroslav Kysela * Abramo Bagnara * * * 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 #include #include "seq_local.h" #include "asoundlib.h" #define SND_FILE_SEQ "/dev/snd/seq" #define SND_FILE_ALOADSEQ "/dev/aloadSEQ" #define SND_SEQ_VERSION_MAX SND_PROTOCOL_VERSION(1, 0, 0) typedef struct { int fd; } snd_seq_hw_t; static int snd_seq_hw_close(snd_seq_t *seq) { snd_seq_hw_t *hw = seq->private; if (close(hw->fd)) { SYSERR("close failed\n"); return -errno; } free(hw); return 0; } static int snd_seq_hw_nonblock(snd_seq_t *seq, int nonblock) { snd_seq_hw_t *hw = seq->private; long flags; if ((flags = fcntl(hw->fd, F_GETFL)) < 0) { SYSERR("F_GETFL failed"); return -errno; } if (nonblock) flags &= ~O_NONBLOCK; else flags |= O_NONBLOCK; if (fcntl(hw->fd, F_SETFL, flags) < 0) { SYSERR("F_SETFL for O_NONBLOCK failed"); return -errno; } return 0; } static int snd_seq_hw_client_id(snd_seq_t *seq) { snd_seq_hw_t *hw = seq->private; int client; if (ioctl(hw->fd, SND_SEQ_IOCTL_CLIENT_ID, &client) < 0) { SYSERR("SND_SEQ_IOCTL_CLIENT_ID failed"); return -errno; } return client; } static int snd_seq_hw_system_info(snd_seq_t *seq, snd_seq_system_info_t * info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SYSTEM_INFO, info) < 0) { SYSERR("SND_SEQ_IOCTL_SYSTEM_INFO failed"); return -errno; } return 0; } static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0) { SYSERR("SND_SEQ_IOCTL_GET_CLIENT_INFO failed"); return -errno; } return 0; } static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) { SYSERR("SND_SEQ_IOCTL_SET_CLIENT_INFO failed"); return -errno; } return 0; } static int snd_seq_hw_create_port(snd_seq_t *seq, snd_seq_port_info_t * port) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_CREATE_PORT, port) < 0) { SYSERR("SND_SEQ_IOCTL_CREATE_PORT failed"); return -errno; } return 0; } static int snd_seq_hw_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_DELETE_PORT, port) < 0) { SYSERR("SND_SEQ_IOCTL_DELETE_PORT failed"); return -errno; } return 0; } static int snd_seq_hw_get_port_info(snd_seq_t *seq, snd_seq_port_info_t * info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_PORT_INFO, info) < 0) { SYSERR("SND_SEQ_IOCTL_GET_PORT_INFO failed"); return -errno; } return 0; } static int snd_seq_hw_set_port_info(snd_seq_t *seq, snd_seq_port_info_t * info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_PORT_INFO, info) < 0) { SYSERR("SND_SEQ_IOCTL_SET_PORT_INFO failed"); return -errno; } return 0; } static int snd_seq_hw_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_SUBSCRIPTION, sub) < 0) { SYSERR("SND_SEQ_IOCTL_GET_SUBSCRIPTION failed"); return -errno; } return 0; } static int snd_seq_hw_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0) { SYSERR("SND_SEQ_IOCTL_SUBSCRIBE_PORT failed"); return -errno; } return 0; } static int snd_seq_hw_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0) { SYSERR("SND_SEQ_IOCTL_UNSUBSCRIBE_PORT failed"); return -errno; } return 0; } static int snd_seq_hw_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subs_t * subs) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_SUBS, subs) < 0) { SYSERR("SND_SEQ_IOCTL_QUERY_SUBS failed"); return -errno; } return 0; } static int snd_seq_hw_get_queue_status(snd_seq_t *seq, snd_seq_queue_status_t * status) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_STATUS, status) < 0) { SYSERR("SND_SEQ_IOCTL_GET_QUEUE_STATUS failed"); return -errno; } return 0; } static int snd_seq_hw_get_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_TEMPO, tempo) < 0) { SYSERR("SND_SEQ_IOCTL_GET_QUEUE_TEMPO failed"); return -errno; } return 0; } static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) { SYSERR("SND_SEQ_IOCTL_SET_QUEUE_TEMPO failed"); return -errno; } return 0; } static int snd_seq_hw_get_queue_owner(snd_seq_t *seq, snd_seq_queue_owner_t * owner) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_OWNER, owner) < 0) { SYSERR("SND_SEQ_IOCTL_GET_QUEUE_OWNER failed"); return -errno; } return 0; } static int snd_seq_hw_set_queue_owner(snd_seq_t *seq, snd_seq_queue_owner_t * owner) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_OWNER, owner) < 0) { SYSERR("SND_SEQ_IOCTL_SET_QUEUE_OWNER failed"); return -errno; } return 0; } static int snd_seq_hw_get_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_TIMER, timer) < 0) { SYSERR("SND_SEQ_IOCTL_GET_QUEUE_TIMER failed"); return -errno; } return 0; } static int snd_seq_hw_set_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_TIMER, timer) < 0) { SYSERR("SND_SEQ_IOCTL_SET_QUEUE_TIMER failed"); return -errno; } return 0; } static int snd_seq_hw_get_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0) { SYSERR("SND_SEQ_IOCTL_GET_QUEUE_CLIENT failed"); return -errno; } return 0; } static int snd_seq_hw_set_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0) { SYSERR("SND_SEQ_IOCTL_SET_QUEUE_CLIENT failed"); return -errno; } return 0; } static int snd_seq_hw_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_CREATE_QUEUE, info) < 0) { SYSERR("SND_SEQ_IOCTL_CREATE_QUEUE failed"); return -errno; } return 0; } static int snd_seq_hw_delete_queue(snd_seq_t *seq, snd_seq_queue_info_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_DELETE_QUEUE, info) < 0) { SYSERR("SND_SEQ_IOCTL_DELETE_QUEUE failed"); return -errno; } return 0; } static int snd_seq_hw_get_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0) { SYSERR("SND_SEQ_IOCTL_GET_QUEUE_INFO failed"); return -errno; } return 0; } static int snd_seq_hw_set_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0) { SYSERR("SND_SEQ_IOCTL_SET_QUEUE_INFO failed"); return -errno; } return 0; } static int snd_seq_hw_get_named_queue(snd_seq_t *seq, snd_seq_queue_info_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_NAMED_QUEUE, info) < 0) { SYSERR("SND_SEQ_IOCTL_GET_NAMED_QUEUE failed"); return -errno; } return 0; } static ssize_t snd_seq_hw_write(snd_seq_t *seq, void *buf, size_t len) { snd_seq_hw_t *hw = seq->private; ssize_t result = write(hw->fd, buf, len); if (result < 0) return -errno; return result; } static ssize_t snd_seq_hw_read(snd_seq_t *seq, void *buf, size_t len) { snd_seq_hw_t *hw = seq->private; ssize_t result = read(hw->fd, buf, len); if (result < 0) return -errno; return result; } static int snd_seq_hw_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_REMOVE_EVENTS, rmp) < 0) { SYSERR("SND_SEQ_IOCTL_REMOVE_EVENTS failed"); return -errno; } return 0; } static int snd_seq_hw_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0) { SYSERR("SND_SEQ_IOCTL_GET_CLIENT_POOL failed"); return -errno; } return 0; } static int snd_seq_hw_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0) { SYSERR("SND_SEQ_IOCTL_SET_CLIENT_POOL failed"); return -errno; } return 0; } static int snd_seq_hw_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_NEXT_CLIENT, info) < 0) { SYSERR("SND_SEQ_IOCTL_QUERY_NEXT_CLIENT failed"); return -errno; } return 0; } static int snd_seq_hw_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info) { snd_seq_hw_t *hw = seq->private; if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_NEXT_PORT, info) < 0) { SYSERR("SND_SEQ_IOCTL_QUERY_NEXT_PORT failed"); return -errno; } return 0; } snd_seq_ops_t snd_seq_hw_ops = { close: snd_seq_hw_close, nonblock: snd_seq_hw_nonblock, system_info: snd_seq_hw_system_info, get_client_info: snd_seq_hw_get_client_info, set_client_info: snd_seq_hw_set_client_info, create_port: snd_seq_hw_create_port, delete_port: snd_seq_hw_delete_port, get_port_info: snd_seq_hw_get_port_info, set_port_info: snd_seq_hw_set_port_info, get_port_subscription: snd_seq_hw_get_port_subscription, subscribe_port: snd_seq_hw_subscribe_port, unsubscribe_port: snd_seq_hw_unsubscribe_port, query_port_subscribers: snd_seq_hw_query_port_subscribers, get_queue_status: snd_seq_hw_get_queue_status, get_queue_tempo: snd_seq_hw_get_queue_tempo, set_queue_tempo: snd_seq_hw_set_queue_tempo, get_queue_owner: snd_seq_hw_get_queue_owner, set_queue_owner: snd_seq_hw_set_queue_owner, get_queue_timer: snd_seq_hw_get_queue_timer, set_queue_timer: snd_seq_hw_set_queue_timer, get_queue_client: snd_seq_hw_get_queue_client, set_queue_client: snd_seq_hw_set_queue_client, create_queue: snd_seq_hw_create_queue, delete_queue: snd_seq_hw_delete_queue, get_queue_info: snd_seq_hw_get_queue_info, set_queue_info: snd_seq_hw_set_queue_info, get_named_queue: snd_seq_hw_get_named_queue, write: snd_seq_hw_write, read: snd_seq_hw_read, remove_events: snd_seq_hw_remove_events, get_client_pool: snd_seq_hw_get_client_pool, set_client_pool: snd_seq_hw_set_client_pool, query_next_client: snd_seq_hw_query_next_client, query_next_port: snd_seq_hw_query_next_port, }; int snd_seq_hw_open(snd_seq_t **handle, char *name, int streams, int mode) { int fd, ver, client, fmode; char filename[32]; snd_seq_t *seq; snd_seq_hw_t *hw; *handle = NULL; switch (streams) { case SND_SEQ_OPEN_OUTPUT: fmode = O_WRONLY; break; case SND_SEQ_OPEN_INPUT: fmode = O_RDONLY; break; case SND_SEQ_OPEN_DUPLEX: fmode = O_RDWR; break; default: assert(0); return -EINVAL; } if (mode & SND_SEQ_NONBLOCK) fmode |= O_NONBLOCK; sprintf(filename, SND_FILE_SEQ); if ((fd = open(filename, fmode)) < 0) { close(open(SND_FILE_ALOADSEQ, O_RDWR)); if ((fd = open(filename, fmode)) < 0) { SYSERR("open %s failed", filename); return -errno; } } if (ioctl(fd, SND_SEQ_IOCTL_PVERSION, &ver) < 0) { SYSERR("SND_SEQ_IOCTL_PVERSION failed"); close(fd); return -errno; } if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_SEQ_VERSION_MAX)) { close(fd); return -SND_ERROR_INCOMPATIBLE_VERSION; } hw = calloc(1, sizeof(snd_seq_hw_t)); if (hw == NULL) { close(fd); return -ENOMEM; } seq = calloc(1, sizeof(snd_seq_t)); if (seq == NULL) { free(hw); close(fd); return -ENOMEM; } hw->fd = fd; if (streams & SND_SEQ_OPEN_OUTPUT) { seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE); if (!seq->obuf) { free(hw); free(seq); close(fd); return -ENOMEM; } } if (streams & SND_SEQ_OPEN_INPUT) { seq->ibuf = (snd_seq_event_t *) calloc(sizeof(snd_seq_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE); if (!seq->ibuf) { free(seq->ibuf); free(hw); free(seq); close(fd); return -ENOMEM; } } if (name) seq->name = strdup(name); seq->type = SND_SEQ_TYPE_HW; seq->streams = streams; seq->mode = mode; seq->tmpbuf = NULL; seq->tmpbufsize = 0; seq->poll_fd = fd; seq->ops = &snd_seq_hw_ops; seq->private = hw; client = snd_seq_hw_client_id(seq); if (client < 0) { snd_seq_close(seq); return client; } else seq->client = client; *handle = seq; return 0; } int _snd_seq_hw_open(snd_seq_t **handlep, char *name, snd_config_t *conf, int streams, int mode) { snd_config_iterator_t i; snd_config_foreach(i, conf) { snd_config_t *n = snd_config_entry(i); if (strcmp(n->id, "comment") == 0) continue; if (strcmp(n->id, "type") == 0) continue; if (strcmp(n->id, "streams") == 0) continue; return -EINVAL; } return snd_seq_hw_open(handlep, name, streams, mode); }