1 1.13 joerg /* $NetBSD: radioctl.c,v 1.13 2011/09/06 18:27:08 joerg Exp $ */ 2 1.1 augustss /* $OpenBSD: radioctl.c,v 1.5 2001/12/18 18:42:19 mickey Exp $ */ 3 1.1 augustss /* $RuOBSD: radioctl.c,v 1.4 2001/10/20 18:09:10 pva Exp $ */ 4 1.1 augustss 5 1.1 augustss /* 6 1.1 augustss * Copyright (c) 2001 Vladimir Popov <jumbo (at) narod.ru> 7 1.1 augustss * All rights reserved. 8 1.1 augustss * 9 1.1 augustss * Redistribution and use in source and binary forms, with or without 10 1.1 augustss * modification, are permitted provided that the following conditions 11 1.1 augustss * are met: 12 1.1 augustss * 1. Redistributions of source code must retain the above copyright 13 1.1 augustss * notice, this list of conditions and the following disclaimer. 14 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 augustss * notice, this list of conditions and the following disclaimer in the 16 1.1 augustss * documentation and/or other materials provided with the distribution. 17 1.1 augustss * 18 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 augustss * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 augustss * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 augustss * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 1.1 augustss * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 1.1 augustss * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 1.1 augustss * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 1.1 augustss * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 1.1 augustss * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 1.1 augustss * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 augustss */ 29 1.5 agc #include <sys/cdefs.h> 30 1.5 agc 31 1.5 agc #ifndef lint 32 1.13 joerg __RCSID("$NetBSD: radioctl.c,v 1.13 2011/09/06 18:27:08 joerg Exp $"); 33 1.5 agc #endif 34 1.1 augustss 35 1.1 augustss #include <sys/ioctl.h> 36 1.1 augustss #include <sys/radioio.h> 37 1.1 augustss 38 1.1 augustss #include <err.h> 39 1.1 augustss #include <fcntl.h> 40 1.1 augustss #include <stdio.h> 41 1.1 augustss #include <stdlib.h> 42 1.1 augustss #include <string.h> 43 1.1 augustss #include <unistd.h> 44 1.1 augustss 45 1.1 augustss #define RADIO_ENV "RADIODEVICE" 46 1.1 augustss #define RADIODEVICE "/dev/radio" 47 1.1 augustss 48 1.13 joerg static const char *varname[] = { 49 1.1 augustss "search", 50 1.1 augustss #define OPTION_SEARCH 0x00 51 1.1 augustss "volume", 52 1.1 augustss #define OPTION_VOLUME 0x01 53 1.1 augustss "frequency", 54 1.1 augustss #define OPTION_FREQUENCY 0x02 55 1.1 augustss "mute", 56 1.1 augustss #define OPTION_MUTE 0x03 57 1.1 augustss "reference", 58 1.1 augustss #define OPTION_REFERENCE 0x04 59 1.1 augustss "mono", 60 1.1 augustss #define OPTION_MONO 0x05 61 1.1 augustss "stereo", 62 1.1 augustss #define OPTION_STEREO 0x06 63 1.1 augustss "sensitivity" 64 1.1 augustss #define OPTION_SENSITIVITY 0x07 65 1.1 augustss }; 66 1.1 augustss 67 1.1 augustss #define OPTION_NONE ~0u 68 1.1 augustss #define VALUE_NONE ~0u 69 1.1 augustss 70 1.1 augustss struct opt_t { 71 1.1 augustss char *string; 72 1.1 augustss int option; 73 1.1 augustss int sign; 74 1.1 augustss #define SIGN_NONE 0 75 1.1 augustss #define SIGN_PLUS 1 76 1.1 augustss #define SIGN_MINUS -1 77 1.1 augustss u_int32_t value; 78 1.1 augustss }; 79 1.1 augustss 80 1.13 joerg static const char *onchar = "on"; 81 1.1 augustss #define ONCHAR_LEN 2 82 1.13 joerg static const char *offchar = "off"; 83 1.1 augustss #define OFFCHAR_LEN 3 84 1.1 augustss 85 1.1 augustss static struct radio_info ri; 86 1.1 augustss 87 1.1 augustss static int parse_opt(char *, struct opt_t *); 88 1.1 augustss 89 1.1 augustss static void print_vars(int); 90 1.1 augustss static void do_ioctls(int, struct opt_t *, int); 91 1.1 augustss 92 1.1 augustss static void print_value(int); 93 1.1 augustss static void change_value(const struct opt_t); 94 1.7 mrg static void update_value(int, u_int *, u_int); 95 1.1 augustss 96 1.1 augustss static void warn_unsupported(int); 97 1.13 joerg __dead static void usage(void); 98 1.1 augustss 99 1.1 augustss static void show_verbose(const char *, int); 100 1.8 lukem static void show_int_val(u_long, const char *, const char *, int); 101 1.8 lukem static void show_float_val(float, const char *, const char *, int); 102 1.1 augustss static void show_char_val(const char *, const char *, int); 103 1.1 augustss static int str_to_opt(const char *); 104 1.1 augustss static u_long str_to_long(char *, int); 105 1.1 augustss 106 1.1 augustss /* 107 1.1 augustss * Control behavior of a FM tuner - set frequency, volume etc 108 1.1 augustss */ 109 1.1 augustss int 110 1.1 augustss main(int argc, char **argv) 111 1.1 augustss { 112 1.1 augustss struct opt_t opt; 113 1.8 lukem const char *radiodev = NULL; 114 1.1 augustss int rd = -1; 115 1.2 briggs int optchar; 116 1.1 augustss char *param = NULL; 117 1.1 augustss int show_vars = 0; 118 1.1 augustss int set_param = 0; 119 1.1 augustss int silent = 0; 120 1.1 augustss 121 1.1 augustss if (argc < 2) { 122 1.1 augustss usage(); 123 1.1 augustss exit(1); 124 1.1 augustss } 125 1.1 augustss 126 1.1 augustss radiodev = getenv(RADIO_ENV); 127 1.1 augustss if (radiodev == NULL) 128 1.1 augustss radiodev = RADIODEVICE; 129 1.1 augustss 130 1.1 augustss while ((optchar = getopt(argc, argv, "af:nw:")) != -1) { 131 1.1 augustss switch (optchar) { 132 1.1 augustss case 'a': 133 1.1 augustss show_vars = 1; 134 1.1 augustss break; 135 1.1 augustss case 'f': 136 1.1 augustss radiodev = optarg; 137 1.1 augustss break; 138 1.1 augustss case 'n': 139 1.1 augustss silent = 1; 140 1.1 augustss break; 141 1.1 augustss case 'w': 142 1.1 augustss set_param = 1; 143 1.1 augustss param = optarg; 144 1.1 augustss break; 145 1.1 augustss default: 146 1.1 augustss usage(); 147 1.1 augustss /* NOTREACHED */ 148 1.1 augustss } 149 1.1 augustss } 150 1.4 augustss argc -= optind; 151 1.4 augustss argv += optind; 152 1.1 augustss 153 1.1 augustss rd = open(radiodev, O_RDONLY); 154 1.1 augustss if (rd < 0) 155 1.1 augustss err(1, "%s open error", radiodev); 156 1.1 augustss 157 1.1 augustss if (ioctl(rd, RIOCGINFO, &ri) < 0) 158 1.1 augustss err(1, "RIOCGINFO"); 159 1.1 augustss 160 1.1 augustss if (argc > 1) 161 1.1 augustss if (parse_opt(*(argv + 1), &opt)) { 162 1.1 augustss show_verbose(varname[opt.option], silent); 163 1.1 augustss print_value(opt.option); 164 1.1 augustss free(opt.string); 165 1.1 augustss putchar('\n'); 166 1.1 augustss } 167 1.1 augustss 168 1.1 augustss if (set_param) 169 1.1 augustss if (parse_opt(param, &opt)) 170 1.1 augustss do_ioctls(rd, &opt, silent); 171 1.1 augustss 172 1.1 augustss if (show_vars) 173 1.1 augustss print_vars(silent); 174 1.1 augustss 175 1.1 augustss if (close(rd) < 0) 176 1.1 augustss warn("%s close error", radiodev); 177 1.1 augustss 178 1.1 augustss return 0; 179 1.1 augustss } 180 1.1 augustss 181 1.1 augustss static void 182 1.1 augustss usage(void) 183 1.1 augustss { 184 1.3 briggs const char *progname = getprogname(); 185 1.3 briggs 186 1.6 jmmv fprintf(stderr, "usage:\t%s %s\n\t%s %s\n\t%s %s\n\t%s %s\n", 187 1.3 briggs progname, "[-n] variable ...", 188 1.3 briggs progname, "[-n] -w name=value ...", 189 1.3 briggs progname, "[-n] -a", 190 1.3 briggs progname, "[-n] -f file"); 191 1.3 briggs exit(1); 192 1.1 augustss } 193 1.1 augustss 194 1.1 augustss static void 195 1.1 augustss show_verbose(const char *nick, int silent) 196 1.1 augustss { 197 1.1 augustss if (!silent) 198 1.1 augustss printf("%s=", nick); 199 1.1 augustss } 200 1.1 augustss 201 1.1 augustss static void 202 1.1 augustss warn_unsupported(int optval) 203 1.1 augustss { 204 1.1 augustss warnx("driver does not support `%s'", varname[optval]); 205 1.1 augustss } 206 1.1 augustss 207 1.1 augustss static void 208 1.1 augustss do_ioctls(int fd, struct opt_t *o, int silent) 209 1.1 augustss { 210 1.1 augustss int oval; 211 1.1 augustss 212 1.1 augustss if (fd < 0 || o == NULL) 213 1.1 augustss return; 214 1.1 augustss 215 1.1 augustss if (o->option == OPTION_SEARCH && !(ri.caps & RADIO_CAPS_HW_SEARCH)) { 216 1.1 augustss warn_unsupported(o->option); 217 1.1 augustss return; 218 1.1 augustss } 219 1.1 augustss 220 1.1 augustss oval = o->option == OPTION_SEARCH ? OPTION_FREQUENCY : o->option; 221 1.1 augustss if (!silent) 222 1.1 augustss printf("%s: ", varname[oval]); 223 1.1 augustss 224 1.1 augustss print_value(o->option); 225 1.1 augustss printf(" -> "); 226 1.1 augustss 227 1.1 augustss if (o->option == OPTION_SEARCH) { 228 1.1 augustss 229 1.1 augustss if (ioctl(fd, RIOCSSRCH, &o->value) < 0) { 230 1.1 augustss warn("RIOCSSRCH"); 231 1.1 augustss return; 232 1.1 augustss } 233 1.1 augustss 234 1.1 augustss } else { 235 1.1 augustss 236 1.1 augustss change_value(*o); 237 1.1 augustss if (ioctl(fd, RIOCSINFO, &ri) < 0) { 238 1.1 augustss warn("RIOCSINFO"); 239 1.1 augustss return; 240 1.1 augustss } 241 1.1 augustss 242 1.1 augustss } 243 1.1 augustss 244 1.1 augustss if (ioctl(fd, RIOCGINFO, &ri) < 0) { 245 1.1 augustss warn("RIOCGINFO"); 246 1.1 augustss return; 247 1.1 augustss } 248 1.1 augustss 249 1.1 augustss print_value(o->option); 250 1.1 augustss putchar('\n'); 251 1.1 augustss } 252 1.1 augustss 253 1.1 augustss static void 254 1.1 augustss change_value(const struct opt_t o) 255 1.1 augustss { 256 1.1 augustss int unsupported = 0; 257 1.1 augustss 258 1.1 augustss if (o.value == VALUE_NONE) 259 1.1 augustss return; 260 1.1 augustss 261 1.1 augustss switch (o.option) { 262 1.1 augustss case OPTION_VOLUME: 263 1.7 mrg update_value(o.sign, (u_int *)&ri.volume, o.value); 264 1.1 augustss break; 265 1.1 augustss case OPTION_FREQUENCY: 266 1.7 mrg update_value(o.sign, (u_int *)&ri.freq, o.value); 267 1.1 augustss break; 268 1.1 augustss case OPTION_REFERENCE: 269 1.1 augustss if (ri.caps & RADIO_CAPS_REFERENCE_FREQ) 270 1.7 mrg update_value(o.sign, (u_int *)&ri.rfreq, o.value); 271 1.1 augustss else 272 1.1 augustss unsupported++; 273 1.1 augustss break; 274 1.1 augustss case OPTION_MONO: 275 1.1 augustss /* FALLTHROUGH */ 276 1.1 augustss case OPTION_STEREO: 277 1.1 augustss if (ri.caps & RADIO_CAPS_SET_MONO) 278 1.1 augustss ri.stereo = o.option == OPTION_MONO ? !o.value : o.value; 279 1.1 augustss else 280 1.1 augustss unsupported++; 281 1.1 augustss break; 282 1.1 augustss case OPTION_SENSITIVITY: 283 1.1 augustss if (ri.caps & RADIO_CAPS_LOCK_SENSITIVITY) 284 1.7 mrg update_value(o.sign, (u_int *)&ri.lock, o.value); 285 1.1 augustss else 286 1.1 augustss unsupported++; 287 1.1 augustss break; 288 1.1 augustss case OPTION_MUTE: 289 1.1 augustss ri.mute = o.value; 290 1.1 augustss break; 291 1.1 augustss } 292 1.1 augustss 293 1.1 augustss if ( unsupported ) 294 1.1 augustss warn_unsupported(o.option); 295 1.1 augustss } 296 1.1 augustss 297 1.1 augustss /* 298 1.1 augustss * Convert string to integer representation of a parameter 299 1.1 augustss */ 300 1.1 augustss static int 301 1.1 augustss str_to_opt(const char *topt) 302 1.1 augustss { 303 1.1 augustss int res, toptlen, varlen, len, varsize; 304 1.1 augustss 305 1.1 augustss if (topt == NULL || *topt == '\0') 306 1.1 augustss return OPTION_NONE; 307 1.1 augustss 308 1.1 augustss varsize = sizeof(varname) / sizeof(varname[0]); 309 1.1 augustss toptlen = strlen(topt); 310 1.1 augustss 311 1.1 augustss for (res = 0; res < varsize; res++) { 312 1.1 augustss varlen = strlen(varname[res]); 313 1.1 augustss len = toptlen > varlen ? toptlen : varlen; 314 1.1 augustss if (strncmp(topt, varname[res], len) == 0) 315 1.1 augustss return res; 316 1.1 augustss } 317 1.1 augustss 318 1.4 augustss warnx("name not found `%s'", topt); 319 1.1 augustss return OPTION_NONE; 320 1.1 augustss } 321 1.1 augustss 322 1.1 augustss static void 323 1.7 mrg update_value(int sign, u_int *value, u_int update) 324 1.1 augustss { 325 1.1 augustss switch (sign) { 326 1.1 augustss case SIGN_NONE: 327 1.1 augustss *value = update; 328 1.1 augustss break; 329 1.1 augustss case SIGN_PLUS: 330 1.1 augustss *value += update; 331 1.1 augustss break; 332 1.1 augustss case SIGN_MINUS: 333 1.1 augustss *value -= update; 334 1.1 augustss break; 335 1.1 augustss } 336 1.1 augustss } 337 1.1 augustss 338 1.1 augustss /* 339 1.1 augustss * Convert string to unsigned integer 340 1.1 augustss */ 341 1.1 augustss static u_long 342 1.1 augustss str_to_long(char *str, int optval) 343 1.1 augustss { 344 1.1 augustss u_long val; 345 1.1 augustss 346 1.1 augustss if (str == NULL || *str == '\0') 347 1.1 augustss return VALUE_NONE; 348 1.1 augustss 349 1.1 augustss if (optval == OPTION_FREQUENCY) 350 1.1 augustss val = (u_long)1000 * atof(str); 351 1.1 augustss else 352 1.12 plunky val = (u_long)strtol(str, NULL, 10); 353 1.1 augustss 354 1.1 augustss return val; 355 1.1 augustss } 356 1.1 augustss 357 1.1 augustss /* 358 1.1 augustss * parse string s into struct opt_t 359 1.1 augustss * return true on success, false on failure 360 1.1 augustss */ 361 1.1 augustss static int 362 1.1 augustss parse_opt(char *s, struct opt_t *o) { 363 1.11 christos static const char badvalue[] = "bad value `%s'"; 364 1.1 augustss char *topt = NULL; 365 1.1 augustss int slen, optlen; 366 1.1 augustss 367 1.1 augustss if (s == NULL || *s == '\0' || o == NULL) 368 1.1 augustss return 0; 369 1.1 augustss 370 1.1 augustss o->string = NULL; 371 1.1 augustss o->option = OPTION_NONE; 372 1.1 augustss o->value = VALUE_NONE; 373 1.1 augustss o->sign = SIGN_NONE; 374 1.1 augustss 375 1.1 augustss slen = strlen(s); 376 1.1 augustss optlen = strcspn(s, "="); 377 1.1 augustss 378 1.1 augustss /* Set only o->optval, the rest is missing */ 379 1.1 augustss if (slen == optlen) { 380 1.1 augustss o->option = str_to_opt(s); 381 1.8 lukem return o->option == (int)OPTION_NONE ? 0 : 1; 382 1.1 augustss } 383 1.1 augustss 384 1.1 augustss if (optlen > slen - 2) { 385 1.1 augustss warnx(badvalue, s); 386 1.1 augustss return 0; 387 1.1 augustss } 388 1.1 augustss 389 1.1 augustss slen -= ++optlen; 390 1.1 augustss 391 1.1 augustss if ((topt = (char *)malloc(optlen)) == NULL) { 392 1.1 augustss warn("memory allocation error"); 393 1.1 augustss return 0; 394 1.1 augustss } 395 1.1 augustss strlcpy(topt, s, optlen); 396 1.1 augustss 397 1.8 lukem if ((o->option = str_to_opt(topt)) == (int)OPTION_NONE) { 398 1.1 augustss free(topt); 399 1.1 augustss return 0; 400 1.1 augustss } 401 1.1 augustss o->string = topt; 402 1.1 augustss 403 1.1 augustss topt = &s[optlen]; 404 1.1 augustss switch (*topt) { 405 1.1 augustss case '+': 406 1.1 augustss case '-': 407 1.1 augustss o->sign = (*topt == '+') ? SIGN_PLUS : SIGN_MINUS; 408 1.1 augustss o->value = str_to_long(&topt[1], o->option); 409 1.1 augustss break; 410 1.1 augustss case 'o': 411 1.1 augustss if (strncmp(topt, offchar, 412 1.1 augustss slen > OFFCHAR_LEN ? slen : OFFCHAR_LEN) == 0) 413 1.1 augustss o->value = 0; 414 1.1 augustss else if (strncmp(topt, onchar, 415 1.1 augustss slen > ONCHAR_LEN ? slen : ONCHAR_LEN) == 0) 416 1.1 augustss o->value = 1; 417 1.1 augustss break; 418 1.1 augustss case 'u': 419 1.1 augustss if (strncmp(topt, "up", slen > 2 ? slen : 2) == 0) 420 1.1 augustss o->value = 1; 421 1.1 augustss break; 422 1.1 augustss case 'd': 423 1.1 augustss if (strncmp(topt, "down", slen > 4 ? slen : 4) == 0) 424 1.1 augustss o->value = 0; 425 1.1 augustss break; 426 1.1 augustss default: 427 1.1 augustss if (*topt > 47 && *topt < 58) 428 1.1 augustss o->value = str_to_long(topt, o->option); 429 1.1 augustss break; 430 1.1 augustss } 431 1.1 augustss 432 1.1 augustss if (o->value == VALUE_NONE) { 433 1.1 augustss warnx(badvalue, topt); 434 1.1 augustss return 0; 435 1.1 augustss } 436 1.1 augustss 437 1.1 augustss return 1; 438 1.1 augustss } 439 1.1 augustss 440 1.1 augustss /* 441 1.1 augustss * Print current value of the parameter. 442 1.1 augustss */ 443 1.1 augustss static void 444 1.1 augustss print_value(int optval) 445 1.1 augustss { 446 1.8 lukem if (optval == (int)OPTION_NONE) 447 1.1 augustss return; 448 1.1 augustss 449 1.1 augustss switch (optval) { 450 1.1 augustss case OPTION_SEARCH: 451 1.1 augustss /* FALLTHROUGH */ 452 1.1 augustss case OPTION_FREQUENCY: 453 1.1 augustss printf("%.2fMHz", (float)ri.freq / 1000.); 454 1.1 augustss break; 455 1.1 augustss case OPTION_REFERENCE: 456 1.1 augustss printf("%ukHz", ri.rfreq); 457 1.1 augustss break; 458 1.1 augustss case OPTION_SENSITIVITY: 459 1.1 augustss printf("%umkV", ri.lock); 460 1.1 augustss break; 461 1.1 augustss case OPTION_MUTE: 462 1.9 joerg printf("%s", ri.mute ? onchar : offchar); 463 1.1 augustss break; 464 1.1 augustss case OPTION_MONO: 465 1.9 joerg printf("%s", ri.stereo ? offchar : onchar); 466 1.1 augustss break; 467 1.1 augustss case OPTION_STEREO: 468 1.9 joerg printf("%s", ri.stereo ? onchar : offchar); 469 1.1 augustss break; 470 1.1 augustss case OPTION_VOLUME: 471 1.1 augustss default: 472 1.1 augustss printf("%u", ri.volume); 473 1.1 augustss break; 474 1.1 augustss } 475 1.1 augustss } 476 1.1 augustss 477 1.1 augustss static void 478 1.8 lukem show_int_val(u_long val, const char *nick, const char *append, int silent) 479 1.1 augustss { 480 1.1 augustss show_verbose(nick, silent); 481 1.1 augustss printf("%lu%s\n", val, append); 482 1.1 augustss } 483 1.1 augustss 484 1.1 augustss static void 485 1.8 lukem show_float_val(float val, const char *nick, const char *append, int silent) 486 1.1 augustss { 487 1.1 augustss show_verbose(nick, silent); 488 1.1 augustss printf("%.2f%s\n", val, append); 489 1.1 augustss } 490 1.1 augustss 491 1.1 augustss static void 492 1.1 augustss show_char_val(const char *val, const char *nick, int silent) 493 1.1 augustss { 494 1.1 augustss show_verbose(nick, silent); 495 1.1 augustss printf("%s\n", val); 496 1.1 augustss } 497 1.1 augustss 498 1.1 augustss /* 499 1.1 augustss * Print all available parameters 500 1.1 augustss */ 501 1.1 augustss static void 502 1.1 augustss print_vars(int silent) 503 1.1 augustss { 504 1.4 augustss const char *delim; 505 1.4 augustss 506 1.1 augustss show_int_val(ri.volume, varname[OPTION_VOLUME], "", silent); 507 1.1 augustss show_float_val((float)ri.freq / 1000., varname[OPTION_FREQUENCY], 508 1.1 augustss "MHz", silent); 509 1.1 augustss show_char_val(ri.mute ? onchar : offchar, varname[OPTION_MUTE], silent); 510 1.1 augustss 511 1.1 augustss if (ri.caps & RADIO_CAPS_REFERENCE_FREQ) 512 1.1 augustss show_int_val(ri.rfreq, varname[OPTION_REFERENCE], "kHz", silent); 513 1.1 augustss if (ri.caps & RADIO_CAPS_LOCK_SENSITIVITY) 514 1.1 augustss show_int_val(ri.lock, varname[OPTION_SENSITIVITY], "mkV", silent); 515 1.1 augustss 516 1.1 augustss if (ri.caps & RADIO_CAPS_DETECT_SIGNAL) { 517 1.1 augustss show_verbose("signal", silent); 518 1.1 augustss printf("%s\n", ri.info & RADIO_INFO_SIGNAL ? onchar : offchar); 519 1.1 augustss } 520 1.1 augustss if (ri.caps & RADIO_CAPS_DETECT_STEREO) { 521 1.1 augustss show_verbose(varname[OPTION_STEREO], silent); 522 1.1 augustss printf("%s\n", ri.info & RADIO_INFO_STEREO ? onchar : offchar); 523 1.1 augustss } 524 1.1 augustss 525 1.1 augustss if (!silent) 526 1.4 augustss printf("card capabilities:"); 527 1.4 augustss delim = ""; 528 1.4 augustss if (ri.caps & RADIO_CAPS_DETECT_STEREO) 529 1.4 augustss printf("%s stereo detect", delim), delim=","; 530 1.4 augustss if (ri.caps & RADIO_CAPS_DETECT_SIGNAL) 531 1.4 augustss printf("%s signal detect", delim), delim=","; 532 1.1 augustss if (ri.caps & RADIO_CAPS_SET_MONO) 533 1.4 augustss printf("%s manageable mono/stereo", delim), delim=","; 534 1.1 augustss if (ri.caps & RADIO_CAPS_HW_SEARCH) 535 1.4 augustss printf("%s hardware search", delim), delim=","; 536 1.1 augustss if (ri.caps & RADIO_CAPS_HW_AFC) 537 1.4 augustss printf("%s hardware AFC", delim), delim=","; 538 1.4 augustss printf("\n"); 539 1.1 augustss } 540