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;
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);
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)
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)
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);
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)
}
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)
}
/* 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;
}