FreeCalypso > hg > fc-usbser-tools
comparison 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 |
comparison
equal
deleted
inserted
replaced
91:f4a7ac90cf39 | 92:915a6fa7723e |
---|---|
1 /* | |
2 * This function implemented in this module reads a CP2102 EEPROM patch | |
3 * specification file (which can also be a baud rate table file) and applies | |
4 * patches to the EEPROM image in RAM. | |
5 */ | |
6 | |
7 #include <sys/types.h> | |
8 #include <ctype.h> | |
9 #include <string.h> | |
10 #include <strings.h> | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include "cp210x_defs.h" | |
14 | |
15 extern u_char eeprom[SIZE_EEPROM]; | |
16 | |
17 static char cp2102_install_dir[] = "/opt/freecalypso/cp2102"; | |
18 | |
19 static void | |
20 apply_baud_entry(filename, lineno, args) | |
21 char *filename, *args; | |
22 { | |
23 unsigned entry_idx, intend_baud, baudgen_val, timeout_val; | |
24 unsigned prescaler, extra_byte; | |
25 char *cp = args; | |
26 u_char *eerec; | |
27 | |
28 if (!isdigit(*cp)) { | |
29 inv: fprintf(stderr, "%s line %d: invalid syntax for baud-entry\n", | |
30 filename, lineno); | |
31 exit(1); | |
32 } | |
33 entry_idx = strtoul(cp, &cp, 10); | |
34 while (isspace(*cp)) | |
35 cp++; | |
36 if (*cp++ != ':') | |
37 goto inv; | |
38 while (isspace(*cp)) | |
39 cp++; | |
40 if (!isdigit(*cp)) | |
41 goto inv; | |
42 intend_baud = strtoul(cp, &cp, 10); | |
43 while (isspace(*cp)) | |
44 cp++; | |
45 if (*cp++ != '=') | |
46 goto inv; | |
47 while (isspace(*cp)) | |
48 cp++; | |
49 if (!isxdigit(*cp)) | |
50 goto inv; | |
51 baudgen_val = strtoul(cp, &cp, 16); | |
52 while (isspace(*cp)) | |
53 cp++; | |
54 if (*cp++ != ',') | |
55 goto inv; | |
56 while (isspace(*cp)) | |
57 cp++; | |
58 if (!isxdigit(*cp)) | |
59 goto inv; | |
60 timeout_val = strtoul(cp, &cp, 16); | |
61 while (isspace(*cp)) | |
62 cp++; | |
63 if (*cp++ != ',') | |
64 goto inv; | |
65 while (isspace(*cp)) | |
66 cp++; | |
67 if (!isdigit(*cp)) | |
68 goto inv; | |
69 prescaler = strtoul(cp, &cp, 10); | |
70 while (isspace(*cp)) | |
71 cp++; | |
72 if (*cp++ != ',') | |
73 goto inv; | |
74 while (isspace(*cp)) | |
75 cp++; | |
76 if (!isdigit(*cp)) | |
77 goto inv; | |
78 extra_byte = strtoul(cp, &cp, 10); | |
79 while (isspace(*cp)) | |
80 cp++; | |
81 if (*cp && *cp != '#') | |
82 goto inv; | |
83 /* done with parsing, get to EEPROM */ | |
84 if (entry_idx > 31) { | |
85 fprintf(stderr, "%s line %d: invalid baud-entry index\n", | |
86 filename, lineno); | |
87 exit(1); | |
88 } | |
89 eerec = eeprom + entry_idx * SIZE_BAUDRATE_CFG; | |
90 eerec[0] = baudgen_val >> 8; | |
91 eerec[1] = baudgen_val; | |
92 eerec[2] = timeout_val >> 8; | |
93 eerec[3] = timeout_val; | |
94 eerec[4] = prescaler; | |
95 eerec[5] = extra_byte; | |
96 eerec[6] = intend_baud; | |
97 eerec[7] = intend_baud >> 8; | |
98 eerec[8] = intend_baud >> 16; | |
99 eerec[9] = intend_baud >> 24; | |
100 } | |
101 | |
102 static void | |
103 apply_patch_8bit(filename, lineno, args) | |
104 char *filename, *args; | |
105 { | |
106 unsigned patch_loc, patch_val; | |
107 char *cp = args; | |
108 | |
109 if (!isxdigit(*cp)) { | |
110 inv: fprintf(stderr, "%s line %d: invalid syntax for patch8\n", | |
111 filename, lineno); | |
112 exit(1); | |
113 } | |
114 patch_loc = strtoul(cp, &cp, 16); | |
115 while (isspace(*cp)) | |
116 cp++; | |
117 if (!isxdigit(*cp)) | |
118 goto inv; | |
119 patch_val = strtoul(cp, &cp, 16); | |
120 while (isspace(*cp)) | |
121 cp++; | |
122 if (*cp && *cp != '#') | |
123 goto inv; | |
124 /* validate range */ | |
125 if (patch_loc >= EEPROM_START_ADDR && | |
126 patch_loc <= EEPROM_START_ADDR + SIZE_EEPROM - 1) | |
127 patch_loc -= EEPROM_START_ADDR; | |
128 else if (patch_loc > SIZE_EEPROM - 1) { | |
129 fprintf(stderr, "%s line %d: invalid patch address\n", | |
130 filename, lineno); | |
131 exit(1); | |
132 } | |
133 if (patch_val > 0xFF) { | |
134 fprintf(stderr, | |
135 "%s line %d: patch value does not fit into 8 bits\n", | |
136 filename, lineno); | |
137 exit(1); | |
138 } | |
139 /* checks done, proceed */ | |
140 eeprom[patch_loc] = patch_val; | |
141 } | |
142 | |
143 static void | |
144 apply_patch_16bit(filename, lineno, args) | |
145 char *filename, *args; | |
146 { | |
147 unsigned patch_loc, patch_val; | |
148 char *cp = args; | |
149 | |
150 if (!isxdigit(*cp)) { | |
151 inv: fprintf(stderr, "%s line %d: invalid syntax for patch16\n", | |
152 filename, lineno); | |
153 exit(1); | |
154 } | |
155 patch_loc = strtoul(cp, &cp, 16); | |
156 while (isspace(*cp)) | |
157 cp++; | |
158 if (!isxdigit(*cp)) | |
159 goto inv; | |
160 patch_val = strtoul(cp, &cp, 16); | |
161 while (isspace(*cp)) | |
162 cp++; | |
163 if (*cp && *cp != '#') | |
164 goto inv; | |
165 /* validate range */ | |
166 if (patch_loc >= EEPROM_START_ADDR && | |
167 patch_loc <= EEPROM_START_ADDR + SIZE_EEPROM - 2) | |
168 patch_loc -= EEPROM_START_ADDR; | |
169 else if (patch_loc > SIZE_EEPROM - 2) { | |
170 fprintf(stderr, "%s line %d: invalid patch address\n", | |
171 filename, lineno); | |
172 exit(1); | |
173 } | |
174 if (patch_val > 0xFFFF) { | |
175 fprintf(stderr, | |
176 "%s line %d: patch value does not fit into 16 bits\n", | |
177 filename, lineno); | |
178 exit(1); | |
179 } | |
180 /* checks done, proceed */ | |
181 eeprom[patch_loc] = patch_val; | |
182 eeprom[patch_loc+1] = patch_val >> 8; | |
183 } | |
184 | |
185 static void | |
186 apply_patch_vid(filename, lineno, args) | |
187 char *filename, *args; | |
188 { | |
189 unsigned patch_val; | |
190 char *cp = args; | |
191 | |
192 if (!isxdigit(*cp)) { | |
193 inv: fprintf(stderr, "%s line %d: invalid syntax for vid\n", | |
194 filename, lineno); | |
195 exit(1); | |
196 } | |
197 patch_val = strtoul(cp, &cp, 16); | |
198 while (isspace(*cp)) | |
199 cp++; | |
200 if (*cp && *cp != '#') | |
201 goto inv; | |
202 /* validate range */ | |
203 if (patch_val > 0xFFFF) { | |
204 fprintf(stderr, "%s line %d: VID does not fit into 16 bits\n", | |
205 filename, lineno); | |
206 exit(1); | |
207 } | |
208 /* checks done, proceed */ | |
209 eeprom[0x390] = patch_val; | |
210 eeprom[0x391] = patch_val >> 8; | |
211 } | |
212 | |
213 static void | |
214 apply_patch_pid(filename, lineno, args) | |
215 char *filename, *args; | |
216 { | |
217 unsigned patch_val; | |
218 char *cp = args; | |
219 | |
220 if (!isxdigit(*cp)) { | |
221 inv: fprintf(stderr, "%s line %d: invalid syntax for pid\n", | |
222 filename, lineno); | |
223 exit(1); | |
224 } | |
225 patch_val = strtoul(cp, &cp, 16); | |
226 while (isspace(*cp)) | |
227 cp++; | |
228 if (*cp && *cp != '#') | |
229 goto inv; | |
230 /* validate range */ | |
231 if (patch_val > 0xFFFF) { | |
232 fprintf(stderr, "%s line %d: PID does not fit into 16 bits\n", | |
233 filename, lineno); | |
234 exit(1); | |
235 } | |
236 /* checks done, proceed */ | |
237 eeprom[0x392] = patch_val; | |
238 eeprom[0x393] = patch_val >> 8; | |
239 } | |
240 | |
241 static void | |
242 set_string_desc(start_offset, str) | |
243 unsigned start_offset; | |
244 char *str; | |
245 { | |
246 char *cp; | |
247 u_char *dp; | |
248 | |
249 dp = eeprom + start_offset; | |
250 *dp++ = strlen(str) * 2 + 2; | |
251 *dp++ = 0x03; | |
252 for (cp = str; *cp; ) { | |
253 *dp++ = *cp++; | |
254 *dp++ = 0; | |
255 } | |
256 } | |
257 | |
258 static void | |
259 set_manuf_string(filename, lineno, arg) | |
260 char *filename, *arg; | |
261 { | |
262 if (strlen(arg) > 29) { | |
263 fprintf(stderr, "%s line %d: manuf string is too long\n", | |
264 filename, lineno); | |
265 exit(1); | |
266 } | |
267 set_string_desc(0x3C3, arg); | |
268 } | |
269 | |
270 static void | |
271 set_product_string(filename, lineno, arg) | |
272 char *filename, *arg; | |
273 { | |
274 if (strlen(arg) > 126) { | |
275 fprintf(stderr, "%s line %d: product string is too long\n", | |
276 filename, lineno); | |
277 exit(1); | |
278 } | |
279 set_string_desc(0x208, arg); | |
280 } | |
281 | |
282 static void | |
283 set_serial_string(filename, lineno, arg) | |
284 char *filename, *arg; | |
285 { | |
286 if (strlen(arg) > 63) { | |
287 fprintf(stderr, "%s line %d: serial string is too long\n", | |
288 filename, lineno); | |
289 exit(1); | |
290 } | |
291 set_string_desc(0x307, arg); | |
292 } | |
293 | |
294 static void | |
295 apply_eeprom_patch_int(filename, inf) | |
296 char *filename; | |
297 FILE *inf; | |
298 { | |
299 char linebuf[1024]; | |
300 int lineno; | |
301 char *cp, *np; | |
302 | |
303 for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) { | |
304 cp = index(linebuf, '\n'); | |
305 if (!cp) { | |
306 fprintf(stderr, | |
307 "%s line %d: too long or unterminated\n", | |
308 filename, lineno); | |
309 exit(1); | |
310 } | |
311 *cp = '\0'; | |
312 for (cp = linebuf; isspace(*cp); cp++) | |
313 ; | |
314 if (*cp == '\0' || *cp == '#') | |
315 continue; | |
316 for (np = cp; *cp && !isspace(*cp); cp++) | |
317 ; | |
318 if (*cp) | |
319 *cp++ = '\0'; | |
320 while (isspace(*cp)) | |
321 cp++; | |
322 if (*cp == '\0' || *cp == '#') { | |
323 fprintf(stderr, | |
324 "%s line %d: \"%s\" setting without argument\n", | |
325 filename, lineno, np); | |
326 exit(1); | |
327 } | |
328 if (!strcmp(np, "baud-entry")) | |
329 apply_baud_entry(filename, lineno, cp); | |
330 else if (!strcmp(np, "patch8")) | |
331 apply_patch_8bit(filename, lineno, cp); | |
332 else if (!strcmp(np, "patch16")) | |
333 apply_patch_16bit(filename, lineno, cp); | |
334 else if (!strcmp(np, "vid")) | |
335 apply_patch_vid(filename, lineno, cp); | |
336 else if (!strcmp(np, "pid")) | |
337 apply_patch_pid(filename, lineno, cp); | |
338 else if (!strcmp(np, "manuf")) | |
339 set_manuf_string(filename, lineno, cp); | |
340 else if (!strcmp(np, "product")) | |
341 set_product_string(filename, lineno, cp); | |
342 else if (!strcmp(np, "serial")) | |
343 set_serial_string(filename, lineno, cp); | |
344 else { | |
345 fprintf(stderr, "%s line %d: unknown \"%s\" setting\n", | |
346 filename, lineno, np); | |
347 exit(1); | |
348 } | |
349 } | |
350 } | |
351 | |
352 static FILE * | |
353 open_with_search(req_filename) | |
354 char *req_filename; | |
355 { | |
356 char pathbuf[256]; | |
357 FILE *f; | |
358 | |
359 if (!index(req_filename, '/') && strlen(req_filename) < 128) { | |
360 sprintf(pathbuf, "%s/%s", cp2102_install_dir, req_filename); | |
361 f = fopen(pathbuf, "r"); | |
362 if (f) | |
363 return f; | |
364 } | |
365 f = fopen(req_filename, "r"); | |
366 return f; | |
367 } | |
368 | |
369 void | |
370 apply_eeprom_patch_file(filename) | |
371 char *filename; | |
372 { | |
373 FILE *inf; | |
374 | |
375 inf = open_with_search(filename); | |
376 if (!inf) { | |
377 perror(filename); | |
378 exit(1); | |
379 } | |
380 apply_eeprom_patch_int(filename, inf); | |
381 fclose(inf); | |
382 } | |
383 | |
384 void | |
385 apply_eeprom_patch_baud(baud_spec_name) | |
386 char *baud_spec_name; | |
387 { | |
388 char pathbuf[256]; | |
389 FILE *inf; | |
390 | |
391 if (strlen(baud_spec_name) > 63) { | |
392 fprintf(stderr, "error: no buffer overflow attacks, please\n"); | |
393 exit(1); | |
394 } | |
395 sprintf(pathbuf, "%s/baudtab-%s", cp2102_install_dir, baud_spec_name); | |
396 inf = fopen(pathbuf, "r"); | |
397 if (!inf) { | |
398 perror(pathbuf); | |
399 exit(1); | |
400 } | |
401 apply_eeprom_patch_int(pathbuf, inf); | |
402 fclose(inf); | |
403 } |