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