xref: /openbsd-src/lib/libsndio/mio_rmidi.c (revision 32917b698e0468cc8272f5645d75cfe0a0c39461)
1 /*	$OpenBSD: mio_rmidi.c,v 1.3 2009/07/26 12:38:20 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 #define RMIDI_PATH "/dev/rmidi0"
33 
34 struct rmidi_hdl {
35 	struct mio_hdl mio;
36 	int fd;
37 };
38 
39 static void rmidi_close(struct mio_hdl *);
40 static size_t rmidi_read(struct mio_hdl *, void *, size_t);
41 static size_t rmidi_write(struct mio_hdl *, const void *, size_t);
42 static int rmidi_pollfd(struct mio_hdl *, struct pollfd *, int);
43 static int rmidi_revents(struct mio_hdl *, struct pollfd *);
44 
45 static struct mio_ops rmidi_ops = {
46 	rmidi_close,
47 	rmidi_write,
48 	rmidi_read,
49 	rmidi_pollfd,
50 	rmidi_revents,
51 };
52 
53 struct mio_hdl *
54 mio_open_rmidi(const char *str, unsigned mode, int nbio)
55 {
56 	int fd, flags;
57 	struct rmidi_hdl *hdl;
58 	char path[PATH_MAX];
59 
60 	hdl = malloc(sizeof(struct rmidi_hdl));
61 	if (hdl == NULL)
62 		return NULL;
63 	mio_create(&hdl->mio, &rmidi_ops, mode, nbio);
64 
65 	snprintf(path, sizeof(path), "/dev/rmidi%s", str);
66 	if (mode == (MIO_OUT | MIO_IN))
67 		flags = O_RDWR;
68 	else
69 		flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY;
70 
71 	while ((fd = open(path, flags | O_NONBLOCK)) < 0) {
72 		if (errno == EINTR)
73 			continue;
74 		DPERROR(path);
75 		goto bad_free;
76 	}
77 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
78 		DPERROR("FD_CLOEXEC");
79 		goto bad_close;
80 	}
81 	hdl->fd = fd;
82 	return (struct mio_hdl *)hdl;
83  bad_close:
84 	while (close(hdl->fd) < 0 && errno == EINTR)
85 		; /* retry */
86  bad_free:
87 	free(hdl);
88 	return NULL;
89 }
90 
91 static void
92 rmidi_close(struct mio_hdl *sh)
93 {
94 	struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh;
95 	int rc;
96 
97 	do {
98 		rc = close(hdl->fd);
99 	} while (rc < 0 && errno == EINTR);
100 	free(hdl);
101 }
102 
103 static size_t
104 rmidi_read(struct mio_hdl *sh, void *buf, size_t len)
105 {
106 	struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh;
107 	ssize_t n;
108 
109 	while ((n = read(hdl->fd, buf, len)) < 0) {
110 		if (errno == EINTR)
111 			continue;
112 		if (errno != EAGAIN) {
113 			DPERROR("rmidi_read: read");
114 			hdl->mio.eof = 1;
115 		}
116 		return 0;
117 	}
118 	if (n == 0) {
119 		DPRINTF("rmidi_read: eof\n");
120 		hdl->mio.eof = 1;
121 		return 0;
122 	}
123 	return n;
124 }
125 
126 static size_t
127 rmidi_write(struct mio_hdl *sh, const void *buf, size_t len)
128 {
129 	struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh;
130 	ssize_t n;
131 
132 	while ((n = write(hdl->fd, buf, len)) < 0) {
133 		if (errno == EINTR)
134 			continue;
135 		if (errno != EAGAIN) {
136 			DPERROR("rmidi_write: write");
137 			hdl->mio.eof = 1;
138 			return 0;
139 		}
140  		return 0;
141 	}
142 	return n;
143 }
144 
145 static int
146 rmidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events)
147 {
148 	struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh;
149 
150 	pfd->fd = hdl->fd;
151 	pfd->events = events;
152 	return 1;
153 }
154 
155 int
156 rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
157 {
158 	return pfd->revents;
159 }
160