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 ®)
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