Update doxygen config template
[libftdi] / ftdi_eeprom / main.c
1 /***************************************************************************
2                              main.c  -  description
3                            -------------------
4     begin                : Mon Apr  7 12:05:22 CEST 2003
5     copyright            : (C) 2003-2014 by Intra2net AG and the libftdi developers
6     email                : opensource@intra2net.com
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License version 2 as     *
13  *   published by the Free Software Foundation.                            *
14  *                                                                         *
15  ***************************************************************************/
16
17 /*
18  TODO:
19     - Merge Uwe's eeprom tool. Current features:
20         - Init eeprom defaults based upon eeprom type
21         - Read -> Already there
22         - Write -> Already there
23         - Erase -> Already there
24         - Decode on stdout
25         - Ability to find device by PID/VID, product name or serial
26
27  TODO nice-to-have:
28     - Out-of-the-box compatibility with FTDI's eeprom tool configuration files
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38
39 #include <confuse.h>
40 #include <libusb.h>
41 #include <ftdi.h>
42 #include <ftdi_eeprom_version.h>
43
44 static int parse_cbus(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
45 {
46     static const char* options[] =
47     {
48         "TXDEN", "PWREN", "RXLED", "TXLED", "TXRXLED", "SLEEP", "CLK48",
49         "CLK24", "CLK12", "CLK6", "IOMODE", "BB_WR", "BB_RD"
50     };
51
52     int i;
53     for (i=0; i<sizeof(options)/sizeof(*options); i++)
54     {
55         if (!(strcmp(options[i], value)))
56         {
57             *(int *)result = i;
58             return 0;
59         }
60     }
61
62     cfg_error(cfg, "Invalid %s option '%s'", cfg_opt_name(opt), value);
63     return -1;
64 }
65
66 static int parse_cbush(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
67 {
68     static const char* options[] =
69     {
70         "TRISTATE", "TXLED", "RXLED", "TXRXLED", "PWREN", "SLEEP",
71         "DRIVE_0", "DRIVE1", "IOMODE", "TXDEN", "CLK30", "CLK15", "CLK7_5"
72     };
73
74     int i;
75     for (i=0; i<sizeof(options)/sizeof(*options); i++)
76     {
77         if (!(strcmp(options[i], value)))
78         {
79             *(int *)result = i;
80             return 0;
81         }
82     }
83
84     cfg_error(cfg, "Invalid %s option '%s'", cfg_opt_name(opt), value);
85     return -1;
86 }
87
88 static int parse_cbusx(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
89 {
90     static const char* options[] =
91     {
92         "TRISTATE", "TXLED", "RXLED", "TXRXLED", "PWREN", "SLEEP",
93         "DRIVE_0", "DRIVE1", "IOMODE", "TXDEN", "CLK24", "CLK12",
94         "CLK6", "BAT_DETECT", "BAT_DETECT_NEG", "I2C_TXE", "I2C_RXF", "VBUS_SENSE",
95         "BB_WR", "BB_RD", "TIME_STAMP", "AWAKE"
96     };
97
98     int i;
99     for (i=0; i<sizeof(options)/sizeof(*options); i++)
100     {
101         if (!(strcmp(options[i], value)))
102         {
103             *(int *)result = i;
104             return 0;
105         }
106     }
107
108     cfg_error(cfg, "Invalid %s option '%s'", cfg_opt_name(opt), value);
109     return -1;
110 }
111
112 /**
113  * @brief Set eeprom value
114  *
115  * \param ftdi pointer to ftdi_context
116  * \param value_name Enum of the value to set
117  * \param value Value to set
118  *
119  * Function will abort the program on error
120  **/
121 static void eeprom_set_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int value)
122 {
123     if (ftdi_set_eeprom_value(ftdi, value_name, value) < 0)
124     {
125         printf("Unable to set eeprom value %d: %s. Aborting\n", value_name, ftdi_get_error_string(ftdi));
126         exit (-1);
127     }
128 }
129
130 /**
131  * @brief Get eeprom value
132  *
133  * \param ftdi pointer to ftdi_context
134  * \param value_name Enum of the value to get
135  * \param value Value to get
136  *
137  * Function will abort the program on error
138  **/
139 static void eeprom_get_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int *value)
140 {
141     if (ftdi_get_eeprom_value(ftdi, value_name, value) < 0)
142     {
143         printf("Unable to get eeprom value %d: %s. Aborting\n", value_name, ftdi_get_error_string(ftdi));
144         exit (-1);
145     }
146 }
147
148 static void usage(const char *program)
149 {
150     fprintf(stderr, "Syntax: %s [...options...] <config-file>\n", program);
151     fprintf(stderr, "Valid Options:\n");
152     fprintf(stderr, "--device <description>  Specify device to open by description string. One of:\n");
153     fprintf(stderr, "         d:<devicenode>\n");
154     fprintf(stderr, "         i:<vendor>:<product>\n");
155     fprintf(stderr, "         i:<vendor>:<product>:<index>\n");
156     fprintf(stderr, "         s:<vendor>:<product>:<serial>\n");
157     fprintf(stderr, "--read-eeprom           Read eeprom and write to -filename- from config-file\n");
158     fprintf(stderr, "--erase-eeprom          Erase eeprom\n");
159     fprintf(stderr, "--flash-eeprom          Flash eeprom\n");
160 }
161
162 int main(int argc, char *argv[])
163 {
164     /*
165     configuration options
166     */
167     cfg_opt_t opts[] =
168     {
169         CFG_INT("vendor_id", 0, 0),
170         CFG_INT("product_id", 0, 0),
171         CFG_BOOL("self_powered", cfg_true, 0),
172         CFG_BOOL("remote_wakeup", cfg_true, 0),
173         CFG_BOOL("in_is_isochronous", cfg_false, 0),
174         CFG_BOOL("out_is_isochronous", cfg_false, 0),
175         CFG_BOOL("suspend_pull_downs", cfg_false, 0),
176         CFG_BOOL("use_serial", cfg_false, 0),
177         CFG_BOOL("change_usb_version", cfg_false, 0),
178         CFG_INT("usb_version", 0, 0),
179         CFG_INT("default_pid", 0x6001, 0),
180         CFG_INT("max_power", 0, 0),
181         CFG_STR("manufacturer", "Acme Inc.", 0),
182         CFG_STR("product", "USB Serial Converter", 0),
183         CFG_STR("serial", "08-15", 0),
184         CFG_INT("eeprom_type", 0x00, 0),
185         CFG_STR("filename", "", 0),
186         CFG_BOOL("flash_raw", cfg_false, 0),
187         CFG_BOOL("high_current", cfg_false, 0),
188         CFG_INT_CB("cbus0", -1, 0, parse_cbus),
189         CFG_INT_CB("cbus1", -1, 0, parse_cbus),
190         CFG_INT_CB("cbus2", -1, 0, parse_cbus),
191         CFG_INT_CB("cbus3", -1, 0, parse_cbus),
192         CFG_INT_CB("cbus4", -1, 0, parse_cbus),
193         CFG_INT_CB("cbush0", -1, 0, parse_cbush),
194         CFG_INT_CB("cbush1", -1, 0, parse_cbush),
195         CFG_INT_CB("cbush2", -1, 0, parse_cbush),
196         CFG_INT_CB("cbush3", -1, 0, parse_cbush),
197         CFG_INT_CB("cbush4", -1, 0, parse_cbush),
198         CFG_INT_CB("cbush5", -1, 0, parse_cbush),
199         CFG_INT_CB("cbush6", -1, 0, parse_cbush),
200         CFG_INT_CB("cbush7", -1, 0, parse_cbush),
201         CFG_INT_CB("cbush8", -1, 0, parse_cbush),
202         CFG_INT_CB("cbush9", -1, 0, parse_cbush),
203         CFG_INT_CB("cbusx0", -1, 0, parse_cbusx),
204         CFG_INT_CB("cbusx1", -1, 0, parse_cbusx),
205         CFG_INT_CB("cbusx2", -1, 0, parse_cbusx),
206         CFG_INT_CB("cbusx3", -1, 0, parse_cbusx),
207         CFG_BOOL("invert_txd", cfg_false, 0),
208         CFG_BOOL("invert_rxd", cfg_false, 0),
209         CFG_BOOL("invert_rts", cfg_false, 0),
210         CFG_BOOL("invert_cts", cfg_false, 0),
211         CFG_BOOL("invert_dtr", cfg_false, 0),
212         CFG_BOOL("invert_dsr", cfg_false, 0),
213         CFG_BOOL("invert_dcd", cfg_false, 0),
214         CFG_BOOL("invert_ri", cfg_false, 0),
215         CFG_END()
216     };
217     cfg_t *cfg;
218
219     /*
220     normal variables
221     */
222     enum {
223         COMMAND_READ = 1,
224         COMMAND_ERASE,
225         COMMAND_FLASH
226     } command = 0;
227     const char *cfg_filename = NULL;
228     const char *device_description = NULL;
229
230     const int max_eeprom_size = 256;
231     int my_eeprom_size = 0;
232     unsigned char *eeprom_buf = NULL;
233     char *filename;
234     int size_check;
235     int i;
236     FILE *fp;
237
238     struct ftdi_context *ftdi = NULL;
239
240     printf("\nFTDI eeprom generator v%s\n", EEPROM_VERSION_STRING);
241     printf ("(c) Intra2net AG and the libftdi developers <opensource@intra2net.com>\n");
242
243     for (i = 1; i < argc; i++) {
244         if (*argv[i] != '-')
245         {
246             cfg_filename = argv[i];
247         }
248         else if (!strcmp(argv[i], "--device"))
249         {
250             if (i+1 >= argc)
251             {
252                 usage(argv[0]);
253                 exit(-1);
254             }
255             device_description = argv[++i];
256         }
257         else if (!strcmp(argv[i], "--read-eeprom"))
258         {
259             command = COMMAND_READ;
260         }
261         else if (!strcmp(argv[i], "--erase-eeprom"))
262         {
263             command = COMMAND_ERASE;
264         }
265         else if (!strcmp(argv[i], "--flash-eeprom"))
266         {
267             command = COMMAND_FLASH;
268         }
269         else
270         {
271             usage(argv[0]);
272             exit(-1);
273         }
274     }
275
276     if (!cfg_filename)
277     {
278         usage(argv[0]);
279         exit(-1);
280     }
281
282     if ((fp = fopen(cfg_filename, "r")) == NULL)
283     {
284         printf ("Can't open configuration file\n");
285         exit (-1);
286     }
287     fclose (fp);
288
289     cfg = cfg_init(opts, 0);
290     cfg_parse(cfg, cfg_filename);
291     filename = cfg_getstr(cfg, "filename");
292
293     if (cfg_getbool(cfg, "self_powered") && cfg_getint(cfg, "max_power") > 0)
294         printf("Hint: Self powered devices should have a max_power setting of 0.\n");
295
296     if ((ftdi = ftdi_new()) == 0)
297     {
298         fprintf(stderr, "Failed to allocate ftdi structure :%s \n",
299                 ftdi_get_error_string(ftdi));
300         return EXIT_FAILURE;
301     }
302
303     if (device_description != NULL)
304     {
305         i = ftdi_usb_open_string(ftdi, device_description);
306
307         if (i != 0)
308         {
309             printf("Unable to find FTDI device with description: %s\n",
310                    device_description);
311             printf("Error code: %d (%s)\n", i, ftdi_get_error_string(ftdi));
312             exit (-1);
313         }
314     }
315     else if (command > 0)
316     {
317         int vendor_id = cfg_getint(cfg, "vendor_id");
318         int product_id = cfg_getint(cfg, "product_id");
319
320         i = ftdi_usb_open(ftdi, vendor_id, product_id);
321
322         if (i != 0)
323         {
324             int default_pid = cfg_getint(cfg, "default_pid");
325             printf("Unable to find FTDI devices under given vendor/product id: 0x%X/0x%X\n", vendor_id, product_id);
326             printf("Error code: %d (%s)\n", i, ftdi_get_error_string(ftdi));
327             printf("Retrying with default FTDI pid=%#04x.\n", default_pid);
328
329             i = ftdi_usb_open(ftdi, 0x0403, default_pid);
330             if (i != 0)
331             {
332                 printf("Error: %s\n", ftdi->error_str);
333                 exit (-1);
334             }
335         }
336     }
337     ftdi_eeprom_initdefaults (ftdi, cfg_getstr(cfg, "manufacturer"),
338                               cfg_getstr(cfg, "product"),
339                               cfg_getstr(cfg, "serial"));
340
341     printf("FTDI read eeprom: %d\n", ftdi_read_eeprom(ftdi));
342     eeprom_get_value(ftdi, CHIP_SIZE, &my_eeprom_size);
343     printf("EEPROM size: %d\n", my_eeprom_size);
344
345     if (command == COMMAND_READ)
346     {
347         ftdi_eeprom_decode(ftdi, 0 /* debug: 1 */);
348
349         eeprom_buf = malloc(my_eeprom_size);
350         ftdi_get_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size);
351
352         if (eeprom_buf == NULL)
353         {
354             fprintf(stderr, "Malloc failed, aborting\n");
355             goto cleanup;
356         }
357         if (filename != NULL && strlen(filename) > 0)
358         {
359
360             FILE *fp = fopen (filename, "wb");
361             fwrite (eeprom_buf, 1, my_eeprom_size, fp);
362             fclose (fp);
363         }
364         else
365         {
366             printf("Warning: Not writing eeprom, you must supply a valid filename\n");
367         }
368
369         goto cleanup;
370     }
371
372     eeprom_set_value(ftdi, VENDOR_ID, cfg_getint(cfg, "vendor_id"));
373     eeprom_set_value(ftdi, PRODUCT_ID, cfg_getint(cfg, "product_id"));
374
375     eeprom_set_value(ftdi, SELF_POWERED, cfg_getbool(cfg, "self_powered"));
376     eeprom_set_value(ftdi, REMOTE_WAKEUP, cfg_getbool(cfg, "remote_wakeup"));
377     eeprom_set_value(ftdi, MAX_POWER, cfg_getint(cfg, "max_power"));
378
379     eeprom_set_value(ftdi, IN_IS_ISOCHRONOUS, cfg_getbool(cfg, "in_is_isochronous"));
380     eeprom_set_value(ftdi, OUT_IS_ISOCHRONOUS, cfg_getbool(cfg, "out_is_isochronous"));
381     eeprom_set_value(ftdi, SUSPEND_PULL_DOWNS, cfg_getbool(cfg, "suspend_pull_downs"));
382
383     eeprom_set_value(ftdi, USE_SERIAL, cfg_getbool(cfg, "use_serial"));
384     eeprom_set_value(ftdi, USE_USB_VERSION, cfg_getbool(cfg, "change_usb_version"));
385     eeprom_set_value(ftdi, USB_VERSION, cfg_getint(cfg, "usb_version"));
386     eeprom_set_value(ftdi, CHIP_TYPE, cfg_getint(cfg, "eeprom_type"));
387
388     eeprom_set_value(ftdi, HIGH_CURRENT, cfg_getbool(cfg, "high_current"));
389
390     if (ftdi->type == TYPE_R)
391     {
392         if (cfg_getint(cfg, "cbus0") != -1)
393             eeprom_set_value(ftdi, CBUS_FUNCTION_0, cfg_getint(cfg, "cbus0"));
394         if (cfg_getint(cfg, "cbus1") != -1)
395             eeprom_set_value(ftdi, CBUS_FUNCTION_1, cfg_getint(cfg, "cbus1"));
396         if (cfg_getint(cfg, "cbus2") != -1)
397             eeprom_set_value(ftdi, CBUS_FUNCTION_2, cfg_getint(cfg, "cbus2"));
398         if (cfg_getint(cfg, "cbus3") != -1)
399             eeprom_set_value(ftdi, CBUS_FUNCTION_3, cfg_getint(cfg, "cbus3"));
400         if (cfg_getint(cfg, "cbus4") != -1)
401             eeprom_set_value(ftdi, CBUS_FUNCTION_4, cfg_getint(cfg, "cbus4"));
402     }
403     else if (ftdi->type == TYPE_232H)
404     {
405         if (cfg_getint(cfg, "cbush0") != -1)
406             eeprom_set_value(ftdi, CBUS_FUNCTION_0, cfg_getint(cfg, "cbush0"));
407         if (cfg_getint(cfg, "cbush1") != -1)
408             eeprom_set_value(ftdi, CBUS_FUNCTION_1, cfg_getint(cfg, "cbush1"));
409         if (cfg_getint(cfg, "cbush2") != -1)
410             eeprom_set_value(ftdi, CBUS_FUNCTION_2, cfg_getint(cfg, "cbush2"));
411         if (cfg_getint(cfg, "cbush3") != -1)
412             eeprom_set_value(ftdi, CBUS_FUNCTION_3, cfg_getint(cfg, "cbush3"));
413         if (cfg_getint(cfg, "cbush4") != -1)
414             eeprom_set_value(ftdi, CBUS_FUNCTION_4, cfg_getint(cfg, "cbush4"));
415         if (cfg_getint(cfg, "cbush5") != -1)
416             eeprom_set_value(ftdi, CBUS_FUNCTION_5, cfg_getint(cfg, "cbush5"));
417         if (cfg_getint(cfg, "cbush6") != -1)
418             eeprom_set_value(ftdi, CBUS_FUNCTION_6, cfg_getint(cfg, "cbush6"));
419         if (cfg_getint(cfg, "cbush7") != -1)
420             eeprom_set_value(ftdi, CBUS_FUNCTION_7, cfg_getint(cfg, "cbush7"));
421         if (cfg_getint(cfg, "cbush8") != -1)
422             eeprom_set_value(ftdi, CBUS_FUNCTION_8, cfg_getint(cfg, "cbush8"));
423         if (cfg_getint(cfg, "cbush9") != -1)
424             eeprom_set_value(ftdi, CBUS_FUNCTION_9, cfg_getint(cfg, "cbush9"));
425     }
426     else if (ftdi->type == TYPE_230X)
427     {
428         if (cfg_getint(cfg, "cbusx0") != -1)
429             eeprom_set_value(ftdi, CBUS_FUNCTION_0, cfg_getint(cfg, "cbusx0"));
430         if (cfg_getint(cfg, "cbusx1") != -1)
431             eeprom_set_value(ftdi, CBUS_FUNCTION_1, cfg_getint(cfg, "cbusx1"));
432         if (cfg_getint(cfg, "cbusx2") != -1)
433             eeprom_set_value(ftdi, CBUS_FUNCTION_2, cfg_getint(cfg, "cbusx2"));
434         if (cfg_getint(cfg, "cbusx3") != -1)
435             eeprom_set_value(ftdi, CBUS_FUNCTION_3, cfg_getint(cfg, "cbusx3"));
436     }
437
438     int invert = 0;
439     if (cfg_getbool(cfg, "invert_rxd")) invert |= INVERT_RXD;
440     if (cfg_getbool(cfg, "invert_txd")) invert |= INVERT_TXD;
441     if (cfg_getbool(cfg, "invert_rts")) invert |= INVERT_RTS;
442     if (cfg_getbool(cfg, "invert_cts")) invert |= INVERT_CTS;
443     if (cfg_getbool(cfg, "invert_dtr")) invert |= INVERT_DTR;
444     if (cfg_getbool(cfg, "invert_dsr")) invert |= INVERT_DSR;
445     if (cfg_getbool(cfg, "invert_dcd")) invert |= INVERT_DCD;
446     if (cfg_getbool(cfg, "invert_ri")) invert |= INVERT_RI;
447     eeprom_set_value(ftdi, INVERT, invert);
448
449     eeprom_set_value(ftdi, CHANNEL_A_DRIVER, DRIVER_VCP);
450     eeprom_set_value(ftdi, CHANNEL_B_DRIVER, DRIVER_VCP);
451     eeprom_set_value(ftdi, CHANNEL_C_DRIVER, DRIVER_VCP);
452     eeprom_set_value(ftdi, CHANNEL_D_DRIVER, DRIVER_VCP);
453     eeprom_set_value(ftdi, CHANNEL_A_RS485, 0);
454     eeprom_set_value(ftdi, CHANNEL_B_RS485, 0);
455     eeprom_set_value(ftdi, CHANNEL_C_RS485, 0);
456     eeprom_set_value(ftdi, CHANNEL_D_RS485, 0);
457
458     if (command == COMMAND_ERASE)
459     {
460         printf("FTDI erase eeprom: %d\n", ftdi_erase_eeprom(ftdi));
461     }
462
463     size_check = ftdi_eeprom_build(ftdi);
464     eeprom_get_value(ftdi, CHIP_SIZE, &my_eeprom_size);
465
466     if (size_check == -1)
467     {
468         printf ("Sorry, the eeprom can only contain 128 bytes.\n");
469         goto cleanup;
470     }
471     else if (size_check < 0)
472     {
473         printf ("ftdi_eeprom_build(): error: %d\n", size_check);
474         goto cleanup;
475     }
476     else
477     {
478         printf ("Used eeprom space: %d bytes\n", my_eeprom_size-size_check);
479     }
480
481     if (command == COMMAND_FLASH)
482     {
483         if (cfg_getbool(cfg, "flash_raw"))
484         {
485             if (filename != NULL && strlen(filename) > 0)
486             {
487                 eeprom_buf = malloc(max_eeprom_size);
488                 FILE *fp = fopen(filename, "rb");
489                 if (fp == NULL)
490                 {
491                     printf ("Can't open eeprom file %s.\n", filename);
492                     exit (-1);
493                 }
494                 my_eeprom_size = fread(eeprom_buf, 1, max_eeprom_size, fp);
495                 fclose(fp);
496                 if (my_eeprom_size < 128)
497                 {
498                     printf ("Can't read eeprom file %s.\n", filename);
499                     exit (-1);
500                 }
501
502                 ftdi_set_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size);
503             }
504         }
505         printf ("FTDI write eeprom: %d\n", ftdi_write_eeprom(ftdi));
506         libusb_reset_device(ftdi->usb_dev);
507     }
508
509     // Write to file?
510     if (filename != NULL && strlen(filename) > 0 && !cfg_getbool(cfg, "flash_raw"))
511     {
512         fp = fopen(filename, "w");
513         if (fp == NULL)
514         {
515             printf ("Can't write eeprom file.\n");
516             exit (-1);
517         }
518         else
519             printf ("Writing to file: %s\n", filename);
520
521         if (eeprom_buf == NULL)
522             eeprom_buf = malloc(my_eeprom_size);
523         ftdi_get_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size);
524
525         fwrite(eeprom_buf, my_eeprom_size, 1, fp);
526         fclose(fp);
527     }
528
529 cleanup:
530     if (eeprom_buf)
531         free(eeprom_buf);
532     if (command > 0)
533     {
534         printf("FTDI close: %d\n", ftdi_usb_close(ftdi));
535     }
536
537     ftdi_deinit (ftdi);
538     ftdi_free (ftdi);
539
540     cfg_free(cfg);
541
542     printf("\n");
543     return 0;
544 }