From 64350689dbf61b6a5c5cc09a2f2c05dfb352ee95 Mon Sep 17 00:00:00 2001 From: Simo Piiroinen Date: Fri, 17 Aug 2018 14:09:24 +0300 Subject: [PATCH] [usb_moded] Refactor entering/leaving usb mode. JB#41748 Split mode switching to three layers: Tracking cable connection state, choosing target mode, and performing required actions to activate the chosen mode. Try to minimize places where layer borders are crossed - which should work also as an enabler for moving blocking actions to separate thread later on. Arrange logic in such manner that usb gadget is always configured as being able to serve some function - fallback being the dummy mass_storage function used for charging. Deprecate command line options that serve no useful purpose after the changes. Signed-off-by: Simo Piiroinen --- src/usb_moded-appsync.c | 4 +- src/usb_moded-appsync.h | 1 + src/usb_moded-config.c | 1 - src/usb_moded-dbus.c | 1 - src/usb_moded-modesetting.c | 273 +++++++++++++++++++++--------------- src/usb_moded-modesetting.h | 6 +- src/usb_moded-modules.c | 208 +++------------------------ src/usb_moded-modules.h | 3 - src/usb_moded-trigger.c | 2 - src/usb_moded.c | 192 +++++++++---------------- src/usb_moded.h | 2 +- 11 files changed, 252 insertions(+), 441 deletions(-) diff --git a/src/usb_moded-appsync.c b/src/usb_moded-appsync.c index 8279aa6..ae4e303 100644 --- a/src/usb_moded-appsync.c +++ b/src/usb_moded-appsync.c @@ -62,7 +62,7 @@ static gboolean appsync_enumerate_usb_cb (gpointer data); static void appsync_start_enumerate_usb_timer (void); static void appsync_cancel_enumerate_usb_timer(void); static void appsync_enumerate_usb (void); -static void appsync_stop_apps (int post); +void appsync_stop_apps (int post); int appsync_stop (gboolean force); /* ========================================================================= * @@ -456,7 +456,7 @@ static void appsync_enumerate_usb(void) #endif /* APP_SYNC_DBUS */ } -static void appsync_stop_apps(int post) +void appsync_stop_apps(int post) { GList *iter = 0; diff --git a/src/usb_moded-appsync.h b/src/usb_moded-appsync.h index 5ade098..751f8d2 100644 --- a/src/usb_moded-appsync.h +++ b/src/usb_moded-appsync.h @@ -80,5 +80,6 @@ int appsync_activate_sync (const char *mode); int appsync_activate_sync_post(const char *mode); int appsync_mark_active (const gchar *name, int post); int appsync_stop (gboolean force); +void appsync_stop_apps (int post); #endif /* USB_MODED_APPSYNC_H_ */ diff --git a/src/usb_moded-config.c b/src/usb_moded-config.c index 977e564..4f97338 100644 --- a/src/usb_moded-config.c +++ b/src/usb_moded-config.c @@ -591,7 +591,6 @@ set_config_result_t config_set_mode_whitelist(const char *whitelist) else if (strcmp(current_mode, MODE_CHARGING_FALLBACK) && strcmp(current_mode, MODE_ASK) && usbmoded_valid_mode(current_mode)) { /* Invalid mode that is not MODE_ASK or MODE_CHARGING_FALLBACK * -> switch to MODE_CHARGING_FALLBACK */ - modesetting_cleanup(usbmoded_get_usb_module()); usbmoded_set_usb_mode(MODE_CHARGING_FALLBACK); } diff --git a/src/usb_moded-dbus.c b/src/usb_moded-dbus.c index ba9b2fd..0088abc 100644 --- a/src/usb_moded-dbus.c +++ b/src/usb_moded-dbus.c @@ -283,7 +283,6 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB /* do not change mode if the mode requested is the one already set */ if(strcmp(use, usbmoded_get_usb_mode()) != 0) { - modesetting_cleanup(usbmoded_get_usb_module()); usbmoded_set_usb_mode(use); } if((reply = dbus_message_new_method_return(msg))) diff --git a/src/usb_moded-modesetting.c b/src/usb_moded-modesetting.c index 0b27189..4d781d4 100644 --- a/src/usb_moded-modesetting.c +++ b/src/usb_moded-modesetting.c @@ -61,13 +61,12 @@ void modesetting_verify_values (void); static char *modesetting_strip (char *str); static char *modesetting_read_from_file (const char *path, size_t maxsize); int modesetting_write_to_file_real (const char *file, int line, const char *func, const char *path, const char *text); -static gboolean modesetting_network_retry (gpointer data); +static gboolean modesetting_network_retry_cb (gpointer data); static int modesetting_set_mass_storage_mode (struct mode_list_elem *data); static int modesetting_unset_mass_storage_mode (struct mode_list_elem *data); static void modesetting_report_mass_storage_blocker(const char *mountpoint, int try); -int modesetting_set_dynamic_mode (void); -static void modesetting_unset_dynamic_mode (void); -int modesetting_cleanup (const char *module); +bool modesetting_set_dynamic_mode (void); +void modesetting_unset_dynamic_mode (void); void modesetting_init (void); void modesetting_quit (void); @@ -76,7 +75,7 @@ void modesetting_quit (void); * ========================================================================= */ static GHashTable *tracked_values = 0; -static guint delayed_network = 0; +static guint modesetting_network_retry_id = 0; /* ========================================================================= * * Functions @@ -265,9 +264,9 @@ int modesetting_write_to_file_real(const char *file, int line, const char *func, return err; } -static gboolean modesetting_network_retry(gpointer data) +static gboolean modesetting_network_retry_cb(gpointer data) { - delayed_network = 0; + modesetting_network_retry_id = 0; network_up(data); return(FALSE); } @@ -368,11 +367,11 @@ umount: command = g_strconcat("mount | grep ", mountpath, NULL); } else { - write_to_file(ANDROID0_ENABLE, "0"); + android_set_enabled(false); write_to_file(ANDROID0_FUNCTIONS, "mass_storage"); //write_to_file("/sys/class/android_usb/f_mass_storage/lun/nofua", fua); write_to_file("/sys/class/android_usb/f_mass_storage/lun/file", mount); - write_to_file(ANDROID0_ENABLE, "1"); + android_set_enabled(true); } } @@ -445,7 +444,7 @@ static int modesetting_unset_mass_storage_mode(struct mode_list_elem *data) { log_debug("Disable android mass storage\n"); write_to_file("/sys/class/android_usb/f_mass_storage/lun/file", "0"); - write_to_file(ANDROID0_ENABLE, "0"); + android_set_enabled(false); } } else @@ -499,81 +498,98 @@ static void modesetting_report_mass_storage_blocker(const char *mountpoint, int } -int modesetting_set_dynamic_mode(void) +bool modesetting_set_dynamic_mode(void) { + bool ack = false; + struct mode_list_elem *data; - int ret = 1; int network = 1; - data = usbmoded_get_usb_mode_data(); + log_debug("DYNAMIC MODE: SETUP"); - if(!data) - return(ret); + /* - - - - - - - - - - - - - - - - - - - * + * Is a dynamic mode? + * - - - - - - - - - - - - - - - - - - - */ - if(data->mass_storage) - { - return modesetting_set_mass_storage_mode(data); + if( !(data = usbmoded_get_usb_mode_data()) ) { + log_debug("No dynamic mode data to setup"); + goto EXIT; + } + + log_debug("data->mass_storage = %d", data->mass_storage); + log_debug("data->connman_tethering = %d", data->connman_tethering); + log_debug("data->appsync = %d", data->appsync); + log_debug("data->network = %d", data->network); + + /* - - - - - - - - - - - - - - - - - - - * + * Is a mass storage dynamic mode? + * - - - - - - - - - - - - - - - - - - - */ + + if( data->mass_storage ) { + log_debug("Dynamic mode is mass storage"); + ack = modesetting_set_mass_storage_mode(data) == 0; + goto EXIT; } + /* - - - - - - - - - - - - - - - - - - - * + * Start pre-enum app sync + * - - - - - - - - - - - - - - - - - - - */ + #ifdef APP_SYNC - if(data->appsync) - if(appsync_activate_sync(data->mode_name)) /* returns 1 on error */ - { + if( data->appsync ) { + log_debug("Dynamic mode is appsync: do pre actions"); + if( appsync_activate_sync(data->mode_name) != 0 ) { log_debug("Appsync failure"); - return(ret); + goto EXIT; } + } #endif + + /* - - - - - - - - - - - - - - - - - - - * + * Configure gadget + * - - - - - - - - - - - - - - - - - - - */ + if( configfs_in_use() ) { /* Configfs based gadget configuration */ - char *id = config_get_android_vendor_id(); - configfs_set_udc(false); + configfs_set_function(data->sysfs_value); configfs_set_productid(data->idProduct); + char *id = config_get_android_vendor_id(); configfs_set_vendorid(data->idVendorOverride ?: id); - configfs_set_function(data->sysfs_value); - ret = configfs_set_udc(true) ? 0 : -1; free(id); + if( !configfs_set_udc(true) ) + goto EXIT; } else if( android_in_use() ) { /* Android USB based gadget configuration */ - - /* make sure things are disabled before changing functionality */ - write_to_file(data->softconnect_path, data->softconnect_disconnect); - - /* set functionality first, then enable */ - if(data->android_extra_sysfs_value) - ret = write_to_file(data->android_extra_sysfs_path, data->android_extra_sysfs_value); - else - ret = 0; - - /* ??? */ - write_to_file(data->android_extra_sysfs_path2, data->android_extra_sysfs_value2); - - /* only works for android since the idProduct is a module parameter */ + android_set_function(data->sysfs_value); android_set_productid(data->idProduct); - - /* only works for android since the idProduct is a module parameter */ - android_set_vendorid(data->idVendorOverride); - - write_to_file(data->sysfs_path, data->sysfs_value); - - /* enable the device */ - if( ret == 0 ) - ret = write_to_file(data->softconnect_path, data->softconnect); + char *id = config_get_android_vendor_id(); + android_set_vendorid(data->idVendorOverride ?: id); + free(id); + write_to_file(data->android_extra_sysfs_path, data->android_extra_sysfs_value); + write_to_file(data->android_extra_sysfs_path2, data->android_extra_sysfs_value2); + if( !android_set_enabled(true) ) + goto EXIT; } else if( modules_in_use() ) { /* Assume relevant module has already been successfully loaded * from somewhere else. */ - ret = 0; + // nop } else { log_crit("no backend is selected, can't set dynamic mode"); - ret = 1; + goto EXIT; } + /* - - - - - - - - - - - - - - - - - - - * + * Setup network + * - - - - - - - - - - - - - - - - - - - */ + /* functionality should be enabled, so we can enable the network now */ if(data->network) { + log_debug("Dynamic mode is network"); #ifdef DEBIAN char command[256]; @@ -590,9 +606,9 @@ int modesetting_set_dynamic_mode(void) if(network != 0 && data->network) { log_debug("Retry setting up the network later\n"); - if(delayed_network) - g_source_remove(delayed_network); - delayed_network = g_timeout_add_seconds(3, modesetting_network_retry, data); + if(modesetting_network_retry_id) + g_source_remove(modesetting_network_retry_id); + modesetting_network_retry_id = g_timeout_add_seconds(3, modesetting_network_retry_cb, data); } /* Needs to be called before application post synching so @@ -600,76 +616,122 @@ int modesetting_set_dynamic_mode(void) if(data->nat || data->dhcp_server) network_set_up_dhcpd(data); + /* - - - - - - - - - - - - - - - - - - - * + * Start post-enum app sync + * - - - - - - - - - - - - - - - - - - - */ + /* no need to execute the post sync if there was an error setting the mode */ - if(data->appsync && !ret) + if(data->appsync ) { + log_debug("Dynamic mode is appsync: do post actions"); /* let's sleep for a bit (350ms) to allow interfaces to settle before running postsync */ usbmoded_msleep(350); appsync_activate_sync_post(data->mode_name); } + /* - - - - - - - - - - - - - - - - - - - * + * Start tethering + * - - - - - - - - - - - - - - - - - - - */ + #ifdef CONNMAN - if(data->connman_tethering) + if( data->connman_tethering ) { + log_debug("Dynamic mode is tethering"); connman_set_tethering(data->connman_tethering, TRUE); + } #endif - if(ret) + ack = true; + +EXIT: + if( !ack ) umdbus_send_error_signal(MODE_SETTING_FAILED); - return(ret); + return ack; } -static void modesetting_unset_dynamic_mode(void) +void modesetting_unset_dynamic_mode(void) { + log_debug("DYNAMIC MODE: CLEANUP"); + struct mode_list_elem *data; data = usbmoded_get_usb_mode_data(); - if(delayed_network) + /* - - - - - - - - - - - - - - - - - - - * + * Do not leave timers behind + * - - - - - - - - - - - - - - - - - - - */ + + if(modesetting_network_retry_id) { - g_source_remove(delayed_network); - delayed_network = 0; + g_source_remove(modesetting_network_retry_id); + modesetting_network_retry_id = 0; } - /* the modelist could be empty */ - if(!data) - return; + /* - - - - - - - - - - - - - - - - - - - * + * Is a dynamic mode? + * - - - - - - - - - - - - - - - - - - - */ + if( !data ) { + log_debug("No dynamic mode data to cleanup"); + goto EXIT; + } - if(!strcmp(data->mode_name, MODE_MASS_STORAGE)) - { + log_debug("data->mass_storage = %d", data->mass_storage); + log_debug("data->connman_tethering = %d", data->connman_tethering); + log_debug("data->appsync = %d", data->appsync); + log_debug("data->network = %d", data->network); + + /* - - - - - - - - - - - - - - - - - - - * + * Is a mass storage dynamic mode? + * - - - - - - - - - - - - - - - - - - - */ + + if( data->mass_storage ) { + log_debug("Dynamic mode is mass storage"); modesetting_unset_mass_storage_mode(data); - return; + goto EXIT; } + /* - - - - - - - - - - - - - - - - - - - * + * Stop tethering + * - - - - - - - - - - - - - - - - - - - */ + #ifdef CONNMAN - if(data->connman_tethering) + if( data->connman_tethering ) { + log_debug("Dynamic mode was tethering"); connman_set_tethering(data->connman_tethering, FALSE); + } #endif - if(data->network) - { + /* - - - - - - - - - - - - - - - - - - - * + * Stop post-enum app sync + * - - - - - - - - - - - - - - - - - - - */ + + if(data->appsync ) { + log_debug("Dynamic mode was appsync: undo post actions"); + /* Just stop post enum appsync apps */ + appsync_stop_apps(1); + } + + /* - - - - - - - - - - - - - - - - - - - * + * Teardown network + * - - - - - - - - - - - - - - - - - - - */ + + if( data->network ) { + log_debug("Dynamic mode was network"); network_down(data); } + /* - - - - - - - - - - - - - - - - - - - * + * Configure gadget + * - - - - - - - - - - - - - - - - - - - */ + if( configfs_in_use() ) { /* Leave as is. We will reprogram wnen mode is * set, not when it is unset. */ } else if( android_in_use() ) { - /* disconnect before changing functionality */ - write_to_file(data->softconnect_path, data->softconnect_disconnect); - write_to_file(data->sysfs_path, data->sysfs_reset_value); - - /* restore vendorid if the mode had an override */ - if(data->idVendorOverride) - { - char *id = config_get_android_vendor_id(); - android_set_vendorid(id); - g_free(id); - } - - /* enable after the changes have been made */ - write_to_file(data->softconnect_path, data->softconnect); + /* Leave as is. We will reprogram wnen mode is + * set, not when it is unset. + */ } else if( modules_in_use() ) { /* Assume unloading happens somewhere else */ @@ -677,42 +739,21 @@ static void modesetting_unset_dynamic_mode(void) else { log_crit("no backend is selected, can't unset dynamic mode"); } -} - -/** clean up mode changes or extra actions to perform after a mode change - * @param module Name of module currently in use - * @return 0 on success, non-zero on failure - * - */ -int modesetting_cleanup(const char *module) -{ - log_debug("Cleaning up mode\n"); - - if(!module) - { - log_warning("No module found to unload. Skipping cleanup\n"); - return 0; - } + /* - - - - - - - - - - - - - - - - - - - * + * Stop pre-enum app sync + * - - - - - - - - - - - - - - - - - - - */ #ifdef APP_SYNC - /* Stop applications started due to entering this mode */ - appsync_stop(FALSE); -#endif /* APP_SYNC */ - - if(!strcmp(module, MODULE_MASS_STORAGE)|| !strcmp(module, MODULE_FILE_STORAGE)) - { - /* no clean-up needs to be done when we come from charging mode. We need - * to check since we use fake mass-storage for charging */ - if(!strcmp(MODE_CHARGING, usbmoded_get_usb_mode()) || !strcmp(MODE_CHARGING_FALLBACK, usbmoded_get_usb_mode())) - return 0; - modesetting_unset_mass_storage_mode(NULL); + if( data->appsync ) { + log_debug("Dynamic mode was appsync: undo all actions"); + /* Do full appsync cleanup */ + appsync_stop(false); } +#endif - else if(usbmoded_get_usb_mode_data()) - modesetting_unset_dynamic_mode(); - - return(0); +EXIT: + return; } /** Allocate modesetting related dynamic resouces diff --git a/src/usb_moded-modesetting.h b/src/usb_moded-modesetting.h index c4ed440..4640898 100644 --- a/src/usb_moded-modesetting.h +++ b/src/usb_moded-modesetting.h @@ -31,6 +31,8 @@ # include "usb_moded-dyn-config.h" +# include + /* ========================================================================= * * Prototypes * ========================================================================= */ @@ -39,8 +41,8 @@ void modesetting_verify_values (void); int modesetting_write_to_file_real(const char *file, int line, const char *func, const char *path, const char *text); -int modesetting_set_dynamic_mode (void); -int modesetting_cleanup (const char *module); +bool modesetting_set_dynamic_mode (void); +void modesetting_unset_dynamic_mode(void); void modesetting_init (void); void modesetting_quit (void); diff --git a/src/usb_moded-modules.c b/src/usb_moded-modules.c index 12f70df..aae64d8 100644 --- a/src/usb_moded-modules.c +++ b/src/usb_moded-modules.c @@ -56,19 +56,22 @@ bool modules_in_use (void); void modules_quit (void); int modules_load_module (const char *module); int modules_unload_module (const char *module); -static int modules_module_is_loaded (const char *module); -const char *modules_get_loaded_module (void); -int modules_cleanup_module (const char *module); -static int modules_prepare_for_module_switch(int force); -void modules_check_module_state (const char *module_name); /* ========================================================================= * * Data * ========================================================================= */ +/** Availability of kernel module based gadget configuration functionality + * + * -1 = not checked yet + * 0 = not available + * 1 = chosen as means of gadget configuration for usb-moded + */ +static int modules_probed = -1; + /* kmod context - initialized at start in usbmoded_init by ctx_init() * and cleaned up by ctx_cleanup() functions */ -static struct kmod_ctx *ctx = 0; +static struct kmod_ctx *modules_ctx = 0; /* ========================================================================= * * Functions @@ -81,7 +84,7 @@ static bool modules_have_module(const char *module) bool ack = false; struct kmod_list *list = 0; - if( kmod_module_new_from_lookup(ctx, module, &list) < 0 ) + if( kmod_module_new_from_lookup(modules_ctx, module, &list) < 0 ) goto EXIT; if( list == 0 ) @@ -98,8 +101,6 @@ static bool modules_have_module(const char *module) } -static int modules_probed = -1; - bool modules_in_use(void) { if( modules_probed < 0 ) @@ -140,12 +141,12 @@ bool modules_init(void) { bool ack = false; - if( !ctx ) { - if( !(ctx = kmod_new(NULL, NULL)) ) + if( !modules_ctx ) { + if( !(modules_ctx = kmod_new(NULL, NULL)) ) goto EXIT; } - if( kmod_load_resources(ctx) < 0 ) + if( kmod_load_resources(modules_ctx) < 0 ) goto EXIT; if( !modules_probe() ) @@ -159,8 +160,8 @@ bool modules_init(void) /* kmod module cleanup */ void modules_quit(void) { - if( ctx ) - kmod_unref(ctx), ctx = 0; + if( modules_ctx ) + kmod_unref(modules_ctx), modules_ctx = 0; } /** load module @@ -206,14 +207,14 @@ int modules_load_module(const char *module) g_strfreev(strings); } - ret = kmod_module_new_from_name(ctx, load, &mod); + ret = kmod_module_new_from_name(modules_ctx, load, &mod); /* since kmod_module_new_from_name does not check if the module * exists we test it's path in case we deal with the mass-storage one */ if(!strcmp(module, MODULE_MASS_STORAGE) && (kmod_module_get_path(mod) == NULL)) { log_debug("Fallback on older g_file_storage\n"); - ret = kmod_module_new_from_name(ctx, MODULE_FILE_STORAGE, &mod); + ret = kmod_module_new_from_name(modules_ctx, MODULE_FILE_STORAGE, &mod); } if(!charging_args) @@ -253,182 +254,9 @@ int modules_unload_module(const char *module) return -1; } - kmod_module_new_from_name(ctx, module, &mod); + kmod_module_new_from_name(modules_ctx, module, &mod); ret = kmod_module_remove_module(mod, KMOD_REMOVE_NOWAIT); kmod_module_unref(mod); return(ret); } - -/** Check which state a module is in - * - * @return 1 if loaded, 0 when not loaded - */ -static int modules_module_is_loaded(const char *module) -{ - int ret = 0; - struct kmod_module *mod; - - kmod_module_new_from_name(ctx, module, &mod); - ret = kmod_module_get_initstate(mod); - kmod_module_unref(mod); - if( ret == KMOD_MODULE_LIVE) - return 1; - - return 0; -} - -/** find which module is loaded - * - * @return The name of the loaded module, or NULL if no modules are loaded. - */ -const char * modules_get_loaded_module(void) -{ - if( !modules_in_use() ) { - log_warning("get loaded module - without module support"); - return 0; - } - - if(modules_module_is_loaded("g_ether")) - return(MODULE_DEVELOPER); - - if(modules_module_is_loaded("g_ncm")) - return("g_ncm"); - - if(modules_module_is_loaded("g_ffs")) - return(MODULE_MTP); - - if(modules_module_is_loaded("g_mass_storage")) - return(MODULE_MASS_STORAGE); - - if(modules_module_is_loaded("g_file_storage")) - return(MODULE_FILE_STORAGE); - - if(modules_module_is_loaded(usbmoded_get_usb_module())) - return(usbmoded_get_usb_module()); - - /* no module loaded */ - return(0); -} - -/** clean up for modules when usb gets disconnected - * - * @param module The name of the module to unload - * @return 0 on success, non-zero on failure - * - */ -int modules_cleanup_module(const char *module) -{ - int retry = 0, failure; - - if(!strcmp(module, MODULE_NONE)) - goto END; - - if( !modules_in_use() ) { - log_warning("cleanup module %s - without module support", module); - goto END; - } - - /* wait a bit for all components listening on dbus to clean up their act - * usbmoded_sleep(2); */ - /* check if things were not reconnected in that timespan - * if(usbmoded_get_connection_state()) - * return(0); - */ - - failure = modules_unload_module(module); - - /* if we have MODULE_MASS_STORAGE it might be MODULE_FILE_STORAGE might - * be loaded. So check and unload that one if unloading fails first time */ - if(failure && !strcmp(MODULE_MASS_STORAGE, module)) - failure = modules_unload_module(MODULE_FILE_STORAGE); - - /* if it still failed it might be the mode has not been cleaned-up correctly, - * so we clean up the mode to be sure */ - if(failure) - { - modesetting_cleanup(modules_get_loaded_module()); - } - - while(failure) - { - /* module did not get unloaded. We will wait a bit and try again */ - usbmoded_sleep(1); - /* send the REALLY disconnect message */ - umdbus_send_state_signal(USB_REALLY_DISCONNECT); - failure = modules_unload_module(module); - log_debug("unloading failure = %d\n", failure); - if(!failure) - break; - if(!modules_get_loaded_module()) - goto END; - retry++; - if(retry == 2) - break; - } - if(!failure) - log_info("Module %s unloaded successfully\n", module); - else - { - log_err("Module %s did not unload! Failing and going to undefined.\n", module); - return(1); - } -END: - return(0); -} - -/** try to unload modules to support switching - * - * - * @param force force unloading with a nasty clean-up on TRUE, or just try unloading when FALSE - * @return 0 on success, 1 on failure, 2 if hard clean-up failed - */ - -static int modules_prepare_for_module_switch (int force) -{ - if( !modules_in_use() ) { - log_warning("prep for module switch force=%d - without module support", force); - return 0; - } - - const char *unload; - int ret = 1; - - unload = modules_get_loaded_module(); - if(unload) - { - if(force) - ret = modules_cleanup_module(unload); - else - ret = modules_unload_module(unload); - } - if(ret && force) - return(2); - return ret; -} - -/** check for loaded modules and clean-up if they are not for the chosen mode - * - * @param module_name module name to check for - * - */ -void modules_check_module_state(const char *module_name) -{ - if( !modules_in_use() ) { - log_warning("check module %s state - without module support", module_name); - return; - } - - const char *module; - - module = modules_get_loaded_module(); - if(module != NULL) - { - /* do nothing if the right module is already loaded */ - if(strcmp(module, module_name) != 0) - { - log_debug("%s not loaded, cleaning up\n", module_name); - modules_prepare_for_module_switch(TRUE); - } - } -} diff --git a/src/usb_moded-modules.h b/src/usb_moded-modules.h index 20f9cb5..2367c95 100644 --- a/src/usb_moded-modules.h +++ b/src/usb_moded-modules.h @@ -53,8 +53,5 @@ bool modules_init (void); void modules_quit (void); int modules_load_module (const char *module); int modules_unload_module (const char *module); -const char *modules_get_loaded_module (void); -int modules_cleanup_module (const char *module); -void modules_check_module_state(const char *module_name); #endif /* USB_MODED_MODULES_H_ */ diff --git a/src/usb_moded-trigger.c b/src/usb_moded-trigger.c index 589131d..a42b770 100644 --- a/src/usb_moded-trigger.c +++ b/src/usb_moded-trigger.c @@ -235,7 +235,6 @@ static void trigger_parse_udev_properties(struct udev_device *dev) #endif /* MEEGOLOCK */ if(strcmp(config_get_trigger_mode(), usbmoded_get_usb_mode()) != 0) { - modesetting_cleanup(usbmoded_get_usb_module()); usbmoded_set_usb_mode(config_get_trigger_mode()); } free(trigger); @@ -254,7 +253,6 @@ static void trigger_parse_udev_properties(struct udev_device *dev) #endif /* MEEGOLOCK */ if(strcmp(config_get_trigger_mode(), usbmoded_get_usb_mode()) != 0) { - modesetting_cleanup(usbmoded_get_usb_module()); usbmoded_set_usb_mode(config_get_trigger_mode()); } } diff --git a/src/usb_moded.c b/src/usb_moded.c index b230135..7193b60 100644 --- a/src/usb_moded.c +++ b/src/usb_moded.c @@ -119,9 +119,6 @@ typedef struct usb_mode /** Mount status, true for mounted -UNUSED atm- */ bool mounted; - /** Used to keep an active gadget for broken Android kernels */ - bool android_usb_broken; - /** The logical mode name * * Full set of valid modes can occur here @@ -193,8 +190,6 @@ bool usbmoded_get_connection_state (void); static bool usbmoded_set_connection_state (bool state); // from usbmoded_set_usb_connected() -static void usbmoded_set_usb_disconnected_state_silent(void); -static void usbmoded_set_usb_disconnected_state (void); void usbmoded_set_usb_connected_state (void); // from udev cable_state_changed() @@ -211,7 +206,7 @@ int usbmoded_valid_mode (const char *mode); gchar *usbmoded_get_mode_list (mode_list_type_t type); const char *usbmoded_get_usb_module (void); -void usbmoded_set_usb_module (const char *module); +bool usbmoded_set_usb_module (const char *module); struct mode_list_elem *usbmoded_get_usb_mode_data (void); void usbmoded_set_usb_mode_data (struct mode_list_elem *data); @@ -263,9 +258,6 @@ static GMainLoop *usb_moded_mainloop = NULL; bool usbmoded_rescue_mode = false; static bool diag_mode = false; static bool hw_fallback = false; -static bool android_broken_usb = false; -static bool android_ignore_udev_events = false; -static bool android_ignore_next_udev_disconnect_event = false; #ifdef SYSTEMD static bool systemd_notify = false; #endif @@ -277,7 +269,6 @@ int usbmoded_cable_connection_delay = CABLE_CONNECTION_DELAY_DEFAULT; static struct usb_mode current_mode = { .connected = false, .mounted = false, - .android_usb_broken = false, .internal_mode = NULL, .hardware_mode = NULL, .external_mode = NULL, @@ -456,34 +447,18 @@ static bool usbmoded_switch_to_charging(void) { bool ack = true; - modules_check_module_state(MODULE_MASS_STORAGE); - - /* for charging we use a fake file_storage - * (blame USB certification for this insanity */ - - usbmoded_set_usb_module(MODULE_MASS_STORAGE); - - /* MODULE_CHARGING has all the parameters defined, - * so it will not match the g_file_storage rule in - * modules_load_module */ - - if( modules_load_module(MODULE_CHARGING) == 0 ) - goto SUCCESS; - - /* if charging mode setting did not succeed we - * might be dealing with android */ - - if (android_ignore_udev_events) - android_ignore_next_udev_disconnect_event = true; - - usbmoded_set_usb_module(MODULE_NONE); - if( android_set_charging_mode() ) goto SUCCESS; if( configfs_set_charging_mode() ) goto SUCCESS; + if( modules_in_use() ) { + if( usbmoded_set_usb_module(MODULE_MASS_STORAGE) ) + goto SUCCESS; + usbmoded_set_usb_module(MODULE_NONE); + } + log_err("switch to charging mode failed"); ack = false; @@ -494,7 +469,13 @@ static bool usbmoded_switch_to_charging(void) static void usbmoded_switch_to_mode(const char *mode) { /* set return to 1 to be sure to error out if no matching mode is found either */ - int ret=1; + + log_debug("Cleaning up previous mode"); + + if( usbmoded_get_usb_mode_data() ) { + modesetting_unset_dynamic_mode(); + usbmoded_set_usb_mode_data(NULL); + } log_debug("Setting %s\n", mode); @@ -532,26 +513,22 @@ static void usbmoded_switch_to_mode(const char *mode) continue; log_debug("Matching mode %s found.\n", mode); - modules_check_module_state(data->mode_module); - usbmoded_set_usb_module(data->mode_module); - ret = modules_load_module(data->mode_module); /* set data before calling any of the dynamic mode functions * as they will use the usbmoded_get_usb_mode_data function */ usbmoded_set_usb_mode_data(data); - /* check if modules are ok before continuing */ - if( ret == 0 ) { - if (android_ignore_udev_events) { - android_ignore_next_udev_disconnect_event = true; - } - ret = modesetting_set_dynamic_mode(); - if( ret == 0 ) - goto SUCCESS; - } + if( !usbmoded_set_usb_module(data->mode_module) ) + break; + + if( !modesetting_set_dynamic_mode() ) + break; + + goto SUCCESS; } log_warning("mode setting failed, fall back to charging"); + usbmoded_set_usb_mode_data(NULL); CHARGE: if( usbmoded_switch_to_charging() ) @@ -567,7 +544,6 @@ static void usbmoded_switch_to_mode(const char *mode) usbmoded_set_usb_module(MODULE_NONE); mode = MODE_UNDEFINED; - usbmoded_set_usb_mode_data(NULL); log_debug("mode setting failed or device disconnected, mode to set was = %s\n", mode); SUCCESS: @@ -643,18 +619,17 @@ const char * usbmoded_get_usb_mode(void) /** set the usb mode * * @param mode The requested USB mode - * */ -void usbmoded_set_usb_mode(const char *internal_mode) +void usbmoded_set_usb_mode(const char *mode) { gchar *previous = current_mode.internal_mode; - if( !g_strcmp0(previous, internal_mode) ) + if( !g_strcmp0(previous, mode) ) goto EXIT; log_debug("internal_mode: %s -> %s", - previous, internal_mode); + previous, mode); - current_mode.internal_mode = g_strdup(internal_mode); + current_mode.internal_mode = g_strdup(mode); g_free(previous); // PROPAGATE DOWN TO USB @@ -694,38 +669,9 @@ static bool usbmoded_set_connection_state(bool state) return changed; } -/* set disconnected without sending signals. */ -static void usbmoded_set_usb_disconnected_state_silent(void) -{ - if(!usbmoded_get_connection_state()) - { - log_debug("Resetting connection data after HUP\n"); - /* unload modules and general cleanup if not charging */ - if(strcmp(usbmoded_get_usb_mode(), MODE_CHARGING) || - strcmp(usbmoded_get_usb_mode(), MODE_CHARGING_FALLBACK)) - modesetting_cleanup(usbmoded_get_usb_module()); - /* Nothing else as we do not need to do anything for cleaning up charging mode */ - modules_cleanup_module(usbmoded_get_usb_module()); - usbmoded_set_usb_mode(MODE_UNDEFINED); - } -} - -static void usbmoded_set_usb_disconnected_state(void) -{ - /* signal usb disconnected */ - umdbus_send_state_signal(USB_DISCONNECTED); - - /* unload modules and general cleanup if not charging */ - if( strcmp(usbmoded_get_usb_mode(), MODE_CHARGING) && - strcmp(usbmoded_get_usb_mode(), MODE_CHARGING_FALLBACK)) - modesetting_cleanup(usbmoded_get_usb_module()); - - /* Nothing else as we do not need to do anything for cleaning up charging mode */ - modules_cleanup_module(usbmoded_get_usb_module()); - usbmoded_set_usb_mode(MODE_UNDEFINED); -} - /** set the chosen usb state + * + * gauge what mode to enter and then call usbmoded_set_usb_mode() * */ void usbmoded_set_usb_connected_state(void) @@ -817,16 +763,6 @@ void usbmoded_set_usb_connected_state(void) */ void usbmoded_set_usb_connected(bool connected) { - if( !connected && android_ignore_next_udev_disconnect_event ) { - /* FIXME: udev event processing is changed so that - * disconnect notifications are not repeated - * so whatever this is supposed to do - it is - * broken. - */ - android_ignore_next_udev_disconnect_event = false; - goto EXIT; - } - /* Do not go through the routine if already connected to avoid * spurious load/unloads due to faulty signalling * NOKIA: careful with devicelock @@ -839,22 +775,15 @@ void usbmoded_set_usb_connected(bool connected) /* signal usb connected */ umdbus_send_state_signal(USB_CONNECTED); + + /* choose mode, then call usbmoded_set_usb_mode(chosen_mode) + */ usbmoded_set_usb_connected_state(); } else { log_debug("usb disconnected\n"); - usbmoded_set_usb_disconnected_state(); - /* Some android kernels check for an active gadget to enable charging and - * cable detection, meaning USB is completely dead unless we keep the gadget - * active - */ - if(current_mode.android_usb_broken) { - android_set_charging_mode(); - configfs_set_charging_mode(); - } - if (android_ignore_udev_events) { - android_ignore_next_udev_disconnect_event = true; - } + umdbus_send_state_signal(USB_DISCONNECTED); + usbmoded_set_usb_mode(MODE_UNDEFINED); } EXIT: return; @@ -1038,7 +967,7 @@ gchar *usbmoded_get_mode_list(mode_list_type_t type) */ const char * usbmoded_get_usb_module(void) { - return current_mode.module; + return current_mode.module ?: MODULE_NONE; } /** set the loaded module @@ -1046,11 +975,35 @@ const char * usbmoded_get_usb_module(void) * @param module The module name for the requested mode * */ -void usbmoded_set_usb_module(const char *module) +bool usbmoded_set_usb_module(const char *module) { - char *old = current_mode.module; - current_mode.module = strdup(module); - free(old); + bool ack = false; + + if( !module ) + module = MODULE_NONE; + + const char *current = usbmoded_get_usb_module(); + + log_debug("current module: %s -> %s", current, module); + + if( !g_strcmp0(current, module) ) + goto SUCCESS; + + if( modules_unload_module(current) != 0 ) + goto EXIT; + + free(current_mode.module), current_mode.module = 0; + + if( modules_load_module(module) != 0 ) + goto EXIT; + + if( g_strcmp0(module, MODULE_NONE) ) + current_mode.module = strdup(module); + +SUCCESS: + ack = true; +EXIT: + return ack; } /** get the usb mode data @@ -1299,12 +1252,6 @@ static void usbmoded_handle_signal(int signum) } else if( signum == SIGHUP ) { - /* clean up current mode */ - usbmoded_set_usb_disconnected_state_silent(); - - /* clear existing data to be sure */ - usbmoded_set_usb_mode_data(NULL); - /* free and read in modelist again */ dynconfig_free_mode_list(modelist); @@ -1312,6 +1259,8 @@ static void usbmoded_handle_signal(int signum) usbmoded_send_supported_modes_signal(); usbmoded_send_available_modes_signal(); + + // FIXME invalidate current mode } else { @@ -1322,15 +1271,12 @@ static void usbmoded_handle_signal(int signum) /* set default values for usb_moded */ static void usbmoded_init(void) { - current_mode.connected = false; - current_mode.mounted = false; + current_mode.connected = false; + current_mode.mounted = false; current_mode.internal_mode = strdup(MODE_UNDEFINED); current_mode.hardware_mode = NULL; current_mode.external_mode = NULL; - current_mode.module = strdup(MODULE_NONE); - - if(android_broken_usb) - current_mode.android_usb_broken = true; + current_mode.module = NULL; /* check config, merge or create if outdated */ if(config_merge_conf_file() != 0) @@ -1711,10 +1657,10 @@ int main(int argc, char* argv[]) switch (opt) { case 'a': - android_broken_usb = true; + log_warning("Deprecated option: --android_usb_broken"); break; case 'i': - android_ignore_udev_events = true; + log_warning("Deprecated option: --android_usb_broken_udev_events"); break; case 'f': hw_fallback = true; diff --git a/src/usb_moded.h b/src/usb_moded.h index 858b30c..bfda9ff 100644 --- a/src/usb_moded.h +++ b/src/usb_moded.h @@ -118,7 +118,7 @@ void usbmoded_set_charger_connected (bool state); int usbmoded_valid_mode (const char *mode); gchar *usbmoded_get_mode_list (mode_list_type_t type); const char *usbmoded_get_usb_module (void); -void usbmoded_set_usb_module (const char *module); +bool usbmoded_set_usb_module (const char *module); struct mode_list_elem *usbmoded_get_usb_mode_data (void); void usbmoded_set_usb_mode_data (struct mode_list_elem *data); void usbmoded_send_supported_modes_signal (void);