Refactoring: replace ffs_service to is_functionfs
[platform/core/system/libdevice-node.git] / hw / usb_cfs_client_common.c
index 8069f4d..39dfca2 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <hw/usb_client.h>
-#include <hw/systemd.h>
 #include <hw/shared.h>
 
 #include <limits.h>
 #include <sys/types.h>
 #include <sys/mount.h>
 #include <usbg/usbg.h>
+#include <usbg/function/net.h>
 #include <unistd.h>
 
-#include <unistd.h>
+#include <libsyscommon/dbus-systemd.h>
+
 
 #define zalloc(amount) calloc(1, amount)
 
@@ -124,6 +125,8 @@ static void cfs_free_gadget(struct usb_gadget *gadget)
 
                free(gadget->funcs);
        }
+
+       free(gadget);
 }
 
 static int cfs_read_gadget_attrs_strs(usbg_gadget *gadget,
@@ -144,7 +147,6 @@ static int cfs_read_gadget_attrs_strs(usbg_gadget *gadget,
        usb_gadget->attrs.idProduct = attrs.idProduct;
        usb_gadget->attrs.bcdDevice = attrs.bcdDevice;
 
-
        ret = usbg_get_gadget_strs(gadget, LANG_US_ENG, &strs);
        if (ret)
                goto out;
@@ -153,6 +155,8 @@ static int cfs_read_gadget_attrs_strs(usbg_gadget *gadget,
        usb_gadget->strs[0].product = strdup(strs.product);
        usb_gadget->strs[0].serial = strdup(strs.serial);
 
+       usbg_free_gadget_strs(&strs);
+
        if (!usb_gadget->strs[0].manufacturer ||
            !usb_gadget->strs[0].product ||
            !usb_gadget->strs[0].serial) {
@@ -202,7 +206,7 @@ static int cfs_find_func(const char *name, const char *instance)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i)
+       for (i = 0; _available_funcs[i]; ++i)
                if (cfs_match_func(_available_funcs[i], name, instance))
                        return i;
 
@@ -418,8 +422,7 @@ static int cfs_get_current_gadget(struct usb_client *usb,
        if (!usb)
                return -EINVAL;
 
-       cfs_client = container_of(usb, struct cfs_client,
-                                 client);
+       cfs_client = container_of(usb, struct cfs_client, client);
 
        usb_gadget = zalloc(sizeof(*usb_gadget));
        if (!usb_gadget)
@@ -442,7 +445,6 @@ static int cfs_get_current_gadget(struct usb_client *usb,
        if (ret)
                goto free_strs;
 
-
        n_funcs = cfs_count_functions(cfs_client->gadget);
        usb_funcs = calloc(n_funcs + 1, sizeof(*usb_funcs));
        if (!usb_funcs)
@@ -495,17 +497,12 @@ static bool cfs_is_function_supported(struct usb_client *usb,
        bool res;
        int ret;
 
-       switch (func->function_group) {
-       case USB_FUNCTION_GROUP_SIMPLE:
+       if (!func->is_functionfs) {
                ret = usbg_lookup_function_type(func->name);
                res = ret >= 0;
-               break;
-       case USB_FUNCTION_GROUP_WITH_SERVICE:
+       } else {
                /* TODO: Check if socket is available */
                res = true;
-               break;
-       default:
-               res = false;
        }
 
        return res;
@@ -610,6 +607,8 @@ static int cfs_prep_ffs_service(const char *name, const char *instance,
        int ret;
 
        /* TODO: Add some good error handling */
+       if (!socket_name)
+               return -EINVAL;
 
        left = sizeof(buf);
        pos = buf;
@@ -650,7 +649,7 @@ static int cfs_prep_ffs_service(const char *name, const char *instance,
        if (ret < 0)
                return ret;
 
-       ret = systemd_start_socket(socket_name);
+       ret = systemd_start_unit_wait_started(socket_name, ".socket", -1);
        if (ret < 0)
                goto umount_ffs;
 
@@ -660,6 +659,37 @@ umount_ffs:
        return ret;
 }
 
+static int cfs_set_rndis_mac_addr(usbg_gadget *gadget, usbg_function *func)
+{
+       int i, ret;
+       struct ether_addr ethaddr;
+       struct usbg_gadget_strs strs;
+       struct usbg_f_net *nf = usbg_to_net_function(func);
+
+       if (!nf)
+               return -EINVAL;
+
+       ret = usbg_get_gadget_strs(gadget, LANG_US_ENG, &strs);
+       if (ret != USBG_SUCCESS)
+               return ret;
+
+       for (i = 0; i < ETHER_ADDR_LEN; i++)
+               ethaddr.ether_addr_octet[i] = 0;
+
+       for (i = 0; (i < 256) && strs.serial[i]; i++) {
+               ethaddr.ether_addr_octet[i % (ETHER_ADDR_LEN - 1) + 1] ^= strs.serial[i];
+       }
+       ethaddr.ether_addr_octet[0] &= 0xfe;     /* clear multicast bit */
+       ethaddr.ether_addr_octet[0] |= 0x02;     /* set local assignment bit (IEEE802) */
+
+       usbg_free_gadget_strs(&strs);
+
+       /* host_addr changes mac address */
+       ret = usbg_f_net_set_host_addr(nf, &ethaddr);
+
+       return ret;
+}
+
 static int cfs_set_gadget_config(struct cfs_client *cfs_client,
                                    int config_id,
                                    struct usb_configuration *usb_config)
@@ -700,27 +730,21 @@ static int cfs_set_gadget_config(struct cfs_client *cfs_client,
                int type;
                usbg_function *func;
 
-               switch (usb_func->function_group) {
-               case USB_FUNCTION_GROUP_SIMPLE:
+               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';
-                       break;
-               case USB_FUNCTION_GROUP_WITH_SERVICE:
+               } 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;
-                       break;
-               default:
-                       return -EINVAL;
                }
 
-
                func = usbg_get_function(cfs_client->gadget, type, instance);
                if (!func) {
                        ret = usbg_create_function(cfs_client->gadget,
@@ -730,21 +754,20 @@ static int cfs_set_gadget_config(struct cfs_client *cfs_client,
                        if (ret)
                                return ret;
 
-                       if (usb_func->function_group ==
-                           USB_FUNCTION_GROUP_WITH_SERVICE) {
-                               struct usb_function_with_service *fws;
+                       /* 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 */
 
-                               fws = container_of(usb_func,
-                                                  struct usb_function_with_service,
-                                                  func);
+                       if (usb_func->is_functionfs) {
                                ret = cfs_prep_ffs_service(usb_func->name,
-                                                          usb_func->instance,
-                                                          instance,
-                                                          fws->service);
+                                                       usb_func->instance,
+                                                       instance,
+                                                       usb_func->service);
                                if (ret)
                                        return ret;
                        }
-
                }
 
                ret = usbg_add_config_function(config, NULL, func);
@@ -780,15 +803,12 @@ static int cfs_reconfigure_gadget(struct usb_client *usb,
        int i;
        int ret;
 
-       if (!usb)
+       if (!usb || !gadget || !cfs_is_gadget_supported(usb, gadget))
                return -EINVAL;
 
        cfs_client = container_of(usb, struct cfs_client,
                                  client);
 
-       if (!usb || !gadget || !cfs_is_gadget_supported(usb, gadget))
-               return -EINVAL;
-
        ret = cfs_set_gadget_attrs(cfs_client, &gadget->attrs);
        if (ret)
                goto out;
@@ -806,11 +826,6 @@ static int cfs_reconfigure_gadget(struct usb_client *usb,
                        goto out;
        }
 
-       /* Workaround for enabling extcon notification */
-       ret = usbg_enable_gadget(cfs_client->gadget, cfs_client->udc);
-       if (ret)
-               goto out;
-
        ret = cfs_cleanup_left_configs(cfs_client, i);
 
        /* TODO
@@ -822,28 +837,85 @@ out:
 
 static int cfs_enable(struct usb_client *usb)
 {
+       int i;
+       int ret;
+       struct usb_gadget *gadget;
+       struct usb_function *func;
        struct cfs_client *cfs_client;
 
        if (!usb)
                return -EINVAL;
 
-       cfs_client = container_of(usb, struct cfs_client,
-                                 client);
+       cfs_client = container_of(usb, struct cfs_client, client);
+       ret = usbg_enable_gadget(cfs_client->gadget, cfs_client->udc);
+       if (ret)
+               return ret;
 
-       return usbg_enable_gadget(cfs_client->gadget, cfs_client->udc);
+       ret = cfs_get_current_gadget(usb, &gadget);
+       if (ret) {
+               usbg_disable_gadget(cfs_client->gadget);
+               return ret;
+       }
+
+       for (i = 0; gadget->funcs[i]; ++i) {
+               func = gadget->funcs[i];
+
+               if (func->handler)
+                       func->handler(1);
+
+               /* functionfs service is automatically started by socket activation */
+               if (!func->is_functionfs && func->service)
+                       (void)systemd_start_unit_wait_started(func->service, ".service", -1);
+       }
+
+       cfs_free_gadget(gadget);
+
+       return 0;
 }
 
 static int cfs_disable(struct usb_client *usb)
 {
+       int i;
+       int ret;
+       struct usb_gadget *gadget;
+       struct usb_function *func;
        struct cfs_client *cfs_client;
 
        if (!usb)
                return -EINVAL;
 
-       cfs_client = container_of(usb, struct cfs_client,
-                                 client);
+       ret = cfs_get_current_gadget(usb, &gadget);
+       if (ret)
+               return ret;
+
+       for (i = 0; gadget->funcs[i]; ++i) {
+               func = gadget->funcs[i];
+
+               if (!func->is_functionfs && func->service)
+                       (void)systemd_stop_unit_wait_stopped(func->service, ".service", -1);
+
+               if (func->handler)
+                       func->handler(0);
+       }
 
-       return usbg_disable_gadget(cfs_client->gadget);
+       cfs_client = container_of(usb, struct cfs_client, client);
+       ret = usbg_disable_gadget(cfs_client->gadget); /* ignore error checking */
+
+       /*
+        * Since functionfs service works with socket activation, you must stop it after disabling gadget.
+        * If usb data may come in after stopping functionfs service and before disabling gadget,
+        * functionfs service wakes up again by socket activation.
+        */
+       for (i = 0; gadget->funcs[i]; ++i) {
+               func = gadget->funcs[i];
+
+               if (func->is_functionfs && func->service)
+                       (void)systemd_stop_unit_wait_stopped(func->service, ".service", -1);
+       }
+
+       cfs_free_gadget(gadget);
+
+       return ret;
 }
 
 EXPORT
@@ -921,15 +993,10 @@ int hw_cfs_gadget_close(struct hw_common *common)
                        continue;
 
                usb_func = _available_funcs[ret];
-               if (usb_func->function_group ==
-                   USB_FUNCTION_GROUP_WITH_SERVICE) {
-                       struct usb_function_with_service *fws;
-
-                       fws = container_of(usb_func,
-                                          struct usb_function_with_service,
-                                          func);
-                       systemd_stop_socket(fws->service);
-                       systemd_stop_service(fws->service);
+
+               if (usb_func->is_functionfs && usb_func->service) {
+                       (void)systemd_stop_unit_wait_stopped(usb_func->service, ".socket", -1);
+                       (void)systemd_stop_unit_wait_stopped(usb_func->service, ".service", -1);
                }
        }