[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.4

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