setchannel.c revision 165026
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 165026 2006-12-09 02:44:09Z 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" "  -r    Select radio input.\n"
58	    "  -s    Select svideo input.\n" "  -t    Select tuner.\n"
59	    "  -g    Select geometry.\n" "          352x240 or 352x288 = VCD\n"
60	    "          480x480 or 480x576 = SVCD\n"
61	    "          352x480 or 352x576 = DVD (half D1)\n"
62	    "          720x480 or 720x576 = DVD (full D1)\n"
63	    "  -m    Select channel set / system.\n"
64	    "          0 = Tuner Default\n"
65	    "          %u = US Broadcast / NTSC\n"
66	    "          %u = US Cable / NTSC\n"
67	    "          %u = Western Europe / PAL\n"
68	    "          %u = Japan Broadcast / NTSC\n"
69	    "          %u = Japan Cable / NTSC\n"
70	    "          %u = Australia / PAL\n"
71	    "          %u = France / SECAM\n" "  chnl  Channel\n"
72	    "  freq  Frequency in MHz (must include decimal point).\n",
73	    CHNLSET_NABCST, CHNLSET_CABLEIRC, CHNLSET_WEUROPE, CHNLSET_JPNBCST,
74	    CHNLSET_JPNCABLE, CHNLSET_AUSTRALIA, CHNLSET_FRANCE);
75}
76
77int
78main(int argc, char *argv[])
79{
80	char *ptr;
81	char *endptr;
82	int afc;
83	int audio;
84	int c;
85	int channel_set;
86	int i;
87	int status;
88	int tfd;
89	unsigned int channel;
90	unsigned int fraction;
91	unsigned int freq;
92	unsigned int x_size;
93	unsigned int y_size;
94	unsigned long device;
95	struct bktr_capture_area cap;
96
97	afc = -1;
98	audio = -1;
99	channel = 0;
100	channel_set = -1;
101	device = 0;
102	freq = 0;
103	status = 0;
104	x_size = 0;
105	y_size = 0;
106
107	while ((c = getopt(argc, argv, "a:crstg:m:")) != -1)
108		switch (c) {
109		case 'a':
110			if (strcasecmp(optarg, "on") == 0)
111				afc = 1;
112			else if (strcasecmp(optarg, "off") == 0)
113				afc = 0;
114			else {
115				usage();
116				exit(1);
117			}
118			break;
119
120		case 'c':
121			device = METEOR_INPUT_DEV2;
122			audio = -1;
123			break;
124
125		case 'r':
126			device = 0;
127			audio = AUDIO_INTERN;
128			break;
129
130		case 's':
131			device = METEOR_INPUT_DEV_SVIDEO;
132			audio = -1;
133			break;
134
135		case 't':
136			device = METEOR_INPUT_DEV1;
137			audio = -1;
138			break;
139
140		case 'g':
141			if (sscanf(optarg, "%ux%u", &x_size, &y_size) != 2
142			    || x_size == 0 || y_size == 0) {
143				usage();
144				exit(1);
145			}
146			break;
147
148		case 'm':
149			channel_set = atoi(optarg);
150			if (channel_set < 0 || channel_set > CHNLSET_MAX) {
151				usage();
152				exit(1);
153			}
154			break;
155
156		default:
157			usage();
158			exit(1);
159		}
160
161	if (optind < argc) {
162
163		/*
164		 * A number containing a decimal point is the frequency in MHz.
165		 */
166
167		if ((ptr = strchr(argv[optind], '.')) != NULL) {
168			freq = strtol(argv[optind], &endptr, 10) * 1000;
169			if (ptr != endptr) {
170				usage();
171				exit(1);
172			}
173
174			ptr++;
175
176			fraction = strtol(ptr, &endptr, 10);
177			if (!isdigit(*ptr) || *endptr != '\0') {
178				usage();
179				exit(1);
180			}
181
182			for (i = endptr - ptr; i > 3; i--)
183				fraction /= 10;
184			for (; i < 3; i++)
185				fraction *= 10;
186
187			freq += fraction;
188		}
189
190		/* An integer is the channel. */
191		else
192			channel = atoi(argv[optind]);
193	}
194
195	if (afc == -1 && audio == -1 && !device && x_size == 0 && y_size == 0
196	    && channel_set == -1 && !channel && !freq) {
197		usage();
198		exit(1);
199	}
200
201	tfd = open("/dev/cxm0", O_RDONLY);
202	if (tfd < 0) {
203		perror("open() of /dev/cxm0 failed.");
204		exit(1);
205	}
206
207	if (afc != -1)
208		if (ioctl(tfd, TVTUNER_SETAFC, &afc) < 0) {
209			perror("ioctl(tfd, TVTUNER_SETAFC) failed.");
210			status = 1;
211		}
212
213	if (device)
214		if (ioctl(tfd, METEORSINPUT, &device) < 0) {
215			perror("ioctl(tfd, METEORSINPUT) failed.");
216			status = 1;
217		}
218
219	if (audio != -1)
220		if (ioctl(tfd, BT848_SAUDIO, &audio) < 0) {
221			perror("ioctl(tfd, BT848_SAUDIO) failed.");
222			status = 1;
223		}
224
225	if (ioctl(tfd, BT848_GAUDIO, &audio) < 0) {
226		perror("ioctl(tfd, BT848_GAUDIO) failed.");
227		status = 1;
228	}
229
230	if (x_size && y_size) {
231		memset(&cap, 0, sizeof(cap));
232		cap.x_size = x_size;
233		cap.y_size = y_size;
234		if (ioctl(tfd, BT848_SCAPAREA, &cap) < 0) {
235			perror("ioctl(tfd, BT848_SCAPAREA) failed.");
236			status = 1;
237		}
238	}
239
240	if (channel_set != -1)
241		if (ioctl(tfd, TVTUNER_SETTYPE, &channel_set) < 0) {
242			perror("ioctl(tfd, TVTUNER_SETTYPE) failed.");
243			status = 1;
244		}
245
246	if (channel) {
247		if (ioctl(tfd, TVTUNER_SETCHNL, &channel) < 0) {
248			perror("ioctl(tfd, TVTUNER_SETCHNL) failed.");
249			status = 1;
250		}
251	} else if (freq) {
252		if (audio == AUDIO_INTERN) {
253			/* Convert from kHz to MHz * 100 */
254			freq = freq / 10;
255
256			if (ioctl(tfd, RADIO_SETFREQ, &freq) < 0) {
257				perror("ioctl(tfd, RADIO_SETFREQ) failed.");
258				status = 1;
259			}
260		} else {
261			/* Convert from kHz to MHz * 16 */
262			freq = (freq * 16) / 1000;
263
264			if (ioctl(tfd, TVTUNER_SETFREQ, &freq) < 0) {
265				perror("ioctl(tfd, TVTUNER_SETFREQ) failed.");
266				status = 1;
267			}
268		}
269	}
270
271	close(tfd);
272	exit(status);
273}
274