@@ -981,6 +981,7 @@ static void cmd_show(int argc, char *argv[])
print_property(adapter->proxy, "Alias");
print_property(adapter->proxy, "Class");
print_property(adapter->proxy, "Powered");
+ print_property(adapter->proxy, "PowerState");
print_property(adapter->proxy, "Discoverable");
print_property(adapter->proxy, "DiscoverableTimeout");
print_property(adapter->proxy, "Pairable");
@@ -269,6 +269,20 @@ Properties string Address [readonly]
restart or unplugging of the adapter it will reset
back to false.
+ string PowerState [readonly]
+
+ The power state of an adapter.
+
+ The power state will show whether the adapter is
+ turning off, or turning on, as well as being on
+ or off.
+
+ Possible values:
+ "on" - powered on
+ "off" - powered off
+ "turning-on" - transitioning from "off" to "on"
+ "turning-off" - transitioning from "on" to "off"
+
boolean Discoverable [readwrite]
Switch an adapter to discoverable or non-discoverable
@@ -239,6 +239,12 @@ struct btd_adapter_pin_cb_iter {
/* When the iterator reaches the end, it is NULL and attempt is 0 */
};
+enum {
+ ADAPTER_POWER_STATE_TARGET_NONE = 0,
+ ADAPTER_POWER_STATE_TARGET_OFF,
+ ADAPTER_POWER_STATE_TARGET_ON
+};
+
struct btd_adapter {
int ref_count;
@@ -252,6 +258,7 @@ struct btd_adapter {
char *short_name; /* controller short name */
uint32_t supported_settings; /* controller supported settings */
uint32_t pending_settings; /* pending controller settings */
+ uint32_t power_state_target; /* the target power state */
uint32_t current_settings; /* current controller settings */
char *path; /* adapter object path */
@@ -579,6 +586,8 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
if (changed_mask & MGMT_SETTING_POWERED) {
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Powered");
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "PowerState");
if (adapter->current_settings & MGMT_SETTING_POWERED) {
adapter_start(adapter);
@@ -618,6 +627,16 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
}
}
+static void reset_power_state_target(struct btd_adapter *adapter, uint8_t value)
+{
+ if ((value &&
+ adapter->power_state_target == ADAPTER_POWER_STATE_TARGET_ON) ||
+ (!value &&
+ adapter->power_state_target == ADAPTER_POWER_STATE_TARGET_OFF)) {
+ adapter->power_state_target = ADAPTER_POWER_STATE_TARGET_NONE;
+ }
+}
+
static void new_settings_callback(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
@@ -635,6 +654,9 @@ static void new_settings_callback(uint16_t index, uint16_t length,
if (settings == adapter->current_settings)
return;
+ if ((adapter->current_settings ^ settings) & MGMT_SETTING_POWERED)
+ reset_power_state_target(adapter, settings & MGMT_SETTING_POWERED ? 0x01 : 0x00);
+
DBG("Settings: 0x%08x", settings);
settings_changed(adapter, settings);
@@ -643,6 +665,7 @@ static void new_settings_callback(uint16_t index, uint16_t length,
struct set_mode_data {
struct btd_adapter *adapter;
uint32_t setting;
+ uint8_t value;
};
static void set_mode_complete(uint8_t status, uint16_t length,
@@ -655,6 +678,8 @@ static void set_mode_complete(uint8_t status, uint16_t length,
btd_error(adapter->dev_id, "Failed to set mode: %s (0x%02x)",
mgmt_errstr(status), status);
adapter->pending_settings &= ~data->setting;
+ if (data->setting & MGMT_SETTING_POWERED)
+ reset_power_state_target(adapter, data->value);
return;
}
@@ -692,6 +717,11 @@ static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
switch (opcode) {
case MGMT_OP_SET_POWERED:
setting = MGMT_SETTING_POWERED;
+ adapter->power_state_target = mode ?
+ ADAPTER_POWER_STATE_TARGET_ON :
+ ADAPTER_POWER_STATE_TARGET_OFF;
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "PowerState");
break;
case MGMT_OP_SET_CONNECTABLE:
setting = MGMT_SETTING_CONNECTABLE;
@@ -712,6 +742,7 @@ static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
data = g_new0(struct set_mode_data, 1);
data->adapter = adapter;
data->setting = setting;
+ data->value = mode;
if (mgmt_send(adapter->mgmt, opcode,
adapter->dev_id, sizeof(cp), &cp,
@@ -719,8 +750,13 @@ static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
adapter->pending_settings |= setting;
return true;
}
-
g_free(data);
+ if (setting == MGMT_SETTING_POWERED) {
+ /* cancel the earlier setting */
+ adapter->power_state_target = ADAPTER_POWER_STATE_TARGET_NONE;
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "PowerState");
+ }
btd_error(adapter->dev_id, "Failed to set mode for index %u",
adapter->dev_id);
@@ -2898,6 +2934,7 @@ struct property_set_data {
struct btd_adapter *adapter;
uint32_t setting;
GDBusPendingPropertySet id;
+ uint8_t value;
};
static void property_set_mode_complete(uint8_t status, uint16_t length,
@@ -2923,6 +2960,8 @@ static void property_set_mode_complete(uint8_t status, uint16_t length,
mgmt_errstr(status));
adapter->pending_settings &= ~data->setting;
+ if (data->setting & MGMT_SETTING_POWERED)
+ reset_power_state_target(adapter, data->value);
return;
}
@@ -3046,6 +3085,16 @@ static void property_set_mode(struct btd_adapter *adapter, uint32_t setting,
data->adapter = adapter;
data->setting = setting;
data->id = id;
+ data->setting = setting;
+ data->value = mode;
+
+ if (setting == MGMT_SETTING_POWERED) {
+ adapter->power_state_target = mode ?
+ ADAPTER_POWER_STATE_TARGET_ON :
+ ADAPTER_POWER_STATE_TARGET_OFF;
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "PowerState");
+ }
if (mgmt_send(adapter->mgmt, opcode, adapter->dev_id, len, param,
property_set_mode_complete, data, g_free) > 0) {
@@ -3054,6 +3103,12 @@ static void property_set_mode(struct btd_adapter *adapter, uint32_t setting,
}
g_free(data);
+ if (setting == MGMT_SETTING_POWERED) {
+ /* cancel the earlier setting */
+ adapter->power_state_target = ADAPTER_POWER_STATE_TARGET_NONE;
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "PowerState");
+ }
failed:
btd_error(adapter->dev_id, "Failed to set mode for index %u",
@@ -3085,6 +3140,29 @@ static void property_set_powered(const GDBusPropertyTable *property,
property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id);
}
+static gboolean property_get_power_state(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ const char *str;
+
+ if (adapter->power_state_target == ADAPTER_POWER_STATE_TARGET_NONE) {
+ if (adapter->current_settings & MGMT_SETTING_POWERED)
+ str = "on";
+ else
+ str = "off";
+ } else {
+ if (adapter->power_state_target == ADAPTER_POWER_STATE_TARGET_ON)
+ str = "turning-on";
+ else
+ str = "turning-off";
+ }
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+ return TRUE;
+}
+
static gboolean property_get_discoverable(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *user_data)
{
@@ -3723,6 +3801,7 @@ static const GDBusPropertyTable adapter_properties[] = {
{ "Alias", "s", property_get_alias, property_set_alias },
{ "Class", "u", property_get_class },
{ "Powered", "b", property_get_powered, property_set_powered },
+ { "PowerState", "s", property_get_power_state },
{ "Discoverable", "b", property_get_discoverable,
property_set_discoverable },
{ "DiscoverableTimeout", "u", property_get_discoverable_timeout,
@@ -5529,6 +5608,8 @@ static void adapter_start(struct btd_adapter *adapter)
{
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Powered");
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "PowerState");
DBG("adapter %s has been enabled", adapter->path);
@@ -7272,6 +7353,8 @@ static void adapter_stop(struct btd_adapter *adapter)
g_dbus_emit_property_changed(dbus_conn, adapter->path,
ADAPTER_INTERFACE, "Powered");
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "PowerState");
DBG("adapter %s has been disabled", adapter->path);
}