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