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