Merge branch 'vendor/GCC50'
[dragonfly.git] / usr.sbin / mixer / mixer.c
1 /*
2  *      This is an example of a mixer program for Linux
3  *
4  *      updated 1/1/93 to add stereo, level query, broken
5  *              devmask kludge - cmetz@thor.tjhsst.edu
6  *
7  * (C) Craig Metz and Hannu Savolainen 1993.
8  *
9  * You may do anything you wish with this program.
10  *
11  * ditto for my modifications (John-Mark Gurney, 1997)
12  *
13  * $FreeBSD: head/usr.sbin/mixer/mixer.c 230611 2012-01-27 09:15:55Z mav $
14  */
15
16 #include <err.h>
17 #include <fcntl.h>
18 #include <libgen.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/soundcard.h>
25
26 static const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
27
28 static void     usage(int devmask, int recmask);
29 static int      res_name(const char *name, int mask);
30 static void     print_recsrc(int recsrc, int recmask, int sflag);
31
32 static void
33 usage(int devmask, int recmask)
34 {
35         int     i, n;
36
37         printf("usage: mixer [-f device] [-s | -S] [dev [+|-][voll[:[+|-]volr]] ...\n"
38             "       mixer [-f device] [-s | -S] recsrc ...\n"
39             "       mixer [-f device] [-s | -S] {^|+|-|=}rec rdev ...\n");
40         if (devmask != 0) {
41                 printf(" devices: ");
42                 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
43                         if ((1 << i) & devmask)  {
44                                 if (n)
45                                         printf(", ");
46                                 printf("%s", names[i]);
47                                 n++;
48                         }
49                 }
50         }
51         if (recmask != 0) {
52                 printf("\n rec devices: ");
53                 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
54                         if ((1 << i) & recmask)  {
55                                 if (n)
56                                         printf(", ");
57                                 printf("%s", names[i]);
58                                 n++;
59                         }
60                 }
61         }
62         printf("\n");
63         exit(1);
64 }
65
66 static int
67 res_name(const char *name, int mask)
68 {
69         int     i;
70
71         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
72                 if ((1 << i) & mask && strcmp(names[i], name) == 0)
73                         break;
74
75         if (i == SOUND_MIXER_NRDEVICES)
76                 return (-1);
77
78         return (i);
79 }
80
81 static void
82 print_recsrc(int recsrc, int recmask, int sflag)
83 {
84         int     i, n;
85
86         if (recmask == 0)
87                 return;
88
89         if (!sflag)
90                 printf("Recording source: ");
91
92         for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
93                 if ((1 << i) & recsrc) {
94                         if (sflag)
95                                 printf("%srec ", n ? " +" : "=");
96                         else if (n)
97                                 printf(", ");
98                         printf("%s", names[i]);
99                         n++;
100                 }
101         }
102         if (!sflag)
103                 printf("\n");
104 }
105
106 int
107 main(int argc, char *argv[])
108 {
109         char    mixer[PATH_MAX] = "/dev/mixer";
110         char    lstr[5], rstr[5];
111         char    *name, *eptr;
112         int     devmask = 0, recmask = 0, recsrc = 0, orecsrc;
113         int     dusage = 0, drecsrc = 0, sflag = 0, Sflag = 0;
114         int     l, r, lrel, rrel;
115         int     ch, i, bar, baz, dev, m, n, t;
116
117         if ((name = strdup(basename(argv[0]))) == NULL)
118                 err(1, "strdup()");
119         if (strncmp(name, "mixer", 5) == 0 && name[5] != '\0') {
120                 n = strtol(name + 5, &eptr, 10) - 1;
121                 if (n > 0 && *eptr == '\0')
122                         snprintf(mixer, PATH_MAX - 1, "/dev/mixer%d", n);
123         }
124         free(name);
125         name = mixer;
126
127         n = 1;
128         for (;;) {
129                 if (n >= argc || *argv[n] != '-')
130                         break;
131                 if (strlen(argv[n]) != 2) {
132                         if (strcmp(argv[n] + 1, "rec") != 0)
133                                 dusage = 1;
134                         break;
135                 }
136                 ch = *(argv[n] + 1);
137                 if (ch == 'f' && n < argc - 1) {
138                         name = argv[n + 1];
139                         n += 2;
140                 } else if (ch == 's') {
141                         sflag = 1;
142                         n++;
143                 } else if (ch == 'S') {
144                         Sflag = 1;
145                         n++;
146                 } else {
147                         dusage = 1;
148                         break;
149                 }
150         }
151         if (sflag && Sflag)
152                 dusage = 1;
153
154         argc -= n - 1;
155         argv += n - 1;
156
157         if ((baz = open(name, O_RDWR)) < 0)
158                 err(1, "%s", name);
159         if (ioctl(baz, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
160                 err(1, "SOUND_MIXER_READ_DEVMASK");
161         if (ioctl(baz, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
162                 err(1, "SOUND_MIXER_READ_RECMASK");
163         if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
164                 err(1, "SOUND_MIXER_READ_RECSRC");
165         orecsrc = recsrc;
166
167         if (argc == 1 && dusage == 0) {
168                 for (i = 0, n = 0; i < SOUND_MIXER_NRDEVICES; i++) {
169                         if (!((1 << i) & devmask))
170                                 continue;
171                         if (ioctl(baz, MIXER_READ(i),&bar) == -1) {
172                                 warn("MIXER_READ");
173                                 continue;
174                         }
175                         if (Sflag || sflag) {
176                                 printf("%s%s%c%d:%d", n ? " " : "",
177                                     names[i], Sflag ? ':' : ' ',
178                                     bar & 0x7f, (bar >> 8) & 0x7f);
179                                 n++;
180                         } else
181                                 printf("Mixer %-8s is currently set to "
182                                     "%3d:%d\n", names[i], bar & 0x7f,
183                                     (bar >> 8) & 0x7f);
184                 }
185                 if (n && recmask)
186                         printf(" ");
187                 print_recsrc(recsrc, recmask, Sflag || sflag);
188                 return (0);
189         }
190
191         argc--;
192         argv++;
193
194         n = 0;
195         while (argc > 0 && dusage == 0) {
196                 if (strcmp("recsrc", *argv) == 0) {
197                         drecsrc = 1;
198                         argc--;
199                         argv++;
200                         continue;
201                 } else if (strcmp("rec", *argv + 1) == 0) {
202                         if (**argv != '+' && **argv != '-' &&
203                             **argv != '=' && **argv != '^') {
204                                 warnx("unknown modifier: %c", **argv);
205                                 dusage = 1;
206                                 break;
207                         }
208                         if (argc <= 1) {
209                                 warnx("no recording device specified");
210                                 dusage = 1;
211                                 break;
212                         }
213                         if ((dev = res_name(argv[1], recmask)) == -1) {
214                                 warnx("unknown recording device: %s", argv[1]);
215                                 dusage = 1;
216                                 break;
217                         }
218                         switch (**argv) {
219                         case '+':
220                                 recsrc |= (1 << dev);
221                                 break;
222                         case '-':
223                                 recsrc &= ~(1 << dev);
224                                 break;
225                         case '=':
226                                 recsrc = (1 << dev);
227                                 break;
228                         case '^':
229                                 recsrc ^= (1 << dev);
230                                 break;
231                         }
232                         drecsrc = 1;
233                         argc -= 2;
234                         argv += 2;
235                         continue;
236                 }
237
238                 if ((t = sscanf(*argv, "%d:%d", &l, &r)) > 0)
239                         dev = 0;
240                 else if ((dev = res_name(*argv, devmask)) == -1) {
241                         warnx("unknown device: %s", *argv);
242                         dusage = 1;
243                         break;
244                 }
245
246                 lrel = rrel = 0;
247                 if (argc > 1) {
248                         m = sscanf(argv[1], "%7[^:]:%7s", lstr, rstr);
249                         if (m > 0) {
250                                 if (*lstr == '+' || *lstr == '-')
251                                         lrel = rrel = 1;
252                                 l = strtol(lstr, NULL, 10);
253                         }
254                         if (m > 1) {
255                                 if (*rstr == '+' || *rstr == '-')
256                                         rrel = 1;
257                                 r = strtol(rstr, NULL, 10);
258                         }
259                 }
260
261                 switch (argc > 1 ? m : t) {
262                 case 0:
263                         if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
264                                 warn("MIXER_READ");
265                                 argc--;
266                                 argv++;
267                                 continue;
268                         }
269                         if (Sflag || sflag) {
270                                 printf("%s%s%c%d:%d", n ? " " : "",
271                                     names[dev], Sflag ? ':' : ' ',
272                                     bar & 0x7f, (bar >> 8) & 0x7f);
273                                 n++;
274                         } else
275                                 printf("Mixer %-8s is currently set to "
276                                     "%3d:%d\n", names[dev], bar & 0x7f,
277                                     (bar >> 8) & 0x7f);
278
279                         argc--;
280                         argv++;
281                         break;
282                 case 1:
283                         r = l;
284                         /* FALLTHROUGH */
285                 case 2:
286                         if (ioctl(baz, MIXER_READ(dev), &bar) == -1) {
287                                 warn("MIXER_READ");
288                                 argc--;
289                                 argv++;
290                                 continue;
291                         }
292
293                         if (lrel)
294                                 l = (bar & 0x7f) + l;
295                         if (rrel)
296                                 r = ((bar >> 8) & 0x7f) + r;
297
298                         if (l < 0)
299                                 l = 0;
300                         else if (l > 100)
301                                 l = 100;
302                         if (r < 0)
303                                 r = 0;
304                         else if (r > 100)
305                                 r = 100;
306
307                         if (!Sflag)
308                                 printf("Setting the mixer %s from %d:%d to "
309                                     "%d:%d.\n", names[dev], bar & 0x7f,
310                                     (bar >> 8) & 0x7f, l, r);
311
312                         l |= r << 8;
313                         if (ioctl(baz, MIXER_WRITE(dev), &l) == -1)
314                                 warn("WRITE_MIXER");
315
316                         argc -= 2;
317                         argv += 2;
318                         break;
319                 }
320         }
321
322         if (dusage) {
323                 close(baz);
324                 usage(devmask, recmask);
325                 /* NOTREACHED */
326         }
327
328         if (orecsrc != recsrc) {
329                 if (ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)
330                         err(1, "SOUND_MIXER_WRITE_RECSRC");
331                 if (ioctl(baz, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)
332                         err(1, "SOUND_MIXER_READ_RECSRC");
333         }
334
335         if (drecsrc)
336                 print_recsrc(recsrc, recmask, Sflag || sflag);
337
338         close(baz);
339
340         return (0);
341 }