1 /* $OpenBSD: mio.c,v 1.23 2019/06/29 06:05:26 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 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) == -1) { 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 while (todo > 0) { 132 n = hdl->ops->read(hdl, data, todo); 133 if (n == 0 && hdl->eof) 134 break; 135 data += n; 136 todo -= n; 137 if (n > 0 || hdl->nbio) 138 break; 139 if (!mio_psleep(hdl, POLLIN)) 140 break; 141 } 142 return len - todo; 143 } 144 145 size_t 146 mio_write(struct mio_hdl *hdl, const void *buf, size_t len) 147 { 148 unsigned int n; 149 const unsigned char *data = buf; 150 size_t todo = len; 151 152 if (hdl->eof) { 153 DPRINTF("mio_write: eof\n"); 154 return 0; 155 } 156 if (!(hdl->mode & MIO_OUT)) { 157 DPRINTF("mio_write: not output device\n"); 158 hdl->eof = 1; 159 return 0; 160 } 161 while (todo > 0) { 162 n = hdl->ops->write(hdl, data, todo); 163 if (n == 0) { 164 if (hdl->nbio || hdl->eof) 165 break; 166 if (!mio_psleep(hdl, POLLOUT)) 167 break; 168 continue; 169 } 170 data += n; 171 todo -= n; 172 } 173 return len - todo; 174 } 175 176 int 177 mio_nfds(struct mio_hdl *hdl) 178 { 179 return hdl->ops->nfds(hdl); 180 } 181 182 int 183 mio_pollfd(struct mio_hdl *hdl, struct pollfd *pfd, int events) 184 { 185 if (hdl->eof) 186 return 0; 187 return hdl->ops->pollfd(hdl, pfd, events); 188 } 189 190 int 191 mio_revents(struct mio_hdl *hdl, struct pollfd *pfd) 192 { 193 if (hdl->eof) 194 return POLLHUP; 195 return hdl->ops->revents(hdl, pfd); 196 } 197 198 int 199 mio_eof(struct mio_hdl *hdl) 200 { 201 return hdl->eof; 202 } 203