dfu: allow to manage DFU on several devices
[oweals/u-boot.git] / drivers / dfu / dfu.c
index d2b67b18cf020e4288d71806d94d4b3ecaaa2c0d..8bd5216017a5689f544266b2f85a81f88e6cc2ab 100644 (file)
@@ -53,6 +53,54 @@ static int dfu_find_alt_num(const char *s)
        return ++i;
 }
 
+/*
+ * treat dfu_alt_info with several interface information
+ * to allow DFU on several device with one command,
+ * the string format is
+ * interface devstring'='alternate list (';' separated)
+ * and each interface separated by '&'
+ */
+int dfu_config_interfaces(char *env)
+{
+       struct dfu_entity *dfu;
+       char *s, *i, *d, *a, *part;
+       int ret = -EINVAL;
+       int n = 1;
+
+       s = env;
+       for (; *s; s++) {
+               if (*s == ';')
+                       n++;
+               if (*s == '&')
+                       n++;
+       }
+       ret = dfu_alt_init(n, &dfu);
+       if (ret)
+               return ret;
+
+       s = env;
+       while (s) {
+               ret = -EINVAL;
+               i = strsep(&s, " ");
+               if (!i)
+                       break;
+               d = strsep(&s, "=");
+               if (!d)
+                       break;
+               a = strsep(&s, "&");
+               if (!a)
+                       a = s;
+               do {
+                       part = strsep(&a, ";");
+                       ret = dfu_alt_add(dfu, i, d, part);
+                       if (ret)
+                               return ret;
+               } while (a);
+       }
+
+       return ret;
+}
+
 int dfu_init_env_entities(char *interface, char *devstr)
 {
        const char *str_env;
@@ -69,7 +117,11 @@ int dfu_init_env_entities(char *interface, char *devstr)
        }
 
        env_bkp = strdup(str_env);
-       ret = dfu_config_entities(env_bkp, interface, devstr);
+       if (!interface && !devstr)
+               ret = dfu_config_interfaces(env_bkp);
+       else
+               ret = dfu_config_entities(env_bkp, interface, devstr);
+
        if (ret) {
                pr_err("DFU entities configuration failed!\n");
                pr_err("(partition table does not match dfu_alt_info?)\n");
@@ -83,6 +135,7 @@ done:
 
 static unsigned char *dfu_buf;
 static unsigned long dfu_buf_size;
+static enum dfu_device_type dfu_buf_device_type;
 
 unsigned char *dfu_free_buf(void)
 {
@@ -100,6 +153,10 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu)
 {
        char *s;
 
+       /* manage several entity with several contraint */
+       if (dfu_buf && dfu->dev_type != dfu_buf_device_type)
+               dfu_free_buf();
+
        if (dfu_buf != NULL)
                return dfu_buf;
 
@@ -118,6 +175,7 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu)
                printf("%s: Could not memalign 0x%lx bytes\n",
                       __func__, dfu_buf_size);
 
+       dfu_buf_device_type = dfu->dev_type;
        return dfu_buf;
 }
 
@@ -439,13 +497,12 @@ void dfu_free_entities(void)
        alt_num_cnt = 0;
 }
 
-int dfu_config_entities(char *env, char *interface, char *devstr)
+int dfu_alt_init(int num, struct dfu_entity **dfu)
 {
-       struct dfu_entity *dfu;
-       int i, ret;
        char *s;
+       int ret;
 
-       dfu_alt_num = dfu_find_alt_num(env);
+       dfu_alt_num = num;
        debug("%s: dfu_alt_num=%d\n", __func__, dfu_alt_num);
 
        dfu_hash_algo = NULL;
@@ -456,21 +513,49 @@ int dfu_config_entities(char *env, char *interface, char *devstr)
                        pr_err("Hash algorithm %s not supported\n", s);
        }
 
-       dfu = calloc(sizeof(*dfu), dfu_alt_num);
-       if (!dfu)
+       *dfu = calloc(sizeof(struct dfu_entity), dfu_alt_num);
+       if (!*dfu)
                return -1;
-       for (i = 0; i < dfu_alt_num; i++) {
 
+       return 0;
+}
+
+int dfu_alt_add(struct dfu_entity *dfu, char *interface, char *devstr, char *s)
+{
+       struct dfu_entity *p_dfu;
+       int ret;
+
+       if (alt_num_cnt >= dfu_alt_num)
+               return -1;
+
+       p_dfu = &dfu[alt_num_cnt];
+       ret = dfu_fill_entity(p_dfu, s, alt_num_cnt, interface, devstr);
+       if (ret)
+               return -1;
+
+       list_add_tail(&p_dfu->list, &dfu_list);
+       alt_num_cnt++;
+
+       return 0;
+}
+
+int dfu_config_entities(char *env, char *interface, char *devstr)
+{
+       struct dfu_entity *dfu;
+       int i, ret;
+       char *s;
+
+       ret = dfu_alt_init(dfu_find_alt_num(env), &dfu);
+       if (ret)
+               return -1;
+
+       for (i = 0; i < dfu_alt_num; i++) {
                s = strsep(&env, ";");
-               ret = dfu_fill_entity(&dfu[i], s, alt_num_cnt, interface,
-                                     devstr);
+               ret = dfu_alt_add(dfu, interface, devstr, s);
                if (ret) {
                        /* We will free "dfu" in dfu_free_entities() */
                        return -1;
                }
-
-               list_add_tail(&dfu[i].list, &dfu_list);
-               alt_num_cnt++;
        }
 
        return 0;
@@ -478,14 +563,15 @@ int dfu_config_entities(char *env, char *interface, char *devstr)
 
 const char *dfu_get_dev_type(enum dfu_device_type t)
 {
-       const char *dev_t[] = {NULL, "eMMC", "OneNAND", "NAND", "RAM", "SF" };
+       const char *const dev_t[] = {NULL, "eMMC", "OneNAND", "NAND", "RAM",
+                                    "SF"};
        return dev_t[t];
 }
 
 const char *dfu_get_layout(enum dfu_layout l)
 {
-       const char *dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2",
-                                          "EXT3", "EXT4", "RAM_ADDR" };
+       const char *const dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2",
+                                         "EXT3", "EXT4", "RAM_ADDR" };
        return dfu_layout[l];
 }