diff options
Diffstat (limited to 'v4l2-apps')
-rw-r--r-- | v4l2-apps/test/Makefile | 7 | ||||
-rw-r--r-- | v4l2-apps/test/v4l2grab.c | 162 | ||||
-rw-r--r-- | v4l2-apps/util/Makefile | 26 | ||||
-rw-r--r-- | v4l2-apps/util/cx18-ctl.c | 51 | ||||
-rwxr-xr-x | v4l2-apps/util/gen_keytables.pl | 7 | ||||
-rw-r--r-- | v4l2-apps/util/ivtv-ctl.c | 47 | ||||
-rw-r--r-- | v4l2-apps/util/keytable.c | 43 | ||||
-rw-r--r-- | v4l2-apps/util/rewrite_eeprom.pl | 336 | ||||
-rw-r--r-- | v4l2-apps/util/v4l2-ctl.cpp | 639 | ||||
-rw-r--r-- | v4l2-apps/util/v4l2-dbg-micron.h | 46 | ||||
-rw-r--r-- | v4l2-apps/util/v4l2-dbg.cpp | 29 | ||||
-rw-r--r-- | v4l2-apps/util/v4l2-sysfs-path.c | 130 | ||||
-rw-r--r-- | v4l2-apps/util/xc3028-firmware/firmware-tool.c | 4 |
13 files changed, 1327 insertions, 200 deletions
diff --git a/v4l2-apps/test/Makefile b/v4l2-apps/test/Makefile index d118b9210..13eebf377 100644 --- a/v4l2-apps/test/Makefile +++ b/v4l2-apps/test/Makefile @@ -7,6 +7,7 @@ binaries = ioctl-test \ sliced-vbi-detect \ vbi-test \ v4lgrab \ + v4l2grab \ driver-test \ pixfmt-test \ stress-buffer \ @@ -24,9 +25,15 @@ install: ../libv4l2util/libv4l2util.a: ../libv4l2util/v4l2_driver.c ../libv4l2util/frequencies.c make -C ../libv4l2util libv4l2util.a +../libv4l/libv4l2/libv4l2.so: + make -C ../libv4l/ + driver-test: driver-test.o ../libv4l2util/libv4l2util.a pixfmt-test: pixfmt-test.o $(CC) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ -lX11 +v4l2grab: v4l2grab.o + $(CC) $(LDFLAGS) $^ -o $@ -L ../libv4l/libv4l2 -L ../libv4l/libv4lconvert -lv4l2 -lv4lconvert + include ../Make.rules diff --git a/v4l2-apps/test/v4l2grab.c b/v4l2-apps/test/v4l2grab.c new file mode 100644 index 000000000..de921874b --- /dev/null +++ b/v4l2-apps/test/v4l2grab.c @@ -0,0 +1,162 @@ +/* V4L2 video picture grabber + Copyright (C) 2009 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <linux/videodev2.h> +#include "../libv4l/include/libv4l2.h" + +#define CLEAR(x) memset(&(x), 0, sizeof(x)) + +struct buffer { + void *start; + size_t length; +}; + +static void xioctl(int fh, int request, void *arg) +{ + int r; + + do { + r = v4l2_ioctl(fh, request, arg); + } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); + + if (r == -1) { + fprintf(stderr, "error %d, %s\n", errno, strerror(errno)); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char **argv) +{ + struct v4l2_format fmt; + struct v4l2_buffer buf; + struct v4l2_requestbuffers req; + enum v4l2_buf_type type; + fd_set fds; + struct timeval tv; + int r, fd = -1; + unsigned int i, n_buffers; + char *dev_name = "/dev/video0"; + char out_name[256]; + FILE *fout; + struct buffer *buffers; + + fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); + if (fd < 0) { + perror("Cannot open device"); + exit(EXIT_FAILURE); + } + + CLEAR(fmt); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = 640; + fmt.fmt.pix.height = 480; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + xioctl(fd, VIDIOC_S_FMT, &fmt); + if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) { + printf("Libv4l didn't accept RGB24 format. Can't proceed.\n"); + exit(EXIT_FAILURE); + } + if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480)) + printf("Warning: driver is sending image at %dx%d\n", + fmt.fmt.pix.width, fmt.fmt.pix.height); + + CLEAR(req); + req.count = 2; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + xioctl(fd, VIDIOC_REQBUFS, &req); + + buffers = calloc(req.count, sizeof(*buffers)); + for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { + CLEAR(buf); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = n_buffers; + + xioctl(fd, VIDIOC_QUERYBUF, &buf); + + buffers[n_buffers].length = buf.length; + buffers[n_buffers].start = v4l2_mmap(NULL, buf.length, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, buf.m.offset); + + if (MAP_FAILED == buffers[n_buffers].start) { + perror("mmap"); + exit(EXIT_FAILURE); + } + } + + for (i = 0; i < n_buffers; ++i) { + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + xioctl(fd, VIDIOC_QBUF, &buf); + } + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + xioctl(fd, VIDIOC_STREAMON, &type); + for (i = 0; i < 20; i++) { + do { + FD_ZERO(&fds); + FD_SET(fd, &fds); + + /* Timeout. */ + tv.tv_sec = 2; + tv.tv_usec = 0; + + r = select(fd + 1, &fds, NULL, NULL, &tv); + } while ((r == -1 && (errno = EINTR))); + if (r == -1) { + perror("select"); + return errno; + } + + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + xioctl(fd, VIDIOC_DQBUF, &buf); + + sprintf(out_name, "out%03d.ppm", i); + fout = fopen(out_name, "w"); + if (!fout) { + perror("Cannot open image"); + exit(EXIT_FAILURE); + } + fprintf(fout, "P6\n%d %d 255\n", + fmt.fmt.pix.width, fmt.fmt.pix.height); + fwrite(buffers[buf.index].start, buf.bytesused, 1, fout); + fclose(fout); + + xioctl(fd, VIDIOC_QBUF, &buf); + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + xioctl(fd, VIDIOC_STREAMOFF, &type); + for (i = 0; i < n_buffers; ++i) + v4l2_munmap(buffers[i].start, buffers[i].length); + v4l2_close(fd); + + return 0; +} diff --git a/v4l2-apps/util/Makefile b/v4l2-apps/util/Makefile index 6f9d1071a..29f3f4852 100644 --- a/v4l2-apps/util/Makefile +++ b/v4l2-apps/util/Makefile @@ -1,5 +1,26 @@ # Makefile for linuxtv.org v4l2-apps/util +IR_FILES = "linux/drivers/media/common/ir-keymaps.c \ +linux/drivers/media/dvb/dvb-usb/a800.c \ +linux/drivers/media/dvb/dvb-usb/af9005-remote.c \ +linux/drivers/media/dvb/dvb-usb/af9015.c \ +linux/drivers/media/dvb/dvb-usb/af9015.h \ +linux/drivers/media/dvb/dvb-usb/anysee.c \ +linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c \ +linux/drivers/media/dvb/dvb-usb/cxusb.c \ +linux/drivers/media/dvb/dvb-usb/dib0700_devices.c \ +linux/drivers/media/dvb/dvb-usb/dibusb-common.c \ +linux/drivers/media/dvb/dvb-usb/digitv.c \ +linux/drivers/media/dvb/dvb-usb/dtt200u.c \ +linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c \ +linux/drivers/media/dvb/dvb-usb/dvb-usb.h \ +linux/drivers/media/dvb/dvb-usb/dw2102.c \ +linux/drivers/media/dvb/dvb-usb/m920x.c \ +linux/drivers/media/dvb/dvb-usb/nova-t-usb2.c \ +linux/drivers/media/dvb/dvb-usb/opera1.c \ +linux/drivers/media/dvb/dvb-usb/vp702x.c \ +linux/drivers/media/dvb/dvb-usb/vp7045.c " + ifeq ($(KERNEL_DIR),) KERNEL_DIR = /usr endif @@ -62,8 +83,9 @@ parse.h: $(KERNEL_DIR)/include/linux/input.h @printf "\t{ NULL, 0}\n};\n" >>parse.h keytables: - -mkdir -p keycodes - ./gen_keytables.pl ../../linux/drivers/media/common/ir-keymaps.c + @-mkdir -p keycodes + @echo storing existing keycodes at keycodes/ + @for i in `echo $(IR_FILES)`; do ./gen_keytables.pl ../../$$i; done keytable: keytable.c parse.h keytables diff --git a/v4l2-apps/util/cx18-ctl.c b/v4l2-apps/util/cx18-ctl.c index 3d8ff385d..138f3c26a 100644 --- a/v4l2-apps/util/cx18-ctl.c +++ b/v4l2-apps/util/cx18-ctl.c @@ -52,12 +52,6 @@ #define CX18_DBGFLG_HIGHVOL (1 << 8) /* Internals copied from media/v4l2-common.h */ -struct v4l2_routing { - __u32 input; - __u32 output; -}; -#define VIDIOC_INT_S_AUDIO_ROUTING _IOW('d', 109, struct v4l2_routing) - #define VIDIOC_INT_RESET _IOW('d', 102, __u32) #define __stringify_1(x) #x @@ -80,7 +74,6 @@ enum Option { OptHelp = 'h', OptSetGPIO = 'i', OptListGPIO = 'I', - OptSetAudioRoute = 'v', OptReset = 128, OptVersion, OptLast = 256 @@ -97,7 +90,6 @@ static struct option long_options[] = { {"help", no_argument, 0, OptHelp}, {"set-gpio", required_argument, 0, OptSetGPIO}, {"list-gpio", no_argument, 0, OptListGPIO}, - {"audio-route", required_argument, 0, OptSetAudioRoute}, {"reset", required_argument, 0, OptReset}, {"version", no_argument, 0, OptVersion}, {0, 0, 0, 0} @@ -129,8 +121,6 @@ static void usage(void) printf(" show GPIO input/direction/output bits\n"); printf(" -i, --set-gpio [dir=<dir>,]val=<val>\n"); printf(" set GPIO direction bits to <dir> and set output to <val>\n"); - printf(" -v, --audio-route=input=<in>,output=<out>\n"); - printf(" set the audio input/output routing [VIDIOC_INT_S_AUDIO_ROUTING]\n"); exit(0); } @@ -250,14 +240,8 @@ int main(int argc, char **argv) char *subopts[] = { #define SUB_VAL 0 "val", -#define SUB_YUV_MODE 1 - "mode", -#define SUB_DIR 2 +#define SUB_DIR 1 "dir", -#define SUB_INPUT 3 - "input", -#define SUB_OUTPUT 4 - "output", NULL }; @@ -270,7 +254,6 @@ int main(int argc, char **argv) const char *device = "/dev/video0"; /* -d device */ int ch; int yuv_mode = 0; - struct v4l2_routing route; /* audio_route */ unsigned int gpio_out = 0x0; /* GPIO output data */ unsigned int gpio_dir = 0x0; /* GPIO direction bits */ int gpio_set_dir = 0; @@ -321,34 +304,6 @@ int main(int argc, char **argv) device = newdev; } break; - case OptSetAudioRoute: - subs = optarg; - while (*subs != '\0') { - switch (getsubopt(&subs, subopts, &value)) { - case SUB_INPUT: - if (value == NULL) { - printf - ("No value given to suboption <input>\n"); - usage(); - } - route.input = strtol(value, 0L, 0); - break; - case SUB_OUTPUT: - if (value == NULL) { - printf - ("No value given to suboption <output>\n"); - usage(); - } - route.output = strtol(value, 0L, 0); - break; - default: - printf - ("Invalid suboptions specified\n"); - usage(); - break; - } - } - break; case OptReset: reset = strtol(optarg, 0L, 0); break; @@ -414,10 +369,6 @@ int main(int argc, char **argv) } /* Setting Opts */ - - if (options[OptSetAudioRoute]) - doioctl(fd, VIDIOC_INT_S_AUDIO_ROUTING, &route, "VIDIOC_INT_S_AUDIO_ROUTING"); - if (options[OptSetGPIO]) { struct v4l2_dbg_register reg; diff --git a/v4l2-apps/util/gen_keytables.pl b/v4l2-apps/util/gen_keytables.pl index 889516de4..fad4ccfeb 100755 --- a/v4l2-apps/util/gen_keytables.pl +++ b/v4l2-apps/util/gen_keytables.pl @@ -5,9 +5,8 @@ my $keyname=""; my $debug=0; while (<>) { -#IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE] = { - if (m/IR_KEYTAB_TYPE\s+(\w[\w\d_]+)/) { - $keyname = $1; + if (m/struct\s+(dvb_usb_rc_key|ir_scancode)\s+(\w[\w\d_]+)/) { + $keyname = $2; $keyname =~ s/^ir_codes_//; print "Generating keycodes/$keyname\n" if $debug; @@ -15,7 +14,7 @@ while (<>) { next; } if ($keyname ne "") { - if (m/(0x[\d\w]+).*(KEY_[^\s\,]+)/) { + if (m/(0x[\dA-Fa-f]+).*(KEY_[^\s\,\}]+)/) { printf OUT "%s %s\n",$1, $2; next; } diff --git a/v4l2-apps/util/ivtv-ctl.c b/v4l2-apps/util/ivtv-ctl.c index a05dcbba2..6af8fc663 100644 --- a/v4l2-apps/util/ivtv-ctl.c +++ b/v4l2-apps/util/ivtv-ctl.c @@ -56,12 +56,6 @@ #define IVTV_DBGFLG_HIGHVOL (1 << 10) /* Internals copied from media/v4l2-common.h */ -struct v4l2_routing { - __u32 input; - __u32 output; -}; -#define VIDIOC_INT_S_AUDIO_ROUTING _IOW('d', 109, struct v4l2_routing) - #define VIDIOC_INT_RESET _IOW('d', 102, __u32) #include <linux/ivtv.h> @@ -81,7 +75,6 @@ enum Option { OptListGPIO = 'I', OptPassThrough = 'K', OptFrameSync = 'k', - OptSetAudioRoute = 'v', OptReset = 128, OptSetYuvMode, OptGetYuvMode, @@ -106,7 +99,6 @@ static struct option long_options[] = { {"list-gpio", no_argument, 0, OptListGPIO}, {"passthrough", required_argument, 0, OptPassThrough}, {"sync", no_argument, 0, OptFrameSync}, - {"audio-route", required_argument, 0, OptSetAudioRoute}, {"reset", required_argument, 0, OptReset}, {"get-yuv-mode", no_argument, 0, OptGetYuvMode}, {"set-yuv-mode", required_argument, 0, OptSetYuvMode}, @@ -167,8 +159,6 @@ static void usage(void) printf(" -i, --set-gpio [dir=<dir>,]val=<val>\n"); printf(" set GPIO direction bits to <dir> and set output to <val>\n"); printf(" -k, --sync test vsync's capabilities [VIDEO_GET_EVENT]\n"); - printf(" -v, --audio-route=input=<in>,output=<out>\n"); - printf(" set the audio input/output routing [VIDIOC_INT_S_AUDIO_ROUTING]\n"); exit(0); } @@ -330,10 +320,6 @@ int main(int argc, char **argv) "mode", #define SUB_DIR 2 "dir", -#define SUB_INPUT 3 - "input", -#define SUB_OUTPUT 4 - "output", NULL }; @@ -346,7 +332,6 @@ int main(int argc, char **argv) const char *device = "/dev/video0"; /* -d device */ int ch; int yuv_mode = 0; - struct v4l2_routing route; /* audio_route */ unsigned short gpio_out = 0x0; /* GPIO output data */ unsigned short gpio_dir = 0x0; /* GPIO direction bits */ int gpio_set_dir = 0; @@ -424,34 +409,6 @@ int main(int argc, char **argv) device = newdev; } break; - case OptSetAudioRoute: - subs = optarg; - while (*subs != '\0') { - switch (getsubopt(&subs, subopts, &value)) { - case SUB_INPUT: - if (value == NULL) { - printf - ("No value given to suboption <input>\n"); - usage(); - } - route.input = strtol(value, 0L, 0); - break; - case SUB_OUTPUT: - if (value == NULL) { - printf - ("No value given to suboption <output>\n"); - usage(); - } - route.output = strtol(value, 0L, 0); - break; - default: - printf - ("Invalid suboptions specified\n"); - usage(); - break; - } - } - break; case OptReset: reset = strtol(optarg, 0L, 0); break; @@ -529,10 +486,6 @@ int main(int argc, char **argv) /* Setting Opts */ - if (options[OptSetAudioRoute]) - doioctl(fd, VIDIOC_INT_S_AUDIO_ROUTING, &route, - "VIDIOC_INT_S_AUDIO_ROUTING"); - if (options[OptFrameSync]) { printf("ioctl: VIDEO_GET_EVENT\n"); diff --git a/v4l2-apps/util/keytable.c b/v4l2-apps/util/keytable.c index 3b922f12b..4283782d0 100644 --- a/v4l2-apps/util/keytable.c +++ b/v4l2-apps/util/keytable.c @@ -1,6 +1,6 @@ /* keytable.c - This program allows checking/replacing keys at IR - Copyright (C) 2006 Mauro Carvalho Chehab <mchehab@infradead.org> + Copyright (C) 2006-2009 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 @@ -29,7 +29,7 @@ void prtcode (int *codes) for (p=keynames;p->name!=NULL;p++) { if (p->value == (unsigned)codes[1]) { - printf("scancode %d = %s (0x%02x)\n", codes[0], p->name, codes[1]); + printf("scancode 0x%04x = %s (0x%02x)\n", codes[0], p->name, codes[1]); return; } } @@ -55,7 +55,7 @@ int parse_code(char *string) int main (int argc, char *argv[]) { int fd; - unsigned int i; + unsigned int i, j; int codes[2]; if (argc<2 || argc>4) { @@ -104,10 +104,12 @@ int main (int argc, char *argv[]) } /* Clears old table */ - for (i=0;i<256;i++) { - codes[0] = i; - codes[1] = 0; - ioctl(fd, EVIOCSKEYCODE, codes); + for (j = 0; j < 256; j++) { + for (i = 0; i < 256; i++) { + codes[0] = (j << 8) | i; + codes[1] = KEY_RESERVED; + ioctl(fd, EVIOCSKEYCODE, codes); + } } while (fgets(s,sizeof(s),fin)) { @@ -116,14 +118,21 @@ int main (int argc, char *argv[]) perror ("parsing input file scancode"); return -1; } + if (!strcasecmp(scancode, "scancode")) { + scancode = strtok(NULL,"\n\t =:"); + if (!scancode) { + perror ("parsing input file scancode"); + return -1; + } + } - keycode=strtok(NULL,"\n\t "); + keycode=strtok(NULL,"\n\t =:("); if (!keycode) { perror ("parsing input file keycode"); return -1; } - // printf ("parsing %s=%s:",scancode,keycode); + // printf ("parsing %s=%s:", scancode, keycode); value=parse_code(keycode); // printf ("\tvalue=%d\n",value); @@ -136,8 +145,11 @@ int main (int argc, char *argv[]) codes [0] = (unsigned) strtol(scancode, NULL, 0); codes [1] = (unsigned) value; - if(ioctl(fd, EVIOCSKEYCODE, codes)) + // printf("\t%04x=%04x\n",codes[0], codes[1]); + if(ioctl(fd, EVIOCSKEYCODE, codes)) { + fprintf(stderr, "Setting scancode 0x%04x with 0x%04x via ",codes[0], codes[1]); perror ("EVIOCSKEYCODE"); + } if(ioctl(fd, EVIOCGKEYCODE, codes)==0) prtcode(codes); @@ -146,12 +158,13 @@ int main (int argc, char *argv[]) } /* Get scancode table */ - for (i=0;i<256;i++) { - codes[0] = i; - if(ioctl(fd, EVIOCGKEYCODE, codes)==0) - prtcode(codes); + for (j = 0; j < 256; j++) { + for (i = 0; i < 256; i++) { + codes[0] = (j << 8) | i; + if (!ioctl(fd, EVIOCGKEYCODE, codes) && codes[1] != KEY_RESERVED) + prtcode(codes); + } } - return 0; } diff --git a/v4l2-apps/util/rewrite_eeprom.pl b/v4l2-apps/util/rewrite_eeprom.pl new file mode 100644 index 000000000..495c4717c --- /dev/null +++ b/v4l2-apps/util/rewrite_eeprom.pl @@ -0,0 +1,336 @@ +#!/usr/bin/perl -w +# +################################################################################ +# Copyright (C) 2009 +# +# Mauro Carvalho Chehab <mchehab@redhat.com> +# Douglas Schilling Landgraf <dougsland@redhat.com> +# +# 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. +# +# Although not very common, on a few devices, the eeprom may be erased, due to a +# bug on a *few eeprom* chipsets that sometimes considers i2c messages to other +# devices as being for it. +# +# The solution for it is to reprogram the eeprom with their original contents. +# +# Modules this script is known to work with: em28xx and saa7134 +# * Not tested against newer em28xx chipsets like the em2874 and em2884 +# +######################################################## +# NOTE # +################################################################################ +# Since the script will try to detect the proper i2c bus address, it will only # +# work well if you have just one V4L device connected. # +################################################################################ +# +######################################## +# What do you need to run this script? # +######################################## +# +# * eeprom - A dump file with the older eeprom. +# +# As example this is a dump from EMPIRE TV DUAL (310U): +# ^^^^^^^^^^^^^^ +# shell> dmesg +# +# [11196.181543] em28xx #0: i2c eeprom 00: 1a eb 67 95 1a eb 10 e3 d0 12 5c 03 6a 22 00 00 +# [11196.181559] em28xx #0: i2c eeprom 10: 00 00 04 57 4e 07 00 00 00 00 00 00 00 00 00 00 +# [11196.181572] em28xx #0: i2c eeprom 20: 46 00 01 00 f0 10 01 00 00 00 00 00 5b 1e 00 00 +# [11196.181585] em28xx #0: i2c eeprom 30: 00 00 20 40 20 80 02 20 01 01 00 00 00 00 00 00 +# [11196.181598] em28xx #0: i2c eeprom 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# [11196.181610] em28xx #0: i2c eeprom 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# [11196.181622] em28xx #0: i2c eeprom 60: 00 00 00 00 00 00 00 00 00 00 22 03 55 00 53 00 +# [11196.181635] em28xx #0: i2c eeprom 70: 42 00 20 00 32 00 38 00 38 00 31 00 20 00 44 00 +# [11196.181648] em28xx #0: i2c eeprom 80: 65 00 76 00 69 00 63 00 65 00 00 00 00 00 00 00 +# [11196.181660] em28xx #0: i2c eeprom 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# [11196.181673] em28xx #0: i2c eeprom a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# [11196.181685] em28xx #0: i2c eeprom b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# [11196.181698] em28xx #0: i2c eeprom c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# [11196.181710] em28xx #0: i2c eeprom d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# [11196.181722] em28xx #0: i2c eeprom e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# [11196.181735] em28xx #0: i2c eeprom f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +# +############################################# +# Where can I find my original eeprom? # +############################################# +# +# e.g: Old dmesg output +# +######################################## +# How this script works? # +######################################## +# +# To use it, you'll need to run the script, passing, as a parameter, the original dmesg with +# your original eeprom (before the corruption). Something like: +# +# shell> perl ./rewrite_eeprom my_old_dmesg_with_right_eeprom.txt > eeprom_script +# +# It will generate the eeprom_script file, with a script capable of recovering +# your eeprom. +# +# After having the proper eeprom_script generated, you'll need to run it, as root: +# +# shell> sh ./eeprom_script +# +# +# After running the script, your original contents should be restored. Try to +# remove it and reinsert to see if it will be properly detected again. +# +use Switch; + +$argv = $ARGV[0]; + +# Files +$file_eeprom = "/tmp/eeprom-original.txt"; +$file_bus = "/tmp/i2c-detect-bus.txt"; +$file_addr = "/tmp/i2c-detect-addr.txt"; +$file_i2c_tmp = "/tmp/i2ctmp.txt"; + +# Bus +$businfo = ""; +$addrinfo = ""; + +# Modules +$modules = "em28xx|saa713"; +$_ = $modules; +tr/|/ /d; +s/saa713/saa7134/g; +$modules_str = $_; + +# eeprom stuff +$eeprom_backup_dir = "~/.eeprom"; +$NR_EEPROM_REGS = 0; + +########################## +# Subroutines # +########################## + +sub build_script +{ + my $script_prevent; + + # Building script + + $script_prevent = "#!/bin/bash\n"; + $script_prevent .= "#\n"; + $script_prevent .= "# Notes:\n"; + $script_prevent .= "# - i2c_dev module should be loaded\n"; + $script_prevent .= "# - v4l driver should be loaded\n\n"; + + + $script_prevent .= "if [ ! \"\$UID\" = \"0\" ]; then\n\techo \"You must run this script as root\";\n\texit;\nfi\n\n"; + + $script_prevent .= "i2cset &> /dev/null\n"; + $script_prevent .= "if [ ! \"\$\?\" = \"1\" ]; then\n"; + $script_prevent .= "\techo \"Please install i2c-tools package before continue.\";\n"; + $script_prevent .= "\texit;\n"; + $script_prevent .= "fi\n\n"; + + $script_prevent .= "modprobe i2c-dev\n"; + $script_prevent .= "if [ ! \"\$\?\" = \"0\" ]; then\n"; + $script_prevent .= "\techo \"Can't load i2c-dev module.\";\n"; + $script_prevent .= "\texit;\n"; + $script_prevent .= "fi\n\n"; + + $script_prevent .= "clear;\n"; + $script_prevent .= "echo \""; + $script_prevent .= "\n\033[1;31m# # # ###### # # ### # # #####\n"; + $script_prevent .= "# # # # # # # ## # # ## # # #\n"; + $script_prevent .= "# # # # # # # # # # # # # # # \n"; + $script_prevent .= "# # # # # ###### # # # # # # # # ####\n"; + $script_prevent .= "# # # ####### # # # # # # # # # # #\n"; + $script_prevent .= "# # # # # # # # ## # # ## # #\n"; + $script_prevent .= " ## ## # # # # # # ### # # #####\033[0m\n\n"; + + + $script_prevent .= "This tool is *ONLY RECOMMENDED* in cases of: LOST or CORRUPTED EEPROM data.\n"; + $script_prevent .= "Otherwise:\n\nYOU MAY *LOST* THE CURRENT EEPROM FROM YOUR DEVICE AND IT WILL MAKE YOUR BOARD "; + $script_prevent .= "*DO NOT WORK* UNTIL YOU SET THE RIGHT EEPROM AGAIN!\n\n"; + $script_prevent .= "If you have *any doubt*, BEFORE run it contact people from: linux-media\@vger.kernel.org\n"; + + $script_prevent .= "Are you \033[1;31mABSOLUTELY SURE\033[0m to continue? (yes or not)\";\n\n"; + $script_prevent .= "read confirmation;\n"; + $script_prevent .= "if \[ ! \"\$confirmation\" = \"yes\" \]; then\n"; + $script_prevent .= "\techo \"process aborted\";\n"; + $script_prevent .= "\texit;\n"; + $script_prevent .= "fi\n\n"; + + $script_prevent .= "lsmod | egrep -e \"$modules\" &> /dev/null\n"; + $script_prevent .= "if [ ! \"\$\?\" = \"0\" ]; then\n"; + $script_prevent .= "\techo \"Aborting script.. None of the supported driver $modules_str are loaded. Did you forget to connect the device?\";\n"; + $script_prevent .= "\texit;"; + $script_prevent .= "\nfi\n\n"; + + print $script_prevent; +} + +sub check_user +{ + if ($>) { + die "You must run this program as root\n"; + } + +} + +sub get_bus_and_addr +{ + + my $lines = 0; + my $output = "#!/bin/bash\n"; + + system("\ni2cdetect -l | egrep -e \"$modules\" 2> /dev/null | cut -b 5 > $file_bus\n"); + + # Checking number if lines + open(FILE, $file_bus) or die "Can't open `$file_bus': $!"; + while (sysread FILE, $buffer, 1) { + $lines += ($buffer =~ tr/\n//); + } + close FILE; + + switch ($lines) { + case 0 { + $output .= "echo \"Could not detect i2c bus from any device, run again $0. Did you forget to connect the device?\";\n"; + $output .= "echo \"Modules supported: $modules_str\";\n"; + $output .= "exit;"; + print $output; + } + case 1 { + # Starting script + &build_script; + } + else { + $output .= "humm, I got too many busses, please connect or plug just a hardware peer time!\n"; + $output .= "Read a note inside the script!\n"; + $output .= "exit;"; + print $output; + } + } + + # Reading BUS from temporary file + open (FILE, $file_bus); + while (<FILE>) { + $businfo = "$_"; + chomp($businfo); + } + close FILE; + + system("i2cdetect -y $businfo > $file_i2c_tmp 2> /dev/null"); + system("awk \'NR==7\' $file_i2c_tmp | cut -d \' \' -f 2 > $file_addr"); + + # Reading BUS from temporary file + open (FILE, $file_addr); + while (<FILE>) { + $addrinfo = "$_"; + chomp($addrinfo); + } + + if($addrinfo eq "--") { + print "\necho \"**** Failed to recognize bus address!\n**** Please connect your device *with eeprom* and try to run $0 tool again, aborted!\";\n"; + print "exit;"; + } + + # Double check + $bkp_eeprom = "\n\ni2cdetect -y $businfo > $file_i2c_tmp 2> /dev/null;\n"; + $bkp_eeprom .= "BUSCHECK=\`awk \'NR==7\' $file_i2c_tmp | cut -d \' \' -f 2\`;\n"; + $bkp_eeprom .= "rm -f $file_i2c_tmp;\n"; + $bkp_eeprom .= "if [ \"\$BUSCHECK\" == \"--\" ]; then\n"; + $bkp_eeprom .= "\t echo \"Aborting script.. I cannot make backup of your current eeprom.. It's not safe to continue!\";\n"; + $bkp_eeprom .= "\t exit;\n"; + $bkp_eeprom .= "fi\n\n"; + + # Backup + $bkp_eeprom .= "\nDATE=\`/bin/date +%Y%m%d_%I%M%S\`\n"; + $bkp_eeprom .= "echo \"\nMaking backup of current eeprom - dir [$eeprom_backup_dir/eeprom-\$DATE]\";\n"; + $bkp_eeprom .= "mkdir -p $eeprom_backup_dir\n"; + $bkp_eeprom .= "\necho \"\n--EEPROM DUMP START HERE--\n\" > $eeprom_backup_dir/eeprom-\$DATE\n"; + $bkp_eeprom .= "i2cdump -y $businfo 0x$addrinfo >> $eeprom_backup_dir/eeprom-\$DATE 2> /dev/null\n"; + $bkp_eeprom .= "if [ ! \"\$\?\" = \"0\" ]; then\n"; + $bkp_eeprom .= "\t echo \"Aborting script.. I cannot make backup of your current eeprom.. It's not safe to continue!\";\n"; + $bkp_eeprom .= "\t exit;"; + $bkp_eeprom .= "\nfi\n"; + $bkp_eeprom .= "\necho \"\n--DMESG START HERE--\n\" >> $eeprom_backup_dir/eeprom-\$DATE\n"; + $bkp_eeprom .= "\ndmesg >> $eeprom_backup_dir/eeprom-\$DATE\n"; + + print $bkp_eeprom; + + close FILE; +} + +sub print_i2c +{ + $cmd = "cat $argv | egrep \"eeprom [0-9a-f]\"| sed -e \"s/.*eeprom/eeprom/\" | cut -d ' ' -f 3-22 > $file_eeprom"; + system($cmd); + + open (INPUT, "$file_eeprom") or die "Can't open data file: $!"; + + # Reading dump + @eeprom = ""; + my $eeprom_pos = 0; + while (!eof(INPUT)) { + read(INPUT, $fc, 2); + $eeprom[$eeprom_pos] = "0x$fc"; + seek(INPUT, tell(INPUT) + 1, 0); + $eeprom_pos++; + $NR_EEPROM_REGS++; + } + close INPUT; + + if ($NR_EEPROM_REGS == 0) { + print "\necho \"**** Failed to recognize any dump in: $argv! Make sure that you have the right dump file before run again $0 tool, aborted!\";\n"; + print "exit;"; + } + + print "\n\necho \"\033[1;31m\n[DO NOT REMOVE YOUR DEVICE UNTIL THE UPDATE IS FINISHED]\033[0m\";\n"; + print "echo \"Press ENTER to start\";\n"; + print "read\n"; + + for ($i=0; $i < $NR_EEPROM_REGS; $i++) { + printf("i2cset -y $businfo 0x$addrinfo 0x%02x $eeprom[$i] b\n", $i); + } + + printf("\necho \"\nDone! Remove and re-insert your device to see if it will be properly detected again. :-)\n\";\n"); +} + +################ +# Main # +################ + +&check_user; + +if (@ARGV <= 0) { + + my $em28xx_note = "\n\033[1;31m\nNOTES\033[0m:\n\t Not tested against newer em28xx chipsets like the em2874 and em2884\n"; + + print "\033[1;31m\nWARNING\033[0m:\n \t This script can *\033[1;31mDAMAGE\033[0m* your board, if you are not sure how to use it, *DO NOT* run it\n"; + print "\t Current modules supported: $modules_str *\033[1;31mONLY\033[0m*"; + print $em28xx_note; + print "\t If you have *any doubt*, \033[1;31mBEFORE run it\033[0m contact people from: linux-media\@vger.kernel.org\n"; + + print "\nUsage:\n"; + print "\tshell>perl $0 ./dmesg-dump-eeprom > eeprom_script.sh\n"; + print "\tshell>sh ./eeprom_script.sh\n\n"; + exit(); +} + +if (! -e $argv) { + printf("No such file: $argv\n"); + exit(); +} + +# Calling sub routines +&get_bus_and_addr; +&print_i2c; + +# Removing tmp files +system("rm -f $file_bus"); +system("rm -f $file_addr"); +system("rm -f $file_i2c_tmp"); +system("rm -f $file_eeprom"); diff --git a/v4l2-apps/util/v4l2-ctl.cpp b/v4l2-apps/util/v4l2-ctl.cpp index dec9edd61..5b38e37b3 100644 --- a/v4l2-apps/util/v4l2-ctl.cpp +++ b/v4l2-apps/util/v4l2-ctl.cpp @@ -77,6 +77,8 @@ enum Option { OptSetTuner = 't', OptGetVideoFormat = 'V', OptSetVideoFormat = 'v', + OptGetParm = 'P', + OptSetParm = 'p', OptGetSlicedVbiOutFormat = 128, OptGetOverlayFormat, @@ -103,6 +105,9 @@ enum Option { OptStreamOn, OptListStandards, OptListFormats, + OptListFormatsExt, + OptListFrameSizes, + OptListFrameIntervals, OptLogStatus, OptVerbose, OptSilent, @@ -131,7 +136,11 @@ enum Option { OptOverlay, OptGetJpegComp, OptSetJpegComp, + OptGetModulator, + OptSetModulator, OptListDevices, + OptGetOutputParm, + OptSetOutputParm, OptLast = 256 }; @@ -142,19 +151,17 @@ static int verbose; static unsigned capabilities; -typedef std::vector<struct v4l2_ext_control> ctrl_list; -static ctrl_list user_ctrls; -static ctrl_list mpeg_ctrls; +typedef std::map<unsigned, std::vector<struct v4l2_ext_control> > class2ctrls_map; -typedef std::map<std::string, unsigned> ctrl_strmap; -static ctrl_strmap ctrl_str2id; +typedef std::map<std::string, struct v4l2_queryctrl> ctrl_qmap; +static ctrl_qmap ctrl_str2q; typedef std::map<unsigned, std::string> ctrl_idmap; static ctrl_idmap ctrl_id2str; typedef std::list<std::string> ctrl_get_list; static ctrl_get_list get_ctrls; -typedef std::map<std::string,std::string> ctrl_set_map; +typedef std::map<std::string, std::string> ctrl_set_map; static ctrl_set_map set_ctrls; typedef std::vector<std::string> dev_vec; @@ -217,8 +224,15 @@ static struct option long_options[] = { {"streamon", no_argument, 0, OptStreamOn}, {"list-standards", no_argument, 0, OptListStandards}, {"list-formats", no_argument, 0, OptListFormats}, + {"list-formats-ext", no_argument, 0, OptListFormatsExt}, + {"list-framesizes", required_argument, 0, OptListFrameSizes}, + {"list-frameintervals", required_argument, 0, OptListFrameIntervals}, {"get-standard", no_argument, 0, OptGetStandard}, {"set-standard", required_argument, 0, OptSetStandard}, + {"get-parm", no_argument, 0, OptGetParm}, + {"set-parm", required_argument, 0, OptSetParm}, + {"get-output-parm", no_argument, 0, OptGetOutputParm}, + {"set-output-parm", required_argument, 0, OptSetOutputParm}, {"info", no_argument, 0, OptGetDriverInfo}, {"list-ctrls", no_argument, 0, OptListCtrls}, {"list-ctrls-menus", no_argument, 0, OptListCtrlsMenus}, @@ -260,6 +274,8 @@ static struct option long_options[] = { {"set-crop-output-overlay", required_argument, 0, OptSetOutputOverlayCrop}, {"get-jpeg-comp", no_argument, 0, OptGetJpegComp}, {"set-jpeg-comp", required_argument, 0, OptSetJpegComp}, + {"get-modulator", no_argument, 0, OptGetModulator}, + {"set-modulator", required_argument, 0, OptSetModulator}, {"overlay", required_argument, 0, OptOverlay}, {"list-devices", no_argument, 0, OptListDevices}, {0, 0, 0, 0} @@ -301,11 +317,26 @@ static void usage(void) " ntsc-X (X = M/J/K) or just 'ntsc' (V4L2_STD_NTSC)\n" " secam-X (X = B/G/H/D/K/L/Lc) or just 'secam' (V4L2_STD_SECAM)\n" " --list-standards display supported video standards [VIDIOC_ENUMSTD]\n" + " -P, --get-parm display video parameters [VIDIOC_G_PARM]\n" + " -p, --set-parm=<fps>\n" + " set video framerate in <fps> [VIDIOC_S_PARM]\n" " -T, --get-tuner query the tuner settings [VIDIOC_G_TUNER]\n" " -t, --set-tuner=<mode>\n" " set the audio mode of the tuner [VIDIOC_S_TUNER]\n" " Possible values: mono, stereo, lang2, lang1, bilingual\n" " --list-formats display supported video formats [VIDIOC_ENUM_FMT]\n" + " --list-formats-ext display supported video formats including frame sizes\n" + " and intervals\n" + " --list-framesizes=<f>\n" + " list supported framesizes for pixelformat <f>\n" + " [VIDIOC_ENUM_FRAMESIZES]\n" + " pixelformat is either the format index as reported by\n" + " --list-formats, or the fourcc value as a string\n" + " --list-frameintervals=width=<w>,height=<h>,pixelformat=<f>\n" + " list supported frame intervals for pixelformat <f> and\n" + " the given width and height [VIDIOC_ENUM_FRAMEINTERVALS]\n" + " pixelformat is either the format index as reported by\n" + " --list-formats, or the fourcc value as a string\n" " -V, --get-fmt-video\n" " query the video capture format [VIDIOC_G_FMT]\n" " -v, --set-fmt-video=width=<w>,height=<h>,pixelformat=<f>\n" @@ -404,6 +435,20 @@ static void usage(void) " display audio outputs [VIDIOC_ENUMAUDOUT]\n" " --list-audio-inputs\n" " display audio inputs [VIDIOC_ENUMAUDIO]\n" + " --get-modulator query the modulator settings [VIDIOC_G_MODULATOR]\n" + " --set-modulator=<txsubchans>\n" + " set the sub-carrier modulation [VIDIOC_S_MODULATOR]\n" + " <txsubchans> is one of:\n" + " mono: Modulate as mono\n" + " mono-rds: Modulate as mono with RDS (radio only)\n" + " stereo: Modulate as stereo\n" + " stereo-rds: Modulate as stereo with RDS (radio only)\n" + " bilingual: Modulate as bilingual\n" + " mono-sap: Modulate as mono with Second Audio Program\n" + " stereo-sap: Modulate as stereo with Second Audio Program\n" + " --get-output-parm display output video parameters [VIDIOC_G_PARM]\n" + " --set-output-parm=<fps>\n" + " set output video framerate in <fps> [VIDIOC_S_PARM]\n" "\n"); printf("Expert options:\n" " --streamoff turn the stream off [VIDIOC_STREAMOFF]\n" @@ -553,6 +598,43 @@ static std::string name2var(unsigned char *name) return s; } +static std::string safename(const unsigned char *name) +{ + std::string s; + + while (*name) { + if (*name == '\n') { + s += "\\n"; + } + else if (*name == '\r') { + s += "\\r"; + } + else if (*name == '\f') { + s += "\\f"; + } + else if (*name == '\\') { + s += "\\\\"; + } + else if ((*name & 0x7f) < 0x20) { + char buf[3]; + + sprintf(buf, "%02x", *name); + s += "\\x"; + s += buf; + } + else { + s += *name; + } + name++; + } + return s; +} + +static std::string safename(const char *name) +{ + return safename((const unsigned char *)name); +} + static void print_qctrl(int fd, struct v4l2_queryctrl *queryctrl, struct v4l2_ext_control *ctrl, int show_menus) { @@ -572,6 +654,12 @@ static void print_qctrl(int fd, struct v4l2_queryctrl *queryctrl, case V4L2_CTRL_TYPE_INTEGER64: printf("%31s (int64): value=%lld", s.c_str(), ctrl->value64); break; + case V4L2_CTRL_TYPE_STRING: + printf("%31s (str) : min=%d max=%d step=%d value='%s'", + s.c_str(), + queryctrl->minimum, queryctrl->maximum, + queryctrl->step, safename(ctrl->string).c_str()); + break; case V4L2_CTRL_TYPE_BOOLEAN: printf("%31s (bool) : default=%d value=%d", s.c_str(), @@ -629,6 +717,11 @@ static int print_control(int fd, struct v4l2_queryctrl &qctrl, int show_menus) ctrls.controls = &ext_ctrl; if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_USER && qctrl.id < V4L2_CID_PRIVATE_BASE) { + if (qctrl.type == V4L2_CTRL_TYPE_STRING) { + ext_ctrl.size = qctrl.maximum + 1; + ext_ctrl.string = (char *)malloc(ext_ctrl.size); + ext_ctrl.string[0] = 0; + } if (ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls)) { printf("error %d getting ext_ctrl %s\n", errno, qctrl.name); @@ -645,6 +738,8 @@ static int print_control(int fd, struct v4l2_queryctrl &qctrl, int show_menus) ext_ctrl.value = ctrl.value; } print_qctrl(fd, &qctrl, &ext_ctrl, show_menus); + if (qctrl.type == V4L2_CTRL_TYPE_STRING) + free(ext_ctrl.string); return 1; } @@ -678,7 +773,7 @@ static void find_controls(int fd) while (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) { if (qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS && !(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl_str2id[name2var(qctrl.name)] = qctrl.id; + ctrl_str2q[name2var(qctrl.name)] = qctrl; ctrl_id2str[qctrl.id] = name2var(qctrl.name); } qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; @@ -689,14 +784,14 @@ static void find_controls(int fd) qctrl.id = id; if (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0 && !(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl_str2id[name2var(qctrl.name)] = qctrl.id; + ctrl_str2q[name2var(qctrl.name)] = qctrl; ctrl_id2str[qctrl.id] = name2var(qctrl.name); } } for (qctrl.id = V4L2_CID_PRIVATE_BASE; ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0; qctrl.id++) { if (!(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl_str2id[name2var(qctrl.name)] = qctrl.id; + ctrl_str2q[name2var(qctrl.name)] = qctrl; ctrl_id2str[qctrl.id] = name2var(qctrl.name); } } @@ -810,7 +905,7 @@ static void printcropcap(const struct v4l2_cropcap &cropcap) printf("\tPixel Aspect: %u/%u\n", cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator); } -static void printfmt(struct v4l2_format vfmt) +static void printfmt(const struct v4l2_format &vfmt) { const flag_def vbi_def[] = { { V4L2_VBI_UNSYNC, "unsynchronized" }, @@ -874,6 +969,72 @@ static void printfmt(struct v4l2_format vfmt) } } +static std::string frmtype2s(unsigned type) +{ + static const char *types[] = { + "Unknown", + "Discrete", + "Continuous", + "Stepwise" + }; + + if (type > 3) + type = 0; + return types[type]; +} + +static std::string fract2sec(const struct v4l2_fract &f) +{ + char buf[100]; + + sprintf(buf, "%.3f s", (1.0 * f.numerator) / f.denominator); + return buf; +} + +static std::string fract2fps(const struct v4l2_fract &f) +{ + char buf[100]; + + sprintf(buf, "%.3f fps", (1.0 * f.denominator) / f.numerator); + return buf; +} + +static void print_frmsize(const struct v4l2_frmsizeenum &frmsize, const char *prefix) +{ + printf("%s\tSize: %s ", prefix, frmtype2s(frmsize.type).c_str()); + if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) { + printf("%dx%d", frmsize.discrete.width, frmsize.discrete.height); + } else if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) { + printf("%dx%d - %dx%d with step %d/%d", + frmsize.stepwise.min_width, + frmsize.stepwise.min_height, + frmsize.stepwise.max_width, + frmsize.stepwise.max_height, + frmsize.stepwise.step_width, + frmsize.stepwise.step_height); + } + printf("\n"); +} + +static void print_frmival(const struct v4l2_frmivalenum &frmival, const char *prefix) +{ + printf("%s\tInterval: %s ", prefix, frmtype2s(frmival.type).c_str()); + if (frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE) { + printf("%s (%s)\n", fract2sec(frmival.discrete).c_str(), + fract2fps(frmival.discrete).c_str()); + } else if (frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE) { + printf("%s - %s with step %s\n", + fract2sec(frmival.stepwise.min).c_str(), + fract2sec(frmival.stepwise.max).c_str(), + fract2sec(frmival.stepwise.step).c_str()); + printf("%s\t : ", prefix); + printf("(%s - %s with step %s)\n", + fract2fps(frmival.stepwise.min).c_str(), + fract2fps(frmival.stepwise.max).c_str(), + fract2fps(frmival.stepwise.step).c_str()); + } +} + static void print_video_formats(int fd, enum v4l2_buf_type type) { struct v4l2_fmtdesc fmt; @@ -893,6 +1054,43 @@ static void print_video_formats(int fd, enum v4l2_buf_type type) } } +static void print_video_formats_ext(int fd, enum v4l2_buf_type type) +{ + struct v4l2_fmtdesc fmt; + struct v4l2_frmsizeenum frmsize; + struct v4l2_frmivalenum frmival; + + fmt.index = 0; + fmt.type = type; + while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) >= 0) { + printf("\tIndex : %d\n", fmt.index); + printf("\tType : %s\n", buftype2s(type).c_str()); + printf("\tPixel Format: '%s'", fcc2s(fmt.pixelformat).c_str()); + if (fmt.flags) + printf(" (compressed)"); + printf("\n"); + printf("\tName : %s\n", fmt.description); + frmsize.pixel_format = fmt.pixelformat; + frmsize.index = 0; + while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) >= 0) { + print_frmsize(frmsize, "\t"); + if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) { + frmival.index = 0; + frmival.pixel_format = fmt.pixelformat; + frmival.width = frmsize.discrete.width; + frmival.height = frmsize.discrete.height; + while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) >= 0) { + print_frmival(frmival, "\t\t"); + frmival.index++; + } + } + frmsize.index++; + } + printf("\n"); + fmt.index++; + } +} + static char *pts_to_string(char *str, unsigned long pts) { static char buf[256]; @@ -943,6 +1141,25 @@ static std::string rxsubchans2s(int rxsubchans) s += "lang1 "; if (rxsubchans & V4L2_TUNER_SUB_LANG2) s += "lang2 "; + if (rxsubchans & V4L2_TUNER_SUB_RDS) + s += "rds "; + return s; +} + +static std::string txsubchans2s(int txsubchans) +{ + std::string s; + + if (txsubchans & V4L2_TUNER_SUB_MONO) + s += "mono"; + if (txsubchans & V4L2_TUNER_SUB_STEREO) + s += "stereo"; + if (txsubchans & V4L2_TUNER_SUB_LANG1) + s += "bilingual"; + if (txsubchans & V4L2_TUNER_SUB_SAP) + s += "+sap"; + if (txsubchans & V4L2_TUNER_SUB_RDS) + s += "+rds"; return s; } @@ -962,6 +1179,8 @@ static std::string tcap2s(unsigned cap) s += "lang1 "; if (cap & V4L2_TUNER_CAP_LANG2) s += "lang2 "; + if (cap & V4L2_TUNER_CAP_RDS) + s += "rds "; return s; } @@ -987,8 +1206,12 @@ static std::string cap2s(unsigned cap) s += "\t\tSliced VBI Output\n"; if (cap & V4L2_CAP_RDS_CAPTURE) s += "\t\tRDS Capture\n"; + if (cap & V4L2_CAP_RDS_OUTPUT) + s += "\t\tRDS Output\n"; if (cap & V4L2_CAP_TUNER) s += "\t\tTuner\n"; + if (cap & V4L2_CAP_MODULATOR) + s += "\t\tModulator\n"; if (cap & V4L2_CAP_AUDIO) s += "\t\tAudio\n"; if (cap & V4L2_CAP_RADIO) @@ -1339,6 +1562,17 @@ static enum v4l2_field parse_field(const char *s) return V4L2_FIELD_ANY; } +static __u32 find_pixel_format(int fd, unsigned index) +{ + struct v4l2_fmtdesc fmt; + + fmt.index = index; + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (doioctl(fd, VIDIOC_ENUM_FMT, &fmt, "VIDIOC_ENUM_FMT")) + return 0; + return fmt.pixelformat; +} + int main(int argc, char **argv) { char *value, *subs; @@ -1370,22 +1604,29 @@ int main(int argc, char **argv) struct v4l2_format raw_fmt_out; /* set_format/get_format for VBI output */ struct v4l2_format overlay_fmt; /* set_format/get_format video overlay */ struct v4l2_format overlay_fmt_out; /* set_format/get_format video overlay output */ - struct v4l2_tuner tuner; /* set_tuner/get_tuner */ + struct v4l2_tuner tuner; /* set_freq/get_freq */ + struct v4l2_modulator modulator;/* set_freq/get_freq */ struct v4l2_capability vcap; /* list_cap */ struct v4l2_input vin; /* list_inputs */ struct v4l2_output vout; /* list_outputs */ struct v4l2_audio vaudio; /* list audio inputs */ struct v4l2_audioout vaudout; /* audio outputs */ + struct v4l2_frmsizeenum frmsize;/* list frame sizes */ + struct v4l2_frmivalenum frmival;/* list frame intervals */ struct v4l2_rect vcrop; /* crop rect */ struct v4l2_rect vcrop_out; /* crop rect */ struct v4l2_rect vcrop_overlay; /* crop rect */ struct v4l2_rect vcrop_out_overlay; /* crop rect */ struct v4l2_framebuffer fbuf; /* fbuf */ struct v4l2_jpegcompression jpegcomp; /* jpeg compression */ + struct v4l2_streamparm parm; /* get/set parm */ int input; /* set_input/get_input */ int output; /* set_output/get_output */ + int txsubchans; /* set_modulator */ v4l2_std_id std; /* get_std/set_std */ double freq = 0; /* get/set frequency */ + double fps = 0; /* set framerate speed, in fps */ + double output_fps = 0; /* set framerate speed, in fps */ struct v4l2_frequency vf; /* get_freq/set_freq */ struct v4l2_standard vs; /* list_std */ int overlay; /* overlay */ @@ -1404,11 +1645,14 @@ int main(int argc, char **argv) memset(&overlay_fmt_out, 0, sizeof(overlay_fmt_out)); memset(&raw_fmt_out, 0, sizeof(raw_fmt_out)); memset(&tuner, 0, sizeof(tuner)); + memset(&modulator, 0, sizeof(modulator)); memset(&vcap, 0, sizeof(vcap)); memset(&vin, 0, sizeof(vin)); memset(&vout, 0, sizeof(vout)); memset(&vaudio, 0, sizeof(vaudio)); memset(&vaudout, 0, sizeof(vaudout)); + memset(&frmsize, 0, sizeof(frmsize)); + memset(&frmival, 0, sizeof(frmival)); memset(&vcrop, 0, sizeof(vcrop)); memset(&vcrop_out, 0, sizeof(vcrop_out)); memset(&vcrop_overlay, 0, sizeof(vcrop_overlay)); @@ -1602,6 +1846,41 @@ int main(int argc, char **argv) case OptOverlay: overlay = strtol(optarg, 0L, 0); break; + case OptListFrameSizes: + if (strlen(optarg) == 4) + frmsize.pixel_format = v4l2_fourcc(optarg[0], optarg[1], + optarg[2], optarg[3]); + else + frmsize.pixel_format = strtol(optarg, 0L, 0); + break; + case OptListFrameIntervals: + subs = optarg; + while (*subs != '\0') { + static const char *const subopts[] = { + "width", + "height", + "pixelformat", + NULL + }; + + switch (parse_subopt(&subs, subopts, &value)) { + case 0: + frmival.width = strtol(value, 0L, 0); + break; + case 1: + frmival.height = strtol(value, 0L, 0); + break; + case 2: + if (strlen(value) == 4) + frmival.pixel_format = + v4l2_fourcc(value[0], value[1], + value[2], value[3]); + else + frmival.pixel_format = strtol(value, 0L, 0); + break; + } + } + break; case OptSetCrop: parse_crop(optarg, set_crop, vcrop); break; @@ -1652,6 +1931,12 @@ int main(int argc, char **argv) std = strtol(optarg, 0L, 0) | (1ULL << 63); } break; + case OptSetParm: + fps = strtod(optarg, NULL); + break; + case OptSetOutputParm: + output_fps = strtod(optarg, NULL); + break; case OptGetCtrl: subs = optarg; while (*subs != '\0') { @@ -1695,6 +1980,28 @@ int main(int argc, char **argv) return 1; } break; + case OptSetModulator: + txsubchans = strtol(optarg, 0L, 0); + if (!strcmp(optarg, "stereo")) + txsubchans = V4L2_TUNER_SUB_STEREO; + else if (!strcmp(optarg, "stereo-sap")) + txsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP; + else if (!strcmp(optarg, "bilingual")) + txsubchans = V4L2_TUNER_SUB_LANG1; + else if (!strcmp(optarg, "mono")) + txsubchans = V4L2_TUNER_SUB_MONO; + else if (!strcmp(optarg, "mono-sap")) + txsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP; + else if (!strcmp(optarg, "stereo-rds")) + txsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS; + else if (!strcmp(optarg, "mono-rds")) + txsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_RDS; + else { + fprintf(stderr, "Unknown txsubchans value\n"); + usage(); + return 1; + } + break; case OptSetSlicedVbiFormat: case OptSetSlicedVbiOutFormat: case OptTrySlicedVbiFormat: @@ -1837,13 +2144,13 @@ int main(int argc, char **argv) capabilities = vcap.capabilities; find_controls(fd); for (ctrl_get_list::iterator iter = get_ctrls.begin(); iter != get_ctrls.end(); ++iter) { - if (ctrl_str2id.find(*iter) == ctrl_str2id.end()) { + if (ctrl_str2q.find(*iter) == ctrl_str2q.end()) { fprintf(stderr, "unknown control '%s'\n", (*iter).c_str()); exit(1); } } for (ctrl_set_map::iterator iter = set_ctrls.begin(); iter != set_ctrls.end(); ++iter) { - if (ctrl_str2id.find(iter->first) == ctrl_str2id.end()) { + if (ctrl_str2q.find(iter->first) == ctrl_str2q.end()) { fprintf(stderr, "unknown control '%s'\n", iter->first.c_str()); exit(1); } @@ -1859,8 +2166,11 @@ int main(int argc, char **argv) options[OptGetAudioInput] = 1; options[OptGetAudioOutput] = 1; options[OptGetStandard] = 1; + options[OptGetParm] = 1; + options[OptGetOutputParm] = 1; options[OptGetFreq] = 1; options[OptGetTuner] = 1; + options[OptGetModulator] = 1; options[OptGetOverlayFormat] = 1; options[OptGetOutputOverlayFormat] = 1; options[OptGetVbiFormat] = 1; @@ -1896,11 +2206,17 @@ int main(int argc, char **argv) if (options[OptSetFreq]) { double fac = 16; - if (doioctl(fd, VIDIOC_G_TUNER, &tuner, "VIDIOC_G_TUNER") == 0) { - fac = (tuner.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16; + if (capabilities & V4L2_CAP_MODULATOR) { + if (doioctl(fd, VIDIOC_G_MODULATOR, &modulator, "VIDIOC_G_MODULATOR") == 0) + fac = (modulator.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16; + } else { + vf.type = V4L2_TUNER_ANALOG_TV; + if (doioctl(fd, VIDIOC_G_TUNER, &tuner, "VIDIOC_G_TUNER") == 0) { + fac = (tuner.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16; + vf.type = tuner.type; + } } vf.tuner = 0; - vf.type = tuner.type; vf.frequency = __u32(freq * fac); if (doioctl(fd, VIDIOC_S_FREQUENCY, &vf, "VIDIOC_S_FREQUENCY") == 0) @@ -1919,6 +2235,43 @@ int main(int argc, char **argv) printf("Standard set to %08llx\n", (unsigned long long)std); } + + if (options[OptSetParm]) { + memset(&parm, 0, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + parm.parm.capture.timeperframe.numerator = 1000; + parm.parm.capture.timeperframe.denominator = + fps * parm.parm.capture.timeperframe.numerator; + + if (doioctl(fd, VIDIOC_S_PARM, &parm, "VIDIOC_S_PARM") == 0) { + struct v4l2_fract *tf = &parm.parm.capture.timeperframe; + + if (!tf->denominator || !tf->numerator) + printf("Invalid frame rate\n"); + else + printf("Frame rate set to %.3f fps\n", + 1.0 * tf->denominator / tf->numerator); + } + } + + if (options[OptSetOutputParm]) { + memset(&parm, 0, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + parm.parm.output.timeperframe.numerator = 1000; + parm.parm.output.timeperframe.denominator = + fps * parm.parm.output.timeperframe.numerator; + + if (doioctl(fd, VIDIOC_S_PARM, &parm, "VIDIOC_S_PARM") == 0) { + struct v4l2_fract *tf = &parm.parm.output.timeperframe; + + if (!tf->denominator || !tf->numerator) + printf("Invalid frame rate\n"); + else + printf("Frame rate set to %.3f fps\n", + 1.0 * tf->denominator / tf->numerator); + } + } + if (options[OptSetInput]) { if (doioctl(fd, VIDIOC_S_INPUT, &input, "VIDIOC_S_INPUT") == 0) { printf("Video input set to %d", input); @@ -1954,6 +2307,16 @@ int main(int argc, char **argv) } } + if (options[OptSetModulator]) { + struct v4l2_modulator mt; + + memset(&mt, 0, sizeof(struct v4l2_modulator)); + if (doioctl(fd, VIDIOC_G_MODULATOR, &mt, "VIDIOC_G_MODULATOR") == 0) { + mt.txsubchans = txsubchans; + doioctl(fd, VIDIOC_S_MODULATOR, &mt, "VIDIOC_S_MODULATOR"); + } + } + if (options[OptSetVideoFormat] || options[OptTryVideoFormat]) { struct v4l2_format in_vfmt; @@ -1966,13 +2329,8 @@ int main(int argc, char **argv) if (set_fmts & FmtPixelFormat) { in_vfmt.fmt.pix.pixelformat = vfmt.fmt.pix.pixelformat; if (in_vfmt.fmt.pix.pixelformat < 256) { - struct v4l2_fmtdesc fmt; - - fmt.index = in_vfmt.fmt.pix.pixelformat; - fmt.type = in_vfmt.type; - if (doioctl(fd, VIDIOC_ENUM_FMT, &fmt, "VIDIOC_ENUM_FMT")) - goto set_vid_fmt_error; - in_vfmt.fmt.pix.pixelformat = fmt.pixelformat; + in_vfmt.fmt.pix.pixelformat = + find_pixel_format(fd, in_vfmt.fmt.pix.pixelformat); } } if (options[OptSetVideoFormat]) @@ -2116,42 +2474,61 @@ set_vid_fmt_error: if (options[OptSetCtrl] && !set_ctrls.empty()) { struct v4l2_ext_controls ctrls = { 0 }; + class2ctrls_map class2ctrls; for (ctrl_set_map::iterator iter = set_ctrls.begin(); iter != set_ctrls.end(); ++iter) { struct v4l2_ext_control ctrl = { 0 }; - ctrl.id = ctrl_str2id[iter->first]; - ctrl.value = strtol(iter->second.c_str(), NULL, 0); - if (V4L2_CTRL_ID2CLASS(ctrl.id) == V4L2_CTRL_CLASS_MPEG) - mpeg_ctrls.push_back(ctrl); - else - user_ctrls.push_back(ctrl); - } - for (unsigned i = 0; i < user_ctrls.size(); i++) { - struct v4l2_control ctrl; - - ctrl.id = user_ctrls[i].id; - ctrl.value = user_ctrls[i].value; - if (doioctl(fd, VIDIOC_S_CTRL, &ctrl, "VIDIOC_S_CTRL")) { - fprintf(stderr, "%s: %s\n", - ctrl_id2str[ctrl.id].c_str(), - strerror(errno)); + ctrl.id = ctrl_str2q[iter->first].id; + if (ctrl_str2q[iter->first].type == V4L2_CTRL_TYPE_STRING) { + unsigned len = iter->second.length(); + unsigned maxlen = ctrl_str2q[iter->first].maximum; + + ctrl.size = maxlen + 1; + ctrl.string = (char *)malloc(ctrl.size); + if (len > maxlen) { + memcpy(ctrl.string, iter->second.c_str(), maxlen); + ctrl.string[maxlen] = 0; + } + else { + strcpy(ctrl.string, iter->second.c_str()); + } + } else { + ctrl.value = strtol(iter->second.c_str(), NULL, 0); } + class2ctrls[V4L2_CTRL_ID2CLASS(ctrl.id)].push_back(ctrl); } - if (mpeg_ctrls.size()) { - ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; - ctrls.count = mpeg_ctrls.size(); - ctrls.controls = &mpeg_ctrls[0]; - if (doioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls, "VIDIOC_S_EXT_CTRLS")) { - if (ctrls.error_idx >= ctrls.count) { - fprintf(stderr, "Error setting MPEG controls: %s\n", - strerror(errno)); + for (class2ctrls_map::iterator iter = class2ctrls.begin(); + iter != class2ctrls.end(); ++iter) { + if (iter->first == V4L2_CTRL_CLASS_USER) { + for (unsigned i = 0; i < iter->second.size(); i++) { + struct v4l2_control ctrl; + + ctrl.id = iter->second[i].id; + ctrl.value = iter->second[i].value; + if (doioctl(fd, VIDIOC_S_CTRL, &ctrl, "VIDIOC_S_CTRL")) { + fprintf(stderr, "%s: %s\n", + ctrl_id2str[ctrl.id].c_str(), + strerror(errno)); + } } - else { - fprintf(stderr, "%s: %s\n", - ctrl_id2str[mpeg_ctrls[ctrls.error_idx].id].c_str(), - strerror(errno)); + continue; + } + if (iter->second.size()) { + ctrls.ctrl_class = iter->first; + ctrls.count = iter->second.size(); + ctrls.controls = &iter->second[0]; + if (doioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls, "VIDIOC_S_EXT_CTRLS")) { + if (ctrls.error_idx >= ctrls.count) { + fprintf(stderr, "Error setting MPEG controls: %s\n", + strerror(errno)); + } + else { + fprintf(stderr, "%s: %s\n", + ctrl_id2str[iter->second[ctrls.error_idx].id].c_str(), + strerror(errno)); + } } } } @@ -2321,6 +2698,16 @@ set_vid_fmt_error: if (options[OptGetFreq]) { double fac = 16; + if (capabilities & V4L2_CAP_MODULATOR) { + if (doioctl(fd, VIDIOC_G_MODULATOR, &modulator, "VIDIOC_G_MODULATOR") == 0) + fac = (modulator.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16; + } else { + vf.type = V4L2_TUNER_ANALOG_TV; + if (doioctl(fd, VIDIOC_G_TUNER, &tuner, "VIDIOC_G_TUNER") == 0) { + fac = (tuner.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16; + vf.type = tuner.type; + } + } if (doioctl(fd, VIDIOC_G_TUNER, &tuner, "VIDIOC_G_TUNER") == 0) { fac = (tuner.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16; } @@ -2366,43 +2753,99 @@ set_vid_fmt_error: } } + if (options[OptGetParm]) { + memset(&parm, 0, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (doioctl(fd, VIDIOC_G_PARM, &parm, "VIDIOC_G_PARM") == 0) { + const struct v4l2_fract &tf = parm.parm.capture.timeperframe; + + printf("Streaming Parameters %s:\n", buftype2s(parm.type).c_str()); + if (parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) + printf("\tCapabilities : timeperframe\n"); + if (parm.parm.capture.capturemode & V4L2_MODE_HIGHQUALITY) + printf("\tCapture mode : high quality\n"); + if (!tf.denominator || !tf.numerator) + printf("\tFrames per second: invalid (%d/%d)\n", + tf.denominator, tf.numerator); + else + printf("\tFrames per second: %.3f (%d/%d)\n", + (1.0 * tf.denominator) / tf.numerator, + tf.denominator, tf.numerator); + printf("\tRead buffers : %d\n", parm.parm.output.writebuffers); + } + } + + if (options[OptGetOutputParm]) { + memset(&parm, 0, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + if (doioctl(fd, VIDIOC_G_PARM, &parm, "VIDIOC_G_PARM") == 0) { + const struct v4l2_fract &tf = parm.parm.output.timeperframe; + + printf("Streaming Parameters %s:\n", buftype2s(parm.type).c_str()); + if (parm.parm.output.capability & V4L2_CAP_TIMEPERFRAME) + printf("\tCapabilities : timeperframe\n"); + if (parm.parm.output.outputmode & V4L2_MODE_HIGHQUALITY) + printf("\tOutput mode : high quality\n"); + if (!tf.denominator || !tf.numerator) + printf("\tFrames per second: invalid (%d/%d)\n", + tf.denominator, tf.numerator); + else + printf("\tFrames per second: %.3f (%d/%d)\n", + (1.0 * tf.denominator) / tf.numerator, + tf.denominator, tf.numerator); + printf("\tWrite buffers : %d\n", parm.parm.output.writebuffers); + } + } + if (options[OptGetCtrl] && !get_ctrls.empty()) { struct v4l2_ext_controls ctrls = { 0 }; + class2ctrls_map class2ctrls; - mpeg_ctrls.clear(); - user_ctrls.clear(); for (ctrl_get_list::iterator iter = get_ctrls.begin(); iter != get_ctrls.end(); ++iter) { struct v4l2_ext_control ctrl = { 0 }; - ctrl.id = ctrl_str2id[*iter]; - if (V4L2_CTRL_ID2CLASS(ctrl.id) == V4L2_CTRL_CLASS_MPEG) - mpeg_ctrls.push_back(ctrl); - else - user_ctrls.push_back(ctrl); - } - for (unsigned i = 0; i < user_ctrls.size(); i++) { - struct v4l2_control ctrl; - - ctrl.id = user_ctrls[i].id; - doioctl(fd, VIDIOC_G_CTRL, &ctrl, "VIDIOC_G_CTRL"); - printf("%s: %d\n", ctrl_id2str[ctrl.id].c_str(), ctrl.value); + ctrl.id = ctrl_str2q[*iter].id; + if (ctrl_str2q[*iter].type == V4L2_CTRL_TYPE_STRING) { + ctrl.size = ctrl_str2q[*iter].maximum + 1; + ctrl.string = (char *)malloc(ctrl.size); + ctrl.string[0] = 0; + } + class2ctrls[V4L2_CTRL_ID2CLASS(ctrl.id)].push_back(ctrl); } - if (mpeg_ctrls.size()) { - ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; - ctrls.count = mpeg_ctrls.size(); - ctrls.controls = &mpeg_ctrls[0]; - doioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls, "VIDIOC_G_EXT_CTRLS"); - for (unsigned i = 0; i < mpeg_ctrls.size(); i++) { - struct v4l2_ext_control ctrl = mpeg_ctrls[i]; - - printf("%s: %d\n", ctrl_id2str[ctrl.id].c_str(), ctrl.value); + for (class2ctrls_map::iterator iter = class2ctrls.begin(); + iter != class2ctrls.end(); ++iter) { + if (iter->first == V4L2_CTRL_CLASS_USER) { + for (unsigned i = 0; i < iter->second.size(); i++) { + struct v4l2_control ctrl; + + ctrl.id = iter->second[i].id; + doioctl(fd, VIDIOC_G_CTRL, &ctrl, "VIDIOC_G_CTRL"); + printf("%s: %d\n", ctrl_id2str[ctrl.id].c_str(), ctrl.value); + } + continue; + } + if (iter->second.size()) { + ctrls.ctrl_class = iter->first; + ctrls.count = iter->second.size(); + ctrls.controls = &iter->second[0]; + doioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls, "VIDIOC_G_EXT_CTRLS"); + for (unsigned i = 0; i < iter->second.size(); i++) { + struct v4l2_ext_control ctrl = iter->second[i]; + + if (ctrl_str2q[ctrl_id2str[ctrl.id]].type == V4L2_CTRL_TYPE_STRING) + printf("%s: '%s'\n", ctrl_id2str[ctrl.id].c_str(), + safename(ctrl.string).c_str()); + else + printf("%s: %d\n", ctrl_id2str[ctrl.id].c_str(), ctrl.value); + } } } } if (options[OptGetTuner]) { struct v4l2_tuner vt; + memset(&vt, 0, sizeof(struct v4l2_tuner)); if (doioctl(fd, VIDIOC_G_TUNER, &vt, "VIDIOC_G_TUNER") == 0) { printf("Tuner:\n"); @@ -2421,6 +2864,25 @@ set_vid_fmt_error: } } + if (options[OptGetModulator]) { + struct v4l2_modulator mt; + + memset(&mt, 0, sizeof(struct v4l2_modulator)); + if (doioctl(fd, VIDIOC_G_MODULATOR, &mt, "VIDIOC_G_MODULATOR") == 0) { + printf("Modulator:\n"); + printf("\tName : %s\n", mt.name); + printf("\tCapabilities : %s\n", tcap2s(mt.capability).c_str()); + if (mt.capability & V4L2_TUNER_CAP_LOW) + printf("\tFrequency range : %.1f MHz - %.1f MHz\n", + mt.rangelow / 16000.0, mt.rangehigh / 16000.0); + else + printf("\tFrequency range : %.1f MHz - %.1f MHz\n", + mt.rangelow / 16.0, mt.rangehigh / 16.0); + printf("\tSubchannel modulation: %s\n", + txsubchans2s(mt.txsubchans).c_str()); + } + } + if (options[OptLogStatus]) { static char buf[40960]; int len; @@ -2546,6 +3008,35 @@ set_vid_fmt_error: print_video_formats(fd, V4L2_BUF_TYPE_VIDEO_OVERLAY); } + if (options[OptListFormatsExt]) { + printf("ioctl: VIDIOC_ENUM_FMT\n"); + print_video_formats_ext(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE); + print_video_formats(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT); + print_video_formats(fd, V4L2_BUF_TYPE_VIDEO_OVERLAY); + } + + if (options[OptListFrameSizes]) { + printf("ioctl: VIDIOC_ENUM_FRAMESIZES\n"); + if (frmsize.pixel_format < 256) + frmsize.pixel_format = find_pixel_format(fd, frmsize.pixel_format); + frmsize.index = 0; + while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) >= 0) { + print_frmsize(frmsize, ""); + frmsize.index++; + } + } + + if (options[OptListFrameIntervals]) { + printf("ioctl: VIDIOC_ENUM_FRAMEINTERVALS\n"); + if (frmival.pixel_format < 256) + frmival.pixel_format = find_pixel_format(fd, frmival.pixel_format); + frmival.index = 0; + while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) >= 0) { + print_frmival(frmival, ""); + frmival.index++; + } + } + if (options[OptGetSlicedVbiCap]) { struct v4l2_sliced_vbi_cap cap; diff --git a/v4l2-apps/util/v4l2-dbg-micron.h b/v4l2-apps/util/v4l2-dbg-micron.h new file mode 100644 index 000000000..8466322bf --- /dev/null +++ b/v4l2-apps/util/v4l2-dbg-micron.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2009 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 "v4l2-dbg.h" + +#define MT9V011_IDENT "mt9v011" + +/* Register name prefix */ +#define MT9V011_PREFIX "MT9V011_" + +static struct board_regs mt9v011_regs[] = { + {0x00, MT9V011_PREFIX "CHIP_VERSION"}, + {0x01, MT9V011_PREFIX "ROWSTART"}, + {0x02, MT9V011_PREFIX "COLSTART"}, + {0x03, MT9V011_PREFIX "HEIGHT"}, + {0x04, MT9V011_PREFIX "WIDTH"}, + {0x05, MT9V011_PREFIX "HBLANK"}, + {0x06, MT9V011_PREFIX "VBLANK"}, + {0x07, MT9V011_PREFIX "OUT_CTRL"}, + {0x09, MT9V011_PREFIX "SHUTTER_WIDTH"}, + {0x0a, MT9V011_PREFIX "CLK_SPEED"}, + {0x0b, MT9V011_PREFIX "RESTART"}, + {0x0c, MT9V011_PREFIX "SHUTTER_DELAY"}, + {0x0d, MT9V011_PREFIX "RESET"}, + {0x1e, MT9V011_PREFIX "DIGITAL_ZOOM"}, + {0x20, MT9V011_PREFIX "READ_MODE"}, + {0x2b, MT9V011_PREFIX "GREEN_1_GAIN"}, + {0x2c, MT9V011_PREFIX "BLUE_GAIN"}, + {0x2d, MT9V011_PREFIX "RED_GAIN"}, + {0x2e, MT9V011_PREFIX "GREEN_2_GAIN"}, + {0x35, MT9V011_PREFIX "GLOBAL_GAIN"}, + {0xf1, MT9V011_PREFIX "CHIP_ENABLE"}, +}; diff --git a/v4l2-apps/util/v4l2-dbg.cpp b/v4l2-apps/util/v4l2-dbg.cpp index f427d4442..1a481c04c 100644 --- a/v4l2-apps/util/v4l2-dbg.cpp +++ b/v4l2-apps/util/v4l2-dbg.cpp @@ -47,6 +47,7 @@ #include "v4l2-dbg-em28xx.h" #include "v4l2-dbg-ac97.h" #include "v4l2-dbg-tvp5150.h" +#include "v4l2-dbg-micron.h" #define ARRAY_SIZE(arr) ((int)(sizeof(arr) / sizeof((arr)[0]))) @@ -61,7 +62,7 @@ struct board_list { static const struct board_list boards[] = { #define AC97_BOARD 0 - { /* From ac97-dbg.h */ + { /* From v4l2-dbg-ac97.h */ AC97_IDENT, sizeof(AC97_PREFIX) - 1, ac97_regs, @@ -69,7 +70,7 @@ static const struct board_list boards[] = { NULL, 0, }, - { /* From bttv-dbg.h */ + { /* From v4l2-dbg-bttv.h */ BTTV_IDENT, sizeof(BTTV_PREFIX) - 1, bt8xx_regs, @@ -77,7 +78,7 @@ static const struct board_list boards[] = { bt8xx_regs_other, ARRAY_SIZE(bt8xx_regs_other), }, - { /* From saa7134-dbg.h */ + { /* From v4l2-dbg-saa7134.h */ SAA7134_IDENT, sizeof(SAA7134_PREFIX) - 1, saa7134_regs, @@ -85,7 +86,7 @@ static const struct board_list boards[] = { NULL, 0, }, - { /* From em28xx-dbg.h */ + { /* From v4l2-dbg-em28xx.h */ EM28XX_IDENT, sizeof(EM28XX_PREFIX) - 1, em28xx_regs, @@ -93,7 +94,7 @@ static const struct board_list boards[] = { em28xx_alt_regs, ARRAY_SIZE(em28xx_alt_regs), }, - { /* From tvp5150-dbg.h */ + { /* From v4l2-dbg-tvp5150.h */ TVP5150_IDENT, sizeof(TVP5150_PREFIX) - 1, tvp5150_regs, @@ -101,6 +102,14 @@ static const struct board_list boards[] = { NULL, 0, }, + { /* From v4l2-dbg-micron.h */ + MT9V011_IDENT, + sizeof(MT9V011_PREFIX) - 1, + mt9v011_regs, + ARRAY_SIZE(mt9v011_regs), + NULL, + 0, + }, }; struct chipid { @@ -713,6 +722,9 @@ int main(int argc, char **argv) case V4L2_IDENT_CX23418: name = "cx23418"; break; + case V4L2_IDENT_CAFE: + name = "cafe"; + break; default: if (get_reg.match.type == V4L2_CHIP_MATCH_I2C_DRIVER) name = get_reg.match.name; @@ -726,6 +738,8 @@ int main(int argc, char **argv) print_regs(fd, &get_reg, 0, 0xff, stride); } else if (name == "saa7127") { print_regs(fd, &get_reg, 0, 0x7f, stride); + } else if (name == "ov7670") { + print_regs(fd, &get_reg, 0, 0x89, stride); } else if (name == "cx25840") { print_regs(fd, &get_reg, 0, 2, stride); print_regs(fd, &get_reg, 0x100, 0x15f, stride); @@ -738,6 +752,11 @@ int main(int argc, char **argv) print_regs(fd, &get_reg, 0x02000000, 0x020000ff, stride); } else if (name == "cx23418") { print_regs(fd, &get_reg, 0x02c40000, 0x02c409c7, stride); + } else if (name == "cafe") { + print_regs(fd, &get_reg, 0, 0x43, stride); + print_regs(fd, &get_reg, 0x88, 0x8f, stride); + print_regs(fd, &get_reg, 0xb4, 0xbb, stride); + print_regs(fd, &get_reg, 0x3000, 0x300c, stride); } else { /* unknown chip, dump 0-0xff by default */ print_regs(fd, &get_reg, 0, 0xff, stride); diff --git a/v4l2-apps/util/v4l2-sysfs-path.c b/v4l2-apps/util/v4l2-sysfs-path.c index e3f3e63e8..4f0817017 100644 --- a/v4l2-apps/util/v4l2-sysfs-path.c +++ b/v4l2-apps/util/v4l2-sysfs-path.c @@ -23,6 +23,7 @@ #include <stdio.h> #include <string.h> #include <dirent.h> +#include <sys/stat.h> #define USB_ID "usb-" #define PCI_ID "PCI:" @@ -135,6 +136,131 @@ err: return NULL; } +char *seek_name(char *path, char *match) +{ + DIR *dir; + struct dirent *entry; + struct stat st; + char *p; + static char name[1024]; + int major, minor; + + dir = opendir(path); + if (!dir) + return NULL; + + strcpy(name, path); + strcat(name, "/"); + p = name + strlen(name); + + entry = readdir(dir); + while (entry) { + if (!strncmp(entry->d_name, match, strlen(match))) { + + strcpy(name, entry->d_name); + closedir(dir); + return name; + } + entry = readdir(dir); + } + closedir(dir); + return NULL; +} + +int get_dev(char *class, int *major, int *minor, char *extra) +{ + char path[1024]; + char *name; + FILE *fp; + + name = strchr(class,':'); + if (!name) + return -1; + *name = 0; + name++; + + *extra = 0; + + if (!strcmp(class, "input")) { + char *event; + + sprintf(path, "/sys/class/%s/%s/", class, name); + event = seek_name(path, "event"); + if (!event) + return -1; + + strcpy(extra, event); + + sprintf(path, "/sys/class/%s/%s/%s/dev", class, name, event); + + } else + sprintf(path, "/sys/class/%s/%s/dev", class, name); + + fp = fopen(path, "r"); + if (!fp) + return -1; + + fscanf(fp, "%d:%d", major, minor); + + return 0; +} + +/* + Examples of subdevs: + sound:audio1 + sound:controlC1 + sound:dsp1 + sound:mixer1 + sound:pcmC1D0c + dvb:dvb0.demux0 + dvb:dvb0.dvr0 + dvb:dvb0.frontend0 + dvb:dvb0.net0 + i2c-adapter:i2c-4 + input:input8 +*/ + +void get_subdevs(char *path) +{ + DIR *dir; + struct dirent *entry; + struct stat st; + char *p, name[1024], extra[20]; + int major, minor; + + dir = opendir(path); + if (!dir) + return; + + strcpy(name, path); + strcat(name, "/"); + p = name + strlen(name); + + printf("Associated devices:\n"); + entry = readdir(dir); + while (entry) { + strcpy(p, entry->d_name); + if ((lstat(name, &st) == 0) && + !S_ISDIR(st.st_mode)) { + char *s = strchr(entry->d_name, ':'); + if (s) { + printf("\t%s", entry->d_name); + if (!get_dev(entry->d_name, &major, &minor, extra)) { + if (*extra) + printf(":%s (dev %d,%d)", + extra, major, minor); + else + printf(" (dev %d,%d)", + major, minor); + } + printf("\n"); + } + } + entry = readdir(dir); + } + closedir(dir); +} + void get_sysfs(char *fname) { struct v4l2_driver drv; @@ -148,9 +274,11 @@ void get_sysfs(char *fname) printf("bus info = %s\n", drv.cap.bus_info); path = obtain_bus_sysfs_path((char *)drv.cap.bus_info); if (path) { - printf("sysfs path = %s\n\n", path); + printf("sysfs path = %s\n", path); + get_subdevs(path); free(path); } + printf("\n"); v4l2_close(&drv); } diff --git a/v4l2-apps/util/xc3028-firmware/firmware-tool.c b/v4l2-apps/util/xc3028-firmware/firmware-tool.c index de1262ceb..43b78df7e 100644 --- a/v4l2-apps/util/xc3028-firmware/firmware-tool.c +++ b/v4l2-apps/util/xc3028-firmware/firmware-tool.c @@ -33,8 +33,8 @@ #include <asm/byteorder.h> #include <asm/types.h> -#include "../../../linux/drivers/media/video/tuner-xc2028-types.h" -#include "../../../linux/include/linux/videodev2.h" +#include "../../../linux/drivers/media/common/tuners/tuner-xc2028-types.h" +#include "linux/videodev2.h" #include "extract_head.h" #include "standards.h" |