153642Sguido/* $OpenBSD: mio.c,v 1.23 2019/06/29 06:05:26 ratchov Exp $ */ 260854Sdarrenr/* 353642Sguido * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> 453642Sguido * 553642Sguido * Permission to use, copy, modify, and distribute this software for any 653642Sguido * purpose with or without fee is hereby granted, provided that the above 753642Sguido * copyright notice and this permission notice appear in all copies. 853642Sguido * 953642Sguido * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1057126Sguido * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1153642Sguido * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1253642Sguido * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1353642Sguido * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1453642Sguido * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1553642Sguido * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1653642Sguido */ 1753642Sguido 1853642Sguido#include <sys/types.h> 1953642Sguido#include <sys/time.h> 2053642Sguido 2160854Sdarrenr#include <errno.h> 2260854Sdarrenr#include <fcntl.h> 2360854Sdarrenr#include <poll.h> 2460854Sdarrenr#include <stdio.h> 2553642Sguido#include <stdlib.h> 2653642Sguido#include <string.h> 2753642Sguido#include <unistd.h> 2853642Sguido 2953642Sguido#include "debug.h" 3053642Sguido#include "mio_priv.h" 3153642Sguido 3253642Sguidostruct mio_hdl * 3353642Sguidomio_open(const char *str, unsigned int mode, int nbio) 3453642Sguido{ 3560854Sdarrenr static char portany[] = MIO_PORTANY; 3653642Sguido struct mio_hdl *hdl; 3753642Sguido 3853642Sguido#ifdef DEBUG 3953642Sguido _sndio_debug_init(); 4053642Sguido#endif 4153642Sguido if ((mode & (MIO_OUT | MIO_IN)) == 0) 4253642Sguido return NULL; 4353642Sguido if (str == NULL) /* backward compat */ 4453642Sguido str = portany; 4553642Sguido if (strcmp(str, portany) == 0 && !issetugid()) { 4653642Sguido str = getenv("MIDIDEVICE"); 4753642Sguido if (str == NULL) 4853642Sguido str = portany; 4953642Sguido } 5057096Sguido if (strcmp(str, portany) == 0) { 5153642Sguido hdl = _mio_aucat_open("midithru/0", mode, nbio); 5253642Sguido if (hdl != NULL) 5353642Sguido return hdl; 5453642Sguido return _mio_rmidi_open("rmidi/0", mode, nbio); 5553642Sguido } 5653642Sguido if (_sndio_parsetype(str, "snd") || 5753642Sguido _sndio_parsetype(str, "midithru") || 5853642Sguido _sndio_parsetype(str, "midi")) 5953642Sguido return _mio_aucat_open(str, mode, nbio); 6053642Sguido if (_sndio_parsetype(str, "rmidi")) 6153642Sguido return _mio_rmidi_open(str, mode, nbio); 6253642Sguido DPRINTF("mio_open: %s: unknown device type\n", str); 6353642Sguido return NULL; 6453642Sguido} 6553642Sguido 6653642Sguidovoid 6753642Sguido_mio_create(struct mio_hdl *hdl, struct mio_ops *ops, 6853642Sguido unsigned int mode, int nbio) 6953642Sguido{ 7053642Sguido hdl->ops = ops; 7153642Sguido hdl->mode = mode; 7253642Sguido hdl->nbio = nbio; 7353642Sguido hdl->eof = 0; 7453642Sguido} 7553642Sguido 7653642Sguidovoid 7753642Sguidomio_close(struct mio_hdl *hdl) 7853642Sguido{ 7953642Sguido hdl->ops->close(hdl); 8053642Sguido} 8153642Sguido 8253642Sguidostatic int 8353642Sguidomio_psleep(struct mio_hdl *hdl, int event) 8453642Sguido{ 8553642Sguido struct pollfd pfd[MIO_MAXNFDS]; 8653642Sguido int revents; 8753642Sguido int nfds; 8853642Sguido 8960854Sdarrenr nfds = mio_nfds(hdl); 9060854Sdarrenr if (nfds > MIO_MAXNFDS) { 9160854Sdarrenr DPRINTF("mio_psleep: %d: too many descriptors\n", nfds); 9253642Sguido hdl->eof = 1; 9353642Sguido return 0; 9453642Sguido } 9553642Sguido for (;;) { 9653642Sguido nfds = mio_pollfd(hdl, pfd, event); 9753642Sguido while (poll(pfd, nfds, -1) == -1) { 9853642Sguido if (errno == EINTR) 9953642Sguido continue; 10053642Sguido DPERROR("mio_psleep: poll"); 10153642Sguido hdl->eof = 1; 10253642Sguido return 0; 10353642Sguido } 10453642Sguido revents = mio_revents(hdl, pfd); 10553642Sguido if (revents & POLLHUP) { 10660854Sdarrenr DPRINTF("mio_psleep: hang-up\n"); 10760854Sdarrenr return 0; 10860854Sdarrenr } 10967614Sdarrenr if (revents & event) 11060854Sdarrenr break; 11153642Sguido } 11253642Sguido return 1; 11353642Sguido} 11453642Sguido 11553642Sguidosize_t 11660854Sdarrenrmio_read(struct mio_hdl *hdl, void *buf, size_t len) 11760854Sdarrenr{ 11860854Sdarrenr unsigned int n; 11960854Sdarrenr char *data = buf; 12053642Sguido size_t todo = len; 12153642Sguido 12260854Sdarrenr if (hdl->eof) { 12353642Sguido DPRINTF("mio_read: eof\n"); 12453642Sguido return 0; 12553642Sguido } 12660854Sdarrenr if (!(hdl->mode & MIO_IN)) { 12767614Sdarrenr DPRINTF("mio_read: not input device\n"); 12860854Sdarrenr hdl->eof = 1; 12960854Sdarrenr return 0; 13060854Sdarrenr } 13153642Sguido while (todo > 0) { 13253642Sguido n = hdl->ops->read(hdl, data, todo); 13353642Sguido if (n == 0 && hdl->eof) 13453642Sguido break; 13553642Sguido data += n; 13653642Sguido todo -= n; 13753642Sguido if (n > 0 || hdl->nbio) 13853642Sguido break; 13953642Sguido if (!mio_psleep(hdl, POLLIN)) 14067614Sdarrenr break; 14167614Sdarrenr } 14253642Sguido return len - todo; 14353642Sguido} 14453642Sguido 14553642Sguidosize_t 14660854Sdarrenrmio_write(struct mio_hdl *hdl, const void *buf, size_t len) 14760854Sdarrenr{ 14853642Sguido unsigned int n; 14960854Sdarrenr const unsigned char *data = buf; 15053642Sguido size_t todo = len; 15153642Sguido 15253642Sguido if (hdl->eof) { 15360854Sdarrenr DPRINTF("mio_write: eof\n"); 15460854Sdarrenr return 0; 15553642Sguido } 15653642Sguido if (!(hdl->mode & MIO_OUT)) { 15753642Sguido DPRINTF("mio_write: not output device\n"); 15853642Sguido hdl->eof = 1; 15953642Sguido return 0; 16060854Sdarrenr } 16160854Sdarrenr while (todo > 0) { 16260854Sdarrenr n = hdl->ops->write(hdl, data, todo); 16360854Sdarrenr if (n == 0) { 16460854Sdarrenr if (hdl->nbio || hdl->eof) 16560854Sdarrenr break; 16660854Sdarrenr if (!mio_psleep(hdl, POLLOUT)) 16760854Sdarrenr break; 16860854Sdarrenr continue; 16953642Sguido } 17053642Sguido data += n; 17153642Sguido todo -= n; 17253642Sguido } 17353642Sguido return len - todo; 17453642Sguido} 17553642Sguido 17653642Sguidoint 17760854Sdarrenrmio_nfds(struct mio_hdl *hdl) 17853642Sguido{ 17953642Sguido return hdl->ops->nfds(hdl); 18053642Sguido} 18153642Sguido 18253642Sguidoint 18353642Sguidomio_pollfd(struct mio_hdl *hdl, struct pollfd *pfd, int events) 18453642Sguido{ 18553642Sguido if (hdl->eof) 18664580Sdarrenr return 0; 18753642Sguido return hdl->ops->pollfd(hdl, pfd, events); 18853642Sguido} 18953642Sguido 19053642Sguidoint 19153642Sguidomio_revents(struct mio_hdl *hdl, struct pollfd *pfd) 19253642Sguido{ 19353642Sguido if (hdl->eof) 19453642Sguido return POLLHUP; 19553642Sguido return hdl->ops->revents(hdl, pfd); 19653642Sguido} 19753642Sguido 19860854Sdarrenrint 19960854Sdarrenrmio_eof(struct mio_hdl *hdl) 20053642Sguido{ 20160854Sdarrenr return hdl->eof; 20260854Sdarrenr} 20360854Sdarrenr