5 * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <connman/plugin.h>
31 #include <connman/driver.h>
32 #include <connman/dbus.h>
33 #include <connman/log.h>
35 #define BLUEZ_SERVICE "org.bluez"
36 #define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
37 #define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
39 #define LIST_ADAPTERS "ListAdapters"
40 #define ADAPTER_ADDED "AdapterAdded"
41 #define ADAPTER_REMOVED "AdapterRemoved"
43 #define PROPERTY_CHANGED "PropertyChanged"
44 #define SET_PROPERTY "SetProperty"
49 DBusConnection *connection;
52 static int bluetooth_probe(struct connman_element *adapter)
54 struct adapter_data *data;
56 DBG("adapter %p name %s", adapter, adapter->name);
58 data = g_try_new0(struct adapter_data, 1);
62 data->connection = connman_dbus_get_connection();
63 if (data->connection == NULL) {
68 connman_element_set_data(adapter, data);
73 static void bluetooth_remove(struct connman_element *adapter)
75 struct adapter_data *data = connman_element_get_data(adapter);
77 DBG("adapter %p name %s", adapter, adapter->name);
79 connman_element_set_data(adapter, NULL);
81 dbus_connection_unref(data->connection);
86 static void powered_reply(DBusPendingCall *call, void *user_data)
92 reply = dbus_pending_call_steal_reply(call);
94 dbus_message_unref(reply);
97 static int change_powered(DBusConnection *connection, const char *path,
100 DBusMessage *message;
101 DBusMessageIter iter;
102 DBusPendingCall *call;
106 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
107 BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
111 dbus_message_iter_init_append(message, &iter);
112 connman_dbus_property_append_variant(&iter, "Powered",
113 DBUS_TYPE_BOOLEAN, &powered);
115 if (dbus_connection_send_with_reply(connection, message,
116 &call, TIMEOUT) == FALSE) {
117 connman_error("Failed to change Powered property");
118 dbus_message_unref(message);
122 dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
124 dbus_message_unref(message);
129 static int bluetooth_enable(struct connman_element *adapter)
131 struct adapter_data *data = connman_element_get_data(adapter);
133 DBG("adapter %p name %s", adapter, adapter->name);
135 return change_powered(data->connection, adapter->devpath, TRUE);
138 static int bluetooth_disable(struct connman_element *adapter)
140 struct adapter_data *data = connman_element_get_data(adapter);
142 DBG("adapter %p name %s", adapter, adapter->name);
144 return change_powered(data->connection, adapter->devpath, FALSE);
147 static struct connman_driver bluetooth_driver = {
149 .type = CONNMAN_ELEMENT_TYPE_DEVICE,
150 .subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH,
151 .probe = bluetooth_probe,
152 .remove = bluetooth_remove,
153 .enable = bluetooth_enable,
154 .disable = bluetooth_disable,
157 static GSList *device_list = NULL;
159 static struct connman_element *find_adapter(const char *path)
163 DBG("path %s", path);
165 for (list = device_list; list; list = list->next) {
166 struct connman_element *device = list->data;
168 if (g_str_equal(device->devpath, path) == TRUE)
175 static void property_changed(DBusConnection *connection, DBusMessage *message)
177 const char *path = dbus_message_get_path(message);
178 struct connman_element *device;
179 DBusMessageIter iter, value;
182 DBG("path %s", path);
184 device = find_adapter(path);
188 if (dbus_message_iter_init(message, &iter) == FALSE)
191 dbus_message_iter_get_basic(&iter, &key);
193 dbus_message_iter_next(&iter);
194 dbus_message_iter_recurse(&iter, &value);
196 if (g_str_equal(key, "Powered") == TRUE) {
199 dbus_message_iter_get_basic(&value, &val);
200 connman_element_set_enabled(device, val);
201 } else if (g_str_equal(key, "Discovering") == TRUE) {
204 dbus_message_iter_get_basic(&value, &val);
205 connman_element_set_scanning(device, val);
209 static void properties_reply(DBusPendingCall *call, void *user_data)
211 DBusMessage *message = user_data;
212 const char *path = dbus_message_get_path(message);
213 struct connman_element *device;
214 DBusMessageIter array, dict;
217 DBG("path %s", path);
219 device = find_adapter(path);
221 dbus_message_unref(message);
223 reply = dbus_pending_call_steal_reply(call);
228 if (dbus_message_iter_init(reply, &array) == FALSE)
231 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
234 dbus_message_iter_recurse(&array, &dict);
235 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
236 DBusMessageIter entry, value;
239 dbus_message_iter_recurse(&dict, &entry);
240 dbus_message_iter_get_basic(&entry, &key);
242 dbus_message_iter_next(&entry);
243 dbus_message_iter_recurse(&entry, &value);
245 if (g_str_equal(key, "Powered") == TRUE) {
248 dbus_message_iter_get_basic(&value, &val);
249 connman_element_set_enabled(device, val);
250 } else if (g_str_equal(key, "Discovering") == TRUE) {
253 dbus_message_iter_get_basic(&value, &val);
254 connman_element_set_scanning(device, val);
257 dbus_message_iter_next(&dict);
261 dbus_message_unref(reply);
264 static void devices_reply(DBusPendingCall *call, void *user_data)
266 DBusMessage *message = user_data;
267 const char *path = dbus_message_get_path(message);
273 DBG("path %s", path);
275 dbus_message_unref(message);
277 reply = dbus_pending_call_steal_reply(call);
279 dbus_error_init(&error);
281 if (dbus_message_get_args(reply, &error,
282 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
283 &devices, &num_devices,
284 DBUS_TYPE_INVALID) == FALSE) {
285 if (dbus_error_is_set(&error) == TRUE) {
286 connman_error("%s", error.message);
287 dbus_error_free(&error);
289 connman_error("Wrong arguments for device list");
293 for (i = 0; i < num_devices; i++) {
294 DBG("device %s", devices[i]);
300 dbus_message_unref(reply);
303 static void add_adapter(DBusConnection *connection, const char *path)
305 struct connman_element *device;
306 DBusMessage *message;
307 DBusPendingCall *call;
309 DBG("path %s", path);
311 device = find_adapter(path);
315 device = connman_element_create(NULL);
316 device->type = CONNMAN_ELEMENT_TYPE_DEVICE;
317 device->subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH;
318 device->policy = CONNMAN_ELEMENT_POLICY_IGNORE;
320 device->name = g_path_get_basename(path);
321 device->devpath = g_strdup(path);
323 if (connman_element_register(device, NULL) < 0) {
324 connman_element_unref(device);
328 device_list = g_slist_append(device_list, device);
330 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
331 BLUEZ_ADAPTER_INTERFACE, "GetProperties");
335 if (dbus_connection_send_with_reply(connection, message,
336 &call, TIMEOUT) == FALSE) {
337 connman_error("Failed to get adapter properties");
338 dbus_message_unref(message);
342 dbus_pending_call_set_notify(call, properties_reply, message, NULL);
344 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
345 BLUEZ_ADAPTER_INTERFACE, "ListDevices");
349 if (dbus_connection_send_with_reply(connection, message,
350 &call, TIMEOUT) == FALSE) {
351 connman_error("Failed to get Bluetooth devices");
352 dbus_message_unref(message);
356 dbus_pending_call_set_notify(call, devices_reply, message, NULL);
359 static void remove_adapter(DBusConnection *connection, const char *path)
361 struct connman_element *device;
363 DBG("path %s", path);
365 device = find_adapter(path);
369 device_list = g_slist_remove(device_list, device);
371 connman_element_unregister(device);
372 connman_element_unref(device);
375 static void adapters_reply(DBusPendingCall *call, void *user_data)
377 DBusConnection *connection = user_data;
385 reply = dbus_pending_call_steal_reply(call);
387 dbus_error_init(&error);
389 if (dbus_message_get_args(reply, &error,
390 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
391 &adapters, &num_adapters,
392 DBUS_TYPE_INVALID) == FALSE) {
393 if (dbus_error_is_set(&error) == TRUE) {
394 connman_error("%s", error.message);
395 dbus_error_free(&error);
397 connman_error("Wrong arguments for adapter list");
401 for (i = 0; i < num_adapters; i++)
402 add_adapter(connection, adapters[i]);
404 g_strfreev(adapters);
407 dbus_message_unref(reply);
410 static void bluetooth_connect(DBusConnection *connection, void *user_data)
412 DBusMessage *message;
413 DBusPendingCall *call;
415 DBG("connection %p", connection);
417 message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
418 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
422 if (dbus_connection_send_with_reply(connection, message,
423 &call, TIMEOUT) == FALSE) {
424 connman_error("Failed to get Bluetooth adapters");
425 dbus_message_unref(message);
429 dbus_pending_call_set_notify(call, adapters_reply, connection, NULL);
431 dbus_message_unref(message);
434 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
438 DBG("connection %p", connection);
440 for (list = device_list; list; list = list->next) {
441 struct connman_element *device = list->data;
443 connman_element_unregister(device);
444 connman_element_unref(device);
447 g_slist_free(device_list);
451 static DBusHandlerResult bluetooth_signal(DBusConnection *connection,
452 DBusMessage *message, void *user_data)
454 DBG("connection %p", connection);
456 if (dbus_message_is_signal(message, BLUEZ_ADAPTER_INTERFACE,
457 PROPERTY_CHANGED) == TRUE) {
458 property_changed(connection, message);
459 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
460 ADAPTER_ADDED) == TRUE) {
462 dbus_message_get_args(message, NULL,
463 DBUS_TYPE_OBJECT_PATH, &path,
465 add_adapter(connection, path);
466 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
467 ADAPTER_REMOVED) == TRUE) {
469 dbus_message_get_args(message, NULL,
470 DBUS_TYPE_OBJECT_PATH, &path,
472 remove_adapter(connection, path);
475 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
478 static DBusConnection *connection;
481 static const char *added_rule = "type=signal,member=" ADAPTER_ADDED
482 ",interface=" BLUEZ_MANAGER_INTERFACE;
483 static const char *removed_rule = "type=signal,member=" ADAPTER_REMOVED
484 ",interface=" BLUEZ_MANAGER_INTERFACE;
486 static const char *adapter_rule = "type=signal,member=" PROPERTY_CHANGED
487 ",interface=" BLUEZ_ADAPTER_INTERFACE;
489 static int bluetooth_init(void)
493 connection = connman_dbus_get_connection();
494 if (connection == NULL)
497 if (dbus_connection_add_filter(connection, bluetooth_signal,
498 NULL, NULL) == FALSE)
501 err = connman_driver_register(&bluetooth_driver);
505 watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
506 bluetooth_connect, bluetooth_disconnect, NULL, NULL);
508 connman_driver_unregister(&bluetooth_driver);
513 if (g_dbus_check_service(connection, BLUEZ_SERVICE) == TRUE)
514 bluetooth_connect(connection, NULL);
516 dbus_bus_add_match(connection, added_rule, NULL);
517 dbus_bus_add_match(connection, removed_rule, NULL);
518 dbus_bus_add_match(connection, adapter_rule, NULL);
519 dbus_connection_flush(connection);
524 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
527 dbus_connection_unref(connection);
532 static void bluetooth_exit(void)
534 dbus_bus_remove_match(connection, adapter_rule, NULL);
535 dbus_bus_remove_match(connection, removed_rule, NULL);
536 dbus_bus_remove_match(connection, added_rule, NULL);
537 dbus_connection_flush(connection);
539 g_dbus_remove_watch(connection, watch);
541 bluetooth_disconnect(connection, NULL);
543 connman_driver_unregister(&bluetooth_driver);
545 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
547 dbus_connection_unref(connection);
550 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
551 bluetooth_init, bluetooth_exit)