diff --git a/src/adapter.c b/src/adapter.c
index d6f91cb..138c129 100644
--- a/src/adapter.c
+++ b/src/adapter.c
return session_ref(req);
}
-static void set_discoverable(struct btd_adapter *adapter,
- gboolean discoverable, GDBusPendingPropertySet id)
+static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
{
- mgmt_set_discoverable(adapter->dev_id, discoverable, 0);
- g_dbus_pending_property_success(id);
+ uint32_t changed_mask;
+
+ if (adapter->current_settings == settings)
+ return;
+
+ DBG("Settings: 0x%08x", settings);
+
+ changed_mask = adapter->current_settings ^ settings;
+
+ adapter->current_settings = settings;
+
+ if (changed_mask & MGMT_SETTING_POWERED)
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "Powered");
+
+ if (changed_mask & MGMT_SETTING_CONNECTABLE)
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "Connectable");
+
+ if (changed_mask & MGMT_SETTING_DISCOVERABLE)
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "Discoverable");
+
+ if (changed_mask & MGMT_SETTING_PAIRABLE)
+ g_dbus_emit_property_changed(dbus_conn, adapter->path,
+ ADAPTER_INTERFACE, "Pairable");
}
static void new_settings_callback(uint16_t index, uint16_t length,
DBG("Settings: 0x%08x", settings);
- adapter_update_settings(adapter, settings);
+ settings_changed(adapter, settings);
+}
+
+static void set_mode_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ uint32_t settings;
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ error("Failed to set mode: %s (0x%02x)",
+ mgmt_errstr(status), status);
+ return;
+ }
+
+ if (length < sizeof(settings)) {
+ error("Wrong size of set mode response");
+ return;
+ }
+
+ settings = bt_get_le32(param);
+
+ DBG("Settings: 0x%08x", settings);
+
+ settings_changed(adapter, settings);
+}
+
+static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
+ uint8_t mode)
+{
+ struct mgmt_mode cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.val = mode;
+
+ DBG("sending set mode command for index %u", adapter->dev_id);
+
+ if (mgmt_send(adapter->mgmt, opcode,
+ adapter->dev_id, sizeof(cp), &cp,
+ set_mode_complete, adapter, NULL) > 0)
+ return true;
+
+ error("Failed to set mode for index %u", adapter->dev_id);
+
+ return false;
+}
+
+static bool set_discoverable(struct btd_adapter *adapter, uint8_t mode,
+ uint16_t timeout)
+{
+ struct mgmt_cp_set_discoverable cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.val = mode;
+ cp.timeout = htobs(timeout);
+
+ DBG("sending set mode command for index %u", adapter->dev_id);
+
+ if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DISCOVERABLE,
+ adapter->dev_id, sizeof(cp), &cp,
+ set_mode_complete, adapter, NULL) > 0)
+ return true;
+
+ error("Failed to set mode for index %u", adapter->dev_id);
+
+ return false;
}
static void set_pairable(struct btd_adapter *adapter, gboolean pairable,
if (pairable == mgmt_pairable(adapter->current_settings))
goto done;
- /* TODO: disable pairable setting */
+ set_mode(adapter, MGMT_OP_SET_PAIRABLE, 0x00);
done:
if (reply)
}
if (mgmt_discoverable(adapter->current_settings))
- mgmt_set_discoverable(adapter->dev_id, TRUE, timeout);
+ set_discoverable(adapter, 0x01, timeout);
adapter->discov_timeout = timeout;
return TRUE;
}
-static gboolean property_get_powered(const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *user_data)
+static gboolean property_get_mode(struct btd_adapter *adapter,
+ uint32_t setting, DBusMessageIter *iter)
{
- struct btd_adapter *adapter = user_data;
- dbus_bool_t powered;
+ dbus_bool_t enable;
- if (adapter->current_settings & MGMT_SETTING_POWERED)
- powered = TRUE;
- else
- powered = FALSE;
+ enable = (adapter->current_settings & setting) ? TRUE : FALSE;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &powered);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &enable);
return TRUE;
}
GDBusPendingPropertySet id;
};
-static void set_powered_complete(uint8_t status, uint16_t length,
+static void property_set_mode_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
struct property_set_data *data = user_data;
uint32_t settings;
if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to set powered: %s (0x%02x)",
+ error("Failed to set mode: %s (0x%02x)",
mgmt_errstr(status), status);
g_dbus_pending_property_error(data->id,
ERROR_INTERFACE ".Failed",
}
if (length < sizeof(settings)) {
- error("Wrong size of set powered response");
+ error("Wrong size of set mode response");
g_dbus_pending_property_error(data->id,
ERROR_INTERFACE ".Failed",
"Invalid response data");
DBG("Settings: 0x%08x", settings);
- adapter->current_settings = settings;
-
g_dbus_pending_property_success(data->id);
- g_dbus_emit_property_changed(dbus_conn, adapter->path,
- ADAPTER_INTERFACE, "Powered");
+ settings_changed(adapter, settings);
}
-static void property_set_powered(const GDBusPropertyTable *property,
- DBusMessageIter *value,
- GDBusPendingPropertySet id, void *user_data)
+static void property_set_mode(struct btd_adapter *adapter, uint32_t setting,
+ DBusMessageIter *value,
+ GDBusPendingPropertySet id)
{
- struct btd_adapter *adapter = user_data;
struct property_set_data *data;
- struct mgmt_mode cp;
- dbus_bool_t powered, current_powered;
+ struct mgmt_cp_set_discoverable cp;
+ void *param;
+ dbus_bool_t enable, current_enable;
+ uint16_t opcode, len;
+ uint8_t mode;
- dbus_message_iter_get_basic(value, &powered);
+ dbus_message_iter_get_basic(value, &enable);
- if (adapter->current_settings & MGMT_SETTING_POWERED)
- current_powered = TRUE;
+ if (adapter->current_settings & setting)
+ current_enable = TRUE;
else
- current_powered = FALSE;
+ current_enable = FALSE;
- if (powered == current_powered) {
+ if (enable == current_enable) {
g_dbus_pending_property_success(id);
return;
}
+ mode = (enable == TRUE) ? 0x01 : 0x00;
+
+ switch (setting) {
+ case MGMT_SETTING_POWERED:
+ opcode = MGMT_OP_SET_POWERED;
+ param = &mode;
+ len = sizeof(mode);
+ break;
+ case MGMT_SETTING_DISCOVERABLE:
+ memset(&cp, 0, sizeof(cp));
+ cp.val = mode;
+ cp.timeout = htobs(0);
+
+ opcode = MGMT_OP_SET_DISCOVERABLE;
+ param = &cp;
+ len = sizeof(cp);
+ break;
+ case MGMT_SETTING_PAIRABLE:
+ opcode = MGMT_OP_SET_PAIRABLE;
+ param = &mode;
+ len = sizeof(mode);
+ break;
+ default:
+ goto failed;
+ }
+
memset(&cp, 0, sizeof(cp));
- cp.val = (powered == TRUE) ? 0x01 : 0x00;
+ cp.val = (enable == TRUE) ? 0x01 : 0x00;
- DBG("sending set powered command for index %u", adapter->dev_id);
+ DBG("sending set mode command for index %u", adapter->dev_id);
data = g_try_new0(struct property_set_data, 1);
if (!data)
data->adapter = adapter;
data->id = id;
- if (mgmt_send(adapter->mgmt, MGMT_OP_SET_POWERED,
- adapter->dev_id, sizeof(cp), &cp,
- set_powered_complete, data, g_free) > 0)
+ if (mgmt_send(adapter->mgmt, opcode, adapter->dev_id, len, param,
+ property_set_mode_complete, data, g_free) > 0)
return;
g_free(data);
failed:
- error("Failed to set powered for index %u", adapter->dev_id);
+ error("Failed to set mode for index %u", adapter->dev_id);
g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", NULL);
}
-static gboolean property_get_pairable(const GDBusPropertyTable *property,
+static gboolean property_get_powered(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *user_data)
{
struct btd_adapter *adapter = user_data;
- dbus_bool_t pairable;
-
- if (adapter->current_settings & MGMT_SETTING_PAIRABLE)
- pairable = TRUE;
- else
- pairable = FALSE;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &pairable);
-
- return TRUE;
+ return property_get_mode(adapter, MGMT_SETTING_POWERED, iter);
}
-static void set_pairable_complete(uint8_t status, uint16_t length,
- const void *param, void *user_data)
+static void property_set_powered(const GDBusPropertyTable *property,
+ DBusMessageIter *iter,
+ GDBusPendingPropertySet id, void *user_data)
{
- struct property_set_data *data = user_data;
- struct btd_adapter *adapter = data->adapter;
- uint32_t settings;
-
- if (status != MGMT_STATUS_SUCCESS) {
- error("Failed to set pairable: %s (0x%02x)",
- mgmt_errstr(status), status);
- g_dbus_pending_property_error(data->id,
- ERROR_INTERFACE ".Failed",
- mgmt_errstr(status));
- return;
- }
-
- if (length < sizeof(settings)) {
- error("Wrong size of set pairable response");
- g_dbus_pending_property_error(data->id,
- ERROR_INTERFACE ".Failed",
- "Invalid response data");
- return;
- }
-
- settings = bt_get_le32(param);
-
- DBG("Settings: 0x%08x", settings);
+ struct btd_adapter *adapter = user_data;
- adapter->current_settings = settings;
+ property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id);
+}
- g_dbus_pending_property_success(data->id);
+static gboolean property_get_pairable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
- g_dbus_emit_property_changed(dbus_conn, adapter->path,
- ADAPTER_INTERFACE, "Pairable");
+ return property_get_mode(adapter, MGMT_SETTING_PAIRABLE, iter);
}
static void property_set_pairable(const GDBusPropertyTable *property,
- DBusMessageIter *value,
+ DBusMessageIter *iter,
GDBusPendingPropertySet id, void *user_data)
{
struct btd_adapter *adapter = user_data;
- struct property_set_data *data;
- struct mgmt_mode cp;
- dbus_bool_t pairable, current_pairable;
-
- dbus_message_iter_get_basic(value, &pairable);
-
- if (adapter->current_settings & MGMT_SETTING_PAIRABLE)
- current_pairable = TRUE;
- else
- current_pairable = FALSE;
-
- if (pairable == current_pairable) {
- g_dbus_pending_property_success(id);
- return;
- }
-
- memset(&cp, 0, sizeof(cp));
- cp.val = (pairable == TRUE) ? 0x01 : 0x00;
-
- DBG("sending set pairable command for index %u", adapter->dev_id);
- data = g_try_new0(struct property_set_data, 1);
- if (!data)
- goto failed;
-
- data->adapter = adapter;
- data->id = id;
-
- if (mgmt_send(adapter->mgmt, MGMT_OP_SET_PAIRABLE,
- adapter->dev_id, sizeof(cp), &cp,
- set_pairable_complete, data, g_free) > 0)
- return;
-
- g_free(data);
-
-failed:
- error("Failed to set pairable for index %u", adapter->dev_id);
-
- g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", NULL);
+ property_set_mode(adapter, MGMT_SETTING_PAIRABLE, iter, id);
}
-static gboolean adapter_property_get_discoverable(
- const GDBusPropertyTable *property,
- DBusMessageIter *iter, void *data)
+static gboolean property_get_discoverable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *user_data)
{
- struct btd_adapter *adapter = data;
- dbus_bool_t value;
-
- value = mgmt_discoverable(adapter->current_settings) ? TRUE : FALSE;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+ struct btd_adapter *adapter = user_data;
- return TRUE;
+ return property_get_mode(adapter, MGMT_SETTING_DISCOVERABLE, iter);
}
-static void adapter_property_set_discoverable(
- const GDBusPropertyTable *property,
- DBusMessageIter *value,
- GDBusPendingPropertySet id, void *data)
+static void property_set_discoverable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter,
+ GDBusPendingPropertySet id, void *user_data)
{
- dbus_bool_t discoverable;
-
- if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) {
- g_dbus_pending_property_error(id,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments in method call");
- return;
- }
-
- dbus_message_iter_get_basic(value, &discoverable);
+ struct btd_adapter *adapter = user_data;
- set_discoverable(data, discoverable, id);
+ property_set_mode(adapter, MGMT_SETTING_DISCOVERABLE, iter, id);
}
static gboolean adapter_property_get_discoverable_timeout(
{ "Class", "u", adapter_property_get_class },
{ "Powered", "b", property_get_powered, property_set_powered },
{ "Pairable", "b", property_get_pairable, property_set_pairable },
- { "Discoverable", "b", adapter_property_get_discoverable,
- adapter_property_set_discoverable },
+ { "Discoverable", "b", property_get_discoverable,
+ property_set_discoverable },
{ "DiscoverableTimeout", "u",
adapter_property_get_discoverable_timeout,
adapter_property_set_discoverable_timeout },
if (adapter->toggle_discoverable) {
bool discov = mgmt_discoverable(adapter->current_settings);
DBG("toggling discoverable from %u to %u", discov, !discov);
- mgmt_set_discoverable(adapter->dev_id, !discov,
- adapter->discov_timeout);
+ set_discoverable(adapter, !discov, adapter->discov_timeout);
adapter->toggle_discoverable = false;
}
}
gerr = NULL;
}
- if (!mgmt_connectable(adapter->current_settings))
- mgmt_set_connectable(adapter->dev_id, TRUE);
-
if (adapter->discov_timeout > 0 &&
mgmt_discoverable(adapter->current_settings)) {
if (mgmt_connectable(adapter->current_settings))
- mgmt_set_discoverable(adapter->dev_id, FALSE, 0);
+ set_discoverable(adapter, 0x00, 0);
else
adapter->toggle_discoverable = true;
} else if (stored_discoverable !=
mgmt_discoverable(adapter->current_settings)) {
if (mgmt_connectable(adapter->current_settings))
- mgmt_set_discoverable(adapter->dev_id,
- stored_discoverable,
+ set_discoverable(adapter, stored_discoverable,
adapter->discov_timeout);
else
adapter->toggle_discoverable = true;
g_slist_free(adapter->pin_callbacks);
- /* TODO: power off controller */
+ set_mode(adapter, MGMT_OP_SET_POWERED, 0x00);
}
uint16_t adapter_get_dev_id(struct btd_adapter *adapter)
if (mgmt_powered(adapter->current_settings))
return 0;
- /* TODO: power on controller */
+ set_mode(adapter, MGMT_OP_SET_POWERED, 0x01);
return 0;
}
if (!mgmt_powered(adapter->current_settings))
return -EINVAL;
- return mgmt_set_fast_connectable(adapter->dev_id, enable);
+ set_mode(adapter, MGMT_OP_SET_FAST_CONNECTABLE, enable ? 0x01 : 0x00);
+
+ return 0;
}
int btd_adapter_read_clock(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
set_name(adapter, btd_adapter_get_name(adapter));
+ set_mode(adapter, MGMT_OP_SET_PAIRABLE, 0x01);
+ set_mode(adapter, MGMT_OP_SET_CONNECTABLE, 0x01);
+
if (mgmt_powered(rp->current_settings))
adapter_start(adapter);
}