diff options
author | INSUN PYO <insun.pyo@samsung.com> | 2020-03-17 16:21:36 +0900 |
---|---|---|
committer | INSUN PYO <insun.pyo@samsung.com> | 2020-03-19 11:40:14 +0900 |
commit | 52e9dce09444267176cc1aade368944aadf8cc58 (patch) | |
tree | e4dde9f97211d72efab23ecb87d2c08da35291bd | |
parent | e62a0170c30e06e1f7c69d5f4512dce2f73b0946 (diff) | |
download | libdevice-node-52e9dce09444267176cc1aade368944aadf8cc58.tar.gz libdevice-node-52e9dce09444267176cc1aade368944aadf8cc58.tar.bz2 libdevice-node-52e9dce09444267176cc1aade368944aadf8cc58.zip |
Rework getting the currently enabled function list in the SLP gadget.
Before Change: Obtain all information of gadget from the enabled gadget.
After Change: Obtain only necessary function list from the enabled gadget.
Change-Id: Ib6547209f443e7a58bbbdb87373e53d252cdbdb6
-rw-r--r-- | hw/usb_client_common.c | 467 |
1 files changed, 91 insertions, 376 deletions
diff --git a/hw/usb_client_common.c b/hw/usb_client_common.c index e8357e0..6822f32 100644 --- a/hw/usb_client_common.c +++ b/hw/usb_client_common.c @@ -26,10 +26,7 @@ #include <hw/shared.h> #include <hw/usb_client.h> -#define zalloc(amount) calloc(1, amount) - #define MAX_GADGET_STR_LEN 256 -#define MAX_FUNCS 32 #define LEGACY_ROOTPATH "/sys/class/usb_mode/usb0" @@ -44,11 +41,11 @@ /* Strings */ #define LEGACY_IMANUFACTURER_PATH LEGACY_ROOTPATH"/iManufacturer" #define LEGACY_IPRODUCT_PATH LEGACY_ROOTPATH"/iProduct" -#define LEGACY_ISERIAL_PATH LEGACY_ROOTPATH"/iSerial" /* Functions in each config */ #define LEGACY_CONFIG_1_PATH LEGACY_ROOTPATH"/funcs_fconf" #define LEGACY_CONFIG_2_PATH LEGACY_ROOTPATH"/funcs_sconf" + /* should be single char */ #define LEGACY_FUNC_SEP "," @@ -57,315 +54,35 @@ #define LEGACY_ENABLE "1" #define LEGACY_DISABLE "0" -#define LEGACY_BMATTRIBUTES ((1 << 7) | (1 << 6)) -#define LEGACY_MAX_POWER 500 - -/* +5 to be always big enough */ -#define INT_BUF_SIZE (sizeof(int)*8 + 5) - #ifndef EXPORT #define EXPORT __attribute__ ((visibility("default"))) #endif -static void legacy_free_gadget(struct usb_gadget *gadget); - -static int get_int_from_file(char *path, int *_val, int base) -{ - char buf[INT_BUF_SIZE]; - char *endptr; - long int val; - int ret; - - ret = sys_get_str(path, buf, sizeof(buf)); - if (ret) - return ret; - - val = strtol(buf, &endptr, base); - if (val == LONG_MIN || val == LONG_MAX || - buf[0] == '\0' || (*endptr != '\0' && *endptr != '\n') - || val >= INT_MAX) - return -EINVAL; - - *_val = (int)val; - return 0; -} - -static int legacy_read_gadget_attrs_strs(struct usb_gadget *gadget) -{ - int val; - int ret; - /* We assume that values received from kernel will be valid */ -#define GET_VALUE_FROM_SYSFS(path, field, type, base) \ - do { \ - ret = get_int_from_file(path, &val, base); \ - if (ret) \ - return ret; \ - \ - gadget->attrs.field = (type)val; \ - } while (0) - - GET_VALUE_FROM_SYSFS(LEGACY_CLASS_PATH, bDeviceClass, uint8_t, 0); - GET_VALUE_FROM_SYSFS(LEGACY_SUBCLASS_PATH, bDeviceSubClass, uint8_t, 0); - GET_VALUE_FROM_SYSFS(LEGACY_PROTOCOL_PATH, bDeviceProtocol, uint8_t, 0); - GET_VALUE_FROM_SYSFS(LEGACY_ID_VENDOR_PATH, idVendor, uint16_t, 16); - GET_VALUE_FROM_SYSFS(LEGACY_ID_PRODUCT_PATH, idProduct, uint16_t, 16); - GET_VALUE_FROM_SYSFS(LEGACY_BCD_DEVICE_PATH, bcdDevice, uint16_t, 0); -#undef GET_VALUE_FROM_SYSFS - -#define GET_STRING_FROM_SYSFS(path, field) \ - do { \ - char buf[MAX_GADGET_STR_LEN]; \ - \ - ret = sys_get_str(path, buf, sizeof(buf)); \ - if (ret) \ - goto err_##field; \ - \ - gadget->strs[0].field = strdup(buf); \ - if (!gadget->strs[0].field) { \ - ret = -ENOMEM; \ - goto err_##field; \ - } \ - } while (0) - - GET_STRING_FROM_SYSFS(LEGACY_IMANUFACTURER_PATH, manufacturer); - GET_STRING_FROM_SYSFS(LEGACY_IPRODUCT_PATH, product); - GET_STRING_FROM_SYSFS(LEGACY_ISERIAL_PATH, serial); -#undef GET_STRING_FROM_SYSFS - - return 0; - -err_serial: - free(gadget->strs[0].product); -err_product: - free(gadget->strs[0].manufacturer); -err_manufacturer: - return ret; -} - -static int legacy_find_func(const char *name) +static struct usb_function *legacy_find_func(const char *name) { int i; for (i = 0; _available_funcs[i]; ++i) if (!strcmp(name, _available_funcs[i]->name)) - return i; - - return -1; -} + return _available_funcs[i]; -static struct usb_function *legacy_find_func_in_gadget( - struct usb_gadget *gadget, const char *name) -{ - int i; - - for (i = 0; gadget->funcs[i]; ++i) - if (!strcmp(name, gadget->funcs[i]->name)) - return gadget->funcs[i]; return NULL; } -static int legacy_alloc_config(int n_funcs, struct usb_configuration **_config) -{ - struct usb_configuration *config; - - config = zalloc(sizeof(*config)); - if (!config) - goto out; - - config->strs = calloc(1, sizeof(*config->strs)); - if (!config->strs) - goto free_config; - - config->funcs = calloc(n_funcs + 1, sizeof(*config->funcs)); - if (!config->funcs) - goto free_strs; - - /* - * We cannot read correct values - * so assume that they are always default - */ - config->attrs.bmAttributs = LEGACY_BMATTRIBUTES; - config->attrs.MaxPower = LEGACY_MAX_POWER; - - *_config = config; - - return 0; -free_strs: - free(config->strs); -free_config: - free(config); -out: - return -ENOMEM; -} - -static int legacy_alloc_new_func(struct usb_gadget *gadget, const char *fname, - struct usb_function **_func) -{ - struct usb_function *func; - int ret; - - ret = legacy_find_func(fname); - if (ret < 0) - return -ENOTSUP; - - ret = _available_funcs[ret]->clone(_available_funcs[ret], &func); - if (ret) - return ret; - - *_func = func; - return 0; -} - -static int legacy_read_config(struct usb_gadget *gadget, - char *cpath, - struct usb_configuration **_config) -{ - struct usb_configuration *config; - char buf[MAX_GADGET_STR_LEN]; - char *begin = buf; - char *fname; - char *sep = LEGACY_FUNC_SEP; - int i, f_cnt; - int f_idx; - int g_f_idx; - int ret; - - ret = sys_get_str(cpath, buf, sizeof(buf)); - if (ret) - return ret; - - /* Empty */ - if (buf[0] == '\0' || buf[0] == '\n') - return 0; - - /* count number of functions in this config */ - f_cnt = 1; - for (i = 0; buf[i] != '\0'; ++i) { - if (buf[i] == sep[0]) - ++f_cnt; - if (buf[i] == '\n') /* buf ends with it */ - buf[i] = 0; - } - - ret = legacy_alloc_config(f_cnt, &config); - if (ret) - return ret; - - for (g_f_idx = 0; gadget->funcs[g_f_idx]; ++g_f_idx); - - f_idx = 0; - for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) { - struct usb_function *func; - - func = legacy_find_func_in_gadget(gadget, fname); - if (!func) { - /* new function not added yet to gadget */ - ret = legacy_alloc_new_func(gadget, fname, &func); - if (ret) - goto free_config; - - gadget->funcs[g_f_idx++] = func; - } - - config->funcs[f_idx++] = func; - } - - *_config = config; - return 0; -free_config: - free(config->strs); - free(config->funcs); - free(config); - return ret; -} - -static int legacy_get_current_gadget(struct usb_client *usb, - struct usb_gadget **_gadget) -{ - struct usb_gadget *gadget; - struct usb_gadget_strings *strs; - struct usb_configuration **configs; - struct usb_function **funcs; - int i; - int ret = -ENOMEM; - - gadget = zalloc(sizeof(*gadget)); - if (!gadget) - goto out; - - strs = calloc(2, sizeof(*strs)); - if (!strs) - goto free_gadget; - - strs[0].lang_code = 0x409; - - gadget->strs = strs; - - ret = legacy_read_gadget_attrs_strs(gadget); - if (ret) - goto free_strs; - - /* There will be no more functions than bits in int */ - funcs = calloc(MAX_FUNCS, sizeof(*funcs)); - if (!funcs) - goto free_strs_with_content; - - gadget->funcs = funcs; - - /* slp-gadget use max 2 confiuration and NULL termination */ - configs = calloc(3, sizeof(*configs)); - if (!configs) - goto free_funcs; - - gadget->configs = configs; - - ret = legacy_read_config(gadget, LEGACY_CONFIG_1_PATH, configs + 0); - if (ret) - goto free_configs; - - ret = legacy_read_config(gadget, LEGACY_CONFIG_2_PATH, configs + 1); - if (ret) - goto free_config_1; - - *_gadget = gadget; - return 0; - -free_config_1: - free(configs[0]->funcs); - free(configs[0]->strs); - free(configs[0]); -free_configs: - free(configs); - for (i = 0; gadget->funcs[i]; ++i) - gadget->funcs[i]->free_func(gadget->funcs[i]); -free_funcs: - free(funcs); -free_strs_with_content: - free(gadget->strs[0].manufacturer); - free(gadget->strs[0].product); - free(gadget->strs[0].serial); -free_strs: - free(gadget->strs); -free_gadget: - free(gadget); -out: - return ret; -} static bool legacy_is_function_supported(struct usb_client *usb, struct usb_function *func) { - int ret; - /* * TODO * Instead of only checking whether we know this function * we should also parse sysfs to check if it is build into * slp-gadget. */ - ret = legacy_find_func(func->name); - - return ret >= 0; + if (legacy_find_func(func->name)) + return true; + else + return false; } static bool legacy_is_gadget_supported(struct usb_client *usb, @@ -536,121 +253,119 @@ static int legacy_reconfigure_gadget(struct usb_client *usb, return ret; } -static int legacy_enable(struct usb_client *usb) +static void legacy_start_stop_service_and_handler(bool start) { int i; int ret; - struct usb_gadget *gadget; + int n_func = 0; + char *ptr; + char *begin; + char *fname; + char *sep = LEGACY_FUNC_SEP; + char buf[MAX_GADGET_STR_LEN]; struct usb_function *func; + struct usb_function *funcs[USB_FUNCTION_IDX_MAX]; + + /* SLP gadget uses two USB configuration. + * (/sys/class/usb_mode/usb0/funcs_fconf and /sys/class/usb_mode/usb0/funcs_sconf) + * + * One usb function can be included in two configurations simultaneously. + * In this situation, a handler associated with function can be called twice for a usb function. + * To prevent duplicate calls, + * Collect all functions and remove duplicates and process them. + */ - ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_ENABLE); - if (ret < 0) - return ret; + /* First configuration */ + ret = sys_get_str(LEGACY_CONFIG_1_PATH, buf, sizeof(buf)); + if (ret) + goto second_configuration; - ret = legacy_get_current_gadget(usb, &gadget); - if (ret < 0) - goto disable_gadget; + /* Caution: buf ends with '\n' */ + ptr = strchr(buf, '\n'); + if (ptr) + *ptr = 0; + + begin = buf; + for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) { + func = legacy_find_func(fname); + if (!func) + continue; - for (i = 0; gadget->funcs[i]; ++i) { - func = gadget->funcs[i]; + for (i = 0; i < n_func; i++) + if (funcs[i] == func) + continue; - if (func->handler) - func->handler(1); + if(n_func >= USB_FUNCTION_IDX_MAX) /* What happen */ + break; - if (func->service) - (void)systemd_start_unit_wait_started(func->service, ".service", -1); + funcs[n_func] = func; + n_func++; } - legacy_free_gadget(gadget); - return 0; - -disable_gadget: - sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE); - return ret; -} + /* Second configuration */ +second_configuration: + ret = sys_get_str(LEGACY_CONFIG_2_PATH, buf, sizeof(buf)); + if (ret) + return; -static int legacy_disable(struct usb_client *usb) -{ - int i; - int ret; - struct usb_gadget *gadget; - struct usb_function *func; + /* Caution: buf ends with '\n' */ + ptr = strchr(buf, '\n'); + if (ptr) + *ptr = 0; - ret = legacy_get_current_gadget(usb, &gadget); - if (ret < 0) - return ret; + begin = buf; + for (fname = strsep(&begin, sep); fname; fname = strsep(&begin, sep)) { + func = legacy_find_func(fname); + if (!func) + continue; - for (i = 0; gadget->funcs[i]; ++i) { - func = gadget->funcs[i]; + for (i = 0; i < n_func; i++) + if (funcs[i] == func) + continue; - if (func->service) - (void)systemd_stop_unit_wait_stopped(func->service, ".service", -1); + if(n_func >= USB_FUNCTION_IDX_MAX) /* What happen */ + break; - if (func->handler) - func->handler(0); + funcs[n_func] = func; + n_func++; } - ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE); + for (i = 0; i < n_func; i++) { + if (start) { + if (funcs[i]->handler) + funcs[i]->handler(1); - legacy_free_gadget(gadget); - return ret; -} - -static void legacy_free_config(struct usb_configuration *config) -{ - int i; + if (funcs[i]->service) + (void)systemd_start_unit_wait_started(funcs[i]->service, ".service", -1); + } else { + if (funcs[i]->service) + (void)systemd_stop_unit_wait_stopped(funcs[i]->service, ".service", -1); - if (!config) - return; - - if (config->strs) { - for (i = 0; config->strs[i].lang_code; ++i) - free(config->strs[i].config_str); - - free(config->strs); + if (funcs[i]->handler) + funcs[i]->handler(0); + } } - - /* - * Each function will be free later, - * for now we cleanup only pointers. - */ - if (config->funcs) - free(config->funcs); - - free(config); } -static void legacy_free_gadget(struct usb_gadget *gadget) +static int legacy_enable(struct usb_client *usb) { - int i; - - if (!gadget) - return; + int ret; - if (gadget->strs) { - for (i = 0; gadget->strs[i].lang_code; ++i) { - free(gadget->strs[i].manufacturer); - free(gadget->strs[i].product); - free(gadget->strs[i].serial); - } - free(gadget->strs); - } + ret = sys_set_str(LEGACY_ENABLE_PATH, LEGACY_ENABLE); + if (ret < 0) + return ret; - if (gadget->configs) { - for (i = 0; gadget->configs[i]; ++i) - legacy_free_config(gadget->configs[i]); + legacy_start_stop_service_and_handler(true); - free(gadget->configs); - } + return 0; +} - if (gadget->funcs) { - for (i = 0; gadget->funcs[i]; ++i) - gadget->funcs[i]->free_func(gadget->funcs[i]); +static int legacy_disable(struct usb_client *usb) +{ - free(gadget->funcs); - } + legacy_start_stop_service_and_handler(false); - free(gadget); + return sys_set_str(LEGACY_ENABLE_PATH, LEGACY_DISABLE); } EXPORT @@ -666,7 +381,7 @@ int hw_legacy_gadget_open(struct hw_info *info, if (access("/sys/class/usb_mode/usb0/enable", F_OK)) return -ENOENT; - legacy = zalloc(sizeof(*legacy)); + legacy = calloc(1, sizeof(*legacy)); if (!legacy) return -ENOMEM; |