CMake: bump the minimal required version to 3.5
[libftdi] / ftdi_eeprom / main.c
index edcfad7..e3a09ba 100644 (file)
@@ -2,8 +2,9 @@
                              main.c  -  description
                            -------------------
     begin                : Mon Apr  7 12:05:22 CEST 2003
-    copyright            : (C) 2003-2014 by Intra2net AG and the libftdi developers
+    copyright            : (C) 2003-2020 by Intra2net AG and the libftdi developers
     email                : opensource@intra2net.com
+    SPDX-License-Identifier: GPL-2.0-only
  ***************************************************************************/
 
 /***************************************************************************
@@ -35,6 +36,8 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
 
 #include <confuse.h>
 #include <libusb.h>
@@ -63,6 +66,27 @@ static int parse_cbus(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *resul
     return -1;
 }
 
+static int parse_group0_drive(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
+{
+    static const char* options[] =
+    {
+        "4MA", "8MA", "12MA", "16MA"
+    };
+
+    int i;
+    for (i=0; i<sizeof(options)/sizeof(*options); i++)
+    {
+        if (!(strcasecmp(options[i], value)))
+        {
+            *(int *)result = i;
+            return 0;
+        }
+    }
+
+    cfg_error(cfg, "Invalid %s option '%s'", cfg_opt_name(opt), value);
+    return -1;
+}
+
 static int parse_cbush(cfg_t *cfg, cfg_opt_t *opt, const char *value, void *result)
 {
     static const char* options[] =
@@ -179,13 +203,15 @@ static void usage(const char *program)
     fprintf(stderr, "Syntax: %s [...options...] <config-file>\n", program);
     fprintf(stderr, "Valid Options:\n");
     fprintf(stderr, "--device <description>  Specify device to open by description string. One of:\n");
-    fprintf(stderr, "         d:<devicenode>\n");
+    fprintf(stderr, "         d:<device node>\n");
     fprintf(stderr, "         i:<vendor>:<product>\n");
     fprintf(stderr, "         i:<vendor>:<product>:<index>\n");
     fprintf(stderr, "         s:<vendor>:<product>:<serial>\n");
     fprintf(stderr, "--read-eeprom           Read eeprom and write to -filename- from config-file\n");
+    fprintf(stderr, "--build-eeprom          Build eeprom image\n");
     fprintf(stderr, "--erase-eeprom          Erase eeprom\n");
     fprintf(stderr, "--flash-eeprom          Flash eeprom\n");
+    fprintf(stderr, "--verbose               Print more information\n");
 }
 
 int main(int argc, char *argv[])
@@ -197,6 +223,7 @@ int main(int argc, char *argv[])
     {
         CFG_INT("vendor_id", 0, 0),
         CFG_INT("product_id", 0, 0),
+        CFG_INT("release_number", -1, 0),
         CFG_BOOL("self_powered", cfg_true, 0),
         CFG_BOOL("remote_wakeup", cfg_true, 0),
         CFG_BOOL("in_is_isochronous", cfg_false, 0),
@@ -233,6 +260,7 @@ int main(int argc, char *argv[])
         CFG_INT_CB("cbusx1", -1, 0, parse_cbusx),
         CFG_INT_CB("cbusx2", -1, 0, parse_cbusx),
         CFG_INT_CB("cbusx3", -1, 0, parse_cbusx),
+        CFG_INT_CB("group0_drive", -1, 0, parse_group0_drive),
         CFG_BOOL("invert_txd", cfg_false, 0),
         CFG_BOOL("invert_rxd", cfg_false, 0),
         CFG_BOOL("invert_rts", cfg_false, 0),
@@ -251,6 +279,9 @@ int main(int argc, char *argv[])
         CFG_BOOL("chb_rs485", cfg_false, 0),
         CFG_BOOL("chc_rs485", cfg_false, 0),
         CFG_BOOL("chd_rs485", cfg_false, 0),
+        CFG_FUNC("include", &cfg_include),
+        CFG_INT("user_data_addr", 0x18, 0),
+        CFG_STR("user_data_file", "", 0),
         CFG_END()
     };
     cfg_t *cfg;
@@ -261,10 +292,13 @@ int main(int argc, char *argv[])
     enum {
         COMMAND_READ = 1,
         COMMAND_ERASE,
-        COMMAND_FLASH
+        COMMAND_FLASH,
+        COMMAND_BUILD
     } command = 0;
     const char *cfg_filename = NULL;
     const char *device_description = NULL;
+    const char *user_data_file = NULL;
+    char *user_data_buffer = NULL;
 
     const int max_eeprom_size = 256;
     int my_eeprom_size = 0;
@@ -274,6 +308,8 @@ int main(int argc, char *argv[])
     int i;
     FILE *fp;
 
+    int verbose=0;
+
     struct ftdi_context *ftdi = NULL;
 
     printf("\nFTDI eeprom generator v%s\n", EEPROM_VERSION_STRING);
@@ -305,6 +341,14 @@ int main(int argc, char *argv[])
         {
             command = COMMAND_FLASH;
         }
+        else if (!strcmp(argv[i], "--build-eeprom"))
+        {
+            command = COMMAND_BUILD;
+        }
+        else if (!strcmp(argv[i], "--verbose"))
+        {
+            verbose = 1;
+        }
         else
         {
             usage(argv[0]);
@@ -383,7 +427,7 @@ int main(int argc, char *argv[])
 
     if (command == COMMAND_READ)
     {
-        ftdi_eeprom_decode(ftdi, 0 /* debug: 1 */);
+        ftdi_eeprom_decode(ftdi, verbose);
 
         eeprom_buf = malloc(my_eeprom_size);
         ftdi_get_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size);
