xref: /openbsd/lib/libsndio/mio.c (revision 898184e3)
1 /*	$OpenBSD: mio.c,v 1.17 2012/11/23 07:03:28 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/param.h>
19 #include <sys/types.h>
20 #include <sys/time.h>
21 #include <sys/stat.h>
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <poll.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "debug.h"
32 #include "mio_priv.h"
33 
34 struct mio_hdl *
35 mio_open(const char *str, unsigned int mode, int nbio)
36 {
37 	static char portany[] = MIO_PORTANY;
38 	struct mio_hdl *hdl;
39 	const char *p;
40 
41 #ifdef DEBUG
42 	sndio_debug_init();
43 #endif
44 	if ((mode & (MIO_OUT | MIO_IN)) == 0)
45 		return NULL;
46 	if (str == NULL) /* backward compat */
47 		str = portany;
48 	if (strcmp(str, portany) == 0 && !issetugid()) {
49 		str = getenv("MIDIDEVICE");
50 		if (str == NULL)
51 			str = portany;
52 	}
53 	if (strcmp(str, portany) == 0) {
54 		hdl = mio_aucat_open("/0", mode, nbio, 1);
55 		if (hdl != NULL)
56 			return hdl;
57 		return mio_rmidi_open("/0", mode, nbio);
58 	}
59 	if ((p = sndio_parsetype(str, "snd")) != NULL ||
60 	    (p = sndio_parsetype(str, "aucat")) != NULL)
61 		return mio_aucat_open(p, mode, nbio, 0);
62 	if ((p = sndio_parsetype(str, "midithru")) != NULL)
63 		return mio_aucat_open(p, mode, nbio, 1);
64 	if ((p = sndio_parsetype(str, "midi")) != NULL)
65 		return mio_aucat_open(p, mode, nbio, 2);
66 	if ((p = sndio_parsetype(str, "rmidi")) != NULL) {
67 		return mio_rmidi_open(p, mode, nbio);
68 	}
69 	DPRINTF("mio_open: %s: unknown device type\n", str);
70 	return NULL;
71 }
72 
73 void
74 mio_create(struct mio_hdl *hdl, struct mio_ops *ops,
75     unsigned int mode, int nbio)
76 {
77 	hdl->ops = ops;
78 	hdl->mode = mode;
79 	hdl->nbio = nbio;
80 	hdl->eof = 0;
81 }
82 
83 void
84 mio_close(struct mio_hdl *hdl)
85 {
86 	hdl->ops->close(hdl);
87 }
88 
89 static int
90 mio_psleep(struct mio_hdl *hdl, int event)
91 {
92 	struct pollfd pfd[MIO_MAXNFDS];
93 	int revents;
94 	int nfds;
95 
96 	nfds = mio_nfds(hdl);
97 	if (nfds > MIO_MAXNFDS) {
98 		DPRINTF("mio_psleep: %d: too many descriptors\n", nfds);
99 		hdl->eof = 1;
100 		return 0;
101 	}
102 	for (;;) {
103 		nfds = mio_pollfd(hdl, pfd, event);
104 		while (poll(pfd, nfds, -1) < 0) {
105 			if (errno == EINTR)
106 				continue;
107 			DPERROR("mio_psleep: poll");
108 			hdl->eof = 1;
109 			return 0;
110 		}
111 		revents = mio_revents(hdl, pfd);
112 		if (revents & POLLHUP) {
113 			DPRINTF("mio_psleep: hang-up\n");
114 			return 0;
115 		}
116 		if (revents & event)
117 			break;
118 	}
119 	return 1;
120 }
121 
122 size_t
123 mio_read(struct mio_hdl *hdl, void *buf, size_t len)
124 {
125 	unsigned int n;
126 	char *data = buf;
127 	size_t todo = len;
128 
129 	if (hdl->eof) {
130 		DPRINTF("mio_read: eof\n");
131 		return 0;
132 	}
133 	if (!(hdl->mode & MIO_IN)) {
134 		DPRINTF("mio_read: not input device\n");
135 		hdl->eof = 1;
136 		return 0;
137 	}
138 	if (len == 0) {
139 		DPRINTF("mio_read: zero length read ignored\n");
140 		return 0;
141 	}
142 	while (todo > 0) {
143 		n = hdl->ops->read(hdl, data, todo);
144 		if (n == 0 && hdl->eof)
145 			break;
146 		data += n;
147 		todo -= n;
148 		if (n > 0 || hdl->nbio)
149 			break;
150 		if (!mio_psleep(hdl, POLLIN))
151 			break;
152 	}
153 	return len - todo;
154 }
155 
156 size_t
157 mio_write(struct mio_hdl *hdl, const void *buf, size_t len)
158 {
159 	unsigned int n;
160 	const unsigned char *data = buf;
161 	size_t todo = len;
162 
163 	if (hdl->eof) {
164 		DPRINTF("mio_write: eof\n");
165 		return 0;
166 	}
167 	if (!(hdl->mode & MIO_OUT)) {
168 		DPRINTF("mio_write: not output device\n");
169 		hdl->eof = 1;
170 		return 0;
171 	}
172 	if (len == 0) {
173 		DPRINTF("mio_write: zero length write ignored\n");
174 		return 0;
175 	}
176 	if (todo == 0) {
177 		DPRINTF("mio_write: zero length write ignored\n");
178 		return 0;
179 	}
180 	while (todo > 0) {
181 		n = hdl->ops->write(hdl, data, todo);
182 		if (n == 0) {
183 			if (hdl->nbio || hdl->eof)
184 				break;
185 			if (!mio_psleep(hdl, POLLOUT))
186 				break;
187 			continue;
188 		}
189 		data += n;
190 		todo -= n;
191 	}
192 	return len - todo;
193 }
194 
195 int
196 mio_nfds(struct mio_hdl *hdl)
197 {
198 	return hdl->ops->nfds(hdl);
199 }
200 
201 int
202 mio_pollfd(struct mio_hdl *hdl, struct pollfd *pfd, int events)
203 {
204 	if (hdl->eof)
205 		return 0;
206 	return hdl->ops->pollfd(hdl, pfd, events);
207 }
208 
209 int
210 mio_revents(struct mio_hdl *hdl, struct pollfd *pfd)
211 {
212 	if (hdl->eof)
213 		return POLLHUP;
214 	return hdl->ops->revents(hdl, pfd);
215 }
216 
217 int
218 mio_eof(struct mio_hdl *hdl)
219 {
220 	return hdl->eof;
221 }
222