Remove unused usb functions after changing usb mode 99/227499/7
authorINSUN PYO <insun.pyo@samsung.com>
Thu, 12 Mar 2020 07:29:19 +0000 (16:29 +0900)
committerINSUN PYO <insun.pyo@samsung.com>
Mon, 16 Mar 2020 01:06:01 +0000 (01:06 +0000)
After setting the new usb mode, the configfs functions that was not used remain.
For example, changing from rndis mode to sdb mode, /sys/kernel/config/usb_gadget/hal-gadget/rndis.default remains.

A functionfs has to do a few extra things.
 - The socket and service associated with functionfs must be terminated.
 - Umount /dev/usb-funcs/[sdb|mtp]/default
 - Delete /dev/usb-funcs/[sdb|mtp]/default recursively

Change-Id: I2d66f033babd5bea20cfc74d8bf23eb9a89c3be1

hw/usb_cfs_client_common.c

index 66ca48b..10bed2a 100644 (file)
@@ -659,6 +659,64 @@ umount_ffs:
        return ret;
 }
 
+static int cfs_cleanup_ffs_service(usbg_function *function)
+{
+       int ret;
+       int index;
+       const char *name;
+       const char *instance;
+       char buf[MAX_INSTANCE_LEN];
+       struct usb_function *usb_function;
+
+       if (!function)
+               return -EINVAL;
+
+       instance = usbg_get_function_instance(function); /* Ex: sdb.default */
+       name = usbg_get_function_type_str(usbg_get_function_type(function)); /* Fixed: ffs */
+
+       index = cfs_find_func(name, instance);
+       if (index < 0)
+               return index;
+
+       usb_function = _available_funcs[index];
+
+       /* stop .socket first and stop .service later becuase of socket activation */
+       if (usb_function->service) {
+               (void)systemd_stop_unit_wait_stopped(usb_function->service, ".socket", -1);
+               (void)systemd_stop_unit_wait_stopped(usb_function->service, ".service", -1);
+       }
+
+       /* 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);
+       if (ret < 0)
+               return ret;
+
+       ret = umount(buf);
+       if (ret < 0)
+               return ret;
+
+       ret = rmdir(buf);
+       if (ret < 0)
+               return ret;
+
+       /* remove /dev/usb-funcs/[sdb|mtp] directory */
+       ret = snprintf(buf, sizeof(buf), "%s%s", USB_FUNCS_PATH, usb_function->name);
+       if (ret < 0)
+               return ret;
+
+       ret = rmdir(buf);
+       if (ret < 0 && errno != ENOTEMPTY)
+               return ret;
+
+       /* remove /dev/usb-funcs/ directory */
+       ret = rmdir(USB_FUNCS_PATH);
+       if (ret < 0 && errno != ENOTEMPTY)
+               return ret;
+
+       return 0;
+}
+
+
 static int cfs_set_rndis_mac_addr(usbg_gadget *gadget, usbg_function *func)
 {
        int i, ret;
@@ -796,6 +854,50 @@ static int cfs_cleanup_left_configs(struct cfs_client *cfs_client,
        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;
+
+               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;
+
+               /* 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)
 {
@@ -827,10 +929,12 @@ static int cfs_reconfigure_gadget(struct usb_client *usb,
        }
 
        ret = cfs_cleanup_left_configs(cfs_client, i);
+       if(ret)
+               goto out;
+
+       /* Cleanup things which are left after previous gadget */
+       ret = cfs_cleanup_unused_function(cfs_client->gadget);
 
-       /* TODO
-        * Cleanup things which are left after previous gadget
-        */
 out:
        return ret;
 }