[BACK]Return to radioctl.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / radioctl

Annotation of src/usr.bin/radioctl/radioctl.c, Revision 1.10

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