dundee: Add Bluetooth DUN driver
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Wed, 4 Jan 2012 17:12:46 +0000 (18:12 +0100)
committerDaniel Wagner <daniel.wagner@bmw-carit.de>
Tue, 22 May 2012 16:44:47 +0000 (18:44 +0200)
Makefile.am
dundee/bluetooth.c [new file with mode: 0644]
dundee/dundee.h
dundee/main.c

index 19261ce..19844d9 100644 (file)
@@ -687,10 +687,10 @@ if DUNDEE
 
 sbin_PROGRAMS += dundee/dundee
 
-dundee_dundee_SOURCES = $(gdbus_sources) $(gatchat_sources) \
-                       src/log.c src/dbus.c \
+dundee_dundee_SOURCES = $(gdbus_sources) $(gatchat_sources) $(btio_sources) \
+                       src/log.c src/dbus.c plugins/bluetooth.c \
                        dundee/dundee.h dundee/main.c dundee/dbus.c \
-                       dundee/manager.c dundee/device.c
+                       dundee/manager.c dundee/device.c dundee/bluetooth.c
 
 dundee_dundee_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl
 
diff --git a/dundee/bluetooth.c b/dundee/bluetooth.c
new file mode 100644 (file)
index 0000000..e2e2bca
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2012  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  BMW Car IT GmbH. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "plugins/bluetooth.h"
+
+#include "dundee.h"
+
+static GHashTable *bluetooth_hash;
+
+struct bluetooth_device {
+       struct dundee_device *device;
+
+       char *path;
+       char *address;
+       char *name;
+
+       DBusPendingCall *call;
+};
+
+static void bt_disconnect(struct dundee_device *device,
+                               dundee_device_disconnect_cb_t cb, void *data)
+{
+       struct bluetooth_device *bt = dundee_device_get_data(device);
+
+       DBG("%p", bt);
+
+       CALLBACK_WITH_SUCCESS(cb, data);
+}
+
+static void bt_connect_reply(DBusPendingCall *call, gpointer user_data)
+{
+       struct cb_data *cbd = user_data;
+       dundee_device_connect_cb_t cb = cbd->cb;
+       struct bluetooth_device *bt = cbd->user;
+       DBusMessage *reply;
+       DBusError derr;
+       int fd;
+
+       DBG("%p", bt);
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       bt->call = NULL;
+
+       dbus_error_init(&derr);
+       if (dbus_set_error_from_message(&derr, reply)) {
+               DBG("Connection to bt serial returned with error: %s, %s",
+                                               derr.name, derr.message);
+
+               dbus_error_free(&derr);
+
+               CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+               goto done;
+       }
+
+       dbus_message_get_args(reply, NULL, DBUS_TYPE_UNIX_FD, &fd,
+                       DBUS_TYPE_INVALID);
+
+       DBG("%p fd %d", bt, fd);
+
+       if (fd < 0) {
+               CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+               goto done;
+       }
+
+       CALLBACK_WITH_SUCCESS(cb, fd, cbd->data);
+
+done:
+       dbus_message_unref(reply);
+       g_free(cbd);
+}
+
+static void bt_connect(struct dundee_device *device,
+                       dundee_device_connect_cb_t cb, void *data)
+{
+       struct bluetooth_device *bt = dundee_device_get_data(device);
+       struct cb_data *cbd = cb_data_new(cb, data);
+       char *profile = "dun";
+       int status;
+
+       DBG("%p", bt);
+
+       cbd->user = bt;
+
+       status = bluetooth_send_with_reply(bt->path,
+                                       BLUEZ_SERIAL_INTERFACE, "ConnectFD",
+                                       &bt->call, bt_connect_reply,
+                                       cbd, NULL, DBUS_TIMEOUT,
+                                       DBUS_TYPE_STRING, &profile,
+                                       DBUS_TYPE_INVALID);
+       if (status == 0)
+               return;
+
+       g_free(cbd);
+
+       CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
+
+struct dundee_device_driver bluetooth_driver = {
+       .name = "bluetooth",
+       .connect = bt_connect,
+       .disconnect = bt_disconnect,
+};
+
+static int bt_probe(const char *path, const char *dev_addr,
+                               const char *adapter_addr, const char *alias)
+{
+       struct bluetooth_device *bt;
+       struct dundee_device *device;
+       char buf[256];
+
+       DBG("");
+
+       /* We already have this device in our hash, ignore */
+       if (g_hash_table_lookup(bluetooth_hash, path) != NULL)
+               return -EALREADY;
+
+       ofono_info("Using device: %s, devaddr: %s, adapter: %s",
+                       path, dev_addr, adapter_addr);
+
+       strcpy(buf, "dun/");
+       bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4);
+
+       bt = g_try_new0(struct bluetooth_device, 1);
+       if (bt == NULL)
+               return -ENOMEM;
+
+       DBG("%p", bt);
+
+       device = dundee_device_create(&bluetooth_driver);
+       if (device == NULL)
+               goto free;
+
+       dundee_device_set_data(device, bt);
+
+       bt->path = g_strdup(path);
+       if (bt->path == NULL)
+               goto free;
+
+       bt->address = g_strdup(dev_addr);
+       if (bt->address == NULL)
+               goto free;
+
+       bt->name = g_strdup(alias);
+       if (bt->name == NULL)
+               goto free;
+
+       dundee_device_set_name(device, bt->name);
+
+       if (dundee_device_register(device) < 0) {
+               g_free(device);
+               goto free;
+       }
+
+       bt->device = device;
+       g_hash_table_insert(bluetooth_hash, g_strdup(path), bt);
+
+       return 0;
+
+free:
+       g_free(bt->path);
+       g_free(bt->address);
+       g_free(bt->name);
+       g_free(bt);
+
+       return -ENOMEM;
+}
+
+static void destroy_device(gpointer user)
+{
+       struct bluetooth_device *bt = user;
+
+       DBG("%p", bt);
+
+       if (bt->call != NULL)
+               dbus_pending_call_cancel(bt->call);
+
+       g_free(bt->path);
+       g_free(bt->address);
+
+       g_free(bt);
+}
+
+static gboolean bt_remove_device(gpointer key, gpointer value,
+                                       gpointer user_data)
+{
+       struct bluetooth_device *bt = value;
+       const char *path = key;
+       const char *prefix = user_data;
+
+       DBG("%p", bt);
+
+       if (prefix && g_str_has_prefix(path, prefix) == FALSE)
+               return FALSE;
+
+       dundee_device_unregister(bt->device);
+
+       return TRUE;
+}
+
+static void bt_remove(const char *prefix)
+{
+       DBG("%s", prefix);
+
+       if (bluetooth_hash == NULL)
+               return;
+
+       g_hash_table_foreach_remove(bluetooth_hash, bt_remove_device,
+                                                       (gpointer) prefix);
+}
+
+static void bt_set_alias(const char *path, const char *alias)
+{
+       struct bluetooth_device *bt;
+
+       DBG("");
+
+       if (path == NULL || alias == NULL)
+               return;
+
+       bt = g_hash_table_lookup(bluetooth_hash, path);
+       if (bt == NULL)
+               return;
+
+       g_free(bt->name);
+       bt->name = g_strdup(alias);
+
+       dundee_device_set_name(bt->device, bt->name);
+}
+
+static struct bluetooth_profile dun_profile = {
+       .name           = "dun_dt",
+       .probe          = bt_probe,
+       .remove         = bt_remove,
+       .set_alias      = bt_set_alias,
+};
+
+int __dundee_bluetooth_init(void)
+{
+       int err;
+
+       DBG("");
+
+       err = bluetooth_register_uuid(DUN_GW_UUID, &dun_profile);
+       if (err < 0)
+               return err;
+
+       bluetooth_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                               g_free, destroy_device);
+
+       return 0;
+}
+
+void  __dundee_bluetooth_cleanup(void)
+{
+       DBG("");
+
+       bluetooth_unregister_uuid(DUN_GW_UUID);
+       g_hash_table_destroy(bluetooth_hash);
+}
index 7104531..8866007 100644 (file)
@@ -139,3 +139,6 @@ void __dundee_device_foreach(dundee_device_foreach_func cb, void *userdata);
 const char *__dundee_device_get_path(struct dundee_device *device);
 void __dundee_device_append_properties(struct dundee_device *device,
                                        DBusMessageIter *dict);
+
+int __dundee_bluetooth_init(void);
+void  __dundee_bluetooth_cleanup(void);
index 2d3d75e..5e2da80 100644 (file)
@@ -234,9 +234,11 @@ int main(int argc, char **argv)
 
        __dundee_manager_init();
        __dundee_device_init();
+       __dundee_bluetooth_init();
 
        g_main_loop_run(event_loop);
 
+       __dundee_bluetooth_cleanup();
        __dundee_device_cleanup();
        __dundee_manager_cleanup();