1 /*
2     Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
17  */
18 
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <inttypes.h>
23 #include <getopt.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <sys/ioctl.h>
30 #include <sys/time.h>
31 #include <math.h>
32 #include <cstdlib>
33 
34 #ifdef ANDROID
35 #include <android-config.h>
36 #else
37 #include <config.h>
38 #endif
39 
40 #ifdef HAVE_SYS_KLOG_H
41 #include <sys/klog.h>
42 #endif
43 
44 #include <linux/videodev2.h>
45 
46 #include <cstring>
47 #include <list>
48 #include <vector>
49 #include <map>
50 #include <string>
51 
52 #include "v4l2-dbg-bttv.h"
53 #include "v4l2-dbg-saa7134.h"
54 #include "v4l2-dbg-em28xx.h"
55 #include "v4l2-dbg-ac97.h"
56 #include "v4l2-dbg-tvp5150.h"
57 #include "v4l2-dbg-micron.h"
58 
59 #define ARRAY_SIZE(arr) ((int)(sizeof(arr) / sizeof((arr)[0])))
60 
61 struct board_list {
62 	const char *name;
63 	int prefix; 		/* Register prefix size */
64 	const struct board_regs *regs;
65 	int regs_size;
66 	const struct board_regs *alt_regs;
67 	int alt_regs_size;
68 };
69 
70 static const struct board_list boards[] = {
71 #define AC97_BOARD 0
72 	{				/* From v4l2-dbg-ac97.h */
73 		AC97_IDENT,
74 		sizeof(AC97_PREFIX) - 1,
75 		ac97_regs,
76 		ARRAY_SIZE(ac97_regs),
77 		NULL,
78 		0,
79 	},
80 	{				/* From v4l2-dbg-bttv.h */
81 		BTTV_IDENT,
82 		sizeof(BTTV_PREFIX) - 1,
83 		bt8xx_regs,
84 		ARRAY_SIZE(bt8xx_regs),
85 		bt8xx_regs_other,
86 		ARRAY_SIZE(bt8xx_regs_other),
87 	},
88 	{				/* From v4l2-dbg-saa7134.h */
89 		SAA7134_IDENT,
90 		sizeof(SAA7134_PREFIX) - 1,
91 		saa7134_regs,
92 		ARRAY_SIZE(saa7134_regs),
93 		NULL,
94 		0,
95 	},
96 	{				/* From v4l2-dbg-em28xx.h */
97 		EM28XX_IDENT,
98 		sizeof(EM28XX_PREFIX) - 1,
99 		em28xx_regs,
100 		ARRAY_SIZE(em28xx_regs),
101 		em28xx_alt_regs,
102 		ARRAY_SIZE(em28xx_alt_regs),
103 	},
104 	{				/* From v4l2-dbg-tvp5150.h */
105 		TVP5150_IDENT,
106 		sizeof(TVP5150_PREFIX) - 1,
107 		tvp5150_regs,
108 		ARRAY_SIZE(tvp5150_regs),
109 		NULL,
110 		0,
111 	},
112 	{				/* From v4l2-dbg-micron.h */
113 		MT9V011_IDENT,
114 		sizeof(MT9V011_PREFIX) - 1,
115 		mt9v011_regs,
116 		ARRAY_SIZE(mt9v011_regs),
117 		NULL,
118 		0,
119 	},
120 };
121 
122 /* Short option list
123 
124    Please keep in alphabetical order.
125    That makes it easier to see which short options are still free.
126 
127    In general the lower case is used to set something and the upper
128    case is used to retrieve a setting. */
129 enum Option {
130 	OptListRegisters = 'l',
131 	OptGetRegister = 'g',
132 	OptSetRegister = 's',
133 	OptSetDevice = 'd',
134 	OptGetDriverInfo = 'D',
135 	OptChip = 'c',
136 	OptScanChips = 'n',
137 	OptSetStride = 'w',
138 	OptHelp = 'h',
139 
140 	OptLogStatus = 128,
141 	OptVerbose,
142 	OptListSymbols,
143 	OptLast = 256
144 };
145 
146 static char options[OptLast];
147 
148 static unsigned capabilities;
149 
150 static struct option long_options[] = {
151 	{"device", required_argument, 0, OptSetDevice},
152 	{"help", no_argument, 0, OptHelp},
153 	{"list-registers", optional_argument, 0, OptListRegisters},
154 	{"get-register", required_argument, 0, OptGetRegister},
155 	{"set-register", required_argument, 0, OptSetRegister},
156 	{"chip", required_argument, 0, OptChip},
157 	{"scan-chips", no_argument, 0, OptScanChips},
158 	{"info", no_argument, 0, OptGetDriverInfo},
159 	{"verbose", no_argument, 0, OptVerbose},
160 	{"log-status", no_argument, 0, OptLogStatus},
161 	{"list-symbols", no_argument, 0, OptListSymbols},
162 	{"wide", required_argument, 0, OptSetStride},
163 	{0, 0, 0, 0}
164 };
165 
usage()166 static void usage()
167 {
168 	printf("Usage: v4l2-dbg [options] [values]\n"
169 	       "  -D, --info         Show driver info [VIDIOC_QUERYCAP]\n"
170 	       "  -d, --device <dev> Use device <dev> instead of /dev/video0\n"
171 	       "                     If <dev> starts with a digit, then /dev/video<dev> is used\n"
172 	       "  -h, --help         Display this help message\n"
173 	       "  --verbose          Turn on verbose ioctl error reporting\n"
174 	       "  -c, --chip <chip>  The chip identifier to use with other commands\n"
175 	       "                     It can be one of:\n"
176 	       "                         bridge<num>: bridge chip number <num>\n"
177 	       "                         bridge (default): same as bridge0\n"
178 	       "                         subdev<num>: sub-device number <num>\n"
179 	       "  -l, --list-registers[=min=<addr>[,max=<addr>]]\n"
180 	       "		     Dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]\n"
181 	       "  -g, --get-register <addr>\n"
182 	       "		     Get the specified register [VIDIOC_DBG_G_REGISTER]\n"
183 	       "  -s, --set-register <addr>\n"
184 	       "		     Set the register with the commandline arguments\n"
185 	       "                     The register will autoincrement [VIDIOC_DBG_S_REGISTER]\n"
186 	       "  -n, --scan-chips   Scan the available bridge and subdev chips [VIDIOC_DBG_G_CHIP_INFO]\n"
187 	       "  -w, --wide <reg length>\n"
188 	       "		     Sets step between two registers\n"
189 	       "  --list-symbols     List the symbolic register names you can use, if any\n"
190 	       "  --log-status       Log the board status in the kernel log [VIDIOC_LOG_STATUS]\n");
191 }
192 
cap2s(unsigned cap)193 static std::string cap2s(unsigned cap)
194 {
195 	std::string s;
196 
197 	if (cap & V4L2_CAP_VIDEO_CAPTURE)
198 		s += "\t\tVideo Capture\n";
199 	if (cap & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
200 		s += "\t\tVideo Capture Multiplanar\n";
201 	if (cap & V4L2_CAP_VIDEO_OUTPUT)
202 		s += "\t\tVideo Output\n";
203 	if (cap & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
204 		s += "\t\tVideo Output Multiplanar\n";
205 	if (cap & V4L2_CAP_VIDEO_M2M)
206 		s += "\t\tVideo Memory-to-Memory\n";
207 	if (cap & V4L2_CAP_VIDEO_M2M_MPLANE)
208 		s += "\t\tVideo Memory-to-Memory Multiplanar\n";
209 	if (cap & V4L2_CAP_VIDEO_OVERLAY)
210 		s += "\t\tVideo Overlay\n";
211 	if (cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
212 		s += "\t\tVideo Output Overlay\n";
213 	if (cap & V4L2_CAP_VBI_CAPTURE)
214 		s += "\t\tVBI Capture\n";
215 	if (cap & V4L2_CAP_VBI_OUTPUT)
216 		s += "\t\tVBI Output\n";
217 	if (cap & V4L2_CAP_SLICED_VBI_CAPTURE)
218 		s += "\t\tSliced VBI Capture\n";
219 	if (cap & V4L2_CAP_SLICED_VBI_OUTPUT)
220 		s += "\t\tSliced VBI Output\n";
221 	if (cap & V4L2_CAP_RDS_CAPTURE)
222 		s += "\t\tRDS Capture\n";
223 	if (cap & V4L2_CAP_RDS_OUTPUT)
224 		s += "\t\tRDS Output\n";
225 	if (cap & V4L2_CAP_SDR_CAPTURE)
226 		s += "\t\tSDR Capture\n";
227 	if (cap & V4L2_CAP_TOUCH)
228 		s += "\t\tTouch Device\n";
229 	if (cap & V4L2_CAP_TUNER)
230 		s += "\t\tTuner\n";
231 	if (cap & V4L2_CAP_HW_FREQ_SEEK)
232 		s += "\t\tHW Frequency Seek\n";
233 	if (cap & V4L2_CAP_MODULATOR)
234 		s += "\t\tModulator\n";
235 	if (cap & V4L2_CAP_AUDIO)
236 		s += "\t\tAudio\n";
237 	if (cap & V4L2_CAP_RADIO)
238 		s += "\t\tRadio\n";
239 	if (cap & V4L2_CAP_READWRITE)
240 		s += "\t\tRead/Write\n";
241 	if (cap & V4L2_CAP_ASYNCIO)
242 		s += "\t\tAsync I/O\n";
243 	if (cap & V4L2_CAP_STREAMING)
244 		s += "\t\tStreaming\n";
245 	if (cap & V4L2_CAP_EXT_PIX_FORMAT)
246 		s += "\t\tExtended Pix Format\n";
247 	if (cap & V4L2_CAP_DEVICE_CAPS)
248 		s += "\t\tDevice Capabilities\n";
249 	return s;
250 }
251 
print_regs(int fd,struct v4l2_dbg_register * reg,unsigned long min,unsigned long max,int stride)252 static void print_regs(int fd, struct v4l2_dbg_register *reg, unsigned long min, unsigned long max, int stride)
253 {
254 	unsigned long mask;
255 	unsigned long i;
256 	int line = 0;
257 
258 	/* Query size of the first register */
259 	reg->reg = min;
260 	if (ioctl(fd, VIDIOC_DBG_G_REGISTER, reg) == 0) {
261 		/* If size is set, then use this as the stride */
262 		if (reg->size)
263 			stride = reg->size;
264 	}
265 
266 	mask = stride > 2 ? 0x1f : 0x0f;
267 
268 	for (i = min & ~mask; i <= max; i += stride) {
269 		if ((i & mask) == 0 && line % 32 == 0) {
270 			if (stride == 4)
271 				printf("\n                00       04       08       0C       10       14       18       1C");
272 			else if (stride == 2)
273 				printf("\n            00   02   04   06   08   0A   0C   0E");
274 			else
275 				printf("\n          00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
276 		}
277 
278 		if ((i & mask) == 0) {
279 			printf("\n%08lx: ", i);
280 			line++;
281 		}
282 		if (i < min) {
283 			printf("%*s ", 2 * stride, "");
284 			continue;
285 		}
286 		reg->reg = i;
287 		if (ioctl(fd, VIDIOC_DBG_G_REGISTER, reg) < 0) {
288 			perror("ioctl: VIDIOC_DBG_G_REGISTER failed\n");
289 			break;
290 		}
291 		printf("%0*llx ", 2 * stride, reg->val);
292 		usleep(1);
293 	}
294 	printf("\n");
295 }
296 
print_name(struct v4l2_dbg_chip_info * chip)297 static void print_name(struct v4l2_dbg_chip_info *chip)
298 {
299 	printf("%-10s (%c%c)\n", chip->name,
300 		(chip->flags & V4L2_CHIP_FL_READABLE) ? 'r' : '-',
301 		(chip->flags & V4L2_CHIP_FL_WRITABLE) ? 'w' : '-');
302 }
303 
parse_reg(const struct board_list * curr_bd,const std::string & reg)304 static unsigned long long parse_reg(const struct board_list *curr_bd, const std::string &reg)
305 {
306 	if (curr_bd) {
307 		for (int i = 0; i < curr_bd->regs_size; i++) {
308 			if (!strcasecmp(reg.c_str(), curr_bd->regs[i].name) ||
309 			    !strcasecmp(reg.c_str(), curr_bd->regs[i].name + curr_bd->prefix)) {
310 				return curr_bd->regs[i].reg;
311 			}
312 		}
313 		for (int i = 0; i < curr_bd->alt_regs_size; i++) {
314 			if (!strcasecmp(reg.c_str(), curr_bd->alt_regs[i].name) ||
315 			    !strcasecmp(reg.c_str(), curr_bd->alt_regs[i].name + curr_bd->prefix)) {
316 				return curr_bd->alt_regs[i].reg;
317 			}
318 		}
319 	}
320 	return strtoull(reg.c_str(), NULL, 0);
321 }
322 
reg_name(const struct board_list * curr_bd,unsigned long long reg)323 static const char *reg_name(const struct board_list *curr_bd, unsigned long long reg)
324 {
325 	if (curr_bd) {
326 		for (int i = 0; i < curr_bd->regs_size; i++) {
327 			if (reg == curr_bd->regs[i].reg)
328 				return curr_bd->regs[i].name;
329 		}
330 		for (int i = 0; i < curr_bd->alt_regs_size; i++) {
331 			if (reg == curr_bd->regs[i].reg)
332 				return curr_bd->regs[i].name;
333 		}
334 	}
335 	return NULL;
336 }
337 
binary(unsigned long long val)338 static const char *binary(unsigned long long val)
339 {
340 	static char bin[80];
341 	char *p = bin;
342 	int i, j;
343 	int bits = 64;
344 
345 	if ((val & 0xffffffff00000000LL) == 0) {
346 		if ((val & 0xffff0000) == 0) {
347 			if ((val & 0xff00) == 0)
348 				bits = 8;
349 			else
350 				bits= 16;
351 		}
352 		else
353 			bits = 32;
354 	}
355 
356 	for (i = bits - 1; i >= 0; i -= 8) {
357 		for (j = i; j >= i - 7; j--) {
358 			if (val & (1LL << j))
359 				*p++ = '1';
360 			else
361 				*p++ = '0';
362 		}
363 		*p++ = ' ';
364 	}
365 	p[-1] = 0;
366 	return bin;
367 }
368 
doioctl(int fd,unsigned long int request,void * parm,const char * name)369 static int doioctl(int fd, unsigned long int request, void *parm, const char *name)
370 {
371 	int retVal = ioctl(fd, request, parm);
372 
373 	if (options[OptVerbose]) {
374 		if (retVal < 0)
375 			printf("%s: failed: %s\n", name, strerror(errno));
376 		else
377 			printf("%s: ok\n", name);
378 	}
379 
380 	return retVal;
381 }
382 
parse_subopt(char ** subs,const char * const * subopts,char ** value)383 static int parse_subopt(char **subs, const char * const *subopts, char **value)
384 {
385 	int opt = getsubopt(subs, const_cast<char * const *>(subopts), value);
386 
387 	if (opt == -1) {
388 		fprintf(stderr, "Invalid suboptions specified\n");
389 		usage();
390 		std::exit(EXIT_FAILURE);
391 	}
392 	if (*value == NULL) {
393 		fprintf(stderr, "No value given to suboption <%s>\n",
394 				subopts[opt]);
395 		usage();
396 		std::exit(EXIT_FAILURE);
397 	}
398 	return opt;
399 }
400 
main(int argc,char ** argv)401 int main(int argc, char **argv)
402 {
403 	char *value, *subs;
404 	int i, forcedstride = 0;
405 
406 	int fd = -1;
407 
408 	/* command args */
409 	int ch;
410 	const char *device = "/dev/video0";	/* -d device */
411 	struct v4l2_capability vcap;	/* list_cap */
412 	struct v4l2_dbg_register set_reg;
413 	struct v4l2_dbg_register get_reg;
414 	struct v4l2_dbg_chip_info chip_info;
415 	const struct board_list *curr_bd = NULL;
416 	char short_options[26 * 2 * 3 + 1];
417 	int idx = 0;
418 	std::string reg_min_arg, reg_max_arg;
419 	std::string reg_set_arg;
420 	unsigned long long reg_min = 0, reg_max = 0;
421 	std::vector<std::string> get_regs;
422 	struct v4l2_dbg_match match;
423 	char *p;
424 
425 	match.type = V4L2_CHIP_MATCH_BRIDGE;
426 	match.addr = 0;
427 	memset(&set_reg, 0, sizeof(set_reg));
428 	memset(&get_reg, 0, sizeof(get_reg));
429 
430 	if (argc == 1) {
431 		usage();
432 		std::exit(EXIT_SUCCESS);
433 	}
434 	for (i = 0; long_options[i].name; i++) {
435 		if (!isalpha(long_options[i].val))
436 			continue;
437 		short_options[idx++] = long_options[i].val;
438 		if (long_options[i].has_arg == required_argument) {
439 			short_options[idx++] = ':';
440 		} else if (long_options[i].has_arg == optional_argument) {
441 			short_options[idx++] = ':';
442 			short_options[idx++] = ':';
443 		}
444 	}
445 	while (true) {
446 		int option_index = 0;
447 
448 		short_options[idx] = 0;
449 		ch = getopt_long(argc, argv, short_options,
450 				 long_options, &option_index);
451 		if (ch == -1)
452 			break;
453 
454 		options[ch] = 1;
455 		if (!option_index) {
456 			for (i = 0; long_options[i].val; i++) {
457 				if (long_options[i].val == ch) {
458 					option_index = i;
459 					break;
460 				}
461 			}
462 		}
463 		if (long_options[option_index].has_arg == optional_argument &&
464 		    !optarg && argv[optind] && argv[optind][0] != '-')
465 			optarg = argv[optind++];
466 
467 		switch (ch) {
468 		case OptHelp:
469 			usage();
470 			std::exit(EXIT_SUCCESS);
471 
472 		case OptSetDevice:
473 			device = optarg;
474 			if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) {
475 				static char newdev[20];
476 
477 				sprintf(newdev, "/dev/video%s", device);
478 				device = newdev;
479 			}
480 			break;
481 
482 		case OptChip:
483 			if (!memcmp(optarg, "subdev", 6) && isdigit(optarg[6])) {
484 				match.type = V4L2_CHIP_MATCH_SUBDEV;
485 				match.addr = strtoul(optarg + 6, NULL, 0);
486 				break;
487 			}
488 			if (!memcmp(optarg, "bridge", 6)) {
489 				match.type = V4L2_CHIP_MATCH_BRIDGE;
490 				match.addr = strtoul(optarg + 6, NULL, 0);
491 				break;
492 			}
493 			match.type = V4L2_CHIP_MATCH_BRIDGE;
494 			match.addr = 0;
495 			break;
496 
497 		case OptSetRegister:
498 			reg_set_arg = optarg;
499 			break;
500 
501 		case OptGetRegister:
502 			get_regs.push_back(optarg);
503 			break;
504 
505 		case OptSetStride:
506 			forcedstride = strtoull(optarg, 0L, 0);
507 			break;
508 
509 		case OptListRegisters:
510 			subs = optarg;
511 			if (subs == NULL)
512 				break;
513 
514 			while (*subs != '\0') {
515 				static const char * const subopts[] = {
516 					"min",
517 					"max",
518 					NULL
519 				};
520 
521 				switch (parse_subopt(&subs, subopts, &value)) {
522 				case 0:
523 					reg_min_arg = value;
524 					//if (reg_max == 0)
525 					//	reg_max = reg_min + 0xff;
526 					break;
527 				case 1:
528 					reg_max_arg = value;
529 					break;
530 				}
531 			}
532 			break;
533 
534 		case OptListSymbols:
535 			break;
536 
537 		case ':':
538 			fprintf(stderr, "Option `%s' requires a value\n",
539 				argv[optind]);
540 			usage();
541 			return 1;
542 
543 		case '?':
544 			fprintf(stderr, "Unknown argument `%s'\n",
545 				argv[optind]);
546 			usage();
547 			return 1;
548 		}
549 	}
550 
551 	if ((fd = open(device, O_RDWR)) < 0) {
552 		fprintf(stderr, "Failed to open %s: %s\n", device,
553 			strerror(errno));
554 		std::exit(EXIT_FAILURE);
555 	}
556 
557 	doioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP");
558 	capabilities = vcap.capabilities;
559 
560 	/* Information Opts */
561 
562 	if (options[OptGetDriverInfo]) {
563 		printf("Driver info:\n");
564 		printf("\tDriver name   : %s\n", vcap.driver);
565 		printf("\tCard type     : %s\n", vcap.card);
566 		printf("\tBus info      : %s\n", vcap.bus_info);
567 		printf("\tDriver version: %d.%d.%d\n",
568 				vcap.version >> 16,
569 				(vcap.version >> 8) & 0xff,
570 				vcap.version & 0xff);
571 		printf("\tCapabilities  : 0x%08X\n", vcap.capabilities);
572 		printf("%s", cap2s(vcap.capabilities).c_str());
573 	}
574 
575 	chip_info.name[0] = '\0';
576 	if (options[OptChip]) {
577 		/* try to figure out which chip it is */
578 		chip_info.match = match;
579 		if (doioctl(fd, VIDIOC_DBG_G_CHIP_INFO, &chip_info, "VIDIOC_DBG_G_CHIP_INFO") != 0)
580 			chip_info.name[0] = '\0';
581 
582 		if (!strncasecmp(match.name, "ac97", 4)) {
583 			curr_bd = &boards[AC97_BOARD];
584 		} else {
585 			for (int board = ARRAY_SIZE(boards) - 1; board >= 0; board--) {
586 				if (!strcasecmp(chip_info.name, boards[board].name)) {
587 					curr_bd = &boards[board];
588 					break;
589 				}
590 			}
591 		}
592 	}
593 
594 	/* Set options */
595 
596 	if (options[OptSetRegister]) {
597 		set_reg.match = match;
598 		if (optind >= argc) {
599 			usage();
600 			exit(1);
601 		}
602 		set_reg.reg = parse_reg(curr_bd, reg_set_arg);
603 		while (optind < argc) {
604 			unsigned size = 0;
605 
606 			if (doioctl(fd, VIDIOC_DBG_G_REGISTER, &set_reg,
607 				    "VIDIOC_DBG_G_REGISTER") >= 0)
608 				size = set_reg.size;
609 
610 			set_reg.val = strtoull(argv[optind++], NULL, 0);
611 			if (doioctl(fd, VIDIOC_DBG_S_REGISTER, &set_reg,
612 						"VIDIOC_DBG_S_REGISTER") >= 0) {
613 				const char *name = reg_name(curr_bd, set_reg.reg);
614 
615 				printf("Register ");
616 
617 				if (name)
618 					printf("%s (0x%08llx)", name, set_reg.reg);
619 				else
620 					printf("0x%08llx", set_reg.reg);
621 
622 				printf(" set to 0x%llx\n", set_reg.val);
623 			} else {
624 				printf("Failed to set register 0x%08llx value 0x%llx: %s\n",
625 					set_reg.reg, set_reg.val, strerror(errno));
626 			}
627 			set_reg.reg += size ? : (forcedstride ? : 1);
628 		}
629 	}
630 
631 	if (options[OptScanChips]) {
632 		chip_info.match.type = V4L2_CHIP_MATCH_BRIDGE;
633 		chip_info.match.addr = 0;
634 
635 		while (doioctl(fd, VIDIOC_DBG_G_CHIP_INFO, &chip_info, "VIDIOC_DBG_G_CHIP_INFO") == 0 && chip_info.name[0]) {
636 			printf("bridge%d: ", chip_info.match.addr);
637 			print_name(&chip_info);
638 			chip_info.match.addr++;
639 		}
640 
641 		chip_info.match.type = V4L2_CHIP_MATCH_SUBDEV;
642 		chip_info.match.addr = 0;
643 		while (doioctl(fd, VIDIOC_DBG_G_CHIP_INFO, &chip_info, "VIDIOC_DBG_G_CHIP_INFO") == 0 && chip_info.name[0]) {
644 			printf("subdev%d: ", chip_info.match.addr++);
645 			print_name(&chip_info);
646 		}
647 	}
648 
649 	if (options[OptGetRegister]) {
650 		get_reg.match = match;
651 		printf("ioctl: VIDIOC_DBG_G_REGISTER\n");
652 
653 		for (std::vector<std::string>::iterator iter = get_regs.begin();
654 				iter != get_regs.end(); ++iter) {
655 			get_reg.reg = parse_reg(curr_bd, *iter);
656 			if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &get_reg) < 0)
657 				fprintf(stderr, "ioctl: VIDIOC_DBG_G_REGISTER "
658 						"failed for 0x%llx\n", get_reg.reg);
659 			else {
660 				const char *name = reg_name(curr_bd, get_reg.reg);
661 
662 				printf("Register ");
663 
664 				if (name)
665 					printf("%s (0x%08llx)", name, get_reg.reg);
666 				else
667 					printf("0x%08llx", get_reg.reg);
668 
669 				printf(" = %llxh (%lldd  %sb)\n",
670 					get_reg.val, get_reg.val, binary(get_reg.val));
671 			}
672 		}
673 	}
674 
675 	if (options[OptListRegisters]) {
676 		std::string name;
677 		int stride = 1;
678 
679 		get_reg.match = match;
680 		if (forcedstride) {
681 			stride = forcedstride;
682 		} else if (get_reg.match.type == V4L2_CHIP_MATCH_BRIDGE) {
683 			stride = 4;
684 		}
685 		printf("ioctl: VIDIOC_DBG_G_REGISTER\n");
686 
687 		if (curr_bd) {
688 			if (reg_min_arg.empty())
689 				reg_min = 0;
690 			else
691 				reg_min = parse_reg(curr_bd, reg_min_arg);
692 
693 
694 			if (reg_max_arg.empty())
695 				reg_max = (1ll << 32) - 1;
696 			else
697 				reg_max = parse_reg(curr_bd, reg_max_arg);
698 
699 			for (int i = 0; i < curr_bd->regs_size; i++) {
700 				if (reg_min_arg.empty() || ((curr_bd->regs[i].reg >= reg_min) && curr_bd->regs[i].reg <= reg_max)) {
701 					get_reg.reg = curr_bd->regs[i].reg;
702 
703 					if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &get_reg) < 0)
704 						fprintf(stderr, "ioctl: VIDIOC_DBG_G_REGISTER "
705 								"failed for 0x%llx\n", get_reg.reg);
706 					else {
707 						const char *name = reg_name(curr_bd, get_reg.reg);
708 
709 						printf("Register ");
710 
711 						if (name)
712 							printf("%s (0x%08llx)", name, get_reg.reg);
713 						else
714 							printf("0x%08llx", get_reg.reg);
715 
716 						printf(" = %llxh (%lldd  %sb)\n",
717 							get_reg.val, get_reg.val, binary(get_reg.val));
718 					}
719 				}
720 			}
721 			goto list_done;
722 		}
723 
724 		if (!reg_min_arg.empty()) {
725 			reg_min = parse_reg(curr_bd, reg_min_arg);
726 			if (reg_max_arg.empty())
727 				reg_max = reg_min + 0xff;
728 			else
729 				reg_max = parse_reg(curr_bd, reg_max_arg);
730 			/* Explicit memory range: just do it */
731 			print_regs(fd, &get_reg, reg_min, reg_max, stride);
732 			goto list_done;
733 		}
734 
735 		p = std::strchr(chip_info.name, ' ');
736 		if (p)
737 			*p = '\0';
738 		name = chip_info.name;
739 
740 		if (name == "saa7115") {
741 			print_regs(fd, &get_reg, 0, 0xff, stride);
742 		} else if (name == "saa717x") {
743 			// FIXME: use correct reg regions
744 			print_regs(fd, &get_reg, 0, 0xff, stride);
745 		} else if (name == "saa7127") {
746 			print_regs(fd, &get_reg, 0, 0x7f, stride);
747 		} else if (name == "ov7670") {
748 			print_regs(fd, &get_reg, 0, 0x89, stride);
749 		} else if (name == "cx25840") {
750 			print_regs(fd, &get_reg, 0, 2, stride);
751 			print_regs(fd, &get_reg, 0x100, 0x15f, stride);
752 			print_regs(fd, &get_reg, 0x200, 0x23f, stride);
753 			print_regs(fd, &get_reg, 0x400, 0x4bf, stride);
754 			print_regs(fd, &get_reg, 0x800, 0x9af, stride);
755 		} else if (name == "cs5345") {
756 			print_regs(fd, &get_reg, 1, 0x10, stride);
757 		} else if (name == "cx23416") {
758 			print_regs(fd, &get_reg, 0x02000000, 0x020000ff, stride);
759 		} else if (name == "cx23418") {
760 			print_regs(fd, &get_reg, 0x02c40000, 0x02c409c7, stride);
761 		} else if (name == "cafe") {
762 			print_regs(fd, &get_reg, 0, 0x43, stride);
763 			print_regs(fd, &get_reg, 0x88, 0x8f, stride);
764 			print_regs(fd, &get_reg, 0xb4, 0xbb, stride);
765 			print_regs(fd, &get_reg, 0x3000, 0x300c, stride);
766 		} else {
767 			/* unknown chip, dump 0-0xff by default */
768 			print_regs(fd, &get_reg, 0, 0xff, stride);
769 		}
770 	}
771 list_done:
772 
773 	if (options[OptLogStatus]) {
774 		static char buf[40960];
775 		int len = -1;
776 
777 		if (doioctl(fd, VIDIOC_LOG_STATUS, NULL, "VIDIOC_LOG_STATUS") == 0) {
778 			printf("\nStatus Log:\n\n");
779 #ifdef HAVE_KLOGCTL
780 			len = klogctl(3, buf, sizeof(buf) - 1);
781 #endif
782 			if (len >= 0) {
783 				bool found_status = false;
784 				char *p = buf;
785 				char *q;
786 
787 				buf[len] = 0;
788 				while ((q = strstr(p, "START STATUS"))) {
789 					found_status = true;
790 					p = q + 1;
791 				}
792 				if (found_status) {
793 					while (p > buf && *p != '<') p--;
794 					q = p;
795 					while ((q = strstr(q, "<6>"))) {
796 						memcpy(q, "   ", 3);
797 					}
798 					printf("%s", p);
799 				}
800 			}
801 		}
802 	}
803 
804 	if (options[OptListSymbols]) {
805 		if (curr_bd == NULL) {
806 			printf("No symbols found for driver %s\n", vcap.driver);
807 		}
808 		else {
809 			printf("Symbols for driver %s:\n", curr_bd->name);
810 			for (int i = 0; i < curr_bd->regs_size; i++)
811 				printf("0x%08x: %s\n", curr_bd->regs[i].reg, curr_bd->regs[i].name);
812 			for (int i = 0; i < curr_bd->alt_regs_size; i++)
813 				printf("0x%08x: %s\n", curr_bd->alt_regs[i].reg, curr_bd->alt_regs[i].name);
814 		}
815 	}
816 
817 	close(fd);
818 	std::exit(EXIT_SUCCESS);
819 }
820