File: | src/usr.bin/radioctl/radioctl.c |
Warning: | line 211, column 6 Potential leak of memory pointed to by 'opt.string' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: radioctl.c,v 1.20 2019/06/28 13:35:03 deraadt Exp $ */ | |||
2 | /* $RuOBSD: radioctl.c,v 1.4 2001/10/20 18:09:10 pva Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 2001 Vladimir Popov <jumbo@narod.ru> | |||
6 | * All rights reserved. | |||
7 | * | |||
8 | * Redistribution and use in source and binary forms, with or without | |||
9 | * modification, are permitted provided that the following conditions | |||
10 | * are met: | |||
11 | * 1. Redistributions of source code must retain the above copyright | |||
12 | * notice, this list of conditions and the following disclaimer. | |||
13 | * 2. Redistributions in binary form must reproduce the above copyright | |||
14 | * notice, this list of conditions and the following disclaimer in the | |||
15 | * documentation and/or other materials provided with the distribution. | |||
16 | * | |||
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |||
23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||
24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |||
25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |||
26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
27 | */ | |||
28 | ||||
29 | #include <sys/ioctl.h> | |||
30 | #include <sys/radioio.h> | |||
31 | ||||
32 | #include <dev/ic/bt8xx.h> | |||
33 | ||||
34 | #include <err.h> | |||
35 | #include <fcntl.h> | |||
36 | #include <stdio.h> | |||
37 | #include <stdlib.h> | |||
38 | #include <string.h> | |||
39 | #include <unistd.h> | |||
40 | #include <ctype.h> | |||
41 | ||||
42 | #define RADIO_ENV"RADIODEVICE" "RADIODEVICE" | |||
43 | #define RADIODEVICE"/dev/radio" "/dev/radio" | |||
44 | ||||
45 | const char *varname[] = { | |||
46 | "search", | |||
47 | #define OPTION_SEARCH0x00 0x00 | |||
48 | "volume", | |||
49 | #define OPTION_VOLUME0x01 0x01 | |||
50 | "frequency", | |||
51 | #define OPTION_FREQUENCY0x02 0x02 | |||
52 | "mute", | |||
53 | #define OPTION_MUTE0x03 0x03 | |||
54 | "reference", | |||
55 | #define OPTION_REFERENCE0x04 0x04 | |||
56 | "mono", | |||
57 | #define OPTION_MONO0x05 0x05 | |||
58 | "stereo", | |||
59 | #define OPTION_STEREO0x06 0x06 | |||
60 | "sensitivity", | |||
61 | #define OPTION_SENSITIVITY0x07 0x07 | |||
62 | "channel", | |||
63 | #define OPTION_CHANNEL0x08 0x08 | |||
64 | "chnlset" | |||
65 | #define OPTION_CHNLSET0x09 0x09 | |||
66 | }; | |||
67 | ||||
68 | #define OPTION_NONE~0u ~0u | |||
69 | #define VALUE_NONE~0u ~0u | |||
70 | ||||
71 | struct opt_t { | |||
72 | char *string; | |||
73 | int option; | |||
74 | int sign; | |||
75 | #define SIGN_NONE0 0 | |||
76 | #define SIGN_PLUS1 1 | |||
77 | #define SIGN_MINUS-1 -1 | |||
78 | u_int32_t value; | |||
79 | }; | |||
80 | ||||
81 | struct chansets { | |||
82 | int value; | |||
83 | char *name; | |||
84 | } chansets[] = { | |||
85 | { CHNLSET_NABCST1, "nabcst", }, | |||
86 | { CHNLSET_CABLEIRC2, "cableirc", }, | |||
87 | { CHNLSET_CABLEHRC3, "cablehrc", }, | |||
88 | { CHNLSET_WEUROPE4, "weurope", }, | |||
89 | { CHNLSET_JPNBCST5, "jpnbcst", }, | |||
90 | { CHNLSET_JPNCABLE6, "jpncable", }, | |||
91 | { CHNLSET_XUSSR7, "xussr", }, | |||
92 | { CHNLSET_AUSTRALIA8, "australia", }, | |||
93 | { CHNLSET_FRANCE9, "france", }, | |||
94 | { 0, NULL((void *)0) } | |||
95 | }; | |||
96 | ||||
97 | extern char *__progname; | |||
98 | const char *onchar = "on"; | |||
99 | #define ONCHAR_LEN2 2 | |||
100 | const char *offchar = "off"; | |||
101 | #define OFFCHAR_LEN3 3 | |||
102 | ||||
103 | struct radio_info ri; | |||
104 | unsigned int i = 0; | |||
105 | ||||
106 | int parse_opt(char *, struct opt_t *); | |||
107 | ||||
108 | void print_vars(int, int); | |||
109 | void do_ioctls(int, struct opt_t *, int); | |||
110 | ||||
111 | void print_value(int, int); | |||
112 | void change_value(const struct opt_t); | |||
113 | void update_value(int, int *, int); | |||
114 | ||||
115 | void warn_unsupported(int); | |||
116 | void usage(void); | |||
117 | ||||
118 | void show_verbose(const char *, int); | |||
119 | void show_int_val(int, const char *, char *, int); | |||
120 | void show_float_val(float, const char *, char *, int); | |||
121 | void show_char_val(const char *, const char *, int); | |||
122 | int str_to_opt(const char *); | |||
123 | u_int str_to_int(char *, int); | |||
124 | ||||
125 | /* | |||
126 | * Control behavior of a FM tuner - set frequency, volume etc | |||
127 | */ | |||
128 | int | |||
129 | main(int argc, char **argv) | |||
130 | { | |||
131 | struct opt_t opt; | |||
132 | char **avp; | |||
133 | ||||
134 | char *radiodev = NULL((void *)0); | |||
135 | int rd = -1; | |||
136 | int optchar; | |||
137 | int show_vars = 0; | |||
138 | int show_choices = 0; | |||
139 | int silent = 0; | |||
140 | int mode = O_RDONLY0x0000; | |||
141 | ||||
142 | radiodev = getenv(RADIO_ENV"RADIODEVICE"); | |||
143 | if (radiodev == NULL((void *)0)) | |||
| ||||
144 | radiodev = RADIODEVICE"/dev/radio"; | |||
145 | ||||
146 | while ((optchar = getopt(argc, argv, "af:nvw")) != -1) { | |||
147 | switch (optchar) { | |||
148 | case 'a': | |||
149 | show_vars = 1; | |||
150 | break; | |||
151 | case 'f': | |||
152 | radiodev = optarg; | |||
153 | break; | |||
154 | case 'n': | |||
155 | silent = 1; | |||
156 | break; | |||
157 | case 'v': | |||
158 | show_choices = 1; | |||
159 | break; | |||
160 | case 'w': | |||
161 | /* backwards compatibility */ | |||
162 | break; | |||
163 | default: | |||
164 | usage(); | |||
165 | /* NOTREACHED */ | |||
166 | } | |||
167 | } | |||
168 | ||||
169 | argc -= optind; | |||
170 | argv += optind; | |||
171 | ||||
172 | if (argc == 0) | |||
173 | show_vars = 1; | |||
174 | ||||
175 | /* | |||
176 | * Scan the options for `name=value` so the | |||
177 | * device can be opened in the proper mode. | |||
178 | */ | |||
179 | for (avp = argv; *avp != NULL((void *)0); avp++) | |||
180 | if (strchr(*avp, '=') != NULL((void *)0)) { | |||
181 | mode = O_RDWR0x0002; | |||
182 | break; | |||
183 | } | |||
184 | ||||
185 | rd = open(radiodev, mode); | |||
186 | if (rd == -1) | |||
187 | err(1, "%s open error", radiodev); | |||
188 | ||||
189 | if (ioctl(rd, RIOCGINFO((unsigned long)0x40000000 | ((sizeof(struct radio_info) & 0x1fff) << 16) | ((('R')) << 8) | ((21))), &ri) == -1) | |||
190 | err(1, "RIOCGINFO"); | |||
191 | ||||
192 | if (!argc
| |||
193 | print_vars(silent, show_choices); | |||
194 | else if (argc > 0 && !show_vars
| |||
195 | if (mode
| |||
196 | for (; argc--; argv++) | |||
197 | if (parse_opt(*argv, &opt)) | |||
198 | do_ioctls(rd, &opt, silent); | |||
199 | } else { | |||
200 | for (; argc--; argv++) | |||
201 | if (parse_opt(*argv, &opt)) { | |||
202 | show_verbose(varname[opt.option], | |||
203 | silent); | |||
204 | print_value(opt.option, show_choices); | |||
205 | free(opt.string); | |||
206 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
207 | } | |||
208 | } | |||
209 | } | |||
210 | ||||
211 | if (close(rd) == -1) | |||
| ||||
212 | warn("%s close error", radiodev); | |||
213 | ||||
214 | return 0; | |||
215 | } | |||
216 | ||||
217 | void | |||
218 | usage(void) | |||
219 | { | |||
220 | fprintf(stderr(&__sF[2]), | |||
221 | "usage: %s [-anv] [-f file]\n" | |||
222 | " %s [-nv] [-f file] name\n" | |||
223 | " %s [-n] [-f file] name=value\n", | |||
224 | __progname, __progname, __progname); | |||
225 | exit(1); | |||
226 | } | |||
227 | ||||
228 | void | |||
229 | show_verbose(const char *nick, int silent) | |||
230 | { | |||
231 | if (!silent) | |||
232 | printf("%s=", nick); | |||
233 | } | |||
234 | ||||
235 | void | |||
236 | warn_unsupported(int optval) | |||
237 | { | |||
238 | warnx("driver does not support `%s'", varname[optval]); | |||
239 | } | |||
240 | ||||
241 | void | |||
242 | do_ioctls(int fd, struct opt_t *o, int silent) | |||
243 | { | |||
244 | int oval; | |||
245 | ||||
246 | if (fd < 0 || o == NULL((void *)0)) | |||
247 | return; | |||
248 | ||||
249 | if (o->option == OPTION_SEARCH0x00 && !(ri.caps & RADIO_CAPS_HW_SEARCH(1<<3))) { | |||
250 | warn_unsupported(o->option); | |||
251 | return; | |||
252 | } | |||
253 | ||||
254 | oval = o->option == OPTION_SEARCH0x00 ? OPTION_FREQUENCY0x02 : o->option; | |||
255 | if (!silent) | |||
256 | printf("%s: ", varname[oval]); | |||
257 | ||||
258 | print_value(o->option, 0); | |||
259 | printf(" -> "); | |||
260 | ||||
261 | if (o->option == OPTION_SEARCH0x00) { | |||
262 | ||||
263 | if (ioctl(fd, RIOCSSRCH((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('R')) << 8) | ((23))), &o->value) == -1) { | |||
264 | warn("RIOCSSRCH"); | |||
265 | return; | |||
266 | } | |||
267 | ||||
268 | } else { | |||
269 | ||||
270 | change_value(*o); | |||
271 | if (ioctl(fd, RIOCSINFO(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct radio_info) & 0x1fff) << 16) | ((('R')) << 8) | ((22))), &ri) == -1) { | |||
272 | warn("RIOCSINFO"); | |||
273 | return; | |||
274 | } | |||
275 | ||||
276 | } | |||
277 | ||||
278 | if (ioctl(fd, RIOCGINFO((unsigned long)0x40000000 | ((sizeof(struct radio_info) & 0x1fff) << 16) | ((('R')) << 8) | ((21))), &ri) == -1) { | |||
279 | warn("RIOCGINFO"); | |||
280 | return; | |||
281 | } | |||
282 | ||||
283 | print_value(o->option, 0); | |||
284 | putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n', (&__sF[1]))); | |||
285 | } | |||
286 | ||||
287 | void | |||
288 | change_value(const struct opt_t o) | |||
289 | { | |||
290 | int unsupported = 0; | |||
291 | ||||
292 | if (o.value == VALUE_NONE~0u) | |||
293 | return; | |||
294 | ||||
295 | switch (o.option) { | |||
296 | case OPTION_VOLUME0x01: | |||
297 | update_value(o.sign, &ri.volume, o.value); | |||
298 | break; | |||
299 | case OPTION_FREQUENCY0x02: | |||
300 | ri.tuner_mode = RADIO_TUNER_MODE_RADIO(1<<0); | |||
301 | update_value(o.sign, &ri.freq, o.value); | |||
302 | break; | |||
303 | case OPTION_REFERENCE0x04: | |||
304 | if (ri.caps & RADIO_CAPS_REFERENCE_FREQ(1<<5)) | |||
305 | update_value(o.sign, &ri.rfreq, o.value); | |||
306 | else | |||
307 | unsupported++; | |||
308 | break; | |||
309 | case OPTION_MONO0x05: | |||
310 | /* FALLTHROUGH */ | |||
311 | case OPTION_STEREO0x06: | |||
312 | if (ri.caps & RADIO_CAPS_SET_MONO(1<<2)) | |||
313 | ri.stereo = o.option == OPTION_MONO0x05 ? !o.value : o.value; | |||
314 | else | |||
315 | unsupported++; | |||
316 | break; | |||
317 | case OPTION_SENSITIVITY0x07: | |||
318 | if (ri.caps & RADIO_CAPS_LOCK_SENSITIVITY(1<<6)) | |||
319 | update_value(o.sign, &ri.lock, o.value); | |||
320 | else | |||
321 | unsupported++; | |||
322 | break; | |||
323 | case OPTION_MUTE0x03: | |||
324 | ri.mute = o.value; | |||
325 | break; | |||
326 | case OPTION_CHANNEL0x08: | |||
327 | ri.tuner_mode = RADIO_TUNER_MODE_TV(1<<1); | |||
328 | update_value(o.sign, &ri.chan, o.value); | |||
329 | break; | |||
330 | case OPTION_CHNLSET0x09: | |||
331 | ri.chnlset = o.value; | |||
332 | break; | |||
333 | } | |||
334 | ||||
335 | if (unsupported) | |||
336 | warn_unsupported(o.option); | |||
337 | } | |||
338 | ||||
339 | /* | |||
340 | * Convert string to integer representation of a parameter | |||
341 | */ | |||
342 | int | |||
343 | str_to_opt(const char *topt) | |||
344 | { | |||
345 | int res, toptlen, varlen, len, varsize; | |||
346 | ||||
347 | if (topt == NULL((void *)0) || *topt == '\0') | |||
348 | return OPTION_NONE~0u; | |||
349 | ||||
350 | varsize = sizeof(varname) / sizeof(varname[0]); | |||
351 | toptlen = strlen(topt); | |||
352 | ||||
353 | for (res = 0; res < varsize; res++) { | |||
354 | varlen = strlen(varname[res]); | |||
355 | len = toptlen > varlen ? toptlen : varlen; | |||
356 | if (strncmp(topt, varname[res], len) == 0) | |||
357 | return res; | |||
358 | } | |||
359 | ||||
360 | warnx("bad name `%s'", topt); | |||
361 | return OPTION_NONE~0u; | |||
362 | } | |||
363 | ||||
364 | void | |||
365 | update_value(int sign, int *value, int update) | |||
366 | { | |||
367 | switch (sign) { | |||
368 | case SIGN_NONE0: | |||
369 | *value = update; | |||
370 | break; | |||
371 | case SIGN_PLUS1: | |||
372 | *value += update; | |||
373 | break; | |||
374 | case SIGN_MINUS-1: | |||
375 | *value -= update; | |||
376 | break; | |||
377 | } | |||
378 | } | |||
379 | ||||
380 | /* | |||
381 | * Convert string to unsigned integer | |||
382 | */ | |||
383 | u_int | |||
384 | str_to_int(char *str, int optval) | |||
385 | { | |||
386 | int val; | |||
387 | ||||
388 | if (str == NULL((void *)0) || *str == '\0') | |||
389 | return VALUE_NONE~0u; | |||
390 | ||||
391 | if (optval == OPTION_FREQUENCY0x02) | |||
392 | val = (int)(1000 * atof(str)); | |||
393 | else | |||
394 | val = (int)strtol(str, (char **)NULL((void *)0), 10); | |||
395 | ||||
396 | return val; | |||
397 | } | |||
398 | ||||
399 | /* | |||
400 | * parse string s into struct opt_t | |||
401 | * return true on success, false on failure | |||
402 | */ | |||
403 | int | |||
404 | parse_opt(char *s, struct opt_t *o) { | |||
405 | static const char badvalue[] = "bad value `%s'"; | |||
406 | char *topt = NULL((void *)0); | |||
407 | int slen, optlen; | |||
408 | ||||
409 | if (s == NULL((void *)0) || *s == '\0' || o
| |||
410 | return 0; | |||
411 | ||||
412 | o->string = NULL((void *)0); | |||
413 | o->option = OPTION_NONE~0u; | |||
414 | o->value = VALUE_NONE~0u; | |||
415 | o->sign = SIGN_NONE0; | |||
416 | ||||
417 | slen = strlen(s); | |||
418 | optlen = strcspn(s, "="); | |||
419 | ||||
420 | /* Set only o->optval, the rest is missing */ | |||
421 | if (slen == optlen) { | |||
422 | o->option = str_to_opt(s); | |||
423 | return o->option == OPTION_NONE~0u ? 0 : 1; | |||
424 | } | |||
425 | ||||
426 | if (optlen > slen - 2) { | |||
427 | warnx(badvalue, s); | |||
428 | return 0; | |||
429 | } | |||
430 | ||||
431 | slen -= ++optlen; | |||
432 | ||||
433 | if ((topt = malloc(optlen)) == NULL((void *)0)) { | |||
434 | warn("memory allocation error"); | |||
435 | return 0; | |||
436 | } | |||
437 | strlcpy(topt, s, optlen); | |||
438 | ||||
439 | if ((o->option = str_to_opt(topt)) == OPTION_NONE~0u) { | |||
440 | free(topt); | |||
441 | return 0; | |||
442 | } | |||
443 | o->string = topt; | |||
444 | ||||
445 | topt = &s[optlen]; | |||
446 | ||||
447 | if (strcmp(o->string, "chnlset") == 0) { | |||
448 | for (i = 0; chansets[i].name; i++) | |||
449 | if (strncmp(chansets[i].name, topt, | |||
450 | strlen(chansets[i].name)) == 0) | |||
451 | break; | |||
452 | if (chansets[i].name != NULL((void *)0)) { | |||
453 | o->value = chansets[i].value; | |||
454 | return 1; | |||
455 | } else { | |||
456 | warnx(badvalue, topt); | |||
457 | return 0; | |||
458 | } | |||
459 | } | |||
460 | ||||
461 | switch (*topt) { | |||
462 | case '+': | |||
463 | case '-': | |||
464 | o->sign = (*topt == '+') ? SIGN_PLUS1 : SIGN_MINUS-1; | |||
465 | o->value = str_to_int(&topt[1], o->option); | |||
466 | break; | |||
467 | case 'o': | |||
468 | if (strncmp(topt, offchar, | |||
469 | slen > OFFCHAR_LEN3 ? slen : OFFCHAR_LEN3) == 0) | |||
470 | o->value = 0; | |||
471 | else if (strncmp(topt, onchar, | |||
472 | slen > ONCHAR_LEN2 ? slen : ONCHAR_LEN2) == 0) | |||
473 | o->value = 1; | |||
474 | break; | |||
475 | case 'u': | |||
476 | if (strncmp(topt, "up", slen > 2 ? slen : 2) == 0) | |||
477 | o->value = 1; | |||
478 | break; | |||
479 | case 'd': | |||
480 | if (strncmp(topt, "down", slen > 4 ? slen : 4) == 0) | |||
481 | o->value = 0; | |||
482 | break; | |||
483 | default: | |||
484 | if (isdigit((unsigned char)*topt)) | |||
485 | o->value = str_to_int(topt, o->option); | |||
486 | break; | |||
487 | } | |||
488 | ||||
489 | if (o->value == VALUE_NONE~0u) { | |||
490 | warnx(badvalue, topt); | |||
491 | return 0; | |||
492 | } | |||
493 | ||||
494 | return 1; | |||
495 | } | |||
496 | ||||
497 | /* | |||
498 | * Print current value of the parameter. | |||
499 | */ | |||
500 | void | |||
501 | print_value(int optval, int show_choices) | |||
502 | { | |||
503 | if (optval == OPTION_NONE~0u) | |||
504 | return; | |||
505 | ||||
506 | switch (optval) { | |||
507 | case OPTION_SEARCH0x00: | |||
508 | /* FALLTHROUGH */ | |||
509 | case OPTION_FREQUENCY0x02: | |||
510 | printf("%.2fMHz", (float)ri.freq / 1000.); | |||
511 | break; | |||
512 | case OPTION_REFERENCE0x04: | |||
513 | printf("%ukHz", ri.rfreq); | |||
514 | break; | |||
515 | case OPTION_SENSITIVITY0x07: | |||
516 | printf("%umkV", ri.lock); | |||
517 | break; | |||
518 | case OPTION_MUTE0x03: | |||
519 | printf("%s", ri.mute ? onchar : offchar); | |||
520 | break; | |||
521 | case OPTION_MONO0x05: | |||
522 | printf("%s", ri.stereo ? offchar : onchar); | |||
523 | break; | |||
524 | case OPTION_STEREO0x06: | |||
525 | printf("%s", ri.stereo ? onchar : offchar); | |||
526 | break; | |||
527 | case OPTION_CHANNEL0x08: | |||
528 | printf("%u", ri.chan); | |||
529 | break; | |||
530 | case OPTION_CHNLSET0x09: | |||
531 | for (i = 0; chansets[i].name; i++) { | |||
532 | if (chansets[i].value == ri.chnlset) | |||
533 | printf("%s", chansets[i].name); | |||
534 | } | |||
535 | if (show_choices) { | |||
536 | printf("\n\t["); | |||
537 | for (i = 0; chansets[i].name; i++) | |||
538 | printf("%s ", chansets[i].name); | |||
539 | printf("]"); | |||
540 | } | |||
541 | break; | |||
542 | case OPTION_VOLUME0x01: | |||
543 | default: | |||
544 | printf("%u", ri.volume); | |||
545 | break; | |||
546 | } | |||
547 | } | |||
548 | ||||
549 | void | |||
550 | show_int_val(int val, const char *nick, char *append, int silent) | |||
551 | { | |||
552 | show_verbose(nick, silent); | |||
553 | printf("%u%s\n", val, append); | |||
554 | } | |||
555 | ||||
556 | void | |||
557 | show_float_val(float val, const char *nick, char *append, int silent) | |||
558 | { | |||
559 | show_verbose(nick, silent); | |||
560 | printf("%.2f%s\n", val, append); | |||
561 | } | |||
562 | ||||
563 | void | |||
564 | show_char_val(const char *val, const char *nick, int silent) | |||
565 | { | |||
566 | show_verbose(nick, silent); | |||
567 | printf("%s\n", val); | |||
568 | } | |||
569 | ||||
570 | /* | |||
571 | * Print all available parameters | |||
572 | */ | |||
573 | void | |||
574 | print_vars(int silent, int show_choices) | |||
575 | { | |||
576 | show_int_val(ri.volume, varname[OPTION_VOLUME0x01], "", silent); | |||
577 | show_int_val(ri.chan, varname[OPTION_CHANNEL0x08], "", silent); | |||
578 | for (i = 0; chansets[i].name; i++) { | |||
579 | if (chansets[i].value == ri.chnlset) | |||
580 | show_char_val(chansets[i].name, varname[OPTION_CHNLSET0x09], silent); | |||
581 | } | |||
582 | if (show_choices) { | |||
583 | printf("\t[ "); | |||
584 | for (i = 0; chansets[i].name; i++) | |||
585 | printf("%s ", chansets[i].name); | |||
586 | printf("]\n"); | |||
587 | } | |||
588 | show_float_val((float)ri.freq / 1000., varname[OPTION_FREQUENCY0x02], | |||
589 | "MHz", silent); | |||
590 | show_char_val(ri.mute ? onchar : offchar, varname[OPTION_MUTE0x03], silent); | |||
591 | ||||
592 | if (ri.caps & RADIO_CAPS_REFERENCE_FREQ(1<<5)) | |||
593 | show_int_val(ri.rfreq, varname[OPTION_REFERENCE0x04], "kHz", silent); | |||
594 | if (ri.caps & RADIO_CAPS_LOCK_SENSITIVITY(1<<6)) | |||
595 | show_int_val(ri.lock, varname[OPTION_SENSITIVITY0x07], "mkV", silent); | |||
596 | ||||
597 | if (ri.caps & RADIO_CAPS_DETECT_SIGNAL(1<<1)) { | |||
598 | show_verbose("signal", silent); | |||
599 | printf("%s\n", ri.info & RADIO_INFO_SIGNAL(1<<1) ? onchar : offchar); | |||
600 | } | |||
601 | if (ri.caps & RADIO_CAPS_DETECT_STEREO(1<<0)) { | |||
602 | show_verbose(varname[OPTION_STEREO0x06], silent); | |||
603 | printf("%s\n", ri.info & RADIO_INFO_STEREO(1<<0) ? onchar : offchar); | |||
604 | } | |||
605 | ||||
606 | if (!silent) { | |||
607 | printf("mode: %s\n", | |||
608 | ri.tuner_mode == RADIO_TUNER_MODE_TV(1<<1) ? "TV" : "radio"); | |||
609 | ||||
610 | puts("card capabilities:"); | |||
611 | } | |||
612 | ||||
613 | if (ri.caps & RADIO_CAPS_SET_MONO(1<<2)) | |||
614 | puts("\tmanageable mono/stereo"); | |||
615 | if (ri.caps & RADIO_CAPS_HW_SEARCH(1<<3)) | |||
616 | puts("\thardware search"); | |||
617 | if (ri.caps & RADIO_CAPS_HW_AFC(1<<4)) | |||
618 | puts("\thardware AFC"); | |||
619 | } |