FreeCalypso > hg > fc-usbser-tools
view cp2102/apply_eeprom_patch.c @ 104:866eae65dbea
LICENSE: same as other FreeCalypso tools
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 29 Sep 2023 18:20:04 +0000 |
parents | 915a6fa7723e |
children |
line wrap: on
line source
/* * This function implemented in this module reads a CP2102 EEPROM patch * specification file (which can also be a baud rate table file) and applies * patches to the EEPROM image in RAM. */ #include <sys/types.h> #include <ctype.h> #include <string.h> #include <strings.h> #include <stdio.h> #include <stdlib.h> #include "cp210x_defs.h" extern u_char eeprom[SIZE_EEPROM]; static char cp2102_install_dir[] = "/opt/freecalypso/cp2102"; static void apply_baud_entry(filename, lineno, args) char *filename, *args; { unsigned entry_idx, intend_baud, baudgen_val, timeout_val; unsigned prescaler, extra_byte; char *cp = args; u_char *eerec; if (!isdigit(*cp)) { inv: fprintf(stderr, "%s line %d: invalid syntax for baud-entry\n", filename, lineno); exit(1); } entry_idx = strtoul(cp, &cp, 10); while (isspace(*cp)) cp++; if (*cp++ != ':') goto inv; while (isspace(*cp)) cp++; if (!isdigit(*cp)) goto inv; intend_baud = strtoul(cp, &cp, 10); while (isspace(*cp)) cp++; if (*cp++ != '=') goto inv; while (isspace(*cp)) cp++; if (!isxdigit(*cp)) goto inv; baudgen_val = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (*cp++ != ',') goto inv; while (isspace(*cp)) cp++; if (!isxdigit(*cp)) goto inv; timeout_val = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (*cp++ != ',') goto inv; while (isspace(*cp)) cp++; if (!isdigit(*cp)) goto inv; prescaler = strtoul(cp, &cp, 10); while (isspace(*cp)) cp++; if (*cp++ != ',') goto inv; while (isspace(*cp)) cp++; if (!isdigit(*cp)) goto inv; extra_byte = strtoul(cp, &cp, 10); while (isspace(*cp)) cp++; if (*cp && *cp != '#') goto inv; /* done with parsing, get to EEPROM */ if (entry_idx > 31) { fprintf(stderr, "%s line %d: invalid baud-entry index\n", filename, lineno); exit(1); } eerec = eeprom + entry_idx * SIZE_BAUDRATE_CFG; eerec[0] = baudgen_val >> 8; eerec[1] = baudgen_val; eerec[2] = timeout_val >> 8; eerec[3] = timeout_val; eerec[4] = prescaler; eerec[5] = extra_byte; eerec[6] = intend_baud; eerec[7] = intend_baud >> 8; eerec[8] = intend_baud >> 16; eerec[9] = intend_baud >> 24; } static void apply_patch_8bit(filename, lineno, args) char *filename, *args; { unsigned patch_loc, patch_val; char *cp = args; if (!isxdigit(*cp)) { inv: fprintf(stderr, "%s line %d: invalid syntax for patch8\n", filename, lineno); exit(1); } patch_loc = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (!isxdigit(*cp)) goto inv; patch_val = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (*cp && *cp != '#') goto inv; /* validate range */ if (patch_loc >= EEPROM_START_ADDR && patch_loc <= EEPROM_START_ADDR + SIZE_EEPROM - 1) patch_loc -= EEPROM_START_ADDR; else if (patch_loc > SIZE_EEPROM - 1) { fprintf(stderr, "%s line %d: invalid patch address\n", filename, lineno); exit(1); } if (patch_val > 0xFF) { fprintf(stderr, "%s line %d: patch value does not fit into 8 bits\n", filename, lineno); exit(1); } /* checks done, proceed */ eeprom[patch_loc] = patch_val; } static void apply_patch_16bit(filename, lineno, args) char *filename, *args; { unsigned patch_loc, patch_val; char *cp = args; if (!isxdigit(*cp)) { inv: fprintf(stderr, "%s line %d: invalid syntax for patch16\n", filename, lineno); exit(1); } patch_loc = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (!isxdigit(*cp)) goto inv; patch_val = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (*cp && *cp != '#') goto inv; /* validate range */ if (patch_loc >= EEPROM_START_ADDR && patch_loc <= EEPROM_START_ADDR + SIZE_EEPROM - 2) patch_loc -= EEPROM_START_ADDR; else if (patch_loc > SIZE_EEPROM - 2) { fprintf(stderr, "%s line %d: invalid patch address\n", filename, lineno); exit(1); } if (patch_val > 0xFFFF) { fprintf(stderr, "%s line %d: patch value does not fit into 16 bits\n", filename, lineno); exit(1); } /* checks done, proceed */ eeprom[patch_loc] = patch_val; eeprom[patch_loc+1] = patch_val >> 8; } static void apply_patch_vid(filename, lineno, args) char *filename, *args; { unsigned patch_val; char *cp = args; if (!isxdigit(*cp)) { inv: fprintf(stderr, "%s line %d: invalid syntax for vid\n", filename, lineno); exit(1); } patch_val = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (*cp && *cp != '#') goto inv; /* validate range */ if (patch_val > 0xFFFF) { fprintf(stderr, "%s line %d: VID does not fit into 16 bits\n", filename, lineno); exit(1); } /* checks done, proceed */ eeprom[0x390] = patch_val; eeprom[0x391] = patch_val >> 8; } static void apply_patch_pid(filename, lineno, args) char *filename, *args; { unsigned patch_val; char *cp = args; if (!isxdigit(*cp)) { inv: fprintf(stderr, "%s line %d: invalid syntax for pid\n", filename, lineno); exit(1); } patch_val = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (*cp && *cp != '#') goto inv; /* validate range */ if (patch_val > 0xFFFF) { fprintf(stderr, "%s line %d: PID does not fit into 16 bits\n", filename, lineno); exit(1); } /* checks done, proceed */ eeprom[0x392] = patch_val; eeprom[0x393] = patch_val >> 8; } static void set_string_desc(start_offset, str) unsigned start_offset; char *str; { char *cp; u_char *dp; dp = eeprom + start_offset; *dp++ = strlen(str) * 2 + 2; *dp++ = 0x03; for (cp = str; *cp; ) { *dp++ = *cp++; *dp++ = 0; } } static void set_manuf_string(filename, lineno, arg) char *filename, *arg; { if (strlen(arg) > 29) { fprintf(stderr, "%s line %d: manuf string is too long\n", filename, lineno); exit(1); } set_string_desc(0x3C3, arg); } static void set_product_string(filename, lineno, arg) char *filename, *arg; { if (strlen(arg) > 126) { fprintf(stderr, "%s line %d: product string is too long\n", filename, lineno); exit(1); } set_string_desc(0x208, arg); } static void set_serial_string(filename, lineno, arg) char *filename, *arg; { if (strlen(arg) > 63) { fprintf(stderr, "%s line %d: serial string is too long\n", filename, lineno); exit(1); } set_string_desc(0x307, arg); } static void apply_eeprom_patch_int(filename, inf) char *filename; FILE *inf; { char linebuf[1024]; int lineno; char *cp, *np; for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) { cp = index(linebuf, '\n'); if (!cp) { fprintf(stderr, "%s line %d: too long or unterminated\n", filename, lineno); exit(1); } *cp = '\0'; for (cp = linebuf; isspace(*cp); cp++) ; if (*cp == '\0' || *cp == '#') continue; for (np = cp; *cp && !isspace(*cp); cp++) ; if (*cp) *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0' || *cp == '#') { fprintf(stderr, "%s line %d: \"%s\" setting without argument\n", filename, lineno, np); exit(1); } if (!strcmp(np, "baud-entry")) apply_baud_entry(filename, lineno, cp); else if (!strcmp(np, "patch8")) apply_patch_8bit(filename, lineno, cp); else if (!strcmp(np, "patch16")) apply_patch_16bit(filename, lineno, cp); else if (!strcmp(np, "vid")) apply_patch_vid(filename, lineno, cp); else if (!strcmp(np, "pid")) apply_patch_pid(filename, lineno, cp); else if (!strcmp(np, "manuf")) set_manuf_string(filename, lineno, cp); else if (!strcmp(np, "product")) set_product_string(filename, lineno, cp); else if (!strcmp(np, "serial")) set_serial_string(filename, lineno, cp); else { fprintf(stderr, "%s line %d: unknown \"%s\" setting\n", filename, lineno, np); exit(1); } } } static FILE * open_with_search(req_filename) char *req_filename; { char pathbuf[256]; FILE *f; if (!index(req_filename, '/') && strlen(req_filename) < 128) { sprintf(pathbuf, "%s/%s", cp2102_install_dir, req_filename); f = fopen(pathbuf, "r"); if (f) return f; } f = fopen(req_filename, "r"); return f; } void apply_eeprom_patch_file(filename) char *filename; { FILE *inf; inf = open_with_search(filename); if (!inf) { perror(filename); exit(1); } apply_eeprom_patch_int(filename, inf); fclose(inf); } void apply_eeprom_patch_baud(baud_spec_name) char *baud_spec_name; { char pathbuf[256]; FILE *inf; if (strlen(baud_spec_name) > 63) { fprintf(stderr, "error: no buffer overflow attacks, please\n"); exit(1); } sprintf(pathbuf, "%s/baudtab-%s", cp2102_install_dir, baud_spec_name); inf = fopen(pathbuf, "r"); if (!inf) { perror(pathbuf); exit(1); } apply_eeprom_patch_int(pathbuf, inf); fclose(inf); }