📄 firmware-tool.c
字号:
/* Xceive XC2028/3028 tuner module firmware manipulation tool Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> Copyright (C) 2007, 2008 Mauro Carvalho Chehab <mchehab@infradead.org> - Improve --list command - Add --seek command 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>#define __USE_GNU#include <string.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 "extract_head.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)#define SEEK_FIRM_ACTION (1<<5)struct firmware_description { __u32 type; __u64 id; unsigned char *data; __u16 int_freq; __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); if (f->desc[i].type & HAS_IF) { f->desc[i].int_freq = __le16_to_cpu(*(__u16 *) p); p += sizeof(f->desc[i].int_freq); } 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(FILE *fp, unsigned int type){ if (type & SCODE) fprintf(fp, "SCODE FW "); else if (type & BASE) fprintf(fp, "BASE FW "); else fprintf(fp, "STD FW "); if (type & F8MHZ) fprintf(fp, "F8MHZ "); if (type & MTS) fprintf(fp, "MTS "); if (type & D2620) fprintf(fp, "D2620 "); if (type & D2633) fprintf(fp, "D2633 "); if (type & DTV6) fprintf(fp, "DTV6 "); if (type & QAM) fprintf(fp, "QAM "); if (type & DTV7) fprintf(fp, "DTV7 "); if (type & DTV78) fprintf(fp, "DTV78 "); if (type & DTV8) fprintf(fp, "DTV8 "); if (type & FM) fprintf(fp, "FM "); if (type & INPUT1) fprintf(fp, "INPUT1 "); if (type & LCD) fprintf(fp, "LCD "); if (type & NOGD) fprintf(fp, "NOGD "); if (type & MONO) fprintf(fp, "MONO "); if (type & ATSC) fprintf(fp, "ATSC "); if (type & IF) fprintf(fp, "IF "); if (type & LG60) fprintf(fp, "LG60 "); if (type & ATI638) fprintf(fp, "ATI638 "); if (type & OREN538) fprintf(fp, "OREN538 "); if (type & OREN36) fprintf(fp, "OREN36 "); if (type & TOYOTA388) fprintf(fp, "TOYOTA388 "); if (type & TOYOTA794) fprintf(fp, "TOYOTA794 "); if (type & DIBCOM52) fprintf(fp, "DIBCOM52 "); if (type & ZARLINK456) fprintf(fp, "ZARLINK456 "); if (type & CHINA) fprintf(fp, "CHINA "); if (type & F6MHZ) fprintf(fp, "F6MHZ "); if (type & INPUT2) fprintf(fp, "INPUT2 "); if (type & HAS_IF) fprintf(fp, "HAS IF ");}void dump_firm_std(FILE *fp, 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) { fprintf (fp, "PAL "); curr_id = V4L2_STD_PAL; } else if ( (id & V4L2_STD_MN) == V4L2_STD_MN) { fprintf (fp, "NTSC PAL/M PAL/N "); curr_id = V4L2_STD_PAL; } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) { fprintf (fp, "PAL/BG "); curr_id = V4L2_STD_PAL_BG; } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) { fprintf (fp, "PAL/DK "); curr_id = V4L2_STD_PAL_DK; } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) { fprintf (fp, "PAL/B "); curr_id = V4L2_STD_PAL_B; } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) { fprintf (fp, "PAL/B1 "); curr_id = V4L2_STD_PAL_B1; } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) { fprintf (fp, "PAL/G "); curr_id = V4L2_STD_PAL_G; } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) { fprintf (fp, "PAL/H "); curr_id = V4L2_STD_PAL_H; } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) { fprintf (fp, "PAL/I "); curr_id = V4L2_STD_PAL_I; } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) { fprintf (fp, "PAL/D "); curr_id = V4L2_STD_PAL_D; } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) { fprintf (fp, "PAL/D1 "); curr_id = V4L2_STD_PAL_D1; } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) { fprintf (fp, "PAL/K "); curr_id = V4L2_STD_PAL_K; } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) { fprintf (fp, "PAL/M "); curr_id = V4L2_STD_PAL_M; } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) { fprintf (fp, "PAL/N "); curr_id = V4L2_STD_PAL_N; } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) { fprintf (fp, "PAL/Nc "); curr_id = V4L2_STD_PAL_Nc; } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) { fprintf (fp, "PAL/60 "); curr_id = V4L2_STD_PAL_60; } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) { fprintf (fp, "NTSC "); curr_id = V4L2_STD_NTSC; } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) { fprintf (fp, "NTSC/M "); curr_id = V4L2_STD_NTSC_M; } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) { fprintf (fp, "NTSC/M Jp "); curr_id = V4L2_STD_NTSC_M_JP; } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) { fprintf (fp, "NTSC 443 "); curr_id = V4L2_STD_NTSC_443; } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) { fprintf (fp, "NTSC/M Kr "); curr_id = V4L2_STD_NTSC_M_KR; } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) { fprintf (fp, "SECAM "); curr_id = V4L2_STD_SECAM; } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) { fprintf (fp, "SECAM/DK "); curr_id = V4L2_STD_SECAM_DK; } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) { fprintf (fp, "SECAM/B "); curr_id = V4L2_STD_SECAM_B; } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) { fprintf (fp, "SECAM/D "); curr_id = V4L2_STD_SECAM_D; } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) { fprintf (fp, "SECAM/G "); curr_id = V4L2_STD_SECAM_G; } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) { fprintf (fp, "SECAM/H "); curr_id = V4L2_STD_SECAM_H; } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) { fprintf (fp, "SECAM/K "); curr_id = V4L2_STD_SECAM_K; } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) { fprintf (fp, "SECAM/K1 "); curr_id = V4L2_STD_SECAM_K1; } else if ( (id & V4L2_STD_SECAM_K3) == V4L2_STD_SECAM_K3) { fprintf (fp, "SECAM/K3 "); curr_id = V4L2_STD_SECAM_K3; } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) { fprintf (fp, "SECAM/L "); curr_id = V4L2_STD_SECAM_L; } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) { fprintf (fp, "SECAM/Lc "); curr_id = V4L2_STD_SECAM_LC; } else if ( (id & V4L2_STD_A2) == V4L2_STD_A2) { fprintf (fp, "A2 "); curr_id = V4L2_STD_A2; } else if ( (id & V4L2_STD_A2_A) == V4L2_STD_A2_A) { fprintf (fp, "A2/A "); curr_id = V4L2_STD_A2_A; } else if ( (id & V4L2_STD_A2_B) == V4L2_STD_A2_B) { fprintf (fp, "A2/B "); curr_id = V4L2_STD_A2_B; } else if ( (id & V4L2_STD_NICAM) == V4L2_STD_NICAM) { fprintf (fp, "NICAM "); curr_id = V4L2_STD_NICAM; } else if ( (id & V4L2_STD_NICAM_A) == V4L2_STD_NICAM_A) { fprintf (fp, "NICAM/A "); curr_id = V4L2_STD_NICAM_A; } else if ( (id & V4L2_STD_NICAM_B) == V4L2_STD_NICAM_B) { fprintf (fp, "NICAM/B "); curr_id = V4L2_STD_NICAM_B; } else if ( (id & V4L2_STD_AM) == V4L2_STD_AM) { fprintf (fp, "AM "); curr_id = V4L2_STD_AM; } else if ( (id & V4L2_STD_BTSC) == V4L2_STD_BTSC) { fprintf (fp, "BTSC "); curr_id = V4L2_STD_BTSC; } else if ( (id & V4L2_STD_EIAJ) == V4L2_STD_EIAJ) { fprintf (fp, "EIAJ "); curr_id = V4L2_STD_EIAJ; } else { curr_id = 0; break; } id &= ~curr_id; }}void list_firmware_desc(FILE *fp, struct firmware_description *desc){ fprintf(fp, "type: "); dump_firm_type(fp, desc->type); fprintf(fp, "(0x%08x), ", desc->type); if (desc->type & HAS_IF) fprintf(fp, "IF = %.2f MHz ", desc->int_freq/1000.0); fprintf(fp, "id: "); dump_firm_std(fp, desc->id); fprintf(fp, "(%016llx), ", desc->id); fprintf(fp, "size: %u\n", desc->size);}void list_firmware(struct firmware *f, unsigned int dump, char *binfile){ 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("Firmware %2u, ", i); list_firmware_desc(stdout, &f->desc[i]); if (dump) { printf("\t"); unsigned j, k = 0; for (j = 0; j < f->desc[i].size; j++) { printf("%02x", f->desc[i].data[j]); k++; if (k >= 32) { printf("\n\t"); k = 0; } else if (!(k % 2)) printf(" "); } printf("\n"); } if (binfile) { char name[strlen(binfile)+4], *p; p = strrchr(binfile,'.'); if (p) { int n = p - binfile; strncpy(name, binfile, n); sprintf(name + n, "%03i", i); strcat(name, p); } else { strcpy(name, binfile); sprintf(name + strlen(name), "%03i", i); } FILE *fp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -