summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorGrigoriy Orlov <gluk@cvs.openbsd.org>2001-10-04 22:22:12 +0000
committerGrigoriy Orlov <gluk@cvs.openbsd.org>2001-10-04 22:22:12 +0000
commit973878ac4e51aed758d8d3e10660fc9c56326eb0 (patch)
tree244470ffc94f6b957bc0bb15e409a6c7fde02bfd /usr.bin
parent105c4ee4d284f339b1ae425b60fc44734f891cb2 (diff)
Configuration utility for radio devices.
Work by Vladimir Popov <jumbo@narod.ru>
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/Makefile5
-rw-r--r--usr.bin/radioctl/Makefile7
-rw-r--r--usr.bin/radioctl/radioctl.1156
-rw-r--r--usr.bin/radioctl/radioctl.c507
4 files changed, 673 insertions, 2 deletions
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 218a9e7a861..8959f0f0f3c 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.73 2001/09/11 00:03:28 jason Exp $
+# $OpenBSD: Makefile,v 1.74 2001/10/04 22:22:11 gluk Exp $
.include <bsd.own.mk>
@@ -12,7 +12,8 @@ SUBDIR= apply apropos arch asa at aucat audioctl awk banner basename bdes \
login logname look lorder m4 mail make man mesg mg midiplay mixerctl \
mkdep mkstr mktemp modstat msgs nc netstat newsyslog nfsstat nice \
nohup oldrdist pagesize passwd paste patch pctr pr printenv printf \
- quota rdist rdistd readlink renice rev rlogin rpcgen rpcinfo rs rsh \
+ quota radioctl rdist rdistd readlink renice rev rlogin rpcgen rpcinfo \
+ rs rsh \
rup ruptime rusers rwall rwho script sectok sed shar showmount skey \
skeyaudit skeyinfo skeyinit sort split ssh su sup systat sudo tail \
talk tcopy tee telnet tftp tic time tip tn3270 top touch tput tr true \
diff --git a/usr.bin/radioctl/Makefile b/usr.bin/radioctl/Makefile
new file mode 100644
index 00000000000..ec1fb4ddc14
--- /dev/null
+++ b/usr.bin/radioctl/Makefile
@@ -0,0 +1,7 @@
+# $OpenBSD: Makefile,v 1.1 2001/10/04 22:22:11 gluk Exp $
+# $NetBSD: Makefile,v 1.1 1997/05/13 17:35:52 augustss Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= radioctl
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/radioctl/radioctl.1 b/usr.bin/radioctl/radioctl.1
new file mode 100644
index 00000000000..ceac42f9680
--- /dev/null
+++ b/usr.bin/radioctl/radioctl.1
@@ -0,0 +1,156 @@
+.\"
+.\" Copyright (c) 2001 Vladimir Popov
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+.\" ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd September 16, 2001
+.Dt RADIOCTL 1
+.Os
+.Sh NAME
+.Nm radioctl
+.Nd control radio tuners
+.Sh SYNOPSIS
+.Nm radioctl
+.Op Fl f Ar file
+.Op Fl n
+.Fl a
+.Nm radioctl
+.Op Fl f Ar file
+.Op Fl n
+.Ar name
+.Nm radioctl
+.Op Fl f Ar file
+.Op Fl n
+.Fl w
+.Ar name=value
+.Sh DESCRIPTION
+The
+.Nm
+command displays or sets various variables that affect the radio tuner
+behavior. If a variable is present on the command line,
+.Nm
+prints the current value of this variable for the specified device.
+By default,
+.Nm
+operates on the
+.Pa /dev/radio
+device.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Print all device variables and their current values.
+.It Fl w Ar name=value
+Attempt to set the specified variable
+.Ar name
+to
+.Ar value .
+.It Fl f Ar file
+Specify an alternative radio tuner device.
+.It Fl n
+Suppress printing of the variable name.
+.El
+.Pp
+Values may be specified in either absolute or relative forms.
+The relative form is indicated by a prefix of
+.Ql +
+or
+.Ql -
+to denote an increase or decrease, respectively.
+.Pp
+The exact set of controls that can be manipulated depends on
+the tuner.
+The general format (in both getting and setting a value) is
+.Pp
+.Va name = value
+.Pp
+The
+.Va name
+indicates what part of the tuner the control affects.
+.Pp
+Write only controls:
+.Bl -tag -width search
+.It search
+Only for cards that allow hardware search. Can be
+.Ql up
+or
+.Ql down .
+.El
+.Pp
+Read-write controls:
+.Bl -tag -width volume
+.It frequency
+Float value from 87.5 to 108.0.
+.It volume
+Integer value from 0 to 255.
+.It mute
+Mutes the card (volume is not affected),
+.Ql on
+or
+.Ql off .
+.It mono
+Forces card output to mono,
+.Ql on
+or
+.Ql off .
+Only for cards that allow forced mono.
+.It reference
+Reference frequency. Can be 25 kHz, 50 kHz and 100 kHz. Not all cards allow
+to change the reference frequency.
+.It sensitivity
+Station locking sensitivity. Can be 5 mkV, 10 mkV, 30 mkV and 150 mkV. Not all
+cards allow to change the station locking sensitivity.
+.El
+.Pp
+All the remaining controls (signal, stereo and card capabilities) are read-only
+and can be viewed using option
+.Fl a .
+.Sh EXAMPLES
+The command
+.Pp
+.Dl "radioctl -a"
+.Pp
+can produce
+.Bd -literal
+volume=255
+frequency=106.30MHz
+mute=off
+reference=50kHz
+signal=on
+stereo=on
+card capabilities:
+ manageable mono/stereo
+.Ed
+.Sh ENVIRONMENT
+The following environment variable affects the execution of
+.Nm radioctl :
+.Bl -tag -width RADIODEVICE
+.It Ev RADIODEVICE
+The radio tuner device to use.
+.El
+.Sh FILES
+.Bl -tag -width /dev/radio
+.It Pa /dev/radio
+radio tuner device
+.El
+.Sh SEE ALSO
+.Xr radio 4
diff --git a/usr.bin/radioctl/radioctl.c b/usr.bin/radioctl/radioctl.c
new file mode 100644
index 00000000000..1b7e91a79c1
--- /dev/null
+++ b/usr.bin/radioctl/radioctl.c
@@ -0,0 +1,507 @@
+/* $RuOBSD: radioctl.c,v 1.1 2001/10/03 05:53:35 gluk Exp $ */
+
+/*
+ * Copyright (c) 2001 Vladimir Popov <jumbo@narod.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/radioio.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define RADIO_ENV "RADIODEVICE"
+#define RADIODEVICE "/dev/radio"
+
+const char *varname[] = {
+ "search",
+#define OPTION_SEARCH 0x00
+ "volume",
+#define OPTION_VOLUME 0x01
+ "frequency",
+#define OPTION_FREQUENCY 0x02
+ "mute",
+#define OPTION_MUTE 0x03
+ "reference",
+#define OPTION_REFERENCE 0x04
+ "mono",
+#define OPTION_MONO 0x05
+ "stereo",
+#define OPTION_STEREO 0x06
+ "sensitivity"
+#define OPTION_SENSITIVITY 0x07
+};
+
+#define OPTION_NONE ~0u
+#define VALUE_NONE ~0ul
+
+extern char *__progname;
+const char *onchar = "on";
+#define ONCHAR_LEN 2
+const char *offchar = "off";
+#define OFFCHAR_LEN 3
+
+u_long caps;
+
+static void usage(void);
+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);
+
+/*
+ * Control behavior of a FM tuner - set frequency, volume etc
+ */
+int
+main(int argc, char **argv)
+{
+ char *radiodev = NULL;
+ char optchar;
+ char *param = NULL;
+ int rd = -1;
+ int show_vars = 0;
+ int set_param = 0;
+ int silent = 0;
+
+ if (argc < 2) {
+ usage();
+ exit(1);
+ }
+
+ radiodev = getenv(RADIO_ENV);
+ if (radiodev == NULL)
+ radiodev = RADIODEVICE;
+
+ while ((optchar = getopt(argc, argv, "af:nw:")) != -1) {
+ switch (optchar) {
+ case 'a':
+ show_vars = 1;
+ optind = 1;
+ break;
+ case 'f':
+ radiodev = optarg;
+ optind = 2;
+ break;
+ case 'n':
+ silent = 1;
+ optind = 1;
+ break;
+ case 'w':
+ set_param = 1;
+ param = optarg;
+ optind = 2;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ argc -= optind;
+ argv += optind;
+ }
+
+ rd = open(radiodev, O_RDONLY);
+ if (rd < 0)
+ err(1, "%s open error", radiodev);
+
+ if (ioctl(rd, RIOCGCAPS, &caps) < 0)
+ err(1, "RIOCGCAPS");
+
+ if (argc > 1)
+ ext_print(rd, parse_option(*(argv + 1)), silent);
+
+ if (set_param)
+ write_param(rd, param, silent);
+
+ if (show_vars)
+ print_vars(rd, silent);
+
+ if (close(rd) < 0)
+ warn("%s close error", radiodev);
+
+ return 0;
+}
+
+static void
+usage(void)
+{
+ printf("Usage: %s [-f file] [-a] [-n] [-w name=value] [name]\n",
+ __progname);
+}
+
+/*
+ * Print all available parameters
+ */
+static void
+print_vars(int fd, 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)
+ puts("card capabilities:");
+ 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
+write_param(int fd, char *param, int silent)
+{
+ int paramlen = 0;
+ 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')
+ return;
+
+ paramlen = strlen(param);
+ namelen = strcspn(param, "=");
+ if (namelen > paramlen - 2) {
+ warnx(badvalue, param);
+ return;
+ }
+
+ paramlen -= ++namelen;
+
+ if ((topt = (char *)malloc(namelen)) == NULL) {
+ warn("memory allocation error");
+ return;
+ }
+ strlcpy(topt, param, namelen);
+ optval = parse_option(topt);
+
+ if (optval == OPTION_NONE) {
+ free(topt);
+ return;
+ }
+
+ if (!silent)
+ printf("%s: ", topt);
+
+ free(topt);
+
+ topt = &param[namelen];
+ switch (*topt) {
+ case '+':
+ case '-':
+ if ((addvar = read_value(topt + 1, optval)) == VALUE_NONE)
+ break;
+ if ((var = get_value(fd, optval)) == VALUE_NONE)
+ break;
+ sign++;
+ if (*topt == '+')
+ var += addvar;
+ else
+ var -= addvar;
+ break;
+ case 'o':
+ if (strncmp(topt, offchar,
+ paramlen > OFFCHAR_LEN ? paramlen : OFFCHAR_LEN) == 0)
+ var = 0;
+ else
+ if (strncmp(topt, onchar,
+ paramlen > ONCHAR_LEN ? paramlen : ONCHAR_LEN) == 0)
+ var = 1;
+ break;
+ case 'u':
+ if (strncmp(topt, "up", paramlen > 2 ? paramlen : 2) == 0)
+ var = 1;
+ break;
+ case 'd':
+ if (strncmp(topt, "down", paramlen > 4 ? paramlen : 4) == 0)
+ var = 0;
+ break;
+ default:
+ if (*topt > 47 && *topt < 58)
+ var = read_value(topt, optval);
+ break;
+ }
+
+ if (var == VALUE_NONE || (sign && addvar == VALUE_NONE)) {
+ warnx(badvalue, topt);
+ 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
+ */
+static u_int
+parse_option(const char *topt)
+{
+ u_int res;
+ int toptlen, varlen, len, varsize;
+
+ if (topt == NULL || *topt == '\0')
+ return OPTION_NONE;
+
+ varsize = sizeof(varname) / sizeof(varname[0]);
+ toptlen = strlen(topt);
+
+ for (res = 0; res < varsize; res++) {
+ varlen = strlen(varname[res]);
+ len = toptlen > varlen ? toptlen : varlen;
+ if (strncmp(topt, varname[res], len) == 0)
+ return res;
+ }
+
+ warnx("bad name `%s'", topt);
+ 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
+set_value(int fd, u_int optval, u_long var)
+{
+ int unsupported = 0;
+
+ if (var == VALUE_NONE)
+ return;
+
+ switch (optval) {
+ case OPTION_VOLUME:
+ if (ioctl(fd, RIOCSVOLU, &var) < 0)
+ warn("RIOCSVOLU");
+ break;
+ case OPTION_FREQUENCY:
+ if (ioctl(fd, RIOCSFREQ, &var) < 0)
+ warn("RIOCSFREQ");
+ break;
+ case OPTION_REFERENCE:
+ if (caps & RADIO_CAPS_REFERENCE_FREQ) {
+ if (ioctl(fd, RIOCSREFF, &var) < 0)
+ warn("RIOCSREFF");
+ } else unsupported++;
+ 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
+ */
+static u_long
+read_value(char *str, u_int optval)
+{
+ u_long val;
+
+ if (str == NULL || *str == '\0')
+ return VALUE_NONE;
+
+ if (optval == OPTION_FREQUENCY)
+ val = (u_long)1000 * atof(str);
+ else
+ val = (u_long)strtol(str, (char **)NULL, 10);
+
+ return val;
+}
+
+/*
+ * Print current value of the parameter.
+ */
+static void
+print_value(int fd, u_int optval)
+{
+ u_long var, mhz;
+
+ if (optval == OPTION_NONE)
+ return;
+
+ if ( optval == OPTION_SEARCH)
+ var = get_value(fd, OPTION_FREQUENCY);
+ else
+ var = get_value(fd, optval);
+
+ if (var == VALUE_NONE)
+ return;
+
+ switch (optval) {
+ case OPTION_SEARCH:
+ /* FALLTHROUGH */
+ case OPTION_FREQUENCY:
+ mhz = var / 1000;
+ printf("%u.%uMHz", (u_int)mhz,
+ (u_int)var / 10 - (u_int)mhz * 100);
+ break;
+ case OPTION_REFERENCE:
+ printf("%ukHz", (u_int)var);
+ break;
+ case OPTION_SENSITIVITY:
+ printf("%umkV", (u_int)var);
+ break;
+ case OPTION_MUTE:
+ /* FALLTHROUGH */
+ case OPTION_MONO:
+ printf("%s", var ? onchar : offchar);
+ break;
+ case OPTION_STEREO:
+ printf("%s", var ? offchar : onchar);
+ break;
+ default:
+ printf("%u", (u_int)var);
+ break;
+ }
+}
+
+static void
+warn_unsupported(u_int optval)
+{
+ warnx("driver does not support `%s'", varname[optval]);
+}
+
+static void
+ext_print(int fd, u_int optval, int silent)
+{
+ if (optval == OPTION_NONE)
+ return;
+
+ if (!silent)
+ printf("%s=", varname[optval]);
+ print_value(fd, optval);
+ putchar('\n');
+}