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

Diff for /src/usr.bin/radioctl/radioctl.c between version 1.2 and 1.3

version 1.2, 2001/10/04 22:43:45 version 1.3, 2001/12/05 19:40:46
Line 1 
Line 1 
 /*      $OpenBSD$       */  /* $RuOBSD: radioctl.c,v 1.4 2001/10/20 18:09:10 pva Exp $ */
 /* $RuOBSD: radioctl.c,v 1.1 2001/10/03 05:53:35 gluk Exp $ */  
   
 /*  /*
  * Copyright (c) 2001 Vladimir Popov <jumbo@narod.ru>   * Copyright (c) 2001 Vladimir Popov <jumbo@narod.ru>
Line 27 
Line 26 
  */   */
   
 #include <sys/ioctl.h>  #include <sys/ioctl.h>
   #include "/sys/sys/radioio.h"
   #if 0
 #include <sys/radioio.h>  #include <sys/radioio.h>
   #endif
   
 #include <err.h>  #include <err.h>
 #include <fcntl.h>  #include <fcntl.h>
Line 61 
Line 63 
 #define OPTION_NONE             ~0u  #define OPTION_NONE             ~0u
 #define VALUE_NONE              ~0ul  #define VALUE_NONE              ~0ul
   
   struct opt_t {
           char *string;
           int option;
           int sign;
   #define SIGN_NONE       0
   #define SIGN_PLUS       1
   #define SIGN_MINUS      -1
           u_int32_t value;
   };
   
 extern char *__progname;  extern char *__progname;
 const char *onchar = "on";  const char *onchar = "on";
 #define ONCHAR_LEN      2  #define ONCHAR_LEN      2
 const char *offchar = "off";  const char *offchar = "off";
 #define OFFCHAR_LEN     3  #define OFFCHAR_LEN     3
   
 u_long caps;  static struct radio_info ri;
   
 static void     usage(void);  static int      parse_opt(char *, struct opt_t *);
 static void     print_vars(int, int);  
 static void     write_param(int, char *, int);  
 static u_int    parse_option(const char *);  
 static u_long   get_value(int, u_int);  
 static void     set_value(int, u_int, u_long);  
 static u_long   read_value(char *, u_int);  
 static void     print_value(int, u_int);  
 static void     warn_unsupported(u_int);  
 static void     ext_print(int, u_int, int);  
   
   static void     print_vars(int);
   static void     do_ioctls(int, struct opt_t *, int);
   
   static void     print_value(int);
   static void     change_value(const struct opt_t);
   static void     update_value(int, u_long *, u_long);
   
   static void     warn_unsupported(int);
   static void     usage(void);
   
   static void     show_verbose(const char *, int);
   static void     show_int_val(u_long, const char *, char *, int);
   static void     show_float_val(float, const char *, char *, int);
   static void     show_char_val(const char *, const char *, int);
   static int      str_to_opt(const char *);
   static u_long   str_to_long(char *, int);
   
 /*  /*
  * Control behavior of a FM tuner - set frequency, volume etc   * Control behavior of a FM tuner - set frequency, volume etc
  */   */
 int  int
 main(int argc, char **argv)  main(int argc, char **argv)
 {  {
           struct opt_t opt;
   
         char *radiodev = NULL;          char *radiodev = NULL;
           int rd = -1;
   
         char optchar;          char optchar;
         char *param = NULL;          char *param = NULL;
         int rd = -1;  
         int show_vars = 0;          int show_vars = 0;
         int set_param = 0;          int set_param = 0;
         int silent = 0;          int silent = 0;
   
           int optv = 0;
   
         if (argc < 2) {          if (argc < 2) {
                 usage();                  usage();
                 exit(1);                  exit(1);
Line 107 
Line 133 
                 switch (optchar) {                  switch (optchar) {
                 case 'a':                  case 'a':
                         show_vars = 1;                          show_vars = 1;
                         optind = 1;                          optv = 1;
                         break;                          break;
                 case 'f':                  case 'f':
                         radiodev = optarg;                          radiodev = optarg;
                         optind = 2;                          optv = 2;
                         break;                          break;
                 case 'n':                  case 'n':
                         silent = 1;                          silent = 1;
                         optind = 1;                          optv = 1;
                         break;                          break;
                 case 'w':                  case 'w':
                         set_param = 1;                          set_param = 1;
                         param = optarg;                          param = optarg;
                         optind = 2;                          optv = 2;
                         break;                          break;
                 default:                  default:
                         usage();                          usage();
                         /* NOTREACHED */                          /* NOTREACHED */
                 }                  }
   
                 argc -= optind;                  argc -= optv;
                 argv += optind;                  argv += optv;
         }          }
   
         rd = open(radiodev, O_RDONLY);          rd = open(radiodev, O_RDONLY);
         if (rd < 0)          if (rd < 0)
                 err(1, "%s open error", radiodev);                  err(1, "%s open error", radiodev);
   
         if (ioctl(rd, RIOCGCAPS, &caps) < 0)          if (ioctl(rd, RIOCGINFO, &ri) < 0)
                 err(1, "RIOCGCAPS");                  err(1, "RIOCGINFO");
   
         if (argc > 1)          if (argc > 1)
                 ext_print(rd, parse_option(*(argv + 1)), silent);                  if (parse_opt(*(argv + 1), &opt)) {
                           show_verbose(varname[opt.option], silent);
                           print_value(opt.option);
                           free(opt.string);
                           putchar('\n');
                   }
   
         if (set_param)          if (set_param)
                 write_param(rd, param, silent);                  if (parse_opt(param, &opt))
                           do_ioctls(rd, &opt, silent);
   
         if (show_vars)          if (show_vars)
                 print_vars(rd, silent);                  print_vars(silent);
   
         if (close(rd) < 0)          if (close(rd) < 0)
                 warn("%s close error", radiodev);                  warn("%s close error", radiodev);
Line 160 
Line 192 
                 __progname);                  __progname);
 }  }
   
 /*  
  * Print all available parameters  
  */  
 static void  static void
 print_vars(int fd, int silent)  show_verbose(const char *nick, int silent)
 {  {
         u_long var;  
   
         ext_print(fd, OPTION_VOLUME, silent);  
         ext_print(fd, OPTION_FREQUENCY, silent);  
         ext_print(fd, OPTION_MUTE, silent);  
   
         if (caps & RADIO_CAPS_REFERENCE_FREQ)  
                 ext_print(fd, OPTION_REFERENCE, silent);  
         if (caps & RADIO_CAPS_LOCK_SENSITIVITY)  
                 ext_print(fd, OPTION_SENSITIVITY, silent);  
   
         if (ioctl(fd, RIOCGINFO, &var) < 0)  
                 warn("RIOCGINFO");  
         if (caps & RADIO_CAPS_DETECT_SIGNAL)  
                 if (!silent)  
                         printf("%s=", "signal");  
                 printf("%s\n", var & RADIO_INFO_SIGNAL ? onchar : offchar);  
         if (caps & RADIO_CAPS_DETECT_STEREO) {  
                 if (!silent)  
                         printf("%s=", varname[OPTION_STEREO]);  
                 printf("%s\n", var & RADIO_INFO_STEREO ? onchar : offchar);  
         }  
   
         if (!silent)          if (!silent)
                 puts("card capabilities:");                  printf("%s=", nick);
         if (caps & RADIO_CAPS_SET_MONO)  
                 puts("\tmanageable mono/stereo");  
         if (caps & RADIO_CAPS_HW_SEARCH)  
                 puts("\thardware search");  
         if (caps & RADIO_CAPS_HW_AFC)  
                 puts("\thardware AFC");  
 }  }
   
 /*  
  * Set new value of a parameter  
  */  
 static void  static void
 write_param(int fd, char *param, int silent)  warn_unsupported(int optval)
 {  {
         int paramlen = 0;          warnx("driver does not support `%s'", varname[optval]);
         int namelen = 0;  }
         char *topt = NULL;  
         const char *badvalue = "bad value `%s'";  
         u_int optval = OPTION_NONE;  
         u_long var = VALUE_NONE;  
         u_long addvar = VALUE_NONE;  
         u_char sign = 0;  
   
         if (param == NULL || *param == '\0')  static void
   do_ioctls(int fd, struct opt_t *o, int silent)
   {
           int oval;
   
           if (fd < 0 || o == NULL)
                 return;                  return;
   
         paramlen = strlen(param);          if (o->option == OPTION_SEARCH && !(ri.caps & RADIO_CAPS_HW_SEARCH)) {
         namelen = strcspn(param, "=");                  warn_unsupported(o->option);
         if (namelen > paramlen - 2) {  
                 warnx(badvalue, param);  
                 return;                  return;
         }          }
   
         paramlen -= ++namelen;          oval = o->option == OPTION_SEARCH ? OPTION_FREQUENCY : o->option;
           if (!silent)
                   printf("%s: ", varname[oval]);
   
         if ((topt = (char *)malloc(namelen)) == NULL) {          print_value(o->option);
                 warn("memory allocation error");          printf(" -> ");
                 return;  
           if (o->option == OPTION_SEARCH) {
   
                   if (ioctl(fd, RIOCSSRCH, &o->value) < 0) {
                           warn("RIOCSSRCH");
                           return;
                   }
   
           } else {
   
                   change_value(*o);
                   if (ioctl(fd, RIOCSINFO, &ri) < 0) {
                           warn("RIOCSINFO");
                           return;
                   }
   
         }          }
         strlcpy(topt, param, namelen);  
         optval = parse_option(topt);  
   
         if (optval == OPTION_NONE) {          if (ioctl(fd, RIOCGINFO, &ri) < 0) {
                 free(topt);                  warn("RIOCGINFO");
                 return;                  return;
         }          }
   
         if (!silent)          print_value(o->option);
                 printf("%s: ", topt);          putchar('\n');
   }
   
         free(topt);  static void
   change_value(const struct opt_t o)
   {
           int unsupported = 0;
   
         topt = &param[namelen];          if (o.value == VALUE_NONE)
         switch (*topt) {                  return;
         case '+':  
         case '-':          switch (o.option) {
                 if ((addvar = read_value(topt + 1, optval)) == VALUE_NONE)          case OPTION_VOLUME:
                         break;                  update_value(o.sign, (u_long *)&ri.volume, o.value);
                 if ((var = get_value(fd, optval)) == VALUE_NONE)                  break;
                         break;          case OPTION_FREQUENCY:
                 sign++;                  update_value(o.sign, (u_long *)&ri.freq, o.value);
                 if (*topt == '+')                  break;
                         var += addvar;          case OPTION_REFERENCE:
                   if (ri.caps & RADIO_CAPS_REFERENCE_FREQ)
                           update_value(o.sign, (u_long *)&ri.rfreq, o.value);
                 else                  else
                         var -= addvar;                          unsupported++;
                 break;                  break;
         case 'o':          case OPTION_MONO:
                 if (strncmp(topt, offchar,                  /* FALLTHROUGH */
                         paramlen > OFFCHAR_LEN ? paramlen : OFFCHAR_LEN) == 0)          case OPTION_STEREO:
                         var = 0;                  if (ri.caps & RADIO_CAPS_SET_MONO)
                           ri.stereo = o.option == OPTION_MONO ? !o.value : o.value;
                 else                  else
                         if (strncmp(topt, onchar,                          unsupported++;
                                 paramlen > ONCHAR_LEN ? paramlen : ONCHAR_LEN) == 0)  
                                 var = 1;  
                 break;                  break;
         case 'u':          case OPTION_SENSITIVITY:
                 if (strncmp(topt, "up", paramlen > 2 ? paramlen : 2) == 0)                  if (ri.caps & RADIO_CAPS_LOCK_SENSITIVITY)
                         var = 1;                          update_value(o.sign, (u_long *)&ri.lock, o.value);
                   else
                           unsupported++;
                 break;                  break;
         case 'd':          case OPTION_MUTE:
                 if (strncmp(topt, "down", paramlen > 4 ? paramlen : 4) == 0)                  ri.mute = o.value;
                         var = 0;  
                 break;                  break;
         default:  
                 if (*topt > 47 && *topt < 58)  
                         var = read_value(topt, optval);  
                 break;  
         }          }
   
         if (var == VALUE_NONE || (sign && addvar == VALUE_NONE)) {          if ( unsupported )
                 warnx(badvalue, topt);                  warn_unsupported(o.option);
                 return;  
         }  
   
         print_value(fd, optval);  
         printf(" -> ");  
   
         set_value(fd, optval, var);  
   
         print_value(fd, optval);  
         putchar('\n');  
 }  }
   
 /*  /*
  * Convert string to integer representation of a parameter   * Convert string to integer representation of a parameter
  */   */
 static u_int  static int
 parse_option(const char *topt)  str_to_opt(const char *topt)
 {  {
         u_int res;          int res, toptlen, varlen, len, varsize;
         int toptlen, varlen, len, varsize;  
   
         if (topt == NULL || *topt == '\0')          if (topt == NULL || *topt == '\0')
                 return OPTION_NONE;                  return OPTION_NONE;
Line 320 
Line 320 
         return OPTION_NONE;          return OPTION_NONE;
 }  }
   
 /*  
  * Returns current value of parameter optval  
  */  
 static u_long  
 get_value(int fd, u_int optval)  
 {  
         u_long var = VALUE_NONE;  
   
         switch (optval) {  
         case OPTION_VOLUME:  
                 if (ioctl(fd, RIOCGVOLU, &var) < 0)  
                         warn("RIOCGVOLU");  
                 break;  
         case OPTION_FREQUENCY:  
                 if (ioctl(fd, RIOCGFREQ, &var) < 0)  
                         warn("RIOCGFREQ");  
                 break;  
         case OPTION_REFERENCE:  
                 if (caps & RADIO_CAPS_REFERENCE_FREQ)  
                         if (ioctl(fd, RIOCGREFF, &var) < 0)  
                                 warn("RIOCGREFF");  
                 break;  
         case OPTION_MONO:  
                 /* FALLTHROUGH */  
         case OPTION_STEREO:  
                 if (caps & RADIO_CAPS_SET_MONO)  
                         if (ioctl(fd, RIOCGMONO, &var) < 0)  
                                 warn("RIOCGMONO");  
                 break;  
         case OPTION_SENSITIVITY:  
                 if (caps & RADIO_CAPS_LOCK_SENSITIVITY)  
                         if (ioctl(fd, RIOCGLOCK, &var) < 0)  
                                 warn("RIOCGLOCK");  
                 break;  
         case OPTION_MUTE:  
                 if (ioctl(fd, RIOCGMUTE, &var) < 0)  
                         warn("RIOCGMUTE");  
                 break;  
         }  
   
         if (var == VALUE_NONE)  
                 warn_unsupported(optval);  
   
         return var;  
 }  
   
 /*  
  * Set card parameter optval to value var  
  */  
 static void  static void
 set_value(int fd, u_int optval, u_long var)  update_value(int sign, u_long *value, u_long update)
 {  {
         int unsupported = 0;          switch (sign) {
           case SIGN_NONE:
         if (var == VALUE_NONE)                  *value  = update;
                 return;  
   
         switch (optval) {  
         case OPTION_VOLUME:  
                 if (ioctl(fd, RIOCSVOLU, &var) < 0)  
                         warn("RIOCSVOLU");  
                 break;                  break;
         case OPTION_FREQUENCY:          case SIGN_PLUS:
                 if (ioctl(fd, RIOCSFREQ, &var) < 0)                  *value += update;
                         warn("RIOCSFREQ");  
                 break;                  break;
         case OPTION_REFERENCE:          case SIGN_MINUS:
                 if (caps & RADIO_CAPS_REFERENCE_FREQ) {                  *value -= update;
                         if (ioctl(fd, RIOCSREFF, &var) < 0)  
                                 warn("RIOCSREFF");  
                 } else unsupported++;  
                 break;                  break;
         case OPTION_STEREO:  
                 var = !var;  
                 /* FALLTHROUGH */  
         case OPTION_MONO:  
                 if (caps & RADIO_CAPS_SET_MONO) {  
                         if (ioctl(fd, RIOCSMONO, &var) < 0)  
                                 warn("RIOCSMONO");  
                 } else unsupported++;  
                 break;  
         case OPTION_SENSITIVITY:  
                 if (caps & RADIO_CAPS_LOCK_SENSITIVITY) {  
                         if (ioctl(fd, RIOCSLOCK, &var) < 0)  
                                 warn("RIOCSLOCK");  
                 } else unsupported++;  
                 break;  
         case OPTION_SEARCH:  
                 if (caps & RADIO_CAPS_HW_SEARCH) {  
                         if (ioctl(fd, RIOCSSRCH, &var) < 0)  
                                 warn("RIOCSSRCH");  
                 } else unsupported++;  
                 break;  
         case OPTION_MUTE:  
                 if (ioctl(fd, RIOCSMUTE, &var) < 0)  
                         warn("RIOCSMUTE");  
                 break;  
         }          }
   
         if ( unsupported )  
                 warn_unsupported(optval);  
 }  }
   
 /*  /*
  * Convert string to float or unsigned integer   * Convert string to unsigned integer
  */   */
 static u_long  static u_long
 read_value(char *str, u_int optval)  str_to_long(char *str, int optval)
 {  {
         u_long val;          u_long val;
   
Line 443 
Line 356 
 }  }
   
 /*  /*
    * parse string s into struct opt_t
    * return true on success, false on failure
    */
   static int
   parse_opt(char *s, struct opt_t *o) {
           const char *badvalue = "bad value `%s'";
           char *topt = NULL;
           int slen, optlen;
   
           if (s == NULL || *s == '\0' || o == NULL)
                   return 0;
   
           o->string = NULL;
           o->option = OPTION_NONE;
           o->value = VALUE_NONE;
           o->sign = SIGN_NONE;
   
           slen = strlen(s);
           optlen = strcspn(s, "=");
   
           /* Set only o->optval, the rest is missing */
           if (slen == optlen) {
                   o->option = str_to_opt(s);
                   return o->option == OPTION_NONE ? 0 : 1;
           }
   
           if (optlen > slen - 2) {
                   warnx(badvalue, s);
                   return 0;
           }
   
           slen -= ++optlen;
   
           if ((topt = (char *)malloc(optlen)) == NULL) {
                   warn("memory allocation error");
                   return 0;
           }
           strlcpy(topt, s, optlen);
   
           if ((o->option = str_to_opt(topt)) == OPTION_NONE) {
                   free(topt);
                   return 0;
           }
           o->string = topt;
   
           topt = &s[optlen];
           switch (*topt) {
           case '+':
           case '-':
                   o->sign = (*topt == '+') ? SIGN_PLUS : SIGN_MINUS;
                   o->value = str_to_long(&topt[1], o->option);
                   break;
           case 'o':
                   if (strncmp(topt, offchar,
                           slen > OFFCHAR_LEN ? slen : OFFCHAR_LEN) == 0)
                           o->value = 0;
                   else if (strncmp(topt, onchar,
                                   slen > ONCHAR_LEN ? slen : ONCHAR_LEN) == 0)
                                   o->value = 1;
                   break;
           case 'u':
                   if (strncmp(topt, "up", slen > 2 ? slen : 2) == 0)
                           o->value = 1;
                   break;
           case 'd':
                   if (strncmp(topt, "down", slen > 4 ? slen : 4) == 0)
                           o->value = 0;
                   break;
           default:
                   if (*topt > 47 && *topt < 58)
                           o->value = str_to_long(topt, o->option);
                   break;
           }
   
           if (o->value == VALUE_NONE) {
                   warnx(badvalue, topt);
                   return 0;
           }
   
           return 1;
   }
   
   /*
  * Print current value of the parameter.   * Print current value of the parameter.
  */   */
 static void  static void
 print_value(int fd, u_int optval)  print_value(int optval)
 {  {
         u_long var, mhz;  
   
         if (optval == OPTION_NONE)          if (optval == OPTION_NONE)
                 return;                  return;
   
         if ( optval == OPTION_SEARCH)  
                 var = get_value(fd, OPTION_FREQUENCY);  
         else  
                 var = get_value(fd, optval);  
   
         if (var == VALUE_NONE)  
                 return;  
   
         switch (optval) {          switch (optval) {
         case OPTION_SEARCH:          case OPTION_SEARCH:
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
         case OPTION_FREQUENCY:          case OPTION_FREQUENCY:
                 mhz = var / 1000;                  printf("%.2fMHz", (float)ri.freq / 1000.);
                 printf("%u.%uMHz", (u_int)mhz,  
                         (u_int)var / 10 - (u_int)mhz * 100);  
                 break;                  break;
         case OPTION_REFERENCE:          case OPTION_REFERENCE:
                 printf("%ukHz", (u_int)var);                  printf("%ukHz", ri.rfreq);
                 break;                  break;
         case OPTION_SENSITIVITY:          case OPTION_SENSITIVITY:
                 printf("%umkV", (u_int)var);                  printf("%umkV", ri.lock);
                 break;                  break;
         case OPTION_MUTE:          case OPTION_MUTE:
                 /* FALLTHROUGH */                  printf(ri.mute ? onchar : offchar);
                   break;
         case OPTION_MONO:          case OPTION_MONO:
                 printf("%s", var ? onchar : offchar);                  printf(ri.stereo ? offchar : onchar);
                 break;                  break;
         case OPTION_STEREO:          case OPTION_STEREO:
                 printf("%s", var ? offchar : onchar);                  printf(ri.stereo ? onchar : offchar);
                 break;                  break;
           case OPTION_VOLUME:
         default:          default:
                 printf("%u", (u_int)var);                  printf("%u", ri.volume);
                 break;                  break;
         }          }
 }  }
   
 static void  static void
 warn_unsupported(u_int optval)  show_int_val(u_long val, const char *nick, char *append, int silent)
 {  {
         warnx("driver does not support `%s'", varname[optval]);          show_verbose(nick, silent);
           printf("%lu%s\n", val, append);
 }  }
   
 static void  static void
 ext_print(int fd, u_int optval, int silent)  show_float_val(float val, const char *nick, char *append, int silent)
 {  {
         if (optval == OPTION_NONE)          show_verbose(nick, silent);
                 return;          printf("%.2f%s\n", val, append);
   }
   
   static void
   show_char_val(const char *val, const char *nick, int silent)
   {
           show_verbose(nick, silent);
           printf("%s\n", val);
   }
   
   /*
    * Print all available parameters
    */
   static void
   print_vars(int silent)
   {
           show_int_val(ri.volume, varname[OPTION_VOLUME], "", silent);
           show_float_val((float)ri.freq / 1000., varname[OPTION_FREQUENCY],
                           "MHz", silent);
           show_char_val(ri.mute ? onchar : offchar, varname[OPTION_MUTE], silent);
   
           if (ri.caps & RADIO_CAPS_REFERENCE_FREQ)
                   show_int_val(ri.rfreq, varname[OPTION_REFERENCE], "kHz", silent);
           if (ri.caps & RADIO_CAPS_LOCK_SENSITIVITY)
                   show_int_val(ri.lock, varname[OPTION_SENSITIVITY], "mkV", silent);
   
           if (ri.caps & RADIO_CAPS_DETECT_SIGNAL) {
                   show_verbose("signal", silent);
                   printf("%s\n", ri.info & RADIO_INFO_SIGNAL ? onchar : offchar);
           }
           if (ri.caps & RADIO_CAPS_DETECT_STEREO) {
                   show_verbose(varname[OPTION_STEREO], silent);
                   printf("%s\n", ri.info & RADIO_INFO_STEREO ? onchar : offchar);
           }
   
         if (!silent)          if (!silent)
                 printf("%s=", varname[optval]);                  puts("card capabilities:");
         print_value(fd, optval);          if (ri.caps & RADIO_CAPS_SET_MONO)
         putchar('\n');                  puts("\tmanageable mono/stereo");
           if (ri.caps & RADIO_CAPS_HW_SEARCH)
                   puts("\thardware search");
           if (ri.caps & RADIO_CAPS_HW_AFC)
                   puts("\thardware AFC");
 }  }

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3