1*4aaef610Sratchov /* $OpenBSD: sndioctl.c,v 1.21 2024/05/24 15:10:27 ratchov Exp $ */
282fd4e08Sratchov /*
382fd4e08Sratchov * Copyright (c) 2014-2020 Alexandre Ratchov <alex@caoua.org>
482fd4e08Sratchov *
582fd4e08Sratchov * Permission to use, copy, modify, and distribute this software for any
682fd4e08Sratchov * purpose with or without fee is hereby granted, provided that the above
782fd4e08Sratchov * copyright notice and this permission notice appear in all copies.
882fd4e08Sratchov *
982fd4e08Sratchov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1082fd4e08Sratchov * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1182fd4e08Sratchov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1282fd4e08Sratchov * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1382fd4e08Sratchov * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1482fd4e08Sratchov * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1582fd4e08Sratchov * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1682fd4e08Sratchov */
1782fd4e08Sratchov #include <errno.h>
1882fd4e08Sratchov #include <poll.h>
1982fd4e08Sratchov #include <sndio.h>
2082fd4e08Sratchov #include <stdlib.h>
2182fd4e08Sratchov #include <stdio.h>
2282fd4e08Sratchov #include <string.h>
2382fd4e08Sratchov #include <unistd.h>
2482fd4e08Sratchov
2582fd4e08Sratchov struct info {
2682fd4e08Sratchov struct info *next;
2782fd4e08Sratchov struct sioctl_desc desc;
2882fd4e08Sratchov unsigned ctladdr;
2982fd4e08Sratchov #define MODE_IGNORE 0 /* ignore this value */
3082fd4e08Sratchov #define MODE_PRINT 1 /* print-only, don't change value */
3182fd4e08Sratchov #define MODE_SET 2 /* set to newval value */
3282fd4e08Sratchov #define MODE_ADD 3 /* increase current value by newval */
3382fd4e08Sratchov #define MODE_SUB 4 /* decrease current value by newval */
3482fd4e08Sratchov #define MODE_TOGGLE 5 /* toggle current value */
3582fd4e08Sratchov unsigned mode;
3682fd4e08Sratchov int curval, newval;
3782fd4e08Sratchov };
3882fd4e08Sratchov
3982fd4e08Sratchov int cmpdesc(struct sioctl_desc *, struct sioctl_desc *);
4082fd4e08Sratchov int isdiag(struct info *);
4182fd4e08Sratchov struct info *vecent(struct info *, char *, int);
4282fd4e08Sratchov struct info *nextfunc(struct info *);
4382fd4e08Sratchov struct info *nextpar(struct info *);
4482fd4e08Sratchov struct info *firstent(struct info *, char *);
4582fd4e08Sratchov struct info *nextent(struct info *, int);
4682fd4e08Sratchov int matchpar(struct info *, char *, int);
4782fd4e08Sratchov int matchent(struct info *, char *, int);
4882fd4e08Sratchov int ismono(struct info *);
4982fd4e08Sratchov void print_node(struct sioctl_node *, int);
50*4aaef610Sratchov void print_display(struct info *);
5182fd4e08Sratchov void print_desc(struct info *, int);
52070d2896Sratchov void print_num(struct info *);
53f707c874Sratchov void print_ent(struct info *, char *);
5482fd4e08Sratchov void print_val(struct info *, int);
55f707c874Sratchov void print_par(struct info *, int);
5682fd4e08Sratchov int parse_name(char **, char *);
576c473e8bSratchov int parse_unit(char **, int *);
5882fd4e08Sratchov int parse_val(char **, float *);
5982fd4e08Sratchov int parse_node(char **, char *, int *);
6082fd4e08Sratchov int parse_modeval(char **, int *, float *);
6182fd4e08Sratchov void dump(void);
6282fd4e08Sratchov int cmd(char *);
6382fd4e08Sratchov void commit(void);
6482fd4e08Sratchov void list(void);
6582fd4e08Sratchov void ondesc(void *, struct sioctl_desc *, int);
6682fd4e08Sratchov void onctl(void *, unsigned, unsigned);
6782fd4e08Sratchov
6882fd4e08Sratchov struct sioctl_hdl *hdl;
6982fd4e08Sratchov struct info *infolist;
703b691801Sratchov int i_flag = 0, v_flag = 0, m_flag = 0, n_flag = 0, q_flag = 0;
7182fd4e08Sratchov
7282fd4e08Sratchov static inline int
isname(int c)732d7b56acSratchov isname(int c)
7482fd4e08Sratchov {
752d7b56acSratchov return (c == '_') ||
762d7b56acSratchov (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
772d7b56acSratchov (c >= '0' && c <= '9');
7882fd4e08Sratchov }
7982fd4e08Sratchov
8082fd4e08Sratchov static int
ftoi(float f)8182fd4e08Sratchov ftoi(float f)
8282fd4e08Sratchov {
8382fd4e08Sratchov return f + 0.5;
8482fd4e08Sratchov }
8582fd4e08Sratchov
8682fd4e08Sratchov /*
8782fd4e08Sratchov * compare two sioctl_desc structures, used to sort infolist
8882fd4e08Sratchov */
8982fd4e08Sratchov int
cmpdesc(struct sioctl_desc * d1,struct sioctl_desc * d2)9082fd4e08Sratchov cmpdesc(struct sioctl_desc *d1, struct sioctl_desc *d2)
9182fd4e08Sratchov {
9282fd4e08Sratchov int res;
9382fd4e08Sratchov
9482fd4e08Sratchov res = strcmp(d1->group, d2->group);
9582fd4e08Sratchov if (res != 0)
9682fd4e08Sratchov return res;
9782fd4e08Sratchov res = strcmp(d1->node0.name, d2->node0.name);
9882fd4e08Sratchov if (res != 0)
9982fd4e08Sratchov return res;
10082fd4e08Sratchov res = d1->type - d2->type;
10182fd4e08Sratchov if (res != 0)
10282fd4e08Sratchov return res;
10382fd4e08Sratchov res = strcmp(d1->func, d2->func);
10482fd4e08Sratchov if (res != 0)
10582fd4e08Sratchov return res;
10682fd4e08Sratchov res = d1->node0.unit - d2->node0.unit;
10749f67e12Sratchov if (d1->type == SIOCTL_SEL ||
10849f67e12Sratchov d1->type == SIOCTL_VEC ||
10982fd4e08Sratchov d1->type == SIOCTL_LIST) {
11082fd4e08Sratchov if (res != 0)
11182fd4e08Sratchov return res;
11282fd4e08Sratchov res = strcmp(d1->node1.name, d2->node1.name);
11382fd4e08Sratchov if (res != 0)
11482fd4e08Sratchov return res;
11582fd4e08Sratchov res = d1->node1.unit - d2->node1.unit;
11682fd4e08Sratchov }
11782fd4e08Sratchov return res;
11882fd4e08Sratchov }
11982fd4e08Sratchov
12082fd4e08Sratchov /*
12182fd4e08Sratchov * return true of the vector entry is diagonal
12282fd4e08Sratchov */
12382fd4e08Sratchov int
isdiag(struct info * e)12482fd4e08Sratchov isdiag(struct info *e)
12582fd4e08Sratchov {
12682fd4e08Sratchov if (e->desc.node0.unit < 0 || e->desc.node1.unit < 0)
12782fd4e08Sratchov return 1;
12882fd4e08Sratchov return e->desc.node1.unit == e->desc.node0.unit;
12982fd4e08Sratchov }
13082fd4e08Sratchov
13182fd4e08Sratchov /*
13282fd4e08Sratchov * find the selector or vector entry with the given name and channels
13382fd4e08Sratchov */
13482fd4e08Sratchov struct info *
vecent(struct info * i,char * vstr,int vunit)13582fd4e08Sratchov vecent(struct info *i, char *vstr, int vunit)
13682fd4e08Sratchov {
13782fd4e08Sratchov while (i != NULL) {
13882fd4e08Sratchov if ((strcmp(i->desc.node1.name, vstr) == 0) &&
13982fd4e08Sratchov (vunit < 0 || i->desc.node1.unit == vunit))
14082fd4e08Sratchov break;
14182fd4e08Sratchov i = i->next;
14282fd4e08Sratchov }
14382fd4e08Sratchov return i;
14482fd4e08Sratchov }
14582fd4e08Sratchov
14682fd4e08Sratchov /*
14782fd4e08Sratchov * skip all parameters with the same group, name, and func
14882fd4e08Sratchov */
14982fd4e08Sratchov struct info *
nextfunc(struct info * i)15082fd4e08Sratchov nextfunc(struct info *i)
15182fd4e08Sratchov {
15282fd4e08Sratchov char *str, *group, *func;
15382fd4e08Sratchov
15482fd4e08Sratchov group = i->desc.group;
15582fd4e08Sratchov func = i->desc.func;
15682fd4e08Sratchov str = i->desc.node0.name;
15782fd4e08Sratchov for (i = i->next; i != NULL; i = i->next) {
15882fd4e08Sratchov if (strcmp(i->desc.group, group) != 0 ||
15982fd4e08Sratchov strcmp(i->desc.node0.name, str) != 0 ||
16082fd4e08Sratchov strcmp(i->desc.func, func) != 0)
16182fd4e08Sratchov return i;
16282fd4e08Sratchov }
16382fd4e08Sratchov return NULL;
16482fd4e08Sratchov }
16582fd4e08Sratchov
16682fd4e08Sratchov /*
16782fd4e08Sratchov * find the next parameter with the same group, name, func
16882fd4e08Sratchov */
16982fd4e08Sratchov struct info *
nextpar(struct info * i)17082fd4e08Sratchov nextpar(struct info *i)
17182fd4e08Sratchov {
17282fd4e08Sratchov char *str, *group, *func;
17382fd4e08Sratchov int unit;
17482fd4e08Sratchov
17582fd4e08Sratchov group = i->desc.group;
17682fd4e08Sratchov func = i->desc.func;
17782fd4e08Sratchov str = i->desc.node0.name;
17882fd4e08Sratchov unit = i->desc.node0.unit;
17982fd4e08Sratchov for (i = i->next; i != NULL; i = i->next) {
18082fd4e08Sratchov if (strcmp(i->desc.group, group) != 0 ||
18182fd4e08Sratchov strcmp(i->desc.node0.name, str) != 0 ||
18282fd4e08Sratchov strcmp(i->desc.func, func) != 0)
18382fd4e08Sratchov break;
18482fd4e08Sratchov /* XXX: need to check for -1 ? */
18582fd4e08Sratchov if (i->desc.node0.unit != unit)
18682fd4e08Sratchov return i;
18782fd4e08Sratchov }
18882fd4e08Sratchov return NULL;
18982fd4e08Sratchov }
19082fd4e08Sratchov
19182fd4e08Sratchov /*
19282fd4e08Sratchov * return the first vector entry with the given name
19382fd4e08Sratchov */
19482fd4e08Sratchov struct info *
firstent(struct info * g,char * vstr)19582fd4e08Sratchov firstent(struct info *g, char *vstr)
19682fd4e08Sratchov {
19782fd4e08Sratchov char *astr, *group, *func;
19882fd4e08Sratchov struct info *i;
19982fd4e08Sratchov
20082fd4e08Sratchov group = g->desc.group;
20182fd4e08Sratchov astr = g->desc.node0.name;
20282fd4e08Sratchov func = g->desc.func;
20382fd4e08Sratchov for (i = g; i != NULL; i = i->next) {
20482fd4e08Sratchov if (strcmp(i->desc.group, group) != 0 ||
20582fd4e08Sratchov strcmp(i->desc.node0.name, astr) != 0 ||
20682fd4e08Sratchov strcmp(i->desc.func, func) != 0)
20782fd4e08Sratchov break;
20882fd4e08Sratchov if (!isdiag(i))
20982fd4e08Sratchov continue;
21082fd4e08Sratchov if (strcmp(i->desc.node1.name, vstr) == 0)
21182fd4e08Sratchov return i;
21282fd4e08Sratchov }
21382fd4e08Sratchov return NULL;
21482fd4e08Sratchov }
21582fd4e08Sratchov
21682fd4e08Sratchov /*
21782fd4e08Sratchov * find the next entry of the given vector, if the mono flag
21882fd4e08Sratchov * is set then the whole group is searched and off-diagonal entries are
21982fd4e08Sratchov * skipped
22082fd4e08Sratchov */
22182fd4e08Sratchov struct info *
nextent(struct info * i,int mono)22282fd4e08Sratchov nextent(struct info *i, int mono)
22382fd4e08Sratchov {
22482fd4e08Sratchov char *str, *group, *func;
22582fd4e08Sratchov int unit;
22682fd4e08Sratchov
22782fd4e08Sratchov group = i->desc.group;
22882fd4e08Sratchov func = i->desc.func;
22982fd4e08Sratchov str = i->desc.node0.name;
23082fd4e08Sratchov unit = i->desc.node0.unit;
23182fd4e08Sratchov for (i = i->next; i != NULL; i = i->next) {
23282fd4e08Sratchov if (strcmp(i->desc.group, group) != 0 ||
23382fd4e08Sratchov strcmp(i->desc.node0.name, str) != 0 ||
23482fd4e08Sratchov strcmp(i->desc.func, func) != 0)
23582fd4e08Sratchov return NULL;
23682fd4e08Sratchov if (mono)
23782fd4e08Sratchov return i;
23882fd4e08Sratchov if (i->desc.node0.unit == unit)
23982fd4e08Sratchov return i;
24082fd4e08Sratchov }
24182fd4e08Sratchov return NULL;
24282fd4e08Sratchov }
24382fd4e08Sratchov
24482fd4e08Sratchov /*
24582fd4e08Sratchov * return true if parameter matches the given name and channel
24682fd4e08Sratchov */
24782fd4e08Sratchov int
matchpar(struct info * i,char * astr,int aunit)24882fd4e08Sratchov matchpar(struct info *i, char *astr, int aunit)
24982fd4e08Sratchov {
25082fd4e08Sratchov if (strcmp(i->desc.node0.name, astr) != 0)
25182fd4e08Sratchov return 0;
25282fd4e08Sratchov if (aunit < 0)
25382fd4e08Sratchov return 1;
25482fd4e08Sratchov else if (i->desc.node0.unit < 0) {
25582fd4e08Sratchov fprintf(stderr, "unit used for parameter with no unit\n");
25682fd4e08Sratchov exit(1);
25782fd4e08Sratchov }
25882fd4e08Sratchov return i->desc.node0.unit == aunit;
25982fd4e08Sratchov }
26082fd4e08Sratchov
26182fd4e08Sratchov /*
26282fd4e08Sratchov * return true if selector or vector entry matches the given name and
26382fd4e08Sratchov * channel range
26482fd4e08Sratchov */
26582fd4e08Sratchov int
matchent(struct info * i,char * vstr,int vunit)26682fd4e08Sratchov matchent(struct info *i, char *vstr, int vunit)
26782fd4e08Sratchov {
26882fd4e08Sratchov if (strcmp(i->desc.node1.name, vstr) != 0)
26982fd4e08Sratchov return 0;
27082fd4e08Sratchov if (vunit < 0)
27182fd4e08Sratchov return 1;
27282fd4e08Sratchov else if (i->desc.node1.unit < 0) {
27382fd4e08Sratchov fprintf(stderr, "unit used for parameter with no unit\n");
27482fd4e08Sratchov exit(1);
27582fd4e08Sratchov }
27682fd4e08Sratchov return i->desc.node1.unit == vunit;
27782fd4e08Sratchov }
27882fd4e08Sratchov
27982fd4e08Sratchov /*
28082fd4e08Sratchov * return true if the given group can be represented as a signle mono
28182fd4e08Sratchov * parameter
28282fd4e08Sratchov */
28382fd4e08Sratchov int
ismono(struct info * g)28482fd4e08Sratchov ismono(struct info *g)
28582fd4e08Sratchov {
28682fd4e08Sratchov struct info *p1, *p2;
28782fd4e08Sratchov struct info *e1, *e2;
28882fd4e08Sratchov
28982fd4e08Sratchov p1 = g;
29082fd4e08Sratchov switch (g->desc.type) {
29182fd4e08Sratchov case SIOCTL_NUM:
29282fd4e08Sratchov case SIOCTL_SW:
29382fd4e08Sratchov for (p2 = g; p2 != NULL; p2 = nextpar(p2)) {
29482fd4e08Sratchov if (p2->curval != p1->curval)
29582fd4e08Sratchov return 0;
29682fd4e08Sratchov }
29782fd4e08Sratchov break;
29849f67e12Sratchov case SIOCTL_SEL:
29982fd4e08Sratchov case SIOCTL_VEC:
30082fd4e08Sratchov case SIOCTL_LIST:
30182fd4e08Sratchov for (p2 = g; p2 != NULL; p2 = nextpar(p2)) {
30282fd4e08Sratchov for (e2 = p2; e2 != NULL; e2 = nextent(e2, 0)) {
30382fd4e08Sratchov if (!isdiag(e2)) {
30482fd4e08Sratchov if (e2->curval != 0)
30582fd4e08Sratchov return 0;
30682fd4e08Sratchov } else {
30782fd4e08Sratchov e1 = vecent(p1,
30882fd4e08Sratchov e2->desc.node1.name,
30982fd4e08Sratchov p1->desc.node0.unit);
31082fd4e08Sratchov if (e1 == NULL)
31182fd4e08Sratchov continue;
31282fd4e08Sratchov if (e1->curval != e2->curval)
31382fd4e08Sratchov return 0;
314*4aaef610Sratchov if (strcmp(e1->desc.display,
315*4aaef610Sratchov e2->desc.display) != 0)
316*4aaef610Sratchov return 0;
31782fd4e08Sratchov }
31882fd4e08Sratchov }
31982fd4e08Sratchov }
32082fd4e08Sratchov break;
32182fd4e08Sratchov }
32282fd4e08Sratchov return 1;
32382fd4e08Sratchov }
32482fd4e08Sratchov
32582fd4e08Sratchov /*
32682fd4e08Sratchov * print a sub-stream, eg. "spkr[4]"
32782fd4e08Sratchov */
32882fd4e08Sratchov void
print_node(struct sioctl_node * c,int mono)32982fd4e08Sratchov print_node(struct sioctl_node *c, int mono)
33082fd4e08Sratchov {
33182fd4e08Sratchov printf("%s", c->name);
33282fd4e08Sratchov if (!mono && c->unit >= 0)
33382fd4e08Sratchov printf("[%d]", c->unit);
33482fd4e08Sratchov }
33582fd4e08Sratchov
33682fd4e08Sratchov /*
337*4aaef610Sratchov * print display string, with '(' and ')' and non-printable chars removed
338*4aaef610Sratchov * in order to match command syntax
339*4aaef610Sratchov */
340*4aaef610Sratchov void
print_display(struct info * p)341*4aaef610Sratchov print_display(struct info *p)
342*4aaef610Sratchov {
343*4aaef610Sratchov char buf[SIOCTL_NAMEMAX], *s, *d;
344*4aaef610Sratchov unsigned int c;
345*4aaef610Sratchov
346*4aaef610Sratchov s = p->desc.display;
347*4aaef610Sratchov d = buf;
348*4aaef610Sratchov while ((c = *s++) != 0) {
349*4aaef610Sratchov if (c == '(' || c == ')' || c < ' ')
350*4aaef610Sratchov continue;
351*4aaef610Sratchov *d++ = c;
352*4aaef610Sratchov }
353*4aaef610Sratchov *d = 0;
354*4aaef610Sratchov if (buf[0] != 0)
355*4aaef610Sratchov printf("(%s)", buf);
356*4aaef610Sratchov }
357*4aaef610Sratchov
358*4aaef610Sratchov /*
35982fd4e08Sratchov * print info about the parameter
36082fd4e08Sratchov */
36182fd4e08Sratchov void
print_desc(struct info * p,int mono)36282fd4e08Sratchov print_desc(struct info *p, int mono)
36382fd4e08Sratchov {
36482fd4e08Sratchov struct info *e;
36582fd4e08Sratchov int more;
36682fd4e08Sratchov
36782fd4e08Sratchov switch (p->desc.type) {
36882fd4e08Sratchov case SIOCTL_NUM:
36982fd4e08Sratchov case SIOCTL_SW:
37082fd4e08Sratchov printf("*");
371*4aaef610Sratchov print_display(p);
37282fd4e08Sratchov break;
37349f67e12Sratchov case SIOCTL_SEL:
37482fd4e08Sratchov case SIOCTL_VEC:
37582fd4e08Sratchov case SIOCTL_LIST:
37682fd4e08Sratchov more = 0;
37782fd4e08Sratchov for (e = p; e != NULL; e = nextent(e, mono)) {
37882fd4e08Sratchov if (mono) {
37982fd4e08Sratchov if (!isdiag(e))
38082fd4e08Sratchov continue;
38182fd4e08Sratchov if (e != firstent(p, e->desc.node1.name))
38282fd4e08Sratchov continue;
38382fd4e08Sratchov }
38482fd4e08Sratchov if (more)
38582fd4e08Sratchov printf(",");
38682fd4e08Sratchov print_node(&e->desc.node1, mono);
38749f67e12Sratchov if (p->desc.type != SIOCTL_SEL)
38882fd4e08Sratchov printf(":*");
389*4aaef610Sratchov if (e->desc.display[0] != 0)
390*4aaef610Sratchov print_display(e);
39182fd4e08Sratchov more = 1;
39282fd4e08Sratchov }
39382fd4e08Sratchov }
39482fd4e08Sratchov }
39582fd4e08Sratchov
396070d2896Sratchov void
print_num(struct info * p)397070d2896Sratchov print_num(struct info *p)
398070d2896Sratchov {
399070d2896Sratchov if (p->desc.maxval == 1)
400070d2896Sratchov printf("%d", p->curval);
401070d2896Sratchov else {
402070d2896Sratchov /*
403070d2896Sratchov * For now, maxval is always 127 or 255,
404070d2896Sratchov * so three decimals is always ideal.
405070d2896Sratchov */
406070d2896Sratchov printf("%.3f", p->curval / (float)p->desc.maxval);
407070d2896Sratchov }
408070d2896Sratchov }
409070d2896Sratchov
41082fd4e08Sratchov /*
411f707c874Sratchov * print a single control
412f707c874Sratchov */
413f707c874Sratchov void
print_ent(struct info * e,char * comment)414f707c874Sratchov print_ent(struct info *e, char *comment)
415f707c874Sratchov {
416f707c874Sratchov if (e->desc.group[0] != 0) {
417f707c874Sratchov printf("%s", e->desc.group);
418f707c874Sratchov printf("/");
419f707c874Sratchov }
420f707c874Sratchov print_node(&e->desc.node0, 0);
421f707c874Sratchov printf(".%s=", e->desc.func);
422f707c874Sratchov switch (e->desc.type) {
423f707c874Sratchov case SIOCTL_NONE:
424f707c874Sratchov printf("<removed>\n");
425f707c874Sratchov break;
42649f67e12Sratchov case SIOCTL_SEL:
427f707c874Sratchov case SIOCTL_VEC:
428f707c874Sratchov case SIOCTL_LIST:
429f707c874Sratchov print_node(&e->desc.node1, 0);
430f707c874Sratchov printf(":");
431f707c874Sratchov /* FALLTHROUGH */
432f707c874Sratchov case SIOCTL_SW:
433f707c874Sratchov case SIOCTL_NUM:
434f707c874Sratchov print_num(e);
435f707c874Sratchov }
436*4aaef610Sratchov print_display(e);
437f707c874Sratchov if (comment)
438f707c874Sratchov printf("\t# %s", comment);
439f707c874Sratchov printf("\n");
440f707c874Sratchov }
441f707c874Sratchov
442f707c874Sratchov /*
44382fd4e08Sratchov * print parameter value
44482fd4e08Sratchov */
44582fd4e08Sratchov void
print_val(struct info * p,int mono)44682fd4e08Sratchov print_val(struct info *p, int mono)
44782fd4e08Sratchov {
44882fd4e08Sratchov struct info *e;
44982fd4e08Sratchov int more;
45082fd4e08Sratchov
45182fd4e08Sratchov switch (p->desc.type) {
45282fd4e08Sratchov case SIOCTL_NUM:
45382fd4e08Sratchov case SIOCTL_SW:
454070d2896Sratchov print_num(p);
455*4aaef610Sratchov print_display(p);
45682fd4e08Sratchov break;
45749f67e12Sratchov case SIOCTL_SEL:
45882fd4e08Sratchov case SIOCTL_VEC:
45982fd4e08Sratchov case SIOCTL_LIST:
46082fd4e08Sratchov more = 0;
46182fd4e08Sratchov for (e = p; e != NULL; e = nextent(e, mono)) {
46282fd4e08Sratchov if (mono) {
46382fd4e08Sratchov if (!isdiag(e))
46482fd4e08Sratchov continue;
46582fd4e08Sratchov if (e != firstent(p, e->desc.node1.name))
46682fd4e08Sratchov continue;
46782fd4e08Sratchov }
4686ce0bcf9Sratchov if (e->desc.maxval == 1) {
4696ce0bcf9Sratchov if (e->curval) {
4706ce0bcf9Sratchov if (more)
4716ce0bcf9Sratchov printf(",");
4726ce0bcf9Sratchov print_node(&e->desc.node1, mono);
473*4aaef610Sratchov print_display(e);
4746ce0bcf9Sratchov more = 1;
4756ce0bcf9Sratchov }
4766ce0bcf9Sratchov } else {
47782fd4e08Sratchov if (more)
47882fd4e08Sratchov printf(",");
47982fd4e08Sratchov print_node(&e->desc.node1, mono);
480070d2896Sratchov printf(":");
481070d2896Sratchov print_num(e);
482*4aaef610Sratchov print_display(e);
48382fd4e08Sratchov more = 1;
48482fd4e08Sratchov }
48582fd4e08Sratchov }
48682fd4e08Sratchov }
4876ce0bcf9Sratchov }
48882fd4e08Sratchov
48982fd4e08Sratchov /*
49082fd4e08Sratchov * print ``<parameter>=<value>'' string (including '\n')
49182fd4e08Sratchov */
49282fd4e08Sratchov void
print_par(struct info * p,int mono)493f707c874Sratchov print_par(struct info *p, int mono)
49482fd4e08Sratchov {
49526791b1eSratchov if (!n_flag) {
49682fd4e08Sratchov if (p->desc.group[0] != 0) {
49782fd4e08Sratchov printf("%s", p->desc.group);
49882fd4e08Sratchov printf("/");
49982fd4e08Sratchov }
50082fd4e08Sratchov print_node(&p->desc.node0, mono);
50182fd4e08Sratchov printf(".%s=", p->desc.func);
50226791b1eSratchov }
50382fd4e08Sratchov if (i_flag)
50482fd4e08Sratchov print_desc(p, mono);
50582fd4e08Sratchov else
50682fd4e08Sratchov print_val(p, mono);
50782fd4e08Sratchov printf("\n");
50882fd4e08Sratchov }
50982fd4e08Sratchov
51082fd4e08Sratchov /*
51182fd4e08Sratchov * parse a stream name or parameter name
51282fd4e08Sratchov */
51382fd4e08Sratchov int
parse_name(char ** line,char * name)51482fd4e08Sratchov parse_name(char **line, char *name)
51582fd4e08Sratchov {
51682fd4e08Sratchov char *p = *line;
51782fd4e08Sratchov unsigned len = 0;
51882fd4e08Sratchov
5192d7b56acSratchov if (!isname(*p)) {
5202d7b56acSratchov fprintf(stderr, "letter or digit expected near '%s'\n", p);
52182fd4e08Sratchov return 0;
52282fd4e08Sratchov }
5232d7b56acSratchov while (isname(*p)) {
52482fd4e08Sratchov if (len >= SIOCTL_NAMEMAX - 1) {
52582fd4e08Sratchov name[SIOCTL_NAMEMAX - 1] = '\0';
52682fd4e08Sratchov fprintf(stderr, "%s...: too long\n", name);
52782fd4e08Sratchov return 0;
52882fd4e08Sratchov }
52982fd4e08Sratchov name[len++] = *p;
53082fd4e08Sratchov p++;
53182fd4e08Sratchov }
53282fd4e08Sratchov name[len] = '\0';
53382fd4e08Sratchov *line = p;
53482fd4e08Sratchov return 1;
53582fd4e08Sratchov }
53682fd4e08Sratchov
53782fd4e08Sratchov /*
53882fd4e08Sratchov * parse a decimal integer
53982fd4e08Sratchov */
54082fd4e08Sratchov int
parse_unit(char ** line,int * num)5416c473e8bSratchov parse_unit(char **line, int *num)
54282fd4e08Sratchov {
54382fd4e08Sratchov char *p = *line;
54482fd4e08Sratchov unsigned int val;
54582fd4e08Sratchov int n;
54682fd4e08Sratchov
54782fd4e08Sratchov if (sscanf(p, "%u%n", &val, &n) != 1) {
54882fd4e08Sratchov fprintf(stderr, "number expected near '%s'\n", p);
54982fd4e08Sratchov return 0;
55082fd4e08Sratchov }
55182fd4e08Sratchov if (val >= 255) {
55282fd4e08Sratchov fprintf(stderr, "%d: too large\n", val);
55382fd4e08Sratchov return 0;
55482fd4e08Sratchov }
55582fd4e08Sratchov *num = val;
55682fd4e08Sratchov *line = p + n;
55782fd4e08Sratchov return 1;
55882fd4e08Sratchov }
55982fd4e08Sratchov
56082fd4e08Sratchov int
parse_val(char ** line,float * num)56182fd4e08Sratchov parse_val(char **line, float *num)
56282fd4e08Sratchov {
56382fd4e08Sratchov char *p = *line;
56482fd4e08Sratchov float val;
56582fd4e08Sratchov int n;
56682fd4e08Sratchov
56782fd4e08Sratchov if (sscanf(p, "%g%n", &val, &n) != 1) {
56882fd4e08Sratchov fprintf(stderr, "number expected near '%s'\n", p);
56982fd4e08Sratchov return 0;
57082fd4e08Sratchov }
57182fd4e08Sratchov if (val < 0 || val > 1) {
57282fd4e08Sratchov fprintf(stderr, "%g: expected number between 0 and 1\n", val);
57382fd4e08Sratchov return 0;
57482fd4e08Sratchov }
57582fd4e08Sratchov *num = val;
57682fd4e08Sratchov *line = p + n;
57782fd4e08Sratchov return 1;
57882fd4e08Sratchov }
57982fd4e08Sratchov
58082fd4e08Sratchov /*
58182fd4e08Sratchov * parse a sub-stream, eg. "spkr[7]"
58282fd4e08Sratchov */
58382fd4e08Sratchov int
parse_node(char ** line,char * str,int * unit)58482fd4e08Sratchov parse_node(char **line, char *str, int *unit)
58582fd4e08Sratchov {
58682fd4e08Sratchov char *p = *line;
58782fd4e08Sratchov
58882fd4e08Sratchov if (!parse_name(&p, str))
58982fd4e08Sratchov return 0;
59082fd4e08Sratchov if (*p != '[') {
59182fd4e08Sratchov *unit = -1;
59282fd4e08Sratchov *line = p;
59382fd4e08Sratchov return 1;
59482fd4e08Sratchov }
59582fd4e08Sratchov p++;
59682fd4e08Sratchov if (!parse_unit(&p, unit))
59782fd4e08Sratchov return 0;
59882fd4e08Sratchov if (*p != ']') {
59982fd4e08Sratchov fprintf(stderr, "']' expected near '%s'\n", p);
60082fd4e08Sratchov return 0;
60182fd4e08Sratchov }
60282fd4e08Sratchov p++;
60382fd4e08Sratchov *line = p;
60482fd4e08Sratchov return 1;
60582fd4e08Sratchov }
60682fd4e08Sratchov
60782fd4e08Sratchov /*
60882fd4e08Sratchov * parse a decimal prefixed by the optional mode
60982fd4e08Sratchov */
61082fd4e08Sratchov int
parse_modeval(char ** line,int * rmode,float * rval)61182fd4e08Sratchov parse_modeval(char **line, int *rmode, float *rval)
61282fd4e08Sratchov {
61382fd4e08Sratchov char *p = *line;
61482fd4e08Sratchov unsigned mode;
61582fd4e08Sratchov
61682fd4e08Sratchov switch (*p) {
61782fd4e08Sratchov case '+':
61882fd4e08Sratchov mode = MODE_ADD;
61982fd4e08Sratchov p++;
62082fd4e08Sratchov break;
62182fd4e08Sratchov case '-':
62282fd4e08Sratchov mode = MODE_SUB;
62382fd4e08Sratchov p++;
62482fd4e08Sratchov break;
62582fd4e08Sratchov case '!':
62682fd4e08Sratchov mode = MODE_TOGGLE;
62782fd4e08Sratchov p++;
62882fd4e08Sratchov break;
62982fd4e08Sratchov default:
63082fd4e08Sratchov mode = MODE_SET;
63182fd4e08Sratchov }
63282fd4e08Sratchov if (mode != MODE_TOGGLE) {
63382fd4e08Sratchov if (!parse_val(&p, rval))
63482fd4e08Sratchov return 0;
63582fd4e08Sratchov }
63682fd4e08Sratchov *line = p;
63782fd4e08Sratchov *rmode = mode;
63882fd4e08Sratchov return 1;
63982fd4e08Sratchov }
64082fd4e08Sratchov
64182fd4e08Sratchov /*
64282fd4e08Sratchov * dump the whole controls list, useful for debugging
64382fd4e08Sratchov */
64482fd4e08Sratchov void
dump(void)64582fd4e08Sratchov dump(void)
64682fd4e08Sratchov {
64782fd4e08Sratchov struct info *i;
64882fd4e08Sratchov
64982fd4e08Sratchov for (i = infolist; i != NULL; i = i->next) {
65082fd4e08Sratchov printf("%03u:", i->ctladdr);
65182fd4e08Sratchov print_node(&i->desc.node0, 0);
65282fd4e08Sratchov printf(".%s", i->desc.func);
65382fd4e08Sratchov printf("=");
65482fd4e08Sratchov switch (i->desc.type) {
65582fd4e08Sratchov case SIOCTL_NUM:
65682fd4e08Sratchov case SIOCTL_SW:
65782fd4e08Sratchov printf("0..%d (%u)", i->desc.maxval, i->curval);
65882fd4e08Sratchov break;
65949f67e12Sratchov case SIOCTL_SEL:
66049f67e12Sratchov print_node(&i->desc.node1, 0);
66149f67e12Sratchov break;
66282fd4e08Sratchov case SIOCTL_VEC:
66382fd4e08Sratchov case SIOCTL_LIST:
66482fd4e08Sratchov print_node(&i->desc.node1, 0);
66582fd4e08Sratchov printf(":0..%d (%u)", i->desc.maxval, i->curval);
66682fd4e08Sratchov }
667*4aaef610Sratchov print_display(i);
66882fd4e08Sratchov printf("\n");
66982fd4e08Sratchov }
67082fd4e08Sratchov }
67182fd4e08Sratchov
67282fd4e08Sratchov /*
67382fd4e08Sratchov * parse and execute a command ``<parameter>[=<value>]''
67482fd4e08Sratchov */
67582fd4e08Sratchov int
cmd(char * line)67682fd4e08Sratchov cmd(char *line)
67782fd4e08Sratchov {
67882fd4e08Sratchov char *pos, *group;
67982fd4e08Sratchov struct info *i, *e, *g;
68082fd4e08Sratchov char func[SIOCTL_NAMEMAX];
68182fd4e08Sratchov char astr[SIOCTL_NAMEMAX], vstr[SIOCTL_NAMEMAX];
68282fd4e08Sratchov int aunit, vunit;
68382fd4e08Sratchov unsigned npar = 0, nent = 0;
68482fd4e08Sratchov int comma, mode;
68582fd4e08Sratchov float val;
68682fd4e08Sratchov
68782fd4e08Sratchov pos = strrchr(line, '/');
68882fd4e08Sratchov if (pos != NULL) {
68982fd4e08Sratchov group = line;
69082fd4e08Sratchov pos[0] = 0;
69182fd4e08Sratchov pos++;
69282fd4e08Sratchov } else {
69382fd4e08Sratchov group = "";
69482fd4e08Sratchov pos = line;
69582fd4e08Sratchov }
69682fd4e08Sratchov if (!parse_node(&pos, astr, &aunit))
69782fd4e08Sratchov return 0;
69882fd4e08Sratchov if (*pos != '.') {
69982fd4e08Sratchov fprintf(stderr, "'.' expected near '%s'\n", pos);
70082fd4e08Sratchov return 0;
70182fd4e08Sratchov }
70282fd4e08Sratchov pos++;
70382fd4e08Sratchov if (!parse_name(&pos, func))
70482fd4e08Sratchov return 0;
70582fd4e08Sratchov for (g = infolist;; g = g->next) {
70682fd4e08Sratchov if (g == NULL) {
70782fd4e08Sratchov fprintf(stderr, "%s.%s: no such control\n", astr, func);
70882fd4e08Sratchov return 0;
70982fd4e08Sratchov }
71082fd4e08Sratchov if (strcmp(g->desc.group, group) == 0 &&
71182fd4e08Sratchov strcmp(g->desc.func, func) == 0 &&
71282fd4e08Sratchov strcmp(g->desc.node0.name, astr) == 0)
71382fd4e08Sratchov break;
71482fd4e08Sratchov }
71582fd4e08Sratchov g->mode = MODE_PRINT;
71682fd4e08Sratchov if (*pos != '=') {
71782fd4e08Sratchov if (*pos != '\0') {
71882fd4e08Sratchov fprintf(stderr, "junk at end of command\n");
71982fd4e08Sratchov return 0;
72082fd4e08Sratchov }
72182fd4e08Sratchov return 1;
72282fd4e08Sratchov }
72382fd4e08Sratchov pos++;
72482fd4e08Sratchov if (i_flag) {
72582fd4e08Sratchov printf("can't set values in info mode\n");
72682fd4e08Sratchov return 0;
72782fd4e08Sratchov }
72882fd4e08Sratchov npar = 0;
72982fd4e08Sratchov switch (g->desc.type) {
73082fd4e08Sratchov case SIOCTL_NUM:
73182fd4e08Sratchov case SIOCTL_SW:
73282fd4e08Sratchov if (!parse_modeval(&pos, &mode, &val))
73382fd4e08Sratchov return 0;
73482fd4e08Sratchov for (i = g; i != NULL; i = nextpar(i)) {
73582fd4e08Sratchov if (!matchpar(i, astr, aunit))
73682fd4e08Sratchov continue;
73782fd4e08Sratchov i->mode = mode;
73882fd4e08Sratchov i->newval = ftoi(val * i->desc.maxval);
73982fd4e08Sratchov npar++;
74082fd4e08Sratchov }
74182fd4e08Sratchov break;
74249f67e12Sratchov case SIOCTL_SEL:
743bd915203Sratchov if (*pos == '\0') {
744bd915203Sratchov fprintf(stderr, "%s.%s: expects value\n", astr, func);
745bd915203Sratchov exit(1);
746bd915203Sratchov }
747d9a51c35Sjmc /* FALLTHROUGH */
74882fd4e08Sratchov case SIOCTL_VEC:
74982fd4e08Sratchov case SIOCTL_LIST:
75082fd4e08Sratchov for (i = g; i != NULL; i = nextpar(i)) {
75182fd4e08Sratchov if (!matchpar(i, astr, aunit))
75282fd4e08Sratchov continue;
75382fd4e08Sratchov for (e = i; e != NULL; e = nextent(e, 0)) {
75482fd4e08Sratchov e->newval = 0;
75582fd4e08Sratchov e->mode = MODE_SET;
75682fd4e08Sratchov }
75782fd4e08Sratchov npar++;
75882fd4e08Sratchov }
75982fd4e08Sratchov comma = 0;
76082fd4e08Sratchov for (;;) {
76182fd4e08Sratchov if (*pos == '\0')
76282fd4e08Sratchov break;
76382fd4e08Sratchov if (comma) {
76482fd4e08Sratchov if (*pos != ',')
76582fd4e08Sratchov break;
76682fd4e08Sratchov pos++;
76782fd4e08Sratchov }
76882fd4e08Sratchov if (!parse_node(&pos, vstr, &vunit))
76982fd4e08Sratchov return 0;
77082fd4e08Sratchov if (*pos == ':') {
77182fd4e08Sratchov pos++;
77282fd4e08Sratchov if (!parse_modeval(&pos, &mode, &val))
77382fd4e08Sratchov return 0;
77482fd4e08Sratchov } else {
77582fd4e08Sratchov val = 1.;
77682fd4e08Sratchov mode = MODE_SET;
77782fd4e08Sratchov }
77882fd4e08Sratchov nent = 0;
77982fd4e08Sratchov for (i = g; i != NULL; i = nextpar(i)) {
78082fd4e08Sratchov if (!matchpar(i, astr, aunit))
78182fd4e08Sratchov continue;
78282fd4e08Sratchov for (e = i; e != NULL; e = nextent(e, 0)) {
78382fd4e08Sratchov if (matchent(e, vstr, vunit)) {
78482fd4e08Sratchov e->newval = ftoi(val * e->desc.maxval);
78582fd4e08Sratchov e->mode = mode;
78682fd4e08Sratchov nent++;
78782fd4e08Sratchov }
78882fd4e08Sratchov }
78982fd4e08Sratchov }
790*4aaef610Sratchov if (*pos == '(') {
791*4aaef610Sratchov while (*pos != 0) {
792*4aaef610Sratchov if (*pos++ == ')')
793*4aaef610Sratchov break;
794*4aaef610Sratchov }
795*4aaef610Sratchov }
79682fd4e08Sratchov if (nent == 0) {
79782fd4e08Sratchov /* XXX: use print_node()-like routine */
79882fd4e08Sratchov fprintf(stderr, "%s[%d]: invalid value\n", vstr, vunit);
799f707c874Sratchov print_par(g, 0);
80082fd4e08Sratchov exit(1);
80182fd4e08Sratchov }
80282fd4e08Sratchov comma = 1;
80382fd4e08Sratchov }
80482fd4e08Sratchov }
80582fd4e08Sratchov if (npar == 0) {
80682fd4e08Sratchov fprintf(stderr, "%s: invalid parameter\n", line);
80782fd4e08Sratchov exit(1);
80882fd4e08Sratchov }
80982fd4e08Sratchov if (*pos != '\0') {
81082fd4e08Sratchov printf("%s: junk at end of command\n", pos);
81182fd4e08Sratchov exit(1);
81282fd4e08Sratchov }
81382fd4e08Sratchov return 1;
81482fd4e08Sratchov }
81582fd4e08Sratchov
81682fd4e08Sratchov /*
81782fd4e08Sratchov * write the controls with the ``set'' flag on the device
81882fd4e08Sratchov */
81982fd4e08Sratchov void
commit(void)82082fd4e08Sratchov commit(void)
82182fd4e08Sratchov {
82282fd4e08Sratchov struct info *i;
82382fd4e08Sratchov int val;
82482fd4e08Sratchov
82582fd4e08Sratchov for (i = infolist; i != NULL; i = i->next) {
82682fd4e08Sratchov val = 0xdeadbeef;
82782fd4e08Sratchov switch (i->mode) {
82882fd4e08Sratchov case MODE_IGNORE:
82982fd4e08Sratchov case MODE_PRINT:
83082fd4e08Sratchov continue;
83182fd4e08Sratchov case MODE_SET:
83282fd4e08Sratchov val = i->newval;
83382fd4e08Sratchov break;
83482fd4e08Sratchov case MODE_ADD:
83582fd4e08Sratchov val = i->curval + i->newval;
83682fd4e08Sratchov if (val > i->desc.maxval)
83782fd4e08Sratchov val = i->desc.maxval;
83882fd4e08Sratchov break;
83982fd4e08Sratchov case MODE_SUB:
84082fd4e08Sratchov val = i->curval - i->newval;
84182fd4e08Sratchov if (val < 0)
84282fd4e08Sratchov val = 0;
84382fd4e08Sratchov break;
84482fd4e08Sratchov case MODE_TOGGLE:
84582fd4e08Sratchov val = i->curval ? 0 : i->desc.maxval;
84682fd4e08Sratchov }
84782fd4e08Sratchov sioctl_setval(hdl, i->ctladdr, val);
84882fd4e08Sratchov i->curval = val;
84982fd4e08Sratchov }
85082fd4e08Sratchov }
85182fd4e08Sratchov
85282fd4e08Sratchov /*
85382fd4e08Sratchov * print all parameters
85482fd4e08Sratchov */
85582fd4e08Sratchov void
list(void)85682fd4e08Sratchov list(void)
85782fd4e08Sratchov {
85882fd4e08Sratchov struct info *p, *g;
85982fd4e08Sratchov
86082fd4e08Sratchov for (g = infolist; g != NULL; g = nextfunc(g)) {
86182fd4e08Sratchov if (g->mode == MODE_IGNORE)
86282fd4e08Sratchov continue;
86382fd4e08Sratchov if (i_flag) {
86482fd4e08Sratchov if (v_flag) {
86582fd4e08Sratchov for (p = g; p != NULL; p = nextpar(p))
866f707c874Sratchov print_par(p, 0);
86782fd4e08Sratchov } else
868f707c874Sratchov print_par(g, 1);
86982fd4e08Sratchov } else {
87082fd4e08Sratchov if (v_flag || !ismono(g)) {
87182fd4e08Sratchov for (p = g; p != NULL; p = nextpar(p))
872f707c874Sratchov print_par(p, 0);
87382fd4e08Sratchov } else
874f707c874Sratchov print_par(g, 1);
87582fd4e08Sratchov }
87682fd4e08Sratchov }
87782fd4e08Sratchov }
87882fd4e08Sratchov
87982fd4e08Sratchov /*
88082fd4e08Sratchov * register a new knob/button, called from the poll() loop. this may be
88182fd4e08Sratchov * called when label string changes, in which case we update the
882e8de1577Sratchov * existing label widget rather than inserting a new one.
88382fd4e08Sratchov */
88482fd4e08Sratchov void
ondesc(void * arg,struct sioctl_desc * d,int curval)88582fd4e08Sratchov ondesc(void *arg, struct sioctl_desc *d, int curval)
88682fd4e08Sratchov {
88782fd4e08Sratchov struct info *i, **pi;
88882fd4e08Sratchov int cmp;
88982fd4e08Sratchov
89082fd4e08Sratchov if (d == NULL)
89182fd4e08Sratchov return;
89282fd4e08Sratchov
89382fd4e08Sratchov /*
89482fd4e08Sratchov * delete control
89582fd4e08Sratchov */
89682fd4e08Sratchov for (pi = &infolist; (i = *pi) != NULL; pi = &i->next) {
89782fd4e08Sratchov if (d->addr == i->desc.addr) {
89882fd4e08Sratchov if (m_flag)
899f707c874Sratchov print_ent(i, "deleted");
90082fd4e08Sratchov *pi = i->next;
90182fd4e08Sratchov free(i);
90282fd4e08Sratchov break;
90382fd4e08Sratchov }
90482fd4e08Sratchov }
90582fd4e08Sratchov
906a7cecdf4Sratchov switch (d->type) {
907a7cecdf4Sratchov case SIOCTL_NUM:
908a7cecdf4Sratchov case SIOCTL_SW:
909a7cecdf4Sratchov case SIOCTL_VEC:
910a7cecdf4Sratchov case SIOCTL_LIST:
91149f67e12Sratchov case SIOCTL_SEL:
912a7cecdf4Sratchov break;
913a7cecdf4Sratchov default:
91482fd4e08Sratchov return;
915a7cecdf4Sratchov }
91682fd4e08Sratchov
91782fd4e08Sratchov /*
91882fd4e08Sratchov * find the right position to insert the new widget
91982fd4e08Sratchov */
92082fd4e08Sratchov for (pi = &infolist; (i = *pi) != NULL; pi = &i->next) {
92182fd4e08Sratchov cmp = cmpdesc(d, &i->desc);
9220bc434f8Sratchov if (cmp <= 0)
92382fd4e08Sratchov break;
92482fd4e08Sratchov }
92582fd4e08Sratchov i = malloc(sizeof(struct info));
92682fd4e08Sratchov if (i == NULL) {
92782fd4e08Sratchov perror("malloc");
92882fd4e08Sratchov exit(1);
92982fd4e08Sratchov }
93082fd4e08Sratchov i->desc = *d;
93182fd4e08Sratchov i->ctladdr = d->addr;
93282fd4e08Sratchov i->curval = i->newval = curval;
93382fd4e08Sratchov i->mode = MODE_IGNORE;
93482fd4e08Sratchov i->next = *pi;
93582fd4e08Sratchov *pi = i;
93682fd4e08Sratchov if (m_flag)
937f707c874Sratchov print_ent(i, "added");
93882fd4e08Sratchov }
93982fd4e08Sratchov
94082fd4e08Sratchov /*
94182fd4e08Sratchov * update a knob/button state, called from the poll() loop
94282fd4e08Sratchov */
94382fd4e08Sratchov void
onctl(void * arg,unsigned addr,unsigned val)94482fd4e08Sratchov onctl(void *arg, unsigned addr, unsigned val)
94582fd4e08Sratchov {
94649f67e12Sratchov struct info *i, *j;
94782fd4e08Sratchov
94849f67e12Sratchov i = infolist;
94949f67e12Sratchov for (;;) {
95049f67e12Sratchov if (i == NULL)
95149f67e12Sratchov return;
95249f67e12Sratchov if (i->ctladdr == addr)
95349f67e12Sratchov break;
95449f67e12Sratchov i = i->next;
95549f67e12Sratchov }
95649f67e12Sratchov
95749f67e12Sratchov if (i->curval == val) {
95849f67e12Sratchov print_ent(i, "eq");
95949f67e12Sratchov return;
96049f67e12Sratchov }
96149f67e12Sratchov
96249f67e12Sratchov if (i->desc.type == SIOCTL_SEL) {
96349f67e12Sratchov for (j = infolist; j != NULL; j = j->next) {
96449f67e12Sratchov if (strcmp(i->desc.group, j->desc.group) != 0 ||
96549f67e12Sratchov strcmp(i->desc.node0.name, j->desc.node0.name) != 0 ||
96649f67e12Sratchov strcmp(i->desc.func, j->desc.func) != 0 ||
96749f67e12Sratchov i->desc.node0.unit != j->desc.node0.unit)
96882fd4e08Sratchov continue;
96949f67e12Sratchov j->curval = (i->ctladdr == j->ctladdr);
97049f67e12Sratchov }
97149f67e12Sratchov } else
97282fd4e08Sratchov i->curval = val;
97349f67e12Sratchov
97482fd4e08Sratchov if (m_flag)
975f707c874Sratchov print_ent(i, "changed");
97682fd4e08Sratchov }
97782fd4e08Sratchov
97882fd4e08Sratchov int
main(int argc,char ** argv)97982fd4e08Sratchov main(int argc, char **argv)
98082fd4e08Sratchov {
98182fd4e08Sratchov char *devname = SIO_DEVANY;
98282fd4e08Sratchov int i, c, d_flag = 0;
98382fd4e08Sratchov struct info *g;
98482fd4e08Sratchov struct pollfd *pfds;
98582fd4e08Sratchov int nfds, revents;
98682fd4e08Sratchov
9873b691801Sratchov while ((c = getopt(argc, argv, "df:imnqv")) != -1) {
98882fd4e08Sratchov switch (c) {
98982fd4e08Sratchov case 'd':
99082fd4e08Sratchov d_flag = 1;
99182fd4e08Sratchov break;
99282fd4e08Sratchov case 'f':
99382fd4e08Sratchov devname = optarg;
99482fd4e08Sratchov break;
99582fd4e08Sratchov case 'i':
99682fd4e08Sratchov i_flag = 1;
99782fd4e08Sratchov break;
99882fd4e08Sratchov case 'm':
99982fd4e08Sratchov m_flag = 1;
100082fd4e08Sratchov break;
100126791b1eSratchov case 'n':
100226791b1eSratchov n_flag = 1;
100326791b1eSratchov break;
10043b691801Sratchov case 'q':
10053b691801Sratchov q_flag = 1;
10063b691801Sratchov break;
100782fd4e08Sratchov case 'v':
100882fd4e08Sratchov v_flag++;
100982fd4e08Sratchov break;
101082fd4e08Sratchov default:
101182fd4e08Sratchov fprintf(stderr, "usage: sndioctl "
10123b691801Sratchov "[-dimnqv] [-f device] [command ...]\n");
101382fd4e08Sratchov exit(1);
101482fd4e08Sratchov }
101582fd4e08Sratchov }
101682fd4e08Sratchov argc -= optind;
101782fd4e08Sratchov argv += optind;
101882fd4e08Sratchov
101982fd4e08Sratchov hdl = sioctl_open(devname, SIOCTL_READ | SIOCTL_WRITE, 0);
102082fd4e08Sratchov if (hdl == NULL) {
102182fd4e08Sratchov fprintf(stderr, "%s: can't open control device\n", devname);
102282fd4e08Sratchov exit(1);
102382fd4e08Sratchov }
10245d6ea990Smestre
10255d6ea990Smestre if (pledge("stdio audio", NULL) == -1) {
10265d6ea990Smestre fprintf(stderr, "%s: pledge: %s\n", getprogname(),
10275d6ea990Smestre strerror(errno));
10285d6ea990Smestre exit(1);
10295d6ea990Smestre }
10305d6ea990Smestre
103182fd4e08Sratchov if (!sioctl_ondesc(hdl, ondesc, NULL)) {
103282fd4e08Sratchov fprintf(stderr, "%s: can't get device description\n", devname);
103382fd4e08Sratchov exit(1);
103482fd4e08Sratchov }
103582fd4e08Sratchov sioctl_onval(hdl, onctl, NULL);
103682fd4e08Sratchov
103782fd4e08Sratchov if (d_flag) {
103882fd4e08Sratchov if (argc > 0) {
103982fd4e08Sratchov fprintf(stderr,
104082fd4e08Sratchov "commands are not allowed with -d option\n");
104182fd4e08Sratchov exit(1);
104282fd4e08Sratchov }
104382fd4e08Sratchov dump();
104482fd4e08Sratchov } else {
104582fd4e08Sratchov if (argc == 0) {
104682fd4e08Sratchov for (g = infolist; g != NULL; g = nextfunc(g))
104782fd4e08Sratchov g->mode = MODE_PRINT;
104882fd4e08Sratchov } else {
104982fd4e08Sratchov for (i = 0; i < argc; i++) {
105082fd4e08Sratchov if (!cmd(argv[i]))
105182fd4e08Sratchov return 1;
105282fd4e08Sratchov }
105382fd4e08Sratchov }
105482fd4e08Sratchov commit();
10553b691801Sratchov if (!q_flag)
105682fd4e08Sratchov list();
105782fd4e08Sratchov }
105882fd4e08Sratchov if (m_flag) {
105982fd4e08Sratchov pfds = malloc(sizeof(struct pollfd) * sioctl_nfds(hdl));
106082fd4e08Sratchov if (pfds == NULL) {
106182fd4e08Sratchov perror("malloc");
106282fd4e08Sratchov exit(1);
106382fd4e08Sratchov }
106482fd4e08Sratchov for (;;) {
106574b220efSratchov fflush(stdout);
106682fd4e08Sratchov nfds = sioctl_pollfd(hdl, pfds, POLLIN);
106782fd4e08Sratchov if (nfds == 0)
106882fd4e08Sratchov break;
106982fd4e08Sratchov while (poll(pfds, nfds, -1) < 0) {
107082fd4e08Sratchov if (errno != EINTR) {
107182fd4e08Sratchov perror("poll");
107282fd4e08Sratchov exit(1);
107382fd4e08Sratchov }
107482fd4e08Sratchov }
107582fd4e08Sratchov revents = sioctl_revents(hdl, pfds);
107682fd4e08Sratchov if (revents & POLLHUP) {
107782fd4e08Sratchov fprintf(stderr, "disconnected\n");
107882fd4e08Sratchov break;
107982fd4e08Sratchov }
108082fd4e08Sratchov }
108182fd4e08Sratchov free(pfds);
108282fd4e08Sratchov }
108382fd4e08Sratchov sioctl_close(hdl);
108482fd4e08Sratchov return 0;
108582fd4e08Sratchov }
1086