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