xref: /openbsd-src/lib/libsndio/mio.c (revision 95d14907e3e7b1337604dc538627d0a76dab909f)
1*95d14907Sratchov /*	$OpenBSD: mio.c,v 1.23 2019/06/29 06:05:26 ratchov Exp $	*/
26efede29Sratchov /*
36efede29Sratchov  * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
46efede29Sratchov  *
56efede29Sratchov  * Permission to use, copy, modify, and distribute this software for any
66efede29Sratchov  * purpose with or without fee is hereby granted, provided that the above
76efede29Sratchov  * copyright notice and this permission notice appear in all copies.
86efede29Sratchov  *
96efede29Sratchov  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
106efede29Sratchov  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116efede29Sratchov  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
126efede29Sratchov  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
136efede29Sratchov  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146efede29Sratchov  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
156efede29Sratchov  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166efede29Sratchov  */
1732917b69Sratchov 
186efede29Sratchov #include <sys/types.h>
196efede29Sratchov #include <sys/time.h>
2032917b69Sratchov 
216efede29Sratchov #include <errno.h>
226efede29Sratchov #include <fcntl.h>
236efede29Sratchov #include <poll.h>
246efede29Sratchov #include <stdio.h>
256efede29Sratchov #include <stdlib.h>
2632917b69Sratchov #include <string.h>
276efede29Sratchov #include <unistd.h>
286efede29Sratchov 
2982bfc72bSratchov #include "debug.h"
306efede29Sratchov #include "mio_priv.h"
316efede29Sratchov 
326efede29Sratchov struct mio_hdl *
mio_open(const char * str,unsigned int mode,int nbio)337207b069Sratchov mio_open(const char *str, unsigned int mode, int nbio)
346efede29Sratchov {
359f9aa69fSratchov 	static char portany[] = MIO_PORTANY;
366efede29Sratchov 	struct mio_hdl *hdl;
376efede29Sratchov 
3882bfc72bSratchov #ifdef DEBUG
39d418f94bSratchov 	_sndio_debug_init();
406efede29Sratchov #endif
416efede29Sratchov 	if ((mode & (MIO_OUT | MIO_IN)) == 0)
426efede29Sratchov 		return NULL;
439f9aa69fSratchov 	if (str == NULL) /* backward compat */
449f9aa69fSratchov 		str = portany;
459f9aa69fSratchov 	if (strcmp(str, portany) == 0 && !issetugid()) {
466efede29Sratchov 		str = getenv("MIDIDEVICE");
479f9aa69fSratchov 		if (str == NULL)
489f9aa69fSratchov 			str = portany;
499f9aa69fSratchov 	}
509f9aa69fSratchov 	if (strcmp(str, portany) == 0) {
51163486f8Sratchov 		hdl = _mio_aucat_open("midithru/0", mode, nbio);
526efede29Sratchov 		if (hdl != NULL)
536efede29Sratchov 			return hdl;
54163486f8Sratchov 		return _mio_rmidi_open("rmidi/0", mode, nbio);
556efede29Sratchov 	}
56163486f8Sratchov 	if (_sndio_parsetype(str, "snd") ||
57163486f8Sratchov 	    _sndio_parsetype(str, "midithru") ||
58163486f8Sratchov 	    _sndio_parsetype(str, "midi"))
59163486f8Sratchov 		return _mio_aucat_open(str, mode, nbio);
60163486f8Sratchov 	if (_sndio_parsetype(str, "rmidi"))
61163486f8Sratchov 		return _mio_rmidi_open(str, mode, nbio);
626efede29Sratchov 	DPRINTF("mio_open: %s: unknown device type\n", str);
636efede29Sratchov 	return NULL;
646efede29Sratchov }
656efede29Sratchov 
666efede29Sratchov void
_mio_create(struct mio_hdl * hdl,struct mio_ops * ops,unsigned int mode,int nbio)67d418f94bSratchov _mio_create(struct mio_hdl *hdl, struct mio_ops *ops,
687207b069Sratchov     unsigned int mode, int nbio)
696efede29Sratchov {
706efede29Sratchov 	hdl->ops = ops;
716efede29Sratchov 	hdl->mode = mode;
726efede29Sratchov 	hdl->nbio = nbio;
736efede29Sratchov 	hdl->eof = 0;
746efede29Sratchov }
756efede29Sratchov 
766efede29Sratchov void
mio_close(struct mio_hdl * hdl)776efede29Sratchov mio_close(struct mio_hdl *hdl)
786efede29Sratchov {
7911fea108Sratchov 	hdl->ops->close(hdl);
806efede29Sratchov }
816efede29Sratchov 
82cfb56cbfSratchov static int
mio_psleep(struct mio_hdl * hdl,int event)83cfb56cbfSratchov mio_psleep(struct mio_hdl *hdl, int event)
84cfb56cbfSratchov {
85cfb56cbfSratchov 	struct pollfd pfd[MIO_MAXNFDS];
86cfb56cbfSratchov 	int revents;
87cfb56cbfSratchov 	int nfds;
88cfb56cbfSratchov 
89cfb56cbfSratchov 	nfds = mio_nfds(hdl);
90cfb56cbfSratchov 	if (nfds > MIO_MAXNFDS) {
91cfb56cbfSratchov 		DPRINTF("mio_psleep: %d: too many descriptors\n", nfds);
92cfb56cbfSratchov 		hdl->eof = 1;
93cfb56cbfSratchov 		return 0;
94cfb56cbfSratchov 	}
95cfb56cbfSratchov 	for (;;) {
96cfb56cbfSratchov 		nfds = mio_pollfd(hdl, pfd, event);
97*95d14907Sratchov 		while (poll(pfd, nfds, -1) == -1) {
98cfb56cbfSratchov 			if (errno == EINTR)
99cfb56cbfSratchov 				continue;
100cfb56cbfSratchov 			DPERROR("mio_psleep: poll");
101cfb56cbfSratchov 			hdl->eof = 1;
102cfb56cbfSratchov 			return 0;
103cfb56cbfSratchov 		}
104cfb56cbfSratchov 		revents = mio_revents(hdl, pfd);
105cfb56cbfSratchov 		if (revents & POLLHUP) {
106cfb56cbfSratchov 			DPRINTF("mio_psleep: hang-up\n");
107cfb56cbfSratchov 			return 0;
108cfb56cbfSratchov 		}
109cfb56cbfSratchov 		if (revents & event)
110cfb56cbfSratchov 			break;
111cfb56cbfSratchov 	}
112cfb56cbfSratchov 	return 1;
113cfb56cbfSratchov }
114cfb56cbfSratchov 
1156efede29Sratchov size_t
mio_read(struct mio_hdl * hdl,void * buf,size_t len)1166efede29Sratchov mio_read(struct mio_hdl *hdl, void *buf, size_t len)
1176efede29Sratchov {
118cfb56cbfSratchov 	unsigned int n;
119cfb56cbfSratchov 	char *data = buf;
120cfb56cbfSratchov 	size_t todo = len;
121cfb56cbfSratchov 
1226efede29Sratchov 	if (hdl->eof) {
1236efede29Sratchov 		DPRINTF("mio_read: eof\n");
1246efede29Sratchov 		return 0;
1256efede29Sratchov 	}
1266efede29Sratchov 	if (!(hdl->mode & MIO_IN)) {
1276efede29Sratchov 		DPRINTF("mio_read: not input device\n");
1286efede29Sratchov 		hdl->eof = 1;
1296efede29Sratchov 		return 0;
1306efede29Sratchov 	}
131cfb56cbfSratchov 	while (todo > 0) {
132cfb56cbfSratchov 		n = hdl->ops->read(hdl, data, todo);
133cfb56cbfSratchov 		if (n == 0 && hdl->eof)
134cfb56cbfSratchov 			break;
135cfb56cbfSratchov 		data += n;
136cfb56cbfSratchov 		todo -= n;
137cfb56cbfSratchov 		if (n > 0 || hdl->nbio)
138cfb56cbfSratchov 			break;
139cfb56cbfSratchov 		if (!mio_psleep(hdl, POLLIN))
140cfb56cbfSratchov 			break;
141cfb56cbfSratchov 	}
142cfb56cbfSratchov 	return len - todo;
1436efede29Sratchov }
1446efede29Sratchov 
1456efede29Sratchov size_t
mio_write(struct mio_hdl * hdl,const void * buf,size_t len)1464c244198Sratchov mio_write(struct mio_hdl *hdl, const void *buf, size_t len)
1476efede29Sratchov {
148cfb56cbfSratchov 	unsigned int n;
149cfb56cbfSratchov 	const unsigned char *data = buf;
150cfb56cbfSratchov 	size_t todo = len;
151cfb56cbfSratchov 
1526efede29Sratchov 	if (hdl->eof) {
1536efede29Sratchov 		DPRINTF("mio_write: eof\n");
1546efede29Sratchov 		return 0;
1556efede29Sratchov 	}
1566efede29Sratchov 	if (!(hdl->mode & MIO_OUT)) {
1576efede29Sratchov 		DPRINTF("mio_write: not output device\n");
1586efede29Sratchov 		hdl->eof = 1;
1596efede29Sratchov 		return 0;
1606efede29Sratchov 	}
161cfb56cbfSratchov 	while (todo > 0) {
162cfb56cbfSratchov 		n = hdl->ops->write(hdl, data, todo);
163cfb56cbfSratchov 		if (n == 0) {
164cfb56cbfSratchov 			if (hdl->nbio || hdl->eof)
165cfb56cbfSratchov 				break;
166cfb56cbfSratchov 			if (!mio_psleep(hdl, POLLOUT))
167cfb56cbfSratchov 				break;
168cfb56cbfSratchov 			continue;
169cfb56cbfSratchov 		}
170cfb56cbfSratchov 		data += n;
171cfb56cbfSratchov 		todo -= n;
172cfb56cbfSratchov 	}
173cfb56cbfSratchov 	return len - todo;
1746efede29Sratchov }
1756efede29Sratchov 
1766efede29Sratchov int
mio_nfds(struct mio_hdl * hdl)1776efede29Sratchov mio_nfds(struct mio_hdl *hdl)
1786efede29Sratchov {
179cfb56cbfSratchov 	return hdl->ops->nfds(hdl);
1806efede29Sratchov }
1816efede29Sratchov 
1826efede29Sratchov int
mio_pollfd(struct mio_hdl * hdl,struct pollfd * pfd,int events)1836efede29Sratchov mio_pollfd(struct mio_hdl *hdl, struct pollfd *pfd, int events)
1846efede29Sratchov {
1856efede29Sratchov 	if (hdl->eof)
1866efede29Sratchov 		return 0;
1876efede29Sratchov 	return hdl->ops->pollfd(hdl, pfd, events);
1886efede29Sratchov }
1896efede29Sratchov 
1906efede29Sratchov int
mio_revents(struct mio_hdl * hdl,struct pollfd * pfd)1916efede29Sratchov mio_revents(struct mio_hdl *hdl, struct pollfd *pfd)
1926efede29Sratchov {
1936efede29Sratchov 	if (hdl->eof)
1946efede29Sratchov 		return POLLHUP;
1956efede29Sratchov 	return hdl->ops->revents(hdl, pfd);
1966efede29Sratchov }
1976efede29Sratchov 
1986efede29Sratchov int
mio_eof(struct mio_hdl * hdl)1996efede29Sratchov mio_eof(struct mio_hdl *hdl)
2006efede29Sratchov {
2016efede29Sratchov 	return hdl->eof;
2026efede29Sratchov }
203