diff options
author | INSUN PYO <insun.pyo@samsung.com> | 2020-03-19 11:43:30 +0900 |
---|---|---|
committer | INSUN PYO <insun.pyo@samsung.com> | 2020-03-19 03:55:46 +0000 |
commit | 7803a3c5a1b0293a5bda490c26c95ae8b967e001 (patch) | |
tree | c17d758d364f106093ef7d59f4f81c1ceeee5d62 | |
parent | 52e9dce09444267176cc1aade368944aadf8cc58 (diff) | |
download | libdevice-node-7803a3c5a1b0293a5bda490c26c95ae8b967e001.tar.gz libdevice-node-7803a3c5a1b0293a5bda490c26c95ae8b967e001.tar.bz2 libdevice-node-7803a3c5a1b0293a5bda490c26c95ae8b967e001.zip |
Fixed a possibility that the function handler might be called twice
Configfs can use more than one configs.
(/sys/kernel/config/usb_gadget/hal-gadget/configs/hal-config.1 and /sys/kernel/config/usb_gadget/hal-gadget/configs/hal-config.2)
One usb function can be included in two config simultaneously.
In this situation, a handler associated with function can be called twice for a usb function.
To prevent duplicate calls,
it handles only the handlers of functions enabled in configfs, not the usb functions included in all configs.
Change-Id: I5e02dadc5d2688f0ad9210ad5ab149fb95ab05ba
-rw-r--r-- | hw/usb_cfs_client_common.c | 92 |
1 files changed, 47 insertions, 45 deletions
diff --git a/hw/usb_cfs_client_common.c b/hw/usb_cfs_client_common.c index 12e73c4..846eb77 100644 --- a/hw/usb_cfs_client_common.c +++ b/hw/usb_cfs_client_common.c @@ -16,8 +16,8 @@ * limitations under the License. */ -#include <string.h> #include <errno.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/mount.h> @@ -28,11 +28,6 @@ #include <hw/usb_client.h> -#define zalloc(amount) calloc(1, amount) - -#define MAX_GADGET_STR_LEN 256 -#define MAX_FUNCS 32 - #define CONFIGFS_PATH "/sys/kernel/config" #define CONFIGFS_GADGET_NAME "hal-gadget" @@ -47,6 +42,12 @@ #define EXPORT __attribute__ ((visibility("default"))) #endif +enum cfs_function_service_operation { + CFS_FUNCTION_SERVICE_START, + CFS_FUNCTION_SERVICE_STOP, + CFS_FUNCTION_SERVICE_POST_STOP, +}; + struct cfs_client { struct usb_client client; usbg_state *ctx; @@ -556,48 +557,49 @@ out: return ret; } -static void cfs_start_stop_service_handler(usbg_gadget *gadget, bool start, bool post_stop) +static void cfs_start_stop_service_and_handler(usbg_gadget *gadget, enum cfs_function_service_operation operation) { int index; const char *name; const char *instance; - usbg_config *config; - usbg_binding *binding; usbg_function *function; struct usb_function *usb_function; - /* Execute service and handler related to functions bound to configs */ - usbg_for_each_config(config, gadget) { - usbg_for_each_binding(binding, config) { - function = usbg_get_binding_target(binding); - instance = usbg_get_function_instance(function); - name = usbg_get_function_type_str(usbg_get_function_type(function)); - - index = cfs_find_func(name, instance); - if (index < 0) - continue; - - usb_function = _available_funcs[index]; - - if (start) { - if (usb_function->handler) - usb_function->handler(1); - - /* functionfs service is automatically started by socket activation */ - if (!usb_function->is_functionfs && usb_function->service) - (void)systemd_start_unit_wait_started(usb_function->service, ".service", -1); - } else { - if (post_stop) { - if (usb_function->is_functionfs && usb_function->service) - (void)systemd_stop_unit_wait_stopped(usb_function->service, ".service", -1); - } else { - if (!usb_function->is_functionfs && usb_function->service) - (void)systemd_stop_unit_wait_stopped(usb_function->service, ".service", -1); - - if (usb_function->handler) - usb_function->handler(0); - } - } + usbg_for_each_function(function, gadget) { + instance = usbg_get_function_instance(function); + name = usbg_get_function_type_str(usbg_get_function_type(function)); + + index = cfs_find_func(name, instance); + if (index < 0) + continue; + + usb_function = _available_funcs[index]; + + switch(operation) { + case CFS_FUNCTION_SERVICE_START: + if (usb_function->handler) + usb_function->handler(1); + + /* functionfs service is automatically started by socket activation */ + if (!usb_function->is_functionfs && usb_function->service) + (void)systemd_start_unit_wait_started(usb_function->service, ".service", -1); + break; + + case CFS_FUNCTION_SERVICE_STOP: + if (!usb_function->is_functionfs && usb_function->service) + (void)systemd_stop_unit_wait_stopped(usb_function->service, ".service", -1); + + if (usb_function->handler) + usb_function->handler(0); + break; + + case CFS_FUNCTION_SERVICE_POST_STOP: + if (usb_function->is_functionfs && usb_function->service) + (void)systemd_stop_unit_wait_stopped(usb_function->service, ".service", -1); + break; + + default: + break; } } } @@ -616,7 +618,7 @@ static int cfs_enable(struct usb_client *usb) if (ret) return ret; - cfs_start_stop_service_handler(cfs_client->gadget, true, false); + cfs_start_stop_service_and_handler(cfs_client->gadget, CFS_FUNCTION_SERVICE_START); return 0; } @@ -631,7 +633,7 @@ static int cfs_disable(struct usb_client *usb) cfs_client = container_of(usb, struct cfs_client, client); - cfs_start_stop_service_handler(cfs_client->gadget, false, false); + cfs_start_stop_service_and_handler(cfs_client->gadget, CFS_FUNCTION_SERVICE_STOP); ret = usbg_disable_gadget(cfs_client->gadget); /* ignore error checking */ @@ -640,7 +642,7 @@ static int cfs_disable(struct usb_client *usb) * If usb data may come in after stopping functionfs service and before disabling gadget, * functionfs service wakes up again by socket activation. */ - cfs_start_stop_service_handler(cfs_client->gadget, false, true); + cfs_start_stop_service_and_handler(cfs_client->gadget, CFS_FUNCTION_SERVICE_POST_STOP); return ret; } @@ -655,7 +657,7 @@ int hw_cfs_gadget_open(struct hw_info *info, if (!info || !common) return -EINVAL; - cfs_client = zalloc(sizeof(*cfs_client)); + cfs_client = calloc(1, sizeof(*cfs_client)); if (!cfs_client) return -ENOMEM; |