setchannel.c revision 166959
1/*
2 * Copyright (c) 2003, 2004, 2005
3 *	John Wehle <john@feith.com>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *  $FreeBSD: head/usr.bin/setchannel/setchannel.c 166959 2007-02-25 01:08:17Z grog $
27 */
28
29/* Set the channel of the tuner card. */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <ctype.h>
34#include <fcntl.h>
35#include <string.h>
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/ioctl.h>
39#include <unistd.h>
40
41#if __FreeBSD_version < 503001
42#  include <machine/ioctl_meteor.h>
43#  include <machine/ioctl_bt848.h>
44#else
45#  include <dev/bktr/ioctl_meteor.h>
46#  include <dev/bktr/ioctl_bt848.h>
47#endif
48
49
50static void
51usage()
52{
53	printf
54	    ("Usage: setchannel [-a {on|off}] [-c | -r | -s | -t] "
55	    "[-g geom] [-m chnl_set] [chnl | freq]\n"
56	    "  -a    Enable / disable AFC.\n"
57	    "  -c    Select composite input.\n"
58            "  -r    Select radio input.\n"
59	    "  -s    Select svideo input.\n"
60            "  -t    Select tuner.\n"
61	    "  -g    Select geometry.\n"
62            "          352x240 or 352x288 = VCD\n"
63	    "          480x480 or 480x576 = SVCD\n"
64	    "          352x480 or 352x576 = DVD (half D1)\n"
65	    "          720x480 or 720x576 = DVD (full D1)\n"
66	    "  -m    Select channel set / system.\n"
67	    "          0 = Tuner Default\n"
68	    "          %u = US Broadcast / NTSC\n"
69	    "          %u = US Cable / NTSC\n"
70	    "          %u = Western Europe / PAL\n"
71	    "          %u = Japan Broadcast / NTSC\n"
72	    "          %u = Japan Cable / NTSC\n"
73	    "          %u = Australia / PAL\n"
74	    "          %u = France / SECAM\n"
75            "  chnl  Channel\n"
76	    "  freq  Frequency in MHz (must include decimal point).\n",
77	    CHNLSET_NABCST, CHNLSET_CABLEIRC, CHNLSET_WEUROPE, CHNLSET_JPNBCST,
78	    CHNLSET_JPNCABLE, CHNLSET_AUSTRALIA, CHNLSET_FRANCE);
79}
80
81int
82main(int argc, char *argv[])
83{
84	char *ptr;
85	char *endptr;
86	int afc;
87	int audio;
88	int c;
89	int channel_set;
90	int i;
91	int status;
92	int tfd;
93	unsigned int channel;
94	unsigned int fraction;
95	unsigned int freq;
96	unsigned int x_size;
97	unsigned int y_size;
98	unsigned long device;
99	struct bktr_capture_area cap;
100
101	afc = -1;
102	audio = -1;
103	channel = 0;
104	channel_set = -1;
105	device = 0;
106	freq = 0;
107	status = 0;
108	x_size = 0;
109	y_size = 0;
110
111	while ((c = getopt(argc, argv, "a:crg:m:st")) != -1)
112		switch (c) {
113		case 'a':
114			if (strcasecmp(optarg, "on") == 0)
115				afc = 1;
116			else if (strcasecmp(optarg, "off") == 0)
117				afc = 0;
118			else {
119				usage();
120				exit(1);
121			}
122			break;
123
124		case 'c':
125			device = METEOR_INPUT_DEV2;
126			audio = -1;
127			break;
128
129		case 'r':
130			device = 0;
131			audio = AUDIO_INTERN;
132			break;
133
134		case 's':
135			device = METEOR_INPUT_DEV_SVIDEO;
136			audio = -1;
137			break;
138
139		case 't':
140			device = METEOR_INPUT_DEV1;
141			audio = -1;
142			break;
143
144		case 'g':
145			if (sscanf(optarg, "%ux%u", &x_size, &y_size) != 2
146			    || x_size == 0 || y_size == 0) {
147				usage();
148				exit(1);
149			}
150			break;
151
152		case 'm':
153			channel_set = atoi(optarg);
154			if (channel_set < 0 || channel_set > CHNLSET_MAX) {
155				usage();
156				exit(1);
157			}
158			break;
159
160		default:
161			usage();
162			exit(1);
163		}
164
165	if (optind < argc) {
166
167		/*
168		 * A number containing a decimal point is the frequency in MHz.
169		 */
170
171		if ((ptr = strchr(argv[optind], '.')) != NULL) {
172			freq = strtol(argv[optind], &endptr, 10) * 1000;
173			if (ptr != endptr) {
174				usage();
175				exit(1);
176			}
177
178			ptr++;
179
180			fraction = strtol(ptr, &endptr, 10);
181			if (!isdigit(*ptr) || *endptr != '\0') {
182				usage();
183				exit(1);
184			}
185
186			for (i = endptr - ptr; i > 3; i--)
187				fraction /= 10;
188			for (; i < 3; i++)
189				fraction *= 10;
190
191			freq += fraction;
192		}
193
194		/* An integer is the channel. */
195		else
196			channel = atoi(argv[optind]);
197	}
198
199	if (afc == -1 && audio == -1 && !device && x_size == 0 && y_size == 0
200	    && channel_set == -1 && !channel && !freq) {
201		usage();
202		exit(1);
203	}
204
205	tfd = open("/dev/cxm0", O_RDONLY);
206	if (tfd < 0) {
207		perror("open() of /dev/cxm0 failed.");
208		exit(1);
209	}
210
211	if (afc != -1)
212		if (ioctl(tfd, TVTUNER_SETAFC, &afc) < 0) {
213			perror("ioctl(tfd, TVTUNER_SETAFC) failed.");
214			status = 1;
215		}
216
217	if (device)
218		if (ioctl(tfd, METEORSINPUT, &device) < 0) {
219			perror("ioctl(tfd, METEORSINPUT) failed.");
220			status = 1;
221		}
222
223	if (audio != -1)
224		if (ioctl(tfd, BT848_SAUDIO, &audio) < 0) {
225			perror("ioctl(tfd, BT848_SAUDIO) failed.");
226			status = 1;
227		}
228
229	if (ioctl(tfd, BT848_GAUDIO, &audio) < 0) {
230		perror("ioctl(tfd, BT848_GAUDIO) failed.");
231		status = 1;
232	}
233
234	if (x_size && y_size) {
235		memset(&cap, 0, sizeof(cap));
236		cap.x_size = x_size;
237		cap.y_size = y_size;
238		if (ioctl(tfd, BT848_SCAPAREA, &cap) < 0) {
239			perror("ioctl(tfd, BT848_SCAPAREA) failed.");
240			status = 1;
241		}
242	}
243
244	if (channel_set != -1)
245		if (ioctl(tfd, TVTUNER_SETTYPE, &channel_set) < 0) {
246			perror("ioctl(tfd, TVTUNER_SETTYPE) failed.");
247			status = 1;
248		}
249
250	if (channel) {
251		if (ioctl(tfd, TVTUNER_SETCHNL, &channel) < 0) {
252			perror("ioctl(tfd, TVTUNER_SETCHNL) failed.");
253			status = 1;
254		}
255	} else if (freq) {
256		if (audio == AUDIO_INTERN) {
257			/* Convert from kHz to MHz * 100 */
258			freq = freq / 10;
259
260			if (ioctl(tfd, RADIO_SETFREQ, &freq) < 0) {
261				perror("ioctl(tfd, RADIO_SETFREQ) failed.");
262				status = 1;
263			}
264		} else {
265			/* Convert from kHz to MHz * 16 */
266			freq = (freq * 16) / 1000;
267
268			if (ioctl(tfd, TVTUNER_SETFREQ, &freq) < 0) {
269				perror("ioctl(tfd, TVTUNER_SETFREQ) failed.");
270				status = 1;
271			}
272		}
273	}
274
275	close(tfd);
276	exit(status);
277}
278