Annotation of src/usr.bin/sndiod/dev_sioctl.c, Revision 1.5
1.5 ! ratchov 1: /* $OpenBSD: dev_sioctl.c,v 1.4 2020/04/16 12:26:55 ratchov Exp $ */
1.1 ratchov 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:
1.2 ratchov 58: if (desc == NULL) {
59: dev_ctlsync(d);
1.1 ratchov 60: return;
1.2 ratchov 61: }
62:
1.1 ratchov 63: addr = CTLADDR_END + desc->addr;
64: dev_rmctl(d, addr);
65:
66: /*
1.4 ratchov 67: * prefix group names we use (currently "app") with "hw/"
1.1 ratchov 68: * to ensure that all controls have unique names when multiple
69: * sndiod's are chained
70: */
1.4 ratchov 71: if (strcmp(desc->group, "app") == 0) {
1.1 ratchov 72: group = group_buf;
73: if (snprintf(group_buf, CTL_NAMEMAX, GROUP_PREFIX "/%s",
74: desc->group) >= CTL_NAMEMAX)
75: return;
1.4 ratchov 76: } else
77: group = desc->group;
1.1 ratchov 78:
79: dev_addctl(d, group, desc->type, addr,
80: desc->node0.name, desc->node0.unit, desc->func,
81: desc->node1.name, desc->node1.unit, desc->maxval, val);
82: }
83:
84: void
85: dev_sioctl_onval(void *arg, unsigned int addr, unsigned int val)
86: {
87: struct dev *d = arg;
88: struct ctl *c;
89:
90: addr += CTLADDR_END;
91:
92: dev_log(d);
93: log_puts(": onctl: addr = ");
94: log_putu(addr);
95: log_puts(", val = ");
96: log_putu(val);
97: log_puts("\n");
98:
99: for (c = d->ctl_list; c != NULL; c = c->next) {
100: if (c->addr != addr)
101: continue;
102: ctl_log(c);
103: log_puts(": new value -> ");
104: log_putu(val);
105: log_puts("\n");
106: c->val_mask = ~0U;
107: c->curval = val;
108: }
109: }
110:
111: /*
112: * open the control device.
113: */
114: void
115: dev_sioctl_open(struct dev *d)
116: {
1.3 ratchov 117: if (d->sioctl.hdl == NULL) {
118: /*
119: * At this point there are clients, for instance if we're
120: * called by dev_reopen() but the control device couldn't
121: * be opened. In this case controls have changed (thoseof
122: * old device are just removed) so we need to notify clients.
123: */
124: dev_ctlsync(d);
1.1 ratchov 125: return;
1.3 ratchov 126: }
1.1 ratchov 127: sioctl_ondesc(d->sioctl.hdl, dev_sioctl_ondesc, d);
128: sioctl_onval(d->sioctl.hdl, dev_sioctl_onval, d);
129: }
130:
131: /*
132: * close the control device.
133: */
134: void
135: dev_sioctl_close(struct dev *d)
136: {
1.5 ! ratchov 137: struct ctl *c, **pc;
! 138:
! 139: /* remove controls */
! 140: pc = &d->ctl_list;
! 141: while ((c = *pc) != NULL) {
! 142: if (c->addr >= CTLADDR_END) {
! 143: c->refs_mask &= ~CTL_DEVMASK;
! 144: if (c->refs_mask == 0) {
! 145: *pc = c->next;
! 146: xfree(c);
! 147: continue;
! 148: }
! 149: c->type = CTL_NONE;
! 150: c->desc_mask = ~0;
! 151: }
! 152: pc = &c->next;
! 153: }
! 154: dev_ctlsync(d);
1.1 ratchov 155: }
156:
157: int
158: dev_sioctl_pollfd(void *arg, struct pollfd *pfd)
159: {
160: struct dev *d = arg;
161: struct ctl *c;
162: int events = 0;
163:
164: for (c = d->ctl_list; c != NULL; c = c->next) {
165: if (c->dirty)
166: events |= POLLOUT;
167: }
168: return sioctl_pollfd(d->sioctl.hdl, pfd, events);
169: }
170:
171: int
172: dev_sioctl_revents(void *arg, struct pollfd *pfd)
173: {
174: struct dev *d = arg;
175:
176: return sioctl_revents(d->sioctl.hdl, pfd);
177: }
178:
179: void
180: dev_sioctl_in(void *arg)
181: {
182: }
183:
184: void
185: dev_sioctl_out(void *arg)
186: {
187: struct dev *d = arg;
188: struct ctl *c;
189: int cnt;
190:
191: /*
192: * for each dirty ctl, call sioctl_setval() and dev_unref(). As
193: * dev_unref() may destroy the ctl_list, we must call it after
194: * we've finished iterating on it.
195: */
196: cnt = 0;
197: for (c = d->ctl_list; c != NULL; c = c->next) {
198: if (!c->dirty)
199: continue;
200: if (!sioctl_setval(d->sioctl.hdl,
201: c->addr - CTLADDR_END, c->curval)) {
202: ctl_log(c);
203: log_puts(": set failed\n");
204: break;
205: }
206: if (log_level >= 2) {
207: ctl_log(c);
208: log_puts(": changed\n");
209: }
210: c->dirty = 0;
211: cnt++;
212: }
213: while (cnt-- > 0)
214: dev_unref(d);
215: }
216:
217: void
218: dev_sioctl_hup(void *arg)
219: {
220: struct dev *d = arg;
221:
222: dev_sioctl_close(d);
1.5 ! ratchov 223: file_del(d->sioctl.file);
! 224: sioctl_close(d->sioctl.hdl);
! 225: d->sioctl.hdl = NULL;
1.1 ratchov 226: }