summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorPatrik Flykt <patrik.flykt@linux.intel.com>2013-01-28 17:44:38 +0200
committerPatrik Flykt <patrik.flykt@linux.intel.com>2013-01-30 10:28:05 +0200
commite1168968df38ff6bd75208c782a51d716efdf3b9 (patch)
tree8ffd5d8e8ae803bc2e5a2b9bd06db82cf6f6dabb /plugins
parent1daefbd49f0b75533c1b0cfc7444ad748064333c (diff)
downloadconnman-e1168968df38ff6bd75208c782a51d716efdf3b9.tar.gz
connman-e1168968df38ff6bd75208c782a51d716efdf3b9.tar.bz2
connman-e1168968df38ff6bd75208c782a51d716efdf3b9.zip
bluetooth: Expose Bluez 5 adapters as ConnMan devices
Set up functions monitoring Bluez 5 objects being added and removed using GDBusProxy. When an adapter appears, create a new device for it and set up a watch function for the adapter's 'Powered' property. Keep the adapter 'Powered' property in sync with the device state and if they differ reset the adapter to the device state. Also update the Bluez 5 adapter 'Powered' property when the device is enabled or disabled.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/bluetooth.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 7e7c35ef..f1ea66c2 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -24,13 +24,292 @@
#endif
#include <errno.h>
+#include <string.h>
#define CONNMAN_API_SUBJECT_TO_CHANGE
#include <connman/plugin.h>
#include <connman/dbus.h>
#include <connman/technology.h>
+#include <connman/device.h>
+#include <gdbus.h>
+
+#define BLUEZ_SERVICE "org.bluez"
+#define BLUEZ_PATH "/org/bluez"
+
+#define BLUETOOTH_ADDR_LEN 6
static DBusConnection *connection;
+static GDBusClient *client;
+static GHashTable *devices;
+
+static void address2ident(const char *address, char *ident)
+{
+ int i;
+
+ for (i = 0; i < BLUETOOTH_ADDR_LEN; i++) {
+ ident[i * 2] = address[i * 3];
+ ident[i * 2 + 1] = address[i * 3 + 1];
+ }
+ ident[BLUETOOTH_ADDR_LEN * 2] = '\0';
+}
+
+static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
+{
+ DBusMessageIter iter;
+ const char *str;
+
+ if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
+ return NULL;
+ dbus_message_iter_get_basic(&iter, &str);
+ return str;
+}
+
+static connman_bool_t proxy_get_bool(GDBusProxy *proxy, const char *property)
+{
+ DBusMessageIter iter;
+ connman_bool_t value;
+
+ if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
+ return FALSE;
+ dbus_message_iter_get_basic(&iter, &value);
+ return value;
+}
+
+static void device_enable_cb(const DBusError *error, void *user_data)
+{
+ char *path = user_data;
+ struct connman_device *device;
+
+ device = g_hash_table_lookup(devices, path);
+ if (device == NULL) {
+ DBG("device already removed");
+ goto out;
+ }
+
+ if (dbus_error_is_set(error) == TRUE) {
+ connman_warn("Bluetooth device %s not enabled %s",
+ path, error->message);
+ goto out;
+ }
+
+ DBG("device %p", device);
+ connman_device_set_powered(device, TRUE);
+
+out:
+ g_free(path);
+}
+
+static int bluetooth_device_enable(struct connman_device *device)
+{
+ GDBusProxy *proxy = connman_device_get_data(device);
+ connman_bool_t device_powered = TRUE;
+ const char *path;
+
+ if (proxy == NULL)
+ return 0;
+
+ path = g_dbus_proxy_get_path(proxy);
+
+ if (proxy_get_bool(proxy, "Powered") == TRUE) {
+ DBG("already enabled %p %s", device, path);
+ return -EALREADY;
+ }
+
+ DBG("device %p %s", device, path);
+
+ g_dbus_proxy_set_property_basic(proxy, "Powered",
+ DBUS_TYPE_BOOLEAN, &device_powered,
+ device_enable_cb, g_strdup(path), NULL);
+
+ return -EINPROGRESS;
+}
+
+static void device_disable_cb(const DBusError *error, void *user_data)
+{
+ char *path = user_data;
+ struct connman_device *device;
+
+ device = g_hash_table_lookup(devices, path);
+ if (device == NULL) {
+ DBG("device already removed");
+ goto out;
+ }
+
+ if (dbus_error_is_set(error) == TRUE) {
+ connman_warn("Bluetooth device %s not disabled: %s",
+ path, error->message);
+ goto out;
+ }
+
+ DBG("device %p", device);
+ connman_device_set_powered(device, FALSE);
+
+out:
+ g_free(path);
+}
+
+static int bluetooth_device_disable(struct connman_device *device)
+{
+ GDBusProxy *proxy = connman_device_get_data(device);
+ connman_bool_t device_powered = FALSE;
+ const char *path;
+
+ if (proxy == NULL)
+ return 0;
+
+ path = g_dbus_proxy_get_path(proxy);
+
+ if (proxy_get_bool(proxy, "Powered") == FALSE) {
+ DBG("already disabled %p %s", device, path);
+ return -EALREADY;
+ }
+
+ DBG("device %p %s", device, path);
+
+ g_dbus_proxy_set_property_basic(proxy, "Powered",
+ DBUS_TYPE_BOOLEAN, &device_powered,
+ device_disable_cb, g_strdup(path), NULL);
+
+ return -EINPROGRESS;
+}
+
+static void adapter_property_change(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct connman_device *device;
+ const char *path;
+ connman_bool_t adapter_powered, device_powered;
+
+ if (strcmp(name, "Powered") != 0)
+ return;
+
+ path = g_dbus_proxy_get_path(proxy);
+ device = g_hash_table_lookup(devices, path);
+
+ adapter_powered = proxy_get_bool(proxy, "Powered");
+ device_powered = connman_device_get_powered(device);
+
+ DBG("device %p %s device powered %d adapter powered %d", device, path,
+ device_powered, adapter_powered);
+
+ if (device_powered != adapter_powered) {
+ if (device_powered == TRUE)
+ bluetooth_device_enable(device);
+ else
+ bluetooth_device_disable(device);
+ }
+}
+
+static void device_free(gpointer data)
+{
+ struct connman_device *device = data;
+ GDBusProxy *proxy = connman_device_get_data(device);
+
+ connman_device_set_data(device, NULL);
+ if (proxy != NULL)
+ g_dbus_proxy_unref(proxy);
+
+ connman_device_unregister(device);
+ connman_device_unref(device);
+}
+
+static void device_create(GDBusProxy *proxy)
+{
+ struct connman_device *device = NULL;
+ const char *path = g_dbus_proxy_get_path(proxy);
+ const char *address;
+ char ident[BLUETOOTH_ADDR_LEN * 2 + 1];
+ connman_bool_t powered;
+
+ address = proxy_get_string(proxy, "Address");
+ if (address == NULL)
+ return;
+
+ address2ident(address, ident);
+
+ device = connman_device_create("bluetooth",
+ CONNMAN_DEVICE_TYPE_BLUETOOTH);
+ if (device == NULL)
+ return;
+
+ connman_device_set_data(device, g_dbus_proxy_ref(proxy));
+ connman_device_set_ident(device, ident);
+
+ g_hash_table_replace(devices, g_strdup(path), device);
+
+ DBG("device %p %s device powered %d adapter powered %d", device,
+ path, connman_device_get_powered(device),
+ proxy_get_bool(proxy, "Powered"));
+
+ if (connman_device_register(device) < 0) {
+ g_hash_table_remove(devices, device);
+ return;
+ }
+
+ g_dbus_proxy_set_property_watch(proxy, adapter_property_change, NULL);
+
+ powered = proxy_get_bool(proxy, "Powered");
+ connman_device_set_powered(device, powered);
+}
+
+static void object_added(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (strcmp(interface, "org.bluez.Adapter1") == 0) {
+ DBG("%s %s", interface, g_dbus_proxy_get_path(proxy));
+ device_create(proxy);
+ return;
+ }
+
+}
+
+static void object_removed(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface, *path;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (strcmp(interface, "org.bluez.Adapter1") == 0) {
+ path = g_dbus_proxy_get_path(proxy);
+ DBG("%s %s", interface, path);
+
+ g_hash_table_remove(devices, path);
+ }
+}
+
+static int bluetooth_device_probe(struct connman_device *device)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init(&iter, devices);
+
+ while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+ struct connman_device *known = value;
+
+ if (device == known)
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static void bluetooth_device_remove(struct connman_device *device)
+{
+ DBG("%p", device);
+}
+
+static struct connman_device_driver device_driver = {
+ .name = "bluetooth",
+ .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
+ .probe = bluetooth_device_probe,
+ .remove = bluetooth_device_remove,
+ .enable = bluetooth_device_enable,
+ .disable = bluetooth_device_disable,
+};
static int bluetooth_tech_probe(struct connman_technology *technology)
{
@@ -60,9 +339,35 @@ static int bluetooth_init(void)
goto out;
}
+ devices = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ device_free);
+
+ if (connman_device_driver_register(&device_driver) < 0) {
+ connman_warn("Failed to initialize device driver for "
+ BLUEZ_SERVICE);
+ connman_technology_driver_unregister(&tech_driver);
+ goto out;
+ }
+
+ client = g_dbus_client_new(connection, BLUEZ_SERVICE, BLUEZ_PATH);
+ if (client == NULL) {
+ connman_warn("Failed to initialize D-Bus client for "
+ BLUEZ_SERVICE);
+ goto out;
+ }
+
+ g_dbus_client_set_proxy_handlers(client, object_added, object_removed,
+ NULL, NULL);
+
return 0;
out:
+ if (devices != NULL)
+ g_hash_table_destroy(devices);
+
+ if (client != NULL)
+ g_dbus_client_unref(client);
+
if (connection != NULL)
dbus_connection_unref(connection);
@@ -71,6 +376,9 @@ out:
static void bluetooth_exit(void)
{
+ connman_device_driver_unregister(&device_driver);
+ g_hash_table_destroy(devices);
+
connman_technology_driver_unregister(&tech_driver);
dbus_connection_unref(connection);
}