1 /*
2     Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo dot com>
3 
4     Cleanup and VBI and audio in/out options:
5     Copyright (C) 2004  Hans Verkuil <hverkuil@xs4all.nl>
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
20  */
21 
22 #include <config.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <inttypes.h>
28 #include <getopt.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <sys/ioctl.h>
35 #include <sys/time.h>
36 #include <math.h>
37 
38 #include <linux/videodev2.h>
39 
40 /* copied from cx18-driver.h */
41 #define CX18_DBGFLG_WARN  (1 << 0)
42 #define CX18_DBGFLG_INFO  (1 << 1)
43 #define CX18_DBGFLG_API   (1 << 2)
44 #define CX18_DBGFLG_DMA   (1 << 3)
45 #define CX18_DBGFLG_IOCTL (1 << 4)
46 #define CX18_DBGFLG_FILE  (1 << 5)
47 #define CX18_DBGFLG_I2C   (1 << 6)
48 #define CX18_DBGFLG_IRQ   (1 << 7)
49 /* Flag to turn on high volume debugging */
50 #define CX18_DBGFLG_HIGHVOL (1 << 8)
51 
52 /* Internals copied from media/v4l2-common.h */
53 #define VIDIOC_INT_RESET            	_IOW('d', 102, uint32_t)
54 
55 #define __stringify_1(x)	#x
56 #define __stringify(x)		__stringify_1(x)
57 
58 /* GPIO */
59 #define CX18_REG_GPIO_IN     0x02c72010
60 #define CX18_REG_GPIO_OUT1   0x02c78100
61 #define CX18_REG_GPIO_DIR1   0x02c78108
62 #define CX18_REG_GPIO_OUT2   0x02c78104
63 #define CX18_REG_GPIO_DIR2   0x02c7810c
64 
65 /* Options */
66 enum Option {
67 	OptSetDebugLevel = 'D',
68 	OptSetDevice = 'd',
69 	OptGetDebugLevel = 'e',
70 	OptHelp = 'h',
71 	OptSetGPIO = 'i',
72 	OptListGPIO = 'I',
73 	OptReset = 128,
74 	OptVersion,
75 	OptLast = 256
76 };
77 
78 static char options[OptLast];
79 
80 static struct option long_options[] = {
81 	/* Please keep in alphabetical order of the short option.
82 	   That makes it easier to see which options are still free. */
83 	{"set-debug", required_argument, 0, OptSetDebugLevel},
84 	{"device", required_argument, 0, OptSetDevice},
85 	{"get-debug", no_argument, 0, OptGetDebugLevel},
86 	{"help", no_argument, 0, OptHelp},
87 	{"set-gpio", required_argument, 0, OptSetGPIO},
88 	{"list-gpio", no_argument, 0, OptListGPIO},
89 	{"reset", required_argument, 0, OptReset},
90 	{"version", no_argument, 0, OptVersion},
91 	{0, 0, 0, 0}
92 };
93 
usage(void)94 static void usage(void)
95 {
96 	printf("Usage:\n");
97 	printf("  -d, --device <dev> use device <dev> instead of /dev/video0\n");
98 	printf("  -h, --help         display this help message\n");
99 	printf("  --reset <mask>     reset the infrared receiver (1) or digitizer (2) [VIDIOC_INT_RESET]\n");
100 	printf("  --version          shows the version number of this utility.\n");
101 	printf("                     It should match the driver version.\n");
102 	printf("\n");
103 	printf("Expert options:\n");
104 	printf("  -D, --set-debug <level>\n");
105 	printf("                     set the module debug variable\n");
106 	printf("                        1/0x0001: warning\n");
107 	printf("                        2/0x0002: info\n");
108 	printf("                        4/0x0004: mailbox\n");
109 	printf("                        8/0x0008: dma\n");
110 	printf("                       16/0x0010: ioctl\n");
111 	printf("                       32/0x0020: file\n");
112 	printf("                       64/0x0040: i2c\n");
113 	printf("                      128/0x0080: irq\n");
114 	printf("                      256/0x0100: high volume\n");
115 	printf("  -e, --get-debug    query the module debug variable\n");
116 	printf("  -I, --list-gpio\n");
117 	printf("                     show GPIO input/direction/output bits\n");
118 	printf("  -i, --set-gpio [dir=<dir>,]val=<val>\n");
119 	printf("                     set GPIO direction bits to <dir> and set output to <val>\n");
120 	exit(0);
121 }
122 
print_debug_mask(int mask)123 static void print_debug_mask(int mask)
124 {
125 #define MASK_OR_NOTHING (mask ? " | " : "")
126 	if (mask & CX18_DBGFLG_WARN) {
127 		mask &= ~CX18_DBGFLG_WARN;
128 		printf("CX18_DBGFLG_WARN%s", MASK_OR_NOTHING);
129 	}
130 	if (mask & CX18_DBGFLG_INFO) {
131 		mask &= ~CX18_DBGFLG_INFO;
132 		printf("CX18_DBGFLG_INFO%s", MASK_OR_NOTHING);
133 	}
134 	if (mask & CX18_DBGFLG_API) {
135 		mask &= ~CX18_DBGFLG_API;
136 		printf("CX18_DBGFLG_API%s", MASK_OR_NOTHING);
137 	}
138 	if (mask & CX18_DBGFLG_DMA) {
139 		mask &= ~CX18_DBGFLG_DMA;
140 		printf("CX18_DBGFLG_DMA%s", MASK_OR_NOTHING);
141 	}
142 	if (mask & CX18_DBGFLG_IOCTL) {
143 		mask &= ~CX18_DBGFLG_IOCTL;
144 		printf("CX18_DBGFLG_IOCTL%s", MASK_OR_NOTHING);
145 	}
146 	if (mask & CX18_DBGFLG_FILE) {
147 		mask &= ~CX18_DBGFLG_FILE;
148 		printf("CX18_DBGFLG_FILE%s", MASK_OR_NOTHING);
149 	}
150 	if (mask & CX18_DBGFLG_I2C) {
151 		mask &= ~CX18_DBGFLG_I2C;
152 		printf("CX18_DBGFLG_I2C%s", MASK_OR_NOTHING);
153 	}
154 	if (mask & CX18_DBGFLG_IRQ) {
155 		mask &= ~CX18_DBGFLG_IRQ;
156 		printf("CX18_DBGFLG_IRQ%s", MASK_OR_NOTHING);
157 	}
158 	if (mask & CX18_DBGFLG_HIGHVOL) {
159 		mask &= ~CX18_DBGFLG_HIGHVOL;
160 		printf("CX18_DBGFLG_HIGHVOL%s", MASK_OR_NOTHING);
161 	}
162 	if (mask)
163 		printf("0x%08x", mask);
164 	printf("\n");
165 }
166 
dowrite(const char * buf,const char * fn)167 static int dowrite(const char *buf, const char *fn)
168 {
169 	FILE *f = fopen(fn, "w");
170 	if (f == NULL) {
171 		printf("failed: %s\n", strerror(errno));
172 		return errno;
173 	}
174 	fprintf(f, "%s", buf);
175 	fclose(f);
176 	return 0;
177 }
178 
doread(const char * fn)179 static char *doread(const char *fn)
180 {
181 	static char buf[1000];
182 	FILE *f = fopen(fn, "r");
183 	int s;
184 
185 	if (f == NULL) {
186 		printf("failed: %s\n", strerror(errno));
187 		return NULL;
188 	}
189 	s = fread(buf, 1, sizeof(buf) - 1, f);
190 	buf[s] = 0;
191 	fclose(f);
192 	return buf;
193 }
194 
doioctl(int fd,unsigned long int request,void * parm,const char * name)195 static int doioctl(int fd, unsigned long int request, void *parm, const char *name)
196 {
197 	int retVal;
198 
199 	printf("ioctl %s ", name);
200 	retVal = ioctl(fd, request, parm);
201 	if (retVal < 0)
202 		printf("failed: %s\n", strerror(errno));
203 	else
204 		printf("ok\n");
205 
206 	return retVal;
207 }
208 
main(int argc,char ** argv)209 int main(int argc, char **argv)
210 {
211 	char *value, *subs;
212 	int i;
213 	char *subopts[] = {
214 #define SUB_VAL				0
215 		"val",
216 #define SUB_DIR				1
217 		"dir",
218 
219 		NULL
220 	};
221 
222 	int fd = -1;
223 
224 	/* bitfield for OptSetCodec */
225 
226 	/* command args */
227 	const char *device = "/dev/video0";	/* -d device */
228 	int ch;
229 	unsigned int gpio_out = 0x0;	/* GPIO output data */
230 	unsigned int gpio_dir = 0x0;	/* GPIO direction bits */
231 	int gpio_set_dir = 0;
232 	int debug_level = 0;
233 	uint32_t reset = 0;
234 	int new_debug_level, gdebug_level;
235 	char short_options[26 * 2 * 2 + 1];
236 
237 	if (argc == 1) {
238 		usage();
239 		return 0;
240 	}
241 	while (1) {
242 		int option_index = 0;
243 		int idx = 0;
244 
245 		for (i = 0; long_options[i].name; i++) {
246 			if (!isalpha(long_options[i].val))
247 				continue;
248 			short_options[idx++] = long_options[i].val;
249 			if (long_options[i].has_arg == required_argument)
250 				short_options[idx++] = ':';
251 		}
252 		short_options[idx] = 0;
253 		ch = getopt_long(argc, argv, short_options,
254 				 long_options, &option_index);
255 		if (ch == -1)
256 			break;
257 
258 		options[ch] = 1;
259 		switch (ch) {
260 		case OptHelp:
261 			usage();
262 			return 0;
263 		case OptSetDebugLevel:{
264 			debug_level = strtol(optarg, 0L, 0);
265 			break;
266 		}
267 		case OptSetDevice:
268 			device = optarg;
269 			if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) {
270 				static char newdev[20];
271 
272 				sprintf(newdev, "/dev/video%s", device);
273 				device = newdev;
274 			}
275 			break;
276 		case OptReset:
277 			reset = strtol(optarg, 0L, 0);
278 			break;
279 		case OptSetGPIO:
280 			subs = optarg;
281 			while (*subs != '\0') {
282 				switch (getsubopt(&subs, subopts, &value)) {
283 				case SUB_DIR:
284 					if (value == NULL) {
285 						fprintf(stderr,
286 							"No value given to suboption <dir>\n");
287 						usage();
288 						exit(EXIT_FAILURE);
289 					}
290 					gpio_dir = strtoul(value, 0L, 0);
291 					gpio_set_dir = 1;
292 					break;
293 				case SUB_VAL:
294 					if (value == NULL) {
295 						fprintf(stderr,
296 							"No value given to suboption <val>\n");
297 						usage();
298 						exit(EXIT_FAILURE);
299 					}
300 					gpio_out =
301 					    (unsigned short)strtoul(value, 0L, 0);
302 					break;
303 				default:
304 					fprintf(stderr,
305 						"Invalid suboptions specified\n");
306 					usage();
307 					exit(EXIT_FAILURE);
308 					break;
309 				}
310 			}
311 			break;
312 		case ':':
313 			fprintf(stderr, "Option `%s' requires a value\n",
314 				argv[optind]);
315 			usage();
316 			return 1;
317 		case '?':
318 			fprintf(stderr, "Unknown argument `%s'\n",
319 				argv[optind]);
320 			usage();
321 			return 1;
322 		}
323 	}
324 	if (optind < argc) {
325 		printf("unknown arguments: ");
326 		while (optind < argc)
327 			printf("%s ", argv[optind++]);
328 		printf("\n");
329 		usage();
330 		return 1;
331 	}
332 
333 	fd = open(device, O_RDWR);
334 	if (fd < 0) {
335 		fprintf(stderr, "Failed to open %s: %s\n", device,
336 			strerror(errno));
337 		exit(EXIT_FAILURE);
338 	}
339 
340 	/* Setting Opts */
341 	if (options[OptSetGPIO]) {
342 		struct v4l2_dbg_register reg;
343 
344 		reg.match.type = V4L2_CHIP_MATCH_HOST;
345 		reg.match.addr = 0;
346 		reg.reg = CX18_REG_GPIO_DIR1;
347 		reg.val = ((gpio_dir & 0xffff) << 16);
348 		if (gpio_set_dir && doioctl(fd, VIDIOC_DBG_S_REGISTER, &reg,
349 			"VIDIOC_DBG_S_REGISTER") == 0)
350 			printf("GPIO dir 1 set to 0x%08llx\n", reg.val);
351 		reg.reg = CX18_REG_GPIO_DIR2;
352 		reg.val = (gpio_dir & 0xffff0000);
353 		if (gpio_set_dir && doioctl(fd, VIDIOC_DBG_S_REGISTER, &reg,
354 			"VIDIOC_DBG_S_REGISTER") == 0)
355 			printf("GPIO dir 2 set to 0x%08llx\n", reg.val);
356 		reg.reg = CX18_REG_GPIO_OUT1;
357 		reg.val = ((gpio_dir & 0xffff) << 16) | (gpio_out & 0xffff);
358 		if (doioctl(fd, VIDIOC_DBG_S_REGISTER, &reg,
359 			"VIDIOC_DBG_S_REGISTER") == 0)
360 			printf("GPIO out 1 set to 0x%08llx\n", reg.val);
361 		reg.reg = CX18_REG_GPIO_OUT2;
362 		reg.val = (gpio_dir & 0xffff0000) | (gpio_out >> 16);
363 		if (doioctl(fd, VIDIOC_DBG_S_REGISTER, &reg,
364 			"VIDIOC_DBG_S_REGISTER") == 0)
365 			printf("GPIO out 2 set to 0x%08llx\n", reg.val);
366 	}
367 
368 	if (options[OptListGPIO]) {
369 		struct v4l2_dbg_register reg;
370 
371 		reg.match.type = V4L2_CHIP_MATCH_HOST;
372 		reg.match.addr = 0;
373 		reg.reg = CX18_REG_GPIO_IN;
374 		if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &reg) == 0)
375 			printf("GPIO in:  0x%04llx\n", reg.val);
376 		reg.reg = CX18_REG_GPIO_DIR1;
377 		if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &reg) == 0)
378 			printf("GPIO dir: 0x%04llx\n", reg.val);
379 		reg.reg = CX18_REG_GPIO_OUT1;
380 		if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &reg) == 0)
381 			printf("GPIO out: 0x%04llx\n", reg.val);
382 	}
383 
384 	if (options[OptSetDebugLevel]) {
385 		char buf[20];
386 		new_debug_level = debug_level;
387 
388 		sprintf(buf, "%d", debug_level);
389 		if (dowrite(buf, "/sys/module/cx18/parameters/debug") == 0) {
390 			printf(" set debug level: ");
391 			print_debug_mask(new_debug_level);
392 			printf("\n");
393 		}
394 	}
395 
396 	if (options[OptGetDebugLevel]) {
397 		char *buf;
398 
399 		gdebug_level = 0;
400 		buf = doread("/sys/module/cx18/parameters/debug");
401 		if (buf) {
402 			gdebug_level = atol(buf);
403 			printf(" debug level: ");
404 			print_debug_mask(gdebug_level);
405 			printf("\n");
406 		}
407 	}
408 
409 	if (options[OptReset])
410 		doioctl(fd, VIDIOC_INT_RESET, &reset, "VIDIOC_INT_RESET");
411 
412 	if (options[OptVersion])
413 		printf("cx18ctl version " V4L_UTILS_VERSION "\n");
414 
415 	close(fd);
416 	exit(0);
417 }
418