1 /* $NetBSD: radioctl.c,v 1.7 2006/05/11 01:24:14 mrg Exp $ */
2 /* $OpenBSD: radioctl.c,v 1.5 2001/12/18 18:42:19 mickey Exp $ */
3 /* $RuOBSD: radioctl.c,v 1.4 2001/10/20 18:09:10 pva Exp $ */
6 * Copyright (c) 2001 Vladimir Popov <jumbo@narod.ru>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: radioctl.c,v 1.7 2006/05/11 01:24:14 mrg Exp $");
35 #include <sys/ioctl.h>
36 #include <sys/radioio.h>
45 #define RADIO_ENV "RADIODEVICE"
46 #define RADIODEVICE "/dev/radio"
48 const char *varname
[] = {
50 #define OPTION_SEARCH 0x00
52 #define OPTION_VOLUME 0x01
54 #define OPTION_FREQUENCY 0x02
56 #define OPTION_MUTE 0x03
58 #define OPTION_REFERENCE 0x04
60 #define OPTION_MONO 0x05
62 #define OPTION_STEREO 0x06
64 #define OPTION_SENSITIVITY 0x07
67 #define OPTION_NONE ~0u
68 #define VALUE_NONE ~0u
80 const char *onchar
= "on";
82 const char *offchar
= "off";
85 static struct radio_info ri
;
87 static int parse_opt(char *, struct opt_t
*);
89 static void print_vars(int);
90 static void do_ioctls(int, struct opt_t
*, int);
92 static void print_value(int);
93 static void change_value(const struct opt_t
);
94 static void update_value(int, u_int
*, u_int
);
96 static void warn_unsupported(int);
97 static void usage(void);
99 static void show_verbose(const char *, int);
100 static void show_int_val(u_long
, const char *, const char *, int);
101 static void show_float_val(float, const char *, const char *, int);
102 static void show_char_val(const char *, const char *, int);
103 static int str_to_opt(const char *);
104 static u_long
str_to_long(char *, int);
107 * Control behavior of a FM tuner - set frequency, volume etc
110 main(int argc
, char **argv
)
113 const char *radiodev
= NULL
;
126 radiodev
= getenv(RADIO_ENV
);
127 if (radiodev
== NULL
)
128 radiodev
= RADIODEVICE
;
130 while ((optchar
= getopt(argc
, argv
, "af:nw:")) != -1) {
153 rd
= open(radiodev
, O_RDONLY
);
155 err(1, "%s open error", radiodev
);
157 if (ioctl(rd
, RIOCGINFO
, &ri
) < 0)
161 if (parse_opt(*(argv
+ 1), &opt
)) {
162 show_verbose(varname
[opt
.option
], silent
);
163 print_value(opt
.option
);
169 if (parse_opt(param
, &opt
))
170 do_ioctls(rd
, &opt
, silent
);
176 warn("%s close error", radiodev
);
184 const char *progname
= getprogname();
186 fprintf(stderr
, "usage:\t%s %s\n\t%s %s\n\t%s %s\n\t%s %s\n",
187 progname
, "[-n] variable ...",
188 progname
, "[-n] -w name=value ...",
190 progname
, "[-n] -f file");
195 show_verbose(const char *nick
, int silent
)
202 warn_unsupported(int optval
)
204 warnx("driver does not support `%s'", varname
[optval
]);
208 do_ioctls(int fd
, struct opt_t
*o
, int silent
)
212 if (fd
< 0 || o
== NULL
)
215 if (o
->option
== OPTION_SEARCH
&& !(ri
.caps
& RADIO_CAPS_HW_SEARCH
)) {
216 warn_unsupported(o
->option
);
220 oval
= o
->option
== OPTION_SEARCH
? OPTION_FREQUENCY
: o
->option
;
222 printf("%s: ", varname
[oval
]);
224 print_value(o
->option
);
227 if (o
->option
== OPTION_SEARCH
) {
229 if (ioctl(fd
, RIOCSSRCH
, &o
->value
) < 0) {
237 if (ioctl(fd
, RIOCSINFO
, &ri
) < 0) {
244 if (ioctl(fd
, RIOCGINFO
, &ri
) < 0) {
249 print_value(o
->option
);
254 change_value(const struct opt_t o
)
258 if (o
.value
== VALUE_NONE
)
263 update_value(o
.sign
, (u_int
*)&ri
.volume
, o
.value
);
265 case OPTION_FREQUENCY
:
266 update_value(o
.sign
, (u_int
*)&ri
.freq
, o
.value
);
268 case OPTION_REFERENCE
:
269 if (ri
.caps
& RADIO_CAPS_REFERENCE_FREQ
)
270 update_value(o
.sign
, (u_int
*)&ri
.rfreq
, o
.value
);
277 if (ri
.caps
& RADIO_CAPS_SET_MONO
)
278 ri
.stereo
= o
.option
== OPTION_MONO
? !o
.value
: o
.value
;
282 case OPTION_SENSITIVITY
:
283 if (ri
.caps
& RADIO_CAPS_LOCK_SENSITIVITY
)
284 update_value(o
.sign
, (u_int
*)&ri
.lock
, o
.value
);
294 warn_unsupported(o
.option
);
298 * Convert string to integer representation of a parameter
301 str_to_opt(const char *topt
)
303 int res
, toptlen
, varlen
, len
, varsize
;
305 if (topt
== NULL
|| *topt
== '\0')
308 varsize
= sizeof(varname
) / sizeof(varname
[0]);
309 toptlen
= strlen(topt
);
311 for (res
= 0; res
< varsize
; res
++) {
312 varlen
= strlen(varname
[res
]);
313 len
= toptlen
> varlen
? toptlen
: varlen
;
314 if (strncmp(topt
, varname
[res
], len
) == 0)
318 warnx("name not found `%s'", topt
);
323 update_value(int sign
, u_int
*value
, u_int update
)
339 * Convert string to unsigned integer
342 str_to_long(char *str
, int optval
)
346 if (str
== NULL
|| *str
== '\0')
349 if (optval
== OPTION_FREQUENCY
)
350 val
= (u_long
)1000 * atof(str
);
352 val
= (u_long
)strtol(str
, (char **)NULL
, 10);
358 * parse string s into struct opt_t
359 * return true on success, false on failure
362 parse_opt(char *s
, struct opt_t
*o
) {
363 const char *badvalue
= "bad value `%s'";
367 if (s
== NULL
|| *s
== '\0' || o
== NULL
)
371 o
->option
= OPTION_NONE
;
372 o
->value
= VALUE_NONE
;
376 optlen
= strcspn(s
, "=");
378 /* Set only o->optval, the rest is missing */
379 if (slen
== optlen
) {
380 o
->option
= str_to_opt(s
);
381 return o
->option
== (int)OPTION_NONE
? 0 : 1;
384 if (optlen
> slen
- 2) {
391 if ((topt
= (char *)malloc(optlen
)) == NULL
) {
392 warn("memory allocation error");
395 strlcpy(topt
, s
, optlen
);
397 if ((o
->option
= str_to_opt(topt
)) == (int)OPTION_NONE
) {
407 o
->sign
= (*topt
== '+') ? SIGN_PLUS
: SIGN_MINUS
;
408 o
->value
= str_to_long(&topt
[1], o
->option
);
411 if (strncmp(topt
, offchar
,
412 slen
> OFFCHAR_LEN
? slen
: OFFCHAR_LEN
) == 0)
414 else if (strncmp(topt
, onchar
,
415 slen
> ONCHAR_LEN
? slen
: ONCHAR_LEN
) == 0)
419 if (strncmp(topt
, "up", slen
> 2 ? slen
: 2) == 0)
423 if (strncmp(topt
, "down", slen
> 4 ? slen
: 4) == 0)
427 if (*topt
> 47 && *topt
< 58)
428 o
->value
= str_to_long(topt
, o
->option
);
432 if (o
->value
== VALUE_NONE
) {
433 warnx(badvalue
, topt
);
441 * Print current value of the parameter.
444 print_value(int optval
)
446 if (optval
== (int)OPTION_NONE
)
452 case OPTION_FREQUENCY
:
453 printf("%.2fMHz", (float)ri
.freq
/ 1000.);
455 case OPTION_REFERENCE
:
456 printf("%ukHz", ri
.rfreq
);
458 case OPTION_SENSITIVITY
:
459 printf("%umkV", ri
.lock
);
462 printf(ri
.mute
? onchar
: offchar
);
465 printf(ri
.stereo
? offchar
: onchar
);
468 printf(ri
.stereo
? onchar
: offchar
);
472 printf("%u", ri
.volume
);
478 show_int_val(u_long val
, const char *nick
, const char *append
, int silent
)
480 show_verbose(nick
, silent
);
481 printf("%lu%s\n", val
, append
);
485 show_float_val(float val
, const char *nick
, const char *append
, int silent
)
487 show_verbose(nick
, silent
);
488 printf("%.2f%s\n", val
, append
);
492 show_char_val(const char *val
, const char *nick
, int silent
)
494 show_verbose(nick
, silent
);
499 * Print all available parameters
502 print_vars(int silent
)
506 show_int_val(ri
.volume
, varname
[OPTION_VOLUME
], "", silent
);
507 show_float_val((float)ri
.freq
/ 1000., varname
[OPTION_FREQUENCY
],
509 show_char_val(ri
.mute
? onchar
: offchar
, varname
[OPTION_MUTE
], silent
);
511 if (ri
.caps
& RADIO_CAPS_REFERENCE_FREQ
)
512 show_int_val(ri
.rfreq
, varname
[OPTION_REFERENCE
], "kHz", silent
);
513 if (ri
.caps
& RADIO_CAPS_LOCK_SENSITIVITY
)
514 show_int_val(ri
.lock
, varname
[OPTION_SENSITIVITY
], "mkV", silent
);
516 if (ri
.caps
& RADIO_CAPS_DETECT_SIGNAL
) {
517 show_verbose("signal", silent
);
518 printf("%s\n", ri
.info
& RADIO_INFO_SIGNAL
? onchar
: offchar
);
520 if (ri
.caps
& RADIO_CAPS_DETECT_STEREO
) {
521 show_verbose(varname
[OPTION_STEREO
], silent
);
522 printf("%s\n", ri
.info
& RADIO_INFO_STEREO
? onchar
: offchar
);
526 printf("card capabilities:");
528 if (ri
.caps
& RADIO_CAPS_DETECT_STEREO
)
529 printf("%s stereo detect", delim
), delim
=",";
530 if (ri
.caps
& RADIO_CAPS_DETECT_SIGNAL
)
531 printf("%s signal detect", delim
), delim
=",";
532 if (ri
.caps
& RADIO_CAPS_SET_MONO
)
533 printf("%s manageable mono/stereo", delim
), delim
=",";
534 if (ri
.caps
& RADIO_CAPS_HW_SEARCH
)
535 printf("%s hardware search", delim
), delim
=",";
536 if (ri
.caps
& RADIO_CAPS_HW_AFC
)
537 printf("%s hardware AFC", delim
), delim
=",";