1 /* $OpenBSD: mio_rmidi.c,v 1.10 2011/11/15 08:05:22 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/stat.h> 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <limits.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_rmidi_hdl { 34 struct mio_hdl mio; 35 int fd; 36 }; 37 38 static void mio_rmidi_close(struct mio_hdl *); 39 static size_t mio_rmidi_read(struct mio_hdl *, void *, size_t); 40 static size_t mio_rmidi_write(struct mio_hdl *, const void *, size_t); 41 static int mio_rmidi_pollfd(struct mio_hdl *, struct pollfd *, int); 42 static int mio_rmidi_revents(struct mio_hdl *, struct pollfd *); 43 44 static struct mio_ops mio_rmidi_ops = { 45 mio_rmidi_close, 46 mio_rmidi_write, 47 mio_rmidi_read, 48 mio_rmidi_pollfd, 49 mio_rmidi_revents, 50 }; 51 52 struct mio_hdl * 53 mio_rmidi_open(const char *str, unsigned mode, int nbio) 54 { 55 int fd, flags; 56 struct mio_rmidi_hdl *hdl; 57 char path[PATH_MAX]; 58 59 switch (*str) { 60 case '/': 61 case ':': /* XXX: for backward compat */ 62 str++; 63 break; 64 default: 65 DPRINTF("sio_sun_open: %s: '/<devnum>' expected\n", str); 66 return NULL; 67 } 68 hdl = malloc(sizeof(struct mio_rmidi_hdl)); 69 if (hdl == NULL) 70 return NULL; 71 mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio); 72 73 snprintf(path, sizeof(path), "/dev/rmidi%s", str); 74 if (mode == (MIO_OUT | MIO_IN)) 75 flags = O_RDWR; 76 else 77 flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY; 78 if (nbio) 79 flags |= O_NONBLOCK; 80 while ((fd = open(path, flags)) < 0) { 81 if (errno == EINTR) 82 continue; 83 DPERROR(path); 84 goto bad_free; 85 } 86 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { 87 DPERROR("FD_CLOEXEC"); 88 goto bad_close; 89 } 90 hdl->fd = fd; 91 return (struct mio_hdl *)hdl; 92 bad_close: 93 while (close(hdl->fd) < 0 && errno == EINTR) 94 ; /* retry */ 95 bad_free: 96 free(hdl); 97 return NULL; 98 } 99 100 static void 101 mio_rmidi_close(struct mio_hdl *sh) 102 { 103 struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh; 104 int rc; 105 106 do { 107 rc = close(hdl->fd); 108 } while (rc < 0 && errno == EINTR); 109 free(hdl); 110 } 111 112 static size_t 113 mio_rmidi_read(struct mio_hdl *sh, void *buf, size_t len) 114 { 115 struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh; 116 ssize_t n; 117 118 while ((n = read(hdl->fd, buf, len)) < 0) { 119 if (errno == EINTR) 120 continue; 121 if (errno != EAGAIN) { 122 DPERROR("mio_rmidi_read: read"); 123 hdl->mio.eof = 1; 124 } 125 return 0; 126 } 127 if (n == 0) { 128 DPRINTF("mio_rmidi_read: eof\n"); 129 hdl->mio.eof = 1; 130 return 0; 131 } 132 return n; 133 } 134 135 static size_t 136 mio_rmidi_write(struct mio_hdl *sh, const void *buf, size_t len) 137 { 138 struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh; 139 ssize_t n; 140 141 while ((n = write(hdl->fd, buf, len)) < 0) { 142 if (errno == EINTR) 143 continue; 144 if (errno != EAGAIN) { 145 DPERROR("mio_rmidi_write: write"); 146 hdl->mio.eof = 1; 147 } 148 return 0; 149 } 150 return n; 151 } 152 153 static int 154 mio_rmidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events) 155 { 156 struct mio_rmidi_hdl *hdl = (struct mio_rmidi_hdl *)sh; 157 158 pfd->fd = hdl->fd; 159 pfd->events = events; 160 return 1; 161 } 162 163 static int 164 mio_rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd) 165 { 166 return pfd->revents; 167 } 168