1 /* $OpenBSD: mio_rmidi.c,v 1.3 2009/07/26 12:38:20 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 "mio_priv.h" 31 32 #define RMIDI_PATH "/dev/rmidi0" 33 34 struct rmidi_hdl { 35 struct mio_hdl mio; 36 int fd; 37 }; 38 39 static void rmidi_close(struct mio_hdl *); 40 static size_t rmidi_read(struct mio_hdl *, void *, size_t); 41 static size_t rmidi_write(struct mio_hdl *, const void *, size_t); 42 static int rmidi_pollfd(struct mio_hdl *, struct pollfd *, int); 43 static int rmidi_revents(struct mio_hdl *, struct pollfd *); 44 45 static struct mio_ops rmidi_ops = { 46 rmidi_close, 47 rmidi_write, 48 rmidi_read, 49 rmidi_pollfd, 50 rmidi_revents, 51 }; 52 53 struct mio_hdl * 54 mio_open_rmidi(const char *str, unsigned mode, int nbio) 55 { 56 int fd, flags; 57 struct rmidi_hdl *hdl; 58 char path[PATH_MAX]; 59 60 hdl = malloc(sizeof(struct rmidi_hdl)); 61 if (hdl == NULL) 62 return NULL; 63 mio_create(&hdl->mio, &rmidi_ops, mode, nbio); 64 65 snprintf(path, sizeof(path), "/dev/rmidi%s", str); 66 if (mode == (MIO_OUT | MIO_IN)) 67 flags = O_RDWR; 68 else 69 flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY; 70 71 while ((fd = open(path, flags | O_NONBLOCK)) < 0) { 72 if (errno == EINTR) 73 continue; 74 DPERROR(path); 75 goto bad_free; 76 } 77 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { 78 DPERROR("FD_CLOEXEC"); 79 goto bad_close; 80 } 81 hdl->fd = fd; 82 return (struct mio_hdl *)hdl; 83 bad_close: 84 while (close(hdl->fd) < 0 && errno == EINTR) 85 ; /* retry */ 86 bad_free: 87 free(hdl); 88 return NULL; 89 } 90 91 static void 92 rmidi_close(struct mio_hdl *sh) 93 { 94 struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh; 95 int rc; 96 97 do { 98 rc = close(hdl->fd); 99 } while (rc < 0 && errno == EINTR); 100 free(hdl); 101 } 102 103 static size_t 104 rmidi_read(struct mio_hdl *sh, void *buf, size_t len) 105 { 106 struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh; 107 ssize_t n; 108 109 while ((n = read(hdl->fd, buf, len)) < 0) { 110 if (errno == EINTR) 111 continue; 112 if (errno != EAGAIN) { 113 DPERROR("rmidi_read: read"); 114 hdl->mio.eof = 1; 115 } 116 return 0; 117 } 118 if (n == 0) { 119 DPRINTF("rmidi_read: eof\n"); 120 hdl->mio.eof = 1; 121 return 0; 122 } 123 return n; 124 } 125 126 static size_t 127 rmidi_write(struct mio_hdl *sh, const void *buf, size_t len) 128 { 129 struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh; 130 ssize_t n; 131 132 while ((n = write(hdl->fd, buf, len)) < 0) { 133 if (errno == EINTR) 134 continue; 135 if (errno != EAGAIN) { 136 DPERROR("rmidi_write: write"); 137 hdl->mio.eof = 1; 138 return 0; 139 } 140 return 0; 141 } 142 return n; 143 } 144 145 static int 146 rmidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events) 147 { 148 struct rmidi_hdl *hdl = (struct rmidi_hdl *)sh; 149 150 pfd->fd = hdl->fd; 151 pfd->events = events; 152 return 1; 153 } 154 155 int 156 rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd) 157 { 158 return pfd->revents; 159 } 160