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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by John Wehle.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Set the channel of the tuner card.
32  */
33 
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/ioctl.h>
37 
38 #include <ctype.h>
39 #include <err.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #include <dev/video/meteor/ioctl_meteor.h>
47 #include <dev/video/bktr/ioctl_bt848.h>
48 
49 static void
50 usage(void)
51 {
52 	fprintf(stderr,
53 	    "usage: cxm_setchannel [-a {on|off}] [-c | -r | -s | -t] [-d unit] [-g geom]\n"
54 	    "                      [-m chnl_set] [chnl | freq]\n");
55 }
56 
57 int
58 main(int argc, char *argv[])
59 {
60 	char *ptr;
61 	char *endptr;
62 	char buf[255];
63 	int afc;
64 	int audio;
65 	int c;
66 	int channel_set;
67 	int i;
68 	int status;
69 	int tfd;
70 	int unit;
71 	unsigned int channel;
72 	unsigned int fraction;
73 	unsigned int freq;
74 	unsigned int x_size;
75 	unsigned int y_size;
76 	unsigned long device;
77 	struct bktr_capture_area cap;
78 
79 	afc = -1;
80 	audio = -1;
81 	channel = 0;
82 	channel_set = -1;
83 	device = 0;
84 	unit = 0;
85 	freq = 0;
86 	status = 0;
87 	x_size = 0;
88 	y_size = 0;
89 
90 	while ((c = getopt(argc, argv, "a:crstg:m:d:")) != -1)
91 		switch (c) {
92 		case 'a':
93 			if (strcasecmp(optarg, "on") == 0)
94 				afc = 1;
95 			else if (strcasecmp(optarg, "off") == 0)
96 				afc = 0;
97 			else {
98 				usage();
99 				exit(1);
100 			}
101 			break;
102 
103 		case 'c':
104 			device = METEOR_INPUT_DEV2;
105 			audio = -1;
106 			break;
107 
108 		case 'd':
109 			unit = atoi(optarg);
110 			break;
111 
112 		case 'r':
113 			device = 0;
114 			audio = AUDIO_INTERN;
115 			break;
116 
117 		case 's':
118 			device = METEOR_INPUT_DEV_SVIDEO;
119 			audio = -1;
120 			break;
121 
122 		case 't':
123 			device = METEOR_INPUT_DEV1;
124 			audio = -1;
125 			break;
126 
127 		case 'g':
128 			if (sscanf(optarg, "%ux%u", &x_size, &y_size) != 2 ||
129 			    x_size == 0 || y_size == 0) {
130 				usage();
131 				exit(1);
132 			}
133 			break;
134 
135 		case 'm':
136 			channel_set = atoi(optarg);
137 			if (channel_set < 0 || channel_set > CHNLSET_MAX) {
138 				usage();
139 				exit(1);
140 			}
141 			break;
142 
143 		default:
144 			usage();
145 			exit(1);
146 		}
147 
148 	if (optind < argc) {
149 
150 		/*
151 		 * A number containing a decimal point is the frequency in
152 		 * MHz.
153 		 */
154 
155 		if ((ptr = strchr(argv[optind], '.')) != NULL) {
156 			freq = strtol(argv[optind], &endptr, 10) * 1000;
157 			if (ptr != endptr) {
158 				usage();
159 				exit(1);
160 			}
161 			ptr++;
162 
163 			fraction = strtol(ptr, &endptr, 10);
164 			if (!isdigit(*ptr) || *endptr != '\0') {
165 				usage();
166 				exit(1);
167 			}
168 			for (i = endptr - ptr; i > 3; i--)
169 				fraction /= 10;
170 			for (; i < 3; i++)
171 				fraction *= 10;
172 
173 			freq += fraction;
174 		}
175 		/*
176 		 * An integer is the channel.
177 		 */
178 
179 		else
180 			channel = atoi(argv[optind]);
181 	}
182 	if (afc == -1 && audio == -1 && !device && x_size == 0 &&
183 	    y_size == 0 && channel_set == -1 && !channel && !freq) {
184 		usage();
185 		exit(1);
186 	}
187 
188 	sprintf(buf, "/dev/cxm%d", unit);
189 
190 	tfd = open(buf, O_RDONLY);
191 	if (tfd < 0) {
192 		warn("open() of /dev/cxm%d failed.", unit);
193 		exit(1);
194 	}
195 
196 	if (afc != -1) {
197 		if (ioctl(tfd, TVTUNER_SETAFC, &afc) < 0) {
198 			warn("ioctl( tfd, TVTUNER_SETAFC ) failed.");
199 			status = 1;
200 		}
201 	}
202 	if (device) {
203 		if (ioctl(tfd, METEORSINPUT, &device) < 0) {
204 			warn("ioctl( tfd, METEORSINPUT ) failed.");
205 			status = 1;
206 		}
207 	}
208 	if (audio != -1) {
209 		if (ioctl(tfd, BT848_SAUDIO, &audio) < 0) {
210 			warn("ioctl( tfd, BT848_SAUDIO ) failed.");
211 			status = 1;
212 		}
213 	}
214 	if (ioctl(tfd, BT848_GAUDIO, &audio) < 0) {
215 		warn("ioctl( tfd, BT848_GAUDIO ) failed.");
216 		status = 1;
217 	}
218 	if (x_size && y_size) {
219 		memset(&cap, 0, sizeof(cap));
220 		cap.x_size = x_size;
221 		cap.y_size = y_size;
222 		if (ioctl(tfd, BT848_SCAPAREA, &cap) < 0) {
223 			warn("ioctl( tfd, BT848_SCAPAREA ) failed.");
224 			status = 1;
225 		}
226 	}
227 	if (channel_set != -1) {
228 		if (ioctl(tfd, TVTUNER_SETTYPE, &channel_set) < 0) {
229 			warn("ioctl( tfd, TVTUNER_SETTYPE ) failed.");
230 			status = 1;
231 		}
232 	}
233 	if (channel) {
234 		if (ioctl(tfd, TVTUNER_SETCHNL, &channel) < 0) {
235 			warn("ioctl( tfd, TVTUNER_SETCHNL ) failed.");
236 			status = 1;
237 		}
238 	} else if (freq) {
239 		if (audio == AUDIO_INTERN) {
240 			/* Convert from kHz to MHz * 100 */
241 			freq = freq / 10;
242 
243 			if (ioctl(tfd, RADIO_SETFREQ, &freq) < 0) {
244 				warn("ioctl( tfd, RADIO_SETFREQ ) failed.");
245 				status = 1;
246 			}
247 		} else {
248 			/* Convert from kHz to MHz * 16 */
249 			freq = (freq * 16) / 1000;
250 
251 			if (ioctl(tfd, TVTUNER_SETFREQ, &freq) < 0) {
252 				warn("ioctl( tfd, TVTUNER_SETFREQ ) failed.");
253 				status = 1;
254 			}
255 		}
256 	}
257 	close(tfd);
258 	exit(status);
259 }
260