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