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