Fixed to stop services of functionfs when gadget is disabled 64/227364/1
authorINSUN PYO <insun.pyo@samsung.com>
Wed, 11 Mar 2020 08:46:35 +0000 (17:46 +0900)
committerHyotaek Shim <hyotaek.shim@samsung.com>
Wed, 11 Mar 2020 11:09:37 +0000 (11:09 +0000)
sdb.service and mtp-responder.service are alive when the usb cable is unplugged in the configfs environment.

If the usb cable is disconnected, gadget disable is called.
These services are stopped when the gadget is disabled.

Caution 1
Note that the socket units for these services should remain.
The scoket unit has ep0 in the functionfs environment.
If ep0 disappears because the socket unit is stopped, the functionfs can never be enabled.

Caution 2
Since ffs_service works by socket activation, it will be started automatically when data is enqueued to the usb socket.
So when enabling configfs gadget, it doesn't start ffs_service.

Change-Id: I660e0cf157320f6a4e8f152a028772547dd701f6
(cherry picked from commit 5e9327a2d5b5215b4371b406339dc83a89891074)

hw/usb_cfs_client_common.c
hw/usb_gadget.h

index d594fd217b57cfa166b7eacb6f3544c2235b8e1a..6d3595f7b1f43e29b8ea99d202ce733598f7ab70 100644 (file)
@@ -865,6 +865,8 @@ static int cfs_enable(struct usb_client *usb)
 
                if (func->service)
                        (void)systemd_start_unit_wait_started(func->service, ".service", -1);
+
+               /* func->ffs_service is automatically started by socket activation */
        }
 
        cfs_free_gadget(gadget);
@@ -897,10 +899,24 @@ static int cfs_disable(struct usb_client *usb)
                        func->handler(0);
        }
 
+       cfs_client = container_of(usb, struct cfs_client, client);
+       ret = usbg_disable_gadget(cfs_client->gadget); /* ignore error checking */
+
+       /*
+        * Since ffs_service works with socket activation, you must stop it after disabling gadget.
+        * If usb data may come in after stopping ffs_service and before disabling gadget,
+        * ffs_service wakes up again by socket activation.
+        */
+       for (i = 0; gadget->funcs[i]; ++i) {
+               func = gadget->funcs[i];
+
+               if (func->ffs_service)
+                       (void)systemd_stop_unit_wait_stopped(func->ffs_service, ".service", -1);
+       }
+
        cfs_free_gadget(gadget);
 
-       cfs_client = container_of(usb, struct cfs_client, client);
-       return usbg_disable_gadget(cfs_client->gadget);
+       return ret;
 }
 
 EXPORT
index fe909ed2ca847a3ba3ffb83c63010f93bf7e2262..dc4b539fd77f116e1e01ea6fe4fa3aad1e142c82 100644 (file)
@@ -65,10 +65,13 @@ typedef enum {
  * legacy enable(usb plug)    : enable gadget -> handler(1) -> ffs_service start -> service start
  * legacy disable(usb unplug) : service stop -> ffs_service stop -> handler(0) -> disable gadget
  *
- * configfs init(booting)       : ffs_service start
- * configfs enable(usb plug)    : enable gadget -> handler(1) -> service start
- * configfs disable(usb unplug) : service stop -> handler(0) -> disable gadget
- * configfs deinit              : ffs_service stop
+ * configfs init(booting)       : ffs_service.socket start
+ * configfs enable(usb plug)*   : enable gadget -> handler(1) -> service start
+ * configfs disable(usb unplug) : service stop -> handler(0) -> disable gadget -> ffs_service.service stop
+ * configfs deinit              : ffs_service.socket stop
+ *
+ * Since ffs_service works by socket activation, it will be started automatically when data is enqueued to the usb socket.
+ * So when enabling configfs gadget, it doesn't start ffs_service.
  */
 struct usb_function {
        int id;