diff options
-rw-r--r-- | sys-mobilephone/fsousaged/Manifest | 5 | ||||
-rw-r--r-- | sys-mobilephone/fsousaged/files/controller-plugin.vala | 769 | ||||
-rw-r--r-- | sys-mobilephone/fsousaged/files/lowlevel_kernel26-plugin.vala | 68 | ||||
-rw-r--r-- | sys-mobilephone/fsousaged/files/lowlevel_openmoko-plugin.vala | 130 | ||||
-rw-r--r-- | sys-mobilephone/fsousaged/fsousaged-0.9.1.0.ebuild | 45 |
5 files changed, 1017 insertions, 0 deletions
diff --git a/sys-mobilephone/fsousaged/Manifest b/sys-mobilephone/fsousaged/Manifest index 6ef9eee..45483f0 100644 --- a/sys-mobilephone/fsousaged/Manifest +++ b/sys-mobilephone/fsousaged/Manifest @@ -1,3 +1,8 @@ +AUX controller-plugin.vala 25009 RMD160 c39962369724c4495a4bdfd77260e2babb612182 SHA1 daba7e911a1dca7c6ca2ec79e26f2d38718ab9f7 SHA256 88e4add559409bc95ce33c9d956b4e2526c9546ff93074ba968270024e708c90 AUX fsousaged_main.patch 450 RMD160 21c2bb26374ff1ac9243d57ac38cd98805dcee27 SHA1 c7c5b15e283f3b5c7f99ed418306182d4b7ab6cb SHA256 522b2638c9a547fdad23dfb92d6227447786a62c4c402ed60e8008770642b32a +AUX lowlevel_kernel26-plugin.vala 2048 RMD160 7788ad6d53adde7a44b8678b2563334cebad988c SHA1 2f5be77178bc679158c66de9b7a1f69d82ecc326 SHA256 4c4f088c5e512c7fff0ed78f77c61b4525ed9074df259b0c7c0ff84d83162918 +AUX lowlevel_openmoko-plugin.vala 5023 RMD160 ede1b1ccdb3682b1d313f4a64aba59980390fb17 SHA1 311bc5bce80af622f40a70605ad53dc24884dc97 SHA256 cb8cdf0d9cb5b93c9926ad55c253ee8755e87928dc8355acb835ffeac4cc5c00 DIST fsousaged-0.9.0.tar.gz 19121 RMD160 6bb47885af8ee7a9efc272795d7ea67622a18818 SHA1 f69395d25fb5e52e928a14068b2a7deda61d33ea SHA256 a7d07e7022806bf525feff56bd99462bdbff48a2019938ade50915cd9ac3166b +DIST fsousaged-0.9.1.0.tar.bz2 249038 RMD160 d6107e2925b717b74d0c62947eb48a748e475dcd SHA1 7656172f4cbba2e15a4e1d3cfe7067b7da0a9ce8 SHA256 2a456677f8c6487f14e2f4346ceb289387a2afe1204e37201369cf6358779d7b EBUILD fsousaged-0.9.0.ebuild 1125 RMD160 72333aa53e002afb65ffc992f587e3c447ad6fec SHA1 dd8046419738a4ad19253365533008dfd57655ab SHA256 6d9465fcbc25b491345095f47de2b2a88dc2153e2537444330dd539789b03936 +EBUILD fsousaged-0.9.1.0.ebuild 1348 RMD160 83912073652866a555c4b671ee0c8ff7815ac245 SHA1 d62c356af79746f05f58fa44c2cbb025fd685ea2 SHA256 0b45f0726fb18830d85b04bfaa6550e488315387a41b317d47a0aca25631e0f5 diff --git a/sys-mobilephone/fsousaged/files/controller-plugin.vala b/sys-mobilephone/fsousaged/files/controller-plugin.vala new file mode 100644 index 0000000..eb14bdc --- /dev/null +++ b/sys-mobilephone/fsousaged/files/controller-plugin.vala @@ -0,0 +1,769 @@ +/* + * Generic Resource Controller + * + * Written by Michael 'Mickey' Lauer <mlauer@vanille-media.de> + * All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +using GLib; +using Gee; + +internal const string RESOURCE_INTERFACE = "org.freesmartphone.Resource"; +internal const string CONFIG_SECTION = "fsousage"; +internal const string DEFAULT_LOWLEVEL_MODULE = "kernel26"; + +internal const string FSO_IDLENOTIFIER_BUS = "org.freesmartphone.odeviced"; +internal const string FSO_IDLENOTIFIER_PATH = "/org/freesmartphone/Device/IdleNotifier/0"; +internal const string FSO_IDLENOTIFIER_IFACE = "org.freesmartphone.Device.IdleNotifier"; + +namespace Usage +{ +/** + * Enum for resource status + **/ +public enum ResourceStatus +{ + UNKNOWN, + ENABLING, + ENABLED, + SUSPENDING, + SUSPENDED, + RESUMING, + DISABLING, + DISABLED +} + +/** + * Helper class encapsulating a registered resource + **/ +public class Resource : Object +{ + public string name { get; set; } + public DBus.BusName busname { get; set; } + public DBus.ObjectPath objectpath { get; set; } + public ResourceStatus status { get; set; } + public FreeSmartphone.UsageResourcePolicy policy { get; set; } + public ArrayList<string> users { get; set; } + + private FreeSmartphone.Resource proxy; + + // called before deserializing, init all non-value types here + construct + { + this.users = new ArrayList<string>( str_equal ); + } + + public Resource( string name, DBus.BusName busname, DBus.ObjectPath objectpath ) + { + this.name = name; + this.busname = busname; + this.objectpath = objectpath; + this.status = ResourceStatus.UNKNOWN; + this.policy = FreeSmartphone.UsageResourcePolicy.AUTO; + + proxy = dbusconn.get_object( busname, objectpath, RESOURCE_INTERFACE ) as FreeSmartphone.Resource; + // workaround until vala 0.7.4 + proxy.ref(); + + //message( "Resource %s served by %s @ %s created", name, busname, objectpath ); + } + + ~Resource() + { + //message( "Resource %s served by %s @ %s destroyed", name, busname, objectpath ); + } + + private void updateStatus() + { + var info = new HashTable<string,Value?>( str_hash, str_equal ); + var p = Value( typeof(int) ); + p.set_int( policy ); + info.insert( "policy", p ); + var u = Value( typeof(int) ); + u.set_int( users.size ); + info.insert( "refcount", u ); + instance.resource_changed( name, isEnabled(), info ); // DBUS SIGNAL + } + + public bool isEnabled() + { + return ( status == ResourceStatus.ENABLED ); + } + + public bool hasUser( string user ) + { + return ( user in users ); + } + + public void setPolicy( FreeSmartphone.UsageResourcePolicy policy ) + { + if ( policy == this.policy ) + return; + else + ( this.policy = policy ); + + switch ( policy ) + { + case FreeSmartphone.UsageResourcePolicy.DISABLED: + disable(); + break; + case FreeSmartphone.UsageResourcePolicy.ENABLED: + enable(); + break; + case FreeSmartphone.UsageResourcePolicy.AUTO: + if ( users.size > 0 ) + enable(); + else + disable(); + break; + default: + assert_not_reached(); + } + + updateStatus(); + } + + public void addUser( string user ) throws FreeSmartphone.UsageError + { + if ( user in users ) + throw new FreeSmartphone.UsageError.USER_EXISTS( "Resource %s already requested by user %s".printf( name, user ) ); + + if ( policy == FreeSmartphone.UsageResourcePolicy.DISABLED ) + throw new FreeSmartphone.UsageError.POLICY_DISABLED( "Resource %s cannot be requested by %s per policy".printf( name, user ) ); + + users.insert( 0, user ); + + if ( policy == FreeSmartphone.UsageResourcePolicy.AUTO && users.size == 1 ) + enable(); + + updateStatus(); + } + + public void delUser( string user ) throws FreeSmartphone.UsageError + { + if ( !(user in users) ) + throw new FreeSmartphone.UsageError.USER_UNKNOWN( "Resource %s never been requested by user %s".printf( name, user ) ); + + users.remove( user ); + + if ( policy == FreeSmartphone.UsageResourcePolicy.AUTO && users.size == 0 ) + disable(); + + updateStatus(); + } + + public void syncUsers() + { + dynamic DBus.Object busobj = dbusconn.get_object( DBus.DBUS_SERVICE_DBUS, DBus.DBUS_PATH_DBUS, DBus.DBUS_INTERFACE_DBUS ); + string[] busnames = busobj.ListNames(); + + var usersToRemove = new ArrayList<string>(); + + foreach ( var userbusname in users ) + { + var found = false; + foreach ( var busname in busnames ) + { + if ( userbusname == busname ) + found = true; + break; + } + if ( !found ) + usersToRemove.add( userbusname ); + } + foreach ( var userbusname in usersToRemove ) + { + instance.logger.warning( "Resource %s user %s has vanished.".printf( name, userbusname ) ); + delUser( userbusname ); + } + } + + public string[] allUsers() + { + string[] res = {}; + foreach ( var user in users ) + res += user; + return res; + } + + public bool isPresent() + { + dynamic DBus.Object peer = dbusconn.get_object( busname, objectpath, DBus.DBUS_INTERFACE_PEER ); + try + { + peer.Ping(); + return true; + } + catch ( DBus.Error e ) + { + instance.logger.warning( "Resource %s incommunicado: %s".printf( name, e.message ) ); + return false; + } + } + + public void enable() throws FreeSmartphone.ResourceError, DBus.Error + { + try + { + proxy.enable(); + status = ResourceStatus.ENABLED; + updateStatus(); + } + catch ( DBus.Error e ) + { + instance.logger.error( "Resource %s can't be enabled: %s. Trying to disable instead".printf( name, e.message ) ); + proxy.disable(); + throw e; + } + } + + public void disable() throws FreeSmartphone.ResourceError, DBus.Error + { + try + { + proxy.disable(); + status = ResourceStatus.DISABLED; + } + catch ( DBus.Error e ) + { + instance.logger.error( "Resource %s can't be disabled: %s. Setting status to UNKNOWN".printf( name, e.message ) ); + status = ResourceStatus.UNKNOWN; + throw e; + } + } + + public void suspend() throws FreeSmartphone.ResourceError, DBus.Error + { + if ( status == ResourceStatus.ENABLED ) + { + try + { + proxy.suspend(); + status = ResourceStatus.SUSPENDED; + } + catch ( DBus.Error e ) + { + instance.logger.error( "Resource %s can't be suspended: %s. Trying to disable instead".printf( name, e.message ) ); + proxy.disable(); + throw e; + } + } + else + { + instance.logger.debug( "Resource %s not enabled: not suspending".printf( name ) ); + } + } + + public void resume() throws FreeSmartphone.ResourceError, DBus.Error + { + if ( status == ResourceStatus.SUSPENDED ) + { + try + { + proxy.resume(); + status = ResourceStatus.ENABLED; + } + catch ( DBus.Error e ) + { + instance.logger.error( "Resource %s can't be resumed: %s. Trying to disable instead".printf( name, e.message ) ); + proxy.disable(); + throw e; + } + } + else + { + instance.logger.debug( "Resource %s not suspended: not resuming".printf( name ) ); + } + } +} + +/** + * Serialized state class + * + * All properties here will be saved on forced shutdown + **/ +public class PersistentData : Object +{ + public HashMap<string,Resource> resources { get; set; } + + construct + { + resources = new HashMap<string,Resource>( str_hash, str_equal, str_equal ); + } +} + +/** + * Controller class implementing org.freesmartphone.Usage API + * + * Note: Unfortunately we can't just use libfso-glib (FreeSmartphone.Usage interface) + * here, since we need access to the dbus sender name (which modifies the interface signature). + **/ +[DBus (name = "org.freesmartphone.Usage")] +public class Controller : FsoFramework.AbstractObject +{ + private FsoFramework.Subsystem subsystem; + + private FsoUsage.LowLevel lowlevel; + private bool do_not_suspend; + + private PersistentData data; + private weak HashMap<string,Resource> resources; + + dynamic DBus.Object dbus; + dynamic DBus.Object idlenotifier; + + public Controller( FsoFramework.Subsystem subsystem ) + { + this.subsystem = subsystem; + + this.subsystem.registerServiceName( FsoFramework.Usage.ServiceDBusName ); + this.subsystem.registerServiceObject( FsoFramework.Usage.ServiceDBusName, + FsoFramework.Usage.ServicePathPrefix, this ); + + // should we really suspend? + do_not_suspend = config.boolValue( CONFIG_SECTION, "do_not_suspend", false ); + + // start listening for name owner changes + dbusconn = ( (FsoFramework.DBusSubsystem)subsystem ).dbusConnection(); + dbus = dbusconn.get_object( DBus.DBUS_SERVICE_DBUS, DBus.DBUS_PATH_DBUS, DBus.DBUS_INTERFACE_DBUS ); + dbus.NameOwnerChanged += onNameOwnerChanged; + + // get handle to IdleNotifier + idlenotifier = dbusconn.get_object( FSO_IDLENOTIFIER_BUS, FSO_IDLENOTIFIER_PATH, FSO_IDLENOTIFIER_IFACE ); + + // delayed init + Idle.add( onIdleForInit ); + } + + public override string repr() + { + return "<%s>".printf( FsoFramework.Usage.ServicePathPrefix ); + } + +#if PERSISTENCE + private void syncResourcesAndUsers() + { + // for ever resource, we check whether it's still present, and if so, + // whether any of the consumers might have disappeared meanwhile + var resourcesToRemove = new Gee.HashSet<Resource>(); + + foreach ( var r in resources.get_values() ) + { + if ( !r.isPresent() ) + { + resourcesToRemove.add( r ); + } + } + foreach ( var r in resourcesToRemove ) + { + resources.remove( r.name ); + this.resource_available( r.name, false ); // DBUS SIGNAL + } + + foreach ( var r in resources.get_values() ) + { + r.syncUsers(); + } + } +#endif + + private bool onIdleForInit() + { + // check preferred low level suspend/resume plugin and instanciate + var lowleveltype = config.stringValue( CONFIG_SECTION, "lowlevel_type", DEFAULT_LOWLEVEL_MODULE ); + string typename = "none"; + + switch ( lowleveltype ) + { + case "kernel26": + typename = "LowLevelKernel26"; + break; + case "openmoko": + typename = "LowLevelOpenmoko"; + break; + default: + warning( "Invalid lowlevel_type '%s'; suspend/resume will NOT be available!".printf( lowleveltype ) ); + return false; // don't call me again + } + + if ( lowleveltype != "none" ) + { + var lowlevelclass = Type.from_name( typename ); + if ( lowlevelclass == Type.INVALID ) + { + logger.warning( "Can't find plugin for lowlevel_type = '%s'".printf( lowleveltype ) ); + return false; // don't call me again + } + + lowlevel = Object.new( lowlevelclass ) as FsoUsage.LowLevel; + logger.info( "Ready. Using lowlevel plugin '%s' to handle suspend/resume".printf( lowleveltype ) ); + } +#if PERSISTENCE + // check whether we have crash data + if ( loadPersistentData() ) + { + resources = data.resources; + syncResourcesAndUsers(); + } + else +#endif + { + data = new PersistentData(); + resources = data.resources; + } + + return false; // don't call me again + } + + private void onResourceAppearing( Resource r ) + { + logger.debug( "Resource %s served by %s @ %s has just been registered".printf( r.name, r.busname, r.objectpath ) ); + this.resource_available( r.name, true ); // DBUS SIGNAL + + // initial status is disabled + try + { + r.disable(); + } + catch ( FreeSmartphone.ResourceError e ) + { + logger.warning( "Error while trying to (initially) disable resource %s: %s".printf( r.name, e.message ) ); + } + catch ( DBus.Error e ) + { + logger.warning( "Error while trying to (initially) disable resource %s: %s".printf( r.name, e.message ) ); + } + } + + private void onResourceVanishing( Resource r ) + { + logger.debug( "Resource %s served by %s @ %s has just been unregistered".printf( r.name, r.busname, r.objectpath ) ); + this.resource_available( r.name, false ); // DBUS SIGNAL + + try + { + r.disable(); + } + catch ( FreeSmartphone.ResourceError e ) + { + logger.warning( "Error while trying to (initially) disable resource %s: %s".printf( r.name, e.message ) ); + } + catch ( DBus.Error e ) + { + logger.warning( "Error while trying to (finally) disable resource %s: %s".printf( r.name, e.message ) ); + } + } + + private void onNameOwnerChanged( dynamic DBus.Object obj, string name, string oldowner, string newowner ) + { + //message( "name owner changed: %s (%s => %s)", name, oldowner, newowner ); + // we're only interested in services disappearing + if ( newowner != "" ) + return; + + logger.debug( "%s disappeared. checking whether resources are affected...".printf( name ) ); + + //FIXME: Consider keeping the known busnames in a map as well, so we don't have to iterate through all values + + var resourcesToRemove = new Gee.HashSet<Resource>(); + + foreach ( var r in resources.get_values() ) + { + // first, check whether the resource provider might have vanished + if ( r.busname == name ) + { + onResourceVanishing( r ); + resourcesToRemove.add( r ); + } + // second, check whether it was one of the users + else + { + if ( r.hasUser( name ) ) + { + r.delUser( name ); + } + } + } + foreach ( var r in resourcesToRemove ) + { + resources.remove( r.name ); + } + } + + private bool onIdleForSuspend() + { + suspendAllResources(); + logger.debug( ">>>>>>> KERNEL SUSPEND" ); + if ( !do_not_suspend ) + lowlevel.suspend(); + else + Posix.sleep( 5 ); + logger.debug( "<<<<<<< KERNEL RESUME" ); + FsoUsage.ResumeReason reason = lowlevel.resume(); + logger.info( "Resume reason seems to be %s".printf( FsoFramework.StringHandling.enumToString( typeof( FsoUsage.ResumeReason ), reason) ) ); + resumeAllResources(); + this.system_action( FreeSmartphone.UsageSystemAction.RESUME ); // DBUS SIGNAL + + var idlestate = lowlevel.isUserInitiated( reason ) ? "busy" : "idle"; + try + { + idlenotifier.SetState( idlestate ); + } + catch ( DBus.Error e ) + { + logger.error( "DBus Error while talking to IdleNotifier: %s".printf( e.message ) ); + } + return false; // MainLoop: Don't call again + } + + private Resource getResource( string name ) throws FreeSmartphone.UsageError + { + Resource r = resources[name]; + if ( r == null ) + throw new FreeSmartphone.UsageError.RESOURCE_UNKNOWN( "Resource %s had never been registered".printf( name ) ); + + logger.debug( "current users for %s = %s".printf( r.name, FsoFramework.StringHandling.stringListToString( r.allUsers() ) ) ); + + return r; + } + + private void disableAllResources() + { + foreach ( var r in resources.get_values() ) + { + try + { + r.disable(); + } + catch ( FreeSmartphone.ResourceError e ) + { + logger.warning( "Error while trying to suspend resource %s: %s".printf( r.name, e.message ) ); + } + catch ( DBus.Error e ) + { + logger.warning( "Error while trying to disable resource %s: %s".printf( r.name, e.message ) ); + } + } + } + + private void suspendAllResources() + { + foreach ( var r in resources.get_values() ) + { + try + { + r.suspend(); + } + catch ( FreeSmartphone.ResourceError e ) + { + logger.warning( "Error while trying to suspend resource %s: %s".printf( r.name, e.message ) ); + } + catch ( DBus.Error e ) + { + logger.warning( "Error while trying to suspend resource %s: %s".printf( r.name, e.message ) ); + } + } + } + + private void resumeAllResources() + { + foreach ( var r in resources.get_values() ) + { + try + { + r.resume(); + } + catch ( FreeSmartphone.ResourceError e ) + { + logger.warning( "Error while trying to suspend resource %s: %s".printf( r.name, e.message ) ); + } + catch ( DBus.Error e ) + { + logger.warning( "Error while trying to resume resource %s: %s".printf( r.name, e.message ) ); + } + } + } + +#if PERSISTENCE + // not public, since we don't want to expose it via dbus + internal void savePersistentData() + { + logger.info( "Saving resource status to file..." ); + var file = File.new_for_path( "/tmp/serialize.output" ); + var stream = file.replace( null, false, FileCreateFlags.NONE, null ); + Persistence.JsonTypeSerializer.instance().ignoreUnknown = true; + var serializer = new Persistence.JsonSerializer( stream ); + serializer.serialize_object( data ); + } + + internal bool loadPersistentData() + { + var file = File.new_for_path( "/tmp/serialize.output" ); + if ( !file.query_exists( null ) ) + { + return false; + } + var stream = file.read( null ); + Persistence.JsonTypeSerializer.instance().ignoreUnknown = true; + var deserializer = new Persistence.JsonDeserializer<PersistentData>( stream ); + data = deserializer.deserialize_object() as PersistentData; + return true; + } +#endif + + // + // DBUS API (for providers) + // + public void register_resource( DBus.BusName sender, string name, DBus.ObjectPath path ) throws FreeSmartphone.UsageError, DBus.Error + { + message( "register_resource called with parameters: %s %s %s", sender, name, path ); + if ( name in resources.get_keys() ) + throw new FreeSmartphone.UsageError.RESOURCE_EXISTS( "Resource %s already registered".printf( name ) ); + + var r = new Resource( name, sender, path ); + resources[name] = r; + + onResourceAppearing( r ); + } + + public void unregister_resource( DBus.BusName sender, string name ) throws FreeSmartphone.UsageError, DBus.Error + { + var r = getResource( name ); + + if ( r.busname != sender ) + throw new FreeSmartphone.UsageError.RESOURCE_UNKNOWN( "Resource %s not yours".printf( name ) ); + + onResourceVanishing( r ); + + resources.remove( name ); + } + + // + // DBUS API (for consumers) + // + //public FreeSmartphone.UsageResourcePolicy get_resource_policy( string name ) throws FreeSmartphone.UsageError, FreeSmartphone.Error, DBus.Error + public string get_resource_policy( string name ) throws FreeSmartphone.UsageError, FreeSmartphone.Error, DBus.Error + { + switch ( getResource( name ).policy ) + { + case FreeSmartphone.UsageResourcePolicy.ENABLED: + return "enabled"; + case FreeSmartphone.UsageResourcePolicy.DISABLED: + return "disabled"; + case FreeSmartphone.UsageResourcePolicy.AUTO: + return "auto"; + default: + var error = "unknown resource policy value %d for resource %s".printf( getResource( name ).policy, name ); + logger.error( error ); + throw new FreeSmartphone.Error.INTERNAL_ERROR( error ); + } + } + + //public void set_resource_policy( string name, FreeSmartphone.UsageResourcePolicy policy ) throws FreeSmartphone.UsageError, FreeSmartphone.Error, DBus.Error + public void set_resource_policy( string name, string policy ) throws FreeSmartphone.UsageError, FreeSmartphone.Error, DBus.Error + { + message( "set resource policy for %s to %s", name, policy ); + + if ( policy == "enabled" ) + getResource( name ).setPolicy( FreeSmartphone.UsageResourcePolicy.ENABLED ); + else if ( policy == "disabled" ) + getResource( name ).setPolicy( FreeSmartphone.UsageResourcePolicy.DISABLED ); + else if ( policy == "auto" ) + getResource( name ).setPolicy( FreeSmartphone.UsageResourcePolicy.AUTO ); + else + throw new FreeSmartphone.Error.INVALID_PARAMETER( "ResourcePolicy needs to be one of { \"enabled\", \"disabled\", \"auto\" }" ); + } + + public bool get_resource_state( string name ) throws FreeSmartphone.UsageError, DBus.Error + { + return getResource( name ).isEnabled(); + } + + public string[] get_resource_users( string name ) throws FreeSmartphone.UsageError, DBus.Error + { + return getResource( name ).allUsers(); + } + + public string[] list_resources() throws DBus.Error + { + string[] res = {}; + foreach ( var key in resources.get_keys() ) + res += key; + return res; + } + + public void request_resource( DBus.BusName sender, string name ) throws FreeSmartphone.UsageError, DBus.Error + { + getResource( name ).addUser( sender ); + } + + public void release_resource( DBus.BusName sender, string name ) throws FreeSmartphone.UsageError, DBus.Error + { + getResource( name ).delUser( sender ); + } + + public void shutdown() throws DBus.Error + { + this.system_action( FreeSmartphone.UsageSystemAction.SHUTDOWN ); // DBUS SIGNAL + disableAllResources(); + Posix.system( "shutdown -h now" ); + } + + public void reboot() throws DBus.Error + { + this.system_action( FreeSmartphone.UsageSystemAction.REBOOT ); // DBUS SIGNAL + disableAllResources(); + Posix.system( "reboot" ); + } + + public void suspend() throws DBus.Error + { + this.system_action( FreeSmartphone.UsageSystemAction.SUSPEND ); // DBUS SIGNAL + // we need to suspend async, otherwise the dbus call would timeout + Idle.add( onIdleForSuspend ); + } + + // DBUS SIGNALS + public signal void resource_available( string name, bool availability ); + public signal void resource_changed( string name, bool state, GLib.HashTable<string,GLib.Value?> attributes ); + public signal void system_action( FreeSmartphone.UsageSystemAction action ); +} + +} /* end namespace */ + +Usage.Controller instance; +DBus.Connection dbusconn; + +public static string fso_factory_function( FsoFramework.Subsystem subsystem ) throws Error +{ + instance = new Usage.Controller( subsystem ); + return "fsousage.controller"; +} + +public static void fso_shutdown_function() +{ +#if PERSISTENCE + instance.savePersistentData(); +#endif +} + +[ModuleInit] +public static void fso_register_function( TypeModule module ) +{ + debug( "usage controller fso_register_function()" ); +} diff --git a/sys-mobilephone/fsousaged/files/lowlevel_kernel26-plugin.vala b/sys-mobilephone/fsousaged/files/lowlevel_kernel26-plugin.vala new file mode 100644 index 0000000..9a1b877 --- /dev/null +++ b/sys-mobilephone/fsousaged/files/lowlevel_kernel26-plugin.vala @@ -0,0 +1,68 @@ +/** + * Copyright (C) 2009 Michael 'Mickey' Lauer <mlauer@vanille-media.de> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +using GLib; + +using FsoUsage; + +class LowLevel.Kernel26 : FsoUsage.LowLevel, FsoFramework.AbstractObject +{ + construct + { + logger.info( "Registering kernel26 low level suspend/resume handling" ); + // grab sysfs paths + var sysfs_root = config.stringValue( "cornucopia", "sysfs_root", "/sys" ); + sys_power_state = Path.build_filename( sysfs_root, "power", "state" ); + } + + public override string repr() + { + return "<>"; + } + + public void suspend() + { + FsoFramework.FileHandling.write( "mem\n", sys_power_state ); + } + + public ResumeReason resume() + { + return ResumeReason.Unknown; + } +} + +string sys_power_state; + +/** + * This function gets called on plugin initialization time. + * @return the name of your plugin here + * @note that it needs to be a name in the format <subsystem>.<plugin> + * else your module will be unloaded immediately. + **/ +public static string fso_factory_function( FsoFramework.Subsystem subsystem ) throws Error +{ + debug( "lowlevel_kernel26 fso_factory_function" ); + return "fsousaged.lowlevel_kernel26"; +} + +[ModuleInit] +public static void fso_register_function( TypeModule module ) +{ + // do not remove this function +} diff --git a/sys-mobilephone/fsousaged/files/lowlevel_openmoko-plugin.vala b/sys-mobilephone/fsousaged/files/lowlevel_openmoko-plugin.vala new file mode 100644 index 0000000..0ea906a --- /dev/null +++ b/sys-mobilephone/fsousaged/files/lowlevel_openmoko-plugin.vala @@ -0,0 +1,130 @@ +/** + * Copyright (C) 2009 Michael 'Mickey' Lauer <mlauer@vanille-media.de> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +using GLib; + +using FsoUsage; + +internal const string SYSFS_RESUME_REASON_PATH = "/class/i2c-adapter/i2c-0/0-0073/neo1973-resume.0/resume_reason"; +internal const string SYSFS_RESUME_SUBREASON_PATH = "/class/i2c-adapter/i2c-0/0-0073/resume_reason"; + +class LowLevel.Openmoko : FsoUsage.LowLevel, FsoFramework.AbstractObject +{ + private HashTable<string,uint> intmap1; + private HashTable<string,uint> intmap2; + + construct + { + logger.info( "Registering openmoko low level suspend/resume handling" ); + // grab sysfs paths + var sysfs_root = config.stringValue( "cornucopia", "sysfs_root", "/sys" ); + sys_power_state = Path.build_filename( sysfs_root, "power", "state" ); + sys_resume_reason = Path.build_filename( sysfs_root, SYSFS_RESUME_REASON_PATH ); + sys_resume_subreason = Path.build_filename( sysfs_root, SYSFS_RESUME_SUBREASON_PATH ); + + intmap1 = new HashTable<string,uint>( str_hash, str_equal ); + intmap1.insert( "EINT00_ACCEL1", ResumeReason.Accelerometer ); + intmap1.insert( "EINT01_GSM", ResumeReason.GSM ); + intmap1.insert( "EINT02_BLUETOOTH", ResumeReason.Bluetooth ); + intmap1.insert( "EINT03_DEBUGBRD", ResumeReason.Debug ); + intmap1.insert( "EINT04_JACK", ResumeReason.Headphone ); + intmap1.insert( "EINT05_WLAN", ResumeReason.WiFi ); + intmap1.insert( "EINT06_AUXKEY", ResumeReason.AuxKey ); + intmap1.insert( "EINT07_HOLDKEY", ResumeReason.Headphone ); + intmap1.insert( "EINT08_ACCEL2", ResumeReason.Accelerometer ); + intmap1.insert( "EINT09_PMU", ResumeReason.PMU ); + intmap1.insert( "EINT10_NULL", ResumeReason.Invalid ); + intmap1.insert( "EINT11_NULL", ResumeReason.Invalid ); + intmap1.insert( "EINT12_GLAMO", ResumeReason.GFX ); + intmap1.insert( "EINT13_NULL", ResumeReason.Invalid ); + intmap1.insert( "EINT14_NULL", ResumeReason.Invalid ); + intmap1.insert( "EINT15_NULL", ResumeReason.Invalid ); + + intmap2 = new HashTable<string,uint>( str_hash, str_equal ); + intmap2.insert( "0000000200", ResumeReason.LowBattery ); + intmap2.insert( "0002000000", ResumeReason.PowerKey ); + } + + public override string repr() + { + return "<>"; + } + + public void suspend() + { + FsoFramework.FileHandling.write( "mem\n", sys_power_state ); + } + + public ResumeReason resume() + { + var reasons = FsoFramework.FileHandling.read( sys_resume_reason ).split( "\n" ); + var reasonkey = "unknown"; + foreach ( var line in reasons ) + { + if ( line.has_prefix( "*" ) ) + { + reasonkey = line.substring( 2 ); + break; + } + } + var reasonvalue = intmap1.lookup( reasonkey ); + if ( reasonvalue == 0 ) + { + logger.info( "No resume reason marked in %s".printf( sys_resume_reason ) ); + return ResumeReason.Unknown; + } + + if ( reasonvalue == ResumeReason.PMU ) + { + logger.debug( "PMU resume reason marked in %s".printf( sys_resume_reason ) ); + + var subreasonkey = FsoFramework.FileHandling.read( sys_resume_subreason ); + var subreasonvalue = intmap2.lookup( subreasonkey ); + if ( subreasonvalue == 0 ) + { + logger.debug( "Unknown subreason %s for PMU resume, please fix me!".printf( subreasonkey ) ); + return ResumeReason.PMU; + } + return (ResumeReason)subreasonvalue; + } + return (ResumeReason)reasonvalue; + } +} + +string sys_power_state; +string sys_resume_reason; +string sys_resume_subreason; + +/** + * This function gets called on plugin initialization time. + * @return the name of your plugin here + * @note that it needs to be a name in the format <subsystem>.<plugin> + * else your module will be unloaded immediately. + **/ +public static string fso_factory_function( FsoFramework.Subsystem subsystem ) throws Error +{ + debug( "lowlevel_openmoko fso_factory_function" ); + return "fsousaged.lowlevel_openmoko"; +} + +[ModuleInit] +public static void fso_register_function( TypeModule module ) +{ + // do not remove this function +} diff --git a/sys-mobilephone/fsousaged/fsousaged-0.9.1.0.ebuild b/sys-mobilephone/fsousaged/fsousaged-0.9.1.0.ebuild new file mode 100644 index 0000000..7635c0d --- /dev/null +++ b/sys-mobilephone/fsousaged/fsousaged-0.9.1.0.ebuild @@ -0,0 +1,45 @@ +# Copyright 1999-2009 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +inherit autotools + +DESCRIPTION="freesmartphone.org usage daemon" +HOMEPAGE="http://www.freesmartphone.org" +SRC_URI="http://www.freesmartphone.org/sources/${P}.tar.bz2" + +LICENSE="GPL-2" +SLOT="0" +KEYWORDS="~arm ~x86 ~amd64" +IUSE="" + +RDEPEND=">=dev-libs/glib-2.18.0 + >=dev-libs/libgee-0.3.0 + >=media-libs/alsa-lib-1.0.20 + >=sys-apps/dbus-1.2.1 + >=dev-libs/dbus-glib-0.76 + >=sys-mobilephone/libfso-glib-0.2.0 + >=sys-mobilephone/libfsoframework-0.2.3" +DEPEND="${RDEPEND} + >=dev-lang/vala-0.7.6" + +EAPI="2" + +src_prepare() { + cp "${FILESDIR}"/controller-plugin.vala "${S}"/src/plugins/controller/plugin.vala + cp "${FILESDIR}"/lowlevel_kernel26-plugin.vala "${S}"/src/plugins/lowlevel_kernel26/plugin.vala + cp "${FILESDIR}"/lowlevel_openmoko-plugin.vala "${S}"/src/plugins/lowlevel_openmoko/plugin.vala +} + +src_install() { + emake DESTDIR="${D}" install || die "make install failed" +} + +pkg_postinst() { + elog "To use fsousaged instead of ousaged edit the config in" + elog "/etc/frameworkd.conf , below the lines where [ousaged] appear make sure" + elog "that \"disable 1\" appear. And anywhere add the lines :" + elog " [fsousage]" + elog " [fsousage.controller]" + elog "With this the daemon will be used without any need of initscript." +} |