1 /* $OpenBSD: mio.c,v 1.7 2009/08/21 16:48:03 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 "mio_priv.h" 32 33 #ifdef DEBUG 34 /* 35 * debug level, -1 means uninitialized 36 */ 37 int mio_debug = -1; 38 #endif 39 40 struct mio_hdl * 41 mio_open(const char *str, unsigned mode, int nbio) 42 { 43 static char prefix_midithru[] = "midithru"; 44 static char prefix_rmidi[] = "rmidi"; 45 static char prefix_aucat[] = "aucat"; 46 struct mio_hdl *hdl; 47 struct stat sb; 48 char *sep, buf[4]; 49 int len; 50 #ifdef DEBUG 51 char *dbg; 52 53 if (mio_debug < 0) { 54 dbg = issetugid() ? NULL : getenv("MIO_DEBUG"); 55 if (!dbg || sscanf(dbg, "%u", &mio_debug) != 1) 56 mio_debug = 0; 57 } 58 #endif 59 if ((mode & (MIO_OUT | MIO_IN)) == 0) 60 return NULL; 61 if (str == NULL && !issetugid()) 62 str = getenv("MIDIDEVICE"); 63 if (str == NULL) { 64 hdl = mio_open_thru("0", mode, nbio); 65 if (hdl != NULL) 66 return hdl; 67 return mio_open_rmidi("0", mode, nbio); 68 } 69 sep = strchr(str, ':'); 70 if (sep == NULL) { 71 /* 72 * try legacy "/dev/rmidioxxx" device name 73 */ 74 if (stat(str, &sb) < 0 || !S_ISCHR(sb.st_mode)) { 75 DPRINTF("mio_open: %s: missing ':' separator\n", str); 76 return NULL; 77 } 78 snprintf(buf, sizeof(buf), "%u", minor(sb.st_rdev)); 79 return mio_open_rmidi(buf, mode, nbio); 80 } 81 82 len = sep - str; 83 if (len == (sizeof(prefix_midithru) - 1) && 84 memcmp(str, prefix_midithru, len) == 0) 85 return mio_open_thru(sep + 1, mode, nbio); 86 if (len == (sizeof(prefix_aucat) - 1) && 87 memcmp(str, prefix_aucat, len) == 0) 88 return mio_open_aucat(sep + 1, mode, nbio); 89 if (len == (sizeof(prefix_rmidi) - 1) && 90 memcmp(str, prefix_rmidi, len) == 0) 91 return mio_open_rmidi(sep + 1, mode, nbio); 92 DPRINTF("mio_open: %s: unknown device type\n", str); 93 return NULL; 94 } 95 96 void 97 mio_create(struct mio_hdl *hdl, struct mio_ops *ops, unsigned mode, int nbio) 98 { 99 hdl->ops = ops; 100 hdl->mode = mode; 101 hdl->nbio = nbio; 102 hdl->eof = 0; 103 } 104 105 void 106 mio_close(struct mio_hdl *hdl) 107 { 108 hdl->ops->close(hdl); 109 } 110 111 size_t 112 mio_read(struct mio_hdl *hdl, void *buf, size_t len) 113 { 114 if (hdl->eof) { 115 DPRINTF("mio_read: eof\n"); 116 return 0; 117 } 118 if (!(hdl->mode & MIO_IN)) { 119 DPRINTF("mio_read: not input device\n"); 120 hdl->eof = 1; 121 return 0; 122 } 123 if (len == 0) { 124 DPRINTF("mio_read: zero length read ignored\n"); 125 return 0; 126 } 127 return hdl->ops->read(hdl, buf, len); 128 } 129 130 size_t 131 mio_write(struct mio_hdl *hdl, const void *buf, size_t len) 132 { 133 if (hdl->eof) { 134 DPRINTF("mio_write: eof\n"); 135 return 0; 136 } 137 if (!(hdl->mode & MIO_OUT)) { 138 DPRINTF("mio_write: not output device\n"); 139 hdl->eof = 1; 140 return 0; 141 } 142 if (len == 0) { 143 DPRINTF("mio_write: zero length write ignored\n"); 144 return 0; 145 } 146 return hdl->ops->write(hdl, buf, len); 147 } 148 149 int 150 mio_nfds(struct mio_hdl *hdl) 151 { 152 return 1; 153 } 154 155 int 156 mio_pollfd(struct mio_hdl *hdl, struct pollfd *pfd, int events) 157 { 158 if (hdl->eof) 159 return 0; 160 return hdl->ops->pollfd(hdl, pfd, events); 161 } 162 163 int 164 mio_revents(struct mio_hdl *hdl, struct pollfd *pfd) 165 { 166 if (hdl->eof) 167 return POLLHUP; 168 return hdl->ops->revents(hdl, pfd); 169 } 170 171 int 172 mio_eof(struct mio_hdl *hdl) 173 { 174 return hdl->eof; 175 } 176