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"
48 static int bluetooth_probe(struct connman_element *device)
50 DBG("device %p name %s", device, device->name);
55 static void bluetooth_remove(struct connman_element *device)
57 DBG("device %p name %s", device, device->name);
60 static void powered_reply(DBusPendingCall *call, void *user_data)
66 reply = dbus_pending_call_steal_reply(call);
68 dbus_message_unref(reply);
71 static int change_powered(DBusConnection *connection, const char *path,
76 DBusPendingCall *call;
80 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
81 BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
85 dbus_message_iter_init_append(message, &iter);
86 connman_dbus_property_append_variant(&iter, "Powered",
87 DBUS_TYPE_BOOLEAN, &powered);
89 if (dbus_connection_send_with_reply(connection, message,
90 &call, TIMEOUT) == FALSE) {
91 connman_error("Failed to change Powered property");
92 dbus_message_unref(message);
96 dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
98 dbus_message_unref(message);
103 static int bluetooth_enable(struct connman_element *device)
105 DBusConnection *connection = connman_element_get_data(device);
107 DBG("device %p name %s", device, device->name);
109 return change_powered(connection, device->devpath, TRUE);
112 static int bluetooth_disable(struct connman_element *device)
114 DBusConnection *connection = connman_element_get_data(device);
116 DBG("device %p name %s", device, device->name);
118 return change_powered(connection, device->devpath, FALSE);
121 static struct connman_driver bluetooth_driver = {
123 .type = CONNMAN_ELEMENT_TYPE_DEVICE,
124 .subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH,
125 .probe = bluetooth_probe,
126 .remove = bluetooth_remove,
127 .enable = bluetooth_enable,
128 .disable = bluetooth_disable,
131 static GSList *device_list = NULL;
133 static struct connman_element *find_adapter(const char *path)
137 DBG("path %s", path);
139 for (list = device_list; list; list = list->next) {
140 struct connman_element *device = list->data;
142 if (g_str_equal(device->devpath, path) == TRUE)
149 static void property_changed(DBusConnection *connection, DBusMessage *message)
151 const char *path = dbus_message_get_path(message);
152 struct connman_element *device;
153 DBusMessageIter iter, value;
156 DBG("path %s", path);
158 device = find_adapter(path);
162 if (dbus_message_iter_init(message, &iter) == FALSE)
165 dbus_message_iter_get_basic(&iter, &key);
167 dbus_message_iter_next(&iter);
168 dbus_message_iter_recurse(&iter, &value);
170 if (g_str_equal(key, "Powered") == TRUE) {
173 dbus_message_iter_get_basic(&value, &val);
174 connman_element_set_enabled(device, val);
175 } else if (g_str_equal(key, "Discovering") == TRUE) {
178 dbus_message_iter_get_basic(&value, &val);
179 connman_element_set_scanning(device, val);
183 static void properties_reply(DBusPendingCall *call, void *user_data)
185 DBusMessage *message = user_data;
186 const char *path = dbus_message_get_path(message);
187 struct connman_element *device;
188 DBusMessageIter array, dict;
191 DBG("path %s", path);
193 device = find_adapter(path);
195 dbus_message_unref(message);
197 reply = dbus_pending_call_steal_reply(call);
202 if (dbus_message_iter_init(reply, &array) == FALSE)
205 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
208 dbus_message_iter_recurse(&array, &dict);
209 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
210 DBusMessageIter entry, value;
213 dbus_message_iter_recurse(&dict, &entry);
214 dbus_message_iter_get_basic(&entry, &key);
216 dbus_message_iter_next(&entry);
217 dbus_message_iter_recurse(&entry, &value);
219 if (g_str_equal(key, "Powered") == TRUE) {
222 dbus_message_iter_get_basic(&value, &val);
223 connman_element_set_enabled(device, val);
224 } else if (g_str_equal(key, "Discovering") == TRUE) {
227 dbus_message_iter_get_basic(&value, &val);
228 connman_element_set_scanning(device, val);
231 dbus_message_iter_next(&dict);
235 dbus_message_unref(reply);
238 static void devices_reply(DBusPendingCall *call, void *user_data)
240 DBusMessage *message = user_data;
241 const char *path = dbus_message_get_path(message);
247 DBG("path %s", path);
249 dbus_message_unref(message);
251 reply = dbus_pending_call_steal_reply(call);
253 dbus_error_init(&error);
255 if (dbus_message_get_args(reply, &error,
256 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
257 &devices, &num_devices,
258 DBUS_TYPE_INVALID) == FALSE) {
259 if (dbus_error_is_set(&error) == TRUE) {
260 connman_error("%s", error.message);
261 dbus_error_free(&error);
263 connman_error("Wrong arguments for device list");
267 for (i = 0; i < num_devices; i++) {
268 DBG("device %s", devices[i]);
274 dbus_message_unref(reply);
277 static void add_adapter(DBusConnection *connection, const char *path)
279 struct connman_element *device;
280 DBusMessage *message;
281 DBusPendingCall *call;
283 DBG("path %s", path);
285 device = find_adapter(path);
289 device = connman_element_create(NULL);
290 device->type = CONNMAN_ELEMENT_TYPE_DEVICE;
291 device->subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH;
292 device->policy = CONNMAN_ELEMENT_POLICY_IGNORE;
294 device->name = g_path_get_basename(path);
295 device->devpath = g_strdup(path);
297 connman_element_set_data(device, connection);
299 if (connman_element_register(device, NULL) < 0) {
300 connman_element_unref(device);
304 device_list = g_slist_append(device_list, device);
306 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
307 BLUEZ_ADAPTER_INTERFACE, "GetProperties");
311 if (dbus_connection_send_with_reply(connection, message,
312 &call, TIMEOUT) == FALSE) {
313 connman_error("Failed to get adapter properties");
314 dbus_message_unref(message);
318 dbus_pending_call_set_notify(call, properties_reply, message, NULL);
320 message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
321 BLUEZ_ADAPTER_INTERFACE, "ListDevices");
325 if (dbus_connection_send_with_reply(connection, message,
326 &call, TIMEOUT) == FALSE) {
327 connman_error("Failed to get Bluetooth devices");
328 dbus_message_unref(message);
332 dbus_pending_call_set_notify(call, devices_reply, message, NULL);
335 static void remove_adapter(DBusConnection *connection, const char *path)
337 struct connman_element *device;
339 DBG("path %s", path);
341 device = find_adapter(path);
345 device_list = g_slist_remove(device_list, device);
347 connman_element_unregister(device);
348 connman_element_unref(device);
351 static void adapters_reply(DBusPendingCall *call, void *user_data)
353 DBusConnection *connection = user_data;
361 reply = dbus_pending_call_steal_reply(call);
363 dbus_error_init(&error);
365 if (dbus_message_get_args(reply, &error,
366 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
367 &adapters, &num_adapters,
368 DBUS_TYPE_INVALID) == FALSE) {
369 if (dbus_error_is_set(&error) == TRUE) {
370 connman_error("%s", error.message);
371 dbus_error_free(&error);
373 connman_error("Wrong arguments for adapter list");
377 for (i = 0; i < num_adapters; i++)
378 add_adapter(connection, adapters[i]);
380 g_strfreev(adapters);
383 dbus_message_unref(reply);
386 static void bluetooth_connect(DBusConnection *connection, void *user_data)
388 DBusMessage *message;
389 DBusPendingCall *call;
391 DBG("connection %p", connection);
393 message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
394 BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
398 if (dbus_connection_send_with_reply(connection, message,
399 &call, TIMEOUT) == FALSE) {
400 connman_error("Failed to get Bluetooth adapters");
401 dbus_message_unref(message);
405 dbus_pending_call_set_notify(call, adapters_reply, connection, NULL);
407 dbus_message_unref(message);
410 static void bluetooth_disconnect(DBusConnection *connection, void *user_data)
414 DBG("connection %p", connection);
416 for (list = device_list; list; list = list->next) {
417 struct connman_element *device = list->data;
419 connman_element_unregister(device);
420 connman_element_unref(device);
423 g_slist_free(device_list);
427 static DBusHandlerResult bluetooth_signal(DBusConnection *connection,
428 DBusMessage *message, void *user_data)
430 DBG("connection %p", connection);
432 if (dbus_message_is_signal(message, BLUEZ_ADAPTER_INTERFACE,
433 PROPERTY_CHANGED) == TRUE) {
434 property_changed(connection, message);
435 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
436 ADAPTER_ADDED) == TRUE) {
438 dbus_message_get_args(message, NULL,
439 DBUS_TYPE_OBJECT_PATH, &path,
441 add_adapter(connection, path);
442 } else if (dbus_message_is_signal(message, BLUEZ_MANAGER_INTERFACE,
443 ADAPTER_REMOVED) == TRUE) {
445 dbus_message_get_args(message, NULL,
446 DBUS_TYPE_OBJECT_PATH, &path,
448 remove_adapter(connection, path);
451 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
454 static DBusConnection *connection;
457 static const char *added_rule = "type=signal,member=" ADAPTER_ADDED
458 ",interface=" BLUEZ_MANAGER_INTERFACE;
459 static const char *removed_rule = "type=signal,member=" ADAPTER_REMOVED
460 ",interface=" BLUEZ_MANAGER_INTERFACE;
462 static const char *adapter_rule = "type=signal,member=" PROPERTY_CHANGED
463 ",interface=" BLUEZ_ADAPTER_INTERFACE;
465 static int bluetooth_init(void)
469 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
470 if (connection == NULL)
473 if (dbus_connection_add_filter(connection, bluetooth_signal,
474 NULL, NULL) == FALSE)
477 err = connman_driver_register(&bluetooth_driver);
481 watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
482 bluetooth_connect, bluetooth_disconnect, NULL, NULL);
484 connman_driver_unregister(&bluetooth_driver);
489 if (g_dbus_check_service(connection, BLUEZ_SERVICE) == TRUE)
490 bluetooth_connect(connection, NULL);
492 dbus_bus_add_match(connection, added_rule, NULL);
493 dbus_bus_add_match(connection, removed_rule, NULL);
494 dbus_bus_add_match(connection, adapter_rule, NULL);
495 dbus_connection_flush(connection);
500 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
503 dbus_connection_unref(connection);
508 static void bluetooth_exit(void)
510 dbus_bus_remove_match(connection, adapter_rule, NULL);
511 dbus_bus_remove_match(connection, removed_rule, NULL);
512 dbus_bus_remove_match(connection, added_rule, NULL);
513 dbus_connection_flush(connection);
515 g_dbus_remove_watch(connection, watch);
517 bluetooth_disconnect(connection, NULL);
519 connman_driver_unregister(&bluetooth_driver);
521 dbus_connection_remove_filter(connection, bluetooth_signal, NULL);
523 dbus_connection_unref(connection);
526 CONNMAN_PLUGIN_DEFINE(bluetooth, "Bluetooth technology plugin", VERSION,
527 bluetooth_init, bluetooth_exit)