• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <unistd.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <inttypes.h>
27 #include <getopt.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <sys/ioctl.h>
34 #include <sys/time.h>
35 #include <math.h>
36 
37 #include <linux/videodev2.h>
38 #include <v4l-getsubopt.h>
39 
40 /* copied from ivtv-driver.h */
41 #define IVTV_DBGFLG_WARN    (1 << 0)
42 #define IVTV_DBGFLG_INFO    (1 << 1)
43 #define IVTV_DBGFLG_MB      (1 << 2)
44 #define IVTV_DBGFLG_IOCTL   (1 << 3)
45 #define IVTV_DBGFLG_FILE    (1 << 4)
46 #define IVTV_DBGFLG_DMA     (1 << 5)
47 #define IVTV_DBGFLG_IRQ     (1 << 6)
48 #define IVTV_DBGFLG_DEC     (1 << 7)
49 #define IVTV_DBGFLG_YUV     (1 << 8)
50 #define IVTV_DBGFLG_I2C     (1 << 9)
51 /* Flag to turn on high volume debugging */
52 #define IVTV_DBGFLG_HIGHVOL (1 << 10)
53 
54 /* Internals copied from media/v4l2-common.h */
55 #define VIDIOC_INT_RESET            	_IOW('d', 102, __u32)
56 
57 #include <linux/ivtv.h>
58 
59 /* GPIO */
60 #define IVTV_REG_GPIO_IN_OFFSET    (0x9008 + 0x02000000)
61 #define IVTV_REG_GPIO_OUT_OFFSET   (0x900c + 0x02000000)
62 #define IVTV_REG_GPIO_DIR_OFFSET   (0x9020 + 0x02000000)
63 
64 /* Options */
65 enum Option {
66 	OptSetDebugLevel = 'D',
67 	OptSetDevice = 'd',
68 	OptGetDebugLevel = 'e',
69 	OptHelp = 'h',
70 	OptSetGPIO = 'i',
71 	OptListGPIO = 'I',
72 	OptPassThrough = 'K',
73 	OptReset = 128,
74 	OptSetYuvMode,
75 	OptGetYuvMode,
76 	OptLast = 256
77 };
78 
79 static char options[OptLast];
80 
81 static int app_result;
82 
83 static struct option long_options[] = {
84 	/* Please keep in alphabetical order of the short option.
85 	   That makes it easier to see which options are still free. */
86 	{"set-debug", required_argument, 0, OptSetDebugLevel},
87 	{"device", required_argument, 0, OptSetDevice},
88 	{"get-debug", no_argument, 0, OptGetDebugLevel},
89 	{"help", no_argument, 0, OptHelp},
90 	{"set-gpio", required_argument, 0, OptSetGPIO},
91 	{"list-gpio", no_argument, 0, OptListGPIO},
92 	{"passthrough", required_argument, 0, OptPassThrough},
93 	{"reset", required_argument, 0, OptReset},
94 	{"get-yuv-mode", no_argument, 0, OptGetYuvMode},
95 	{"set-yuv-mode", required_argument, 0, OptSetYuvMode},
96 	{0, 0, 0, 0}
97 };
98 
usage(void)99 static void usage(void)
100 {
101 	printf("Usage:\n");
102 	printf("  -d, --device <dev> use device <dev> instead of /dev/video0\n");
103 	printf("  -h, --help         display this help message\n");
104 	printf("  -K, --passthrough <mode>\n");
105 	printf("                     set passthrough mode: 1 = on, 0 = off [IVTV_IOC_PASSTHROUGH_MODE]\n");
106 	printf("  --get-yuv-mode     display the current yuv mode\n");
107 	printf("  --set-yuv-mode mode=<mode>\n");
108 	printf("                     set the current yuv mode:\n");
109 	printf("       		     mode 0: interlaced (top transmitted first)\n");
110 	printf("       		     mode 1: interlaced (bottom transmitted first)\n");
111 	printf("       		     mode 2: progressive\n");
112 	printf("       		     mode 3: auto\n");
113 	printf("  --reset <mask>     reset the infrared receiver (1) or digitizer (2) [VIDIOC_INT_RESET]\n");
114 	printf("\n");
115 	printf("Expert options:\n");
116 	printf("  -D, --set-debug <level>\n");
117 	printf("                     set the module debug variable\n");
118 	printf("                        1/0x0001: warning\n");
119 	printf("                        2/0x0002: info\n");
120 	printf("                        4/0x0004: mailbox\n");
121 	printf("                        8/0x0008: ioctl\n");
122 	printf("                       16/0x0010: file\n");
123 	printf("                       32/0x0020: dma\n");
124 	printf("                       64/0x0040: irq\n");
125 	printf("                      128/0x0080: decoder\n");
126 	printf("                      256/0x0100: yuv\n");
127 	printf("                      512/0x0200: i2c\n");
128 	printf("                     1024/0x0400: high volume\n");
129 	printf("  -e, --get-debug    query the module debug variable\n");
130 	printf("  -I, --list-gpio\n");
131 	printf("                     show GPIO input/direction/output bits\n");
132 	printf("  -i, --set-gpio [dir=<dir>,]val=<val>\n");
133 	printf("                     set GPIO direction bits to <dir> and set output to <val>\n");
134 	exit(0);
135 }
136 
print_debug_mask(int mask)137 static void print_debug_mask(int mask)
138 {
139 #define MASK_OR_NOTHING (mask ? " | " : "")
140 	if (mask & IVTV_DBGFLG_WARN) {
141 		mask &= ~IVTV_DBGFLG_WARN;
142 		printf("IVTV_DBGFLG_WARN%s", MASK_OR_NOTHING);
143 	}
144 	if (mask & IVTV_DBGFLG_INFO) {
145 		mask &= ~IVTV_DBGFLG_INFO;
146 		printf("IVTV_DBGFLG_INFO%s", MASK_OR_NOTHING);
147 	}
148 	if (mask & IVTV_DBGFLG_MB) {
149 		mask &= ~IVTV_DBGFLG_MB;
150 		printf("IVTV_DBGFLG_MB%s", MASK_OR_NOTHING);
151 	}
152 	if (mask & IVTV_DBGFLG_DMA) {
153 		mask &= ~IVTV_DBGFLG_DMA;
154 		printf("IVTV_DBGFLG_DMA%s", MASK_OR_NOTHING);
155 	}
156 	if (mask & IVTV_DBGFLG_IOCTL) {
157 		mask &= ~IVTV_DBGFLG_IOCTL;
158 		printf("IVTV_DBGFLG_IOCTL%s", MASK_OR_NOTHING);
159 	}
160 	if (mask & IVTV_DBGFLG_FILE) {
161 		mask &= ~IVTV_DBGFLG_FILE;
162 		printf("IVTV_DBGFLG_FILE%s", MASK_OR_NOTHING);
163 	}
164 	if (mask & IVTV_DBGFLG_I2C) {
165 		mask &= ~IVTV_DBGFLG_I2C;
166 		printf("IVTV_DBGFLG_I2C%s", MASK_OR_NOTHING);
167 	}
168 	if (mask & IVTV_DBGFLG_IRQ) {
169 		mask &= ~IVTV_DBGFLG_IRQ;
170 		printf("IVTV_DBGFLG_IRQ%s", MASK_OR_NOTHING);
171 	}
172 	if (mask & IVTV_DBGFLG_DEC) {
173 		mask &= ~IVTV_DBGFLG_DEC;
174 		printf("IVTV_DBGFLG_DEC%s", MASK_OR_NOTHING);
175 	}
176 	if (mask & IVTV_DBGFLG_YUV) {
177 		mask &= ~IVTV_DBGFLG_YUV;
178 		printf("IVTV_DBGFLG_YUV%s", MASK_OR_NOTHING);
179 	}
180 	if (mask & IVTV_DBGFLG_HIGHVOL) {
181 		mask &= ~IVTV_DBGFLG_HIGHVOL;
182 		printf("IVTV_DBGFLG_HIGHVOL%s", MASK_OR_NOTHING);
183 	}
184 	if (mask)
185 		printf("0x%08x", mask);
186 	printf("\n");
187 }
188 
dowrite(const char * buf,const char * fn)189 static int dowrite(const char *buf, const char *fn)
190 {
191 	FILE *f = fopen(fn, "w");
192 	if (f == NULL) {
193 		printf("failed: %s\n", strerror(errno));
194 		return errno;
195 	}
196 	fprintf(f, "%s", buf);
197 	fclose(f);
198 	return 0;
199 }
200 
doread(const char * fn)201 static char *doread(const char *fn)
202 {
203 	static char buf[1000];
204 	FILE *f = fopen(fn, "r");
205 	int s;
206 
207 	if (f == NULL) {
208 		printf("failed: %s\n", strerror(errno));
209 		return NULL;
210 	}
211 	s = fread(buf, 1, sizeof(buf) - 1, f);
212 	buf[s] = 0;
213 	fclose(f);
214 	return buf;
215 }
216 
field2s(int val)217 static const char *field2s(int val)
218 {
219 	switch (val) {
220 	case V4L2_FIELD_ANY:
221 		return "Any";
222 	case V4L2_FIELD_NONE:
223 		return "None";
224 	case V4L2_FIELD_TOP:
225 		return "Top";
226 	case V4L2_FIELD_BOTTOM:
227 		return "Bottom";
228 	case V4L2_FIELD_INTERLACED:
229 		return "Interlaced";
230 	case V4L2_FIELD_SEQ_TB:
231 		return "Sequential Top-Bottom";
232 	case V4L2_FIELD_SEQ_BT:
233 		return "Sequential Bottom-Top";
234 	case V4L2_FIELD_ALTERNATE:
235 		return "Alternating";
236 	case V4L2_FIELD_INTERLACED_TB:
237 		return "Interlaced Top-Bottom";
238 	case V4L2_FIELD_INTERLACED_BT:
239 		return "Interlaced Bottom-Top";
240 	default:
241 		return "Unknown";
242 	}
243 }
244 
doioctl(int fd,unsigned long int request,void * parm,const char * name)245 static int doioctl(int fd, unsigned long int request, void *parm, const char *name)
246 {
247 	int retVal;
248 
249 	printf("ioctl %s ", name);
250 	retVal = ioctl(fd, request, parm);
251 	if (retVal < 0) {
252 		app_result = -1;
253 		printf("failed: %s\n", strerror(errno));
254 	}
255 	else
256 		printf("ok\n");
257 
258 	return retVal;
259 }
260 
main(int argc,char ** argv)261 int main(int argc, char **argv)
262 {
263 	char *value, *subs;
264 	int i;
265 	char *subopts[] = {
266 #define SUB_VAL				0
267 		"val",
268 #define SUB_YUV_MODE			1
269 		"mode",
270 #define SUB_DIR				2
271 		"dir",
272 
273 		NULL
274 	};
275 
276 	int fd = -1;
277 
278 	/* bitfield for OptSetCodec */
279 
280 	/* command args */
281 	const char *device = "/dev/video0";	/* -d device */
282 	int ch;
283 	int yuv_mode = 0;
284 	unsigned short gpio_out = 0x0;	/* GPIO output data */
285 	unsigned short gpio_dir = 0x0;	/* GPIO direction bits */
286 	int gpio_set_dir = 0;
287 	int passthrough = 0;
288 	int debug_level = 0;
289 	__u32 reset = 0;
290 	int new_debug_level, gdebug_level;
291 	char short_options[26 * 2 * 2 + 1];
292 
293 	if (argc == 1) {
294 		usage();
295 		return 0;
296 	}
297 	while (1) {
298 		int option_index = 0;
299 		int idx = 0;
300 
301 		for (i = 0; long_options[i].name; i++) {
302 			if (!isalpha(long_options[i].val))
303 				continue;
304 			short_options[idx++] = long_options[i].val;
305 			if (long_options[i].has_arg == required_argument)
306 				short_options[idx++] = ':';
307 		}
308 		short_options[idx] = 0;
309 		ch = getopt_long(argc, argv, short_options,
310 				 long_options, &option_index);
311 		if (ch == -1)
312 			break;
313 
314 		options[ch] = 1;
315 		switch (ch) {
316 		case OptSetYuvMode:
317 		    {
318 			subs = optarg;
319 			while (*subs != '\0') {
320 				switch (v4l_getsubopt(&subs, subopts, &value)) {
321 				case SUB_YUV_MODE:
322 					if (value == NULL) {
323 						fprintf(stderr,
324 							"No value given to suboption <mode>\n");
325 						usage();
326 						return 1;
327 
328 					}
329 					yuv_mode = strtol(value, 0L, 0);
330 					if (yuv_mode < 0 || yuv_mode > 3) {
331 						fprintf(stderr, "invalid yuv mode\n");
332 						return 1;
333 					}
334 					break;
335 				}
336 			}
337 		    }
338 		    break;
339 		case OptHelp:
340 			usage();
341 			return 0;
342 		case OptSetDebugLevel:{
343 			debug_level = strtol(optarg, 0L, 0);
344 			break;
345 		}
346 		case OptSetDevice:
347 			device = optarg;
348 			if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) {
349 				static char newdev[20];
350 
351 				sprintf(newdev, "/dev/video%s", device);
352 				device = newdev;
353 			}
354 			break;
355 		case OptReset:
356 			reset = strtol(optarg, 0L, 0);
357 			break;
358 		case OptPassThrough:
359 			passthrough = strtol(optarg, 0L, 0);
360 			break;
361 		case OptSetGPIO:
362 			subs = optarg;
363 			while (*subs != '\0') {
364 				switch (v4l_getsubopt(&subs, subopts, &value)) {
365 				case SUB_DIR:
366 					if (value == NULL) {
367 						fprintf(stderr,
368 							"No value given to suboption <dir>\n");
369 						usage();
370 						exit(1);
371 					}
372 					gpio_dir = strtol(value, 0L, 0);
373 					gpio_set_dir = 1;
374 					break;
375 				case SUB_VAL:
376 					if (value == NULL) {
377 						fprintf(stderr,
378 							"No value given to suboption <val>\n");
379 						usage();
380 						exit(1);
381 					}
382 					gpio_out = (unsigned short)strtol(value, 0L, 0);
383 					break;
384 				default:
385 					fprintf(stderr,
386 						"Invalid suboptions specified\n");
387 					usage();
388 					exit(1);
389 					break;
390 				}
391 			}
392 			break;
393 		case ':':
394 			fprintf(stderr, "Option `%s' requires a value\n",
395 				argv[optind]);
396 			usage();
397 			return 1;
398 		case '?':
399 			fprintf(stderr, "Unknown argument `%s'\n",
400 				argv[optind]);
401 			usage();
402 			return 1;
403 		}
404 	}
405 	if (optind < argc) {
406 		printf("unknown arguments: ");
407 		while (optind < argc)
408 			printf("%s ", argv[optind++]);
409 		printf("\n");
410 		usage();
411 		return 1;
412 	}
413 
414 	fd = open(device, O_RDWR);
415 	if (fd < 0) {
416 		fprintf(stderr, "Failed to open %s: %s\n", device,
417 			strerror(errno));
418 		exit(1);
419 	}
420 
421 	/* Setting Opts */
422 
423 	if (options[OptSetGPIO]) {
424 		struct v4l2_dbg_register reg;
425 
426 		reg.match.type = V4L2_CHIP_MATCH_HOST;
427 		reg.match.addr = 0;
428 		reg.reg = IVTV_REG_GPIO_DIR_OFFSET;
429 		reg.val = gpio_dir;
430 		if (gpio_set_dir && doioctl(fd, VIDIOC_DBG_S_REGISTER, &reg,
431 			"VIDIOC_DBG_S_REGISTER") == 0)
432 			printf("GPIO dir set to 0x%04llx\n", reg.val);
433 		reg.reg = IVTV_REG_GPIO_OUT_OFFSET;
434 		reg.val = gpio_out;
435 		if (doioctl(fd, VIDIOC_DBG_S_REGISTER, &reg,
436 			"VIDIOC_DBG_S_REGISTER") == 0)
437 			printf("GPIO out set to 0x%04llx\n", reg.val);
438 	}
439 
440 	if (options[OptListGPIO]) {
441 		struct v4l2_dbg_register reg;
442 
443 		reg.match.type = V4L2_CHIP_MATCH_HOST;
444 		reg.match.addr = 0;
445 		reg.reg = IVTV_REG_GPIO_IN_OFFSET;
446 		if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &reg) == 0)
447 			printf("GPIO in:  0x%04llx\n", reg.val);
448 		reg.reg = IVTV_REG_GPIO_DIR_OFFSET;
449 		if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &reg) == 0)
450 			printf("GPIO dir: 0x%04llx\n", reg.val);
451 		reg.reg = IVTV_REG_GPIO_OUT_OFFSET;
452 		if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &reg) == 0)
453 			printf("GPIO out: 0x%04llx\n", reg.val);
454 	}
455 
456 	if (options[OptSetDebugLevel]) {
457 		char buf[20];
458 		new_debug_level = debug_level;
459 
460 		sprintf(buf, "%d", debug_level);
461 		if (dowrite(buf, "/sys/module/ivtv/parameters/debug") == 0) {
462 			printf(" set debug level: ");
463 			print_debug_mask(new_debug_level);
464 			printf("\n");
465 		}
466 	}
467 
468 	if (options[OptGetDebugLevel]) {
469 		char *buf = doread("/sys/module/ivtv/parameters/debug");
470 
471 		gdebug_level = 0;
472 		if (buf) {
473 			gdebug_level = atol(buf);
474 			printf(" debug level: ");
475 			print_debug_mask(gdebug_level);
476 			printf("\n");
477 		}
478 	}
479 
480 	if (options[OptPassThrough])
481 		doioctl(fd, IVTV_IOC_PASSTHROUGH_MODE, &passthrough,
482 				"IVTV_IOC_PASSTHROUGH_MODE");
483 
484 	if (options[OptReset])
485 		doioctl(fd, VIDIOC_INT_RESET, &reset, "VIDIOC_INT_RESET");
486 
487 	if (options[OptSetYuvMode]) {
488 		struct ivtv_dma_frame frame;
489 		struct v4l2_format fmt;
490 		const enum v4l2_field map[4] = {
491 			V4L2_FIELD_INTERLACED_TB,
492 			V4L2_FIELD_INTERLACED_BT,
493 			V4L2_FIELD_NONE,
494 			V4L2_FIELD_ANY,
495 		};
496 
497 		printf("set yuv mode\n");
498 		memset(&frame, 0, sizeof(frame));
499 		frame.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
500 		if (ioctl(fd, IVTV_IOC_DMA_FRAME, &frame) < 0) {
501 			fprintf(stderr, "Unable to switch to user DMA YUV mode\n");
502 			exit(1);
503 		}
504 		fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
505 		ioctl(fd, VIDIOC_G_FMT, &fmt);
506 		fmt.fmt.pix.field = map[yuv_mode];
507 		doioctl(fd, VIDIOC_S_FMT, &fmt, "VIDIOC_S_FMT");
508 	}
509 
510 	if (options[OptGetYuvMode]) {
511 		struct ivtv_dma_frame frame;
512 		struct v4l2_format fmt;
513 
514 		memset(&frame, 0, sizeof(frame));
515 		frame.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
516 		if (ioctl(fd, IVTV_IOC_DMA_FRAME, &frame) < 0) {
517 			fprintf(stderr, "Unable to switch to user DMA YUV mode\n");
518 			exit(1);
519 		}
520 		fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
521 		doioctl(fd, VIDIOC_G_FMT, &fmt, "VIDIOC_G_FMT");
522 		printf("Current yuv_mode %d %s\n", fmt.fmt.pix.field,
523 				field2s(fmt.fmt.pix.field));
524 	}
525 
526 	close(fd);
527 	exit(app_result);
528 }
529