Fixed to stop services of functionfs when gadget is disabled 35/227335/2
authorINSUN PYO <insun.pyo@samsung.com>
Wed, 11 Mar 2020 08:46:35 +0000 (17:46 +0900)
committerINSUN PYO <insun.pyo@samsung.com>
Wed, 11 Mar 2020 08:50:32 +0000 (17:50 +0900)
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

hw/usb_cfs_client_common.c
hw/usb_gadget.h

index d594fd2..6d3595f 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 fe909ed..dc4b539 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;