From a80fd7ea7b314b73f8c701b3d5e8900dd57a89c4 Mon Sep 17 00:00:00 2001 From: Simo Piiroinen Date: Tue, 20 Aug 2019 10:02:59 +0300 Subject: [PATCH] [battery-udev] Make charger type available on D-Bus. JB#38667 Battery notifier in lipstick needs charger type information. Add charger type evaluation to udev power supply device tracker and broadcast changes internally within mce via a datapipe. Reflect datapipe changes as D-Bus signals, and add D-Bus methods for querying the current state. For development builds enable charger type simulation and appropriate mcetool options for controlling it. The required D-Bus constants are available in mce-dev >= 1.27.0. Signed-off-by: Simo Piiroinen --- .depend | 20 ++--- datapipe.c | 66 ++++++++++++++ datapipe.h | 2 + mce-common.c | 118 +++++++++++++++++++++++- mce-dbus.h | 20 +++++ mce.conf | 3 + mce.h | 38 +++++++- modules/battery-udev.c | 199 +++++++++++++++++++++++++++++++++++++++-- rpm/mce.spec | 2 +- tools/mcetool.c | 69 ++++++++++++++ 10 files changed, 518 insertions(+), 19 deletions(-) diff --git a/.depend b/.depend index dadcbab1..f42a3969 100644 --- a/.depend +++ b/.depend @@ -1344,6 +1344,16 @@ tklock.pic.o:\ systemui/tklock-dbus-names.h\ tklock.h\ +tools/dummy_compositor.o:\ + tools/dummy_compositor.c\ + builtin-gconf.h\ + mce-dbus.h\ + +tools/dummy_compositor.pic.o:\ + tools/dummy_compositor.c\ + builtin-gconf.h\ + mce-dbus.h\ + tools/evdev_trace.o:\ tools/evdev_trace.c\ evdev.h\ @@ -1356,16 +1366,6 @@ tools/evdev_trace.pic.o:\ mce-log.h\ tools/fileusers.h\ -tools/dummy_compositor.o:\ - tools/dummy_compositor.c\ - builtin-gconf.h\ - mce-dbus.h\ - -tools/dummy_compositor.pic.o:\ - tools/dummy_compositor.c\ - builtin-gconf.h\ - mce-dbus.h\ - tools/fileusers.o:\ tools/fileusers.c\ mce-log.h\ diff --git a/datapipe.c b/datapipe.c index 9154a320..97f59695 100644 --- a/datapipe.c +++ b/datapipe.c @@ -5,6 +5,7 @@ *

* Copyright © 2007-2008 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2014-2019 Jolla Ltd. + * Copyright (c) 2019 Open Mobile Platform LLC. *

