xref: /openbsd-src/lib/libsndio/mio_rmidi.c (revision dd964a889cf8922473a69d35b78f2faa280d4c12)
1*dd964a88Sratchov /*	$OpenBSD: mio_rmidi.c,v 1.8 2011/04/12 21:40:22 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>
196efede29Sratchov #include <sys/stat.h>
2032917b69Sratchov 
216efede29Sratchov #include <errno.h>
226efede29Sratchov #include <fcntl.h>
2332917b69Sratchov #include <limits.h>
246efede29Sratchov #include <poll.h>
256efede29Sratchov #include <stdio.h>
266efede29Sratchov #include <stdlib.h>
276efede29Sratchov #include <string.h>
286efede29Sratchov #include <unistd.h>
296efede29Sratchov 
306efede29Sratchov #include "mio_priv.h"
316efede29Sratchov 
32*dd964a88Sratchov struct mio_rmidi_hdl {
336efede29Sratchov 	struct mio_hdl mio;
346efede29Sratchov 	int fd;
356efede29Sratchov };
366efede29Sratchov 
37*dd964a88Sratchov static void mio_rmidi_close(struct mio_hdl *);
38*dd964a88Sratchov static size_t mio_rmidi_read(struct mio_hdl *, void *, size_t);
39*dd964a88Sratchov static size_t mio_rmidi_write(struct mio_hdl *, const void *, size_t);
40*dd964a88Sratchov static int mio_rmidi_pollfd(struct mio_hdl *, struct pollfd *, int);
41*dd964a88Sratchov static int mio_rmidi_revents(struct mio_hdl *, struct pollfd *);
426efede29Sratchov 
43*dd964a88Sratchov static struct mio_ops mio_rmidi_ops = {
44*dd964a88Sratchov 	mio_rmidi_close,
45*dd964a88Sratchov 	mio_rmidi_write,
46*dd964a88Sratchov 	mio_rmidi_read,
47*dd964a88Sratchov 	mio_rmidi_pollfd,
48*dd964a88Sratchov 	mio_rmidi_revents,
496efede29Sratchov };
506efede29Sratchov 
516efede29Sratchov struct mio_hdl *
52*dd964a88Sratchov mio_rmidi_open(const char *str, unsigned mode, int nbio)
536efede29Sratchov {
546efede29Sratchov 	int fd, flags;
55*dd964a88Sratchov 	struct mio_rmidi_hdl *hdl;
566efede29Sratchov 	char path[PATH_MAX];
576efede29Sratchov 
58*dd964a88Sratchov 	hdl = malloc(sizeof(struct mio_rmidi_hdl));
596efede29Sratchov 	if (hdl == NULL)
606efede29Sratchov 		return NULL;
61*dd964a88Sratchov 	mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio);
626efede29Sratchov 
636efede29Sratchov 	snprintf(path, sizeof(path), "/dev/rmidi%s", str);
646efede29Sratchov 	if (mode == (MIO_OUT | MIO_IN))
656efede29Sratchov 		flags = O_RDWR;
666efede29Sratchov 	else
676efede29Sratchov 		flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY;
689d75d49dSratchov 	if (nbio)
699d75d49dSratchov 		flags |= O_NONBLOCK;
709d75d49dSratchov 	while ((fd = open(path, flags)) < 0) {
716efede29Sratchov 		if (errno == EINTR)
726efede29Sratchov 			continue;
736efede29Sratchov 		DPERROR(path);
746efede29Sratchov 		goto bad_free;
756efede29Sratchov 	}
766efede29Sratchov 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
776efede29Sratchov 		DPERROR("FD_CLOEXEC");
786efede29Sratchov 		goto bad_close;
796efede29Sratchov 	}
806efede29Sratchov 	hdl->fd = fd;
816efede29Sratchov 	return (struct mio_hdl *)hdl;
826efede29Sratchov  bad_close:
836efede29Sratchov 	while (close(hdl->fd) < 0 && errno == EINTR)
846efede29Sratchov 		; /* retry */
856efede29Sratchov  bad_free:
866efede29Sratchov 	free(hdl);
876efede29Sratchov 	return NULL;
886efede29Sratchov }
896efede29Sratchov 
906efede29Sratchov static void
91*dd964a88Sratchov mio_rmidi_close(struct mio_hdl *sh)
926efede29Sratchov {
93*dd964a88Sratchov 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
946efede29Sratchov 	int rc;
956efede29Sratchov 
966efede29Sratchov 	do {
976efede29Sratchov 		rc = close(hdl->fd);
986efede29Sratchov 	} while (rc < 0 && errno == EINTR);
996efede29Sratchov 	free(hdl);
1006efede29Sratchov }
1016efede29Sratchov 
1026efede29Sratchov static size_t
103*dd964a88Sratchov mio_rmidi_read(struct mio_hdl *sh, void *buf, size_t len)
1046efede29Sratchov {
105*dd964a88Sratchov 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
1066efede29Sratchov 	ssize_t n;
1076efede29Sratchov 
1086efede29Sratchov 	while ((n = read(hdl->fd, buf, len)) < 0) {
1096efede29Sratchov 		if (errno == EINTR)
1106efede29Sratchov 			continue;
1116efede29Sratchov 		if (errno != EAGAIN) {
112*dd964a88Sratchov 			DPERROR("mio_rmidi_read: read");
1136efede29Sratchov 			hdl->mio.eof = 1;
1146efede29Sratchov 		}
1156efede29Sratchov 		return 0;
1166efede29Sratchov 	}
1176efede29Sratchov 	if (n == 0) {
118*dd964a88Sratchov 		DPRINTF("mio_rmidi_read: eof\n");
1196efede29Sratchov 		hdl->mio.eof = 1;
1206efede29Sratchov 		return 0;
1216efede29Sratchov 	}
1226efede29Sratchov 	return n;
1236efede29Sratchov }
1246efede29Sratchov 
1256efede29Sratchov static size_t
126*dd964a88Sratchov mio_rmidi_write(struct mio_hdl *sh, const void *buf, size_t len)
1276efede29Sratchov {
128*dd964a88Sratchov 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
1296efede29Sratchov 	ssize_t n;
1306efede29Sratchov 
1316efede29Sratchov 	while ((n = write(hdl->fd, buf, len)) < 0) {
1326efede29Sratchov 		if (errno == EINTR)
1336efede29Sratchov 			continue;
1346efede29Sratchov 		if (errno != EAGAIN) {
135*dd964a88Sratchov 			DPERROR("mio_rmidi_write: write");
1366efede29Sratchov 			hdl->mio.eof = 1;
1376efede29Sratchov 		}
1386efede29Sratchov  		return 0;
1396efede29Sratchov 	}
1406efede29Sratchov 	return n;
1416efede29Sratchov }
1426efede29Sratchov 
1436efede29Sratchov static int
144*dd964a88Sratchov mio_rmidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events)
1456efede29Sratchov {
146*dd964a88Sratchov 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
1476efede29Sratchov 
1486efede29Sratchov 	pfd->fd = hdl->fd;
1496efede29Sratchov 	pfd->events = events;
1506efede29Sratchov 	return 1;
1516efede29Sratchov }
1526efede29Sratchov 
153ee5ea84aSratchov static int
154*dd964a88Sratchov mio_rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
1556efede29Sratchov {
1566efede29Sratchov 	return pfd->revents;
1576efede29Sratchov }
158