Annotation of src/usr.bin/mixerctl/mixerctl.c, Revision 1.3
1.3 ! provos 1: /* $OpenBSD: mixerctl.c,v 1.2 1998/04/26 22:27:30 provos Exp $ */
! 2: /* $NetBSD: mixerctl.c,v 1.11 1998/04/27 16:55:23 augustss Exp $ */
1.1 provos 3:
4: /*
5: * Copyright (c) 1997 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * Author: Lennart Augustsson, with some code and ideas from Chuck Cranor.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38: #include <stdio.h>
39: #include <stdlib.h>
40: #include <fcntl.h>
41: #include <err.h>
42: #include <unistd.h>
43: #include <string.h>
44: #include <sys/types.h>
45: #include <sys/ioctl.h>
46: #include <sys/audioio.h>
47:
48: char *catstr __P((char *p, char *q));
49: struct field *findfield __P((char *name));
50: void prfield __P((struct field *p, char *sep, int prvalset));
51: int rdfield __P((struct field *p, char *q));
52: int main(int argc, char **argv);
53:
54: FILE *out = stdout;
55:
56: char *prog;
57:
58: struct field {
59: char *name;
60: mixer_ctrl_t *valp;
61: mixer_devinfo_t *infp;
62: char changed;
63: } *fields, *rfields;
64:
65: mixer_ctrl_t *values;
66: mixer_devinfo_t *infos;
67:
68: char *
69: catstr(p, q)
70: char *p;
71: char *q;
72: {
73: char *r = malloc(strlen(p) + strlen(q) + 2);
74: strcpy(r, p);
75: strcat(r, ".");
76: strcat(r, q);
77: return r;
78: }
79:
80: struct field *
81: findfield(name)
82: char *name;
83: {
84: int i;
85: for(i = 0; fields[i].name; i++)
86: if (strcmp(fields[i].name, name) == 0)
87: return &fields[i];
88: return 0;
89: }
90:
91: void
92: prfield(p, sep, prvalset)
93: struct field *p;
94: char *sep;
95: int prvalset;
96: {
97: mixer_ctrl_t *m;
98: int i, n;
99:
100: if (sep)
101: fprintf(out, "%s%s", p->name, sep);
102: m = p->valp;
103: switch(m->type) {
104: case AUDIO_MIXER_ENUM:
105: for(i = 0; i < p->infp->un.e.num_mem; i++)
106: if (p->infp->un.e.member[i].ord == m->un.ord)
107: fprintf(out, "%s",
108: p->infp->un.e.member[i].label.name);
109: if (prvalset) {
110: fprintf(out, " [ ");
111: for(i = 0; i < p->infp->un.e.num_mem; i++)
112: fprintf(out, "%s ", p->infp->un.e.member[i].label.name);
113: fprintf(out, "]");
114: }
115: break;
116: case AUDIO_MIXER_SET:
117: for(n = i = 0; i < p->infp->un.s.num_mem; i++)
118: if (m->un.mask & p->infp->un.s.member[i].mask)
119: fprintf(out, "%s%s", n++ ? "," : "",
120: p->infp->un.s.member[i].label.name);
121: if (prvalset) {
122: fprintf(out, " { ");
123: for(i = 0; i < p->infp->un.s.num_mem; i++)
124: fprintf(out, "%s ", p->infp->un.s.member[i].label.name);
125: fprintf(out, "}");
126: }
127: break;
128: case AUDIO_MIXER_VALUE:
129: if (m->un.value.num_channels == 1)
130: fprintf(out, "%d", m->un.value.level[0]);
131: else
132: fprintf(out, "%d,%d", m->un.value.level[0],
133: m->un.value.level[1]);
134: if (prvalset)
135: fprintf(out, " %s", p->infp->un.v.units.name);
136: break;
137: default:
138: printf("\n");
139: errx(1, "Invalid format.");
140: }
141: }
142:
143: int
144: rdfield(p, q)
145: struct field *p;
146: char *q;
147: {
148: mixer_ctrl_t *m;
149: int v, v0, v1, mask;
150: int i;
151: char *s;
152:
153: m = p->valp;
154: switch(m->type) {
155: case AUDIO_MIXER_ENUM:
156: for(i = 0; i < p->infp->un.e.num_mem; i++)
157: if (strcmp(p->infp->un.e.member[i].label.name, q) == 0)
158: break;
159: if (i < p->infp->un.e.num_mem)
160: m->un.ord = p->infp->un.e.member[i].ord;
161: else {
162: warnx("Bad enum value %s", q);
163: return 0;
164: }
165: break;
166: case AUDIO_MIXER_SET:
167: mask = 0;
168: for(v = 0; q && *q; q = s) {
169: s = strchr(q, ',');
170: if (s)
171: *s++ = 0;
172: for(i = 0; i < p->infp->un.s.num_mem; i++)
173: if (strcmp(p->infp->un.s.member[i].label.name, q) == 0)
174: break;
175: if (i < p->infp->un.s.num_mem) {
176: mask |= p->infp->un.s.member[i].mask;
177: } else {
178: warnx("Bad set value %s", q);
179: return 0;
180: }
181: }
182: m->un.mask = mask;
183: break;
184: case AUDIO_MIXER_VALUE:
185: if (m->un.value.num_channels == 1) {
186: if (sscanf(q, "%d", &v) == 1) {
187: m->un.value.level[0] = v;
188: } else {
189: warnx("Bad number %s", q);
190: return 0;
191: }
192: } else {
193: if (sscanf(q, "%d,%d", &v0, &v1) == 2) {
194: m->un.value.level[0] = v0;
195: m->un.value.level[1] = v1;
196: } else if (sscanf(q, "%d", &v) == 1) {
197: m->un.value.level[0] = m->un.value.level[1] = v;
198: } else {
199: warnx("Bad numbers %s", q);
200: return 0;
201: }
202: }
203: break;
204: default:
205: errx(1, "Invalid format.");
206: }
207: p->changed = 1;
208: return 1;
209: }
210:
211: int
212: main(argc, argv)
213: int argc;
214: char **argv;
215: {
216: int fd, i, j, ch, pos;
217: int aflag = 0, wflag = 0, vflag = 0;
1.3 ! provos 218: char *file;
1.1 provos 219: char *sep = "=";
220: mixer_devinfo_t dinfo;
221: mixer_ctrl_t val;
222: int ndev;
1.3 ! provos 223:
! 224: file = getenv("MIXERDEVICE");
! 225: if (file == 0)
! 226: file = "/dev/mixer";
1.1 provos 227:
228: prog = *argv;
229:
230: while ((ch = getopt(argc, argv, "af:nvw")) != -1) {
231: switch(ch) {
232: case 'a':
233: aflag++;
234: break;
235: case 'w':
236: wflag++;
237: break;
238: case 'v':
239: vflag++;
240: break;
241: case 'n':
242: sep = 0;
243: break;
244: case 'f':
245: file = optarg;
246: break;
247: case '?':
248: default:
249: usage:
250: fprintf(out, "%s [-f file] [-v] [-n] name ...\n", prog);
251: fprintf(out, "%s [-f file] [-v] [-n] -w name=value ...\n", prog);
252: fprintf(out, "%s [-f file] [-v] [-n] -a\n", prog);
253: exit(0);
254: }
255: }
256: argc -= optind;
257: argv += optind;
258:
259: fd = open(file, O_RDWR);
260: if (fd < 0)
261: err(1, "%s", file);
262:
263: for(ndev = 0; ; ndev++) {
264: dinfo.index = ndev;
265: if (ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo) < 0)
266: break;
267: }
268: rfields = calloc(ndev, sizeof *rfields);
269: fields = calloc(ndev, sizeof *fields);
270: infos = calloc(ndev, sizeof *infos);
271: values = calloc(ndev, sizeof *values);
272:
273: for(i = 0; i < ndev; i++) {
274: infos[i].index = i;
275: ioctl(fd, AUDIO_MIXER_DEVINFO, &infos[i]);
276: }
277:
278: for(i = 0; i < ndev; i++) {
279: rfields[i].name = infos[i].label.name;
280: rfields[i].valp = &values[i];
281: rfields[i].infp = &infos[i];
282: }
283:
284: for(i = 0; i < ndev; i++) {
285: values[i].dev = i;
286: values[i].type = infos[i].type;
287: if (infos[i].type != AUDIO_MIXER_CLASS) {
288: values[i].un.value.num_channels = 2;
289: if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0) {
290: values[i].un.value.num_channels = 1;
291: if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0)
292: err(1, "AUDIO_MIXER_READ");
293: }
294: }
295: }
296:
297: for(j = i = 0; i < ndev; i++) {
298: if (infos[i].type != AUDIO_MIXER_CLASS &&
299: infos[i].type != -1) {
300: fields[j++] = rfields[i];
301: for(pos = infos[i].next; pos != AUDIO_MIXER_LAST;
302: pos = infos[pos].next) {
303: fields[j] = rfields[pos];
304: fields[j].name = catstr(rfields[i].name,
305: infos[pos].label.name);
306: infos[pos].type = -1;
307: j++;
308: }
309: }
310: }
311:
312: for(i = 0; i < j; i++) {
313: int cls = fields[i].infp->mixer_class;
314: if (cls >= 0 && cls < ndev)
315: fields[i].name = catstr(infos[cls].label.name,
316: fields[i].name);
317: }
318:
319: if (argc == 0 && aflag && !wflag) {
320: for(i = 0; fields[i].name; i++) {
321: prfield(&fields[i], sep, vflag);
322: fprintf(out, "\n");
323: }
324: } else if (argc > 0 && !aflag) {
325: struct field *p;
326: if (wflag) {
327: while(argc--) {
328: char *q;
329:
330: q = strchr(*argv, '=');
331: if (q) {
332: *q++ = 0;
333: p = findfield(*argv);
334: if (p == 0)
335: warnx("field %s does not exist", *argv);
336: else {
337: val = *p->valp;
338: if (rdfield(p, q)) {
339: if (ioctl(fd, AUDIO_MIXER_WRITE, p->valp) < 0)
340: warn("AUDIO_MIXER_WRITE");
341: else if (sep) {
342: *p->valp = val;
343: prfield(p, ": ", 0);
344: ioctl(fd, AUDIO_MIXER_READ, p->valp);
345: printf(" -> ");
346: prfield(p, 0, 0);
347: printf("\n");
348: }
349: }
350: }
351: } else {
352: warnx("No `=' in %s", *argv);
353: }
354: argv++;
355: }
356: } else {
357: while(argc--) {
358: p = findfield(*argv);
359: if (p == 0)
360: warnx("field %s does not exist", *argv);
361: else
362: prfield(p, sep, vflag), fprintf(out, "\n");
363: argv++;
364: }
365: }
366: } else
367: goto usage;
368: exit(0);
369: }