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 handled with udev, it even tries to guess which is the correct power_supply entry to use.
A Qt lib to interact with usb-moded is available here: https://git.merproject.org/mer-core/libusb-moded-qt
Simply start with usb_moded. usb_moded --help will give you more details
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>'
To get the currently stored default mode from the config:
dbus-send --system --type=method_call --print-reply --dest=com.meego.usb_moded /com/meego/usb_moded com.meego.usb_moded.get_config
The supported modes can be queried over dbus as follows:
dbus-send --system --type=method_call --print-reply --dest=com.meego.usb_moded /com/meego/usb_moded com.meego.usb_moded.get_modes
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 The main config file is /etc/usb-moded/usb-moded.ini . This file will be auto-generated if it is not there (default profile will be developer_mode). Also it will be regenerated if some extra config file gets dropped into the /etc/usb-moded/ directory. This way you can easily add extra hw/configuration dependent information in there.
Most common use case would be passing the udev information for the power supply tracking entry, as in some cases it is not /sys/class/power_supply/usb
This is also known as config file merging (see further)
The most imporant entry is the power_supply, or iow the place in sysfs where usb_moded can read the cable connection status and type. For example on the N900
[udev] path = /sys/class/power_supply/isp1704
Without this information usb_moded will not run and exit.
In case nothing is specified and it is not the typical path it will try to guess. This might not always work. There is the source of a utility in the tree udev-search.c under utils, that will give you an idea of what paths usb-moded might be choosing. It always takes the one with the highest score.
There are the 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
Also the default usb mode can be configured there. For example:
[usbmode] mode = ask mode_100001 = charging
This says that default mode for user with uid 100001 is charging and other users default to mode ask. Modes with uid are only used when built with --enable-sailfish-access-control and only users with uid higher than 100000 and lower or equal to 999999 can have user specific usb modes.
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)
There is also an optional network configuration.
Certain parts of this config will override the settingsset in the dynamic mode configuration, like for example interface! The default ip set for usb networking is 192.168.2.15 (for Meego/Nemo/SailfishOS). However this can be configured by hand in the ini file also (optionally in a separate ini file which is possible due to config file merging).
For example:
[network] ip = 10.0.0.2 interface = usb1 gateway = 10.0.0.1
By default usb0 will be used, so no need to fill it in if not needed. The gateway setting is also optional and will not be set if there is no value filled in. If the ip is set to dhcp, usb_moded will try to use dhcp to configure the network (requires dhclient or udhcpc atm)
The network configuration can also be set with dbus method calls via the net_config method. This requires two strings as arguments. Supported are: ip, interface and gateway
for exmaple:
dbus-send --system --type=method_call --print-reply --dest=com.meego.usb_moded /com/meego/usb_moded com.meego.usb_moded.net_config string:'ip' string:'192.168.2.15'
Usb_moded will generate a random mac address for the g_ether driver. Thus when plugging in the device repeatedly the mac address will not change and udev rules / network manager etc will not think it is a new device each time. This mac is stored using the default modprobe configuration and thus will be in /etc/modprobe.d/g_ether.conf If this file exits usb_moded will assume there is a default mac set and will not do anything.
It is possible to set the configuration on the kernel command line also. For this the format of regular ip setting from the kernel is being re-used.
The format followed is: usb_moded_ip=::::::
For more info see the kernel source: Documentation/filesystems/nfs/nfsroot.txt
for example : usb_moded_ip=192.168.3.100::192.168.3.1:255.255.255.0::usb0:off
NOTE: The device must be usb0! The autoconf value is ignored.
Ip forwarding or nat can also be set up by usb_moded. This is in case you want to use an interface on the device to route traffic coming from your pc/laptop. The best use case example would be connecting to the internet over USB using the data connection of your smartphone. This does not work the other way round!
To enable this you need to add the following lines to your network config (the example expects rmnet0 to be your internet facing interface on the device).
nat_interface = rmnet0
When nat=1 is given in the mode configuration this will be used to enable nat on that interface. This is a bit complicated but related to the fact that the nat interface is usually the same on a device, but not all usb network related profiles might want it enabled.
If you want the device to load a dhcp server you need to configure this in the mode config, just like nat. (see lower)
USB moded supports access control of dynamic modes when built with --enable-sailfish-access-control. Modes are allowed and denied based on the user of the process accessing the D-Bus API. By default dynamic modes are allowed for users in sailfish-system but the group can be overridden in configuration.
For example:
[mode_group] mtp_mode = users developer_mode = developers
This allows mode called mtp_mode to users in "users" group and mode called developer_mode for users in "developers" group. Users group includes all regular users which is less restrictive than the default. Note that if the group doesn't exist access is denied.
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 cable 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.
Another special feature is the dedicated charger tracking. When a charger is connected usb_moded will broadcast a charger_connected signal and go to "dedicated charger" mode. This is just a place-holder mode. On charger disconnect then there will be a charger_disconnected signal.
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. Systemd is also supported.
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 for dbus: [info] name = foo mode = foo_mode launch = com.meego.foo
For systemd it would be as follows: [info] name = foo.service mode = foo_mode systemd = 1
The name here is the service name used when launching it for example with systemctl
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.
These services will start before the whole setup for the usb is done. In case the application only works after everything has been set up, you can start the application at the end by adding post = 1 to configuration.
Apart from ask and charging_only modes, all modes for usb_moded are defined within configuration files. These are to be defined with an ini file alsoi, 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 = dyn-mode-module appsync = 1 network = 1 network_interface = usb0
[options] sysfs_path = /* in case you need to echo parameters somewhere in a sysfs path / sysfs_value = / the values / sysfs_reset_value = / in case a reset value needs to be written */
Only the mode name and module are mandatory. In case you do not use modules, use none as the value for module (as for the android gadget for example. See the android section for more info)
If appsync or network is not defined, or explicitly set to 0, it will not be used. To use the mass_storage functions you need to define mass_storage = 1. The needed info for mass_storage data need to be defined in the config file. (other approaches are possible so this is not mandatory for all kinds of mass_storage support)
To enable nat, you need to set nat = 1 and configure the nat_interface in the network settings.
To have dhcp server functionality on the device, set dhcp_server = 1. This will use udhcpd. It also uses the default network address or whatever has been configured and sets up a corresponding dhcp configuration. This way the device is always available on the same address.
Both NAT and dhcp server need a corresponding service that can be started by usb_moded. (see Appsyn feature)
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
A number of configurations are already supported out of the box for android. They just need to be installed in the right spot to work.
In the main configuration file a few extras can be configured for all modes.
An android extra section in the main configuration file would look like this:
[android] iManufacturer = foo-factory idVendor = 0666 /* this is the vendor id code in hex / iProduct = awesome-device idProduct = 0001 / If you decide to use one Product id for all the supported modes. Not recommended if you will connect it to Windows machines */
A mode configuration would look like this:
[mode] name = developer_mode module = none network = 1 network_interface = rndis0
[options]
sysfs_value = rndis idProduct = 0002
On some android kernels cable detection/charging etc is broken unless the gadget is active. Often this is weirdly done on purpose by checking if the gadget is active before doing anything. This is not recommend and is actually wrong. Not to mention all the potential issues this could cause. (extra power drain, suspend issues, accidental exposure of data over USB, ...)
For this purpose there is the -a switch that activates by default the charging mode, and will set it on disconnect. So technically unless you connect and set some mode, the gadget will always be active in the fake mass-storage charging mode.
WARNING: This could potentially expose data over mass-storage (TODO, make sure this does not happen)
When started with -r usb_moded will always enable developer mode (networking) if it can. This is a debug feature and should not be used in production software.
Turning it off when the device is booted completely can easily be done over dbus.
dbus-send --system --type=method_call --print-reply --dest=com.meego.usb_moded /com/meego/usb_moded com.meego.usb_moded.rescue_off
The main config file for usb_moded is /etc/usb-moded/usb-moded.ini
If this does not exist usb_moded will create one for you, which will default to setting up a default network with ip 192.168.2.15 and uses the g_ether module.
The different sections of the config file can be split out in different ini files (they thus need to end in .ini or they will not be considered as valid). However take into account usb_moded will need to be restarted to merge these in a new usb-moded.ini file. As usb_moded will only then check if new files were added to the /etc/usb-moded directory and refresh the main ini file as needed on start-up.
Usb-moded supports a diagnostic mode. This requires a special command line parameter (-d). One mode should be configured in /etc/usb-moded/diag and this will be automatically used. This is a feature to allow for "hidden" or non-standard modes that are only of use for testing/QA.
Usb_moded can set up USB tethering. In the sense that it can share the connection of your device to a second one. Most common use case would be using USB tethering from a phone to a laptop.
When compiled with ofono and connman support you can make the most of this. ofono can be used to detect roaming status. Connman for getting dns settings and interface from the modem connection. However it works also without it. It can be configured so that it knows what the interfaces are and get the dns info from /etc/resolv.conf.
For this are the
#define NETWORK_NAT_INTERFACE_KEY "nat_interface" #define NO_ROAMING_KEY "noroaming"
Network options. nat_interface documents which interfaces the internet facing modem. noroaming when set to 1 will prohibit enabling the modem interface in case you are roaming (this requires ofono).
hidden modes
Sometimes it is useful to hide modes from the ui (the mode can be queried through dbus). To hide modes this can be done by adding a hide= key to the [usbmode] section. If you want to hide more modes this needs to be a comma separated list.
For example [usbmode] hide=developer_mode,bastard_mode
Modes can also be set and removed through dbus (one mode at a time) See usb_moded_util (-v, -i and -u)