@@ -395,10 +439,15 @@ int main(int argc, char *argv[])
         }
         if (filename != NULL && strlen(filename) > 0)
         {
-
             FILE *fp = fopen (filename, "wb");
-            fwrite (eeprom_buf, 1, my_eeprom_size, fp);
-            fclose (fp);
+            
+            if(fp)
+            {
+                fwrite(eeprom_buf, 1, my_eeprom_size, fp);
+                fclose(fp);
+            }
+            else
+                fprintf(stderr, "Could not open output file %s: %s\n", filename, strerror(errno));
         }
         else
         {
@@ -411,6 +460,10 @@ int main(int argc, char *argv[])
     eeprom_set_value(ftdi, VENDOR_ID, cfg_getint(cfg, "vendor_id"));
     eeprom_set_value(ftdi, PRODUCT_ID, cfg_getint(cfg, "product_id"));
 
+    if (cfg_getint(cfg, "release_number") != -1) {
+        eeprom_set_value(ftdi, RELEASE_NUMBER, cfg_getint(cfg, "release_number"));
+    }
+
     eeprom_set_value(ftdi, SELF_POWERED, cfg_getbool(cfg, "self_powered"));
     eeprom_set_value(ftdi, REMOTE_WAKEUP, cfg_getbool(cfg, "remote_wakeup"));
     eeprom_set_value(ftdi, MAX_POWER, cfg_getint(cfg, "max_power"));
@@ -461,6 +514,8 @@ int main(int argc, char *argv[])
             eeprom_set_value(ftdi, CBUS_FUNCTION_8, cfg_getint(cfg, "cbush8"));
         if (cfg_getint(cfg, "cbush9") != -1)
             eeprom_set_value(ftdi, CBUS_FUNCTION_9, cfg_getint(cfg, "cbush9"));
+        if (cfg_getint(cfg, "group0_drive") != -1)
+            eeprom_set_value(ftdi, GROUP0_DRIVE, cfg_getint(cfg, "group0_drive"));
     }
     else if (ftdi->type == TYPE_230X)
     {
@@ -504,6 +559,51 @@ int main(int argc, char *argv[])
     eeprom_set_value(ftdi, CHANNEL_C_RS485, cfg_getbool(cfg, "chc_rs485"));
     eeprom_set_value(ftdi, CHANNEL_D_RS485, cfg_getbool(cfg, "chd_rs485"));
 
+    /* Arbitrary user data */
+    eeprom_set_value(ftdi, USER_DATA_ADDR, cfg_getint(cfg, "user_data_addr"));
+    user_data_file = cfg_getstr(cfg, "user_data_file");
+    if (user_data_file && strlen(user_data_file) > 0)
+    {
+        int data_size;
+        struct stat st;
+
+        printf("User data file: %s\n", user_data_file);
+        /* Allocate a buffer for the user data */
+        user_data_buffer = (char *)malloc(max_eeprom_size);
+        if (user_data_buffer == NULL)
+        {
+            fprintf(stderr, "Malloc failed, aborting\n");
+            goto cleanup;
+        }
+
+        if (stat(user_data_file, &st))
+        {
+            printf ("Can't stat user data file %s.\n", user_data_file);
+            exit (-1);
+        }
+        if (st.st_size > max_eeprom_size)
+            printf("Warning: %s is too big, only reading %d bytes\n",
+                   user_data_file, max_eeprom_size);
+        /* Read the user data file, no more than max_eeprom_size bytes */
+        FILE *fp = fopen(user_data_file, "rb");
+        if (fp == NULL)
+        {
+            printf ("Can't open user data file %s.\n", user_data_file);
+            exit (-1);
+        }
+        data_size = fread(user_data_buffer, 1, max_eeprom_size, fp);
+        fclose(fp);
+        if (data_size < 1)
+        {
+            printf ("Can't read user data file %s.\n", user_data_file);
+            exit (-1);
+        }
+        printf("User data size: %d\n", data_size);
+
+        ftdi_set_eeprom_user_data(ftdi, user_data_buffer, data_size);
+    }
+
+
     if (command == COMMAND_ERASE)
     {
         printf("FTDI erase eeprom: %d\n", ftdi_erase_eeprom(ftdi));
@@ -514,7 +614,7 @@ int main(int argc, char *argv[])
 
     if (size_check == -1)
     {
-        printf ("Sorry, the eeprom can only contain 128 bytes.\n");
+        printf ("Sorry, the eeprom can only contain %d bytes.\n", my_eeprom_size);
         goto cleanup;
     }
     else if (size_check < 0)
@@ -548,7 +648,15 @@ int main(int argc, char *argv[])
                     exit (-1);
                 }
 
+                printf("Flashing raw eeprom from file %s (%d bytes)\n",
+                       filename, my_eeprom_size);
+
                 ftdi_set_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size);
+            } else
+            {
+                printf ("ERROR: flash_raw mode enabled, but no eeprom filename "
+                        "given in config file.\n");
+                exit (-1);
             }
         }
         printf ("FTDI write eeprom: %d\n", ftdi_write_eeprom(ftdi));
@@ -578,6 +686,8 @@ int main(int argc, char *argv[])
 cleanup:
     if (eeprom_buf)
         free(eeprom_buf);
+    if (user_data_buffer)
+        free(user_data_buffer);
     if (command > 0)
     {
         printf("FTDI close: %d\n", ftdi_usb_close(ftdi));