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