FreeCalypso > hg > fc-usbser-tools
diff cp2102/apply_eeprom_patch.c @ 92:915a6fa7723e
cp2102-patch-ee-image program written, compiles
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 28 Sep 2023 01:37:43 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp2102/apply_eeprom_patch.c Thu Sep 28 01:37:43 2023 +0000 @@ -0,0 +1,403 @@ +/* + * 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); +}