xref: /openbsd-src/lib/libsndio/mio_rmidi.c (revision b44cb2ca5b56462db5902739e473d34452fbb2fe)
1 /*	$OpenBSD: mio_rmidi.c,v 1.19 2015/10/02 09:48: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 "debug.h"
31 #include "mio_priv.h"
32 
33 #define DEVPATH_PREFIX	"/dev/rmidi"
34 #define DEVPATH_MAX 	(1 +		\
35 	sizeof(DEVPATH_PREFIX) - 1 +	\
36 	sizeof(int) * 3)
37 
38 struct mio_rmidi_hdl {
39 	struct mio_hdl mio;
40 	int fd;
41 };
42 
43 static void mio_rmidi_close(struct mio_hdl *);
44 static size_t mio_rmidi_read(struct mio_hdl *, void *, size_t);
45 static size_t mio_rmidi_write(struct mio_hdl *, const void *, size_t);
46 static int mio_rmidi_nfds(struct mio_hdl *);
47 static int mio_rmidi_pollfd(struct mio_hdl *, struct pollfd *, int);
48 static int mio_rmidi_revents(struct mio_hdl *, struct pollfd *);
49 
50 static struct mio_ops mio_rmidi_ops = {
51 	mio_rmidi_close,
52 	mio_rmidi_write,
53 	mio_rmidi_read,
54 	mio_rmidi_nfds,
55 	mio_rmidi_pollfd,
56 	mio_rmidi_revents
57 };
58 
59 struct mio_hdl *
60 _mio_rmidi_open(const char *str, unsigned int mode, int nbio)
61 {
62 	int fd, flags;
63 	struct mio_rmidi_hdl *hdl;
64 	char path[DEVPATH_MAX];
65 	unsigned int devnum;
66 
67 	switch (*str) {
68 	case '/':
69 		str++;
70 		break;
71 	default:
72 		DPRINTF("_mio_rmidi_open: %s: '/<devnum>' expected\n", str);
73 		return NULL;
74 	}
75 	str = _sndio_parsenum(str, &devnum, 255);
76 	if (str == NULL || *str != '\0') {
77 		DPRINTF("_mio_rmidi_open: can't determine device number\n");
78 		return NULL;
79 	}
80 	hdl = malloc(sizeof(struct mio_rmidi_hdl));
81 	if (hdl == NULL)
82 		return NULL;
83 	_mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio);
84 	snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
85 	if (mode == (MIO_OUT | MIO_IN))
86 		flags = O_RDWR;
87 	else
88 		flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY;
89 	while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) < 0) {
90 		if (errno == EINTR)
91 			continue;
92 		DPERROR(path);
93 		goto bad_free;
94 	}
95 	hdl->fd = fd;
96 	return (struct mio_hdl *)hdl;
97  bad_free:
98 	free(hdl);
99 	return NULL;
100 }
101 
102 static void
103 mio_rmidi_close(struct mio_hdl *sh)
104 {
105 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
106 	int rc;
107 
108 	do {
109 		rc = close(hdl->fd);
110 	} while (rc < 0 && errno == EINTR);
111 	free(hdl);
112 }
113 
114 static size_t
115 mio_rmidi_read(struct mio_hdl *sh, void *buf, size_t len)
116 {
117 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
118 	ssize_t n;
119 
120 	while ((n = read(hdl->fd, buf, len)) < 0) {
121 		if (errno == EINTR)
122 			continue;
123 		if (errno != EAGAIN) {
124 			DPERROR("mio_rmidi_read: read");
125 			hdl->mio.eof = 1;
126 		}
127 		return 0;
128 	}
129 	if (n == 0) {
130 		DPRINTF("mio_rmidi_read: eof\n");
131 		hdl->mio.eof = 1;
132 		return 0;
133 	}
134 	return n;
135 }
136 
137 static size_t
138 mio_rmidi_write(struct mio_hdl *sh, const void *buf, size_t len)
139 {
140 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
141 	ssize_t n;
142 
143 	while ((n = write(hdl->fd, buf, len)) < 0) {
144 		if (errno == EINTR)
145 			continue;
146 		if (errno != EAGAIN) {
147 			DPERROR("mio_rmidi_write: write");
148 			hdl->mio.eof = 1;
149 		}
150  		return 0;
151 	}
152 	return n;
153 }
154 
155 static int
156 mio_rmidi_nfds(struct mio_hdl *sh)
157 {
158 	return 1;
159 }
160 
161 static int
162 mio_rmidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events)
163 {
164 	struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh;
165 
166 	pfd->fd = hdl->fd;
167 	pfd->events = events;
168 	return 1;
169 }
170 
171 static int
172 mio_rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
173 {
174 	return pfd->revents;
175 }
176