Annotation of src/usr.bin/sndiod/dev_sioctl.c, Revision 1.1
1.1 ! ratchov 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 <sys/time.h>
! 18: #include <sys/types.h>
! 19:
! 20: #include <poll.h>
! 21: #include <sndio.h>
! 22: #include <stdio.h>
! 23: #include <stdlib.h>
! 24: #include <string.h>
! 25: #include "abuf.h"
! 26: #include "defs.h"
! 27: #include "dev.h"
! 28: #include "dsp.h"
! 29: #include "file.h"
! 30: #include "dev_sioctl.h"
! 31: #include "utils.h"
! 32:
! 33: void dev_sioctl_ondesc(void *, struct sioctl_desc *, int);
! 34: void dev_sioctl_onval(void *, unsigned int, unsigned int);
! 35: int dev_sioctl_pollfd(void *, struct pollfd *);
! 36: int dev_sioctl_revents(void *, struct pollfd *);
! 37: void dev_sioctl_in(void *);
! 38: void dev_sioctl_out(void *);
! 39: void dev_sioctl_hup(void *);
! 40:
! 41: struct fileops dev_sioctl_ops = {
! 42: "sioctl",
! 43: dev_sioctl_pollfd,
! 44: dev_sioctl_revents,
! 45: dev_sioctl_in,
! 46: dev_sioctl_out,
! 47: dev_sioctl_hup
! 48: };
! 49:
! 50: void
! 51: dev_sioctl_ondesc(void *arg, struct sioctl_desc *desc, int val)
! 52: {
! 53: #define GROUP_PREFIX "hw"
! 54: char group_buf[CTL_NAMEMAX], *group;
! 55: struct dev *d = arg;
! 56: int addr;
! 57:
! 58: if (desc == NULL)
! 59: return;
! 60: addr = CTLADDR_END + desc->addr;
! 61: dev_rmctl(d, addr);
! 62:
! 63: /*
! 64: * prefix group names we use (top-level and "app") with "hw."
! 65: * to ensure that all controls have unique names when multiple
! 66: * sndiod's are chained
! 67: */
! 68: if (desc->group[0] == 0)
! 69: group = GROUP_PREFIX;
! 70: else {
! 71: group = group_buf;
! 72: if (snprintf(group_buf, CTL_NAMEMAX, GROUP_PREFIX "/%s",
! 73: desc->group) >= CTL_NAMEMAX)
! 74: return;
! 75: }
! 76:
! 77: dev_addctl(d, group, desc->type, addr,
! 78: desc->node0.name, desc->node0.unit, desc->func,
! 79: desc->node1.name, desc->node1.unit, desc->maxval, val);
! 80: }
! 81:
! 82: void
! 83: dev_sioctl_onval(void *arg, unsigned int addr, unsigned int val)
! 84: {
! 85: struct dev *d = arg;
! 86: struct ctl *c;
! 87:
! 88: addr += CTLADDR_END;
! 89:
! 90: dev_log(d);
! 91: log_puts(": onctl: addr = ");
! 92: log_putu(addr);
! 93: log_puts(", val = ");
! 94: log_putu(val);
! 95: log_puts("\n");
! 96:
! 97: for (c = d->ctl_list; c != NULL; c = c->next) {
! 98: if (c->addr != addr)
! 99: continue;
! 100: ctl_log(c);
! 101: log_puts(": new value -> ");
! 102: log_putu(val);
! 103: log_puts("\n");
! 104: c->val_mask = ~0U;
! 105: c->curval = val;
! 106: }
! 107: }
! 108:
! 109: /*
! 110: * open the control device.
! 111: */
! 112: void
! 113: dev_sioctl_open(struct dev *d)
! 114: {
! 115: if (d->sioctl.hdl == NULL)
! 116: return;
! 117: sioctl_ondesc(d->sioctl.hdl, dev_sioctl_ondesc, d);
! 118: sioctl_onval(d->sioctl.hdl, dev_sioctl_onval, d);
! 119: d->sioctl.file = file_new(&dev_sioctl_ops, d, "mix",
! 120: sioctl_nfds(d->sioctl.hdl));
! 121: }
! 122:
! 123: /*
! 124: * close the control device.
! 125: */
! 126: void
! 127: dev_sioctl_close(struct dev *d)
! 128: {
! 129: if (d->sioctl.hdl == NULL)
! 130: return;
! 131: file_del(d->sioctl.file);
! 132: }
! 133:
! 134: int
! 135: dev_sioctl_pollfd(void *arg, struct pollfd *pfd)
! 136: {
! 137: struct dev *d = arg;
! 138: struct ctl *c;
! 139: int events = 0;
! 140:
! 141: for (c = d->ctl_list; c != NULL; c = c->next) {
! 142: if (c->dirty)
! 143: events |= POLLOUT;
! 144: }
! 145: return sioctl_pollfd(d->sioctl.hdl, pfd, events);
! 146: }
! 147:
! 148: int
! 149: dev_sioctl_revents(void *arg, struct pollfd *pfd)
! 150: {
! 151: struct dev *d = arg;
! 152:
! 153: return sioctl_revents(d->sioctl.hdl, pfd);
! 154: }
! 155:
! 156: void
! 157: dev_sioctl_in(void *arg)
! 158: {
! 159: }
! 160:
! 161: void
! 162: dev_sioctl_out(void *arg)
! 163: {
! 164: struct dev *d = arg;
! 165: struct ctl *c;
! 166: int cnt;
! 167:
! 168: /*
! 169: * for each dirty ctl, call sioctl_setval() and dev_unref(). As
! 170: * dev_unref() may destroy the ctl_list, we must call it after
! 171: * we've finished iterating on it.
! 172: */
! 173: cnt = 0;
! 174: for (c = d->ctl_list; c != NULL; c = c->next) {
! 175: if (!c->dirty)
! 176: continue;
! 177: if (!sioctl_setval(d->sioctl.hdl,
! 178: c->addr - CTLADDR_END, c->curval)) {
! 179: ctl_log(c);
! 180: log_puts(": set failed\n");
! 181: break;
! 182: }
! 183: if (log_level >= 2) {
! 184: ctl_log(c);
! 185: log_puts(": changed\n");
! 186: }
! 187: c->dirty = 0;
! 188: cnt++;
! 189: }
! 190: while (cnt-- > 0)
! 191: dev_unref(d);
! 192: }
! 193:
! 194: void
! 195: dev_sioctl_hup(void *arg)
! 196: {
! 197: struct dev *d = arg;
! 198:
! 199: dev_sioctl_close(d);
! 200: }