summaryrefslogtreecommitdiff
path: root/v4l2-apps
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-apps')
-rw-r--r--v4l2-apps/util/Makefile1
-rw-r--r--v4l2-apps/util/xc3028-firmware/Makefile19
-rw-r--r--v4l2-apps/util/xc3028-firmware/README3
-rw-r--r--v4l2-apps/util/xc3028-firmware/firmware-tool.c673
-rw-r--r--v4l2-apps/util/xc3028-firmware/standards.c152
-rw-r--r--v4l2-apps/util/xc3028-firmware/standards.h25
6 files changed, 873 insertions, 0 deletions
diff --git a/v4l2-apps/util/Makefile b/v4l2-apps/util/Makefile
index fcc193a09..34fc9a103 100644
--- a/v4l2-apps/util/Makefile
+++ b/v4l2-apps/util/Makefile
@@ -12,6 +12,7 @@ clean::
rm -f $(binaries) v4l2-driverids.cpp v4l2-chipids.cpp
-if [ -f qv4l2/Makefile ]; then make -C qv4l2 $@; fi
-rm -f qv4l2/qv4l2 qv4l2/Makefile
+ make -C xc3028-firmware $@
qv4l2:
if [ ! -f qv4l2/Makefile ]; then (cd qv4l2; qmake); fi
diff --git a/v4l2-apps/util/xc3028-firmware/Makefile b/v4l2-apps/util/xc3028-firmware/Makefile
new file mode 100644
index 000000000..508575e16
--- /dev/null
+++ b/v4l2-apps/util/xc3028-firmware/Makefile
@@ -0,0 +1,19 @@
+# Makefile for linuxtv.org v4l2-apps/util/xc3028-firmware
+
+CPPFLAGS += -I../../../linux/include
+
+binaries = firmware-tool
+
+.PHONY: all clean install qv4l2
+
+all: $(binaries)
+
+clean::
+ rm -f $(binaries)
+
+firmware-tool: firmware-tool.o standards.o
+ $(CXX) $^ -o $@
+
+install:
+
+include ../../Make.rules
diff --git a/v4l2-apps/util/xc3028-firmware/README b/v4l2-apps/util/xc3028-firmware/README
new file mode 100644
index 000000000..85df42a79
--- /dev/null
+++ b/v4l2-apps/util/xc3028-firmware/README
@@ -0,0 +1,3 @@
+Firmware dumps must be in ASCII format and each line corresponds to an I2C instruction sent to the chip. Each line
+must either be a special instruction like RESET_CLK, RESET_TUNER (see standards.c) or be a sequence of bytes
+represented in hexadecimal format xx separated by a space character ' '.
diff --git a/v4l2-apps/util/xc3028-firmware/firmware-tool.c b/v4l2-apps/util/xc3028-firmware/firmware-tool.c
new file mode 100644
index 000000000..feb804f11
--- /dev/null
+++ b/v4l2-apps/util/xc3028-firmware/firmware-tool.c
@@ -0,0 +1,673 @@
+/*
+ Xceive XC2028/3028 tuner module firmware manipulation tool
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.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
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <asm/byteorder.h>
+#include <asm/types.h>
+
+#include "../../../linux/drivers/media/video/tuner-xc2028-types.h"
+#include "../../../linux/include/linux/videodev2.h"
+
+#include "standards.h"
+
+#define LIST_ACTION (1<<0)
+#define ADD_ACTION (1<<1)
+#define DELETE_ACTION (1<<2)
+#define SET_TYPE_ACTION (1<<3)
+#define SET_ID_ACTION (1<<4)
+
+struct firmware_description {
+ __u32 type;
+ __u64 id;
+ unsigned char *data;
+ __u32 size;
+};
+
+struct firmware {
+ char* name;
+ struct firmware_description* desc;
+ __u16 version;
+ __u16 nr_desc;
+};
+
+struct firmware_description* alloc_firmware_description(void) {
+ struct firmware_description *d = malloc(sizeof(*d));
+ d->type = 0;
+ d->id = 0;
+ d->data = NULL;
+ d->size = 0;
+ return d;
+}
+
+void free_firmware_description(struct firmware_description *d) {
+ free(d->data);
+ free(d);
+}
+
+struct firmware* alloc_firmware(void) {
+ struct firmware *f = malloc(sizeof(*f));
+ f->name = NULL;
+ f->desc = NULL;
+ f->nr_desc = 0;
+ return f;
+}
+
+void free_firmware(struct firmware *f) {
+ free(f->name);
+ free(f->desc);
+ if(f->desc) {
+ unsigned int i = 0;
+ for(i = 0; i < f->nr_desc; ++ i) {
+ free(f->desc[i].data);
+ }
+ }
+ free(f);
+}
+
+void add_firmware_description(struct firmware *f,
+ struct firmware_description *d) {
+ struct firmware_description* new_desc;
+
+ new_desc = malloc((f->nr_desc + 1) * sizeof(*new_desc));
+ memcpy(new_desc, f->desc, f->nr_desc * sizeof(*new_desc));
+ memcpy(new_desc + f->nr_desc, d, sizeof(*d));
+ free(f->desc);
+ f->desc = new_desc;
+ ++f->nr_desc;
+}
+
+void delete_firmware_description(struct firmware *f, __u16 i) {
+ struct firmware_description* new_desc;
+
+ if(f->nr_desc == 0 || i >= f->nr_desc) {
+ return;
+ }
+
+ new_desc = malloc((f->nr_desc - 1) * sizeof(*new_desc));
+ memcpy(new_desc, f->desc, i * sizeof(*f->desc));
+ memcpy(new_desc + i, f->desc + i + 1, (f->nr_desc - i - 1) * sizeof(*f->desc));
+ free(f->desc);
+ f->desc = new_desc;
+ --f->nr_desc;
+}
+
+/* name[32] + version[2] + nr_desc[2] */
+#define HEADER_LENGTH (32 + 2 + 2)
+/* description header: 4 + 8 + 4.*/
+#define DESC_HEADER_LENGTH (4 + 8 + 4)
+
+int read_firmware(unsigned char* data, off_t size, struct firmware** f_res) {
+ char *name = malloc(33);
+ unsigned char *p = data;
+ struct firmware* f = alloc_firmware();
+ unsigned int i;
+
+ if(size < HEADER_LENGTH) {
+ printf("Invalid firmware header length.\n");
+ free_firmware(f);
+ return -1;
+ }
+ name[32] = 0;
+ memcpy(name, data, 32);
+ f->name = name;
+ p += 32;
+ f->version = __le16_to_cpu(*(__u16*)p);
+ p += sizeof(f->version);
+ f->nr_desc = __le16_to_cpu(*(__u16*)p);
+ p += sizeof(f->nr_desc);
+ f->desc = malloc(f->nr_desc * sizeof(*(f->desc)));
+
+ for(i = 0; i < f->nr_desc; ++i) {
+ if(p + DESC_HEADER_LENGTH > data + size) {
+ printf("Invalid description header length.\n");
+ free_firmware(f);
+ return -1;
+ }
+ f->desc[i].type = __le32_to_cpu(*(__u32*) p);
+ p += sizeof(f->desc[i].type);
+ f->desc[i].id = __le64_to_cpu(*(__u64*) p);
+ p += sizeof(f->desc[i].id);
+ f->desc[i].size = __le32_to_cpu(*(__u32*) p);
+ p += sizeof(f->desc[i].size);
+
+ if(p + f->desc[i].size > data + size) {
+ printf("Invalid firmware standard length.\n");
+ f->nr_desc = (f->nr_desc == 0) ? 0 : f->nr_desc -1;
+ free_firmware(f);
+ return -1;
+ }
+
+ f->desc[i].data = malloc(f->desc[i].size);
+ memcpy(f->desc[i].data, p, f->desc[i].size);
+
+ p += f->desc[i].size;
+ }
+
+ *f_res = f;
+ return 0;
+}
+
+void write_firmware(struct firmware *f, unsigned char** r_data, off_t *r_size) {
+ off_t size;
+ unsigned int i = 0;
+ unsigned char* data;
+ unsigned char* p;
+
+ size = HEADER_LENGTH + f->nr_desc * DESC_HEADER_LENGTH;
+ for(i = 0; i < f->nr_desc; ++i) {
+ size += f->desc[i].size;
+ }
+
+ data = malloc(size);
+ p = data;
+
+ memcpy(p, f->name, 32);
+ p += 32;
+
+ *(__u16*)p = __cpu_to_le16(f->version);
+ p += sizeof(f->version);
+
+ *(__u16*)p = __cpu_to_le16(f->nr_desc);
+ p += sizeof(f->nr_desc);
+
+ for(i = 0; i < f->nr_desc; ++i) {
+ *(__u32*) p = __cpu_to_le32(f->desc[i].type);
+ p += sizeof(f->desc[i].type);
+
+ *(__u64*) p = __cpu_to_le64(f->desc[i].id);
+ p += sizeof(f->desc[i].id);
+
+ *(__u32*) p = __cpu_to_le32(f->desc[i].size);
+ p += sizeof(f->desc[i].size);
+
+ memcpy(p, f->desc[i].data, f->desc[i].size);
+ p += f->desc[i].size;
+ }
+
+ *r_data = data;
+ *r_size = size;
+}
+
+struct firmware* read_firmware_file(const char* filename) {
+ struct stat buf;
+ unsigned char *ptr;
+ struct firmware *f;
+ int fd;
+
+ if(stat(filename, &buf) < 0) {
+ perror("Error during stat");
+ return NULL;
+ }
+
+ fd = open(filename, O_RDONLY);
+ if(fd < 0) {
+ perror("Error while opening the firmware file");
+ free_firmware(f);
+ return NULL;
+ }
+
+ /* allocate firmware buffer*/
+ ptr = malloc(buf.st_size);
+
+ if(read(fd, ptr, buf.st_size) < 0) {
+ perror("Error while reading the firmware file");
+ free(ptr);
+ close(fd);
+ return NULL;
+ }
+
+ if(read_firmware(ptr, buf.st_size, &f) < 0) {
+ printf("Invalid firmware file!\n");
+ free(ptr);
+ close(fd);
+ return NULL;
+ }
+
+ close(fd);
+ free(ptr);
+ return f;
+}
+
+void write_firmware_file(const char* filename, struct firmware *f) {
+ int fd;
+ unsigned char* data;
+ off_t size = 0;
+
+ fd = open(filename, O_WRONLY | O_CREAT);
+ if(fd < 0) {
+ perror("Error while opening the firmware file");
+ return;
+ }
+
+ if(ftruncate(fd, 0) < 0) {
+ perror("Error while deleting the firmware file");
+ close(fd);
+ return;
+ }
+
+ write_firmware(f, &data, &size);
+
+ if(write(fd, data, size) < 0) {
+ perror("Error while writing the firmware file");
+ close(fd);
+ return;
+ }
+
+ free(data);
+ close(fd);
+}
+
+void dump_firm_type(unsigned int type)
+{
+ if (type & BASE)
+ printf("BASE ");
+ if (type & F8MHZ)
+ printf("F8MHZ ");
+ if (type & MTS)
+ printf("MTS ");
+ if (type & D2620)
+ printf("D2620 ");
+ if (type & D2633)
+ printf("D2633 ");
+ if (type & DTV6)
+ printf("DTV6 ");
+ if (type & QAM)
+ printf("QAM ");
+ if (type & DTV7)
+ printf("DTV7 ");
+ if (type & DTV78)
+ printf("DTV78 ");
+ if (type & DTV8)
+ printf("DTV8 ");
+ if (type & FM)
+ printf("FM ");
+ if (type & INPUT1)
+ printf("INPUT1 ");
+ if (type & LCD)
+ printf("LCD ");
+ if (type & NOGD)
+ printf("NOGD ");
+ if (type & MONO)
+ printf("MONO ");
+ if (type & ATSC)
+ printf("ATSC ");
+ if (type & IF)
+ printf("IF ");
+ if (type & LG60)
+ printf("LG60 ");
+ if (type & ATI638)
+ printf("ATI638 ");
+ if (type & OREN538)
+ printf("OREN538 ");
+ if (type & OREN36)
+ printf("OREN36 ");
+ if (type & TOYOTA388)
+ printf("TOYOTA388 ");
+ if (type & TOYOTA794)
+ printf("TOYOTA794 ");
+ if (type & DIBCOM52)
+ printf("DIBCOM52 ");
+ if (type & ZARLINK456)
+ printf("ZARLINK456 ");
+ if (type & CHINA)
+ printf("CHINA ");
+ if (type & F6MHZ)
+ printf("F6MHZ ");
+ if (type & INPUT2)
+ printf("INPUT2 ");
+ if (type & SCODE)
+ printf("SCODE ");
+}
+
+void dump_firm_std(v4l2_std_id id)
+{
+ v4l2_std_id old=-1, curr_id;
+
+ /* Dumps video standards */
+ while (old!=id) {
+ old=id;
+ if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
+ printf ("PAL ");
+ curr_id = V4L2_STD_PAL;
+ } else if ( (id & V4L2_STD_MN) == V4L2_STD_MN) {
+ printf ("NTSC PAL/M PAL/N ");
+ curr_id = V4L2_STD_PAL;
+ } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
+ printf ("PAL/BG ");
+ curr_id = V4L2_STD_PAL_BG;
+ } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
+ printf ("PAL/DK ");
+ curr_id = V4L2_STD_PAL_DK;
+ } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
+ printf ("PAL/B ");
+ curr_id = V4L2_STD_PAL_B;
+ } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
+ printf ("PAL/B1 ");
+ curr_id = V4L2_STD_PAL_B1;
+ } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
+ printf ("PAL/G ");
+ curr_id = V4L2_STD_PAL_G;
+ } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
+ printf ("PAL/H ");
+ curr_id = V4L2_STD_PAL_H;
+ } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
+ printf ("PAL/I ");
+ curr_id = V4L2_STD_PAL_I;
+ } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
+ printf ("PAL/D ");
+ curr_id = V4L2_STD_PAL_D;
+ } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
+ printf ("PAL/D1 ");
+ curr_id = V4L2_STD_PAL_D1;
+ } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
+ printf ("PAL/K ");
+ curr_id = V4L2_STD_PAL_K;
+ } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
+ printf ("PAL/M ");
+ curr_id = V4L2_STD_PAL_M;
+ } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
+ printf ("PAL/N ");
+ curr_id = V4L2_STD_PAL_N;
+ } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
+ printf ("PAL/Nc ");
+ curr_id = V4L2_STD_PAL_Nc;
+ } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
+ printf ("PAL/60 ");
+ curr_id = V4L2_STD_PAL_60;
+ } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+ printf ("NTSC ");
+ curr_id = V4L2_STD_NTSC;
+ } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
+ printf ("NTSC/M ");
+ curr_id = V4L2_STD_NTSC_M;
+ } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
+ printf ("NTSC/M Jp ");
+ curr_id = V4L2_STD_NTSC_M_JP;
+ } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
+ printf ("NTSC 443 ");
+ curr_id = V4L2_STD_NTSC_443;
+ } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
+ printf ("NTSC/M Kr ");
+ curr_id = V4L2_STD_NTSC_M_KR;
+ } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
+ printf ("SECAM ");
+ curr_id = V4L2_STD_SECAM;
+ } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
+ printf ("SECAM/DK ");
+ curr_id = V4L2_STD_SECAM_DK;
+ } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
+ printf ("SECAM/B ");
+ curr_id = V4L2_STD_SECAM_B;
+ } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
+ printf ("SECAM/D ");
+ curr_id = V4L2_STD_SECAM_D;
+ } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
+ printf ("SECAM/G ");
+ curr_id = V4L2_STD_SECAM_G;
+ } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
+ printf ("SECAM/H ");
+ curr_id = V4L2_STD_SECAM_H;
+ } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
+ printf ("SECAM/K ");
+ curr_id = V4L2_STD_SECAM_K;
+ } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
+ printf ("SECAM/K1 ");
+ curr_id = V4L2_STD_SECAM_K1;
+ } else if ( (id & V4L2_STD_SECAM_K3) == V4L2_STD_SECAM_K3) {
+ printf ("SECAM/K3 ");
+ curr_id = V4L2_STD_SECAM_K3;
+ } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
+ printf ("SECAM/L ");
+ curr_id = V4L2_STD_SECAM_L;
+ } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
+ printf ("SECAM/Lc ");
+ curr_id = V4L2_STD_SECAM_LC;
+ } else if ( (id & V4L2_STD_A2) == V4L2_STD_A2) {
+ printf ("A2 ");
+ curr_id = V4L2_STD_A2;
+ } else if ( (id & V4L2_STD_A2_A) == V4L2_STD_A2_A) {
+ printf ("A2/A ");
+ curr_id = V4L2_STD_A2_A;
+ } else if ( (id & V4L2_STD_A2_B) == V4L2_STD_A2_B) {
+ printf ("A2/A ");
+ curr_id = V4L2_STD_A2_B;
+ } else if ( (id & V4L2_STD_NICAM) == V4L2_STD_NICAM) {
+ printf ("NICAM ");
+ curr_id = V4L2_STD_NICAM;
+ } else if ( (id & V4L2_STD_NICAM_A) == V4L2_STD_NICAM_A) {
+ printf ("NICAM/A ");
+ curr_id = V4L2_STD_NICAM_A;
+ } else if ( (id & V4L2_STD_NICAM_B) == V4L2_STD_NICAM_B) {
+ printf ("NICAM/B ");
+ curr_id = V4L2_STD_NICAM_B;
+ } else if ( (id & V4L2_STD_AM) == V4L2_STD_AM) {
+ printf ("AM ");
+ curr_id = V4L2_STD_AM;
+ } else if ( (id & V4L2_STD_BTSC) == V4L2_STD_BTSC) {
+ printf ("BTSC ");
+ curr_id = V4L2_STD_BTSC;
+ } else if ( (id & V4L2_STD_EIAJ) == V4L2_STD_EIAJ) {
+ printf ("EIAJ ");
+ curr_id = V4L2_STD_EIAJ;
+ } else {
+ curr_id = 0;
+ break;
+ }
+ id &= ~curr_id;
+ }
+}
+
+void list_firmware(struct firmware *f) {
+ unsigned int i = 0;
+
+ printf("firmware name:\t%s\n", f->name);
+ printf("version:\t%d.%d (%u)\n", f->version >> 8, f->version & 0xff,
+ f->version);
+ printf("standards:\t%u\n", f->nr_desc);
+ for(i = 0; i < f->nr_desc; ++i) {
+ printf("\n");
+ printf("standard firmware %u\n", i);
+ printf("type:\t");
+ dump_firm_type(f->desc[i].type);
+ printf("(0x%08x)\n", f->desc[i].type);
+ printf("id:\t");
+ dump_firm_std(f->desc[i].id);
+ printf("(%016llx)\n", f->desc[i].id);
+ printf("size:\t%u\n", f->desc[i].size);
+ }
+}
+
+void add_standard(struct firmware* f, char* firmware_file, char* standard_file) {
+ unsigned char* standard_data;
+ unsigned int len, i;
+ struct firmware_description desc;
+
+ create_standard_data(standard_file, &standard_data, &len);
+ if(!standard_data) {
+ fprintf(stderr, "Couldn't create the firmware standard data.\n");
+ return;
+ }
+ desc.id = 0;
+ desc.type = 0;
+ desc.size = len;
+ desc.data = standard_data;
+ add_firmware_description(f, &desc);
+ write_firmware_file(firmware_file, f);
+}
+
+void delete_standard(struct firmware* f, char* firmware_file, __u16 i) {
+ delete_firmware_description(f, i);
+ write_firmware_file(firmware_file, f);
+}
+
+void set_standard_type(struct firmware* f, char* firmware_file, __u16 i, __u32 type) {
+ if(i > f->nr_desc) {
+ return;
+ }
+ f->desc[i].type = type;
+ write_firmware_file(firmware_file, f);
+}
+
+void set_standard_id(struct firmware* f, char* firmware_file, __u16 i, __u32 id) {
+ if(i > f->nr_desc) {
+ return;
+ }
+ f->desc[i].id = id;
+ write_firmware_file(firmware_file, f);
+}
+
+void print_usage(void)
+{
+ printf("firmware-tool usage:\n");
+ printf("\t firmware-tool --list <firmware-file>\n");
+ printf("\t firmware-tool --add <firmware-dump> <firmware-file>\n");
+ printf("\t firmware-tool --delete <index> <firmware-file>\n");
+ printf("\t firmware-tool --type <type> --index <i> <firmware-file>\n");
+ printf("\t firmware-tool --id <type> --index <i> <firmware-file>\n");
+}
+
+int main(int argc, char* argv[])
+{
+ int c;
+ int nr_args;
+ unsigned int action = 0;
+ char* firmware_file, *file = NULL, *nr_str = NULL, *index_str = NULL;
+ struct firmware *f;
+ __u64 nr;
+
+ while(1) {
+ static struct option long_options[] = {
+ {"list", no_argument, 0, 'l'},
+ {"add", required_argument, 0, 'a'},
+ {"delete", required_argument, 0, 'd'},
+ {"type", required_argument, 0, 't'},
+ {"id", required_argument, 0, 's'},
+ {"index", required_argument, 0, 'i'},
+ {0, 0, 0, 0}
+ };
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "", long_options, &option_index);
+
+ if (c == -1) {
+ break;
+ }
+
+ switch(c) {
+ case 'l':
+ puts("list action\n");
+ if(action != 0) {
+ printf("Please specify only one action.\n");
+ }
+ action |= LIST_ACTION;
+ break;
+ case 'a':
+ puts("add action\n");
+ if(action != 0) {
+ printf("Please specify only one action.\n");
+ }
+ action |= ADD_ACTION;
+ file = optarg;
+ break;
+ case 'd':
+ puts("delete action\n");
+ if(action != 0) {
+ printf("Please specify only one action.\n");
+ }
+ action |= DELETE_ACTION;
+ nr_str = optarg;
+ break;
+ case 't':
+ puts("set-type action\n");
+ if(action != 0) {
+ printf("Please specify only one action.\n");
+ }
+ action |= SET_TYPE_ACTION;
+ nr_str = optarg;
+ break;
+ case 's':
+ puts("set-id action\n");
+ if(action != 0) {
+ printf("Please specify only one action.\n");
+ }
+ action |= SET_ID_ACTION;
+ nr_str = optarg;
+ break;
+ case 'i':
+ index_str = optarg;
+ break;
+ default:
+ print_usage();
+ return 0;
+ }
+ }
+
+ nr_args = (action == LIST_ACTION) ? 1 : 1;
+ if(!(optind + nr_args == argc)) {
+ printf("Wrong number of arguments!\n\n");
+ print_usage();
+ return -1;
+ }
+
+ if(!action) {
+ printf("Please specify an action!\n\n");
+ print_usage();
+ return -1;
+ }
+
+ firmware_file = argv[optind];
+
+ printf("firmware file name: %s\n", firmware_file);
+
+ f = read_firmware_file(firmware_file);
+ if(!f) {
+ printf("Couldn't read the firmware file!\n");
+ return -1;
+ }
+
+ switch(action) {
+ case LIST_ACTION:
+ list_firmware(f);
+ break;
+
+ case ADD_ACTION:
+ add_standard(f, firmware_file, file);
+ break;
+
+ case DELETE_ACTION:
+ delete_standard(f, firmware_file, strtoul(nr_str, NULL, 10));
+ break;
+
+ case SET_TYPE_ACTION:
+ set_standard_type(f, firmware_file, strtoul(index_str, NULL, 10), strtoul(nr_str, NULL, 10));
+ break;
+
+ case SET_ID_ACTION:
+ set_standard_id(f, firmware_file, strtoul(index_str, NULL, 10), strtoul(nr_str, NULL, 10));
+ break;
+ }
+ return 0;
+}
diff --git a/v4l2-apps/util/xc3028-firmware/standards.c b/v4l2-apps/util/xc3028-firmware/standards.c
new file mode 100644
index 000000000..38b2e625d
--- /dev/null
+++ b/v4l2-apps/util/xc3028-firmware/standards.c
@@ -0,0 +1,152 @@
+/*
+ Xceive XC2028/3028 tuner module firmware manipulation tool
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.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
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "standards.h"
+
+#define _GNU_SOURCE
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <asm/byteorder.h>
+#include <asm/types.h>
+
+#define MAX(a,b) ((a) >= (b) ? (a) : (b))
+
+struct vector {
+ unsigned char* data;
+ unsigned int size;
+};
+
+struct vector* alloc_vector(unsigned int size) {
+ struct vector *v = malloc(sizeof(*v));
+ v->data = malloc(size);
+ v->size = size;
+ return v;
+}
+
+void free_vector(struct vector* v) {
+ free(v->data);
+ free(v);
+}
+
+void enlarge_vector(struct vector* v, unsigned int new_size) {
+ unsigned char *n_data;
+ unsigned int old_size = v->size;
+
+ v->size = MAX(v->size, new_size);
+ n_data = malloc(v->size);
+ memcpy(n_data, v->data, old_size);
+ free(v->data);
+ v->data = n_data;
+}
+
+void copy_vector(struct vector *v, unsigned int i,
+ unsigned char* ptr, unsigned int len) {
+ if(i + len > v->size) {
+ enlarge_vector(v, MAX(2 * v->size, i + len));
+ }
+ memcpy(v->data + i, ptr, len);
+}
+
+void write_vector8(struct vector *v, unsigned int i, __u8 value) {
+ __u8 buf[1];
+
+ buf[0] = value;
+ copy_vector(v, i, buf, 1);
+}
+
+void write_vector16(struct vector *v, unsigned int i, __u16 value) {
+ __u8 buf[2];
+
+ buf[0] = value & 0xff;
+ buf[1] = value >> 8;
+ copy_vector(v, i, buf, 2);
+}
+
+static const const char reset_tuner_str[] = "RESET_TUNER";
+static const const char reset_clk_str[] = "RESET_CLK";
+
+void create_standard_data(char* filename, unsigned char** data, unsigned int *r_len) {
+ FILE *file;
+ char* line = NULL;
+ ssize_t r = 0;
+ size_t len = 0;
+ struct vector *v = alloc_vector(1);
+ unsigned int v_i = 0;
+
+ if (!(file = fopen(filename, "r"))) {
+ perror("Cannot open the firmware standard file.\n");
+ *data = NULL;
+ }
+
+ while ((r = getline(&line, &len, file)) != -1) {
+ unsigned int i = 0;
+ unsigned int val, count = 0;
+ unsigned int values[len];
+
+ printf("read line \"%s\"\n", line);
+
+ if(len >= 9 && memcmp(reset_clk_str, line, strlen(reset_clk_str) - 1) == 0) {
+ printf("adding RESET_CLK\n");
+ write_vector16(v, v_i, (__u16) 0xff00);
+ v_i += 2;
+ continue;
+ }
+ else if(len >= 11 && memcmp(reset_tuner_str, line, strlen(reset_tuner_str) - 1) == 0) {
+ printf("adding RESET_TUNER\n");
+ write_vector16(v, v_i, (__u16) 0x0000);
+ v_i += 2;
+ continue;
+ }
+
+ while(i < len && sscanf(line + i*sizeof(char), "%2x", &val) == 1) {
+ printf("%2x ", val);
+ values[count] = val;
+ ++count;
+ i += 2;
+ while(line[i] == ' ') {
+ ++i;
+ }
+ }
+
+ write_vector16(v, v_i, __cpu_to_le16((__u16) count));
+ v_i += 2;
+
+
+ for(i = 0; i < count; ++i) {
+ write_vector8(v, v_i, (__u8) values[i]);
+ ++v_i;
+ }
+
+ printf("\n");
+ }
+ write_vector16(v, v_i, 0xffff);
+ v_i += 2;
+
+ free(line);
+ fclose(file);
+ *data = malloc(v_i);
+ memcpy(*data, v->data, v_i);
+ free_vector(v);
+ *r_len = v_i;
+}
+
diff --git a/v4l2-apps/util/xc3028-firmware/standards.h b/v4l2-apps/util/xc3028-firmware/standards.h
new file mode 100644
index 000000000..c9da02b5a
--- /dev/null
+++ b/v4l2-apps/util/xc3028-firmware/standards.h
@@ -0,0 +1,25 @@
+/*
+ Xceive XC2028/3028 tuner module firmware manipulation tool
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.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
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STANDARDS_H
+#define STANDARDS_H
+
+void create_standard_data(char* filename, unsigned char** data, unsigned int *len);
+
+#endif