Annotation of src/usr.bin/mixerctl/mixerctl.c, Revision 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: }