[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.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: }