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 26struct sioctl_hdl * 27sioctl_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 56void 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 67int 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 95void 96sioctl_close(struct sioctl_hdl *hdl) 97{ 98 hdl->ops->close(hdl); 99} 100 101int 102sioctl_nfds(struct sioctl_hdl *hdl) 103{ 104 return hdl->ops->nfds(hdl); 105} 106 107int 108sioctl_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 115int 116sioctl_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 123int 124sioctl_eof(struct sioctl_hdl *hdl) 125{ 126 return hdl->eof; 127} 128 129int 130sioctl_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 138int 139sioctl_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 147void 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 163void 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 171int 172sioctl_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