1 /* $NetBSD: ctl.c,v 1.37 2008/04/28 20:24:12 martin Exp $ */
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (augustss@NetBSD.org).
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: ctl.c,v 1.37 2008/04/28 20:24:12 martin Exp $");
38 #include <sys/types.h>
40 #include <sys/ioctl.h>
41 #include <sys/audioio.h>
54 struct field
*findfield (const char *name
);
55 void prfield (struct field
*p
, const char *sep
);
56 void rdfield (struct field
*p
, char *q
);
57 void getinfo (int fd
);
58 void audioctl_write (int, int, char *[]);
60 int main (int argc
, char **argv
);
68 int properties
, fullduplex
, rerror
;
78 #define ULONG 5 /* XXX obsolete now */
89 { "name", &adev
.name
, STRING
, READONLY
},
90 { "version", &adev
.version
, STRING
, READONLY
},
91 { "config", &adev
.config
, STRING
, READONLY
},
92 { "encodings", encbuf
, STRING
, READONLY
},
93 { "properties", &properties
, PROPS
, READONLY
},
94 { "full_duplex", &fullduplex
, UINT
, 0 },
95 { "fullduplex", &fullduplex
, UINT
, 0 },
96 { "blocksize", &info
.blocksize
, UINT
, 0 },
97 { "hiwat", &info
.hiwat
, UINT
, 0 },
98 { "lowat", &info
.lowat
, UINT
, 0 },
99 { "monitor_gain", &info
.monitor_gain
, UINT
, 0 },
100 { "mode", &info
.mode
, P_R
, READONLY
},
101 { "play", &info
.play
, FORMAT
, ALIAS
},
102 { "play.rate", &info
.play
.sample_rate
, UINT
, 0 },
103 { "play.sample_rate", &info
.play
.sample_rate
, UINT
, ALIAS
},
104 { "play.channels", &info
.play
.channels
, UINT
, 0 },
105 { "play.precision", &info
.play
.precision
, UINT
, 0 },
106 { "play.encoding", &info
.play
.encoding
, ENC
, 0 },
107 { "play.gain", &info
.play
.gain
, UINT
, 0 },
108 { "play.balance", &info
.play
.balance
, UCHAR
, 0 },
109 { "play.port", &info
.play
.port
, XINT
, 0 },
110 { "play.avail_ports", &info
.play
.avail_ports
, XINT
, 0 },
111 { "play.seek", &info
.play
.seek
, UINT
, READONLY
},
112 { "play.samples", &info
.play
.samples
, UINT
, READONLY
},
113 { "play.eof", &info
.play
.eof
, UINT
, READONLY
},
114 { "play.pause", &info
.play
.pause
, UCHAR
, 0 },
115 { "play.error", &info
.play
.error
, UCHAR
, READONLY
},
116 { "play.waiting", &info
.play
.waiting
, UCHAR
, READONLY
},
117 { "play.open", &info
.play
.open
, UCHAR
, READONLY
},
118 { "play.active", &info
.play
.active
, UCHAR
, READONLY
},
119 { "play.buffer_size", &info
.play
.buffer_size
, UINT
, 0 },
120 { "record", &info
.record
, FORMAT
, ALIAS
},
121 { "record.rate", &info
.record
.sample_rate
,UINT
, 0 },
122 { "record.sample_rate", &info
.record
.sample_rate
,UINT
, ALIAS
},
123 { "record.channels", &info
.record
.channels
, UINT
, 0 },
124 { "record.precision", &info
.record
.precision
, UINT
, 0 },
125 { "record.encoding", &info
.record
.encoding
, ENC
, 0 },
126 { "record.gain", &info
.record
.gain
, UINT
, 0 },
127 { "record.balance", &info
.record
.balance
, UCHAR
, 0 },
128 { "record.port", &info
.record
.port
, XINT
, 0 },
129 { "record.avail_ports", &info
.record
.avail_ports
,XINT
, 0 },
130 { "record.seek", &info
.record
.seek
, UINT
, READONLY
},
131 { "record.samples", &info
.record
.samples
, UINT
, READONLY
},
132 { "record.eof", &info
.record
.eof
, UINT
, READONLY
},
133 { "record.pause", &info
.record
.pause
, UCHAR
, 0 },
134 { "record.error", &info
.record
.error
, UCHAR
, READONLY
},
135 { "record.waiting", &info
.record
.waiting
, UCHAR
, READONLY
},
136 { "record.open", &info
.record
.open
, UCHAR
, READONLY
},
137 { "record.active", &info
.record
.active
, UCHAR
, READONLY
},
138 { "record.buffer_size", &info
.record
.buffer_size
,UINT
, 0 },
139 { "record.errors", &rerror
, INT
, READONLY
},
147 { "full_duplex", AUDIO_PROP_FULLDUPLEX
},
148 { "mmap", AUDIO_PROP_MMAP
},
149 { "independent", AUDIO_PROP_INDEPENDENT
},
158 for (i
= 0; fields
[i
].name
; i
++)
159 if (strcmp(fields
[i
].name
, name
) == 0)
170 const char *cm
, *encstr
;
174 printf("%s%s", p
->name
, sep
);
177 printf("%s", (char*)p
->valp
);
180 printf("%d", *(int*)p
->valp
);
183 printf("%u", *(u_int
*)p
->valp
);
186 printf("0x%x", *(u_int
*)p
->valp
);
189 printf("%u", *(u_char
*)p
->valp
);
192 printf("%lu", *(u_long
*)p
->valp
);
195 v
= *(u_int
*)p
->valp
;
197 if (v
& AUMODE_PLAY
) {
198 if (v
& AUMODE_PLAY_ALL
)
204 if (v
& AUMODE_RECORD
)
205 printf("%srecord", cm
);
208 v
= *(u_int
*)p
->valp
;
209 encstr
= audio_enc_from_val(v
);
211 printf("%s", encstr
);
216 v
= *(u_int
*)p
->valp
;
217 for (cm
= "", i
= 0; props
[i
].name
; i
++) {
218 if (v
& props
[i
].prop
) {
219 printf("%s%s", cm
, props
[i
].name
);
234 errx(1, "Invalid print format.");
249 if (sscanf(q
, "%u", (unsigned int *)p
->valp
) != 1)
250 errx(1, "Bad number: %s", q
);
253 if (sscanf(q
, "%u", &u
) != 1)
254 errx(1, "Bad number: %s", q
);
256 *(u_char
*)p
->valp
= u
;
259 if (sscanf(q
, "0x%x", (unsigned int *)p
->valp
) != 1 &&
260 sscanf(q
, "%x", (unsigned int *)p
->valp
) != 1)
261 errx(1, "Bad number: %s", q
);
264 enc
= audio_enc_to_val(q
);
266 *(u_int
*)p
->valp
= enc
;
268 errx(1, "Unknown encoding: %s", q
);
284 errx(1, "Bad format");
287 errx(1, "Invalid read format.");
298 if (ioctl(fd
, AUDIO_GETDEV
, &adev
) < 0)
299 err(1, "AUDIO_GETDEV");
300 for (pos
= 0, i
= 0; ; i
++) {
301 audio_encoding_t enc
;
303 if (ioctl(fd
, AUDIO_GETENC
, &enc
) < 0)
305 if (pos
>= (int)sizeof(encbuf
)-1)
309 if (pos
>= (int)sizeof(encbuf
)-1)
311 pos
+= snprintf(encbuf
+pos
, sizeof(encbuf
)-pos
, "%s:%d%s",
312 enc
.name
, enc
.precision
,
313 enc
.flags
& AUDIO_ENCODINGFLAG_EMULATED
? "*" : "");
315 if (ioctl(fd
, AUDIO_GETFD
, &fullduplex
) < 0)
316 err(1, "AUDIO_GETFD");
317 if (ioctl(fd
, AUDIO_GETPROPS
, &properties
) < 0)
318 err(1, "AUDIO_GETPROPS");
319 if (ioctl(fd
, AUDIO_RERROR
, &rerror
) < 0)
320 err(1, "AUDIO_RERROR");
321 if (ioctl(fd
, AUDIO_GETINFO
, &info
) < 0)
322 err(1, "AUDIO_GETINFO");
328 const char *prog
= getprogname();
330 fprintf(stderr
, "Usage: %s [-d file] [-n] name ...\n", prog
);
331 fprintf(stderr
, "Usage: %s [-d file] [-n] -w name=value ...\n", prog
);
332 fprintf(stderr
, "Usage: %s [-d file] [-n] -a\n", prog
);
342 int aflag
= 0, wflag
= 0;
343 const char *deffile
= _PATH_AUDIOCTL
;
345 const char *sep
= "=";
347 file
= getenv("AUDIOCTLDEVICE");
351 while ((ch
= getopt(argc
, argv
, "ad:f:nw")) != -1) {
362 case 'f': /* compatibility */
374 fd
= open(file
, O_WRONLY
);
376 fd
= open(file
, O_RDONLY
);
377 if (fd
< 0 && file
== deffile
) {
378 file
= _PATH_AUDIOCTL0
;
379 fd
= open(file
, O_WRONLY
);
381 fd
= open(file
, O_RDONLY
);
390 if (argc
== 0 && aflag
&& !wflag
) {
391 for (i
= 0; fields
[i
].name
; i
++) {
392 if (!(fields
[i
].flags
& ALIAS
)) {
393 prfield(&fields
[i
], sep
);
397 } else if (argc
> 0 && !aflag
) {
399 audioctl_write(fd
, argc
, argv
);
402 for (i
= 0; fields
[i
].name
; i
++) {
403 if (fields
[i
].flags
& SET
) {
404 printf("%s: -> ", fields
[i
].name
);
405 prfield(&fields
[i
], 0);
413 p
= findfield(*argv
);
415 if (strchr(*argv
, '='))
416 warnx("field %s does not exist (use -w to set a variable)", *argv
);
418 warnx("field %s does not exist", *argv
);
432 audioctl_write(fd
, argc
, argv
)
439 AUDIO_INITINFO(&info
);
443 q
= strchr(*argv
, '=');
446 p
= findfield(*argv
);
448 warnx("field `%s' does not exist", *argv
);
450 if (p
->flags
& READONLY
)
451 warnx("`%s' is read only", *argv
);
454 if (p
->valp
== &fullduplex
)
455 if (ioctl(fd
, AUDIO_SETFD
, &fullduplex
) < 0)
456 err(1, "set failed");
460 warnx("No `=' in %s", *argv
);
463 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0)
464 err(1, "set failed");