Commit 408170be authored by Philippe De Swert's avatar Philippe De Swert

* More robust udev (especially for N900)

* Improved and faster appsync courtesy of Simo Piiroinen
Signed-off-by: default avatarPhilippe De Swert <phdeswer@lumi.maa>
parent 0b9df5b7
......@@ -18,6 +18,7 @@
02110-1301 USA
*/
gboolean usb_moded_app_sync_init(GList *list);
void usb_moded_appsync_cleanup(GList *list);
gboolean usb_moded_app_sync_init(void);
void usb_moded_appsync_cleanup(void);
int usb_moded_dbus_app_launch(const char *launch);
gboolean usb_moded_app_sync_init_connection(void);
This diff is collapsed.
/**
@file usb_moded-appsync.c
Copyright (C) 2010 Nokia Corporation. All rights reserved.
@author: Philippe De Swert <philippe.de-swert@nokia.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the Lesser GNU General Public License
version 2 as published by the Free Software Foundation.
modify it under the terms of the Lesser GNU General Public License
version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <glib.h>
#include <glib/gstdio.h>
......@@ -31,176 +35,191 @@
#include "usb_moded-appsync.h"
#include "usb_moded-appsync-dbus.h"
#include "usb_moded-appsync-dbus-private.h"
#include "usb_moded-modesetting.h"
#include "usb_moded-log.h"
static struct list_elem *read_file(const gchar *filename);
GList *readlist(void)
static GList *sync_list = NULL;
static void free_elem(gpointer aptr)
{
GDir *confdir;
GList *applist = NULL;
const gchar *dirname;
struct list_elem *list_item;
struct list_elem *elem = aptr;
free(elem->name);
free(elem->launch);
free(elem);
}
confdir = g_dir_open(CONF_DIR_PATH, 0, NULL);
if(confdir)
static void free_list(void)
{
if( sync_list != 0 )
{
while((dirname = g_dir_read_name(confdir)) != NULL)
{
log_debug("Read file %s\n", dirname);
list_item = read_file(dirname);
if(list_item)
applist = g_list_append(applist, list_item);
}
g_dir_close(confdir);
g_list_free_full(sync_list, free_elem);
sync_list = 0;
}
else
log_debug("confdir open failed.\n");
return(applist);
}
static struct list_elem *read_file(const gchar *filename)
void readlist(void)
{
GKeyFile *settingsfile;
gboolean test = FALSE;
gchar **keys;
struct list_elem *list_item = NULL;
gchar *full_filename = NULL;
GDir *confdir = 0;
const gchar *dirname;
struct list_elem *list_item;
free_list();
full_filename = g_strconcat(CONF_DIR_PATH, "/", filename, NULL);
if( !(confdir = g_dir_open(CONF_DIR_PATH, 0, NULL)) )
goto cleanup;
settingsfile = g_key_file_new();
test = g_key_file_load_from_file(settingsfile, full_filename, G_KEY_FILE_NONE, NULL);
/* free full_filename immediately as we do not use it anymore */
free(full_filename);
if(!test)
while( (dirname = g_dir_read_name(confdir)) )
{
return(NULL);
log_debug("Read file %s\n", dirname);
if( (list_item = read_file(dirname)) )
sync_list = g_list_append(sync_list, list_item);
}
list_item = malloc(sizeof(struct list_elem));
keys = g_key_file_get_keys (settingsfile, APP_INFO_ENTRY , NULL, NULL);
while (*keys != NULL)
cleanup:
if( confdir ) g_dir_close(confdir);
/* set up session bus connection if app sync in use
* so we do not need to make the time consuming connect
* operation at enumeration time ... */
if( sync_list )
{
if(!strcmp(*keys, APP_INFO_NAME_KEY))
{
list_item->name = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, *keys, NULL);
log_debug("Appname = %s\n", list_item->name);
}
else if(!strcmp(*keys, APP_INFO_LAUNCH_KEY))
{
list_item->launch = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, *keys, NULL);
log_debug("launch path = %s\n", list_item->launch);
}
keys++;
usb_moded_app_sync_init_connection();
}
g_strfreev(keys);
g_key_file_free(settingsfile);
if(list_item->launch == NULL || list_item->name == NULL)
}
static struct list_elem *read_file(const gchar *filename)
{
gchar *full_filename = NULL;
GKeyFile *settingsfile = NULL;
struct list_elem *list_item = NULL;
if( !(full_filename = g_strconcat(CONF_DIR_PATH, "/", filename, NULL)) )
goto cleanup;
if( !(settingsfile = g_key_file_new()) )
goto cleanup;
if( !g_key_file_load_from_file(settingsfile, full_filename, G_KEY_FILE_NONE, NULL) )
goto cleanup;
if( !(list_item = calloc(1, sizeof *list_item)) )
goto cleanup;
list_item->name = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, APP_INFO_NAME_KEY, NULL);
log_debug("Appname = %s\n", list_item->name);
list_item->launch = g_key_file_get_string(settingsfile, APP_INFO_ENTRY, APP_INFO_LAUNCH_KEY, NULL);
log_debug("Launch = %s\n", list_item->name);
cleanup:
if(settingsfile)
g_key_file_free(settingsfile);
g_free(full_filename);
/* if not all the elements are filled in we discard the list_item */
if( list_item && !(list_item->launch && list_item->name) )
{
/* free list_item as it will not be used */
free(list_item);
return NULL;
free_elem(list_item), list_item = 0;
}
else
return(list_item);
return list_item;
}
int activate_sync(GList *list)
int activate_sync(void)
{
GList *list_iter;
GList *iter;
list_iter = list;
/* set list to inactive */
do
{
struct list_elem *data = list_iter->data;
data->active = 0;
list_iter = g_list_next(list_iter);
}
while(list_iter != NULL);
if( sync_list == 0 )
{
enumerate_usb(NULL);
return 0;
}
/* set list to inactive */
for( iter = sync_list; iter; iter = g_list_next(iter) )
{
struct list_elem *data = iter->data;
data->active = 0;
}
/* add dbus filter. Use session bus for ready method call? */
if(!usb_moded_app_sync_init(list))
{
if(!usb_moded_app_sync_init())
{
log_debug("dbus setup failed => activate immediately \n");
enumerate_usb(NULL);
return(1);
}
/* go through list and launch apps */
list_iter = list;
do
{
struct list_elem *data = list_iter->data;
log_debug("launching app %s\n", data->launch);
usb_moded_dbus_app_launch(data->launch);
list_iter = g_list_next(list_iter);
}
while(list_iter != NULL);
for( iter = sync_list; iter; iter = g_list_next(iter) )
{
struct list_elem *data = iter->data;
log_debug("launching app %s\n", data->launch);
usb_moded_dbus_app_launch(data->launch);
}
/* start timer */
log_debug("Starting timer\n");
g_timeout_add_seconds(2, enumerate_usb, list);
g_timeout_add_seconds(2, enumerate_usb, NULL);
return(0);
}
int mark_active(GList *list, const gchar *name)
int mark_active(const gchar *name)
{
int ret = 0;
static int list_length=0;
int counter=0;
GList *list_iter;
int ret = -1; // assume name not found
int missing = 0;
GList *iter;
log_debug("app %s notified it is ready\n", name);
if(list_length == 0)
list_length = g_list_length(list);
list_iter = list;
do
for( iter = sync_list; iter; iter = g_list_next(iter) )
{
struct list_elem *data = iter->data;
if(!strcmp(data->name, name))
{
struct list_elem *data = list_iter->data;
if(!strcmp(data->name, name))
{
if(!data->active)
{
data->active = 1;
counter++;
if(list_length == counter)
{
counter = 0;
log_debug("All apps active. Let's enumerate\n");
enumerate_usb(list);
}
ret = 0;
break;
}
else
{
ret = 1;
}
}
list_iter = g_list_next(list_iter);
/* TODO: do we need to worry about duplicate names in the list? */
ret = !data->active;
data->active = 1;
/* updated + missing -> not going to enumerate */
if( missing ) break;
}
while(list_iter != NULL);
else if( data->active == 0 )
{
missing = 1;
return(ret);
/* updated + missing -> not going to enumerate */
if( ret != -1 ) break;
}
}
if( !missing )
{
log_debug("All apps active. Let's enumerate\n");
enumerate_usb(NULL);
}
/* -1=not found, 0=already active, 1=activated now */
return ret;
}
gboolean enumerate_usb(gpointer data)
{
/* We arrive here twice: when app sync is done
* and when the app sync timeout gets triggered */
/* activate usb connection/enumeration */
system("echo 1 > /sys/devices/platform/musb_hdrc/gadget/softconnect");
write_to_file("/sys/devices/platform/musb_hdrc/gadget/softconnect", "1");
log_debug("Softconnect enumeration done\n");
/* no need to remove timer */
/* remove dbus filter */
if(data != NULL)
usb_moded_appsync_cleanup((GList *)data);
/* remove dbus service */
usb_moded_appsync_cleanup();
/* return false to stop the timer from repeating */
return(FALSE);
return FALSE;
}
......@@ -32,7 +32,7 @@ typedef struct list_elem
int active;
}list_elem;
GList *readlist(void);
int activate_sync(GList *list);
int mark_active(GList *list, const gchar *name);
void readlist(void);
int activate_sync(void);
int mark_active(const gchar *name);
gboolean enumerate_usb(gpointer data);
......@@ -20,6 +20,7 @@
02110-1301 USA
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
......@@ -57,6 +58,43 @@ int find_number_of_mounts(void)
}
#endif /* MAYBE_NEEDED */
int write_to_file(const char *path, const char *text)
{
int err = -1;
int fd = -1;
size_t todo = strlen(text);
/* no O_CREAT -> writes only to already existing files */
if( (fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY))) == -1 )
{
/* gcc -pedantic does not like "%m"
log_warning("open(%s): %m", path); */
log_warning("open(%s): %s", path, strerror(errno));
goto cleanup;
}
while( todo > 0 )
{
ssize_t n = TEMP_FAILURE_RETRY(write(fd, text, todo));
if( n < 0 )
{
log_warning("write(%s): %s", path, strerror(errno));
goto cleanup;
}
todo -= n;
text += n;
}
err = 0;
cleanup:
if( fd != -1 ) TEMP_FAILURE_RETRY(close(fd));
return err;
}
int set_mass_storage_mode(void)
{
gchar *command;
......@@ -137,11 +175,11 @@ umount: command = g_strconcat("mount | grep ", mounts[i], NULL);
sprintf(command2, "echo %i > /sys/devices/platform/musb_hdrc/gadget/gadget-lun%d/nofua", fua, i);
log_debug("usb lun = %s active\n", command2);
system(command2);
sprintf(command2, "echo %s > /sys/devices/platform/musb_hdrc/gadget/gadget-lun%d/file", mounts[i], i);
sprintf(command2, "/sys/devices/platform/musb_hdrc/gadget/gadget-lun%d/file", i);
log_debug("usb lun = %s active\n", command2);
system(command2);
}
g_strfreev(mounts);
write_to_file(command2, mounts[i]);
}
g_strfreev(mounts);
}
/* only send data in use signal in case we actually succeed */
......@@ -153,7 +191,7 @@ umount: command = g_strconcat("mount | grep ", mounts[i], NULL);
}
#ifdef N900
int set_ovi_suite_mode(GList *applist)
int set_ovi_suite_mode(void)
{
#ifdef NOKIA
int timeout = 1;
......@@ -161,13 +199,10 @@ int set_ovi_suite_mode(GList *applist)
#ifdef APP_SYNC
/* do not go through the appsync routine if there is no applist */
if(applist)
activate_sync(applist);
else
enumerate_usb(NULL);
activate_sync();
#else
system("echo 1 > /sys/devices/platform/musb_hdrc/gadget/softconnect");
//system("echo 1 > /sys/devices/platform/musb_hdrc/gadget/softconnect");
write_to_file("/sys/devices/platform/musb_hdrc/gadget/softconnect", "1");
#endif /* APP_SYNC */
/* bring network interface up in case no other network is up */
system("ifdown usb0 ; ifup usb0");
......@@ -186,7 +221,7 @@ int set_ovi_suite_mode(GList *applist)
#ifdef NOKIA
gboolean export_cdrom(gpointer data)
{
const char *path = NULL, *command = NULL;
const char *path = NULL;
path = find_cdrom_path();
......@@ -196,8 +231,7 @@ gboolean export_cdrom(gpointer data)
}
if(access(path, F_OK) == 0)
{
command = g_strconcat("echo ", path, " > /sys/devices/platform/musb_hdrc/gadget/gadget-lun0/file", NULL);
system(command);
write_to_file("/sys/devices/platform/musb_hdrc/gadget/gadget-lun0/file", path);
}
else
log_debug("Cdrom image file does not exist => no export.\n");
......@@ -277,7 +311,7 @@ int usb_moded_mode_cleanup(const char *module)
/* bring network down immediately */
system("ifdown usb0");
/* do soft disconnect */
system("echo 0 > /sys/devices/platform/musb_hdrc/gadget/softconnect");
write_to_file("/sys/devices/platform/musb_hdrc/gadget/softconnect", "0");
/* DIRTY WORKAROUND: acm/phonet does not work as it should, remove when it does */
system("killall -SIGTERM acm");
}
......
......@@ -23,8 +23,9 @@
#ifdef MAYBE_NEEDED
int find_number_of_mounts(void);
#endif
int write_to_file(const char *path, const char *text);
int set_mass_storage_mode(void);
int set_ovi_suite_mode(GList *applist);
int set_ovi_suite_mode(void);
int usb_moded_mode_cleanup(const char *module);
#ifdef NOKIA
gboolean export_cdrom (gpointer data);
......
......@@ -118,8 +118,8 @@ const char * usb_moded_find_module(void)
*/
int usb_moded_module_cleanup(const char *module)
{
int retry = 0, success;
int retry = 0, failure;
if(!strcmp(module, MODULE_NONE))
goto END;
/* wait a bit for all components listening on dbus to clean up their act
......@@ -129,22 +129,21 @@ int usb_moded_module_cleanup(const char *module)
return(0);
*/
success = usb_moded_unload_module(module);
// SP: variable 'success' holds error value?
while(success)
failure = usb_moded_unload_module(module);
while(failure)
{
// SP: up to 2 second sleep -> worth a warning log?
/* module did not get unloaded. We will wait a bit and try again */
sleep(1);
success = usb_moded_unload_module(module);
log_debug("unloading success = %d\n", success);
if(!success)
failure = usb_moded_unload_module(module);
log_debug("unloading failure = %d\n", failure);
if(!failure)
break;
if(!usb_moded_find_module())
goto END;
retry++;
if(retry == 2)
break;
// SP: up to 2 second sleep -> worth a warning log?
}
if(!strcmp(module, MODULE_NETWORK))
{
......@@ -167,8 +166,8 @@ kill:
// SP: system("kill -s SIGTERM $(lsof -t /dev/ttyGS* /dev/gc* /dev/mtp*") ?
// SP: or popen + kill loop?
/* try to unload again and give up if it did not work yet */
success = usb_moded_unload_module(module);
if(success && retry < 10)
failure = usb_moded_unload_module(module);
if(failure && retry < 10)
{
retry++;
// SP: NOTE: we have a root process in busyloop sending kill signals to
......@@ -176,7 +175,7 @@ kill:
goto kill;
// SP: IMHO backwards goto is bad - a loop perhaps?
}
if(success && retry == 10)
if(failure && retry == 10)
{
system("for i in `lsof -t /dev/ttyGS*`; do kill -9 $i ; done");
system("for i in `lsof -t /dev/gc*`; do kill -9 $i ; done");
......@@ -184,12 +183,12 @@ kill:
/* try again since there seem to be hard to kill processes there */
system("killall -9 obexd");
system("killall -9 msycnd");
success = usb_moded_unload_module(module);
failure = usb_moded_unload_module(module);
}
}
}
if(!success)
if(!failure)
log_info("Module %s unloaded successfully\n", module);
else
{
......
......@@ -54,7 +54,7 @@ gboolean hwal_init(void)
else
{
dev_name = udev_device_get_sysname(dev);
udev_device_unref(dev);
log_debug("device name = %s\n", dev_name);
}
mon = udev_monitor_new_from_netlink (udev, "udev");
if (!mon)
......
......@@ -57,10 +57,6 @@ gboolean special_mode = FALSE;
guint timeout_source = 0;
#endif /* NOKIA */
/*#ifdef APP_SYNC */
GList *applist = NULL;
/*#endif APP_SYNC */
/* static helper functions */
static void usb_moded_init(void);
static gboolean charging_fallback(gpointer data);
......@@ -214,7 +210,7 @@ void set_usb_mode(const char *mode)
set_usb_module(MODULE_NETWORK);
ret = usb_moded_load_module(MODULE_NETWORK_MTP);
if(!ret)
ret = set_ovi_suite_mode(applist);
ret = set_ovi_suite_mode();
}
#endif /* N900 */
......@@ -309,7 +305,7 @@ static void usb_moded_init(void)
#endif /* NOKIA */
#ifdef APP_SYNC
applist = readlist();
readlist();
#endif /* APP_SYNC */
/* TODO: add more start-up clean-up and init here if needed */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment