Rework reconfiguration configfs gadget 13/228113/4
authorINSUN PYO <insun.pyo@samsung.com>
Thu, 19 Mar 2020 06:39:35 +0000 (15:39 +0900)
committerINSUN PYO <insun.pyo@samsung.com>
Thu, 19 Mar 2020 07:16:48 +0000 (16:16 +0900)
Before : add new functions -> enable new functions as linking to configs -> delete unused configs -> deleted unused functions
After : remove all configs -> remove all functions -> add new functions -> enable new functions as linking to configs

Change-Id: If0fdcb9a1cda9afcb6d865bee7f0db1539d4df2b

hw/usb_cfs_client_common.c

index 846eb77..577e508 100644 (file)
@@ -36,7 +36,7 @@
 #define NAME_INSTANCE_SEP '.'
 #define MAX_INSTANCE_LEN 512
 
-#define USB_FUNCS_PATH "/dev/usb-funcs/"
+#define USB_FUNCS_PATH "/dev/usb-funcs"
 
 #ifndef EXPORT
 #define EXPORT __attribute__ ((visibility("default")))
@@ -216,64 +216,72 @@ static int cfs_ensure_dir(char *path)
        return ret;
 }
 
-static int cfs_prep_ffs_service(const char *name, const char *instance,
-                               const char *dev_name, const char *socket_name)
+
+static int cfs_prep_ffs_service(struct usb_function *usb_func, usbg_function *function)
 {
-       char buf[PATH_MAX];
-       size_t left;
-       char *pos;
        int ret;
+       const char *name;
+       const char *service;
+       const char *instance;
+       const char *dev_name;
+       char buf[MAX_INSTANCE_LEN];
 
-       /* TODO: Add some good error handling */
-       if (!socket_name)
+       if (!usb_func || !function)
                return -EINVAL;
 
-       left = sizeof(buf);
-       pos = buf;
-       ret = snprintf(pos, left, "%s", USB_FUNCS_PATH);
-       if (ret < 0 || ret >= left) {
+       if (usbg_get_function_type(function) != USBG_F_FFS)
+               return -EINVAL;
+
+       name = usb_func->name;
+       service = usb_func->service;
+       instance = usb_func->instance;
+       dev_name = usbg_get_function_instance(function);
+
+       /* "/dev/usb-funcs" + "/" + "sdb" + "/" + "default"  + '0' */
+       if (strlen(USB_FUNCS_PATH) + strlen(name) + strlen(instance) + 3  > sizeof(buf))
                return -ENAMETOOLONG;
-       } else {
-               left -= ret;
-               pos += ret;
-       }
-       ret = cfs_ensure_dir(buf);
+
+       /* mkdir /dev/usb-funcs */
+       ret = cfs_ensure_dir(USB_FUNCS_PATH);
        if (ret < 0)
                return ret;
 
-       ret = snprintf(pos, left, "/%s", name);
-       if (ret < 0 || ret >= left) {
-               return -ENAMETOOLONG;
-       } else {
-               left -= ret;
-               pos += ret;
-       }
+       /* mkdir /dev/usb-funcs/sdb */
+       snprintf(buf, sizeof(buf), "%s/%s", USB_FUNCS_PATH, name);
        ret = cfs_ensure_dir(buf);
        if (ret < 0)
-               return ret;
+               goto out_rmdir;
 
-       ret = snprintf(pos, left, "/%s", instance);
-       if (ret < 0 || ret >= left) {
-               return -ENAMETOOLONG;
-       } else {
-               left -= ret;
-               pos += ret;
-       }
+       /* mkdir /dev/usb-funcs/sdb/default */
+       snprintf(buf, sizeof(buf), "%s/%s/%s", USB_FUNCS_PATH, name, instance);
        ret = cfs_ensure_dir(buf);
        if (ret < 0)
-               return ret;
+               goto out_rmdir;
 
+       /* mount -t functionfs sdb.default /dev/usb-funcs/sdb/default */
        ret = mount(dev_name, buf, "functionfs", 0, NULL);
        if (ret < 0)
-               return ret;
+               goto out_rmdir;
 
-       ret = systemd_start_unit_wait_started(socket_name, ".socket", -1);
+       /* start sdbd.socket */
+       ret = systemd_start_unit_wait_started(service, ".socket", -1);
        if (ret < 0)
-               goto umount_ffs;
+               goto out_unmount;
 
        return 0;
-umount_ffs:
+
+out_unmount:
        umount(buf);
+
+out_rmdir:
+       snprintf(buf, sizeof(buf), "%s/%s/%s", USB_FUNCS_PATH, name, instance);
+       rmdir(buf);
+
+       snprintf(buf, sizeof(buf), "%s/%s", USB_FUNCS_PATH, name);
+       rmdir(buf);
+
+       rmdir(USB_FUNCS_PATH);
+
        return ret;
 }
 
