Fixed a possibility that the function handler might be called twice 80/228080/3
authorINSUN PYO <insun.pyo@samsung.com>
Thu, 19 Mar 2020 02:43:30 +0000 (11:43 +0900)
committerINSUN PYO <insun.pyo@samsung.com>
Thu, 19 Mar 2020 03:55:46 +0000 (03:55 +0000)
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

hw/usb_cfs_client_common.c

index 12e73c406ef5b09ea4236a2e31e3f50bf6c142ad..846eb77ff4cfe6c3a2e80c6d8f34717d38e0b638 100644 (file)
@@ -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>
 
 #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"
 #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;