adapter->connect_list = g_slist_append(adapter->connect_list, device);
}
+static void set_device_wakeable_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_set_device_flags *rp = param;
+ struct btd_adapter *adapter = user_data;
+ struct btd_device *dev;
+ char addr[18];
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ btd_error(adapter->dev_id, "Set device flags return status: %s",
+ mgmt_errstr(status));
+ return;
+ }
+
+ if (length < sizeof(*rp)) {
+ btd_error(adapter->dev_id,
+ "Too small Set Device Flags complete event: %d",
+ length);
+ return;
+ }
+
+ ba2str(&rp->addr.bdaddr, addr);
+
+ dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr, rp->addr.type);
+ if (!dev) {
+ btd_error(adapter->dev_id,
+ "Set Device Flags complete for unknown device %s",
+ addr);
+ return;
+ }
+
+ device_set_wake_allowed_complete(dev);
+}
+
+void adapter_set_device_wakeable(struct btd_adapter *adapter,
+ struct btd_device *device, bool wakeable)
+{
+ struct mgmt_cp_set_device_flags cp;
+ const bdaddr_t *bdaddr;
+ uint8_t bdaddr_type;
+
+ if (!kernel_conn_control)
+ return;
+
+ bdaddr = device_get_address(device);
+ bdaddr_type = btd_device_get_bdaddr_type(device);
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr.bdaddr, bdaddr);
+ cp.addr.type = bdaddr_type;
+ cp.current_flags = btd_device_get_current_flags(device);
+ if (wakeable)
+ cp.current_flags |= DEVICE_FLAG_REMOTE_WAKEUP;
+ else
+ cp.current_flags &= ~DEVICE_FLAG_REMOTE_WAKEUP;
+
+ mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
+ sizeof(cp), &cp, set_device_wakeable_complete, adapter, NULL);
+}
+
+static void device_flags_changed_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_device_flags_changed *ev = param;
+ struct btd_adapter *adapter = user_data;
+ struct btd_device *dev;
+ char addr[18];
+
+ if (length < sizeof(*ev)) {
+ btd_error(adapter->dev_id,
+ "Too small Device Flags Changed event: %d",
+ length);
+ return;
+ }
+
+ ba2str(&ev->addr.bdaddr, addr);
+
+ dev = btd_adapter_find_device(adapter, &ev->addr.bdaddr, ev->addr.type);
+ if (!dev) {
+ btd_error(adapter->dev_id,
+ "Device Flags Changed for unknown device %s", addr);
+ return;
+ }
+
+ btd_device_flags_changed(dev, ev->supported_flags, ev->current_flags);
+}
+
+
static void remove_device_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
#endif
load:
+ mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_FLAGS_CHANGED,
+ adapter->dev_id,
+ device_flags_changed_callback,
+ adapter, NULL);
+
load_config(adapter);
fix_storage(adapter);
load_drivers(adapter);
uint32_t counter;
};
+enum {
+ WAKE_FLAG_DEFAULT = 0,
+ WAKE_FLAG_ENABLED,
+ WAKE_FLAG_DISABLED,
+};
+
+
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
typedef enum {
DEV_PAIRED_NONE = 0,
bool le;
bool pending_paired; /* "Paired" waiting for SDP */
bool svc_refreshed;
+
+ /* Manage whether this device can wake the system from suspend.
+ * - wake_support: Requires a profile that supports wake (i.e. HID)
+ * - wake_allowed: Is wake currently allowed?
+ * - pending_wake_allowed - Wake flag sent via set_device_flags
+ * - wake_override - User configured wake setting
+ */
+ bool wake_support;
+ bool wake_allowed;
+ bool pending_wake_allowed;
+ uint8_t wake_override;
+ GDBusPendingPropertySet wake_id;
+
+ uint32_t supported_flags;
+ uint32_t current_flags;
GSList *svc_callbacks;
GSList *eir_uuids;
struct bt_ad *ad;
g_key_file_set_boolean(key_file, "General", "Blocked",
device->blocked);
+ if (device->wake_override != WAKE_FLAG_DEFAULT) {
+ g_key_file_set_boolean(key_file, "General", "WakeAllowed",
+ device->wake_override ==
+ WAKE_FLAG_ENABLED);
+ }
+
if (device->uuids) {
GSList *l;
int i;
return bt_ad_has_data(device->ad, NULL);
}
+static bool device_get_wake_support(struct btd_device *device)
+{
+ return device->wake_support;
+}
+
+void device_set_wake_support(struct btd_device *device, bool wake_support)
+{
+ device->wake_support = wake_support;
+
+ /* If wake configuration has not been made yet, set the initial
+ * configuration.
+ */
+ if (device->wake_override == WAKE_FLAG_DEFAULT) {
+ device_set_wake_override(device, wake_support);
+ device_set_wake_allowed(device, wake_support, -1U);
+ }
+}
+
+static bool device_get_wake_allowed(struct btd_device *device)
+{
+ return device->wake_allowed;
+}
+
+void device_set_wake_override(struct btd_device *device, bool wake_override)
+{
+ if (wake_override) {
+ device->wake_override = WAKE_FLAG_ENABLED;
+ device->current_flags |= DEVICE_FLAG_REMOTE_WAKEUP;
+ } else {
+ device->wake_override = WAKE_FLAG_DISABLED;
+ device->current_flags &= ~DEVICE_FLAG_REMOTE_WAKEUP;
+ }
+}
+
+void device_set_wake_allowed(struct btd_device *device, bool wake_allowed,
+ GDBusPendingPropertySet id)
+{
+ /* Pending and current value are the same unless there is a change in
+ * progress. Only update wake allowed if pending value doesn't match the
+ * new value.
+ */
+ if (wake_allowed == device->pending_wake_allowed)
+ return;
+
+ device->wake_id = id;
+ device->pending_wake_allowed = wake_allowed;
+ adapter_set_device_wakeable(device_get_adapter(device), device,
+ wake_allowed);
+}
+
+void device_set_wake_allowed_complete(struct btd_device *device)
+{
+ if (device->wake_id != -1U) {
+ g_dbus_pending_property_success(device->wake_id);
+ device->wake_id = -1U;
+ }
+
+ device->wake_allowed = device->pending_wake_allowed;
+ g_dbus_emit_property_changed(dbus_conn, device->path,
+ DEVICE_INTERFACE, "WakeAllowed");
+
+ store_device_info(device);
+}
+
+
+static gboolean
+dev_property_get_wake_allowed(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct btd_device *device = data;
+ dbus_bool_t wake_allowed = device_get_wake_allowed(device);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &wake_allowed);
+
+ return TRUE;
+}
+
+static void dev_property_set_wake_allowed(const GDBusPropertyTable *property,
+ DBusMessageIter *value,
+ GDBusPendingPropertySet id, void *data)
+{
+ struct btd_device *device = data;
+ dbus_bool_t b;
+
+ 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;
+ }
+
+ if (device->temporary) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".Unsupported",
+ "Cannot set property while temporary");
+ return;
+ }
+
+ /* Emit busy or success depending on current value. */
+ if (b == device->pending_wake_allowed) {
+ if (device->wake_allowed == device->pending_wake_allowed)
+ g_dbus_pending_property_success(id);
+ else
+ g_dbus_pending_property_error(
+ id, ERROR_INTERFACE ".Busy",
+ "Property change in progress");
+
+ return;
+ }
+
+ dbus_message_iter_get_basic(value, &b);
+ device_set_wake_override(device, b);
+ device_set_wake_allowed(device, b, id);
+}
+
+static gboolean dev_property_wake_allowed_exist(
+ const GDBusPropertyTable *property, void *data)
+{
+ struct btd_device *device = data;
+
+ return device_get_wake_support(device);
+}
+
+
static gboolean disconnect_all(gpointer user_data)
{
struct btd_device *device = user_data;
{ "AdvertisingData", "a{yv}", dev_property_get_advertising_data,
NULL, dev_property_advertising_data_exist,
G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "WakeAllowed", "b", dev_property_get_wake_allowed,
+ dev_property_set_wake_allowed,
+ dev_property_wake_allowed_exist },
{ }
};
static void load_info(struct btd_device *device, const char *local,
const char *peer, GKeyFile *key_file)
{
+ GError *gerr = NULL;
char *str;
gboolean store_needed = FALSE;
gboolean blocked;
+ gboolean wake_allowed;
char **uuids;
int source, vendor, product, version;
char **techno, **t;
btd_device_set_pnpid(device, source, vendor, product, version);
}
+ /* Wake allowed is only configured and stored if user changed it.
+ * Otherwise, we enable if profile supports it.
+ */
+ wake_allowed = g_key_file_get_boolean(key_file, "General",
+ "WakeAllowed", &gerr);
+ if (!gerr) {
+ device_set_wake_override(device, wake_allowed);
+ } else {
+ g_error_free(gerr);
+ gerr = NULL;
+ }
+
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
/* Load Service changed Registered flag */
svc_change_regd = g_key_file_get_boolean(key_file, "Att",
store_device_info(device);
}
+uint32_t btd_device_get_current_flags(struct btd_device *dev)
+{
+ return dev->current_flags;
+}
+
+/* This event is sent immediately after add device on all mgmt sockets.
+ * Afterwards, it is only sent to mgmt sockets other than the one which called
+ * set_device_flags.
+ */
+void btd_device_flags_changed(struct btd_device *dev, uint32_t supported_flags,
+ uint32_t current_flags)
+{
+ const uint32_t changed_flags = dev->current_flags ^ current_flags;
+ bool flag_value;
+
+ dev->supported_flags = supported_flags;
+ dev->current_flags = current_flags;
+
+ if (!changed_flags)
+ return;
+
+ if (changed_flags & DEVICE_FLAG_REMOTE_WAKEUP) {
+ flag_value = !!(current_flags & DEVICE_FLAG_REMOTE_WAKEUP);
+ dev->pending_wake_allowed = flag_value;
+
+ /* If an override exists and doesn't match the current state,
+ * apply it. This logic will run after Add Device only and will
+ * enable wake for previously paired devices.
+ */
+ if (dev->wake_override != WAKE_FLAG_DEFAULT) {
+ bool wake_allowed =
+ dev->wake_override == WAKE_FLAG_ENABLED;
+ if (flag_value != wake_allowed)
+ device_set_wake_allowed(dev, wake_allowed, -1U);
+ else
+ device_set_wake_allowed_complete(dev);
+ } else {
+ device_set_wake_allowed_complete(dev);
+ }
+ }
+}
+
static void service_state_changed(struct btd_service *service,
btd_service_state_t old_state,
btd_service_state_t new_state,