From: INSUN PYO Date: Thu, 19 Mar 2020 06:39:35 +0000 (+0900) Subject: Rework reconfiguration configfs gadget X-Git-Tag: submit/tizen/20200402.112144~10 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e513020a513815371d18079de80c55f370aa6ed6;p=platform%2Fcore%2Fsystem%2Flibdevice-node.git Rework reconfiguration configfs gadget 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 --- diff --git a/hw/usb_cfs_client_common.c b/hw/usb_cfs_client_common.c index 846eb77..577e508 100644 --- a/hw/usb_cfs_client_common.c +++ b/hw/usb_cfs_client_common.c @@ -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)