/* * Copyright (c) 2005 Jacob Meuser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * $OpenBSD: tunerctl.c,v 1.1 2005/07/04 21:10:26 jakemsr Exp $ */ #include #include #include #include #include #include #include #include #include #include #define DEFAULT_TUNER_DEVICE "/dev/tuner0" struct fields { char *name; int type; #define INT 1 #define ASRC 2 #define CSET 3 #define MUTE 4 #define OFFON 5 #define FREQ 6 #define VSAT 7 #define USAT 8 #define HUE 9 #define BRIGHT 10 #define CONTR 11 int val; long io_set; long io_get; int valmin; int valmax; } fields[] = { { "chanset", CSET, 0, TVTUNER_SETTYPE, TVTUNER_GETTYPE, 0, 0 }, { "channel", INT, 0, TVTUNER_SETCHNL, TVTUNER_GETCHNL, 0, 150 }, { "freq", FREQ, 0, TVTUNER_SETFREQ, TVTUNER_GETFREQ, 608, 14240 }, { "afc", OFFON, 0, TVTUNER_SETAFC, TVTUNER_GETAFC, 0, 1 }, { "audio", ASRC, 0, BT848_SAUDIO, BT848_GAUDIO, 0, 0 }, { "mute", MUTE, 0, BT848_SAUDIO, BT848_GAUDIO, 0, 1 }, { "bright", BRIGHT, 0, BT848_SBRIG, BT848_GBRIG, BT848_BRIGHTMIN, BT848_BRIGHTMAX }, { "contrast", CONTR, 0, BT848_SCONT, BT848_GCONT, BT848_CONTRASTMIN, BT848_CONTRASTMAX }, { "hue", HUE, 0, BT848_SHUE, BT848_GHUE, BT848_HUEMIN, BT848_HUEMAX }, { "usat", USAT, 0, BT848_SUSAT, BT848_GUSAT, BT848_SATUMIN, BT848_SATUMAX }, { "vsat", VSAT, 0, BT848_SVSAT, BT848_GVSAT, BT848_SATVMIN, BT848_SATVMAX }, { 0, 0, 0, 0, 0, 0, 0} }; struct chansets { int value; char *name; } chansets[] = { { CHNLSET_NABCST, "nabcst", }, { CHNLSET_CABLEIRC, "cableirc", }, { CHNLSET_CABLEHRC, "cablehrc", }, { CHNLSET_WEUROPE, "weurope", }, { CHNLSET_JPNBCST, "jpnbcst", }, { CHNLSET_JPNCABLE, "jpncable", }, { CHNLSET_XUSSR, "xussr", }, { CHNLSET_AUSTRALIA, "australia", }, { CHNLSET_FRANCE, "france", }, { 0, 0 } }; struct audiosources { int value; char *name; } audiosources[] = { { AUDIO_TUNER, "tuner", }, { AUDIO_EXTERN, "extern", }, { AUDIO_INTERN, "intern", }, { 0, 0 } }; int tuner_fd; int print_choices; int print_name; int print_value; __dead void usage(void); int run(int, char *); int findfield(char *); int prfield(int); int do_ioctls(int, char *); #define OFF 0 #define ON 1 int isoffon(const char *); /* getopt externs */ extern char *optarg; extern int opterr; extern int optind; extern int optopt; extern int optreset; __dead void usage(void) { extern char *__progname; fprintf(stderr, "usage: %s [-nv] [-f file] -a\n" " %s [-nv] [-f file] name [...]\n" " %s [-q] [-f file] name=value [...]\n", __progname, __progname, __progname); exit (1); } int isoffon(const char *offon) { if (strncmp(offon, "off", 3) == 0) return (OFF); else if (strncmp(offon, "on", 2) == 0) return (ON); return (-1); } int findfield(char *name) { int i, found = 0; for (i = 0; fields[i].name; i++) { if (strncmp(fields[i].name, name, strlen(fields[i].name)) ==0) { found = 1; break; } } if (found == 1) return (i); else return (-1); } int prfield(int index) { int switchval; int i; if (print_name == 1) printf("%s=", fields[index].name); if (ioctl(tuner_fd, fields[index].io_get, &fields[index].val) < 0) { warn("%s", fields[index].name); return (1); } switchval = fields[index].type; switch (switchval) { case ASRC: for (i = 0; audiosources[i].name; i++) if (audiosources[i].value == (fields[index].val & ~AUDIO_MUTE)) break; printf("%s", audiosources[i].name); if (print_choices == 1) { printf(" [ "); for (i = 0; audiosources[i].name; i++) printf("%s ", audiosources[i].name); printf("]"); } break; case CSET: for (i = 0; chansets[i].name; i++) if (chansets[i].value == fields[index].val) break; printf("%s", chansets[i].name); if (print_choices == 1) { printf(" [ "); for (i = 0; chansets[i].name; i++) printf("%s ", chansets[i].name); printf("]"); } break; case FREQ: printf("%0.2f", (double)fields[index].val / 16); if (print_choices == 1) printf(" ( %0.2f - %0.2f )", (double)fields[index].valmin / 16, (double)fields[index].valmax / 16); break; case INT: case BRIGHT: case CONTR: case HUE: case VSAT: case USAT: i = fields[index].val; if (switchval == BRIGHT) { i = (i - BT848_BRIGHTREGMIN) * BT848_BRIGHTRANGE / BT848_BRIGHTSTEPS + BT848_BRIGHTMIN + (i < 0 ? -0.5 : 0.5); } else if (switchval == CONTR) { i = (i - BT848_CONTRASTREGMIN) * BT848_CONTRASTRANGE / BT848_CONTRASTSTEPS + BT848_CONTRASTMIN + (i < 0 ? -0.5 : 0.5); } else if (switchval == HUE) { i = (i - BT848_HUEREGMIN) * BT848_HUERANGE / BT848_HUESTEPS + BT848_HUEMIN + (i < 0 ? -0.5 : 0.5); } else if (switchval == USAT) { i = (i - BT848_SATUREGMIN) * BT848_SATURANGE / BT848_SATUSTEPS + BT848_SATUMIN + (i < 0 ? -0.5 : 0.5); } else if (switchval == VSAT) { i = (i - BT848_SATVREGMIN) * BT848_SATVRANGE / BT848_SATVSTEPS + BT848_SATVMIN + (i < 0 ? -0.5 : 0.5); } printf("%d", i); if (print_choices == 1) printf(" ( %d - %d )", fields[index].valmin, fields[index].valmax); break; case MUTE: case OFFON: if (((switchval == MUTE) && (fields[index].val & AUDIO_MUTE)) || ((switchval != MUTE) && (fields[index].val == 1))) printf("on"); else printf("off"); if (print_choices == 1) printf(" [ off on ]"); break; default: warnx("internal error: prfield"); break; } printf("\n"); return (0); } int do_ioctls(int index, char *arg) { const char *errstr; int i; int switchval; switchval = fields[index].type; if (arg != NULL) { switch(switchval) { case ASRC: for (i = 0; audiosources[i].name; i++) if (strncmp(audiosources[i].name, arg, strlen(audiosources[i].name)) == 0) break; if (audiosources[i].name[0] != '\0') fields[index].val = audiosources[i].value; else { warnx("%s is invalid: %s", fields[index].name, arg); return (1); } break; case CSET: for (i = 0; chansets[i].name; i++) if (strncmp(chansets[i].name, arg, strlen(chansets[i].name)) == 0) break; if (chansets[i].name[0] != '\0') fields[index].val = chansets[i].value; else { warnx("%s is invalid: %s", fields[index].name, arg); return (1); } break; case FREQ: fields[index].val = strtod(arg, (char **)NULL) * 16; if ((fields[index].val < fields[index].valmin) || (fields[index].val > fields[index].valmax)) { warnx("%s is invalid: %s", fields[index].name, arg); return (1); } break; case INT: case BRIGHT: case CONTR: case HUE: case USAT: case VSAT: i = strtonum(arg, fields[index].valmin, fields[index].valmax, &errstr); if (errstr != NULL) { warnx("%s is %s: %s", fields[index].name, errstr, arg); return (1); } if (switchval == BRIGHT) { i = (i - BT848_BRIGHTMIN) * BT848_BRIGHTSTEPS / BT848_BRIGHTRANGE + BT848_BRIGHTREGMIN + (i < 0 ? -0.5 : 0.5); if (i > BT848_BRIGHTREGMAX) i = BT848_BRIGHTREGMAX; } else if (switchval == CONTR) { i = (i - BT848_CONTRASTMIN) * BT848_CONTRASTSTEPS / BT848_CONTRASTRANGE + BT848_CONTRASTREGMIN + (i < 0 ? -0.5 : 0.5); if (i > BT848_CONTRASTREGMAX) i = BT848_CONTRASTREGMAX; } else if (switchval == HUE) { i = (i - BT848_HUEMIN) * BT848_HUESTEPS / BT848_HUERANGE + BT848_HUEREGMIN + (i < 0 ? -0.5 : 0.5); if (i > BT848_HUEREGMAX) i = BT848_HUEREGMAX; } else if (switchval == USAT) { i = (i - BT848_SATUMIN) * BT848_SATUSTEPS / BT848_SATURANGE + BT848_SATUREGMIN + (i < 0 ? -0.5 : 0.5); if (i > BT848_SATUREGMAX) i = BT848_SATUREGMAX; } else if (switchval == VSAT) { i = (i - BT848_SATVMIN) * BT848_SATVSTEPS / BT848_SATVRANGE + BT848_SATVREGMIN + (i < 0 ? -0.5 : 0.5); if (i > BT848_SATVREGMAX) i = BT848_SATVREGMAX; } fields[index].val = i; break; case MUTE: case OFFON: fields[index].val = isoffon(arg); if (fields[index].val < 0) { warnx("%s is invalid: %s", fields[index].name, optarg); return (1); } if (switchval == MUTE) { if (fields[index].val == 1) fields[index].val = AUDIO_MUTE; else fields[index].val = AUDIO_UNMUTE; } break; default: warnx("internal error: do_ioctls: set"); break; } if (ioctl(tuner_fd, fields[index].io_set,&fields[index].val)<0){ warn("%s", fields[index].name); return (1); } } else { /* nothing is being set, so the -q option is meaningless */ print_value = 1; } if (print_value == 1) if (prfield(index) > 0) return (1); return (0); } int main(int argc, char *argv[]) { char *device = DEFAULT_TUNER_DEVICE; int aflag = 0; int err = 0; int ch, i; print_choices = 0; print_name = 1; print_value = 1; while ((ch = getopt(argc, argv, "af:nqv")) != -1) { switch (ch) { case 'a': aflag++; break; case 'f': device = optarg; break; case 'n': print_name = 0; break; case 'q': print_value = 0; break; case 'v': print_choices = 1; break; default: usage(); } } argc -= optind; argv += optind; if ((argc == 0) && (aflag == 0)) usage(); if ((tuner_fd = open(device, O_RDONLY)) < 0) { warn("%s", device); close(tuner_fd); exit (1); } if (aflag > 0) { for (i = 0; fields[i].name; i++) { if (do_ioctls(i, NULL) > 0) { err++; break; } } } else { for (; argc--; argv++) { char *q; q = strchr(*argv, '='); i = findfield(*argv); if (i < 0) { warnx("field '%s' does not exist", *argv); err++; break; } else { if (q != NULL) *q++ = 0; if (do_ioctls(i, q) > 0) { err++; break; } } } } close(tuner_fd); exit (err); }