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