2
Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
#include <features.h> /* Uses _GNU_SOURCE to define getsubopt in stdlib.h */
26
#include <sys/types.h>
31
#include <sys/ioctl.h>
36
#include <linux/videodev2.h>
37
#include <linux/i2c-id.h>
38
#include <media/v4l2-chip-ident.h>
45
#include "v4l2-dbg-bttv.h"
46
#include "v4l2-dbg-saa7134.h"
47
#include "v4l2-dbg-em28xx.h"
48
#include "v4l2-dbg-ac97.h"
49
#include "v4l2-dbg-tvp5150.h"
50
#include "v4l2-dbg-micron.h"
52
#define ARRAY_SIZE(arr) ((int)(sizeof(arr) / sizeof((arr)[0])))
56
int prefix; /* Register prefix size */
57
const struct board_regs *regs;
59
const struct board_regs *alt_regs;
63
static const struct board_list boards[] = {
65
{ /* From v4l2-dbg-ac97.h */
67
sizeof(AC97_PREFIX) - 1,
69
ARRAY_SIZE(ac97_regs),
73
{ /* From v4l2-dbg-bttv.h */
75
sizeof(BTTV_PREFIX) - 1,
77
ARRAY_SIZE(bt8xx_regs),
79
ARRAY_SIZE(bt8xx_regs_other),
81
{ /* From v4l2-dbg-saa7134.h */
83
sizeof(SAA7134_PREFIX) - 1,
85
ARRAY_SIZE(saa7134_regs),
89
{ /* From v4l2-dbg-em28xx.h */
91
sizeof(EM28XX_PREFIX) - 1,
93
ARRAY_SIZE(em28xx_regs),
95
ARRAY_SIZE(em28xx_alt_regs),
97
{ /* From v4l2-dbg-tvp5150.h */
99
sizeof(TVP5150_PREFIX) - 1,
101
ARRAY_SIZE(tvp5150_regs),
105
{ /* From v4l2-dbg-micron.h */
107
sizeof(MT9V011_PREFIX) - 1,
109
ARRAY_SIZE(mt9v011_regs),
120
extern struct chipid chipids[];
124
Please keep in alphabetical order.
125
That makes it easier to see which short options are still free.
127
In general the lower case is used to set something and the upper
128
case is used to retrieve a setting. */
130
OptListRegisters = 'l',
131
OptGetRegister = 'g',
132
OptSetRegister = 's',
134
OptGetDriverInfo = 'D',
136
OptScanChipIdents = 'S',
137
OptGetChipIdent = 'i',
147
static char options[OptLast];
149
static unsigned capabilities;
151
static struct option long_options[] = {
152
{"device", required_argument, 0, OptSetDevice},
153
{"help", no_argument, 0, OptHelp},
154
{"list-registers", optional_argument, 0, OptListRegisters},
155
{"get-register", required_argument, 0, OptGetRegister},
156
{"set-register", required_argument, 0, OptSetRegister},
157
{"chip", required_argument, 0, OptChip},
158
{"scan-chip-idents", no_argument, 0, OptScanChipIdents},
159
{"get-chip-ident", no_argument, 0, OptGetChipIdent},
160
{"info", no_argument, 0, OptGetDriverInfo},
161
{"verbose", no_argument, 0, OptVerbose},
162
{"log-status", no_argument, 0, OptLogStatus},
163
{"list-symbols", no_argument, 0, OptListSymbols},
164
{"wide", required_argument, 0, OptSetStride},
168
static void usage(void)
170
printf("Usage: v4l2-dbg [options] [values]\n"
171
" -D, --info Show driver info [VIDIOC_QUERYCAP]\n"
172
" -d, --device=<dev> Use device <dev> instead of /dev/video0\n"
173
" If <dev> is a single digit, then /dev/video<dev> is used\n"
174
" -h, --help Display this help message\n"
175
" --verbose Turn on verbose ioctl error reporting\n"
176
" -c, --chip=<chip> The chip identifier to use with other commands\n"
177
" It can be one of:\n"
179
" I2C 7-bit address\n"
180
" AC97: for ac97 anciliary mixer\n"
181
" host<num>: host chip number <num>\n"
182
" host (default): same as host0\n"
183
" -l, --list-registers[=min=<addr>[,max=<addr>]]\n"
184
" Dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]\n"
185
" -g, --get-register=<addr>\n"
186
" Get the specified register [VIDIOC_DBG_G_REGISTER]\n"
187
" -s, --set-register=<addr>\n"
188
" Set the register with the commandline arguments\n"
189
" The register will autoincrement [VIDIOC_DBG_S_REGISTER]\n"
190
" -S, --scan-chip-idents\n"
191
" Scan the available host and i2c chips [VIDIOC_DBG_G_CHIP_IDENT]\n"
192
" -i, --get-chip-ident\n"
193
" Get the chip identifier [VIDIOC_DBG_G_CHIP_IDENT]\n"
194
" -w, --wide=<reg length>\n"
195
" Sets step between two registers\n"
196
" --list-symbols List the symbolic register names you can use, if any\n"
197
" --log-status Log the board status in the kernel log [VIDIOC_LOG_STATUS]\n");
201
static std::string cap2s(unsigned cap)
205
if (cap & V4L2_CAP_VIDEO_CAPTURE)
206
s += "\t\tVideo Capture\n";
207
if (cap & V4L2_CAP_VIDEO_OUTPUT)
208
s += "\t\tVideo Output\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_TUNER)
225
if (cap & V4L2_CAP_AUDIO)
227
if (cap & V4L2_CAP_RADIO)
229
if (cap & V4L2_CAP_READWRITE)
230
s += "\t\tRead/Write\n";
231
if (cap & V4L2_CAP_ASYNCIO)
232
s += "\t\tAsync I/O\n";
233
if (cap & V4L2_CAP_STREAMING)
234
s += "\t\tStreaming\n";
238
static void print_regs(int fd, struct v4l2_dbg_register *reg, unsigned long min, unsigned long max, int stride)
240
unsigned long mask = stride > 1 ? 0x1f : 0x0f;
244
for (i = min & ~mask; i <= max; i += stride) {
245
if ((i & mask) == 0 && line % 32 == 0) {
247
printf("\n 00 04 08 0C 10 14 18 1C");
249
printf("\n 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
252
if ((i & mask) == 0) {
253
printf("\n%08lx: ", i);
257
printf("%*s ", 2 * stride, "");
261
if (ioctl(fd, VIDIOC_DBG_G_REGISTER, reg) < 0) {
262
fprintf(stderr, "ioctl: VIDIOC_DBG_G_REGISTER "
263
"failed for 0x%llx\n", reg->reg);
265
printf("%0*llx ", 2 * stride, reg->val);
272
static void print_chip(struct v4l2_dbg_chip_ident *chip)
274
const char *name = NULL;
276
for (int i = 0; chipids[i].name; i++) {
277
if (chipids[i].id == chip->ident) {
278
name = chipids[i].name;
283
printf("%-10s revision 0x%08x\n", name, chip->revision);
285
printf("%-10d revision 0x%08x\n", chip->ident, chip->revision);
288
static unsigned long long parse_reg(const struct board_list *curr_bd, const std::string ®)
291
for (int i = 0; i < curr_bd->regs_size; i++) {
292
if (!strcasecmp(reg.c_str(), curr_bd->regs[i].name) ||
293
!strcasecmp(reg.c_str(), curr_bd->regs[i].name + curr_bd->prefix)) {
294
return curr_bd->regs[i].reg;
297
for (int i = 0; i < curr_bd->alt_regs_size; i++) {
298
if (!strcasecmp(reg.c_str(), curr_bd->alt_regs[i].name) ||
299
!strcasecmp(reg.c_str(), curr_bd->alt_regs[i].name + curr_bd->prefix)) {
300
return curr_bd->alt_regs[i].reg;
304
return strtoull(reg.c_str(), NULL, 0);
307
static const char *reg_name(const struct board_list *curr_bd, unsigned long long reg)
310
for (int i = 0; i < curr_bd->regs_size; i++) {
311
if (reg == curr_bd->regs[i].reg)
312
return curr_bd->regs[i].name;
314
for (int i = 0; i < curr_bd->alt_regs_size; i++) {
315
if (reg == curr_bd->regs[i].reg)
316
return curr_bd->regs[i].name;
322
static const char *binary(unsigned long long val)
329
if ((val & 0xffffffff00000000LL) == 0) {
330
if ((val & 0xffff0000) == 0) {
331
if ((val & 0xff00) == 0)
340
for (i = bits - 1; i >= 0; i -= 8) {
341
for (j = i; j >= i - 7; j--) {
342
if (val & (1LL << j))
353
static int doioctl(int fd, unsigned long int request, void *parm, const char *name)
355
int retVal = ioctl(fd, request, parm);
357
if (options[OptVerbose]) {
359
printf("%s: failed: %s\n", name, strerror(errno));
361
printf("%s: ok\n", name);
367
static int parse_subopt(char **subs, const char * const *subopts, char **value)
369
int opt = getsubopt(subs, (char * const *)subopts, value);
372
fprintf(stderr, "Invalid suboptions specified\n");
377
fprintf(stderr, "No value given to suboption <%s>\n",
385
int main(int argc, char **argv)
388
int i, forcedstride = 0;
394
const char *device = "/dev/video0"; /* -d device */
395
struct v4l2_capability vcap; /* list_cap */
396
struct v4l2_dbg_register set_reg;
397
struct v4l2_dbg_register get_reg;
398
struct v4l2_dbg_chip_ident chip_id;
399
const struct board_list *curr_bd = NULL;
400
char short_options[26 * 2 * 2 + 1];
402
std::string reg_min_arg, reg_max_arg;
403
std::string reg_set_arg;
404
unsigned long long reg_min = 0, reg_max = 0;
405
std::vector<std::string> get_regs;
406
struct v4l2_dbg_match match;
408
match.type = V4L2_CHIP_MATCH_HOST;
410
memset(&set_reg, 0, sizeof(set_reg));
411
memset(&get_reg, 0, sizeof(get_reg));
412
memset(&chip_id, 0, sizeof(chip_id));
418
for (i = 0; long_options[i].name; i++) {
419
if (!isalpha(long_options[i].val))
421
short_options[idx++] = long_options[i].val;
422
if (long_options[i].has_arg == required_argument)
423
short_options[idx++] = ':';
426
int option_index = 0;
428
short_options[idx] = 0;
429
ch = getopt_long(argc, argv, short_options,
430
long_options, &option_index);
434
options[(int)ch] = 1;
442
if (device[0] >= '0' && device[0] <= '9' && device[1] == 0) {
443
static char newdev[20];
444
char dev = device[0];
446
sprintf(newdev, "/dev/video%c", dev);
452
if (isdigit(optarg[0])) {
453
match.type = V4L2_CHIP_MATCH_I2C_ADDR;
454
match.addr = strtoul(optarg, NULL, 0);
457
if (!memcmp(optarg, "host", 4)) {
458
match.type = V4L2_CHIP_MATCH_HOST;
459
match.addr = strtoul(optarg + 4, NULL, 0);
462
if (!strcasecmp(optarg, "ac97")) {
463
match.type = V4L2_CHIP_MATCH_AC97;
467
match.type = V4L2_CHIP_MATCH_I2C_DRIVER;
468
strncpy(match.name, optarg, sizeof(match.name));
469
match.name[sizeof(match.name) - 1] = '\0';
473
reg_set_arg = optarg;
477
get_regs.push_back(optarg);
481
forcedstride = strtoull(optarg, 0L, 0);
484
case OptListRegisters:
489
while (*subs != '\0') {
490
static const char * const subopts[] = {
496
switch (parse_subopt(&subs, subopts, &value)) {
500
// reg_max = reg_min + 0xff;
509
case OptGetChipIdent:
514
fprintf(stderr, "Option `%s' requires a value\n",
520
fprintf(stderr, "Unknown argument `%s'\n",
527
if ((fd = open(device, O_RDWR)) < 0) {
528
fprintf(stderr, "Failed to open %s: %s\n", device,
533
doioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP");
534
capabilities = vcap.capabilities;
536
/* Information Opts */
538
if (options[OptGetDriverInfo]) {
539
printf("Driver info:\n");
540
printf("\tDriver name : %s\n", vcap.driver);
541
printf("\tCard type : %s\n", vcap.card);
542
printf("\tBus info : %s\n", vcap.bus_info);
543
printf("\tDriver version: %d\n", vcap.version);
544
printf("\tCapabilities : 0x%08X\n", vcap.capabilities);
545
printf("%s", cap2s(vcap.capabilities).c_str());
548
if (match.type == V4L2_CHIP_MATCH_AC97) {
549
curr_bd = &boards[AC97_BOARD];
550
} else if (match.type == V4L2_CHIP_MATCH_HOST) {
551
for (int board = ARRAY_SIZE(boards) - 1; board >= 0; board--) {
552
if (!strcasecmp((char *)vcap.driver, boards[board].name)) {
553
curr_bd = &boards[board];
557
} else if (match.type == V4L2_CHIP_MATCH_I2C_DRIVER) {
558
for (int board = ARRAY_SIZE(boards) - 1; board >= 0; board--) {
559
if (!strcasecmp(match.name, boards[board].name)) {
560
curr_bd = &boards[board];
568
if (options[OptSetRegister]) {
569
set_reg.match = match;
572
set_reg.reg = parse_reg(curr_bd, reg_set_arg);
573
while (optind < argc) {
574
set_reg.val = strtoull(argv[optind++], NULL, 0);
575
if (doioctl(fd, VIDIOC_DBG_S_REGISTER, &set_reg,
576
"VIDIOC_DBG_S_REGISTER") >= 0) {
577
const char *name = reg_name(curr_bd, set_reg.reg);
582
printf("%s (0x%08llx)", name, set_reg.reg);
584
printf("0x%08llx", set_reg.reg);
586
printf(" set to 0x%llx\n", set_reg.val);
588
printf("Failed to set register 0x%08llx value 0x%llx: %s\n",
589
set_reg.reg, set_reg.val, strerror(errno));
595
if (options[OptGetChipIdent]) {
596
chip_id.match = match;
597
if (doioctl(fd, VIDIOC_DBG_G_CHIP_IDENT, &chip_id, "VIDIOC_DBG_G_CHIP_IDENT") == 0)
598
print_chip(&chip_id);
601
if (options[OptScanChipIdents]) {
604
chip_id.match.type = V4L2_CHIP_MATCH_HOST;
605
chip_id.match.addr = 0;
607
while (doioctl(fd, VIDIOC_DBG_G_CHIP_IDENT, &chip_id, "VIDIOC_DBG_G_CHIP_IDENT") == 0 && chip_id.ident) {
608
printf("host%d: ", chip_id.match.addr);
609
print_chip(&chip_id);
610
chip_id.match.addr++;
613
chip_id.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
614
for (i = 0; i < 128; i++) {
615
chip_id.match.addr = i;
616
if (doioctl(fd, VIDIOC_DBG_G_CHIP_IDENT, &chip_id, "VIDIOC_DBG_G_CHIP_IDENT") == 0 && chip_id.ident) {
617
printf("i2c 0x%02x: ", i);
618
print_chip(&chip_id);
623
if (options[OptGetRegister]) {
626
get_reg.match = match;
627
printf("ioctl: VIDIOC_DBG_G_REGISTER\n");
629
for (std::vector<std::string>::iterator iter = get_regs.begin();
630
iter != get_regs.end(); ++iter) {
631
get_reg.reg = parse_reg(curr_bd, *iter);
632
if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &get_reg) < 0)
633
fprintf(stderr, "ioctl: VIDIOC_DBG_G_REGISTER "
634
"failed for 0x%llx\n", get_reg.reg);
636
const char *name = reg_name(curr_bd, get_reg.reg);
641
printf("%s (0x%08llx)", name, get_reg.reg);
643
printf("0x%08llx", get_reg.reg);
645
printf(" = %llxh (%lldd %sb)\n",
646
get_reg.val, get_reg.val, binary(get_reg.val));
651
if (options[OptListRegisters]) {
655
get_reg.match = match;
657
stride = forcedstride;
658
} else if (get_reg.match.type == V4L2_CHIP_MATCH_HOST) {
661
printf("ioctl: VIDIOC_DBG_G_REGISTER\n");
664
if (reg_min_arg.empty())
667
reg_min = parse_reg(curr_bd, reg_min_arg);
670
if (reg_max_arg.empty())
671
reg_max = (1ll << 32) - 1;
673
reg_max = parse_reg(curr_bd, reg_max_arg);
675
for (int i = 0; i < curr_bd->regs_size; i++) {
676
if (reg_min_arg.empty() || ((curr_bd->regs[i].reg >= reg_min) && curr_bd->regs[i].reg <= reg_max)) {
677
get_reg.reg = curr_bd->regs[i].reg;
679
if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &get_reg) < 0)
680
fprintf(stderr, "ioctl: VIDIOC_DBG_G_REGISTER "
681
"failed for 0x%llx\n", get_reg.reg);
683
const char *name = reg_name(curr_bd, get_reg.reg);
688
printf("%s (0x%08llx)", name, get_reg.reg);
690
printf("0x%08llx", get_reg.reg);
692
printf(" = %llxh (%lldd %sb)\n",
693
get_reg.val, get_reg.val, binary(get_reg.val));
700
if (!reg_min_arg.empty()) {
701
reg_min = parse_reg(curr_bd, reg_min_arg);
702
if (reg_max_arg.empty())
703
reg_max = reg_min + 0xff;
705
reg_max = parse_reg(curr_bd, reg_max_arg);
706
/* Explicit memory range: just do it */
707
print_regs(fd, &get_reg, reg_min, reg_max, stride);
711
/* try to figure out which chip it is */
712
chip_id.match = match;
713
if (doioctl(fd, VIDIOC_DBG_G_CHIP_IDENT, &chip_id, "VIDIOC_DBG_G_CHIP_IDENT") != 0) {
714
chip_id.ident = V4L2_IDENT_NONE;
716
switch (chip_id.ident) {
717
case V4L2_IDENT_CX23415:
718
case V4L2_IDENT_CX23416:
721
case V4L2_IDENT_CX23418:
724
case V4L2_IDENT_CAFE:
728
if (get_reg.match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
729
name = get_reg.match.name;
733
if (name == "saa7115") {
734
print_regs(fd, &get_reg, 0, 0xff, stride);
735
} else if (name == "saa717x") {
736
// FIXME: use correct reg regions
737
print_regs(fd, &get_reg, 0, 0xff, stride);
738
} else if (name == "saa7127") {
739
print_regs(fd, &get_reg, 0, 0x7f, stride);
740
} else if (name == "ov7670") {
741
print_regs(fd, &get_reg, 0, 0x89, stride);
742
} else if (name == "cx25840") {
743
print_regs(fd, &get_reg, 0, 2, stride);
744
print_regs(fd, &get_reg, 0x100, 0x15f, stride);
745
print_regs(fd, &get_reg, 0x200, 0x23f, stride);
746
print_regs(fd, &get_reg, 0x400, 0x4bf, stride);
747
print_regs(fd, &get_reg, 0x800, 0x9af, stride);
748
} else if (name == "cs5345") {
749
print_regs(fd, &get_reg, 1, 0x10, stride);
750
} else if (name == "cx23416") {
751
print_regs(fd, &get_reg, 0x02000000, 0x020000ff, stride);
752
} else if (name == "cx23418") {
753
print_regs(fd, &get_reg, 0x02c40000, 0x02c409c7, stride);
754
} else if (name == "cafe") {
755
print_regs(fd, &get_reg, 0, 0x43, stride);
756
print_regs(fd, &get_reg, 0x88, 0x8f, stride);
757
print_regs(fd, &get_reg, 0xb4, 0xbb, stride);
758
print_regs(fd, &get_reg, 0x3000, 0x300c, stride);
760
/* unknown chip, dump 0-0xff by default */
761
print_regs(fd, &get_reg, 0, 0xff, stride);
766
if (options[OptLogStatus]) {
767
static char buf[40960];
770
if (doioctl(fd, VIDIOC_LOG_STATUS, NULL, "VIDIOC_LOG_STATUS") == 0) {
771
printf("\nStatus Log:\n\n");
772
len = klogctl(3, buf, sizeof(buf) - 1);
778
while ((q = strstr(p, "START STATUS CARD #"))) {
782
while (p > buf && *p != '<') p--;
784
while ((q = strstr(q, "<6>"))) {
793
if (options[OptListSymbols]) {
794
if (curr_bd == NULL) {
795
printf("No symbols found for driver %s\n", vcap.driver);
798
printf("Symbols for driver %s:\n", curr_bd->name);
799
for (int i = 0; i < curr_bd->regs_size; i++)
800
printf("0x%08x: %s\n", curr_bd->regs[i].reg, curr_bd->regs[i].name);
801
for (int i = 0; i < curr_bd->alt_regs_size; i++)
802
printf("0x%08x: %s\n", curr_bd->alt_regs[i].reg, curr_bd->alt_regs[i].name);