Add usb configuration exception handling code 50/226450/3
authorINSUN PYO <insun.pyo@samsung.com>
Tue, 3 Mar 2020 02:42:50 +0000 (11:42 +0900)
committerINSUN PYO <insun.pyo@samsung.com>
Tue, 3 Mar 2020 03:06:38 +0000 (12:06 +0900)
If an error occurs during usb configuration, change the usb current mode to USB_FUNCTION_NONE.

The meaning of usb current mode is that usb is working correctly.
If any error occurs, USB operation is not guaranteed.
The value of usb current mode should not have a meaningless value and should have USB_FUNCTION_NONE.

Change-Id: Ia882f517fe696a03cf1a39f97b382383d970e9d5

src/usb/usb.c

index a83e995..8ad5c7d 100644 (file)
@@ -236,8 +236,10 @@ static int usb_change_gadget(unsigned mode)
        struct usb_gadget *gadget;
        struct usb_gadget_id gadget_id;
 
-       if (!gadget_translator || !usb_client)
-               goto no_hal;
+       if (!gadget_translator || !usb_client) {
+               ret = -ENODEV;
+               goto out;
+       }
 
        memset(&gadget_id, 0, sizeof(gadget_id));
        gadget_id.function_mask = mode;
@@ -245,7 +247,7 @@ static int usb_change_gadget(unsigned mode)
        ret = gadget_translator->id_to_gadget(&gadget_id, &gadget);
        if (ret) {
                _E("Unable to translate id into gadget: %d", ret);
-               return ret;
+               goto out;
        }
 
        usb_client->disable(usb_client);
@@ -253,16 +255,17 @@ static int usb_change_gadget(unsigned mode)
        gadget_translator->cleanup_gadget(gadget);
        if (ret) {
                _E("Unable to configure gadget: %d", ret);
-               return ret;
+               goto out;
        }
 
        _I("USB gadget changed to %d.", mode);
 
        return ret;
 
-no_hal:
+out:
        /* TODO. Maybe some default action here? */
-       return -ENODEV;
+       usb_state_set_current_mode(USB_FUNCTION_NONE); /* because usb does not work properly */
+       return ret;
 }
 
 static int usb_enable(unsigned int mode)
@@ -271,7 +274,8 @@ static int usb_enable(unsigned int mode)
 
        if (usb_state_get_connection() != USB_CONNECTED) {
                _E("Failed to enable usb gadget (USB cable is not connected).");
-               return -ENOTSUP;
+               ret = -ENOTSUP;
+               goto out;
        }
 
        if (usb_state_get_current_mode() != USB_FUNCTION_NONE)
@@ -280,7 +284,7 @@ static int usb_enable(unsigned int mode)
        ret = usb_config_enable();
        if (ret < 0) {
                _E("Failed to enable usb config: %d", ret);
-               return ret;
+               goto out;
        }
 
        usb_state_update_state(USB_CONNECTED, mode);
@@ -289,6 +293,10 @@ static int usb_enable(unsigned int mode)
                disp_plgn.pm_lock_internal(INTERNAL_LOCK_USB, LCD_OFF, STAY_CUR_STATE, 0);
 
        return 0;
+
+out:
+       usb_state_set_current_mode(USB_FUNCTION_NONE); /* because usb does not work properly */
+       return ret;
 }
 
 static int usb_disable(void)
@@ -303,13 +311,16 @@ static int usb_disable(void)
        }
 
        ret = usb_config_disable();
-       if (ret != 0)
+       if (ret != 0) {
+               usb_state_set_current_mode(USB_FUNCTION_NONE); /* because usb does not work properly */
                _E("Failed to disable usb config: %d", ret);
+               /* You have to keep going to unlock disp_plgn.pm_unlock_internal */
+       }
 
        if (disp_plgn.pm_unlock_internal)
                disp_plgn.pm_unlock_internal(INTERNAL_LOCK_USB, LCD_OFF, STAY_CUR_STATE);
 
-       return 0;
+       return ret;
 }
 
 static int usb_connected(void)
@@ -348,35 +359,48 @@ static int usb_disconnected(void)
 }
 
 /* Called by dbus signal and vconf change(tethering, debug mode) */
-int usb_change_mode(unsigned mode)
+int usb_change_mode(unsigned new_mode)
 {
        int ret;
-       unsigned int curr = usb_state_get_current_mode();
+       const unsigned int curr_mode = usb_state_get_current_mode();
+       const unsigned int prev_mode = usb_state_get_selected_mode();
 
-       if (curr != USB_FUNCTION_NONE) {
-               ret = usb_disable();
+       _I("usb change mode (0x%x) -> (0x%x), current running mode 0x%x", prev_mode, new_mode, curr_mode);
+
+       /*
+        * Even if the usb cable is plugged in, the current mode may be NULL due to usb fail.
+        * So to find out which mode you are in, you should use the current mode, not the selected mode.
+       */
+       if (curr_mode != USB_FUNCTION_NONE) {
+               ret = usb_disable(); /* Need to clean up because usb_change_gadget() also do usb_client->disable() */
                if (ret < 0) {
                        _E("Failed to disable current usb mode.");
                        return ret;
                }
        }
 
-       ret = usb_change_gadget(mode);
+       /*
+        * You should always change the gadget once when the usb mode is changed.
+        * In this state, usb_enable() is called when the usb cable is connected.
+        * A usb_enable() is called when the usb cable is disconnected.
+        */
+       ret = usb_change_gadget(new_mode);
        if (ret < 0) {
                _E("Failed to change gadget: %d", ret);
-               mode = usb_state_get_selected_mode();
+               return ret;
        }
 
-       (void)usb_state_set_selected_mode(mode);
-
        if (usb_state_get_connection() == USB_CONNECTED) {
-               ret = usb_enable(mode);
+               ret = usb_enable(new_mode);
                if (ret < 0) {
                        _E("Failed to enable usb mode: %d", ret);
                        return ret;
                }
        }
 
+       /* If you success to change the runtime usb configuration, do change the selected mode. */
+       (void)usb_state_set_selected_mode(new_mode);
+
        return 0;
 }