xref: /openbsd-src/lib/libsndio/mio_rmidi.c (revision dd964a889cf8922473a69d35b78f2faa280d4c12)
1 /*	$OpenBSD: mio_rmidi.c,v 1.8 2011/04/12 21:40:22 ratchov Exp $	*/
2 /*
3  * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <limits.h>
24 #include <poll.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include "mio_priv.h"
31 
32 struct mio_rmidi_hdl {
33 	struct mio_hdl mio;
34 	int fd;
35 };
36 
37 static void mio_rmidi_close(struct mio_hdl *);
38 static size_t mio_rmidi_read(struct mio_hdl *, void *, size_t);
39 static size_t mio_rmidi_write(struct mio_hdl *, const void *, size_t);
40 static int mio_rmidi_pollfd(struct mio_hdl *, struct pollfd *, int);
41 static int mio_rmidi_revents(struct mio_hdl *, struct pollfd *);
42 
43 static struct mio_ops mio_rmidi_ops = {
44 	mio_rmidi_close,
45 	mio_rmidi_write,
46 	mio_rmidi_read,
47 	mio_rmidi_pollfd,
48 	mio_rmidi_revents,
49 };
50 
51 struct mio_hdl *
52 mio_rmidi_open(const char *str, unsigned mode, int nbio)
53 {
54 	int fd, flags;
55 	struct mio_rmidi_hdl *hdl;
56 	char path[PATH_MAX];
57 
58 	hdl = malloc(sizeof(struct mio_rmidi_hdl));
59 	if (hdl == NULL)
60 		return NULL;
61 	mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio);
62 
63 	snprintf(path, sizeof(path), "/dev/rmidi%s", str);
64 	if (mode == (MIO_OUT | MIO_IN))
65 		flags = O_RDWR;
66 	else
67 		flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY;
68 	if (nbio)
69 		flags |= O_NONBLOCK;
70 	while ((fd = open(path, flags)) < 0) {
71 		if (errno == EINTR)
72 			continue;
73 		DPERROR(path);
74 		goto bad_free;
75 	}
76 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
77 		DPERROR("FD_CLOEXEC");
78 		goto bad_close;
79 	}
80 	hdl->fd = fd;
81 	return (struct mio_hdl *)hdl;
82  bad_close:
83 	while (close(hdl->fd) < 0 && errno == EINTR)
84 		; /* retry */
85  bad_free:
86 	free(hdl);
87 	return NULL;
88 }
89 
90 static void
91 mio_rmidi_close(struct mio_hdl *sh)
92 {
93 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
94 	int rc;
95 
96 	do {
97 		rc = close(hdl->fd);
98 	} while (rc < 0 && errno == EINTR);
99 	free(hdl);
100 }
101 
102 static size_t
103 mio_rmidi_read(struct mio_hdl *sh, void *buf, size_t len)
104 {
105 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
106 	ssize_t n;
107 
108 	while ((n = read(hdl->fd, buf, len)) < 0) {
109 		if (errno == EINTR)
110 			continue;
111 		if (errno != EAGAIN) {
112 			DPERROR("mio_rmidi_read: read");
113 			hdl->mio.eof = 1;
114 		}
115 		return 0;
116 	}
117 	if (n == 0) {
118 		DPRINTF("mio_rmidi_read: eof\n");
119 		hdl->mio.eof = 1;
120 		return 0;
121 	}
122 	return n;
123 }
124 
125 static size_t
126 mio_rmidi_write(struct mio_hdl *sh, const void *buf, size_t len)
127 {
128 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
129 	ssize_t n;
130 
131 	while ((n = write(hdl->fd, buf, len)) < 0) {
132 		if (errno == EINTR)
133 			continue;
134 		if (errno != EAGAIN) {
135 			DPERROR("mio_rmidi_write: write");
136 			hdl->mio.eof = 1;
137 		}
138  		return 0;
139 	}
140 	return n;
141 }
142 
143 static int
144 mio_rmidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events)
145 {
146 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
147 
148 	pfd->fd = hdl->fd;
149 	pfd->events = events;
150 	return 1;
151 }
152 
153 static int
154 mio_rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
155 {
156 	return pfd->revents;
157 }
158