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