@@ -305,7 +313,7 @@ static int cfs_cleanup_ffs_service(usbg_function *function)
        }
 
        /* umount /dev/usb-funcs/[sdb|mtp]/default and remove it's directory */
-       ret = snprintf(buf, sizeof(buf), "%s%s/%s", USB_FUNCS_PATH, usb_function->name, usb_function->instance);
+       ret = snprintf(buf, sizeof(buf), "%s/%s/%s", USB_FUNCS_PATH, usb_function->name, usb_function->instance);
        if (ret < 0)
                return ret;
 
@@ -318,7 +326,7 @@ static int cfs_cleanup_ffs_service(usbg_function *function)
                return ret;
 
        /* remove /dev/usb-funcs/[sdb|mtp] directory */
-       ret = snprintf(buf, sizeof(buf), "%s%s", USB_FUNCS_PATH, usb_function->name);
+       ret = snprintf(buf, sizeof(buf), "%s/%s", USB_FUNCS_PATH, usb_function->name);
        if (ret < 0)
                return ret;
 
@@ -366,195 +374,130 @@ static int cfs_set_rndis_mac_addr(usbg_gadget *gadget, usbg_function *func)
        return ret;
 }
 
-static int cfs_set_gadget_config(struct cfs_client *cfs_client,
-                                   int config_id,
-                                   struct usb_configuration *usb_config)
+static int cfs_set_gadget_config(struct cfs_client *cfs_client, int config_id, struct usb_configuration *usb_config)
 {
+       int i;
+       int ret;
+       int function_type;
+       usbg_config *config;
+       usbg_function *function;
+       struct usb_function *usb_func;
+       char instance[MAX_INSTANCE_LEN];
        struct usbg_config_attrs cattrs = {
                .bmAttributes = usb_config->attrs.bmAttributs,
                .bMaxPower = usb_config->attrs.MaxPower/2,
        };
-       usbg_config *config;
-       int i;
-       int ret;
 
        if (!usb_config->funcs || !usb_config->funcs[0])
                return -EINVAL;
 
-       config = usbg_get_config(cfs_client->gadget, config_id, NULL);
-       if (config) {
-               ret = usbg_rm_config(config, USBG_RM_RECURSE);
-               if (ret)
-                       return ret;
-       }
-
-       ret = usbg_create_config(cfs_client->gadget, config_id,
-                                CONFIGFS_CONFIG_LABEL, &cattrs, NULL, &config);
+       ret = usbg_create_config(cfs_client->gadget, config_id, CONFIGFS_CONFIG_LABEL, &cattrs, NULL, &config);
        if (ret)
                return ret;
 
        for (i = 0; usb_config->strs && usb_config->strs[i].lang_code; ++i) {
-               ret = usbg_set_config_string(config, usb_config->strs[i].lang_code,
-                                            usb_config->strs[i].config_str);
+               ret = usbg_set_config_string(config, usb_config->strs[i].lang_code, usb_config->strs[i].config_str);
                if (ret)
                        return ret;
        }
 
-       for (i = 0; usb_config->funcs && usb_config->funcs[i]; ++i) {
-               struct usb_function *usb_func = usb_config->funcs[i];
-               char instance[MAX_INSTANCE_LEN];
-               int type;
-               usbg_function *func;
-
-               if (!usb_func->is_functionfs) {
-                       type = usbg_lookup_function_type(usb_func->name);
-                       if (strlen(usb_func->instance) >= MAX_INSTANCE_LEN)
-                               return -ENAMETOOLONG;
-                       strncpy(instance, usb_func->instance, MAX_INSTANCE_LEN);
-                       instance[MAX_INSTANCE_LEN - 1] = '\0';
-               } else {
-                       type = USBG_F_FFS;
-                       ret = snprintf(instance, sizeof(instance), "%s%c%s",
-                                      usb_func->name, NAME_INSTANCE_SEP,
-                                      usb_func->instance);
-                       if (ret < 0 || ret >= sizeof(instance))
-                               return -ENAMETOOLONG;
-               }
+       for (i = 0; usb_config->funcs[i]; ++i) {
+               usb_func = usb_config->funcs[i];
 
-               func = usbg_get_function(cfs_client->gadget, type, instance);
-               if (!func) {
-                       ret = usbg_create_function(cfs_client->gadget,
-                                                  type,
-                                                  instance,
-                                                  NULL, &func);
-                       if (ret)
-                               return ret;
+               /* name("sdb") + NAME_INSTANCE_SEP(".") + instance("default") + '\0' */
+               if (strlen(usb_func->name) + strlen(usb_func->instance) + 2 > sizeof(instance))
+                       return -ENAMETOOLONG;
 
-                       /* Setting rndis mac address. This should be done at this point,
-                        * since the node host_addr changes to read only after the function
-                        * is added to config. */
-                       if (usbg_get_function_type(func) == USBG_F_RNDIS)
-                               (void)cfs_set_rndis_mac_addr(cfs_client->gadget, func); /* A random value is used if fails */
-
-                       if (usb_func->is_functionfs) {
-                               ret = cfs_prep_ffs_service(usb_func->name,
-                                                       usb_func->instance,
-                                                       instance,
-                                                       usb_func->service);
-                               if (ret)
-                                       return ret;
-                       }
+               /* In functionfs, the instance is used in the format "[sdb|mtp].default" instead of "default" */
+               if (usb_func->is_functionfs) {
+                       function_type = USBG_F_FFS;
+                       snprintf(instance, sizeof(instance) - 1, "%s%c%s", usb_func->name, NAME_INSTANCE_SEP, usb_func->instance);
+               } else {
+                       function_type = usbg_lookup_function_type(usb_func->name);
+                       strncpy(instance, usb_func->instance, MAX_INSTANCE_LEN - 1);
                }
 
-               ret = usbg_add_config_function(config, NULL, func);
-               if (ret)
-                       return ret;
-       }
-
-       return ret;
-}
-
-static int cfs_cleanup_left_configs(struct cfs_client *cfs_client,
-                                   int last_config)
-{
-       usbg_config *lconfig, *config;
-       int ret;
-
-       lconfig = usbg_get_config(cfs_client->gadget, last_config, NULL);
-       for (config = usbg_get_next_config(lconfig);
-            config;
-            config = usbg_get_next_config(lconfig)) {
-               ret = usbg_rm_config(config, USBG_RM_RECURSE);
+               ret = usbg_create_function(cfs_client->gadget, function_type, instance, NULL, &function);
                if (ret)
                        return ret;
-       }
-
-       return 0;
-}
-
-static int cfs_function_is_binded(struct usbg_gadget *gadget, struct usbg_function *func)
-{
-       usbg_binding *b;
-       usbg_config *config;
-
-       usbg_for_each_config(config, gadget)
-               usbg_for_each_binding(b, config)
-                       if (usbg_get_binding_target(b) == func)
-                               return 1;
 
-       return 0;
-}
-
-static int cfs_cleanup_unused_function(usbg_gadget *gadget)
-{
-       int ret;
-       usbg_function *function;
-
-       if (!gadget)
-               return -EINVAL;
-
-restart:
-       usbg_for_each_function(function, gadget) {
-               if(cfs_function_is_binded(gadget, function))
-                       continue;
+               /* Setting rndis mac address. This should be done at this point,
+                * since the node host_addr changes to read only after the function
+                * is added to config. */
+               if (usbg_get_function_type(function) == USBG_F_RNDIS)
+                       (void)cfs_set_rndis_mac_addr(cfs_client->gadget, function); /* A random value is used if fails */
 
                if (usbg_get_function_type(function) == USBG_F_FFS) {
-                       ret = cfs_cleanup_ffs_service(function);
+                       ret = cfs_prep_ffs_service(usb_func, function);
                        if (ret)
                                return ret;
                }
 
-               ret = usbg_rm_function(function, USBG_RM_RECURSE);
+               ret = usbg_add_config_function(config, NULL, function);
                if (ret)
                        return ret;
-
-               /* You cannot delete a usbg_function directly in an iterator. */
-               goto restart;
        }
 
        return 0;
 }
 
-
 static int cfs_reconfigure_gadget(struct usb_client *usb,
                                  struct usb_gadget *gadget)
 {
-       struct cfs_client *cfs_client;
        int i;
        int ret;
+       usbg_config *config;
+       usbg_function *function;
+       struct cfs_client *cfs_client;
 
        if (!usb || !gadget || !cfs_is_gadget_supported(usb, gadget))
                return -EINVAL;
 
-       cfs_client = container_of(usb, struct cfs_client,
-                                 client);
+       cfs_client = container_of(usb, struct cfs_client, client);
 
        ret = cfs_set_gadget_attrs(cfs_client, &gadget->attrs);
        if (ret)
-               goto out;
+               return ret;
 
        for (i = 0; gadget->strs && gadget->strs[i].lang_code > 0; ++i) {
                ret = cfs_set_gadget_strs(cfs_client, gadget->strs + i);
                if (ret)
-                       goto out;
+                       return ret;
        }
 
-       for (i = 0; gadget->configs && gadget->configs[i]; ++i) {
-               ret = cfs_set_gadget_config(cfs_client, i + 1,
-                                           gadget->configs[i]);
+       /* delete all configs */
+restart_rm_config:
+       usbg_for_each_config(config, cfs_client->gadget) {
+               ret = usbg_rm_config(config, USBG_RM_RECURSE);
                if (ret)
-                       goto out;
+                       return ret;
+
+               goto restart_rm_config; /* You cannot delete a config directly in an iterator. */
        }
 
-       ret = cfs_cleanup_left_configs(cfs_client, i);
-       if(ret)
-               goto out;
+       /* delete all functions */
+restart_rm_function:
+       usbg_for_each_function(function, cfs_client->gadget) {
+               if (usbg_get_function_type(function) == USBG_F_FFS) {
+                       ret = cfs_cleanup_ffs_service(function);
+                       if (ret)
+                               return ret;
+               }
+
+               ret = usbg_rm_function(function, USBG_RM_RECURSE);
+               if (ret)
+                       return ret;
 
-       /* Cleanup things which are left after previous gadget */
-       ret = cfs_cleanup_unused_function(cfs_client->gadget);
+               goto restart_rm_function; /* You cannot delete a function directly in an iterator. */
+       }
 
-out:
-       return ret;
+       for (i = 0; gadget->configs && gadget->configs[i]; ++i) {
+               ret = cfs_set_gadget_config(cfs_client, i + 1, gadget->configs[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static void cfs_start_stop_service_and_handler(usbg_gadget *gadget, enum cfs_function_service_operation operation)