xref: /openbsd/lib/libsndio/mio_rmidi.c (revision 95d14907)
1*95d14907Sratchov /*	$OpenBSD: mio_rmidi.c,v 1.28 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  */
176efede29Sratchov 
186efede29Sratchov #include <sys/types.h>
1932917b69Sratchov 
206efede29Sratchov #include <errno.h>
216efede29Sratchov #include <fcntl.h>
2232917b69Sratchov #include <limits.h>
236efede29Sratchov #include <poll.h>
246efede29Sratchov #include <stdio.h>
256efede29Sratchov #include <stdlib.h>
266efede29Sratchov #include <string.h>
276efede29Sratchov #include <unistd.h>
286efede29Sratchov 
2982bfc72bSratchov #include "debug.h"
306efede29Sratchov #include "mio_priv.h"
316efede29Sratchov 
32130e1f1bSratchov #define DEVPATH_PREFIX	"/dev/rmidi"
3328996f62Sratchov #define DEVPATH_MAX 	(1 +		\
3428996f62Sratchov 	sizeof(DEVPATH_PREFIX) - 1 +	\
3528996f62Sratchov 	sizeof(int) * 3)
3628996f62Sratchov 
37dd964a88Sratchov struct mio_rmidi_hdl {
386efede29Sratchov 	struct mio_hdl mio;
396efede29Sratchov 	int fd;
406efede29Sratchov };
416efede29Sratchov 
42dd964a88Sratchov static void mio_rmidi_close(struct mio_hdl *);
43dd964a88Sratchov static size_t mio_rmidi_read(struct mio_hdl *, void *, size_t);
44dd964a88Sratchov static size_t mio_rmidi_write(struct mio_hdl *, const void *, size_t);
45cfb56cbfSratchov static int mio_rmidi_nfds(struct mio_hdl *);
46dd964a88Sratchov static int mio_rmidi_pollfd(struct mio_hdl *, struct pollfd *, int);
47dd964a88Sratchov static int mio_rmidi_revents(struct mio_hdl *, struct pollfd *);
486efede29Sratchov 
49dd964a88Sratchov static struct mio_ops mio_rmidi_ops = {
50dd964a88Sratchov 	mio_rmidi_close,
51dd964a88Sratchov 	mio_rmidi_write,
52dd964a88Sratchov 	mio_rmidi_read,
53cfb56cbfSratchov 	mio_rmidi_nfds,
54dd964a88Sratchov 	mio_rmidi_pollfd,
55cfb56cbfSratchov 	mio_rmidi_revents
566efede29Sratchov };
576efede29Sratchov 
58bde5d162Sratchov int
mio_rmidi_getfd(const char * str,unsigned int mode,int nbio)59163486f8Sratchov mio_rmidi_getfd(const char *str, unsigned int mode, int nbio)
606efede29Sratchov {
61163486f8Sratchov 	const char *p;
6228996f62Sratchov 	char path[DEVPATH_MAX];
63b44cb2caSratchov 	unsigned int devnum;
64163486f8Sratchov 	int fd, flags;
656efede29Sratchov 
66bde5d162Sratchov #ifdef DEBUG
67bde5d162Sratchov 	_sndio_debug_init();
68bde5d162Sratchov #endif
69163486f8Sratchov 	p = _sndio_parsetype(str, "rmidi");
70163486f8Sratchov 	if (p == NULL) {
71e08793abSmiko 		DPRINTF("mio_rmidi_getfd: %s: \"rmidi\" expected\n", str);
72163486f8Sratchov 		return -1;
73163486f8Sratchov 	}
74163486f8Sratchov 	switch (*p) {
75b3956098Sratchov 	case '/':
76163486f8Sratchov 		p++;
77b3956098Sratchov 		break;
78b3956098Sratchov 	default:
79163486f8Sratchov 		DPRINTF("mio_rmidi_getfd: %s: '/' expected\n", str);
80163486f8Sratchov 		return -1;
81b3956098Sratchov 	}
82163486f8Sratchov 	p = _sndio_parsenum(p, &devnum, 255);
83ad6eeec3Sratchov 	if (p == NULL) {
84163486f8Sratchov 		DPRINTF("mio_rmidi_getfd: %s: number expected after '/'\n", str);
85163486f8Sratchov 		return -1;
86b44cb2caSratchov 	}
87ad6eeec3Sratchov 	if (*p != '\0') {
88ad6eeec3Sratchov 		DPRINTF("mio_rmidi_getfd: junk at end of string: %s\n", p);
89ad6eeec3Sratchov 		return -1;
90ad6eeec3Sratchov 	}
91b44cb2caSratchov 	snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
926dcfe4ecSratchov 	if (mode == (MIO_IN | MIO_OUT))
936efede29Sratchov 		flags = O_RDWR;
946efede29Sratchov 	else
954aaa725dSratchov 		flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY;
96*95d14907Sratchov 	while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) == -1) {
976efede29Sratchov 		if (errno == EINTR)
986efede29Sratchov 			continue;
996efede29Sratchov 		DPERROR(path);
100163486f8Sratchov 		return -1;
1016efede29Sratchov 	}
102163486f8Sratchov 	return fd;
103163486f8Sratchov }
104163486f8Sratchov 
105bde5d162Sratchov struct mio_hdl *
mio_rmidi_fdopen(int fd,unsigned int mode,int nbio)106163486f8Sratchov mio_rmidi_fdopen(int fd, unsigned int mode, int nbio)
107163486f8Sratchov {
108163486f8Sratchov 	struct mio_rmidi_hdl *hdl;
109163486f8Sratchov 
110bde5d162Sratchov #ifdef DEBUG
111bde5d162Sratchov 	_sndio_debug_init();
112bde5d162Sratchov #endif
113163486f8Sratchov 	hdl = malloc(sizeof(struct mio_rmidi_hdl));
114163486f8Sratchov 	if (hdl == NULL)
115163486f8Sratchov 		return NULL;
116163486f8Sratchov 	_mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio);
1176efede29Sratchov 	hdl->fd = fd;
1186efede29Sratchov 	return (struct mio_hdl *)hdl;
119163486f8Sratchov }
120163486f8Sratchov 
121163486f8Sratchov struct mio_hdl *
_mio_rmidi_open(const char * str,unsigned int mode,int nbio)122163486f8Sratchov _mio_rmidi_open(const char *str, unsigned int mode, int nbio)
123163486f8Sratchov {
124163486f8Sratchov 	struct mio_hdl *hdl;
125163486f8Sratchov 	int fd;
126163486f8Sratchov 
127163486f8Sratchov 	fd = mio_rmidi_getfd(str, mode, nbio);
128*95d14907Sratchov 	if (fd == -1)
129163486f8Sratchov 		return NULL;
130163486f8Sratchov 	hdl = mio_rmidi_fdopen(fd, mode, nbio);
131163486f8Sratchov 	if (hdl != NULL)
132163486f8Sratchov 		return hdl;
133*95d14907Sratchov 	while (close(fd) == -1 && errno == EINTR)
134163486f8Sratchov 		; /* retry */
1356efede29Sratchov 	return NULL;
1366efede29Sratchov }
1376efede29Sratchov 
1386efede29Sratchov static void
mio_rmidi_close(struct mio_hdl * sh)139dd964a88Sratchov mio_rmidi_close(struct mio_hdl *sh)
1406efede29Sratchov {
141dd964a88Sratchov 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
1426efede29Sratchov 	int rc;
1436efede29Sratchov 
1446efede29Sratchov 	do {
1456efede29Sratchov 		rc = close(hdl->fd);
146*95d14907Sratchov 	} while (rc == -1 && errno == EINTR);
1476efede29Sratchov 	free(hdl);
1486efede29Sratchov }
1496efede29Sratchov 
1506efede29Sratchov static size_t
mio_rmidi_read(struct mio_hdl * sh,void * buf,size_t len)151dd964a88Sratchov mio_rmidi_read(struct mio_hdl *sh, void *buf, size_t len)
1526efede29Sratchov {
153dd964a88Sratchov 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
1546efede29Sratchov 	ssize_t n;
1556efede29Sratchov 
156*95d14907Sratchov 	while ((n = read(hdl->fd, buf, len)) == -1) {
1576efede29Sratchov 		if (errno == EINTR)
1586efede29Sratchov 			continue;
1596efede29Sratchov 		if (errno != EAGAIN) {
160dd964a88Sratchov 			DPERROR("mio_rmidi_read: read");
1616efede29Sratchov 			hdl->mio.eof = 1;
1626efede29Sratchov 		}
1636efede29Sratchov 		return 0;
1646efede29Sratchov 	}
1656efede29Sratchov 	if (n == 0) {
166dd964a88Sratchov 		DPRINTF("mio_rmidi_read: eof\n");
1676efede29Sratchov 		hdl->mio.eof = 1;
1686efede29Sratchov 		return 0;
1696efede29Sratchov 	}
1706efede29Sratchov 	return n;
1716efede29Sratchov }
1726efede29Sratchov 
1736efede29Sratchov static size_t
mio_rmidi_write(struct mio_hdl * sh,const void * buf,size_t len)174dd964a88Sratchov mio_rmidi_write(struct mio_hdl *sh, const void *buf, size_t len)
1756efede29Sratchov {
176dd964a88Sratchov 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
1776efede29Sratchov 	ssize_t n;
1786efede29Sratchov 
179*95d14907Sratchov 	while ((n = write(hdl->fd, buf, len)) == -1) {
1806efede29Sratchov 		if (errno == EINTR)
1816efede29Sratchov 			continue;
1826efede29Sratchov 		if (errno != EAGAIN) {
183dd964a88Sratchov 			DPERROR("mio_rmidi_write: write");
1846efede29Sratchov 			hdl->mio.eof = 1;
1856efede29Sratchov 		}
1866efede29Sratchov 		return 0;
1876efede29Sratchov 	}
1886efede29Sratchov 	return n;
1896efede29Sratchov }
1906efede29Sratchov 
1916efede29Sratchov static int
mio_rmidi_nfds(struct mio_hdl * sh)192cfb56cbfSratchov mio_rmidi_nfds(struct mio_hdl *sh)
193cfb56cbfSratchov {
194cfb56cbfSratchov 	return 1;
195cfb56cbfSratchov }
196cfb56cbfSratchov 
197cfb56cbfSratchov static int
mio_rmidi_pollfd(struct mio_hdl * sh,struct pollfd * pfd,int events)198dd964a88Sratchov mio_rmidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events)
1996efede29Sratchov {
200dd964a88Sratchov 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
2016efede29Sratchov 
2026efede29Sratchov 	pfd->fd = hdl->fd;
2036efede29Sratchov 	pfd->events = events;
2046efede29Sratchov 	return 1;
2056efede29Sratchov }
2066efede29Sratchov 
207ee5ea84aSratchov static int
mio_rmidi_revents(struct mio_hdl * sh,struct pollfd * pfd)208dd964a88Sratchov mio_rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
2096efede29Sratchov {
2106efede29Sratchov 	return pfd->revents;
2116efede29Sratchov }
212