Annotation of src/usr.bin/mixerctl/mixerctl.c, Revision 1.5
1.5 ! mickey 1: /* $OpenBSD: mixerctl.c,v 1.4 1998/05/02 22:28:07 millert Exp $ */
1.3 provos 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;
1.4 millert 172: for (i = 0; i < p->infp->un.s.num_mem; i++)
1.1 provos 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) {
1.4 millert 187: switch (*q) {
188: case '+':
189: case '-':
190: m->un.value.level[0] += v;
191: break;
192: default:
193: m->un.value.level[0] = v;
194: break;
195: }
1.1 provos 196: } else {
197: warnx("Bad number %s", q);
198: return 0;
199: }
200: } else {
201: if (sscanf(q, "%d,%d", &v0, &v1) == 2) {
1.4 millert 202: switch (*q) {
203: case '+':
204: case '-':
205: m->un.value.level[0] += v0;
206: break;
207: default:
208: m->un.value.level[0] = v0;
209: break;
210: }
211: s = strchr(q, ',') + 1;
212: switch (*s) {
213: case '+':
214: case '-':
215: m->un.value.level[1] += v1;
216: break;
217: default:
218: m->un.value.level[1] = v1;
219: break;
220: }
1.1 provos 221: } else if (sscanf(q, "%d", &v) == 1) {
1.4 millert 222: switch (*q) {
223: case '+':
224: case '-':
225: m->un.value.level[0] += v;
226: m->un.value.level[1] += v;
227: break;
228: default:
229: m->un.value.level[0] =
230: m->un.value.level[1] = v;
231: break;
232: }
1.1 provos 233: } else {
234: warnx("Bad numbers %s", q);
235: return 0;
236: }
237: }
238: break;
239: default:
240: errx(1, "Invalid format.");
241: }
242: p->changed = 1;
243: return 1;
244: }
245:
246: int
247: main(argc, argv)
248: int argc;
249: char **argv;
250: {
251: int fd, i, j, ch, pos;
252: int aflag = 0, wflag = 0, vflag = 0;
1.3 provos 253: char *file;
1.1 provos 254: char *sep = "=";
255: mixer_devinfo_t dinfo;
256: mixer_ctrl_t val;
257: int ndev;
1.3 provos 258:
259: file = getenv("MIXERDEVICE");
260: if (file == 0)
261: file = "/dev/mixer";
1.1 provos 262:
263: prog = *argv;
264:
265: while ((ch = getopt(argc, argv, "af:nvw")) != -1) {
266: switch(ch) {
267: case 'a':
268: aflag++;
269: break;
270: case 'w':
271: wflag++;
272: break;
273: case 'v':
274: vflag++;
275: break;
276: case 'n':
277: sep = 0;
278: break;
279: case 'f':
280: file = optarg;
281: break;
282: case '?':
283: default:
284: usage:
285: fprintf(out, "%s [-f file] [-v] [-n] name ...\n", prog);
286: fprintf(out, "%s [-f file] [-v] [-n] -w name=value ...\n", prog);
287: fprintf(out, "%s [-f file] [-v] [-n] -a\n", prog);
288: exit(0);
289: }
290: }
291: argc -= optind;
292: argv += optind;
293:
294: fd = open(file, O_RDWR);
295: if (fd < 0)
296: err(1, "%s", file);
297:
298: for(ndev = 0; ; ndev++) {
299: dinfo.index = ndev;
300: if (ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo) < 0)
301: break;
302: }
1.5 ! mickey 303:
! 304: if (ndev == 0)
! 305: errx(1, "no mixer devices configured");
! 306:
1.1 provos 307: rfields = calloc(ndev, sizeof *rfields);
308: fields = calloc(ndev, sizeof *fields);
309: infos = calloc(ndev, sizeof *infos);
310: values = calloc(ndev, sizeof *values);
311:
312: for(i = 0; i < ndev; i++) {
313: infos[i].index = i;
314: ioctl(fd, AUDIO_MIXER_DEVINFO, &infos[i]);
315: }
316:
317: for(i = 0; i < ndev; i++) {
318: rfields[i].name = infos[i].label.name;
319: rfields[i].valp = &values[i];
320: rfields[i].infp = &infos[i];
321: }
322:
323: for(i = 0; i < ndev; i++) {
324: values[i].dev = i;
325: values[i].type = infos[i].type;
326: if (infos[i].type != AUDIO_MIXER_CLASS) {
327: values[i].un.value.num_channels = 2;
328: if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0) {
329: values[i].un.value.num_channels = 1;
330: if (ioctl(fd, AUDIO_MIXER_READ, &values[i]) < 0)
331: err(1, "AUDIO_MIXER_READ");
332: }
333: }
334: }
335:
336: for(j = i = 0; i < ndev; i++) {
337: if (infos[i].type != AUDIO_MIXER_CLASS &&
338: infos[i].type != -1) {
339: fields[j++] = rfields[i];
340: for(pos = infos[i].next; pos != AUDIO_MIXER_LAST;
341: pos = infos[pos].next) {
342: fields[j] = rfields[pos];
343: fields[j].name = catstr(rfields[i].name,
344: infos[pos].label.name);
345: infos[pos].type = -1;
346: j++;
347: }
348: }
349: }
350:
351: for(i = 0; i < j; i++) {
352: int cls = fields[i].infp->mixer_class;
353: if (cls >= 0 && cls < ndev)
354: fields[i].name = catstr(infos[cls].label.name,
355: fields[i].name);
356: }
357:
358: if (argc == 0 && aflag && !wflag) {
359: for(i = 0; fields[i].name; i++) {
360: prfield(&fields[i], sep, vflag);
361: fprintf(out, "\n");
362: }
363: } else if (argc > 0 && !aflag) {
364: struct field *p;
365: if (wflag) {
366: while(argc--) {
367: char *q;
368:
369: q = strchr(*argv, '=');
370: if (q) {
371: *q++ = 0;
372: p = findfield(*argv);
373: if (p == 0)
374: warnx("field %s does not exist", *argv);
375: else {
376: val = *p->valp;
377: if (rdfield(p, q)) {
378: if (ioctl(fd, AUDIO_MIXER_WRITE, p->valp) < 0)
379: warn("AUDIO_MIXER_WRITE");
380: else if (sep) {
381: *p->valp = val;
382: prfield(p, ": ", 0);
383: ioctl(fd, AUDIO_MIXER_READ, p->valp);
384: printf(" -> ");
385: prfield(p, 0, 0);
386: printf("\n");
387: }
388: }
389: }
390: } else {
391: warnx("No `=' in %s", *argv);
392: }
393: argv++;
394: }
395: } else {
396: while(argc--) {
397: p = findfield(*argv);
398: if (p == 0)
399: warnx("field %s does not exist", *argv);
400: else
401: prfield(p, sep, vflag), fprintf(out, "\n");
402: argv++;
403: }
404: }
405: } else
406: goto usage;
407: exit(0);
408: }