1 /* $OpenBSD$ */ 2 /* 3 * Copyright (c) 2014-2020 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 #include <errno.h> 18 #include <poll.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <unistd.h> 22 23 #include "debug.h" 24 #include "sioctl_priv.h" 25 #include "bsd-compat.h" 26 27 struct sioctl_hdl * 28 sioctl_open(const char *str, unsigned int mode, int nbio) 29 { 30 static char devany[] = SIO_DEVANY; 31 struct sioctl_hdl *hdl; 32 33 #ifdef DEBUG 34 _sndio_debug_init(); 35 #endif 36 if (str == NULL) /* backward compat */ 37 str = devany; 38 if (strcmp(str, devany) == 0 && !issetugid()) { 39 str = getenv("AUDIODEVICE"); 40 if (str == NULL) 41 str = devany; 42 } 43 if (strcmp(str, devany) == 0) { 44 hdl = _sioctl_aucat_open("snd/0", mode, nbio); 45 if (hdl != NULL) 46 return hdl; 47 #if defined(USE_SUN_MIXER) 48 return _sioctl_sun_open("rsnd/0", mode, nbio); 49 #else 50 return NULL; 51 #endif 52 } 53 if (_sndio_parsetype(str, "snd")) 54 return _sioctl_aucat_open(str, mode, nbio); 55 if (_sndio_parsetype(str, "rsnd")) 56 #if defined(USE_SUN_MIXER) 57 return _sioctl_sun_open(str, mode, nbio); 58 #else 59 return NULL; 60 #endif 61 DPRINTF("sioctl_open: %s: unknown device type\n", str); 62 return NULL; 63 } 64 65 void 66 _sioctl_create(struct sioctl_hdl *hdl, struct sioctl_ops *ops, 67 unsigned int mode, int nbio) 68 { 69 hdl->ops = ops; 70 hdl->mode = mode; 71 hdl->nbio = nbio; 72 hdl->eof = 0; 73 hdl->ctl_cb = NULL; 74 } 75 76 int 77 _sioctl_psleep(struct sioctl_hdl *hdl, int event) 78 { 79 struct pollfd pfds[SIOCTL_MAXNFDS]; 80 int revents, nfds; 81 82 for (;;) { 83 nfds = sioctl_pollfd(hdl, pfds, event); 84 if (nfds == 0) 85 return 0; 86 while (poll(pfds, nfds, -1) < 0) { 87 if (errno == EINTR) 88 continue; 89 DPERROR("sioctl_psleep: poll"); 90 hdl->eof = 1; 91 return 0; 92 } 93 revents = sioctl_revents(hdl, pfds); 94 if (revents & POLLHUP) { 95 DPRINTF("sioctl_psleep: hang-up\n"); 96 return 0; 97 } 98 if (event == 0 || (revents & event)) 99 break; 100 } 101 return 1; 102 } 103 104 void 105 sioctl_close(struct sioctl_hdl *hdl) 106 { 107 hdl->ops->close(hdl); 108 } 109 110 int 111 sioctl_nfds(struct sioctl_hdl *hdl) 112 { 113 return hdl->ops->nfds(hdl); 114 } 115 116 int 117 sioctl_pollfd(struct sioctl_hdl *hdl, struct pollfd *pfd, int events) 118 { 119 if (hdl->eof) 120 return 0; 121 return hdl->ops->pollfd(hdl, pfd, events); 122 } 123 124 int 125 sioctl_revents(struct sioctl_hdl *hdl, struct pollfd *pfd) 126 { 127 if (hdl->eof) 128 return POLLHUP; 129 return hdl->ops->revents(hdl, pfd); 130 } 131 132 int 133 sioctl_eof(struct sioctl_hdl *hdl) 134 { 135 return hdl->eof; 136 } 137 138 int 139 sioctl_ondesc(struct sioctl_hdl *hdl, 140 void (*cb)(void *, struct sioctl_desc *, int), void *arg) 141 { 142 hdl->desc_cb = cb; 143 hdl->desc_arg = arg; 144 return hdl->ops->ondesc(hdl); 145 } 146 147 int 148 sioctl_onval(struct sioctl_hdl *hdl, 149 void (*cb)(void *, unsigned int, unsigned int), void *arg) 150 { 151 hdl->ctl_cb = cb; 152 hdl->ctl_arg = arg; 153 return hdl->ops->onctl(hdl); 154 } 155 156 void 157 _sioctl_ondesc_cb(struct sioctl_hdl *hdl, 158 struct sioctl_desc *desc, unsigned int val) 159 { 160 if (desc) { 161 DPRINTF("_sioctl_ondesc_cb: %u -> %s[%d].%s=%s[%d]:%d\n", 162 desc->addr, 163 desc->node0.name, desc->node0.unit, 164 desc->func, 165 desc->node1.name, desc->node1.unit, 166 val); 167 } 168 if (hdl->desc_cb) 169 hdl->desc_cb(hdl->desc_arg, desc, val); 170 } 171 172 void 173 _sioctl_onval_cb(struct sioctl_hdl *hdl, unsigned int addr, unsigned int val) 174 { 175 DPRINTF("_sioctl_onval_cb: %u -> %u\n", addr, val); 176 if (hdl->ctl_cb) 177 hdl->ctl_cb(hdl->ctl_arg, addr, val); 178 } 179 180 int 181 sioctl_setval(struct sioctl_hdl *hdl, unsigned int addr, unsigned int val) 182 { 183 if (!(hdl->mode & SIOCTL_WRITE)) 184 return 0; 185 return hdl->ops->setctl(hdl, addr, val); 186 } 187