xref: /openbsd-src/lib/libsndio/mio_rmidi.c (revision 4c2441987b72c7cee8f11767b3c3ae3149d21b37)
1 /*	$OpenBSD: mio_rmidi.c,v 1.2 2009/07/25 11:15:56 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 #include <limits.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <poll.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include "mio_priv.h"
30 
31 #define RMIDI_PATH "/dev/rmidi0"
32 
33 struct rmidi_hdl {
34 	struct mio_hdl mio;
35 	int fd;
36 };
37 
38 static void rmidi_close(struct mio_hdl *);
39 static size_t rmidi_read(struct mio_hdl *, void *, size_t);
40 static size_t rmidi_write(struct mio_hdl *, const void *, size_t);
41 static int rmidi_pollfd(struct mio_hdl *, struct pollfd *, int);
42 static int rmidi_revents(struct mio_hdl *, struct pollfd *);
43 
44 static struct mio_ops rmidi_ops = {
45 	rmidi_close,
46 	rmidi_write,
47 	rmidi_read,
48 	rmidi_pollfd,
49 	rmidi_revents,
50 };
51 
52 struct mio_hdl *
53 mio_open_rmidi(const char *str, unsigned mode, int nbio)
54 {
55 	int fd, flags;
56 	struct rmidi_hdl *hdl;
57 	char path[PATH_MAX];
58 
59 	hdl = malloc(sizeof(struct rmidi_hdl));
60 	if (hdl == NULL)
61 		return NULL;
62 	mio_create(&hdl->mio, &rmidi_ops, mode, nbio);
63 
64 	snprintf(path, sizeof(path), "/dev/rmidi%s", str);
65 	if (mode == (MIO_OUT | MIO_IN))
66 		flags = O_RDWR;
67 	else
68 		flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY;
69 
70 	while ((fd = open(path, flags | O_NONBLOCK)) < 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 rmidi_close(struct mio_hdl *sh)
92 {
93 	struct rmidi_hdl *hdl = (struct 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 rmidi_read(struct mio_hdl *sh, void *buf, size_t len)
104 {
105 	struct rmidi_hdl *hdl = (struct 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("rmidi_read: read");
113 			hdl->mio.eof = 1;
114 		}
115 		return 0;
116 	}
117 	if (n == 0) {
118 		DPRINTF("rmidi_read: eof\n");
119 		hdl->mio.eof = 1;
120 		return 0;
121 	}
122 	return n;
123 }
124 
125 static size_t
126 rmidi_write(struct mio_hdl *sh, const void *buf, size_t len)
127 {
128 	struct rmidi_hdl *hdl = (struct 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("rmidi_write: write");
136 			hdl->mio.eof = 1;
137 			return 0;
138 		}
139  		return 0;
140 	}
141 	return n;
142 }
143 
144 static int
145 rmidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events)
146 {
147 	struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh;
148 
149 	pfd->fd = hdl->fd;
150 	pfd->events = events;
151 	return 1;
152 }
153 
154 int
155 rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
156 {
157 	return pfd->revents;
158 }
159