diff --git a/src/usb_moded-android.c b/src/usb_moded-android.c index b568c22..e69b866 100644 --- a/src/usb_moded-android.c +++ b/src/usb_moded-android.c @@ -23,6 +23,7 @@ #include #include +#include "usb_moded.h" #include "usb_moded-android.h" #include "usb_moded-log.h" #include "usb_moded-modesetting.h" @@ -84,11 +85,17 @@ void android_init_values(void) { gchar *text; + /* If the directory is not there, no point emitting warnings + * about every file that is not going to be there either. */ if( access("/sys/class/android_usb/android0", F_OK) != 0 ) { goto EXIT; } + /* Disable */ + write_to_file("/sys/class/android_usb/android0/enable", "0"); + + /* Configure */ if( (text = get_android_serial()) ) { write_to_file("/sys/class/android_usb/android0/iSerial", text); @@ -128,8 +135,22 @@ void android_init_values(void) /* For rndis to be discovered correctly in M$ Windows (vista and later) */ write_to_file("/sys/class/android_usb/f_rndis/wceis", "1"); - /* Make sure android_usb does not stay disabled in case usb moded - * has crashed / been killed in inconvenient time. */ + + /* Some devices can have enumeration issues due to incomplete + * configuration on the 1st connect after bootup. Briefly setting + * up for example mass_storage function can be utilized as a + * workaround in such cases. */ + if(!init_done_p()) { + const char *function = get_android_bootup_function(); + if(function) { + write_to_file("/sys/class/android_usb/android0/functions", function); + write_to_file("/sys/class/android_usb/android0/enable", "1"); + write_to_file("/sys/class/android_usb/android0/enable", "0"); + } + } + + /* Clear functions and enable */ + write_to_file("/sys/class/android_usb/android0/functions", "none"); write_to_file("/sys/class/android_usb/android0/enable", "1"); EXIT: diff --git a/src/usb_moded-dbus.c b/src/usb_moded-dbus.c index 0c8caec..96c703c 100644 --- a/src/usb_moded-dbus.c +++ b/src/usb_moded-dbus.c @@ -194,6 +194,9 @@ static DBusHandlerResult msg_handler(DBusConnection *const connection, DBusMessa if( type == DBUS_MESSAGE_TYPE_SIGNAL ) { if( !strcmp(interface, INIT_DONE_INTERFACE) && !strcmp(member, INIT_DONE_SIGNAL) ) { + /* Update the cached state value */ + set_init_done(true); + /* Auto-disable rescue mode when bootup is finished */ if( rescue_mode ) { rescue_mode = FALSE; @@ -598,6 +601,9 @@ gboolean usb_moded_dbus_init_connection(void) /* Listen to init-done signals */ dbus_bus_add_match(dbus_connection_sys, INIT_DONE_MATCH, 0); + /* Re-check flag file after adding signal listener */ + probe_init_done(); + /* Connect D-Bus to the mainloop */ dbus_connection_setup_with_g_main(dbus_connection_sys, NULL); diff --git a/src/usb_moded.c b/src/usb_moded.c index 2064d95..455123b 100644 --- a/src/usb_moded.c +++ b/src/usb_moded.c @@ -92,6 +92,30 @@ static gboolean android_ignore_next_udev_disconnect_event = FALSE; static gboolean systemd_notify = FALSE; #endif +/** Optional android usb function to setup during bootup */ +static gchar *android_bootup_function = 0; + + +/** Get android usb function to setup during bootup + * + * @returns function name, or NULL if no function was requested + */ +const char *get_android_bootup_function(void) +{ + return android_bootup_function; +} + +/** Set android usb function to setup during bootup + * + * @param function usb function name, or NULL + */ +void set_android_bootup_function(const char *function) +{ + char *value = function ? g_strdup(function) : 0; + g_free(android_bootup_function); + android_bootup_function = value; +} + /** Default allowed cable detection delay * * To comply with USB standards, the delay should be @@ -150,7 +174,6 @@ static gboolean set_disconnected_silent(gpointer data); static void usb_moded_init(void); static gboolean charging_fallback(gpointer data); static void usage(void); -static bool init_done_p(void); /* ============= Implementation starts here =========================================== */ /** set the usb connection status @@ -850,24 +873,41 @@ static void usage(void) { fprintf(stdout, "Usage: usb_moded [OPTION]...\n" - "USB mode daemon\n" - "\n" - " -a, --android_usb_broken \tkeep gadget active on broken android kernels\n" - " -i, --android_usb_broken_udev_events \tignore incorrect disconnect events after mode setting\n" - " -f, --fallback \tassume always connected\n" - " -s, --force-syslog \t\tlog to syslog\n" - " -T, --force-stderr \t\tlog to stderr\n" - " -l, --log-line-info \t\tlog to stderr and show origin of logging\n" - " -D, --debug \t\tturn on debug printing\n" - " -d, --diag \t\tturn on diag mode\n" - " -h, --help \t\tdisplay this help and exit\n" - " -r, --rescue \t\trescue mode\n" + "USB mode daemon\n" + "\n" + " -a, --android_usb_broken\n" + " keep gadget active on broken android kernels\n" + " -i, --android_usb_broken_udev_events\n" + " ignore incorrect disconnect events after mode setting\n" + " -f, --fallback \n" + " assume always connected\n" + " -s, --force-syslog \n" + " log to syslog\n" + " -T, --force-stderr \n" + " log to stderr\n" + " -l, --log-line-info\n" + " log to stderr and show origin of logging\n" + " -D, --debug \n" + " turn on debug printing\n" + " -d, --diag \n" + " turn on diag mode\n" + " -h, --help \n" + " display this help and exit\n" + " -r, --rescue \n" + " rescue mode\n" #ifdef SYSTEMD - " -n, --systemd \t\tnotify systemd when started up\n" + " -n, --systemd \n" + " notify systemd when started up\n" #endif - " -v, --version \t\toutput version information and exit\n" - " -m, --max-cable-delay=\tmaximum delay before accepting cable connection\n" - "\n"); + " -v, --version \n" + " output version information and exit\n" + " -m, --max-cable-delay=\n" + " maximum delay before accepting cable connection\n" + " -b, --android-bootup-function=\n" + " Setup given function during bootup. Might be required\n" + " on some devices to make enumeration work on the 1st\n" + " cable connect.\n" + "\n"); } void send_supported_modes_signal(void) @@ -1192,13 +1232,35 @@ void delay_suspend(void) allow_suspend_cb, 0); } +/** Path to init-done flag file */ +static const char init_done_flagfile[] = "/run/systemd/boot-status/init-done"; + +/** cached init-done-reached state */ +static bool init_done_reached = false; + /** Check if system has already been successfully booted up * * @return true if init-done has been reached, or false otherwise */ -static bool init_done_p(void) +bool init_done_p(void) +{ + return init_done_reached; +} + +/** Update cached init-done-reached state */ +void set_init_done(bool reached) +{ + if( init_done_reached != reached ) { + init_done_reached = reached; + log_debug("init_done -> %s", + init_done_reached ? "reached" : "not reached"); + } +} + +/** Check whether init-done flag file exists */ +void probe_init_done(void) { - return access("/run/systemd/boot-status/init-done", F_OK) == 0; + set_init_done(access(init_done_flagfile, F_OK) == 0); } /** Request orderly exit from mainloop @@ -1298,6 +1360,7 @@ int main(int argc, char* argv[]) { "systemd", no_argument, 0, 'n' }, { "version", no_argument, 0, 'v' }, { "max-cable-delay", required_argument, 0, 'm' }, + { "android-bootup-function", required_argument, 0, 'b' }, { 0, 0, 0, 0 } }; @@ -1309,7 +1372,7 @@ int main(int argc, char* argv[]) * - - - - - - - - - - - - - - - - - - - */ /* Parse the command-line options */ - while ((opt = getopt_long(argc, argv, "aifsTlDdhrnvm:", options, &opt_idx)) != -1) + while ((opt = getopt_long(argc, argv, "aifsTlDdhrnvm:b:", options, &opt_idx)) != -1) { switch (opt) { @@ -1363,6 +1426,10 @@ int main(int argc, char* argv[]) set_cable_connection_delay(strtol(optarg, 0, 0)); break; + case 'b': + set_android_bootup_function(optarg); + break; + default: usage(); exit(0); @@ -1394,6 +1461,9 @@ int main(int argc, char* argv[]) g_thread_init(NULL); #endif + /* Check if we are in mid-bootup */ + probe_init_done(); + /* Must be the 1st libdbus call that is made */ dbus_threads_init_default(); @@ -1565,6 +1635,8 @@ int main(int argc, char* argv[]) # endif #endif + set_android_bootup_function(0); + /* Must be done just before exit to make sure no more wakelocks * are taken and left behind on exit path */ allow_suspend(); diff --git a/src/usb_moded.h b/src/usb_moded.h index f16df5f..9e71e8b 100644 --- a/src/usb_moded.h +++ b/src/usb_moded.h @@ -25,6 +25,7 @@ #define USB_MODED_H_ #include +#include #include #include #include @@ -103,4 +104,11 @@ void usb_moded_usleep_(const char *file, int line, const char *func, useconds_t #define usb_moded_msleep(msec) usb_moded_usleep_(__FILE__,__LINE__,__FUNCTION__,(msec)*1000) #define usb_moded_sleep(sec) usb_moded_usleep_(__FILE__,__LINE__,__FUNCTION__,(sec)*1000000) +bool init_done_p(void); +void set_init_done(bool reached); +void probe_init_done(void); + +const char *get_android_bootup_function(void); +void set_android_bootup_function(const char *function); + #endif /* USB_MODED_H */