1214886Suqs/*-
2165023Sgrog * Copyright (c) 2003, 2004, 2005
3165023Sgrog *	John Wehle <john@feith.com>.  All rights reserved.
4165023Sgrog *
5165023Sgrog * Redistribution and use in source and binary forms, with or without
6165023Sgrog * modification, are permitted provided that the following conditions
7165023Sgrog * are met:
8165023Sgrog * 1. Redistributions of source code must retain the above copyright
9165023Sgrog *    notice, this list of conditions and the following disclaimer.
10165023Sgrog * 2. Redistributions in binary form must reproduce the above copyright
11165023Sgrog *    notice, this list of conditions and the following disclaimer in the
12165023Sgrog *    documentation and/or other materials provided with the distribution.
13165023Sgrog *
14165025Sgrog * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15165025Sgrog * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16165025Sgrog * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17165025Sgrog * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18165025Sgrog * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19165025Sgrog * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20165025Sgrog * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21165025Sgrog * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22165025Sgrog * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23165025Sgrog * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24165025Sgrog * SUCH DAMAGE.
25165023Sgrog *
26165023Sgrog *  $FreeBSD$
27165023Sgrog */
28165023Sgrog
29165026Sgrog/* Set the channel of the tuner card. */
30165023Sgrog
31214886Suqs#include <sys/ioctl.h>
32214886Suqs#include <sys/param.h>
33214886Suqs
34165023Sgrog#include <ctype.h>
35166960Sgrog#include <errno.h>
36165023Sgrog#include <fcntl.h>
37214886Suqs#include <stdio.h>
38214886Suqs#include <stdlib.h>
39165023Sgrog#include <string.h>
40165023Sgrog#include <unistd.h>
41165023Sgrog
42214886Suqs#include <dev/bktr/ioctl_meteor.h>
43214886Suqs#include <dev/bktr/ioctl_bt848.h>
44165023Sgrog
45165023Sgrogstatic void
46214886Suqsusage(void)
47165023Sgrog{
48165026Sgrog	printf
49165026Sgrog	    ("Usage: setchannel [-a {on|off}] [-c | -r | -s | -t] "
50165026Sgrog	    "[-g geom] [-m chnl_set] [chnl | freq]\n"
51165026Sgrog	    "  -a    Enable / disable AFC.\n"
52166959Sgrog	    "  -c    Select composite input.\n"
53214886Suqs	    "  -d    Select tuner unit number.\n"
54214886Suqs	    "  -r    Select radio input.\n"
55166959Sgrog	    "  -s    Select svideo input.\n"
56214886Suqs	    "  -t    Select tuner.\n"
57166959Sgrog	    "  -g    Select geometry.\n"
58214886Suqs	    "          352x240 or 352x288 = VCD\n"
59165026Sgrog	    "          480x480 or 480x576 = SVCD\n"
60165026Sgrog	    "          352x480 or 352x576 = DVD (half D1)\n"
61165026Sgrog	    "          720x480 or 720x576 = DVD (full D1)\n"
62165026Sgrog	    "  -m    Select channel set / system.\n"
63165026Sgrog	    "          0 = Tuner Default\n"
64165026Sgrog	    "          %u = US Broadcast / NTSC\n"
65165026Sgrog	    "          %u = US Cable / NTSC\n"
66165026Sgrog	    "          %u = Western Europe / PAL\n"
67165026Sgrog	    "          %u = Japan Broadcast / NTSC\n"
68165026Sgrog	    "          %u = Japan Cable / NTSC\n"
69165026Sgrog	    "          %u = Australia / PAL\n"
70166959Sgrog	    "          %u = France / SECAM\n"
71214886Suqs	    "  chnl  Channel\n"
72165026Sgrog	    "  freq  Frequency in MHz (must include decimal point).\n",
73165026Sgrog	    CHNLSET_NABCST, CHNLSET_CABLEIRC, CHNLSET_WEUROPE, CHNLSET_JPNBCST,
74165026Sgrog	    CHNLSET_JPNCABLE, CHNLSET_AUSTRALIA, CHNLSET_FRANCE);
75165023Sgrog}
76165023Sgrog
77166960Sgrog#define DEVNAME_BASE "/dev/cxm"
78166960Sgrogchar dev_name[16];
79166960Sgrog
80165026Sgrogint
81165026Sgrogmain(int argc, char *argv[])
82165023Sgrog{
83165026Sgrog	char *ptr;
84165026Sgrog	char *endptr;
85165026Sgrog	int afc;
86165026Sgrog	int audio;
87165026Sgrog	int c;
88165026Sgrog	int channel_set;
89165026Sgrog	int i;
90165026Sgrog	int status;
91214886Suqs	int unit;
92165026Sgrog	int tfd;
93165026Sgrog	unsigned int channel;
94165026Sgrog	unsigned int fraction;
95165026Sgrog	unsigned int freq;
96165026Sgrog	unsigned int x_size;
97165026Sgrog	unsigned int y_size;
98165026Sgrog	unsigned long device;
99165026Sgrog	struct bktr_capture_area cap;
100165023Sgrog
101165026Sgrog	afc = -1;
102165026Sgrog	audio = -1;
103165026Sgrog	channel = 0;
104165026Sgrog	channel_set = -1;
105165026Sgrog	device = 0;
106165026Sgrog	freq = 0;
107165026Sgrog	status = 0;
108214886Suqs	unit = 0;
109165026Sgrog	x_size = 0;
110165026Sgrog	y_size = 0;
111165023Sgrog
112166960Sgrog	while ((c = getopt(argc, argv, "a:cd:rg:m:st")) != -1)
113165026Sgrog		switch (c) {
114166960Sgrog
115165026Sgrog		case 'a':
116165026Sgrog			if (strcasecmp(optarg, "on") == 0)
117165026Sgrog				afc = 1;
118165026Sgrog			else if (strcasecmp(optarg, "off") == 0)
119165026Sgrog				afc = 0;
120165026Sgrog			else {
121165026Sgrog				usage();
122165026Sgrog				exit(1);
123165026Sgrog			}
124165026Sgrog			break;
125165023Sgrog
126165026Sgrog		case 'c':
127165026Sgrog			device = METEOR_INPUT_DEV2;
128165026Sgrog			audio = -1;
129165026Sgrog			break;
130165023Sgrog
131166960Sgrog		case 'd':
132166960Sgrog			unit = atoi(optarg);
133166960Sgrog			break;
134166960Sgrog
135165026Sgrog		case 'r':
136165026Sgrog			device = 0;
137165026Sgrog			audio = AUDIO_INTERN;
138165026Sgrog			break;
139165023Sgrog
140165026Sgrog		case 's':
141165026Sgrog			device = METEOR_INPUT_DEV_SVIDEO;
142165026Sgrog			audio = -1;
143165026Sgrog			break;
144165023Sgrog
145165026Sgrog		case 't':
146165026Sgrog			device = METEOR_INPUT_DEV1;
147165026Sgrog			audio = -1;
148165026Sgrog			break;
149165023Sgrog
150165026Sgrog		case 'g':
151165026Sgrog			if (sscanf(optarg, "%ux%u", &x_size, &y_size) != 2
152165026Sgrog			    || x_size == 0 || y_size == 0) {
153165026Sgrog				usage();
154165026Sgrog				exit(1);
155165026Sgrog			}
156165026Sgrog			break;
157165023Sgrog
158165026Sgrog		case 'm':
159165026Sgrog			channel_set = atoi(optarg);
160165026Sgrog			if (channel_set < 0 || channel_set > CHNLSET_MAX) {
161165026Sgrog				usage();
162165026Sgrog				exit(1);
163165026Sgrog			}
164165026Sgrog			break;
165165023Sgrog
166165026Sgrog		default:
167165026Sgrog			usage();
168165026Sgrog			exit(1);
169165026Sgrog		}
170165023Sgrog
171165026Sgrog	if (optind < argc) {
172165023Sgrog
173165026Sgrog		/*
174165026Sgrog		 * A number containing a decimal point is the frequency in MHz.
175165026Sgrog		 */
176165023Sgrog
177165026Sgrog		if ((ptr = strchr(argv[optind], '.')) != NULL) {
178165026Sgrog			freq = strtol(argv[optind], &endptr, 10) * 1000;
179165026Sgrog			if (ptr != endptr) {
180165026Sgrog				usage();
181165026Sgrog				exit(1);
182165026Sgrog			}
183165023Sgrog
184165026Sgrog			ptr++;
185165023Sgrog
186165026Sgrog			fraction = strtol(ptr, &endptr, 10);
187165026Sgrog			if (!isdigit(*ptr) || *endptr != '\0') {
188165026Sgrog				usage();
189165026Sgrog				exit(1);
190165026Sgrog			}
191165023Sgrog
192165026Sgrog			for (i = endptr - ptr; i > 3; i--)
193165026Sgrog				fraction /= 10;
194165026Sgrog			for (; i < 3; i++)
195165026Sgrog				fraction *= 10;
196165023Sgrog
197165026Sgrog			freq += fraction;
198165026Sgrog		}
199165023Sgrog
200165026Sgrog		/* An integer is the channel. */
201165026Sgrog		else
202165026Sgrog			channel = atoi(argv[optind]);
203165026Sgrog	}
204165023Sgrog
205165026Sgrog	if (afc == -1 && audio == -1 && !device && x_size == 0 && y_size == 0
206165026Sgrog	    && channel_set == -1 && !channel && !freq) {
207165026Sgrog		usage();
208165026Sgrog		exit(1);
209165026Sgrog	}
210165023Sgrog
211214886Suqs	sprintf(dev_name, DEVNAME_BASE "%d", unit);
212214886Suqs	tfd = open(dev_name, O_RDONLY);
213165026Sgrog	if (tfd < 0) {
214166960Sgrog		fprintf(stderr, "Can't open %s: %s (%d)\n", dev_name,
215214886Suqs		    strerror(errno), errno);
216165026Sgrog		exit(1);
217165026Sgrog	}
218165023Sgrog
219165026Sgrog	if (afc != -1)
220165026Sgrog		if (ioctl(tfd, TVTUNER_SETAFC, &afc) < 0) {
221165026Sgrog			perror("ioctl(tfd, TVTUNER_SETAFC) failed.");
222165026Sgrog			status = 1;
223165026Sgrog		}
224165023Sgrog
225165026Sgrog	if (device)
226165026Sgrog		if (ioctl(tfd, METEORSINPUT, &device) < 0) {
227165026Sgrog			perror("ioctl(tfd, METEORSINPUT) failed.");
228165026Sgrog			status = 1;
229165026Sgrog		}
230165023Sgrog
231165026Sgrog	if (audio != -1)
232165026Sgrog		if (ioctl(tfd, BT848_SAUDIO, &audio) < 0) {
233165026Sgrog			perror("ioctl(tfd, BT848_SAUDIO) failed.");
234165026Sgrog			status = 1;
235165026Sgrog		}
236165023Sgrog
237165026Sgrog	if (ioctl(tfd, BT848_GAUDIO, &audio) < 0) {
238165026Sgrog		perror("ioctl(tfd, BT848_GAUDIO) failed.");
239165026Sgrog		status = 1;
240165026Sgrog	}
241165023Sgrog
242165026Sgrog	if (x_size && y_size) {
243165026Sgrog		memset(&cap, 0, sizeof(cap));
244165026Sgrog		cap.x_size = x_size;
245165026Sgrog		cap.y_size = y_size;
246165026Sgrog		if (ioctl(tfd, BT848_SCAPAREA, &cap) < 0) {
247165026Sgrog			perror("ioctl(tfd, BT848_SCAPAREA) failed.");
248165026Sgrog			status = 1;
249165026Sgrog		}
250165026Sgrog	}
251165023Sgrog
252165026Sgrog	if (channel_set != -1)
253165026Sgrog		if (ioctl(tfd, TVTUNER_SETTYPE, &channel_set) < 0) {
254165026Sgrog			perror("ioctl(tfd, TVTUNER_SETTYPE) failed.");
255165026Sgrog			status = 1;
256165026Sgrog		}
257165023Sgrog
258165026Sgrog	if (channel) {
259165026Sgrog		if (ioctl(tfd, TVTUNER_SETCHNL, &channel) < 0) {
260165026Sgrog			perror("ioctl(tfd, TVTUNER_SETCHNL) failed.");
261165026Sgrog			status = 1;
262165026Sgrog		}
263165026Sgrog	} else if (freq) {
264165026Sgrog		if (audio == AUDIO_INTERN) {
265165026Sgrog			/* Convert from kHz to MHz * 100 */
266165026Sgrog			freq = freq / 10;
267165023Sgrog
268165026Sgrog			if (ioctl(tfd, RADIO_SETFREQ, &freq) < 0) {
269165026Sgrog				perror("ioctl(tfd, RADIO_SETFREQ) failed.");
270165026Sgrog				status = 1;
271165026Sgrog			}
272165026Sgrog		} else {
273165026Sgrog			/* Convert from kHz to MHz * 16 */
274165026Sgrog			freq = (freq * 16) / 1000;
275165023Sgrog
276165026Sgrog			if (ioctl(tfd, TVTUNER_SETFREQ, &freq) < 0) {
277165026Sgrog				perror("ioctl(tfd, TVTUNER_SETFREQ) failed.");
278165026Sgrog				status = 1;
279165026Sgrog			}
280165026Sgrog		}
281165026Sgrog	}
282165023Sgrog
283165026Sgrog	close(tfd);
284165026Sgrog	exit(status);
285165023Sgrog}
286