* @author David Weinehall * @author Simo Piiroinen @@ -113,6 +114,7 @@ static const char *datapipe_hook_call_state_value (gconstpointer data); static const char *datapipe_hook_call_type_value (gconstpointer data); static const char *datapipe_hook_tklock_request_value (gconstpointer data); static const char *datapipe_hook_charger_state_value (gconstpointer data); +static const char *datapipe_hook_charger_type_value (gconstpointer data); static const char *datapipe_hook_battery_status_value (gconstpointer data); static const char *datapipe_hook_camera_button_state_value(gconstpointer data); static const char *datapipe_hook_audio_route_value (gconstpointer data); @@ -202,6 +204,13 @@ const char *service_state_repr(service_state_t state); const char *usb_cable_state_repr (usb_cable_state_t state); const char *usb_cable_state_to_dbus(usb_cable_state_t state); +/* ------------------------------------------------------------------------- * + * CHARGER_TYPE + * ------------------------------------------------------------------------- */ + +const char *charger_type_repr (charger_type_t type); +const char *charger_type_to_dbus(charger_type_t type); + /* ------------------------------------------------------------------------- * * CHARGER_STATE * ------------------------------------------------------------------------- */ @@ -473,6 +482,14 @@ datapipe_hook_tklock_request_value(gconstpointer data) } #define datapipe_hook_tklock_request_change 0 +static const char * +datapipe_hook_charger_type_value(gconstpointer data) +{ + charger_type_t value = GPOINTER_TO_INT(data); + return charger_type_repr(value); +} +#define datapipe_hook_charger_type_change 0 + static const char * datapipe_hook_charger_state_value(gconstpointer data) { @@ -698,6 +715,9 @@ datapipe_t tklock_request_pipe = DATAPIPE_INIT(tklock_request, /** UI side is in a state where user interaction is expected */ datapipe_t interaction_expected_pipe = DATAPIPE_INIT(interaction_expected, boolean, false, 0, DATAPIPE_FILTERING_DENIED, DATAPIPE_CACHE_DEFAULT); +/** Charger type; read only */ +datapipe_t charger_type_pipe = DATAPIPE_INIT(charger_type, charger_type, CHARGER_TYPE_NONE, 0, DATAPIPE_FILTERING_DENIED, DATAPIPE_CACHE_DEFAULT); + /** Charger state; read only */ datapipe_t charger_state_pipe = DATAPIPE_INIT(charger_state, charger_state, CHARGER_STATE_UNDEF, 0, DATAPIPE_FILTERING_DENIED, DATAPIPE_CACHE_DEFAULT); @@ -1283,6 +1303,7 @@ void mce_datapipe_quit(void) datapipe_free(&topmost_window_pid_pipe); datapipe_free(&camera_button_state_pipe); datapipe_free(&battery_status_pipe); + datapipe_free(&charger_type_pipe); datapipe_free(&charger_state_pipe); datapipe_free(&interaction_expected_pipe); datapipe_free(&tklock_request_pipe); @@ -1614,6 +1635,51 @@ const char *usb_cable_state_to_dbus(usb_cable_state_t state) return res; } +/** Convert charger_type_t enum to human readable string + * + * @param type charger_type_t enumeration value + * + * @return human readable representation of type + */ +const char * +charger_type_repr(charger_type_t type) +{ + const char *repr = "unknown"; + switch( type ) { + case CHARGER_TYPE_NONE: repr = "none"; break; + case CHARGER_TYPE_USB: repr = "usb"; break; + case CHARGER_TYPE_DCP: repr = "dcp"; break; + case CHARGER_TYPE_HVDCP: repr = "hwdcp"; break; + case CHARGER_TYPE_CDP: repr = "cdp"; break; + case CHARGER_TYPE_WIRELESS: repr = "wireless"; break; + case CHARGER_TYPE_OTHER: repr = "other"; break; + default: break; + } + return repr; +} + +/** Convert charger_type_t enum to dbus argument string + * + * @param type charger_type_t enumeration value + * + * @return representation of type for use over dbus + */ +const char * +charger_type_to_dbus(charger_type_t type) +{ + const char *repr = MCE_CHARGER_TYPE_OTHER; + switch( type ) { + case CHARGER_TYPE_NONE: repr = MCE_CHARGER_TYPE_NONE; break; + case CHARGER_TYPE_USB: repr = MCE_CHARGER_TYPE_USB; break; + case CHARGER_TYPE_DCP: repr = MCE_CHARGER_TYPE_DCP; break; + case CHARGER_TYPE_HVDCP: repr = MCE_CHARGER_TYPE_HVDCP; break; + case CHARGER_TYPE_CDP: repr = MCE_CHARGER_TYPE_CDP; break; + case CHARGER_TYPE_WIRELESS: repr = MCE_CHARGER_TYPE_WIRELESS; break; + default: break; + } + return repr; +} + /** Convert charger_state_t enum to human readable string * * @param state charger_state_t enumeration value diff --git a/datapipe.h b/datapipe.h index 5d8a48fb..a06b2581 100644 --- a/datapipe.h +++ b/datapipe.h @@ -4,6 +4,7 @@ *

* Copyright © 2007 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2014-2019 Jolla Ltd. + * Copyright (c) 2019 Open Mobile Platform LLC. *

* @author David Weinehall * @author: Simo Piiroinen @@ -253,6 +254,7 @@ extern datapipe_t ignore_incoming_call_event_pipe; extern datapipe_t call_type_pipe; extern datapipe_t tklock_request_pipe; extern datapipe_t interaction_expected_pipe; +extern datapipe_t charger_type_pipe; extern datapipe_t charger_state_pipe; extern datapipe_t battery_status_pipe; extern datapipe_t battery_level_pipe; diff --git a/mce-common.c b/mce-common.c index e4032a83..e65f60f0 100644 --- a/mce-common.c +++ b/mce-common.c @@ -3,6 +3,7 @@ * Common state logic for Mode Control Entity *

