Annotation of src/usr.bin/radioctl/radioctl.c, Revision 1.1
1.1 ! gluk 1: /* $RuOBSD: radioctl.c,v 1.1 2001/10/03 05:53:35 gluk Exp $ */
! 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>
! 29: #include <sys/radioio.h>
! 30:
! 31: #include <err.h>
! 32: #include <fcntl.h>
! 33: #include <stdio.h>
! 34: #include <stdlib.h>
! 35: #include <string.h>
! 36: #include <unistd.h>
! 37:
! 38: #define RADIO_ENV "RADIODEVICE"
! 39: #define RADIODEVICE "/dev/radio"
! 40:
! 41: const char *varname[] = {
! 42: "search",
! 43: #define OPTION_SEARCH 0x00
! 44: "volume",
! 45: #define OPTION_VOLUME 0x01
! 46: "frequency",
! 47: #define OPTION_FREQUENCY 0x02
! 48: "mute",
! 49: #define OPTION_MUTE 0x03
! 50: "reference",
! 51: #define OPTION_REFERENCE 0x04
! 52: "mono",
! 53: #define OPTION_MONO 0x05
! 54: "stereo",
! 55: #define OPTION_STEREO 0x06
! 56: "sensitivity"
! 57: #define OPTION_SENSITIVITY 0x07
! 58: };
! 59:
! 60: #define OPTION_NONE ~0u
! 61: #define VALUE_NONE ~0ul
! 62:
! 63: extern char *__progname;
! 64: const char *onchar = "on";
! 65: #define ONCHAR_LEN 2
! 66: const char *offchar = "off";
! 67: #define OFFCHAR_LEN 3
! 68:
! 69: u_long caps;
! 70:
! 71: static void usage(void);
! 72: static void print_vars(int, int);
! 73: static void write_param(int, char *, int);
! 74: static u_int parse_option(const char *);
! 75: static u_long get_value(int, u_int);
! 76: static void set_value(int, u_int, u_long);
! 77: static u_long read_value(char *, u_int);
! 78: static void print_value(int, u_int);
! 79: static void warn_unsupported(u_int);
! 80: static void ext_print(int, u_int, int);
! 81:
! 82: /*
! 83: * Control behavior of a FM tuner - set frequency, volume etc
! 84: */
! 85: int
! 86: main(int argc, char **argv)
! 87: {
! 88: char *radiodev = NULL;
! 89: char optchar;
! 90: char *param = NULL;
! 91: int rd = -1;
! 92: int show_vars = 0;
! 93: int set_param = 0;
! 94: int silent = 0;
! 95:
! 96: if (argc < 2) {
! 97: usage();
! 98: exit(1);
! 99: }
! 100:
! 101: radiodev = getenv(RADIO_ENV);
! 102: if (radiodev == NULL)
! 103: radiodev = RADIODEVICE;
! 104:
! 105: while ((optchar = getopt(argc, argv, "af:nw:")) != -1) {
! 106: switch (optchar) {
! 107: case 'a':
! 108: show_vars = 1;
! 109: optind = 1;
! 110: break;
! 111: case 'f':
! 112: radiodev = optarg;
! 113: optind = 2;
! 114: break;
! 115: case 'n':
! 116: silent = 1;
! 117: optind = 1;
! 118: break;
! 119: case 'w':
! 120: set_param = 1;
! 121: param = optarg;
! 122: optind = 2;
! 123: break;
! 124: default:
! 125: usage();
! 126: /* NOTREACHED */
! 127: }
! 128:
! 129: argc -= optind;
! 130: argv += optind;
! 131: }
! 132:
! 133: rd = open(radiodev, O_RDONLY);
! 134: if (rd < 0)
! 135: err(1, "%s open error", radiodev);
! 136:
! 137: if (ioctl(rd, RIOCGCAPS, &caps) < 0)
! 138: err(1, "RIOCGCAPS");
! 139:
! 140: if (argc > 1)
! 141: ext_print(rd, parse_option(*(argv + 1)), silent);
! 142:
! 143: if (set_param)
! 144: write_param(rd, param, silent);
! 145:
! 146: if (show_vars)
! 147: print_vars(rd, silent);
! 148:
! 149: if (close(rd) < 0)
! 150: warn("%s close error", radiodev);
! 151:
! 152: return 0;
! 153: }
! 154:
! 155: static void
! 156: usage(void)
! 157: {
! 158: printf("Usage: %s [-f file] [-a] [-n] [-w name=value] [name]\n",
! 159: __progname);
! 160: }
! 161:
! 162: /*
! 163: * Print all available parameters
! 164: */
! 165: static void
! 166: print_vars(int fd, int silent)
! 167: {
! 168: u_long var;
! 169:
! 170: ext_print(fd, OPTION_VOLUME, silent);
! 171: ext_print(fd, OPTION_FREQUENCY, silent);
! 172: ext_print(fd, OPTION_MUTE, silent);
! 173:
! 174: if (caps & RADIO_CAPS_REFERENCE_FREQ)
! 175: ext_print(fd, OPTION_REFERENCE, silent);
! 176: if (caps & RADIO_CAPS_LOCK_SENSITIVITY)
! 177: ext_print(fd, OPTION_SENSITIVITY, silent);
! 178:
! 179: if (ioctl(fd, RIOCGINFO, &var) < 0)
! 180: warn("RIOCGINFO");
! 181: if (caps & RADIO_CAPS_DETECT_SIGNAL)
! 182: if (!silent)
! 183: printf("%s=", "signal");
! 184: printf("%s\n", var & RADIO_INFO_SIGNAL ? onchar : offchar);
! 185: if (caps & RADIO_CAPS_DETECT_STEREO) {
! 186: if (!silent)
! 187: printf("%s=", varname[OPTION_STEREO]);
! 188: printf("%s\n", var & RADIO_INFO_STEREO ? onchar : offchar);
! 189: }
! 190:
! 191: if (!silent)
! 192: puts("card capabilities:");
! 193: if (caps & RADIO_CAPS_SET_MONO)
! 194: puts("\tmanageable mono/stereo");
! 195: if (caps & RADIO_CAPS_HW_SEARCH)
! 196: puts("\thardware search");
! 197: if (caps & RADIO_CAPS_HW_AFC)
! 198: puts("\thardware AFC");
! 199: }
! 200:
! 201: /*
! 202: * Set new value of a parameter
! 203: */
! 204: static void
! 205: write_param(int fd, char *param, int silent)
! 206: {
! 207: int paramlen = 0;
! 208: int namelen = 0;
! 209: char *topt = NULL;
! 210: const char *badvalue = "bad value `%s'";
! 211: u_int optval = OPTION_NONE;
! 212: u_long var = VALUE_NONE;
! 213: u_long addvar = VALUE_NONE;
! 214: u_char sign = 0;
! 215:
! 216: if (param == NULL || *param == '\0')
! 217: return;
! 218:
! 219: paramlen = strlen(param);
! 220: namelen = strcspn(param, "=");
! 221: if (namelen > paramlen - 2) {
! 222: warnx(badvalue, param);
! 223: return;
! 224: }
! 225:
! 226: paramlen -= ++namelen;
! 227:
! 228: if ((topt = (char *)malloc(namelen)) == NULL) {
! 229: warn("memory allocation error");
! 230: return;
! 231: }
! 232: strlcpy(topt, param, namelen);
! 233: optval = parse_option(topt);
! 234:
! 235: if (optval == OPTION_NONE) {
! 236: free(topt);
! 237: return;
! 238: }
! 239:
! 240: if (!silent)
! 241: printf("%s: ", topt);
! 242:
! 243: free(topt);
! 244:
! 245: topt = ¶m[namelen];
! 246: switch (*topt) {
! 247: case '+':
! 248: case '-':
! 249: if ((addvar = read_value(topt + 1, optval)) == VALUE_NONE)
! 250: break;
! 251: if ((var = get_value(fd, optval)) == VALUE_NONE)
! 252: break;
! 253: sign++;
! 254: if (*topt == '+')
! 255: var += addvar;
! 256: else
! 257: var -= addvar;
! 258: break;
! 259: case 'o':
! 260: if (strncmp(topt, offchar,
! 261: paramlen > OFFCHAR_LEN ? paramlen : OFFCHAR_LEN) == 0)
! 262: var = 0;
! 263: else
! 264: if (strncmp(topt, onchar,
! 265: paramlen > ONCHAR_LEN ? paramlen : ONCHAR_LEN) == 0)
! 266: var = 1;
! 267: break;
! 268: case 'u':
! 269: if (strncmp(topt, "up", paramlen > 2 ? paramlen : 2) == 0)
! 270: var = 1;
! 271: break;
! 272: case 'd':
! 273: if (strncmp(topt, "down", paramlen > 4 ? paramlen : 4) == 0)
! 274: var = 0;
! 275: break;
! 276: default:
! 277: if (*topt > 47 && *topt < 58)
! 278: var = read_value(topt, optval);
! 279: break;
! 280: }
! 281:
! 282: if (var == VALUE_NONE || (sign && addvar == VALUE_NONE)) {
! 283: warnx(badvalue, topt);
! 284: return;
! 285: }
! 286:
! 287: print_value(fd, optval);
! 288: printf(" -> ");
! 289:
! 290: set_value(fd, optval, var);
! 291:
! 292: print_value(fd, optval);
! 293: putchar('\n');
! 294: }
! 295:
! 296: /*
! 297: * Convert string to integer representation of a parameter
! 298: */
! 299: static u_int
! 300: parse_option(const char *topt)
! 301: {
! 302: u_int res;
! 303: int toptlen, varlen, len, varsize;
! 304:
! 305: if (topt == NULL || *topt == '\0')
! 306: return OPTION_NONE;
! 307:
! 308: varsize = sizeof(varname) / sizeof(varname[0]);
! 309: toptlen = strlen(topt);
! 310:
! 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)
! 315: return res;
! 316: }
! 317:
! 318: warnx("bad name `%s'", topt);
! 319: return OPTION_NONE;
! 320: }
! 321:
! 322: /*
! 323: * Returns current value of parameter optval
! 324: */
! 325: static u_long
! 326: get_value(int fd, u_int optval)
! 327: {
! 328: u_long var = VALUE_NONE;
! 329:
! 330: switch (optval) {
! 331: case OPTION_VOLUME:
! 332: if (ioctl(fd, RIOCGVOLU, &var) < 0)
! 333: warn("RIOCGVOLU");
! 334: break;
! 335: case OPTION_FREQUENCY:
! 336: if (ioctl(fd, RIOCGFREQ, &var) < 0)
! 337: warn("RIOCGFREQ");
! 338: break;
! 339: case OPTION_REFERENCE:
! 340: if (caps & RADIO_CAPS_REFERENCE_FREQ)
! 341: if (ioctl(fd, RIOCGREFF, &var) < 0)
! 342: warn("RIOCGREFF");
! 343: break;
! 344: case OPTION_MONO:
! 345: /* FALLTHROUGH */
! 346: case OPTION_STEREO:
! 347: if (caps & RADIO_CAPS_SET_MONO)
! 348: if (ioctl(fd, RIOCGMONO, &var) < 0)
! 349: warn("RIOCGMONO");
! 350: break;
! 351: case OPTION_SENSITIVITY:
! 352: if (caps & RADIO_CAPS_LOCK_SENSITIVITY)
! 353: if (ioctl(fd, RIOCGLOCK, &var) < 0)
! 354: warn("RIOCGLOCK");
! 355: break;
! 356: case OPTION_MUTE:
! 357: if (ioctl(fd, RIOCGMUTE, &var) < 0)
! 358: warn("RIOCGMUTE");
! 359: break;
! 360: }
! 361:
! 362: if (var == VALUE_NONE)
! 363: warn_unsupported(optval);
! 364:
! 365: return var;
! 366: }
! 367:
! 368: /*
! 369: * Set card parameter optval to value var
! 370: */
! 371: static void
! 372: set_value(int fd, u_int optval, u_long var)
! 373: {
! 374: int unsupported = 0;
! 375:
! 376: if (var == VALUE_NONE)
! 377: return;
! 378:
! 379: switch (optval) {
! 380: case OPTION_VOLUME:
! 381: if (ioctl(fd, RIOCSVOLU, &var) < 0)
! 382: warn("RIOCSVOLU");
! 383: break;
! 384: case OPTION_FREQUENCY:
! 385: if (ioctl(fd, RIOCSFREQ, &var) < 0)
! 386: warn("RIOCSFREQ");
! 387: break;
! 388: case OPTION_REFERENCE:
! 389: if (caps & RADIO_CAPS_REFERENCE_FREQ) {
! 390: if (ioctl(fd, RIOCSREFF, &var) < 0)
! 391: warn("RIOCSREFF");
! 392: } else unsupported++;
! 393: break;
! 394: case OPTION_STEREO:
! 395: var = !var;
! 396: /* FALLTHROUGH */
! 397: case OPTION_MONO:
! 398: if (caps & RADIO_CAPS_SET_MONO) {
! 399: if (ioctl(fd, RIOCSMONO, &var) < 0)
! 400: warn("RIOCSMONO");
! 401: } else unsupported++;
! 402: break;
! 403: case OPTION_SENSITIVITY:
! 404: if (caps & RADIO_CAPS_LOCK_SENSITIVITY) {
! 405: if (ioctl(fd, RIOCSLOCK, &var) < 0)
! 406: warn("RIOCSLOCK");
! 407: } else unsupported++;
! 408: break;
! 409: case OPTION_SEARCH:
! 410: if (caps & RADIO_CAPS_HW_SEARCH) {
! 411: if (ioctl(fd, RIOCSSRCH, &var) < 0)
! 412: warn("RIOCSSRCH");
! 413: } else unsupported++;
! 414: break;
! 415: case OPTION_MUTE:
! 416: if (ioctl(fd, RIOCSMUTE, &var) < 0)
! 417: warn("RIOCSMUTE");
! 418: break;
! 419: }
! 420:
! 421: if ( unsupported )
! 422: warn_unsupported(optval);
! 423: }
! 424:
! 425: /*
! 426: * Convert string to float or unsigned integer
! 427: */
! 428: static u_long
! 429: read_value(char *str, u_int optval)
! 430: {
! 431: u_long val;
! 432:
! 433: if (str == NULL || *str == '\0')
! 434: return VALUE_NONE;
! 435:
! 436: if (optval == OPTION_FREQUENCY)
! 437: val = (u_long)1000 * atof(str);
! 438: else
! 439: val = (u_long)strtol(str, (char **)NULL, 10);
! 440:
! 441: return val;
! 442: }
! 443:
! 444: /*
! 445: * Print current value of the parameter.
! 446: */
! 447: static void
! 448: print_value(int fd, u_int optval)
! 449: {
! 450: u_long var, mhz;
! 451:
! 452: if (optval == OPTION_NONE)
! 453: return;
! 454:
! 455: if ( optval == OPTION_SEARCH)
! 456: var = get_value(fd, OPTION_FREQUENCY);
! 457: else
! 458: var = get_value(fd, optval);
! 459:
! 460: if (var == VALUE_NONE)
! 461: return;
! 462:
! 463: switch (optval) {
! 464: case OPTION_SEARCH:
! 465: /* FALLTHROUGH */
! 466: case OPTION_FREQUENCY:
! 467: mhz = var / 1000;
! 468: printf("%u.%uMHz", (u_int)mhz,
! 469: (u_int)var / 10 - (u_int)mhz * 100);
! 470: break;
! 471: case OPTION_REFERENCE:
! 472: printf("%ukHz", (u_int)var);
! 473: break;
! 474: case OPTION_SENSITIVITY:
! 475: printf("%umkV", (u_int)var);
! 476: break;
! 477: case OPTION_MUTE:
! 478: /* FALLTHROUGH */
! 479: case OPTION_MONO:
! 480: printf("%s", var ? onchar : offchar);
! 481: break;
! 482: case OPTION_STEREO:
! 483: printf("%s", var ? offchar : onchar);
! 484: break;
! 485: default:
! 486: printf("%u", (u_int)var);
! 487: break;
! 488: }
! 489: }
! 490:
! 491: static void
! 492: warn_unsupported(u_int optval)
! 493: {
! 494: warnx("driver does not support `%s'", varname[optval]);
! 495: }
! 496:
! 497: static void
! 498: ext_print(int fd, u_int optval, int silent)
! 499: {
! 500: if (optval == OPTION_NONE)
! 501: return;
! 502:
! 503: if (!silent)
! 504: printf("%s=", varname[optval]);
! 505: print_value(fd, optval);
! 506: putchar('\n');
! 507: }