/* Copyright (C) 2008 Mauro Carvalho Chehab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include "bttv-dbg.h" #include "saa7134-dbg.h" #include "em28xx-dbg.h" #define ARRAY_SIZE(arr) ((int)(sizeof(arr) / sizeof((arr)[0]))) struct board_list { char *name; int prefix; /* Register prefix size */ struct board_regs *regs; int regs_size; struct board_regs *alt_regs; int alt_regs_size; }; struct board_list boards[] = { [0] = { /* From bttv-dbg.h */ .name = BTTV_IDENT, .prefix = sizeof(BTTV_PREFIX) - 1, .regs = bt8xx_regs, .regs_size = ARRAY_SIZE(bt8xx_regs), .alt_regs = bt8xx_regs_other, .alt_regs_size = ARRAY_SIZE(bt8xx_regs_other), }, [1] = { /* From saa7134-dbg.h */ .name = SAA7134_IDENT, .prefix = sizeof(SAA7134_PREFIX) - 1, .regs = saa7134_regs, .regs_size = ARRAY_SIZE(saa7134_regs), .alt_regs = NULL, .alt_regs_size = 0, }, [2] = { /* From em28xx-dbg.h */ .name = EM28XX_IDENT, .prefix = sizeof(EM28XX_PREFIX) - 1, .regs = em28xx_regs, .regs_size = ARRAY_SIZE(em28xx_regs), .alt_regs = NULL, .alt_regs_size = 0, }, }; static int is_get=0, is_set=0; static int doioctl(int fd, int request, void *parm, const char *name) { int retVal; printf("ioctl %s ", name); retVal = ioctl(fd, request, parm); if (retVal < 0) printf("failed: %s\n", strerror(errno)); else printf("ok\n"); return retVal; } static void usage(void) { printf("bttv-dbg \n"); } enum Option { OptGetReg = 'g', OptSetReg = 's', OptHelp = 'h', }; static void print_bin (int val, int size) { int i, j, v; printf("("); for (i = size-1; i >= 0; i--) { v = (val >> (i * 8)) & 0xff; for (j = 7; j >= 0; j--) { int bit = (v >> j) & 0x1; if (bit) printf("1"); else printf("0"); } if (i) printf(" "); else printf(")"); } } int main(int argc, char **argv) { char *device = strdup("/dev/video0"); char *reg_set = NULL; int ch; int i; int fd = -1; struct v4l2_register reg; struct v4l2_capability cap; struct board_list *curr_bd; int board = 0; struct option long_options[] = { /* Please keep in alphabetical order of the short option. That makes it easier to see which options are still free. */ {"get-reg", no_argument, 0, OptGetReg}, {"set-reg", required_argument, 0, OptSetReg}, {"help", no_argument, 0, OptHelp}, {0, 0, 0, 0} }; /* command args */ if (argc == 1) { usage(); return 0; } while (1) { int option_index = 0; ch = getopt_long(argc, argv, "gs:", long_options, &option_index); if (ch == -1) break; switch (ch) { case OptHelp: usage(); return 0; case OptGetReg: is_get++; break; case OptSetReg: is_set++; reg_set = optarg; break; case '?': fprintf(stderr, "Unknown argument `%s'\n", argv[optind]); usage(); return 1; } } if (optind < argc) { printf("unknown arguments: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); usage(); return 1; } fd = open(device, O_RDWR); if (fd < 0) { fprintf(stderr, "Failed to open %s: %s\n", device, strerror(errno)); exit(1); } free(device); if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { printf("Error while reading capabilities\n"); exit(2); } for (board = ARRAY_SIZE(boards)-1; board >= 0; board--) { if (!strcasecmp((char *)cap.driver, boards[board].name)) break; } if (board < 0) { printf("This software doesn't support %s yet\n", cap.driver); exit(3); } curr_bd = &boards[board]; reg.match_type = V4L2_CHIP_MATCH_HOST; reg.match_chip = 0; if (is_get) { for (i = 0; i < curr_bd->regs_size; i++) { char name[256]; reg.reg = curr_bd->regs[i].reg; if (ioctl(fd, VIDIOC_DBG_G_REGISTER, ®) < 0) { printf("Error while reading. Maybe you're not root?\n"); continue; } sprintf(name, "%s:", curr_bd->regs[i].name); switch (curr_bd->regs[i].size) { case 1: printf("%-32s %02llx ", name, reg.val & 0xff); break; case 2: printf("%-32s %04llx ", name, reg.val & 0xffff); break; case 4: printf("%-32s %08llx ", name, reg.val & 0xffffffff); break; } print_bin (reg.val, curr_bd->regs[i].size); printf("\n"); } return 0; } if (is_set) { char *reg_name; int val; int r, size; unsigned prev; struct board_regs *bd_reg; reg_name = strtok(reg_set, "=:"); val = strtol(strtok(NULL, "=:"), 0L, 0); if (!reg_name) { printf("set argument is invalid\n"); return -1; } for (i = curr_bd->regs_size - 1; i >=0 ; i--) { if (!strcasecmp(reg_name, curr_bd->regs[i].name)) { bd_reg = &curr_bd->regs[i]; r = bd_reg->reg; size = bd_reg->size; break; } } if (i < 0) { for (i = curr_bd->alt_regs_size - 1; i >=0 ; i--) { if (!strcasecmp(reg_name, curr_bd->alt_regs[i].name)) { bd_reg = &curr_bd->alt_regs[i]; r = bd_reg->reg; size = bd_reg->size; break; } } } if (i < 0) { for (i = curr_bd->regs_size - 1; i >=0 ; i--) { if (!strcasecmp(reg_name, curr_bd->regs[i].name + curr_bd->prefix)) { bd_reg = &curr_bd->regs[i]; r = bd_reg->reg; size = bd_reg->size; break; } } } if (i < 0) { for (i = curr_bd->alt_regs_size - 1; i >=0 ; i--) { if (!strcasecmp(reg_name, curr_bd->alt_regs[i].name + curr_bd->prefix)) { bd_reg = &curr_bd->regs[i]; r = bd_reg->reg; size = bd_reg->size; break; } } } if (i < 0) { printf("Register not found\n"); return -1; } reg.reg = r; if (ioctl(fd, VIDIOC_DBG_G_REGISTER, ®) < 0) { printf("Error while reading register 0x%02x\n", r); return -1; } prev = reg.val; switch (size) { case 1: reg.val = (reg.val & (~0xff)) | val; break; case 2: reg.val = (reg.val & (~0xffff)) | val; break; case 4: reg.val = val; break; } printf("Changing value of register %s(0x%x) from 0x%02x to 0x%02x\n", bd_reg->name, r, prev, (unsigned int)reg.val); prev = reg.val; if (ioctl(fd, VIDIOC_DBG_S_REGISTER, ®) < 0) { printf("Error while writing\n"); return -1; } if (ioctl(fd, VIDIOC_DBG_G_REGISTER, ®) < 0) { printf("Error while reading register 0x%02x\n", r); return -1; } if (reg.val != prev) { printf("Value of register %s(0x%x) is now 0x%02x\n", bd_reg->name, r, (unsigned int)reg.val); } } close(fd); exit(0); }