1*7b639200Sratchov /* $OpenBSD: dev_sioctl.c,v 1.11 2024/12/20 07:35:56 ratchov Exp $ */ 2d07fece6Sratchov /* 3d07fece6Sratchov * Copyright (c) 2014-2020 Alexandre Ratchov <alex@caoua.org> 4d07fece6Sratchov * 5d07fece6Sratchov * Permission to use, copy, modify, and distribute this software for any 6d07fece6Sratchov * purpose with or without fee is hereby granted, provided that the above 7d07fece6Sratchov * copyright notice and this permission notice appear in all copies. 8d07fece6Sratchov * 9d07fece6Sratchov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10d07fece6Sratchov * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11d07fece6Sratchov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12d07fece6Sratchov * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13d07fece6Sratchov * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14d07fece6Sratchov * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15d07fece6Sratchov * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16d07fece6Sratchov */ 17d07fece6Sratchov #include <sys/time.h> 18d07fece6Sratchov #include <sys/types.h> 19d07fece6Sratchov 20d07fece6Sratchov #include <poll.h> 21d07fece6Sratchov #include <sndio.h> 22d07fece6Sratchov #include <stdio.h> 23d07fece6Sratchov #include <stdlib.h> 24d07fece6Sratchov #include <string.h> 25d07fece6Sratchov #include "abuf.h" 26d07fece6Sratchov #include "defs.h" 27d07fece6Sratchov #include "dev.h" 28d07fece6Sratchov #include "dsp.h" 29d07fece6Sratchov #include "file.h" 30d07fece6Sratchov #include "dev_sioctl.h" 31d07fece6Sratchov #include "utils.h" 32d07fece6Sratchov 33d07fece6Sratchov void dev_sioctl_ondesc(void *, struct sioctl_desc *, int); 34d07fece6Sratchov void dev_sioctl_onval(void *, unsigned int, unsigned int); 35d07fece6Sratchov int dev_sioctl_pollfd(void *, struct pollfd *); 36d07fece6Sratchov int dev_sioctl_revents(void *, struct pollfd *); 37d07fece6Sratchov void dev_sioctl_in(void *); 38d07fece6Sratchov void dev_sioctl_out(void *); 39d07fece6Sratchov void dev_sioctl_hup(void *); 40d07fece6Sratchov 41d07fece6Sratchov struct fileops dev_sioctl_ops = { 42d07fece6Sratchov "sioctl", 43d07fece6Sratchov dev_sioctl_pollfd, 44d07fece6Sratchov dev_sioctl_revents, 45d07fece6Sratchov dev_sioctl_in, 46d07fece6Sratchov dev_sioctl_out, 47d07fece6Sratchov dev_sioctl_hup 48d07fece6Sratchov }; 49d07fece6Sratchov 50d07fece6Sratchov void 51d07fece6Sratchov dev_sioctl_ondesc(void *arg, struct sioctl_desc *desc, int val) 52d07fece6Sratchov { 53d07fece6Sratchov struct dev *d = arg; 5499580020Sratchov char *group, group_buf[CTL_NAMEMAX]; 55d07fece6Sratchov 56e575fbdeSratchov if (desc == NULL) { 57e575fbdeSratchov dev_ctlsync(d); 58d07fece6Sratchov return; 59e575fbdeSratchov } 60e575fbdeSratchov 6199580020Sratchov ctl_del(CTL_HW, d, &desc->addr); 62d07fece6Sratchov 6399580020Sratchov if (desc->group[0] == 0) 6499580020Sratchov group = d->name; 6599580020Sratchov else { 6699580020Sratchov if (snprintf(group_buf, CTL_NAMEMAX, "%s/%s", 6799580020Sratchov d->name, desc->group) >= CTL_NAMEMAX) 68d07fece6Sratchov return; 6999580020Sratchov group = group_buf; 7099580020Sratchov } 71d07fece6Sratchov 7299580020Sratchov ctl_new(CTL_HW, d, &desc->addr, 734d8b188fSratchov desc->type, desc->display, group, 74d07fece6Sratchov desc->node0.name, desc->node0.unit, desc->func, 75d07fece6Sratchov desc->node1.name, desc->node1.unit, desc->maxval, val); 76d07fece6Sratchov } 77d07fece6Sratchov 78d07fece6Sratchov void 79d07fece6Sratchov dev_sioctl_onval(void *arg, unsigned int addr, unsigned int val) 80d07fece6Sratchov { 81*7b639200Sratchov char str[64]; 82d07fece6Sratchov struct dev *d = arg; 83d07fece6Sratchov struct ctl *c; 84d07fece6Sratchov 85*7b639200Sratchov logx(2, "%s: onctl: addr = %u, val = %u", d->path, addr, val); 86d07fece6Sratchov 8799580020Sratchov for (c = ctl_list; c != NULL; c = c->next) { 8853c84758Sratchov if (c->scope != CTL_HW || c->u.hw.dev != d || 8953c84758Sratchov c->u.hw.addr != addr) 90d07fece6Sratchov continue; 916551a2ffSratchov 92*7b639200Sratchov logx(2, "ctl%u: %s -> %u", c->addr, 93*7b639200Sratchov (ctl_fmt(str, sizeof(str), c), str), val); 946551a2ffSratchov 95d07fece6Sratchov c->val_mask = ~0U; 96d07fece6Sratchov c->curval = val; 97d07fece6Sratchov } 98d07fece6Sratchov } 99d07fece6Sratchov 100d07fece6Sratchov /* 101d07fece6Sratchov * open the control device. 102d07fece6Sratchov */ 103d07fece6Sratchov void 104d07fece6Sratchov dev_sioctl_open(struct dev *d) 105d07fece6Sratchov { 106b3d2daecSratchov if (d->sioctl.hdl == NULL) { 107b3d2daecSratchov /* 108b3d2daecSratchov * At this point there are clients, for instance if we're 109b3d2daecSratchov * called by dev_reopen() but the control device couldn't 110b3d2daecSratchov * be opened. In this case controls have changed (thoseof 111b3d2daecSratchov * old device are just removed) so we need to notify clients. 112b3d2daecSratchov */ 113b3d2daecSratchov dev_ctlsync(d); 114d07fece6Sratchov return; 115b3d2daecSratchov } 116d07fece6Sratchov sioctl_ondesc(d->sioctl.hdl, dev_sioctl_ondesc, d); 117d07fece6Sratchov sioctl_onval(d->sioctl.hdl, dev_sioctl_onval, d); 118d07fece6Sratchov } 119d07fece6Sratchov 120d07fece6Sratchov /* 121d07fece6Sratchov * close the control device. 122d07fece6Sratchov */ 123d07fece6Sratchov void 124d07fece6Sratchov dev_sioctl_close(struct dev *d) 125d07fece6Sratchov { 126bbbe65dfSratchov struct ctl *c, **pc; 127bbbe65dfSratchov 128bbbe65dfSratchov /* remove controls */ 12999580020Sratchov pc = &ctl_list; 130bbbe65dfSratchov while ((c = *pc) != NULL) { 13199580020Sratchov if (c->scope == CTL_HW && c->u.hw.dev == d) { 132bbbe65dfSratchov c->refs_mask &= ~CTL_DEVMASK; 133bbbe65dfSratchov if (c->refs_mask == 0) { 134bbbe65dfSratchov *pc = c->next; 135bbbe65dfSratchov xfree(c); 136bbbe65dfSratchov continue; 137bbbe65dfSratchov } 138bbbe65dfSratchov c->type = CTL_NONE; 139bbbe65dfSratchov c->desc_mask = ~0; 140bbbe65dfSratchov } 141bbbe65dfSratchov pc = &c->next; 142bbbe65dfSratchov } 143bbbe65dfSratchov dev_ctlsync(d); 144d07fece6Sratchov } 145d07fece6Sratchov 146d07fece6Sratchov int 147d07fece6Sratchov dev_sioctl_pollfd(void *arg, struct pollfd *pfd) 148d07fece6Sratchov { 149d07fece6Sratchov struct dev *d = arg; 150d07fece6Sratchov struct ctl *c; 151d07fece6Sratchov int events = 0; 152d07fece6Sratchov 15399580020Sratchov for (c = ctl_list; c != NULL; c = c->next) { 15499580020Sratchov if (c->scope == CTL_HW && c->u.hw.dev == d && c->dirty) 155d07fece6Sratchov events |= POLLOUT; 156d07fece6Sratchov } 157d07fece6Sratchov return sioctl_pollfd(d->sioctl.hdl, pfd, events); 158d07fece6Sratchov } 159d07fece6Sratchov 160d07fece6Sratchov int 161d07fece6Sratchov dev_sioctl_revents(void *arg, struct pollfd *pfd) 162d07fece6Sratchov { 163d07fece6Sratchov struct dev *d = arg; 164d07fece6Sratchov 165d07fece6Sratchov return sioctl_revents(d->sioctl.hdl, pfd); 166d07fece6Sratchov } 167d07fece6Sratchov 168d07fece6Sratchov void 169d07fece6Sratchov dev_sioctl_in(void *arg) 170d07fece6Sratchov { 171d07fece6Sratchov } 172d07fece6Sratchov 173d07fece6Sratchov void 174d07fece6Sratchov dev_sioctl_out(void *arg) 175d07fece6Sratchov { 176d07fece6Sratchov struct dev *d = arg; 177d07fece6Sratchov struct ctl *c; 178d07fece6Sratchov int cnt; 179d07fece6Sratchov 180d07fece6Sratchov /* 181d07fece6Sratchov * for each dirty ctl, call sioctl_setval() and dev_unref(). As 182d07fece6Sratchov * dev_unref() may destroy the ctl_list, we must call it after 183d07fece6Sratchov * we've finished iterating on it. 184d07fece6Sratchov */ 185d07fece6Sratchov cnt = 0; 18699580020Sratchov for (c = ctl_list; c != NULL; c = c->next) { 18799580020Sratchov if (c->scope != CTL_HW || c->u.hw.dev != d || !c->dirty) 188d07fece6Sratchov continue; 18999580020Sratchov if (!sioctl_setval(d->sioctl.hdl, c->u.hw.addr, c->curval)) { 190*7b639200Sratchov logx(1, "ctl%u: set failed", c->addr); 191d07fece6Sratchov break; 192d07fece6Sratchov } 193d07fece6Sratchov c->dirty = 0; 194d07fece6Sratchov cnt++; 195d07fece6Sratchov } 196d07fece6Sratchov while (cnt-- > 0) 197d07fece6Sratchov dev_unref(d); 198d07fece6Sratchov } 199d07fece6Sratchov 200d07fece6Sratchov void 201d07fece6Sratchov dev_sioctl_hup(void *arg) 202d07fece6Sratchov { 203d07fece6Sratchov struct dev *d = arg; 204d07fece6Sratchov 205d07fece6Sratchov dev_sioctl_close(d); 206bbbe65dfSratchov file_del(d->sioctl.file); 207bbbe65dfSratchov sioctl_close(d->sioctl.hdl); 208bbbe65dfSratchov d->sioctl.hdl = NULL; 209d07fece6Sratchov } 210