* Copyright (C) 2017-2019 Jolla Ltd. + * Copyright (c) 2019 Open Mobile Platform LLC. *

* @author Simo Piiroinen * @@ -78,6 +79,8 @@ static void common_on_proximity_quit (void); static void common_dbus_send_usb_cable_state (DBusMessage *const req); static gboolean common_dbus_get_usb_cable_state_cb(DBusMessage *const req); +static void common_dbus_send_charger_type (DBusMessage *const req); +static gboolean common_dbus_get_charger_type_cb (DBusMessage *const req); static void common_dbus_send_charger_state (DBusMessage *const req); static gboolean common_dbus_get_charger_state_cb (DBusMessage *const req); static void common_dbus_send_battery_status (DBusMessage *const req); @@ -93,6 +96,7 @@ static void common_dbus_quit (void); * ------------------------------------------------------------------------- */ static void common_datapipe_usb_cable_state_cb (gconstpointer data); +static void common_datapipe_charger_type_cb (gconstpointer data); static void common_datapipe_charger_state_cb (gconstpointer data); static void common_datapipe_battery_status_cb (gconstpointer data); static void common_datapipe_battery_level_cb (gconstpointer data); @@ -114,6 +118,9 @@ void mce_common_quit(void); /** USB cable status; assume undefined */ static usb_cable_state_t usb_cable_state = USB_CABLE_UNDEF; +/** Charger type; assume none */ +static charger_type_t charger_type = CHARGER_TYPE_NONE; + /** Charger state; assume undefined */ static charger_state_t charger_state = CHARGER_STATE_UNDEF; @@ -393,6 +400,69 @@ common_dbus_get_usb_cable_state_cb(DBusMessage *const req) return TRUE; } +/* ------------------------------------------------------------------------- * + * charger_type + * ------------------------------------------------------------------------- */ + +/** Send charger_type D-Bus signal / method call reply + * + * @param req method call message to reply, or NULL to send signal + */ +static void +common_dbus_send_charger_type(DBusMessage *const req) +{ + static const char *last = 0; + + DBusMessage *msg = NULL; + + const char *value = charger_type_to_dbus(charger_type); + + if( req ) { + msg = dbus_new_method_reply(req); + } + else if( last == value ) { + goto EXIT; + } + else { + last = value; + msg = dbus_new_signal(MCE_SIGNAL_PATH, + MCE_SIGNAL_IF, + MCE_CHARGER_TYPE_SIG); + } + + if( !dbus_message_append_args(msg, + DBUS_TYPE_STRING, &value, + DBUS_TYPE_INVALID) ) + goto EXIT; + + mce_log(LL_DEBUG, "%s: %s = %s", + req ? "reply" : "broadcast", + "charger_type", value); + + dbus_send_message(msg), msg = 0; + +EXIT: + + if( msg ) + dbus_message_unref(msg); +} + +/** Callback for handling charger_type D-Bus queries + * + * @param req method call message to reply + */ +static gboolean +common_dbus_get_charger_type_cb(DBusMessage *const req) +{ + mce_log(LL_DEBUG, "charger_type query from: %s", + mce_dbus_get_message_sender_ident(req)); + + if( !dbus_message_get_no_reply(req) ) + common_dbus_send_charger_type(req); + + return TRUE; +} + /* ------------------------------------------------------------------------- * * charger_state * ------------------------------------------------------------------------- */ @@ -562,7 +632,7 @@ common_dbus_send_battery_level(DBusMessage *const req) mce_log(LL_DEBUG, "%s: %s = %d", req ? "reply" : "broadcast", - "charger_state", value); + "battery_level", value); dbus_send_message(msg), msg = 0; @@ -603,6 +673,13 @@ static mce_dbus_handler_t common_dbus_handlers[] = .args = " \n" }, + { + .interface = MCE_SIGNAL_IF, + .name = MCE_CHARGER_TYPE_SIG, + .type = DBUS_MESSAGE_TYPE_SIGNAL, + .args = + " \n" + }, { .interface = MCE_SIGNAL_IF, .name = MCE_CHARGER_STATE_SIG, @@ -633,6 +710,14 @@ static mce_dbus_handler_t common_dbus_handlers[] = .args = " \n" }, + { + .interface = MCE_REQUEST_IF, + .name = MCE_CHARGER_TYPE_GET, + .type = DBUS_MESSAGE_TYPE_METHOD_CALL, + .callback = common_dbus_get_charger_type_cb, + .args = + " \n" + }, { .interface = MCE_REQUEST_IF, .name = MCE_CHARGER_STATE_GET, @@ -683,6 +768,7 @@ static gboolean common_dbus_initial_cb(gpointer aptr) * some values to undefined state. */ common_dbus_send_usb_cable_state(0); + common_dbus_send_charger_type(0); common_dbus_send_charger_state(0); common_dbus_send_battery_status(0); common_dbus_send_battery_level(0); @@ -754,6 +840,32 @@ static void common_datapipe_usb_cable_state_cb(gconstpointer data) return; } +/* ------------------------------------------------------------------------- * + * charger_type + * ------------------------------------------------------------------------- */ + +/** Callback for handling charger_type_pipe state changes + * + * @param data charger_type (as void pointer) + */ +static void common_datapipe_charger_type_cb(gconstpointer data) +{ + charger_type_t prev = charger_type; + charger_type = GPOINTER_TO_INT(data); + + if( charger_type == prev ) + goto EXIT; + + mce_log(LL_DEBUG, "charger_type = %s -> %s", + charger_type_repr(prev), + charger_type_repr(charger_type)); + + common_dbus_send_charger_type(0); + +EXIT: + return; +} + /* ------------------------------------------------------------------------- * * charger_state * ------------------------------------------------------------------------- */ @@ -868,6 +980,10 @@ static datapipe_handler_t common_datapipe_handlers[] = .datapipe = &usb_cable_state_pipe, .output_cb = common_datapipe_usb_cable_state_cb, }, + { + .datapipe = &charger_type_pipe, + .output_cb = common_datapipe_charger_type_cb, + }, { .datapipe = &charger_state_pipe, .output_cb = common_datapipe_charger_state_cb, diff --git a/mce-dbus.h b/mce-dbus.h index d180e7ad..18fd3d4a 100644 --- a/mce-dbus.h +++ b/mce-dbus.h @@ -4,6 +4,7 @@ *

* Copyright © 2004-2010 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2013-2019 Jolla Ltd. + * Copyright (c) 2019 Open Mobile Platform LLC. *

* @author David Weinehall * @author Simo Piiroinen @@ -49,6 +50,25 @@ */ # define MCE_CHARGER_STATE_REQ "req_charger_state" +/** Override current charger type + * + * Available in devel flavor mce only, and only to privileged applications. + * + * @since mce 1.102.0 + * + * @param string: current charger type, one of: + * - #MCE_CHARGER_TYPE_NONE + * - #MCE_CHARGER_TYPE_USB + * - #MCE_CHARGER_TYPE_DCP + * - #MCE_CHARGER_TYPE_HVDCP + * - #MCE_CHARGER_TYPE_CDP + * - #MCE_CHARGER_TYPE_WIRELESS + * - #MCE_CHARGER_TYPE_OTHER + * + * @return boolean true if accepted, false / error reply otherwise + */ +# define MCE_CHARGER_TYPE_REQ "req_charger_type" + /** Override current battery level * * Available in devel flavor mce only, and only to privileged applications. diff --git a/mce.conf b/mce.conf index 2ccd69fe..f403ec59 100644 --- a/mce.conf +++ b/mce.conf @@ -225,6 +225,9 @@ + * Copyright © 2004-2011 Nokia Corporation and/or its subsidiary(-ies). - * Copyright (C) 2012-2017 Jolla Ltd. + * Copyright (C) 2012-2019 Jolla Ltd. + * Copyright (c) 2019 Open Mobile Platform LLC. *

* @author David Weinehall * @author Irina Bezruk @@ -334,6 +335,41 @@ typedef enum { const char *charger_state_repr(charger_state_t state); const char *charger_state_to_dbus(charger_state_t state); +/** Known charger types + * + * Note that the ordering is: + * + * a) significant in the sense that in case there are several chargers + * connected and active at the same time, maximum numerical value is + * exposed as effective charger type on D-Bus + * + * b) internal to mce, so that values can and should be rearranged if + * there should be changes in what makes sense to ui side. + */ +typedef enum +{ + CHARGER_TYPE_NONE, + + /* Charger types that do not carry special meaning from + * sfos UI point of view. + */ + CHARGER_TYPE_OTHER, + CHARGER_TYPE_WIRELESS, + CHARGER_TYPE_CDP, // Charging Downstream Port + + /* Wall chargers imply notification on disconnect + */ + CHARGER_TYPE_DCP, // Dedicated Charging Port + CHARGER_TYPE_HVDCP, // High Voltage DCP + + /* PC connection implies usb mode management + */ + CHARGER_TYPE_USB, // Standard Downstream Port +} charger_type_t; + +const char *charger_type_repr(charger_type_t type); +const char *charger_type_to_dbus(charger_type_t type); + /** Camera button state */ typedef enum { CAMERA_BUTTON_UNDEF = -1, /**< Camera button state not set */ diff --git a/modules/battery-udev.c b/modules/battery-udev.c index efd76edd..e08f481e 100644 --- a/modules/battery-udev.c +++ b/modules/battery-udev.c @@ -2,7 +2,8 @@ * @file battery-udev.c * Battery module -- this implements battery and charger logic for MCE *

- * Copyright (C) 2018 Jolla Ltd. + * Copyright (C) 2018-2019 Jolla Ltd. + * Copyright (c) 2019 Open Mobile Platform LLC. *

* @author Simo Piiroinen *

@@ -58,10 +59,12 @@ #define BATTERY_CAPACITY_FULL 90 // statefs uses 96 /* Power supply device properties we are interested in */ -#define PROP_PRESENT "POWER_SUPPLY_PRESENT" -#define PROP_ONLINE "POWER_SUPPLY_ONLINE" -#define PROP_CAPACITY "POWER_SUPPLY_CAPACITY" -#define PROP_STATUS "POWER_SUPPLY_STATUS" +#define PROP_PRESENT "POWER_SUPPLY_PRESENT" +#define PROP_ONLINE "POWER_SUPPLY_ONLINE" +#define PROP_CAPACITY "POWER_SUPPLY_CAPACITY" +#define PROP_STATUS "POWER_SUPPLY_STATUS" +#define PROP_REAL_TYPE "POWER_SUPPLY_REAL_TYPE" +#define PROP_TYPE "POWER_SUPPLY_TYPE" /** INI-file group for blacklisting device properties */ #define MCE_CONF_BATTERY_UDEV_PROPERTY_BLACKLIST_GROUP "BatteryUDevPropertyBlacklist" @@ -115,6 +118,9 @@ typedef struct /** Charger connected; for use with charger_state_pipe */ charger_state_t charger_state; + + /** Charger type; for tweaking UI behavior */ + charger_type_t charger_type; } mcebat_t; typedef struct udevtracker_t udevtracker_t; @@ -191,6 +197,7 @@ static gboolean mcebat_dbus_client_removed_cb (DBusMessage *const msg); static bool mcebat_dbus_add_client (const char *dbus_name); static void mcebat_dbus_evaluate_battery_status(void); static gboolean mcebat_dbus_charger_state_req_cb (DBusMessage *const msg); +static gboolean mcebat_dbus_charger_type_req_cb (DBusMessage *const msg); static gboolean mcebat_dbus_battery_level_req_cb (DBusMessage *const msg); #endif // ENABLE_BATTERY_SIMULATION @@ -217,6 +224,7 @@ static bool udevproperty_set (udevproperty_t *self, const ch * UDEVDEVICE * ------------------------------------------------------------------------- */ +static charger_type_t udevdevice_lookup_charger_type(const char *name); static void udevdevice_init_blacklist (void); static void udevdevice_quit_blacklist (void); static bool udevdevice_is_blacklisted (const char *name); @@ -287,6 +295,7 @@ static mcebat_t mcebat_datapipe = { .battery_level = BATTERY_LEVEL_INITIAL, .battery_status = BATTERY_STATUS_UNDEF, .charger_state = CHARGER_STATE_UNDEF, + .charger_type = CHARGER_TYPE_NONE, }; /** Cached battery state as derived from udev @@ -295,6 +304,7 @@ static mcebat_t mcebat_actual = { .battery_level = BATTERY_LEVEL_INITIAL, .battery_status = BATTERY_STATUS_UNDEF, .charger_state = CHARGER_STATE_UNDEF, + .charger_type = CHARGER_TYPE_NONE, }; #ifdef ENABLE_BATTERY_SIMULATION @@ -342,6 +352,8 @@ static const char * const udevproperty_used_keys[] = { PROP_PRESENT, // charger PROP_ONLINE, + PROP_REAL_TYPE, + PROP_TYPE, // battery PROP_CAPACITY, PROP_STATUS, @@ -485,6 +497,77 @@ mcebat_dbus_evaluate_battery_status(void) return; } +/** D-Bus callback: Simulated charger type requested + * + * @param msg The D-Bus message + * + * @return TRUE + */ +static gboolean +mcebat_dbus_charger_type_req_cb(DBusMessage *const msg) +{ + dbus_bool_t accepted = false; + const char *sender = dbus_message_get_sender(msg); + DBusError error = DBUS_ERROR_INIT; + const char *type = 0; + DBusMessage *reply = 0; + + mce_log(LL_DEVEL, "charger type request from %s", + mce_dbus_get_name_owner_ident(sender)); + + if( !mcebat_dbus_add_client(sender) ) + goto EXIT; + + if( !dbus_message_get_args(msg, &error, + DBUS_TYPE_STRING, &type, + DBUS_TYPE_INVALID) ) { + goto EXIT; + } + + if( !strcmp(type, MCE_CHARGER_TYPE_NONE) ) + mcebat_simulated.charger_type = CHARGER_TYPE_NONE; + else if( !strcmp(type, MCE_CHARGER_TYPE_USB) ) + mcebat_simulated.charger_type = CHARGER_TYPE_USB; + else if( !strcmp(type, MCE_CHARGER_TYPE_DCP) ) + mcebat_simulated.charger_type = CHARGER_TYPE_DCP; + else if( !strcmp(type, MCE_CHARGER_TYPE_HVDCP) ) + mcebat_simulated.charger_type = CHARGER_TYPE_HVDCP; + else if( !strcmp(type, MCE_CHARGER_TYPE_CDP) ) + mcebat_simulated.charger_type = CHARGER_TYPE_CDP; + else if( !strcmp(type, MCE_CHARGER_TYPE_WIRELESS) ) + mcebat_simulated.charger_type = CHARGER_TYPE_WIRELESS; + else + mcebat_simulated.charger_type = CHARGER_TYPE_OTHER; + + mcebat_dbus_evaluate_battery_status(); + mcebat_update(); + + accepted = true; + +EXIT: + /* Setup the reply */ + reply = dbus_new_method_reply(msg); + + /* Append the result */ + if( !dbus_message_append_args(reply, + DBUS_TYPE_BOOLEAN, &accepted, + DBUS_TYPE_INVALID)) { + mce_log(LL_ERR,"Failed to append reply arguments to D-Bus " + "message for %s.%s", + MCE_REQUEST_IF, dbus_message_get_member(msg)); + } + else if( !dbus_message_get_no_reply(msg) ) { + dbus_send_message(reply), reply = 0; + } + + if( reply ) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return TRUE; +} + /** D-Bus callback: Simulated charger state requested * * @param msg The D-Bus message @@ -612,6 +695,16 @@ static mce_dbus_handler_t callstate_dbus_handlers[] = { /* method calls */ #ifdef ENABLE_BATTERY_SIMULATION + { + .interface = MCE_REQUEST_IF, + .name = MCE_CHARGER_TYPE_REQ, + .type = DBUS_MESSAGE_TYPE_METHOD_CALL, + .callback = mcebat_dbus_charger_type_req_cb, + .privileged = true, + .args = + " \n" + " \n" + }, { .interface = MCE_REQUEST_IF, .name = MCE_CHARGER_STATE_REQ, @@ -679,6 +772,15 @@ mcebat_update(void) mcebat_t prev = mcebat_datapipe; mcebat_datapipe = *curr; + if( prev.charger_type != curr->charger_type ) { + mce_log(LL_CRUCIAL, "charger_type: %s -> %s", + charger_type_repr(prev.charger_type), + charger_type_repr(curr->charger_type)); + + datapipe_exec_full(&charger_type_pipe, + GINT_TO_POINTER(curr->charger_type)); + } + if( prev.charger_state != curr->charger_state ) { mce_log(LL_CRUCIAL, "charger_state: %s -> %s", charger_state_repr(prev.charger_state), @@ -943,6 +1045,60 @@ udevproperty_set(udevproperty_t *self, const char *val) * UDEVDEVICE * ========================================================================= */ +/** Lookup charger type based on device name / value of type property + * + * @param name string to match + * + * @return charger_type_t enumeration value + */ +static charger_type_t +udevdevice_lookup_charger_type(const char *name) +{ + static const struct { + const char *name; + int value; + } lut[] = { + /* Type map - adapted from statefs sources + */ + { "CDP", CHARGER_TYPE_CDP }, + { "USB_CDP", CHARGER_TYPE_CDP }, + { "USB_DCP", CHARGER_TYPE_DCP }, + { "USB_HVDCP", CHARGER_TYPE_HVDCP }, + { "USB_HVDCP_3", CHARGER_TYPE_HVDCP }, + { "Mains", CHARGER_TYPE_DCP }, + { "USB", CHARGER_TYPE_USB }, + { "USB_ACA", CHARGER_TYPE_USB }, + + /* Additions since leaving statefs behind + */ + { "WIRELESS", CHARGER_TYPE_WIRELESS }, + { "AC", CHARGER_TYPE_DCP }, + + /* To make connect/disconnect transitions + * cleaner, ignore "Unknown" reporting + */ + { "Unknown", CHARGER_TYPE_NONE }, + + /* Sentinel */ + { 0, 0 } + }; + + charger_type_t value = CHARGER_TYPE_OTHER; + if( name ) { + for( size_t i = 0; ; ++i ) { + if( lut[i].name == 0 ) { + mce_log(LL_WARN, "unknown charger type: %s", name); + break; + } + if( !g_ascii_strcasecmp(lut[i].name, name) ) { + value = lut[i].value; + break; + } + } + } + return value; +} + /** Initialize device blacklist lookup table */ static void @@ -1248,9 +1404,36 @@ udevdevice_evaluate_charger(udevdevice_t *self, mcebat_t *mcebat) bool active = (present == 1 || online == 1); - if( active ) + if( active ) { mcebat->charger_state = CHARGER_STATE_ON; + /* Charger is online, evaluate charger type + * + * Legacy QC devices have TYPE property that has + * content sfos sw stack knows how to interpret. + * + * More recent QC devices might expose "USB_PD" in + * TYPE prop and have additional REAL_TYPE property + * containing old style data. + * + * MTK devices have multiple power supply device + * nodes visible in udev and charger type must be + * determined from device node name. + */ + const char *name; + if( !(name = udevdevice_get_str_prop(self, PROP_REAL_TYPE, 0)) ) { + if( !(name = udevdevice_get_str_prop(self, PROP_TYPE, 0)) ) + name = udevdevice_name(self); + } + + charger_type_t type = udevdevice_lookup_charger_type(name); + + /* Update effective charger type exposed on D-Bus + */ + if( mcebat->charger_type < type ) + mcebat->charger_type = type; + } + mce_log(LL_DEBUG, "%s: charger @ " "present=%d online=%d -> active=%d", udevdevice_name(self), @@ -1449,6 +1632,10 @@ udevtracker_rethink(udevtracker_t *self) * indicate charging activity. */ mcebat_actual.charger_state = CHARGER_STATE_OFF; + /* Reset charger type, iterator chooses maximum of + * none < other < wall chargers < pc connection. */ + mcebat_actual.charger_type = CHARGER_TYPE_NONE; + g_hash_table_foreach(self->udt_devices, udevdevice_evaluate_charger_cb, &mcebat_actual); g_hash_table_foreach(self->udt_devices, udevdevice_evaluate_battery_cb, &mcebat_actual); diff --git a/rpm/mce.spec b/rpm/mce.spec index 990fbcd6..9d7ffc16 100644 --- a/rpm/mce.spec +++ b/rpm/mce.spec @@ -20,7 +20,7 @@ BuildRequires: pkgconfig(dsme) >= 0.65.0 BuildRequires: pkgconfig(thermalmanager_dbus_if) BuildRequires: pkgconfig(libiphb) BuildRequires: pkgconfig(glib-2.0) >= 2.36.0 -BuildRequires: pkgconfig(mce) >= 1.26.0 +BuildRequires: pkgconfig(mce) >= 1.27.0 BuildRequires: pkgconfig(libngf0) >= 0.24 BuildRequires: pkgconfig(libsystemd-daemon) BuildRequires: kernel-headers >= 2.6.32 diff --git a/tools/mcetool.c b/tools/mcetool.c index 76b90ad2..1e3941cc 100644 --- a/tools/mcetool.c +++ b/tools/mcetool.c @@ -3,6 +3,7 @@ *

* Copyright © 2005-2011 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2012-2019 Jolla Ltd. + * Copyright (c) 2019 Open Mobile Platform LLC. *

* @author David Weinehall * @author Santtu Lakkala @@ -139,6 +140,7 @@ static bool xmce_get_color_profile_ids (const ch static bool xmce_set_color_profile (const char *args); static void xmce_get_color_profile (void); #ifdef ENABLE_BATTERY_SIMULATION +static bool xmce_set_charger_type (const char *type); static bool xmce_set_charger_state (const char *state); static bool xmce_set_battery_level (int level); #endif @@ -438,6 +440,7 @@ static bool mcetool_do_disable_led_pattern(const char *args); static bool mcetool_do_activate_pattern (const char *args); static bool mcetool_do_deactivate_pattern (const char *args); #ifdef ENABLE_BATTERY_SIMULATION +static bool mcetool_do_set_charger_type(const char *arg); static bool mcetool_do_set_charger_state (const char *arg); static bool mcetool_do_set_battery_level (const char *arg); #endif @@ -2583,6 +2586,33 @@ static void xmce_get_color_profile(void) * ------------------------------------------------------------------------- */ #ifdef ENABLE_BATTERY_SIMULATION +static bool xmce_set_charger_type(const char *type) +{ + dbus_bool_t ret = false; + DBusError err = DBUS_ERROR_INIT; + DBusMessage *rsp = 0; + gboolean ack = xmce_ipc(MCE_CHARGER_TYPE_REQ, &rsp, + DBUS_TYPE_STRING, &type, + DBUS_TYPE_INVALID); + if( !ack || !rsp ) + goto EXIT; + + if( !dbus_message_get_args(rsp, &err, + DBUS_TYPE_BOOLEAN, &ret, + DBUS_TYPE_INVALID) ) + goto EXIT; + +EXIT: + if( dbus_error_is_set(&err) ) { + errorf("set %s: %s: %s\n", type, err.name, err.message); + dbus_error_free(&err); + } + + if( rsp ) dbus_message_unref(rsp); + + return ack && ret; +} + static bool xmce_set_charger_state(const char *state) { dbus_bool_t ret = false; @@ -2638,6 +2668,31 @@ static bool xmce_set_battery_level(int level) return ack && ret; } +static bool mcetool_do_set_charger_type(const char *arg) +{ + const char * const lut[] = { + MCE_CHARGER_TYPE_NONE, + MCE_CHARGER_TYPE_USB, + MCE_CHARGER_TYPE_DCP, + MCE_CHARGER_TYPE_HVDCP, + MCE_CHARGER_TYPE_CDP, + MCE_CHARGER_TYPE_WIRELESS, + MCE_CHARGER_TYPE_OTHER, + 0 + }; + + for( size_t i = 0; ; ++i ) { + if( !lut[i] ) { + errorf("%s: invalid charger type\n", arg); + return false; + } + if( !strcmp(lut[i], arg) ) + break; + } + + return xmce_set_charger_type(arg); +} + static bool mcetool_do_set_charger_state(const char *arg) { const char * const lut[] = { @@ -7863,6 +7918,20 @@ static const mce_opt_t options[] = " disables the feature.\n" }, #ifdef ENABLE_BATTERY_SIMULATION + { + .name = "set-charger-type", + .with_arg = mcetool_do_set_charger_type, + .values = + MCE_CHARGER_TYPE_NONE "|" + MCE_CHARGER_TYPE_USB "|" + MCE_CHARGER_TYPE_DCP "|" + MCE_CHARGER_TYPE_HVDCP "|" + MCE_CHARGER_TYPE_CDP "|" + MCE_CHARGER_TYPE_WIRELESS "|" + MCE_CHARGER_TYPE_OTHER, + .usage = + "Override charger type for debugging purposes\n" + }, { .name = "set-charger-state", .with_arg = mcetool_do_set_charger_state,