Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
improved dynamic modes, trigger and added docs
Signed-off-by: Philippe De Swert <philippedeswert@gmail.com>
  • Loading branch information
philippedeswert committed May 16, 2011
1 parent ac296c8 commit 6e1d204
Show file tree
Hide file tree
Showing 16 changed files with 490 additions and 13 deletions.
2 changes: 2 additions & 0 deletions TODO
@@ -0,0 +1,2 @@
* verify appsync/usb_moded functionality with multiple sessions
* Fix daemon mode
2 changes: 1 addition & 1 deletion configure.ac
Expand Up @@ -95,7 +95,7 @@ AM_CONDITIONAL([UDEV], [test x$udev = xtrue])


PKG_CHECK_MODULES([USB_MODED], [
glib-2.0 >= 2.28.0
glib-2.0 >= 2.24.0
dbus-1 >= 1.2.1
dbus-glib-1 >= 0.78
gobject-2.0 >= 2.16.6
Expand Down
5 changes: 4 additions & 1 deletion debian/changelog
Expand Up @@ -4,8 +4,11 @@ usb-moded (0.38) unstable; urgency=low
* Fix doxygen warnings and improve documentation
* Add dynamic mode support
* Add debug printing for finding who keeps the mass-storage device busy
* Add more aegis capabilities.
* Remove dependency on glib 2.28.0, glib 2.24.2 is enough now.
* Fix fallback mount options. Fixes: NB#255798

-- Philippe De Swert <philippe.de-swert@nokia.com> Tue, 03 May 2011 14:57:38 +0300
-- Philippe De Swert <philippe.de-swert@nokia.com> Mon May 16 13:06:17 EEST 2011

usb-moded (0.37) unstable; urgency=low

Expand Down
1 change: 1 addition & 0 deletions debian/usb-moded.aegis
Expand Up @@ -33,6 +33,7 @@
<credential name="CAP::net_admin" />
<credential name="CAP::sys_ptrace" />
<credential name="CAP::kill" />
<credential name="CAP::dac_override" />
<for path="/usr/sbin/usb_moded" />
</request>
</aegis>
Expand Down
190 changes: 190 additions & 0 deletions docs/usb_moded-doc.txt
@@ -0,0 +1,190 @@
USB_MODED use and API description/overview.
==========================================

Usb_moded is a relatively simple daemon which tracks the
usb cable connection status and activates a certain USB
profile based on that.
To do this it has a number of built in common profiles,
an optional application launcher (app_sync) and configurable
dynamic modes.

All the system wide communication goes over the DBus system bus,
while application launching is handled on the session bus.
Thus if you need this functionality, usb_moded needs to be started
with the session.
(functionality not verified yet on multi-user setups. See TODO)

Usb cable detection is supported by several different methods.
Old deprecated hal, through Nokia's own battery monitoring bme,
or the preferred udev option. (This has to be chosen at compile time)

Starting usb_moded
-------------------

Simply start with usb_moded.
usb_moded --help will give you more details

*NOTE: daemon mode does not work correctly. See TODO*


Status and configuration query/setting
---------------------------------------

The current status can be queried any time over DBus. From a program
using a method call or using dbus-send.

dbus-send --system --type=method_call --print-reply --dest=com.meego.usb_moded /com/meego/usb_moded com.meego.usb_moded.mode_request

Similary a mode can be set.

dbus-send --system --type=method_call --print-reply --dest=com.meego.usb_moded /com/meego/usb_moded com.meego.usb_moded.set_mode string:'<mode_name>'

Even the configuration can be set over DBus.

dbus-send --system --type=method_call --print-reply --dest=com.meego.usb_moded /com/meego/usb_moded com.meego.usb_moded.set_config string:'<mode_name>'

However this can also be handled by setting the following GConf key.

/Meego/System/UsbMode (querying and setting can be done as follows:

gconftool-2 -g /Meego/System/UsbMode
gconftool-2 -s /Meego/System/UsbMode --type=string <mode_name>

Usb_moded will also broadcast changes and errors over the system bus.
This will happen on the com.meego.usb_moded interface

For regular signals: sig_usb_state_ind
And errors: sig_usb_state_error_ind

More info and details in usb_moded-dbus.h

There is also a configuration file and some configuration directories under /etc/usb-moded
It should have some pre-filled fields for the default mass-storage profile

The first one would be mountpoints, this defines which device/filesystem entry should be
exported over mass-storage (this ideally also has an entry in /etc/fstab). You can add more
filesystems to the mount option, by making it a comma-seperated list in case there are
several exports (like internal mmc and sd card for example)

[mountpoints]
mount = /dev/mmcblk0p1

The following option plays with certain sync options that exist and have to be set per
fs and thus cannot be handled by setting them in /etc/modprobe.d/....conf

[sync]
nofua = 1

This mount is the alternative mountpoint for in case something goes wrong. Usb_moded
will mount a 512 RO tmpfs on that location to mitigate potential disasters on the system,
and make clear to programs on the device that something is wrong with the fs they want to use.

[altmount]
mount = /home/user/MyDocs

The other settings and config dirs will be handled later in the appsync and dynamic modes part.
(This is optional and can be compiled out)

Functional overview
--------------------

When a usb cable is insertion is detected usb_moded will start to act.
First it will warn on the system bus that a cable is connected.
Then it will check what the configuration setting is. Thus it knows how to act.
If it is a known configured mode it will load the correct modules (after checking
what is loaded and clean up if needed), perform other needed operations and
make sure the chosen mode works. At this point it will broadcast which mode
is set to warn other programs.
If things fail it will go to undefined state (and also broadcast this).

There is the special case where the config option is called "ask". In this
case usb_moded will enable a fake mass_storage profile to enable enumeration
so charging can be done, and wait until it is instructed which mode needs
to be selected. Thus this state can be used for an UI that will set the right
mode on user interaction. For this purpose usb_moded broadcasts it goes in ask
mode, and also stays in ask mode until a chosen mode is requested or the cable
is disconnected. This also avoids race conditions in case the UI starts
after a cable is inserted and usb_moded has also been started. The UI can then
query the state to know if it needs to show a selection dialog or not.

On disconnect usb_moded will broadcast a disconnect signal, so that all programs
that use the usb interface/mode know that a cable is disconnected and then can act
(if needed) on the changed situation. It will then do all the necessary to reset
the system to a clean state.

Appsync feature
---------------

In case you need some program to be started along some mode the appsync option
provides this option.
Only condition is that it can be activated by dbus and that (preferably) it will
notify usb_moded that it is ready by ready_method call on the session bus.
This ready method call is just calling the regular usb_moded interface, but now
on the session bus, with as argument the program name as defined in the config file.

To achieve this you need to have a config file in /etc/usb-moded/run.
Best practice would be giving it a descriptive name followed by .ini

For example:
/etc/usb-moded/run/foo.ini

Where foo.ini would be:
[info]
name = foo
mode = foo_mode
launch = com.meego.foo

Those files will be read on start and usb_moded will keep a list of apps to launch
for a certain mode. This also means that if you change the files or add/remove some
you need to restart usb_moded. Later when the mode is activated, usb_moded will start
each of them after the module has been loaded and keep track if they have been started.
It will warn you if that failed. This works together with an optional softconnect option
that will need kernel support. (Nokia only atm)

Dynamic modes
-------------

Dynamic modes will only work if the appsync feature is enabled, since it is expected
that this will need some special userspace programs. These will be started
through the appsync part and thus need their own config files in the normal appsync dir.

Dynamic modes need to be defined with an ini file also but this time in
/etc/usb-moded/dyn-modes.

The format would be for example for : /etc/usb-moded/dyn-modes/dyn-mode-1.ini

[mode]
name = dyn-mode-1
module = h_dyn-mode
appsync = 1
network = 1
network_interface = usb0

Only the mode name and module are mandatory.
However if you specify that there has to be network bringup, the
network interface is mandatory. Atm the network interface
bring-up will only work on debian based systems, since it uses
ifup/ifdown as the network configuration has to be handled
in the regular places to avoid conflicts and keep it easy to
configure.

If appsync is not defined or explicitly set to 0 it will not be used.

Trigger support
---------------

This will only work if udev is configured as it is a udev trigger.
Atm only one trigger is supported.
This is to support special equipment that will send a trigger event.
Usually this will be in combination with a dynamic mode.

You need to add the following to usb-moded.ini to get a trigger activated

For example

[trigger]
path = /sys/devices/platform/musb_hdrc
udev_subsystem = platform
mode = mass_storage
property = TRIGGER_CMD

3 changes: 2 additions & 1 deletion src/Makefile.am
Expand Up @@ -40,7 +40,8 @@ endif

if UDEV
usb_moded_SOURCES += \
usb_moded-udev.c
usb_moded-udev.c \
usb_moded-trigger.c
endif

if NOKIA
Expand Down
21 changes: 19 additions & 2 deletions src/usb_moded-appsync.c
Expand Up @@ -60,7 +60,9 @@ static void free_list(void)
{
if( sync_list != 0 )
{
g_list_free_full(sync_list, free_elem);
/*g_list_free_full(sync_list, free_elem); */
g_list_foreach (sync_list, (GFunc) free_elem, NULL);
g_list_free (sync_list);
sync_list = 0;
}
}
Expand Down Expand Up @@ -140,6 +142,7 @@ static struct list_elem *read_file(const gchar *filename)
int activate_sync(const char *mode)
{
GList *iter;
int count = 0, count2 = 0;

log_debug("activate sync");

Expand All @@ -156,12 +159,26 @@ int activate_sync(const char *mode)
for( iter = sync_list; iter; iter = g_list_next(iter) )
{
struct list_elem *data = iter->data;

count++;
if(!strcmp(data->mode, mode))
data->active = 0;
else
{
count2++;
data->active = 1;
}
}

/* if the number of active modes is equal to the number of existing modes
we enumerate immediately */
if(count == count2)
{
log_debug("Nothing to launch.\n");
enumerate_usb(NULL);
return(1);
}

/* add dbus filter. Use session bus for ready method call? */
if(!usb_moded_app_sync_init())
{
Expand All @@ -171,7 +188,7 @@ int activate_sync(const char *mode)
}

/* start timer */
log_debug("Starting timer\n");
log_debug("Starting appsync timer\n");
g_timeout_add_seconds(2, enumerate_usb, NULL);

/* go through list and launch apps */
Expand Down
21 changes: 18 additions & 3 deletions src/usb_moded-config.c
Expand Up @@ -78,17 +78,32 @@ int find_cdrom_timeout(void)
}
#endif /* NOKIA */

#ifdef APP_SYNC
#ifdef UDEV
const char * check_trigger(void)
{
return(get_conf_string(TRIGGER_ENTRY, TRIGGER_PATH_KEY));
}

const char * check_trigger_mode(void)
const char * get_trigger_subsystem(void)
{
return(get_conf_string(TRIGGER_ENTRY, TRIGGER_UDEV_SUBSYSTEM));
}

const char * get_trigger_mode(void)
{
return(get_conf_string(TRIGGER_ENTRY, TRIGGER_MODE_KEY));
}
#endif /* APP_SYNC */

const char * get_trigger_property(void)
{
return(get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_KEY));
}

const char * get_trigger_value(void)
{
return(get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_VALUE_KEY));
}
#endif /* UDEV */

static int get_conf_int(const gchar *entry, const gchar *key)
{
Expand Down
12 changes: 9 additions & 3 deletions src/usb_moded-config.h
Expand Up @@ -36,7 +36,10 @@
#define CDROM_TIMEOUT_KEY "timeout"
#define TRIGGER_ENTRY "trigger"
#define TRIGGER_PATH_KEY "path"
#define TRIGGER_UDEV_SUBSYSTEM "udev_subsystem"
#define TRIGGER_MODE_KEY "mode"
#define TRIGGER_PROPERTY_KEY "property"
#define TRIGGER_PROPERTY_VALUE_KEY "value"

const char * find_mounts(void);
int find_sync(void);
Expand All @@ -51,7 +54,10 @@ const char * find_cdrom_path(void);
int find_cdrom_timeout(void);
#endif

#ifdef APP_SYNC
#ifdef UDEV
const char * check_trigger(void);
const char * check_trigger_mode(void);
#endif /* APP_SYNC */
const char * get_trigger_subsystem(void);
const char * get_trigger_mode(void);
const char * get_trigger_property(void);
const char * get_trigger_value(void);
#endif /* UDEV */
2 changes: 1 addition & 1 deletion src/usb_moded-dyn-config.c
Expand Up @@ -53,7 +53,7 @@ GList *read_mode_list(void)
g_dir_close(confdir);
}
else
log_debug("confdir open failed.\n");
log_debug("Dynamic mode confdir open failed.\n");
return(modelist);
}

Expand Down
4 changes: 3 additions & 1 deletion src/usb_moded-modesetting.c
Expand Up @@ -331,12 +331,14 @@ int usb_moded_mode_cleanup(const char *module)
mount = find_alt_mount();
if(mount)
{
/* check if it is already mounted, if not mount failure fallback */
command = g_strconcat("mount | grep ", mount, NULL);
ret = system(command);
g_free(command);
if(ret)
{
command = g_strconcat("mount -t tmpfs tmpfs -o ro -size=512K ", mount, NULL);
command = g_strconcat("mount -t tmpfs tmpfs -o ro --size=512K ", mount, NULL);
log_debug("Total failure, mount ro tmpfs as fallback\n");
ret = system(command);
g_free(command);
}
Expand Down

0 comments on commit 6e1d204

Please sign in to comment.