diff options
Diffstat (limited to 'v4l2-apps/util/v4l-board-dbg.c')
-rw-r--r-- | v4l2-apps/util/v4l-board-dbg.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/v4l2-apps/util/v4l-board-dbg.c b/v4l2-apps/util/v4l-board-dbg.c new file mode 100644 index 000000000..e74c7300e --- /dev/null +++ b/v4l2-apps/util/v4l-board-dbg.c @@ -0,0 +1,335 @@ +/* + Copyright (C) 2008 Mauro Carvalho Chehab <mchehab@infradead.org> + 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 <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <linux/types.h> +#include <linux/videodev2.h> + +#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 <args>\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); +} |