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