* [PATCH v0 0/6] HFP HF: External Profile
@ 2013-01-10 14:44 Claudio Takahasi
2013-01-10 14:44 ` [PATCH v0 1/6] Makefile: Enable BlueZ 4 and BlueZ 5 Claudio Takahasi
` (7 more replies)
0 siblings, 8 replies; 26+ messages in thread
From: Claudio Takahasi @ 2013-01-10 14:44 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2056 bytes --]
This is the first group of the patches which introduces the Handsfree
BlueZ external profile.
The following patches contain only initial files and basic structures
for the HFP HF plugin (since files and plugins names are one of
controversial points).
Remaining HFP HF patches:
git://git.infradead.org/users/cktakahasi/ofono.git HF-20130109
Claudio Takahasi (6):
Makefile: Enable BlueZ 4 and BlueZ 5
bluetooth: Add versioning information to BlueZ plugins
bluetooth: Initial files for BlueZ 5
hfp_hf: Add initial file for external HFP
hfp_hf: Add hfp_driver
hfp_hf: Add BlueZ Profile handler
Claudio Takahasi (6):
Makefile: Enable BlueZ 4 and BlueZ 5
bluetooth: Add versioning information to BlueZ plugins
bluetooth: Initial files for BlueZ 5
hfp_hf: Add initial file for external HFP
hfp_hf: Add hfp_driver
hfp_hf: Add BlueZ Profile handler
Makefile.am | 33 +-
configure.ac | 10 +-
dundee/bluetooth.c | 2 +-
plugins/bluetooth.c | 989 ------------------------------------------------
plugins/bluetooth.h | 84 ----
plugins/bluez4.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++
plugins/bluez4.h | 84 ++++
plugins/bluez5.c | 145 +++++++
plugins/bluez5.h | 31 ++
plugins/dun_gw.c | 2 +-
plugins/hfp_ag.c | 2 +-
plugins/hfp_hf.c | 552 ---------------------------
plugins/hfp_hf_bluez4.c | 552 +++++++++++++++++++++++++++
plugins/hfp_hf_bluez5.c | 194 ++++++++++
plugins/sap.c | 2 +-
plugins/telit.c | 2 +-
16 files changed, 2030 insertions(+), 1643 deletions(-)
delete mode 100644 plugins/bluetooth.c
delete mode 100644 plugins/bluetooth.h
create mode 100644 plugins/bluez4.c
create mode 100644 plugins/bluez4.h
create mode 100644 plugins/bluez5.c
create mode 100644 plugins/bluez5.h
delete mode 100644 plugins/hfp_hf.c
create mode 100644 plugins/hfp_hf_bluez4.c
create mode 100644 plugins/hfp_hf_bluez5.c
--
1.7.11.7
^ permalink raw reply [flat|nested] 26+ messages in thread* [PATCH v0 1/6] Makefile: Enable BlueZ 4 and BlueZ 5 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi @ 2013-01-10 14:44 ` Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi ` (6 subsequent siblings) 7 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-10 14:44 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2008 bytes --] This patch enables BlueZ 4 and BlueZ 5 plugins if --enable-bluetooth is informed. BlueZ 5 will be the default Bluetooth plugin. For BlueZ 4, there is an additional BlueZ Library package version verification. --- Makefile.am | 4 +++- configure.ac | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0d2ba9f..811a3f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -407,7 +407,7 @@ builtin_sources += plugins/samsung.c builtin_modules += sim900 builtin_sources += plugins/sim900.c -if BLUETOOTH +if BLUEZ4 builtin_modules += bluetooth builtin_sources += plugins/bluetooth.c plugins/bluetooth.h @@ -742,6 +742,7 @@ tools_stktest_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ endif endif +if BLUEZ4 if DUNDEE sbin_PROGRAMS += dundee/dundee @@ -759,6 +760,7 @@ if SYSTEMD systemdunit_DATA += dundee/dundee.service endif endif +endif endif diff --git a/configure.ac b/configure.ac index 450352b..e55d11d 100644 --- a/configure.ac +++ b/configure.ac @@ -176,12 +176,16 @@ AC_ARG_ENABLE(bluetooth, AC_HELP_STRING([--disable-bluetooth], [disable Bluetooth modem support]), [enable_bluetooth=${enableval}]) if (test "${enable_bluetooth}" != "no"); then - PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99, dummy=yes, - AC_MSG_ERROR(Bluetooth library >= 4.99 is required)) + PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99 bluez < 5, + enable_bluez4=yes enable_bluez5=yes + AC_MSG_NOTICE(Enabling BLUEZ 4 and BlueZ 5), + enable_bluez4=no enable_bluez5=yes + AC_MSG_NOTICE(Enabling BLUEZ 5)) fi AC_SUBST(BLUEZ_CFLAGS) AC_SUBST(BLUEZ_LIBS) -AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no") +AM_CONDITIONAL(BLUEZ4, test "${enable_bluez4}" != "no") +AM_CONDITIONAL(BLUEZ5, test "${enable_bluez5}" != "no") AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE], [location of provision database]), [path_provisiondb=${withval}]) -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v0 2/6] bluetooth: Add versioning information to BlueZ plugins 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 1/6] Makefile: Enable BlueZ 4 and BlueZ 5 Claudio Takahasi @ 2013-01-10 14:44 ` Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi ` (5 subsequent siblings) 7 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-10 14:44 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 91571 bytes --] As BlueZ 5 introduced backwards incompatible changes, and we want to keep support for BlueZ 4 based plugins for some time, we need to separate the plugins that are based on BlueZ 4 from the ones based on BlueZ 5. The HFP HF plugin is renamed to hfp_hf_bluez4 to make it easy to add a HFP HF that talks to BlueZ 5. --- Makefile.am | 18 +- dundee/bluetooth.c | 2 +- plugins/bluetooth.c | 989 ------------------------------------------------ plugins/bluetooth.h | 84 ---- plugins/bluez4.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++ plugins/bluez4.h | 84 ++++ plugins/dun_gw.c | 2 +- plugins/hfp_ag.c | 2 +- plugins/hfp_hf.c | 552 --------------------------- plugins/hfp_hf_bluez4.c | 552 +++++++++++++++++++++++++++ plugins/sap.c | 2 +- plugins/telit.c | 2 +- 12 files changed, 1639 insertions(+), 1639 deletions(-) delete mode 100644 plugins/bluetooth.c delete mode 100644 plugins/bluetooth.h create mode 100644 plugins/bluez4.c create mode 100644 plugins/bluez4.h delete mode 100644 plugins/hfp_hf.c create mode 100644 plugins/hfp_hf_bluez4.c diff --git a/Makefile.am b/Makefile.am index 811a3f5..85824be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -408,23 +408,23 @@ builtin_modules += sim900 builtin_sources += plugins/sim900.c if BLUEZ4 -builtin_modules += bluetooth -builtin_sources += plugins/bluetooth.c plugins/bluetooth.h +builtin_modules += bluez4 +builtin_sources += plugins/bluez4.c plugins/bluez4.h builtin_modules += telit -builtin_sources += plugins/telit.c plugins/bluetooth.h +builtin_sources += plugins/telit.c plugins/bluez4.h builtin_modules += sap -builtin_sources += plugins/sap.c plugins/bluetooth.h +builtin_sources += plugins/sap.c plugins/bluez4.h -builtin_modules += hfp -builtin_sources += plugins/hfp_hf.c plugins/bluetooth.h +builtin_modules += hfp_bluez4 +builtin_sources += plugins/hfp_hf_bluez4.c plugins/bluez4.h builtin_modules += hfp_ag -builtin_sources += plugins/hfp_ag.c plugins/bluetooth.h +builtin_sources += plugins/hfp_ag.c plugins/bluez4.h builtin_modules += dun_gw -builtin_sources += plugins/dun_gw.c plugins/bluetooth.h +builtin_sources += plugins/dun_gw.c plugins/bluez4.h builtin_modules += connman builtin_sources += plugins/connman.c @@ -747,7 +747,7 @@ if DUNDEE sbin_PROGRAMS += dundee/dundee dundee_dundee_SOURCES = $(gdbus_sources) $(gatchat_sources) $(btio_sources) \ - src/log.c src/dbus.c plugins/bluetooth.c \ + src/log.c src/dbus.c plugins/bluez4.c \ dundee/dundee.h dundee/main.c dundee/dbus.c \ dundee/manager.c dundee/device.c dundee/bluetooth.c diff --git a/dundee/bluetooth.c b/dundee/bluetooth.c index 9ddc72c..58355d3 100644 --- a/dundee/bluetooth.c +++ b/dundee/bluetooth.c @@ -32,7 +32,7 @@ #include <glib.h> -#include "plugins/bluetooth.h" +#include "plugins/bluez4.h" #include "dundee.h" diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c deleted file mode 100644 index 5d28530..0000000 --- a/plugins/bluetooth.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. - * Copyright (C) 2010 ProFUSION embedded systems - * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> - * - * 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 <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <glib.h> -#include <gdbus.h> - -#define OFONO_API_SUBJECT_TO_CHANGE -#include <ofono/plugin.h> -#include <ofono/log.h> - -#include <btio.h> -#include "bluetooth.h" - -static DBusConnection *connection; -static GHashTable *uuid_hash = NULL; -static GHashTable *adapter_address_hash = NULL; -static gint bluetooth_refcount; -static GSList *server_list = NULL; -static const char *adapter_any_name = "any"; -static char *adapter_any_path; - -#define TIMEOUT 60 /* Timeout for user response (seconds) */ - -struct server { - guint8 channel; - char *sdp_record; - guint32 handle; - GIOChannel *io; - ConnectFunc connect_cb; - gpointer user_data; -}; - -struct cb_data { - struct server *server; - char *path; - guint source; - GIOChannel *io; -}; - -void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, - char *buf, int size) -{ - int i, j; - - for (i = 0, j = 0; adapter_addr[j] && i < size - 1; j++) - if (adapter_addr[j] >= '0' && adapter_addr[j] <= '9') - buf[i++] = adapter_addr[j]; - else if (adapter_addr[j] >= 'A' && adapter_addr[j] <= 'F') - buf[i++] = adapter_addr[j]; - - if (i < size - 1) - buf[i++] = '_'; - - for (j = 0; dev_addr[j] && i < size - 1; j++) - if (dev_addr[j] >= '0' && dev_addr[j] <= '9') - buf[i++] = dev_addr[j]; - else if (dev_addr[j] >= 'A' && dev_addr[j] <= 'F') - buf[i++] = dev_addr[j]; - - buf[i] = '\0'; -} - -int bluetooth_send_with_reply(const char *path, const char *interface, - const char *method, DBusPendingCall **call, - DBusPendingCallNotifyFunction cb, - void *user_data, DBusFreeFunction free_func, - int timeout, int type, ...) -{ - DBusMessage *msg; - DBusPendingCall *c; - va_list args; - int err; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, path, - interface, method); - if (msg == NULL) { - ofono_error("Unable to allocate new D-Bus %s message", method); - err = -ENOMEM; - goto fail; - } - - va_start(args, type); - - if (!dbus_message_append_args_valist(msg, type, args)) { - va_end(args); - err = -EIO; - goto fail; - } - - va_end(args); - - if (timeout > 0) - timeout *= 1000; - - if (!dbus_connection_send_with_reply(connection, msg, &c, timeout)) { - ofono_error("Sending %s failed", method); - err = -EIO; - goto fail; - } - - if (call != NULL) - *call = c; - - dbus_pending_call_set_notify(c, cb, user_data, free_func); - dbus_pending_call_unref(c); - - dbus_message_unref(msg); - - return 0; - -fail: - if (free_func && user_data) - free_func(user_data); - - if (msg) - dbus_message_unref(msg); - - return err; -} - -typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data); - -struct property_handler { - const char *property; - PropertyHandler callback; - gpointer user_data; -}; - -static gint property_handler_compare(gconstpointer a, gconstpointer b) -{ - const struct property_handler *handler = a; - const char *property = b; - - return strcmp(handler->property, property); -} - -void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...) -{ - va_list args; - GSList *prop_handlers = NULL; - DBusMessageIter array, dict; - - va_start(args, property); - - while (property != NULL) { - struct property_handler *handler = - g_new0(struct property_handler, 1); - - handler->property = property; - handler->callback = va_arg(args, PropertyHandler); - handler->user_data = va_arg(args, gpointer); - - property = va_arg(args, const char *); - - prop_handlers = g_slist_prepend(prop_handlers, handler); - } - - va_end(args); - - if (dbus_message_iter_init(reply, &array) == FALSE) - goto done; - - if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY) - goto done; - - dbus_message_iter_recurse(&array, &dict); - - while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { - DBusMessageIter entry, value; - const char *key; - GSList *l; - - dbus_message_iter_recurse(&dict, &entry); - - if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) - goto done; - - dbus_message_iter_get_basic(&entry, &key); - - dbus_message_iter_next(&entry); - - if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) - goto done; - - dbus_message_iter_recurse(&entry, &value); - - l = g_slist_find_custom(prop_handlers, key, - property_handler_compare); - - if (l) { - struct property_handler *handler = l->data; - - handler->callback(&value, handler->user_data); - } - - dbus_message_iter_next(&dict); - } - -done: - g_slist_foreach(prop_handlers, (GFunc) g_free, NULL); - g_slist_free(prop_handlers); -} - -static void parse_uuids(DBusMessageIter *array, gpointer user_data) -{ - GSList **uuids = user_data; - DBusMessageIter value; - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) { - const char *uuid; - - dbus_message_iter_get_basic(&value, &uuid); - - *uuids = g_slist_prepend(*uuids, (char *) uuid); - - dbus_message_iter_next(&value); - } -} - -static void parse_string(DBusMessageIter *iter, gpointer user_data) -{ - char **str = user_data; - int arg_type = dbus_message_iter_get_arg_type(iter); - - if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING) - return; - - dbus_message_iter_get_basic(iter, str); -} - -static void bluetooth_probe(GSList *uuids, const char *path, - const char *device, const char *adapter, - const char *alias) -{ - for (; uuids; uuids = uuids->next) { - struct bluetooth_profile *driver; - const char *uuid = uuids->data; - int err; - - driver = g_hash_table_lookup(uuid_hash, uuid); - if (driver == NULL) - continue; - - err = driver->probe(path, device, adapter, alias); - if (err == 0 || err == -EALREADY) - continue; - - ofono_error("%s probe: %s (%d)", driver->name, strerror(-err), - -err); - } -} - -static void device_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply; - const char *path = user_data; - const char *adapter = NULL; - const char *adapter_addr = NULL; - const char *device_addr = NULL; - const char *alias = NULL; - struct DBusError derr; - GSList *uuids = NULL; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Device.GetProperties replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, "UUIDs", parse_uuids, &uuids, - "Adapter", parse_string, &adapter, - "Address", parse_string, &device_addr, - "Alias", parse_string, &alias, NULL); - - if (adapter) - adapter_addr = g_hash_table_lookup(adapter_address_hash, - adapter); - - if (!device_addr || !adapter_addr) - goto done; - - bluetooth_probe(uuids, path, device_addr, adapter_addr, alias); - -done: - g_slist_free(uuids); - dbus_message_unref(reply); -} - -static void parse_devices(DBusMessageIter *array, gpointer user_data) -{ - DBusMessageIter value; - GSList **device_list = user_data; - - DBG(""); - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) - == DBUS_TYPE_OBJECT_PATH) { - const char *path; - - dbus_message_iter_get_basic(&value, &path); - - *device_list = g_slist_prepend(*device_list, (gpointer) path); - - dbus_message_iter_next(&value); - } -} - -static gboolean property_changed(DBusConnection *conn, DBusMessage *msg, - void *user_data) -{ - const char *property; - DBusMessageIter iter; - - dbus_message_iter_init(msg, &iter); - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return FALSE; - - dbus_message_iter_get_basic(&iter, &property); - if (g_str_equal(property, "UUIDs") == TRUE) { - GSList *uuids = NULL; - const char *path = dbus_message_get_path(msg); - DBusMessageIter variant; - - if (!dbus_message_iter_next(&iter)) - return FALSE; - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - return FALSE; - - dbus_message_iter_recurse(&iter, &variant); - - parse_uuids(&variant, &uuids); - - /* We need the full set of properties to be able to create - * the modem properly, including Adapter and Alias, so - * refetch everything again - */ - if (uuids) - bluetooth_send_with_reply(path, BLUEZ_DEVICE_INTERFACE, - "GetProperties", NULL, - device_properties_cb, g_strdup(path), - g_free, -1, DBUS_TYPE_INVALID); - } else if (g_str_equal(property, "Alias") == TRUE) { - const char *path = dbus_message_get_path(msg); - struct bluetooth_profile *profile; - const char *alias = NULL; - DBusMessageIter variant; - GHashTableIter hash_iter; - gpointer key, value; - - if (!dbus_message_iter_next(&iter)) - return FALSE; - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - return FALSE; - - dbus_message_iter_recurse(&iter, &variant); - - parse_string(&variant, &alias); - - g_hash_table_iter_init(&hash_iter, uuid_hash); - while (g_hash_table_iter_next(&hash_iter, &key, &value)) { - profile = value; - if (profile->set_alias) - profile->set_alias(path, alias); - } - } - - return TRUE; -} - -static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - const char *path = user_data; - DBusMessage *reply; - DBusError derr; - GSList *device_list = NULL; - GSList *l; - const char *addr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Adapter.GetProperties replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, - "Devices", parse_devices, &device_list, - "Address", parse_string, &addr, - NULL); - - DBG("Adapter Address: %s, Path: %s", addr, path); - g_hash_table_insert(adapter_address_hash, - g_strdup(path), g_strdup(addr)); - - for (l = device_list; l; l = l->next) { - const char *device = l->data; - - bluetooth_send_with_reply(device, BLUEZ_DEVICE_INTERFACE, - "GetProperties", NULL, - device_properties_cb, g_strdup(device), - g_free, -1, DBUS_TYPE_INVALID); - } - -done: - g_slist_free(device_list); - dbus_message_unref(reply); -} - -static void get_adapter_properties(const char *path, const char *handle, - gpointer user_data) -{ - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); -} - -static void remove_record(struct server *server) -{ - DBusMessage *msg; - - if (server->handle == 0) - return; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, adapter_any_path, - BLUEZ_SERVICE_INTERFACE, - "RemoveRecord"); - if (msg == NULL) { - ofono_error("Unable to allocate D-Bus RemoveRecord message"); - return; - } - - dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID); - g_dbus_send_message(connection, msg); - - ofono_info("Unregistered handle for channel %d: 0x%x", - server->channel, server->handle); -} - -static void cb_data_destroy(gpointer data) -{ - struct cb_data *cb_data = data; - - if (cb_data->source != 0) - g_source_remove(cb_data->source); - - g_free(cb_data->path); - g_free(cb_data); -} - -static void cancel_authorization(struct cb_data *user_data) -{ - DBusMessage *msg; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, user_data->path, - BLUEZ_SERVICE_INTERFACE, - "CancelAuthorization"); - - if (msg == NULL) { - ofono_error("Unable to allocate D-Bus CancelAuthorization" - " message"); - return; - } - - g_dbus_send_message(connection, msg); -} - -static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data) -{ - struct cb_data *cb_data = data; - - cancel_authorization(cb_data); - cb_data->source = 0; - - return FALSE; -} - -static void auth_cb(DBusPendingCall *call, gpointer user_data) -{ - struct cb_data *cb_data = user_data; - struct server *server = cb_data->server; - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - GError *err = NULL; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("RequestAuthorization error: %s, %s", - derr.name, derr.message); - - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) - cancel_authorization(cb_data); - - dbus_error_free(&derr); - } else { - ofono_info("RequestAuthorization succeeded"); - - if (!bt_io_accept(cb_data->io, server->connect_cb, - server->user_data, NULL, &err)) { - ofono_error("%s", err->message); - g_error_free(err); - } - } - - dbus_message_unref(reply); -} - -static void new_connection(GIOChannel *io, gpointer user_data) -{ - struct server *server = user_data; - struct cb_data *cbd; - const char *addr; - GError *err = NULL; - char laddress[18], raddress[18]; - guint8 channel; - GHashTableIter iter; - gpointer key, value; - const char *path; - - bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE, laddress, - BT_IO_OPT_DEST, raddress, - BT_IO_OPT_CHANNEL, &channel, - BT_IO_OPT_INVALID); - if (err) { - ofono_error("%s", err->message); - g_error_free(err); - return; - } - - ofono_info("New connection for %s on channel %u from: %s,", laddress, - channel, raddress); - - path = NULL; - g_hash_table_iter_init(&iter, adapter_address_hash); - - while (g_hash_table_iter_next(&iter, &key, &value)) { - if (g_str_equal(laddress, value) == TRUE) { - path = key; - break; - } - } - - if (path == NULL) - return; - - cbd = g_try_new0(struct cb_data, 1); - if (cbd == NULL) { - ofono_error("Unable to allocate client cb_data structure"); - return; - } - - cbd->path = g_strdup(path); - cbd->server = server; - cbd->io = io; - - addr = raddress; - - if (bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, - "RequestAuthorization", NULL, - auth_cb, cbd, cb_data_destroy, - TIMEOUT, DBUS_TYPE_STRING, &addr, - DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID) < 0) { - ofono_error("Request Bluetooth authorization failed"); - return; - } - - ofono_info("RequestAuthorization(%s, 0x%x)", raddress, server->handle); - - cbd->source = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, - client_event, cbd); -} - -static void remove_service_handle(gpointer data, gpointer user_data) -{ - struct server *server = data; - - server->handle = 0; -} - -static void add_record_cb(DBusPendingCall *call, gpointer user_data) -{ - struct server *server = user_data; - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Replied with an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID); - - ofono_info("Registered handle for channel %d: 0x%x", - server->channel, server->handle); - -done: - dbus_message_unref(reply); -} - -static void add_record(gpointer data, gpointer user_data) -{ - struct server *server = data; - - if (server->sdp_record == NULL) - return; - - bluetooth_send_with_reply(adapter_any_path, - BLUEZ_SERVICE_INTERFACE, "AddRecord", - NULL, add_record_cb, server, NULL, -1, - DBUS_TYPE_STRING, &server->sdp_record, - DBUS_TYPE_INVALID); -} - -static void find_adapter_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - const char *path; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Replied with an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - - adapter_any_path = g_strdup(path); - - g_slist_foreach(server_list, (GFunc) add_record, NULL); - -done: - dbus_message_unref(reply); -} - -static gboolean adapter_added(DBusConnection *conn, DBusMessage *message, - void *user_data) -{ - const char *path; - - dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); - - return TRUE; -} - -static void bluetooth_remove(gpointer key, gpointer value, gpointer user_data) -{ - struct bluetooth_profile *profile = value; - - profile->remove(user_data); -} - -static gboolean adapter_removed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path; - - if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) - return FALSE; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); - g_hash_table_remove(adapter_address_hash, path); - - return TRUE; -} - -static gboolean device_removed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path; - - if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) - return FALSE; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); - - return TRUE; -} - -static void parse_adapters(DBusMessageIter *array, gpointer user_data) -{ - DBusMessageIter value; - - DBG(""); - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) - == DBUS_TYPE_OBJECT_PATH) { - const char *path; - - dbus_message_iter_get_basic(&value, &path); - - DBG("Calling GetProperties on %s", path); - - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); - - dbus_message_iter_next(&value); - } -} - -static void manager_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Manager.GetProperties() replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, "Adapters", parse_adapters, NULL, - NULL); - -done: - dbus_message_unref(reply); -} - -static void bluetooth_connect(DBusConnection *conn, void *user_data) -{ - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties", - NULL, manager_properties_cb, NULL, NULL, -1, - DBUS_TYPE_INVALID); - - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "FindAdapter", - NULL, find_adapter_cb, NULL, NULL, -1, - DBUS_TYPE_STRING, &adapter_any_name, - DBUS_TYPE_INVALID); -} - -static void bluetooth_disconnect(DBusConnection *conn, void *user_data) -{ - if (uuid_hash == NULL) - return; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, NULL); - - g_slist_foreach(server_list, (GFunc) remove_service_handle, NULL); -} - -static guint bluetooth_watch; -static guint adapter_added_watch; -static guint adapter_removed_watch; -static guint device_removed_watch; -static guint property_watch; - -static void bluetooth_ref(void) -{ - if (bluetooth_refcount > 0) - goto increment; - - connection = ofono_dbus_get_connection(); - - bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE, - bluetooth_connect, - bluetooth_disconnect, NULL, NULL); - - adapter_added_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, - NULL, BLUEZ_MANAGER_INTERFACE, - "AdapterAdded", - adapter_added, NULL, NULL); - - adapter_removed_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_MANAGER_INTERFACE, - "AdapterRemoved", - adapter_removed, NULL, NULL); - - device_removed_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_ADAPTER_INTERFACE, - "DeviceRemoved", - device_removed, NULL, NULL); - - property_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_DEVICE_INTERFACE, - "PropertyChanged", - property_changed, NULL, NULL); - - if (bluetooth_watch == 0 || adapter_added_watch == 0 || - adapter_removed_watch == 0 || property_watch == 0) { - goto remove; - } - - uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, NULL); - - adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - -increment: - g_atomic_int_inc(&bluetooth_refcount); - - return; - -remove: - g_dbus_remove_watch(connection, bluetooth_watch); - g_dbus_remove_watch(connection, adapter_added_watch); - g_dbus_remove_watch(connection, adapter_removed_watch); - g_dbus_remove_watch(connection, property_watch); -} - -static void bluetooth_unref(void) -{ - if (g_atomic_int_dec_and_test(&bluetooth_refcount) == FALSE) - return; - - g_free(adapter_any_path); - adapter_any_path = NULL; - - g_dbus_remove_watch(connection, bluetooth_watch); - g_dbus_remove_watch(connection, adapter_added_watch); - g_dbus_remove_watch(connection, adapter_removed_watch); - g_dbus_remove_watch(connection, property_watch); - - g_hash_table_destroy(uuid_hash); - g_hash_table_destroy(adapter_address_hash); -} - -void bluetooth_get_properties() -{ - g_hash_table_foreach(adapter_address_hash, - (GHFunc) get_adapter_properties, NULL); -} - -int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile) -{ - bluetooth_ref(); - - g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); - - g_hash_table_foreach(adapter_address_hash, - (GHFunc) get_adapter_properties, NULL); - - return 0; -} - -void bluetooth_unregister_uuid(const char *uuid) -{ - g_hash_table_remove(uuid_hash, uuid); - - bluetooth_unref(); -} - -struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, - ConnectFunc cb, gpointer user_data) -{ - struct server *server; - GError *err = NULL; - - server = g_try_new0(struct server, 1); - if (!server) - return NULL; - - server->channel = channel; - - server->io = bt_io_listen(BT_IO_RFCOMM, NULL, new_connection, - server, NULL, &err, - BT_IO_OPT_CHANNEL, server->channel, - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, - BT_IO_OPT_INVALID); - if (server->io == NULL) { - g_error_free(err); - g_free(server); - return NULL; - } - - bluetooth_ref(); - - if (sdp_record != NULL) - server->sdp_record = g_strdup(sdp_record); - - server->connect_cb = cb; - server->user_data = user_data; - - server_list = g_slist_prepend(server_list, server); - - if (adapter_any_path != NULL) - add_record(server, NULL); - - return server; -} - -void bluetooth_unregister_server(struct server *server) -{ - server_list = g_slist_remove(server_list, server); - - remove_record(server); - - if (server->io != NULL) { - g_io_channel_shutdown(server->io, TRUE, NULL); - g_io_channel_unref(server->io); - server->io = NULL; - } - - g_free(server->sdp_record); - g_free(server); - - bluetooth_unref(); -} - -OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION, - OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluetooth.h b/plugins/bluetooth.h deleted file mode 100644 index 4fc16ad..0000000 --- a/plugins/bluetooth.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> - * - * 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 - * - */ - -#include <ofono/modem.h> -#include <ofono/dbus.h> - -#define BLUEZ_SERVICE "org.bluez" -#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager" -#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter" -#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device" -#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service" -#define BLUEZ_SERIAL_INTERFACE BLUEZ_SERVICE ".Serial" - -#define DBUS_TIMEOUT 15 - -#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" -#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" -#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" -#define SAP_UUID "0000112d-0000-1000-8000-00805f9b34fb" - -struct bluetooth_profile { - const char *name; - int (*probe)(const char *device, const char *dev_addr, - const char *adapter_addr, const char *alias); - void (*remove)(const char *prefix); - void (*set_alias)(const char *device, const char *); -}; - -struct bluetooth_sap_driver { - const char *name; - int (*enable) (struct ofono_modem *modem, struct ofono_modem *sap_modem, - int bt_fd); - void (*pre_sim) (struct ofono_modem *modem); - void (*post_sim) (struct ofono_modem *modem); - void (*set_online) (struct ofono_modem *modem, ofono_bool_t online, - ofono_modem_online_cb_t cb, void *user_data); - void (*post_online) (struct ofono_modem *modem); - int (*disable) (struct ofono_modem *modem); -}; - -struct server; - -typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data); - -void bluetooth_get_properties(); -int bluetooth_register_uuid(const char *uuid, - struct bluetooth_profile *profile); -void bluetooth_unregister_uuid(const char *uuid); - -struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, - ConnectFunc cb, gpointer user_data); -void bluetooth_unregister_server(struct server *server); - -void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, - char *buf, int size); - -int bluetooth_send_with_reply(const char *path, const char *interface, - const char *method, DBusPendingCall **call, - DBusPendingCallNotifyFunction cb, - void *user_data, DBusFreeFunction free_func, - int timeout, int type, ...); -void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...); - -int bluetooth_sap_client_register(struct bluetooth_sap_driver *sap, - struct ofono_modem *modem); -void bluetooth_sap_client_unregister(struct ofono_modem *modem); diff --git a/plugins/bluez4.c b/plugins/bluez4.c new file mode 100644 index 0000000..6a29d9f --- /dev/null +++ b/plugins/bluez4.c @@ -0,0 +1,989 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2010 ProFUSION embedded systems + * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> + * + * 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 <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <glib.h> +#include <gdbus.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +#include <btio.h> +#include "bluez4.h" + +static DBusConnection *connection; +static GHashTable *uuid_hash = NULL; +static GHashTable *adapter_address_hash = NULL; +static gint bluetooth_refcount; +static GSList *server_list = NULL; +static const char *adapter_any_name = "any"; +static char *adapter_any_path; + +#define TIMEOUT 60 /* Timeout for user response (seconds) */ + +struct server { + guint8 channel; + char *sdp_record; + guint32 handle; + GIOChannel *io; + ConnectFunc connect_cb; + gpointer user_data; +}; + +struct cb_data { + struct server *server; + char *path; + guint source; + GIOChannel *io; +}; + +void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, + char *buf, int size) +{ + int i, j; + + for (i = 0, j = 0; adapter_addr[j] && i < size - 1; j++) + if (adapter_addr[j] >= '0' && adapter_addr[j] <= '9') + buf[i++] = adapter_addr[j]; + else if (adapter_addr[j] >= 'A' && adapter_addr[j] <= 'F') + buf[i++] = adapter_addr[j]; + + if (i < size - 1) + buf[i++] = '_'; + + for (j = 0; dev_addr[j] && i < size - 1; j++) + if (dev_addr[j] >= '0' && dev_addr[j] <= '9') + buf[i++] = dev_addr[j]; + else if (dev_addr[j] >= 'A' && dev_addr[j] <= 'F') + buf[i++] = dev_addr[j]; + + buf[i] = '\0'; +} + +int bluetooth_send_with_reply(const char *path, const char *interface, + const char *method, DBusPendingCall **call, + DBusPendingCallNotifyFunction cb, + void *user_data, DBusFreeFunction free_func, + int timeout, int type, ...) +{ + DBusMessage *msg; + DBusPendingCall *c; + va_list args; + int err; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, path, + interface, method); + if (msg == NULL) { + ofono_error("Unable to allocate new D-Bus %s message", method); + err = -ENOMEM; + goto fail; + } + + va_start(args, type); + + if (!dbus_message_append_args_valist(msg, type, args)) { + va_end(args); + err = -EIO; + goto fail; + } + + va_end(args); + + if (timeout > 0) + timeout *= 1000; + + if (!dbus_connection_send_with_reply(connection, msg, &c, timeout)) { + ofono_error("Sending %s failed", method); + err = -EIO; + goto fail; + } + + if (call != NULL) + *call = c; + + dbus_pending_call_set_notify(c, cb, user_data, free_func); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); + + return 0; + +fail: + if (free_func && user_data) + free_func(user_data); + + if (msg) + dbus_message_unref(msg); + + return err; +} + +typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data); + +struct property_handler { + const char *property; + PropertyHandler callback; + gpointer user_data; +}; + +static gint property_handler_compare(gconstpointer a, gconstpointer b) +{ + const struct property_handler *handler = a; + const char *property = b; + + return strcmp(handler->property, property); +} + +void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...) +{ + va_list args; + GSList *prop_handlers = NULL; + DBusMessageIter array, dict; + + va_start(args, property); + + while (property != NULL) { + struct property_handler *handler = + g_new0(struct property_handler, 1); + + handler->property = property; + handler->callback = va_arg(args, PropertyHandler); + handler->user_data = va_arg(args, gpointer); + + property = va_arg(args, const char *); + + prop_handlers = g_slist_prepend(prop_handlers, handler); + } + + va_end(args); + + if (dbus_message_iter_init(reply, &array) == FALSE) + goto done; + + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY) + goto done; + + dbus_message_iter_recurse(&array, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value; + const char *key; + GSList *l; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + goto done; + + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) + goto done; + + dbus_message_iter_recurse(&entry, &value); + + l = g_slist_find_custom(prop_handlers, key, + property_handler_compare); + + if (l) { + struct property_handler *handler = l->data; + + handler->callback(&value, handler->user_data); + } + + dbus_message_iter_next(&dict); + } + +done: + g_slist_foreach(prop_handlers, (GFunc) g_free, NULL); + g_slist_free(prop_handlers); +} + +static void parse_uuids(DBusMessageIter *array, gpointer user_data) +{ + GSList **uuids = user_data; + DBusMessageIter value; + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) { + const char *uuid; + + dbus_message_iter_get_basic(&value, &uuid); + + *uuids = g_slist_prepend(*uuids, (char *) uuid); + + dbus_message_iter_next(&value); + } +} + +static void parse_string(DBusMessageIter *iter, gpointer user_data) +{ + char **str = user_data; + int arg_type = dbus_message_iter_get_arg_type(iter); + + if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING) + return; + + dbus_message_iter_get_basic(iter, str); +} + +static void bluetooth_probe(GSList *uuids, const char *path, + const char *device, const char *adapter, + const char *alias) +{ + for (; uuids; uuids = uuids->next) { + struct bluetooth_profile *driver; + const char *uuid = uuids->data; + int err; + + driver = g_hash_table_lookup(uuid_hash, uuid); + if (driver == NULL) + continue; + + err = driver->probe(path, device, adapter, alias); + if (err == 0 || err == -EALREADY) + continue; + + ofono_error("%s probe: %s (%d)", driver->name, strerror(-err), + -err); + } +} + +static void device_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + const char *path = user_data; + const char *adapter = NULL; + const char *adapter_addr = NULL; + const char *device_addr = NULL; + const char *alias = NULL; + struct DBusError derr; + GSList *uuids = NULL; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Device.GetProperties replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, "UUIDs", parse_uuids, &uuids, + "Adapter", parse_string, &adapter, + "Address", parse_string, &device_addr, + "Alias", parse_string, &alias, NULL); + + if (adapter) + adapter_addr = g_hash_table_lookup(adapter_address_hash, + adapter); + + if (!device_addr || !adapter_addr) + goto done; + + bluetooth_probe(uuids, path, device_addr, adapter_addr, alias); + +done: + g_slist_free(uuids); + dbus_message_unref(reply); +} + +static void parse_devices(DBusMessageIter *array, gpointer user_data) +{ + DBusMessageIter value; + GSList **device_list = user_data; + + DBG(""); + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) + == DBUS_TYPE_OBJECT_PATH) { + const char *path; + + dbus_message_iter_get_basic(&value, &path); + + *device_list = g_slist_prepend(*device_list, (gpointer) path); + + dbus_message_iter_next(&value); + } +} + +static gboolean property_changed(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + const char *property; + DBusMessageIter iter; + + dbus_message_iter_init(msg, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return FALSE; + + dbus_message_iter_get_basic(&iter, &property); + if (g_str_equal(property, "UUIDs") == TRUE) { + GSList *uuids = NULL; + const char *path = dbus_message_get_path(msg); + DBusMessageIter variant; + + if (!dbus_message_iter_next(&iter)) + return FALSE; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return FALSE; + + dbus_message_iter_recurse(&iter, &variant); + + parse_uuids(&variant, &uuids); + + /* We need the full set of properties to be able to create + * the modem properly, including Adapter and Alias, so + * refetch everything again + */ + if (uuids) + bluetooth_send_with_reply(path, BLUEZ_DEVICE_INTERFACE, + "GetProperties", NULL, + device_properties_cb, g_strdup(path), + g_free, -1, DBUS_TYPE_INVALID); + } else if (g_str_equal(property, "Alias") == TRUE) { + const char *path = dbus_message_get_path(msg); + struct bluetooth_profile *profile; + const char *alias = NULL; + DBusMessageIter variant; + GHashTableIter hash_iter; + gpointer key, value; + + if (!dbus_message_iter_next(&iter)) + return FALSE; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return FALSE; + + dbus_message_iter_recurse(&iter, &variant); + + parse_string(&variant, &alias); + + g_hash_table_iter_init(&hash_iter, uuid_hash); + while (g_hash_table_iter_next(&hash_iter, &key, &value)) { + profile = value; + if (profile->set_alias) + profile->set_alias(path, alias); + } + } + + return TRUE; +} + +static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + const char *path = user_data; + DBusMessage *reply; + DBusError derr; + GSList *device_list = NULL; + GSList *l; + const char *addr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Adapter.GetProperties replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, + "Devices", parse_devices, &device_list, + "Address", parse_string, &addr, + NULL); + + DBG("Adapter Address: %s, Path: %s", addr, path); + g_hash_table_insert(adapter_address_hash, + g_strdup(path), g_strdup(addr)); + + for (l = device_list; l; l = l->next) { + const char *device = l->data; + + bluetooth_send_with_reply(device, BLUEZ_DEVICE_INTERFACE, + "GetProperties", NULL, + device_properties_cb, g_strdup(device), + g_free, -1, DBUS_TYPE_INVALID); + } + +done: + g_slist_free(device_list); + dbus_message_unref(reply); +} + +static void get_adapter_properties(const char *path, const char *handle, + gpointer user_data) +{ + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); +} + +static void remove_record(struct server *server) +{ + DBusMessage *msg; + + if (server->handle == 0) + return; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, adapter_any_path, + BLUEZ_SERVICE_INTERFACE, + "RemoveRecord"); + if (msg == NULL) { + ofono_error("Unable to allocate D-Bus RemoveRecord message"); + return; + } + + dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID); + g_dbus_send_message(connection, msg); + + ofono_info("Unregistered handle for channel %d: 0x%x", + server->channel, server->handle); +} + +static void cb_data_destroy(gpointer data) +{ + struct cb_data *cb_data = data; + + if (cb_data->source != 0) + g_source_remove(cb_data->source); + + g_free(cb_data->path); + g_free(cb_data); +} + +static void cancel_authorization(struct cb_data *user_data) +{ + DBusMessage *msg; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, user_data->path, + BLUEZ_SERVICE_INTERFACE, + "CancelAuthorization"); + + if (msg == NULL) { + ofono_error("Unable to allocate D-Bus CancelAuthorization" + " message"); + return; + } + + g_dbus_send_message(connection, msg); +} + +static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct cb_data *cb_data = data; + + cancel_authorization(cb_data); + cb_data->source = 0; + + return FALSE; +} + +static void auth_cb(DBusPendingCall *call, gpointer user_data) +{ + struct cb_data *cb_data = user_data; + struct server *server = cb_data->server; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + GError *err = NULL; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("RequestAuthorization error: %s, %s", + derr.name, derr.message); + + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) + cancel_authorization(cb_data); + + dbus_error_free(&derr); + } else { + ofono_info("RequestAuthorization succeeded"); + + if (!bt_io_accept(cb_data->io, server->connect_cb, + server->user_data, NULL, &err)) { + ofono_error("%s", err->message); + g_error_free(err); + } + } + + dbus_message_unref(reply); +} + +static void new_connection(GIOChannel *io, gpointer user_data) +{ + struct server *server = user_data; + struct cb_data *cbd; + const char *addr; + GError *err = NULL; + char laddress[18], raddress[18]; + guint8 channel; + GHashTableIter iter; + gpointer key, value; + const char *path; + + bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE, laddress, + BT_IO_OPT_DEST, raddress, + BT_IO_OPT_CHANNEL, &channel, + BT_IO_OPT_INVALID); + if (err) { + ofono_error("%s", err->message); + g_error_free(err); + return; + } + + ofono_info("New connection for %s on channel %u from: %s,", laddress, + channel, raddress); + + path = NULL; + g_hash_table_iter_init(&iter, adapter_address_hash); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + if (g_str_equal(laddress, value) == TRUE) { + path = key; + break; + } + } + + if (path == NULL) + return; + + cbd = g_try_new0(struct cb_data, 1); + if (cbd == NULL) { + ofono_error("Unable to allocate client cb_data structure"); + return; + } + + cbd->path = g_strdup(path); + cbd->server = server; + cbd->io = io; + + addr = raddress; + + if (bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, + "RequestAuthorization", NULL, + auth_cb, cbd, cb_data_destroy, + TIMEOUT, DBUS_TYPE_STRING, &addr, + DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID) < 0) { + ofono_error("Request Bluetooth authorization failed"); + return; + } + + ofono_info("RequestAuthorization(%s, 0x%x)", raddress, server->handle); + + cbd->source = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, + client_event, cbd); +} + +static void remove_service_handle(gpointer data, gpointer user_data) +{ + struct server *server = data; + + server->handle = 0; +} + +static void add_record_cb(DBusPendingCall *call, gpointer user_data) +{ + struct server *server = user_data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID); + + ofono_info("Registered handle for channel %d: 0x%x", + server->channel, server->handle); + +done: + dbus_message_unref(reply); +} + +static void add_record(gpointer data, gpointer user_data) +{ + struct server *server = data; + + if (server->sdp_record == NULL) + return; + + bluetooth_send_with_reply(adapter_any_path, + BLUEZ_SERVICE_INTERFACE, "AddRecord", + NULL, add_record_cb, server, NULL, -1, + DBUS_TYPE_STRING, &server->sdp_record, + DBUS_TYPE_INVALID); +} + +static void find_adapter_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + const char *path; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + adapter_any_path = g_strdup(path); + + g_slist_foreach(server_list, (GFunc) add_record, NULL); + +done: + dbus_message_unref(reply); +} + +static gboolean adapter_added(DBusConnection *conn, DBusMessage *message, + void *user_data) +{ + const char *path; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); + + return TRUE; +} + +static void bluetooth_remove(gpointer key, gpointer value, gpointer user_data) +{ + struct bluetooth_profile *profile = value; + + profile->remove(user_data); +} + +static gboolean adapter_removed(DBusConnection *conn, + DBusMessage *message, void *user_data) +{ + const char *path; + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID) == FALSE) + return FALSE; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); + g_hash_table_remove(adapter_address_hash, path); + + return TRUE; +} + +static gboolean device_removed(DBusConnection *conn, + DBusMessage *message, void *user_data) +{ + const char *path; + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID) == FALSE) + return FALSE; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); + + return TRUE; +} + +static void parse_adapters(DBusMessageIter *array, gpointer user_data) +{ + DBusMessageIter value; + + DBG(""); + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) + == DBUS_TYPE_OBJECT_PATH) { + const char *path; + + dbus_message_iter_get_basic(&value, &path); + + DBG("Calling GetProperties on %s", path); + + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); + + dbus_message_iter_next(&value); + } +} + +static void manager_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Manager.GetProperties() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, "Adapters", parse_adapters, NULL, + NULL); + +done: + dbus_message_unref(reply); +} + +static void bluetooth_connect(DBusConnection *conn, void *user_data) +{ + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties", + NULL, manager_properties_cb, NULL, NULL, -1, + DBUS_TYPE_INVALID); + + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "FindAdapter", + NULL, find_adapter_cb, NULL, NULL, -1, + DBUS_TYPE_STRING, &adapter_any_name, + DBUS_TYPE_INVALID); +} + +static void bluetooth_disconnect(DBusConnection *conn, void *user_data) +{ + if (uuid_hash == NULL) + return; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, NULL); + + g_slist_foreach(server_list, (GFunc) remove_service_handle, NULL); +} + +static guint bluetooth_watch; +static guint adapter_added_watch; +static guint adapter_removed_watch; +static guint device_removed_watch; +static guint property_watch; + +static void bluetooth_ref(void) +{ + if (bluetooth_refcount > 0) + goto increment; + + connection = ofono_dbus_get_connection(); + + bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE, + bluetooth_connect, + bluetooth_disconnect, NULL, NULL); + + adapter_added_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, + NULL, BLUEZ_MANAGER_INTERFACE, + "AdapterAdded", + adapter_added, NULL, NULL); + + adapter_removed_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_MANAGER_INTERFACE, + "AdapterRemoved", + adapter_removed, NULL, NULL); + + device_removed_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_ADAPTER_INTERFACE, + "DeviceRemoved", + device_removed, NULL, NULL); + + property_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_DEVICE_INTERFACE, + "PropertyChanged", + property_changed, NULL, NULL); + + if (bluetooth_watch == 0 || adapter_added_watch == 0 || + adapter_removed_watch == 0 || property_watch == 0) { + goto remove; + } + + uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); + + adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + +increment: + g_atomic_int_inc(&bluetooth_refcount); + + return; + +remove: + g_dbus_remove_watch(connection, bluetooth_watch); + g_dbus_remove_watch(connection, adapter_added_watch); + g_dbus_remove_watch(connection, adapter_removed_watch); + g_dbus_remove_watch(connection, property_watch); +} + +static void bluetooth_unref(void) +{ + if (g_atomic_int_dec_and_test(&bluetooth_refcount) == FALSE) + return; + + g_free(adapter_any_path); + adapter_any_path = NULL; + + g_dbus_remove_watch(connection, bluetooth_watch); + g_dbus_remove_watch(connection, adapter_added_watch); + g_dbus_remove_watch(connection, adapter_removed_watch); + g_dbus_remove_watch(connection, property_watch); + + g_hash_table_destroy(uuid_hash); + g_hash_table_destroy(adapter_address_hash); +} + +void bluetooth_get_properties() +{ + g_hash_table_foreach(adapter_address_hash, + (GHFunc) get_adapter_properties, NULL); +} + +int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile) +{ + bluetooth_ref(); + + g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); + + g_hash_table_foreach(adapter_address_hash, + (GHFunc) get_adapter_properties, NULL); + + return 0; +} + +void bluetooth_unregister_uuid(const char *uuid) +{ + g_hash_table_remove(uuid_hash, uuid); + + bluetooth_unref(); +} + +struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, + ConnectFunc cb, gpointer user_data) +{ + struct server *server; + GError *err = NULL; + + server = g_try_new0(struct server, 1); + if (!server) + return NULL; + + server->channel = channel; + + server->io = bt_io_listen(BT_IO_RFCOMM, NULL, new_connection, + server, NULL, &err, + BT_IO_OPT_CHANNEL, server->channel, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, + BT_IO_OPT_INVALID); + if (server->io == NULL) { + g_error_free(err); + g_free(server); + return NULL; + } + + bluetooth_ref(); + + if (sdp_record != NULL) + server->sdp_record = g_strdup(sdp_record); + + server->connect_cb = cb; + server->user_data = user_data; + + server_list = g_slist_prepend(server_list, server); + + if (adapter_any_path != NULL) + add_record(server, NULL); + + return server; +} + +void bluetooth_unregister_server(struct server *server) +{ + server_list = g_slist_remove(server_list, server); + + remove_record(server); + + if (server->io != NULL) { + g_io_channel_shutdown(server->io, TRUE, NULL); + g_io_channel_unref(server->io); + server->io = NULL; + } + + g_free(server->sdp_record); + g_free(server); + + bluetooth_unref(); +} + +OFONO_PLUGIN_DEFINE(bluez4, "Bluetooth Utils Plugins", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluez4.h b/plugins/bluez4.h new file mode 100644 index 0000000..4fc16ad --- /dev/null +++ b/plugins/bluez4.h @@ -0,0 +1,84 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> + * + * 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 + * + */ + +#include <ofono/modem.h> +#include <ofono/dbus.h> + +#define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager" +#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter" +#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device" +#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service" +#define BLUEZ_SERIAL_INTERFACE BLUEZ_SERVICE ".Serial" + +#define DBUS_TIMEOUT 15 + +#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" +#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" +#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" +#define SAP_UUID "0000112d-0000-1000-8000-00805f9b34fb" + +struct bluetooth_profile { + const char *name; + int (*probe)(const char *device, const char *dev_addr, + const char *adapter_addr, const char *alias); + void (*remove)(const char *prefix); + void (*set_alias)(const char *device, const char *); +}; + +struct bluetooth_sap_driver { + const char *name; + int (*enable) (struct ofono_modem *modem, struct ofono_modem *sap_modem, + int bt_fd); + void (*pre_sim) (struct ofono_modem *modem); + void (*post_sim) (struct ofono_modem *modem); + void (*set_online) (struct ofono_modem *modem, ofono_bool_t online, + ofono_modem_online_cb_t cb, void *user_data); + void (*post_online) (struct ofono_modem *modem); + int (*disable) (struct ofono_modem *modem); +}; + +struct server; + +typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data); + +void bluetooth_get_properties(); +int bluetooth_register_uuid(const char *uuid, + struct bluetooth_profile *profile); +void bluetooth_unregister_uuid(const char *uuid); + +struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, + ConnectFunc cb, gpointer user_data); +void bluetooth_unregister_server(struct server *server); + +void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, + char *buf, int size); + +int bluetooth_send_with_reply(const char *path, const char *interface, + const char *method, DBusPendingCall **call, + DBusPendingCallNotifyFunction cb, + void *user_data, DBusFreeFunction free_func, + int timeout, int type, ...); +void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...); + +int bluetooth_sap_client_register(struct bluetooth_sap_driver *sap, + struct ofono_modem *modem); +void bluetooth_sap_client_unregister(struct ofono_modem *modem); diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c index 75b62eb..fc8bde4 100644 --- a/plugins/dun_gw.c +++ b/plugins/dun_gw.c @@ -33,7 +33,7 @@ #include <ofono/modem.h> #include <gdbus.h> -#include "bluetooth.h" +#include "bluez4.h" #define DUN_GW_CHANNEL 1 diff --git a/plugins/hfp_ag.c b/plugins/hfp_ag.c index c2d1d30..12374ad 100644 --- a/plugins/hfp_ag.c +++ b/plugins/hfp_ag.c @@ -33,7 +33,7 @@ #include <ofono/modem.h> #include <gdbus.h> -#include "bluetooth.h" +#include "bluez4.h" #define HFP_AG_CHANNEL 13 diff --git a/plugins/hfp_hf.c b/plugins/hfp_hf.c deleted file mode 100644 index 7c500e3..0000000 --- a/plugins/hfp_hf.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. - * Copyright (C) 2010 ProFUSION embedded systems - * Copyright (C) 2011 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 <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <glib.h> -#include <gatchat.h> -#include <gattty.h> -#include <gdbus.h> -#include <ofono.h> - -#define OFONO_API_SUBJECT_TO_CHANGE -#include <ofono/plugin.h> -#include <ofono/log.h> -#include <ofono/modem.h> -#include <ofono/devinfo.h> -#include <ofono/netreg.h> -#include <ofono/voicecall.h> -#include <ofono/call-volume.h> -#include <ofono/handsfree.h> - -#include <drivers/hfpmodem/slc.h> - -#include "bluetooth.h" - -#define BLUEZ_GATEWAY_INTERFACE BLUEZ_SERVICE ".HandsfreeGateway" - -#define HFP_AGENT_INTERFACE "org.bluez.HandsfreeAgent" -#define HFP_AGENT_ERROR_INTERFACE "org.bluez.Error" - -#ifndef DBUS_TYPE_UNIX_FD -#define DBUS_TYPE_UNIX_FD -1 -#endif - -static DBusConnection *connection; -static GHashTable *modem_hash = NULL; - -struct hfp_data { - struct hfp_slc_info info; - char *handsfree_path; - char *handsfree_address; - DBusMessage *slc_msg; - gboolean agent_registered; - DBusPendingCall *call; -}; - -static void hfp_debug(const char *str, void *user_data) -{ - const char *prefix = user_data; - - ofono_info("%s%s", prefix, str); -} - -static void slc_established(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - ofono_modem_set_powered(modem, TRUE); - - msg = dbus_message_new_method_return(data->slc_msg); - g_dbus_send_message(connection, msg); - dbus_message_unref(data->slc_msg); - data->slc_msg = NULL; - - ofono_info("Service level connection established"); -} - -static void slc_failed(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - msg = g_dbus_create_error(data->slc_msg, HFP_AGENT_ERROR_INTERFACE - ".Failed", - "HFP Handshake failed"); - g_dbus_send_message(connection, msg); - dbus_message_unref(data->slc_msg); - data->slc_msg = NULL; - - ofono_error("Service level connection failed"); - ofono_modem_set_powered(modem, FALSE); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; -} - -static void hfp_disconnected_cb(gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - - ofono_modem_set_powered(modem, FALSE); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; -} - -/* either oFono or Phone could request SLC connection */ -static int service_level_connection(struct ofono_modem *modem, int fd) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - GIOChannel *io; - GAtSyntax *syntax; - GAtChat *chat; - - io = g_io_channel_unix_new(fd); - if (io == NULL) { - ofono_error("Service level connection failed: %s (%d)", - strerror(errno), errno); - return -EIO; - } - - syntax = g_at_syntax_new_gsm_permissive(); - chat = g_at_chat_new(io, syntax); - g_at_syntax_unref(syntax); - g_io_channel_unref(io); - - if (chat == NULL) - return -ENOMEM; - - g_at_chat_set_disconnect_function(chat, hfp_disconnected_cb, modem); - - if (getenv("OFONO_AT_DEBUG")) - g_at_chat_set_debug(chat, hfp_debug, ""); - - data->info.chat = chat; - hfp_slc_establish(&data->info, slc_established, slc_failed, modem); - - return -EINPROGRESS; -} - -static DBusMessage *hfp_agent_new_connection(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - int fd, err; - struct ofono_modem *modem = data; - struct hfp_data *hfp_data = ofono_modem_get_data(modem); - guint16 version; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UNIX_FD, &fd, - DBUS_TYPE_UINT16, &version, DBUS_TYPE_INVALID)) - return __ofono_error_invalid_args(msg); - - hfp_slc_info_init(&hfp_data->info, version); - - err = service_level_connection(modem, fd); - if (err < 0 && err != -EINPROGRESS) - return __ofono_error_failed(msg); - - hfp_data->slc_msg = msg; - dbus_message_ref(msg); - - return NULL; -} - -static DBusMessage *hfp_agent_release(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct ofono_modem *modem = data; - struct hfp_data *hfp_data = ofono_modem_get_data(modem); - const char *obj_path = ofono_modem_get_path(modem); - - g_dbus_unregister_interface(connection, obj_path, HFP_AGENT_INTERFACE); - hfp_data->agent_registered = FALSE; - - g_hash_table_remove(modem_hash, hfp_data->handsfree_path); - ofono_modem_remove(modem); - - return dbus_message_new_method_return(msg); -} - -static const GDBusMethodTable agent_methods[] = { - { GDBUS_ASYNC_METHOD("NewConnection", - GDBUS_ARGS({ "fd", "h" }, { "version", "q" }), - NULL, hfp_agent_new_connection) }, - { GDBUS_METHOD("Release", NULL, NULL, hfp_agent_release) }, - { } -}; - -static int hfp_hf_probe(const char *device, const char *dev_addr, - const char *adapter_addr, const char *alias) -{ - struct ofono_modem *modem; - struct hfp_data *data; - char buf[256]; - - /* We already have this device in our hash, ignore */ - if (g_hash_table_lookup(modem_hash, device) != NULL) - return -EALREADY; - - ofono_info("Using device: %s, devaddr: %s, adapter: %s", - device, dev_addr, adapter_addr); - - strcpy(buf, "hfp/"); - bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4); - - modem = ofono_modem_create(buf, "hfp"); - if (modem == NULL) - return -ENOMEM; - - data = g_try_new0(struct hfp_data, 1); - if (data == NULL) - goto free; - - data->handsfree_path = g_strdup(device); - if (data->handsfree_path == NULL) - goto free; - - data->handsfree_address = g_strdup(dev_addr); - if (data->handsfree_address == NULL) - goto free; - - ofono_modem_set_data(modem, data); - ofono_modem_set_name(modem, alias); - ofono_modem_register(modem); - - g_hash_table_insert(modem_hash, g_strdup(device), modem); - - return 0; - -free: - if (data != NULL) - g_free(data->handsfree_path); - - g_free(data); - ofono_modem_remove(modem); - - return -ENOMEM; -} - -static gboolean hfp_remove_modem(gpointer key, gpointer value, - gpointer user_data) -{ - struct ofono_modem *modem = value; - const char *device = key; - const char *prefix = user_data; - - if (prefix && g_str_has_prefix(device, prefix) == FALSE) - return FALSE; - - ofono_modem_remove(modem); - - return TRUE; -} - -static void hfp_hf_remove(const char *prefix) -{ - DBG("%s", prefix); - - if (modem_hash == NULL) - return; - - g_hash_table_foreach_remove(modem_hash, hfp_remove_modem, - (gpointer) prefix); -} - -static void hfp_hf_set_alias(const char *device, const char *alias) -{ - struct ofono_modem *modem; - - if (device == NULL || alias == NULL) - return; - - modem = g_hash_table_lookup(modem_hash, device); - if (modem == NULL) - return; - - ofono_modem_set_name(modem, alias); -} - -static int hfp_register_ofono_handsfree(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - DBG("Registering oFono Agent to bluetooth daemon"); - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "RegisterAgent"); - if (msg == NULL) - return -ENOMEM; - - dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, - DBUS_TYPE_INVALID); - - g_dbus_send_message(connection, msg); - return 0; -} - -static int hfp_unregister_ofono_handsfree(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - DBG("Unregistering oFono Agent from bluetooth daemon"); - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "UnregisterAgent"); - if (msg == NULL) - return -ENOMEM; - - dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, - DBUS_TYPE_INVALID); - - g_dbus_send_message(connection, msg); - return 0; -} - -static int hfp_probe(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - - if (data == NULL) - return -EINVAL; - - g_dbus_register_interface(connection, obj_path, HFP_AGENT_INTERFACE, - agent_methods, NULL, NULL, modem, NULL); - - data->agent_registered = TRUE; - - if (hfp_register_ofono_handsfree(modem) != 0) - return -EINVAL; - - return 0; -} - -static void hfp_remove(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - const char *obj_path = ofono_modem_get_path(modem); - - if (data->call != NULL) - dbus_pending_call_cancel(data->call); - - if (g_dbus_unregister_interface(connection, obj_path, - HFP_AGENT_INTERFACE)) - hfp_unregister_ofono_handsfree(modem); - - g_free(data->handsfree_address); - g_free(data->handsfree_path); - g_free(data); - - ofono_modem_set_data(modem, NULL); -} - -static void hfp_connect_reply(DBusPendingCall *call, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusError derr; - DBusMessage *reply, *msg; - - reply = dbus_pending_call_steal_reply(call); - - if (ofono_modem_get_powered(modem)) - goto done; - - dbus_error_init(&derr); - if (!dbus_set_error_from_message(&derr, reply)) - goto done; - - DBG("Connect reply: %s", derr.message); - - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { - msg = dbus_message_new_method_call(BLUEZ_SERVICE, - data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Disconnect"); - if (msg == NULL) - ofono_error("Disconnect failed"); - else - g_dbus_send_message(connection, msg); - } - - ofono_modem_set_powered(modem, FALSE); - - dbus_error_free(&derr); - -done: - dbus_message_unref(reply); - data->call = NULL; -} - -/* power up hardware */ -static int hfp_enable(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - int status; - - DBG("%p", modem); - - status = bluetooth_send_with_reply(data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Connect", - &data->call, hfp_connect_reply, - modem, NULL, - DBUS_TIMEOUT, DBUS_TYPE_INVALID); - - if (status < 0) - return -EINVAL; - - return -EINPROGRESS; -} - -static void hfp_power_down(DBusPendingCall *call, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - DBG("Disconnect reply: %s", derr.message); - dbus_error_free(&derr); - goto done; - } - - ofono_modem_set_powered(modem, FALSE); - -done: - dbus_message_unref(reply); - data->call = NULL; -} - -static int hfp_disable(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - int status; - - DBG("%p", modem); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; - - if (data->agent_registered) { - status = bluetooth_send_with_reply(data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Disconnect", - &data->call, hfp_power_down, - modem, NULL, - DBUS_TIMEOUT, DBUS_TYPE_INVALID); - - if (status < 0) - return -EINVAL; - } - - return -EINPROGRESS; -} - -static void hfp_pre_sim(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - ofono_devinfo_create(modem, 0, "hfpmodem", data->handsfree_address); - ofono_voicecall_create(modem, 0, "hfpmodem", &data->info); - ofono_netreg_create(modem, 0, "hfpmodem", &data->info); - ofono_call_volume_create(modem, 0, "hfpmodem", &data->info); - ofono_handsfree_create(modem, 0, "hfpmodem", &data->info); -} - -static void hfp_post_sim(struct ofono_modem *modem) -{ - DBG("%p", modem); -} - -static struct ofono_modem_driver hfp_driver = { - .name = "hfp", - .modem_type = OFONO_MODEM_TYPE_HFP, - .probe = hfp_probe, - .remove = hfp_remove, - .enable = hfp_enable, - .disable = hfp_disable, - .pre_sim = hfp_pre_sim, - .post_sim = hfp_post_sim, -}; - -static struct bluetooth_profile hfp_hf = { - .name = "hfp_hf", - .probe = hfp_hf_probe, - .remove = hfp_hf_remove, - .set_alias = hfp_hf_set_alias, -}; - -static int hfp_init(void) -{ - int err; - - if (DBUS_TYPE_UNIX_FD < 0) - return -EBADF; - - connection = ofono_dbus_get_connection(); - - err = ofono_modem_driver_register(&hfp_driver); - if (err < 0) - return err; - - err = bluetooth_register_uuid(HFP_AG_UUID, &hfp_hf); - if (err < 0) { - ofono_modem_driver_unregister(&hfp_driver); - return err; - } - - modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, NULL); - - return 0; -} - -static void hfp_exit(void) -{ - bluetooth_unregister_uuid(HFP_AG_UUID); - ofono_modem_driver_unregister(&hfp_driver); - - g_hash_table_destroy(modem_hash); -} - -OFONO_PLUGIN_DEFINE(hfp, "Hands-Free Profile Plugins", VERSION, - OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) diff --git a/plugins/hfp_hf_bluez4.c b/plugins/hfp_hf_bluez4.c new file mode 100644 index 0000000..450c183 --- /dev/null +++ b/plugins/hfp_hf_bluez4.c @@ -0,0 +1,552 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2010 ProFUSION embedded systems + * Copyright (C) 2011 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 <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <glib.h> +#include <gatchat.h> +#include <gattty.h> +#include <gdbus.h> +#include <ofono.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> +#include <ofono/modem.h> +#include <ofono/devinfo.h> +#include <ofono/netreg.h> +#include <ofono/voicecall.h> +#include <ofono/call-volume.h> +#include <ofono/handsfree.h> + +#include <drivers/hfpmodem/slc.h> + +#include "bluez4.h" + +#define BLUEZ_GATEWAY_INTERFACE BLUEZ_SERVICE ".HandsfreeGateway" + +#define HFP_AGENT_INTERFACE "org.bluez.HandsfreeAgent" +#define HFP_AGENT_ERROR_INTERFACE "org.bluez.Error" + +#ifndef DBUS_TYPE_UNIX_FD +#define DBUS_TYPE_UNIX_FD -1 +#endif + +static DBusConnection *connection; +static GHashTable *modem_hash = NULL; + +struct hfp_data { + struct hfp_slc_info info; + char *handsfree_path; + char *handsfree_address; + DBusMessage *slc_msg; + gboolean agent_registered; + DBusPendingCall *call; +}; + +static void hfp_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + ofono_info("%s%s", prefix, str); +} + +static void slc_established(gpointer userdata) +{ + struct ofono_modem *modem = userdata; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + ofono_modem_set_powered(modem, TRUE); + + msg = dbus_message_new_method_return(data->slc_msg); + g_dbus_send_message(connection, msg); + dbus_message_unref(data->slc_msg); + data->slc_msg = NULL; + + ofono_info("Service level connection established"); +} + +static void slc_failed(gpointer userdata) +{ + struct ofono_modem *modem = userdata; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + msg = g_dbus_create_error(data->slc_msg, HFP_AGENT_ERROR_INTERFACE + ".Failed", + "HFP Handshake failed"); + g_dbus_send_message(connection, msg); + dbus_message_unref(data->slc_msg); + data->slc_msg = NULL; + + ofono_error("Service level connection failed"); + ofono_modem_set_powered(modem, FALSE); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; +} + +static void hfp_disconnected_cb(gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + + ofono_modem_set_powered(modem, FALSE); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; +} + +/* either oFono or Phone could request SLC connection */ +static int service_level_connection(struct ofono_modem *modem, int fd) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + GIOChannel *io; + GAtSyntax *syntax; + GAtChat *chat; + + io = g_io_channel_unix_new(fd); + if (io == NULL) { + ofono_error("Service level connection failed: %s (%d)", + strerror(errno), errno); + return -EIO; + } + + syntax = g_at_syntax_new_gsm_permissive(); + chat = g_at_chat_new(io, syntax); + g_at_syntax_unref(syntax); + g_io_channel_unref(io); + + if (chat == NULL) + return -ENOMEM; + + g_at_chat_set_disconnect_function(chat, hfp_disconnected_cb, modem); + + if (getenv("OFONO_AT_DEBUG")) + g_at_chat_set_debug(chat, hfp_debug, ""); + + data->info.chat = chat; + hfp_slc_establish(&data->info, slc_established, slc_failed, modem); + + return -EINPROGRESS; +} + +static DBusMessage *hfp_agent_new_connection(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + int fd, err; + struct ofono_modem *modem = data; + struct hfp_data *hfp_data = ofono_modem_get_data(modem); + guint16 version; + + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UNIX_FD, &fd, + DBUS_TYPE_UINT16, &version, DBUS_TYPE_INVALID)) + return __ofono_error_invalid_args(msg); + + hfp_slc_info_init(&hfp_data->info, version); + + err = service_level_connection(modem, fd); + if (err < 0 && err != -EINPROGRESS) + return __ofono_error_failed(msg); + + hfp_data->slc_msg = msg; + dbus_message_ref(msg); + + return NULL; +} + +static DBusMessage *hfp_agent_release(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_modem *modem = data; + struct hfp_data *hfp_data = ofono_modem_get_data(modem); + const char *obj_path = ofono_modem_get_path(modem); + + g_dbus_unregister_interface(connection, obj_path, HFP_AGENT_INTERFACE); + hfp_data->agent_registered = FALSE; + + g_hash_table_remove(modem_hash, hfp_data->handsfree_path); + ofono_modem_remove(modem); + + return dbus_message_new_method_return(msg); +} + +static const GDBusMethodTable agent_methods[] = { + { GDBUS_ASYNC_METHOD("NewConnection", + GDBUS_ARGS({ "fd", "h" }, { "version", "q" }), + NULL, hfp_agent_new_connection) }, + { GDBUS_METHOD("Release", NULL, NULL, hfp_agent_release) }, + { } +}; + +static int hfp_hf_probe(const char *device, const char *dev_addr, + const char *adapter_addr, const char *alias) +{ + struct ofono_modem *modem; + struct hfp_data *data; + char buf[256]; + + /* We already have this device in our hash, ignore */ + if (g_hash_table_lookup(modem_hash, device) != NULL) + return -EALREADY; + + ofono_info("Using device: %s, devaddr: %s, adapter: %s", + device, dev_addr, adapter_addr); + + strcpy(buf, "hfp/"); + bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4); + + modem = ofono_modem_create(buf, "hfp"); + if (modem == NULL) + return -ENOMEM; + + data = g_try_new0(struct hfp_data, 1); + if (data == NULL) + goto free; + + data->handsfree_path = g_strdup(device); + if (data->handsfree_path == NULL) + goto free; + + data->handsfree_address = g_strdup(dev_addr); + if (data->handsfree_address == NULL) + goto free; + + ofono_modem_set_data(modem, data); + ofono_modem_set_name(modem, alias); + ofono_modem_register(modem); + + g_hash_table_insert(modem_hash, g_strdup(device), modem); + + return 0; + +free: + if (data != NULL) + g_free(data->handsfree_path); + + g_free(data); + ofono_modem_remove(modem); + + return -ENOMEM; +} + +static gboolean hfp_remove_modem(gpointer key, gpointer value, + gpointer user_data) +{ + struct ofono_modem *modem = value; + const char *device = key; + const char *prefix = user_data; + + if (prefix && g_str_has_prefix(device, prefix) == FALSE) + return FALSE; + + ofono_modem_remove(modem); + + return TRUE; +} + +static void hfp_hf_remove(const char *prefix) +{ + DBG("%s", prefix); + + if (modem_hash == NULL) + return; + + g_hash_table_foreach_remove(modem_hash, hfp_remove_modem, + (gpointer) prefix); +} + +static void hfp_hf_set_alias(const char *device, const char *alias) +{ + struct ofono_modem *modem; + + if (device == NULL || alias == NULL) + return; + + modem = g_hash_table_lookup(modem_hash, device); + if (modem == NULL) + return; + + ofono_modem_set_name(modem, alias); +} + +static int hfp_register_ofono_handsfree(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + DBG("Registering oFono Agent to bluetooth daemon"); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "RegisterAgent"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, + DBUS_TYPE_INVALID); + + g_dbus_send_message(connection, msg); + return 0; +} + +static int hfp_unregister_ofono_handsfree(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + DBG("Unregistering oFono Agent from bluetooth daemon"); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "UnregisterAgent"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, + DBUS_TYPE_INVALID); + + g_dbus_send_message(connection, msg); + return 0; +} + +static int hfp_probe(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + + if (data == NULL) + return -EINVAL; + + g_dbus_register_interface(connection, obj_path, HFP_AGENT_INTERFACE, + agent_methods, NULL, NULL, modem, NULL); + + data->agent_registered = TRUE; + + if (hfp_register_ofono_handsfree(modem) != 0) + return -EINVAL; + + return 0; +} + +static void hfp_remove(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + const char *obj_path = ofono_modem_get_path(modem); + + if (data->call != NULL) + dbus_pending_call_cancel(data->call); + + if (g_dbus_unregister_interface(connection, obj_path, + HFP_AGENT_INTERFACE)) + hfp_unregister_ofono_handsfree(modem); + + g_free(data->handsfree_address); + g_free(data->handsfree_path); + g_free(data); + + ofono_modem_set_data(modem, NULL); +} + +static void hfp_connect_reply(DBusPendingCall *call, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusError derr; + DBusMessage *reply, *msg; + + reply = dbus_pending_call_steal_reply(call); + + if (ofono_modem_get_powered(modem)) + goto done; + + dbus_error_init(&derr); + if (!dbus_set_error_from_message(&derr, reply)) + goto done; + + DBG("Connect reply: %s", derr.message); + + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { + msg = dbus_message_new_method_call(BLUEZ_SERVICE, + data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Disconnect"); + if (msg == NULL) + ofono_error("Disconnect failed"); + else + g_dbus_send_message(connection, msg); + } + + ofono_modem_set_powered(modem, FALSE); + + dbus_error_free(&derr); + +done: + dbus_message_unref(reply); + data->call = NULL; +} + +/* power up hardware */ +static int hfp_enable(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + int status; + + DBG("%p", modem); + + status = bluetooth_send_with_reply(data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Connect", + &data->call, hfp_connect_reply, + modem, NULL, + DBUS_TIMEOUT, DBUS_TYPE_INVALID); + + if (status < 0) + return -EINVAL; + + return -EINPROGRESS; +} + +static void hfp_power_down(DBusPendingCall *call, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + DBG("Disconnect reply: %s", derr.message); + dbus_error_free(&derr); + goto done; + } + + ofono_modem_set_powered(modem, FALSE); + +done: + dbus_message_unref(reply); + data->call = NULL; +} + +static int hfp_disable(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + int status; + + DBG("%p", modem); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; + + if (data->agent_registered) { + status = bluetooth_send_with_reply(data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Disconnect", + &data->call, hfp_power_down, + modem, NULL, + DBUS_TIMEOUT, DBUS_TYPE_INVALID); + + if (status < 0) + return -EINVAL; + } + + return -EINPROGRESS; +} + +static void hfp_pre_sim(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + + DBG("%p", modem); + + ofono_devinfo_create(modem, 0, "hfpmodem", data->handsfree_address); + ofono_voicecall_create(modem, 0, "hfpmodem", &data->info); + ofono_netreg_create(modem, 0, "hfpmodem", &data->info); + ofono_call_volume_create(modem, 0, "hfpmodem", &data->info); + ofono_handsfree_create(modem, 0, "hfpmodem", &data->info); +} + +static void hfp_post_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static struct ofono_modem_driver hfp_driver = { + .name = "hfp", + .modem_type = OFONO_MODEM_TYPE_HFP, + .probe = hfp_probe, + .remove = hfp_remove, + .enable = hfp_enable, + .disable = hfp_disable, + .pre_sim = hfp_pre_sim, + .post_sim = hfp_post_sim, +}; + +static struct bluetooth_profile hfp_hf = { + .name = "hfp_hf", + .probe = hfp_hf_probe, + .remove = hfp_hf_remove, + .set_alias = hfp_hf_set_alias, +}; + +static int hfp_init(void) +{ + int err; + + if (DBUS_TYPE_UNIX_FD < 0) + return -EBADF; + + connection = ofono_dbus_get_connection(); + + err = ofono_modem_driver_register(&hfp_driver); + if (err < 0) + return err; + + err = bluetooth_register_uuid(HFP_AG_UUID, &hfp_hf); + if (err < 0) { + ofono_modem_driver_unregister(&hfp_driver); + return err; + } + + modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); + + return 0; +} + +static void hfp_exit(void) +{ + bluetooth_unregister_uuid(HFP_AG_UUID); + ofono_modem_driver_unregister(&hfp_driver); + + g_hash_table_destroy(modem_hash); +} + +OFONO_PLUGIN_DEFINE(hfp_bluez4, "Hands-Free Profile Plugins", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) diff --git a/plugins/sap.c b/plugins/sap.c index d893bc1..d1913fb 100644 --- a/plugins/sap.c +++ b/plugins/sap.c @@ -37,7 +37,7 @@ #include <ofono/log.h> #include <ofono/modem.h> -#include "bluetooth.h" +#include "bluez4.h" #include "util.h" #ifndef DBUS_TYPE_UNIX_FD diff --git a/plugins/telit.c b/plugins/telit.c index 79bc421..392283a 100644 --- a/plugins/telit.c +++ b/plugins/telit.c @@ -58,7 +58,7 @@ #include <drivers/atmodem/atutil.h> #include <drivers/atmodem/vendor.h> -#include "bluetooth.h" +#include "bluez4.h" static const char *none_prefix[] = { NULL }; static const char *rsen_prefix[]= { "#RSEN:", NULL }; -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v0 3/6] bluetooth: Initial files for BlueZ 5 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 1/6] Makefile: Enable BlueZ 4 and BlueZ 5 Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi @ 2013-01-10 14:44 ` Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi ` (4 subsequent siblings) 7 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-10 14:44 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1998 bytes --] This patch adds the file for Bluetooth(BlueZ 5) oFono plugin. --- Makefile.am | 8 ++++++++ plugins/bluez5.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 plugins/bluez5.c diff --git a/Makefile.am b/Makefile.am index 85824be..69cc61d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -407,6 +407,14 @@ builtin_sources += plugins/samsung.c builtin_modules += sim900 builtin_sources += plugins/sim900.c +if BLUEZ5 +builtin_modules += bluez5 +builtin_sources += plugins/bluez5.c + +builtin_cflags += @BLUEZ_CFLAGS@ +builtin_libadd += @BLUEZ_LIBS@ +endif + if BLUEZ4 builtin_modules += bluez4 builtin_sources += plugins/bluez4.c plugins/bluez4.h diff --git a/plugins/bluez5.c b/plugins/bluez5.c new file mode 100644 index 0000000..028af66 --- /dev/null +++ b/plugins/bluez5.c @@ -0,0 +1,33 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT + * + * 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 <glib.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +OFONO_PLUGIN_DEFINE(bluez5, "BlueZ 5 Utils Plugin", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v0 4/6] hfp_hf: Add initial file for external HFP 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi ` (2 preceding siblings ...) 2013-01-10 14:44 ` [PATCH v0 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi @ 2013-01-10 14:44 ` Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 5/6] hfp_hf: Add hfp_driver Claudio Takahasi ` (3 subsequent siblings) 7 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-10 14:44 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2246 bytes --] This patch adds the initial file to support external HFP profile and BlueZ 5. "hfp_bluez5" plugin will implement an external Bluetooth profile compatible with BlueZ 5, and "hfp" plugin will keep the compatibility with BlueZ 4. Both plugins can be enabled in the system. --- Makefile.am | 3 +++ plugins/hfp_hf_bluez5.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 plugins/hfp_hf_bluez5.c diff --git a/Makefile.am b/Makefile.am index 69cc61d..ee71f85 100644 --- a/Makefile.am +++ b/Makefile.am @@ -411,6 +411,9 @@ if BLUEZ5 builtin_modules += bluez5 builtin_sources += plugins/bluez5.c +builtin_modules += hfp_bluez5 +builtin_sources += plugins/hfp_hf_bluez5.c + builtin_cflags += @BLUEZ_CFLAGS@ builtin_libadd += @BLUEZ_LIBS@ endif diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c new file mode 100644 index 0000000..aa77ba7 --- /dev/null +++ b/plugins/hfp_hf_bluez5.c @@ -0,0 +1,42 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT + * + * 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 <glib.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +static int hfp_init(void) +{ + return 0; +} + +static void hfp_exit(void) +{ +} + +OFONO_PLUGIN_DEFINE(hfp_bluez5, "External Hands-Free Profile Plugin", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v0 5/6] hfp_hf: Add hfp_driver 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi ` (3 preceding siblings ...) 2013-01-10 14:44 ` [PATCH v0 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi @ 2013-01-10 14:44 ` Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi ` (2 subsequent siblings) 7 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-10 14:44 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 7725 bytes --] Adds HFP modem driver registration. --- Makefile.am | 4 +- plugins/bluez5.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ plugins/bluez5.h | 29 +++++++++++++ plugins/hfp_hf_bluez5.c | 80 ++++++++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 plugins/bluez5.h diff --git a/Makefile.am b/Makefile.am index ee71f85..799cd28 100644 --- a/Makefile.am +++ b/Makefile.am @@ -409,10 +409,10 @@ builtin_sources += plugins/sim900.c if BLUEZ5 builtin_modules += bluez5 -builtin_sources += plugins/bluez5.c +builtin_sources += plugins/bluez5.c plugins/bluez5.h builtin_modules += hfp_bluez5 -builtin_sources += plugins/hfp_hf_bluez5.c +builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h builtin_cflags += @BLUEZ_CFLAGS@ builtin_libadd += @BLUEZ_LIBS@ diff --git a/plugins/bluez5.c b/plugins/bluez5.c index 028af66..986a3ac 100644 --- a/plugins/bluez5.c +++ b/plugins/bluez5.c @@ -23,11 +23,123 @@ #include <config.h> #endif +#include <errno.h> #include <glib.h> #define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/dbus.h> #include <ofono/plugin.h> #include <ofono/log.h> +#include <gdbus/gdbus.h> +#include "bluez5.h" + +#define BLUEZ_PROFILE_MGMT_INTERFACE BLUEZ_SERVICE ".ProfileManager1" + +static void profile_register_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("RegisterProfile() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + +done: + dbus_message_unref(reply); +} + +static void unregister_profile_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("UnregisterProfile() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + +done: + dbus_message_unref(reply); +} + +int bluetooth_register_profile(DBusConnection *conn, const char *uuid, + const char *name, const char *object) +{ + DBusMessageIter iter, dict; + DBusPendingCall *c; + DBusMessage *msg; + + DBG("Bluetooth: Registering %s (%s) profile", uuid, name); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", + BLUEZ_PROFILE_MGMT_INTERFACE, "RegisterProfile"); + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &object); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uuid); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict); + ofono_dbus_dict_append(&dict, "Name", DBUS_TYPE_STRING, &name); + + dbus_message_iter_close_container(&iter, &dict); + + if (!dbus_connection_send_with_reply(conn, msg, &c, -1)) { + ofono_error("Sending RegisterProfile failed"); + dbus_message_unref(msg); + return -EIO; + } + + dbus_pending_call_set_notify(c, profile_register_cb, NULL, NULL); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); + + return 0; +} + +void bluetooth_unregister_profile(DBusConnection *conn, const char *object) +{ + DBusMessageIter iter; + DBusPendingCall *c; + DBusMessage *msg; + + DBG("Bluetooth: Unregistering profile %s", object); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", + BLUEZ_PROFILE_MGMT_INTERFACE, "UnregisterProfile"); + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &object); + + if (!dbus_connection_send_with_reply(conn, msg, &c, -1)) { + ofono_error("Sending RegisterProfile failed"); + dbus_message_unref(msg); + return; + } + + dbus_pending_call_set_notify(c, unregister_profile_cb, NULL, NULL); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); +} + OFONO_PLUGIN_DEFINE(bluez5, "BlueZ 5 Utils Plugin", VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluez5.h b/plugins/bluez5.h new file mode 100644 index 0000000..e403b85 --- /dev/null +++ b/plugins/bluez5.h @@ -0,0 +1,29 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT + * + * 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 + * + */ + +#define BLUEZ_SERVICE "org.bluez" + +#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" + +int bluetooth_register_profile(DBusConnection *conn, const char *uuid, + const char *name, const char *object); + +void bluetooth_unregister_profile(DBusConnection *conn, const char *object); diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c index aa77ba7..ff70481 100644 --- a/plugins/hfp_hf_bluez5.c +++ b/plugins/hfp_hf_bluez5.c @@ -23,19 +23,99 @@ #include <config.h> #endif +#include <errno.h> #include <glib.h> #define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/modem.h> +#include <ofono/dbus.h> #include <ofono/plugin.h> #include <ofono/log.h> +#include "bluez5.h" + +#ifndef DBUS_TYPE_UNIX_FD +#define DBUS_TYPE_UNIX_FD -1 +#endif + +#define HFP_EXT_PROFILE_PATH "/bluetooth/profile/hfp_hf" + +static int hfp_probe(struct ofono_modem *modem) +{ + DBG("modem: %p", modem); + + return 0; +} + +static void hfp_remove(struct ofono_modem *modem) +{ + DBG("modem: %p", modem); +} + +/* power up hardware */ +static int hfp_enable(struct ofono_modem *modem) +{ + DBG("%p", modem); + + return 0; +} + +static int hfp_disable(struct ofono_modem *modem) +{ + DBG("%p", modem); + + return 0; +} + +static void hfp_pre_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static void hfp_post_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static struct ofono_modem_driver hfp_driver = { + .name = "hfp", + .modem_type = OFONO_MODEM_TYPE_HFP, + .probe = hfp_probe, + .remove = hfp_remove, + .enable = hfp_enable, + .disable = hfp_disable, + .pre_sim = hfp_pre_sim, + .post_sim = hfp_post_sim, +}; + static int hfp_init(void) { + DBusConnection *conn = ofono_dbus_get_connection(); + int err; + + if (DBUS_TYPE_UNIX_FD < 0) + return -EBADF; + + err = ofono_modem_driver_register(&hfp_driver); + if (err < 0) + return err; + + err = bluetooth_register_profile(conn, HFP_HS_UUID, "hfp_hf", + HFP_EXT_PROFILE_PATH); + if (err < 0) { + ofono_modem_driver_unregister(&hfp_driver); + return err; + } + return 0; } static void hfp_exit(void) { + DBusConnection *conn = ofono_dbus_get_connection(); + + bluetooth_unregister_profile(conn, HFP_EXT_PROFILE_PATH); + ofono_modem_driver_unregister(&hfp_driver); } OFONO_PLUGIN_DEFINE(hfp_bluez5, "External Hands-Free Profile Plugin", VERSION, -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v0 6/6] hfp_hf: Add BlueZ Profile handler 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi ` (4 preceding siblings ...) 2013-01-10 14:44 ` [PATCH v0 5/6] hfp_hf: Add hfp_driver Claudio Takahasi @ 2013-01-10 14:44 ` Claudio Takahasi 2013-01-11 9:27 ` [PATCH v0 0/6] HFP HF: External Profile Mikel Astiz 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi 7 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-10 14:44 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 4081 bytes --] This patch declares the external HFP Profile handler. It contains the initial implementation of the D-Bus Profile1 interface and methods responsible for handling Bluetooth connections. --- plugins/bluez5.h | 2 ++ plugins/hfp_hf_bluez5.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/plugins/bluez5.h b/plugins/bluez5.h index e403b85..e832791 100644 --- a/plugins/bluez5.h +++ b/plugins/bluez5.h @@ -20,6 +20,8 @@ */ #define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1" +#define BLUEZ_ERROR_INTERFACE BLUEZ_SERVICE ".Error" #define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c index ff70481..0a63f14 100644 --- a/plugins/hfp_hf_bluez5.c +++ b/plugins/hfp_hf_bluez5.c @@ -26,6 +26,8 @@ #include <errno.h> #include <glib.h> +#include <gdbus.h> + #define OFONO_API_SUBJECT_TO_CHANGE #include <ofono/modem.h> #include <ofono/dbus.h> @@ -88,6 +90,59 @@ static struct ofono_modem_driver hfp_driver = { .post_sim = hfp_post_sim, }; +static DBusMessage *profile_new_connection(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler NewConnection"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_release(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler Release"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_cancel(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler Cancel"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_disconnection(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler RequestDisconnection"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static const GDBusMethodTable profile_methods[] = { + { GDBUS_ASYNC_METHOD("NewConnection", + GDBUS_ARGS({ "device", "o"}, { "fd", "h"}, + { "fd_properties", "a{sv}" }), + NULL, profile_new_connection) }, + { GDBUS_METHOD("Release", NULL, NULL, profile_release) }, + { GDBUS_METHOD("Cancel", NULL, NULL, profile_cancel) }, + { GDBUS_METHOD("RequestDisconnection", + GDBUS_ARGS({"device", "o"}), NULL, + profile_disconnection) }, + { } +}; + static int hfp_init(void) { DBusConnection *conn = ofono_dbus_get_connection(); @@ -96,13 +151,28 @@ static int hfp_init(void) if (DBUS_TYPE_UNIX_FD < 0) return -EBADF; + /* Registers External Profile handler */ + if (!g_dbus_register_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE, + profile_methods, NULL, + NULL, NULL, NULL)) { + ofono_error("Register Profile interface failed: %s", + HFP_EXT_PROFILE_PATH); + return -EIO; + } + err = ofono_modem_driver_register(&hfp_driver); - if (err < 0) + if (err < 0) { + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); return err; + } err = bluetooth_register_profile(conn, HFP_HS_UUID, "hfp_hf", HFP_EXT_PROFILE_PATH); if (err < 0) { + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); ofono_modem_driver_unregister(&hfp_driver); return err; } @@ -115,6 +185,8 @@ static void hfp_exit(void) DBusConnection *conn = ofono_dbus_get_connection(); bluetooth_unregister_profile(conn, HFP_EXT_PROFILE_PATH); + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); ofono_modem_driver_unregister(&hfp_driver); } -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v0 0/6] HFP HF: External Profile 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi ` (5 preceding siblings ...) 2013-01-10 14:44 ` [PATCH v0 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi @ 2013-01-11 9:27 ` Mikel Astiz 2013-01-11 14:26 ` Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi 7 siblings, 1 reply; 26+ messages in thread From: Mikel Astiz @ 2013-01-11 9:27 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 856 bytes --] Hi Claudio, On Thu, Jan 10, 2013 at 3:44 PM, Claudio Takahasi <claudio.takahasi@openbossa.org> wrote: > This is the first group of the patches which introduces the Handsfree > BlueZ external profile. > > The following patches contain only initial files and basic structures > for the HFP HF plugin (since files and plugins names are one of > controversial points). > > Remaining HFP HF patches: > git://git.infradead.org/users/cktakahasi/ofono.git HF-20130109 Regarding these remaining patches, I know it's WIP but just to make sure, please consider the latest Media API changes introduced by the BlueZ patchset "Media API clarifications": 1. Return org.bluez.Error.NotAvailable if TryAcquire() fails because SCO is down. 2. Add SpeakerGain/MicrophoneGain properties to the transport, and note that they are uint8. Cheers, Mikel ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v0 0/6] HFP HF: External Profile 2013-01-11 9:27 ` [PATCH v0 0/6] HFP HF: External Profile Mikel Astiz @ 2013-01-11 14:26 ` Claudio Takahasi 2013-01-11 16:05 ` Mikel Astiz 0 siblings, 1 reply; 26+ messages in thread From: Claudio Takahasi @ 2013-01-11 14:26 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 728 bytes --] Hi Mikel: > > Remaining HFP HF patches: > > git://git.infradead.org/users/cktakahasi/ofono.git HF-20130109 > > Regarding these remaining patches, I know it's WIP but just to make > sure, please consider the latest Media API changes introduced by the > BlueZ patchset "Media API clarifications": > 1. Return org.bluez.Error.NotAvailable if TryAcquire() fails because > SCO is down. Fixed! I think we should add InProgress error to avoid the same "owner" to call Acquire(or TryAcquire) for a previously "acquired" fd without calling Release. Do you agree? > 2. Add SpeakerGain/MicrophoneGain properties to the transport, and > note that they are uint8. ok. We gonna investigate it. Regards, Claudio ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v0 0/6] HFP HF: External Profile 2013-01-11 14:26 ` Claudio Takahasi @ 2013-01-11 16:05 ` Mikel Astiz 0 siblings, 0 replies; 26+ messages in thread From: Mikel Astiz @ 2013-01-11 16:05 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1190 bytes --] Hi Claudio, On Fri, Jan 11, 2013 at 3:26 PM, Claudio Takahasi <claudio.takahasi@openbossa.org> wrote: > Hi Mikel: > >> > Remaining HFP HF patches: >> > git://git.infradead.org/users/cktakahasi/ofono.git HF-20130109 >> >> Regarding these remaining patches, I know it's WIP but just to make >> sure, please consider the latest Media API changes introduced by the >> BlueZ patchset "Media API clarifications": >> 1. Return org.bluez.Error.NotAvailable if TryAcquire() fails because >> SCO is down. > > Fixed! > > I think we should add InProgress error to avoid the same "owner" to > call Acquire(or TryAcquire) for a previously "acquired" fd without > calling Release. > Do you agree? I can't imagine any usage scenario where this is relevant: the client should be aware of having acquired the transport before, so I don't see the interest of defining a specific error for such a case. > >> 2. Add SpeakerGain/MicrophoneGain properties to the transport, and >> note that they are uint8. > > ok. We gonna investigate it. I'll send the updated PulseAudio patches early next week. Please note that the last RFC v0 I sent is not up-to-date. Cheers, Mikel ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v1 0/6] HFP HF: External Profile 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi ` (6 preceding siblings ...) 2013-01-11 9:27 ` [PATCH v0 0/6] HFP HF: External Profile Mikel Astiz @ 2013-01-15 18:24 ` Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi ` (6 more replies) 7 siblings, 7 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-15 18:24 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1895 bytes --] This is the first group of the patches which introduces the Handsfree BlueZ external profile. The following patches contain only initial files and basic structures for the HFP HF plugin (since files and plugins names are one of the controversial points). Remaining HFP HF patches: git://git.infradead.org/users/cktakahasi/ofono.git HF-20130115 Changes from v0: * Append BlueZ version to hfp_hf* files * --enable-bluez4 configure option Claudio Takahasi (6): Makefile: Add configure option for BlueZ 4 and 5 bluetooth: Add versioning information to BlueZ plugins bluetooth: Initial files for BlueZ 5 hfp_hf: Add initial file for external HFP hfp_hf: Add hfp_driver hfp_hf: Add BlueZ Profile handler Makefile.am | 30 +- configure.ac | 24 +- dundee/bluetooth.c | 2 +- plugins/bluetooth.c | 989 ------------------------------------------------ plugins/bluetooth.h | 84 ---- plugins/bluez4.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++ plugins/bluez4.h | 84 ++++ plugins/bluez5.c | 145 +++++++ plugins/bluez5.h | 31 ++ plugins/dun_gw.c | 2 +- plugins/hfp_ag.c | 2 +- plugins/hfp_hf.c | 552 --------------------------- plugins/hfp_hf_bluez4.c | 552 +++++++++++++++++++++++++++ plugins/hfp_hf_bluez5.c | 194 ++++++++++ plugins/sap.c | 2 +- plugins/telit.c | 2 +- 16 files changed, 2036 insertions(+), 1648 deletions(-) delete mode 100644 plugins/bluetooth.c delete mode 100644 plugins/bluetooth.h create mode 100644 plugins/bluez4.c create mode 100644 plugins/bluez4.h create mode 100644 plugins/bluez5.c create mode 100644 plugins/bluez5.h delete mode 100644 plugins/hfp_hf.c create mode 100644 plugins/hfp_hf_bluez4.c create mode 100644 plugins/hfp_hf_bluez5.c -- 1.7.11.7 ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v1 1/6] Makefile: Add configure option for BlueZ 4 and 5 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi @ 2013-01-15 18:24 ` Claudio Takahasi 2013-01-15 19:01 ` Marcel Holtmann 2013-01-15 18:24 ` [PATCH v1 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi ` (5 subsequent siblings) 6 siblings, 1 reply; 26+ messages in thread From: Claudio Takahasi @ 2013-01-15 18:24 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2460 bytes --] BlueZ 5 is the default option. If --enable-bluez4 is provided, oFono plugins based on BlueZ 4 are enabled prior to BlueZ 5. --disable-bluetooth configure option disables BlueZ 5 and BlueZ 4 plugins. --- Makefile.am | 4 +++- configure.ac | 24 ++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0d2ba9f..811a3f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -407,7 +407,7 @@ builtin_sources += plugins/samsung.c builtin_modules += sim900 builtin_sources += plugins/sim900.c -if BLUETOOTH +if BLUEZ4 builtin_modules += bluetooth builtin_sources += plugins/bluetooth.c plugins/bluetooth.h @@ -742,6 +742,7 @@ tools_stktest_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ endif endif +if BLUEZ4 if DUNDEE sbin_PROGRAMS += dundee/dundee @@ -759,6 +760,7 @@ if SYSTEMD systemdunit_DATA += dundee/dundee.service endif endif +endif endif diff --git a/configure.ac b/configure.ac index 450352b..47b0600 100644 --- a/configure.ac +++ b/configure.ac @@ -173,15 +173,23 @@ AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem], AM_CONDITIONAL(QMIMODEM, test "${enable_qmimodem}" != "no") AC_ARG_ENABLE(bluetooth, AC_HELP_STRING([--disable-bluetooth], - [disable Bluetooth modem support]), - [enable_bluetooth=${enableval}]) -if (test "${enable_bluetooth}" != "no"); then - PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99, dummy=yes, - AC_MSG_ERROR(Bluetooth library >= 4.99 is required)) + [disable BlueZ 4 and BlueZ 5 plugins support]), + [enable_bluez5=${enableval}]) + +AC_ARG_ENABLE(bluez4, AC_HELP_STRING([--enable-bluez4], + [enable BlueZ 4 plugins support prior to BlueZ 5]), + [enable_bluez4=${enableval}]) + +if (test "${enable_bluez4}" = "yes"); then + PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99 bluez < 5, + enable_bluez4=yes enable_bluez5=no, + AC_MSG_ERROR(Bluetooth library >= 4.99 and < 5 is required)) + AC_SUBST(BLUEZ_CFLAGS) + AC_SUBST(BLUEZ_LIBS) fi -AC_SUBST(BLUEZ_CFLAGS) -AC_SUBST(BLUEZ_LIBS) -AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no") + +AM_CONDITIONAL(BLUEZ4, test "${enable_bluez4}" = "yes") +AM_CONDITIONAL(BLUEZ5, test "${enable_bluez5}" != "no" && test "${enable_bluez4}" != "yes") AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE], [location of provision database]), [path_provisiondb=${withval}]) -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v1 1/6] Makefile: Add configure option for BlueZ 4 and 5 2013-01-15 18:24 ` [PATCH v1 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi @ 2013-01-15 19:01 ` Marcel Holtmann 0 siblings, 0 replies; 26+ messages in thread From: Marcel Holtmann @ 2013-01-15 19:01 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2627 bytes --] Hi Claudio, > BlueZ 5 is the default option. If --enable-bluez4 is provided, oFono > plugins based on BlueZ 4 are enabled prior to BlueZ 5. > --disable-bluetooth configure option disables BlueZ 5 and BlueZ 4 > plugins. > --- > Makefile.am | 4 +++- > configure.ac | 24 ++++++++++++++++-------- > 2 files changed, 19 insertions(+), 9 deletions(-) > > diff --git a/Makefile.am b/Makefile.am > index 0d2ba9f..811a3f5 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -407,7 +407,7 @@ builtin_sources += plugins/samsung.c > builtin_modules += sim900 > builtin_sources += plugins/sim900.c > > -if BLUETOOTH > +if BLUEZ4 > builtin_modules += bluetooth > builtin_sources += plugins/bluetooth.c plugins/bluetooth.h > > @@ -742,6 +742,7 @@ tools_stktest_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ > endif > endif > > +if BLUEZ4 > if DUNDEE > sbin_PROGRAMS += dundee/dundee > > @@ -759,6 +760,7 @@ if SYSTEMD > systemdunit_DATA += dundee/dundee.service > endif > endif > +endif > > endif > > diff --git a/configure.ac b/configure.ac > index 450352b..47b0600 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -173,15 +173,23 @@ AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem], > AM_CONDITIONAL(QMIMODEM, test "${enable_qmimodem}" != "no") > > AC_ARG_ENABLE(bluetooth, AC_HELP_STRING([--disable-bluetooth], > - [disable Bluetooth modem support]), > - [enable_bluetooth=${enableval}]) > -if (test "${enable_bluetooth}" != "no"); then > - PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99, dummy=yes, > - AC_MSG_ERROR(Bluetooth library >= 4.99 is required)) > + [disable BlueZ 4 and BlueZ 5 plugins support]), > + [enable_bluez5=${enableval}]) > + > +AC_ARG_ENABLE(bluez4, AC_HELP_STRING([--enable-bluez4], > + [enable BlueZ 4 plugins support prior to BlueZ 5]), > + [enable_bluez4=${enableval}]) > + > +if (test "${enable_bluez4}" = "yes"); then > + PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99 bluez < 5, > + enable_bluez4=yes enable_bluez5=no, > + AC_MSG_ERROR(Bluetooth library >= 4.99 and < 5 is required)) > + AC_SUBST(BLUEZ_CFLAGS) > + AC_SUBST(BLUEZ_LIBS) > fi > -AC_SUBST(BLUEZ_CFLAGS) > -AC_SUBST(BLUEZ_LIBS) > -AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no") > + > +AM_CONDITIONAL(BLUEZ4, test "${enable_bluez4}" = "yes") > +AM_CONDITIONAL(BLUEZ5, test "${enable_bluez5}" != "no" && test "${enable_bluez4}" != "yes") can we keep BLUETOOTH conditional for overall Bluetooth enabled/disabled and just make BLUEZ4 the if-else statement for selecting which one. Regards Marcel ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v1 2/6] bluetooth: Add versioning information to BlueZ plugins 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi @ 2013-01-15 18:24 ` Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi ` (4 subsequent siblings) 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-15 18:24 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 91571 bytes --] As BlueZ 5 introduced backwards incompatible changes, and we want to keep support for BlueZ 4 based plugins for some time, we need to separate the plugins that are based on BlueZ 4 from the ones based on BlueZ 5. The HFP HF plugin is renamed to hfp_hf_bluez4 to make it easy to add a HFP HF that talks to BlueZ 5. --- Makefile.am | 18 +- dundee/bluetooth.c | 2 +- plugins/bluetooth.c | 989 ------------------------------------------------ plugins/bluetooth.h | 84 ---- plugins/bluez4.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++ plugins/bluez4.h | 84 ++++ plugins/dun_gw.c | 2 +- plugins/hfp_ag.c | 2 +- plugins/hfp_hf.c | 552 --------------------------- plugins/hfp_hf_bluez4.c | 552 +++++++++++++++++++++++++++ plugins/sap.c | 2 +- plugins/telit.c | 2 +- 12 files changed, 1639 insertions(+), 1639 deletions(-) delete mode 100644 plugins/bluetooth.c delete mode 100644 plugins/bluetooth.h create mode 100644 plugins/bluez4.c create mode 100644 plugins/bluez4.h delete mode 100644 plugins/hfp_hf.c create mode 100644 plugins/hfp_hf_bluez4.c diff --git a/Makefile.am b/Makefile.am index 811a3f5..85824be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -408,23 +408,23 @@ builtin_modules += sim900 builtin_sources += plugins/sim900.c if BLUEZ4 -builtin_modules += bluetooth -builtin_sources += plugins/bluetooth.c plugins/bluetooth.h +builtin_modules += bluez4 +builtin_sources += plugins/bluez4.c plugins/bluez4.h builtin_modules += telit -builtin_sources += plugins/telit.c plugins/bluetooth.h +builtin_sources += plugins/telit.c plugins/bluez4.h builtin_modules += sap -builtin_sources += plugins/sap.c plugins/bluetooth.h +builtin_sources += plugins/sap.c plugins/bluez4.h -builtin_modules += hfp -builtin_sources += plugins/hfp_hf.c plugins/bluetooth.h +builtin_modules += hfp_bluez4 +builtin_sources += plugins/hfp_hf_bluez4.c plugins/bluez4.h builtin_modules += hfp_ag -builtin_sources += plugins/hfp_ag.c plugins/bluetooth.h +builtin_sources += plugins/hfp_ag.c plugins/bluez4.h builtin_modules += dun_gw -builtin_sources += plugins/dun_gw.c plugins/bluetooth.h +builtin_sources += plugins/dun_gw.c plugins/bluez4.h builtin_modules += connman builtin_sources += plugins/connman.c @@ -747,7 +747,7 @@ if DUNDEE sbin_PROGRAMS += dundee/dundee dundee_dundee_SOURCES = $(gdbus_sources) $(gatchat_sources) $(btio_sources) \ - src/log.c src/dbus.c plugins/bluetooth.c \ + src/log.c src/dbus.c plugins/bluez4.c \ dundee/dundee.h dundee/main.c dundee/dbus.c \ dundee/manager.c dundee/device.c dundee/bluetooth.c diff --git a/dundee/bluetooth.c b/dundee/bluetooth.c index 9ddc72c..58355d3 100644 --- a/dundee/bluetooth.c +++ b/dundee/bluetooth.c @@ -32,7 +32,7 @@ #include <glib.h> -#include "plugins/bluetooth.h" +#include "plugins/bluez4.h" #include "dundee.h" diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c deleted file mode 100644 index 5d28530..0000000 --- a/plugins/bluetooth.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. - * Copyright (C) 2010 ProFUSION embedded systems - * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> - * - * 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 <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <glib.h> -#include <gdbus.h> - -#define OFONO_API_SUBJECT_TO_CHANGE -#include <ofono/plugin.h> -#include <ofono/log.h> - -#include <btio.h> -#include "bluetooth.h" - -static DBusConnection *connection; -static GHashTable *uuid_hash = NULL; -static GHashTable *adapter_address_hash = NULL; -static gint bluetooth_refcount; -static GSList *server_list = NULL; -static const char *adapter_any_name = "any"; -static char *adapter_any_path; - -#define TIMEOUT 60 /* Timeout for user response (seconds) */ - -struct server { - guint8 channel; - char *sdp_record; - guint32 handle; - GIOChannel *io; - ConnectFunc connect_cb; - gpointer user_data; -}; - -struct cb_data { - struct server *server; - char *path; - guint source; - GIOChannel *io; -}; - -void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, - char *buf, int size) -{ - int i, j; - - for (i = 0, j = 0; adapter_addr[j] && i < size - 1; j++) - if (adapter_addr[j] >= '0' && adapter_addr[j] <= '9') - buf[i++] = adapter_addr[j]; - else if (adapter_addr[j] >= 'A' && adapter_addr[j] <= 'F') - buf[i++] = adapter_addr[j]; - - if (i < size - 1) - buf[i++] = '_'; - - for (j = 0; dev_addr[j] && i < size - 1; j++) - if (dev_addr[j] >= '0' && dev_addr[j] <= '9') - buf[i++] = dev_addr[j]; - else if (dev_addr[j] >= 'A' && dev_addr[j] <= 'F') - buf[i++] = dev_addr[j]; - - buf[i] = '\0'; -} - -int bluetooth_send_with_reply(const char *path, const char *interface, - const char *method, DBusPendingCall **call, - DBusPendingCallNotifyFunction cb, - void *user_data, DBusFreeFunction free_func, - int timeout, int type, ...) -{ - DBusMessage *msg; - DBusPendingCall *c; - va_list args; - int err; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, path, - interface, method); - if (msg == NULL) { - ofono_error("Unable to allocate new D-Bus %s message", method); - err = -ENOMEM; - goto fail; - } - - va_start(args, type); - - if (!dbus_message_append_args_valist(msg, type, args)) { - va_end(args); - err = -EIO; - goto fail; - } - - va_end(args); - - if (timeout > 0) - timeout *= 1000; - - if (!dbus_connection_send_with_reply(connection, msg, &c, timeout)) { - ofono_error("Sending %s failed", method); - err = -EIO; - goto fail; - } - - if (call != NULL) - *call = c; - - dbus_pending_call_set_notify(c, cb, user_data, free_func); - dbus_pending_call_unref(c); - - dbus_message_unref(msg); - - return 0; - -fail: - if (free_func && user_data) - free_func(user_data); - - if (msg) - dbus_message_unref(msg); - - return err; -} - -typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data); - -struct property_handler { - const char *property; - PropertyHandler callback; - gpointer user_data; -}; - -static gint property_handler_compare(gconstpointer a, gconstpointer b) -{ - const struct property_handler *handler = a; - const char *property = b; - - return strcmp(handler->property, property); -} - -void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...) -{ - va_list args; - GSList *prop_handlers = NULL; - DBusMessageIter array, dict; - - va_start(args, property); - - while (property != NULL) { - struct property_handler *handler = - g_new0(struct property_handler, 1); - - handler->property = property; - handler->callback = va_arg(args, PropertyHandler); - handler->user_data = va_arg(args, gpointer); - - property = va_arg(args, const char *); - - prop_handlers = g_slist_prepend(prop_handlers, handler); - } - - va_end(args); - - if (dbus_message_iter_init(reply, &array) == FALSE) - goto done; - - if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY) - goto done; - - dbus_message_iter_recurse(&array, &dict); - - while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { - DBusMessageIter entry, value; - const char *key; - GSList *l; - - dbus_message_iter_recurse(&dict, &entry); - - if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) - goto done; - - dbus_message_iter_get_basic(&entry, &key); - - dbus_message_iter_next(&entry); - - if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) - goto done; - - dbus_message_iter_recurse(&entry, &value); - - l = g_slist_find_custom(prop_handlers, key, - property_handler_compare); - - if (l) { - struct property_handler *handler = l->data; - - handler->callback(&value, handler->user_data); - } - - dbus_message_iter_next(&dict); - } - -done: - g_slist_foreach(prop_handlers, (GFunc) g_free, NULL); - g_slist_free(prop_handlers); -} - -static void parse_uuids(DBusMessageIter *array, gpointer user_data) -{ - GSList **uuids = user_data; - DBusMessageIter value; - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) { - const char *uuid; - - dbus_message_iter_get_basic(&value, &uuid); - - *uuids = g_slist_prepend(*uuids, (char *) uuid); - - dbus_message_iter_next(&value); - } -} - -static void parse_string(DBusMessageIter *iter, gpointer user_data) -{ - char **str = user_data; - int arg_type = dbus_message_iter_get_arg_type(iter); - - if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING) - return; - - dbus_message_iter_get_basic(iter, str); -} - -static void bluetooth_probe(GSList *uuids, const char *path, - const char *device, const char *adapter, - const char *alias) -{ - for (; uuids; uuids = uuids->next) { - struct bluetooth_profile *driver; - const char *uuid = uuids->data; - int err; - - driver = g_hash_table_lookup(uuid_hash, uuid); - if (driver == NULL) - continue; - - err = driver->probe(path, device, adapter, alias); - if (err == 0 || err == -EALREADY) - continue; - - ofono_error("%s probe: %s (%d)", driver->name, strerror(-err), - -err); - } -} - -static void device_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply; - const char *path = user_data; - const char *adapter = NULL; - const char *adapter_addr = NULL; - const char *device_addr = NULL; - const char *alias = NULL; - struct DBusError derr; - GSList *uuids = NULL; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Device.GetProperties replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, "UUIDs", parse_uuids, &uuids, - "Adapter", parse_string, &adapter, - "Address", parse_string, &device_addr, - "Alias", parse_string, &alias, NULL); - - if (adapter) - adapter_addr = g_hash_table_lookup(adapter_address_hash, - adapter); - - if (!device_addr || !adapter_addr) - goto done; - - bluetooth_probe(uuids, path, device_addr, adapter_addr, alias); - -done: - g_slist_free(uuids); - dbus_message_unref(reply); -} - -static void parse_devices(DBusMessageIter *array, gpointer user_data) -{ - DBusMessageIter value; - GSList **device_list = user_data; - - DBG(""); - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) - == DBUS_TYPE_OBJECT_PATH) { - const char *path; - - dbus_message_iter_get_basic(&value, &path); - - *device_list = g_slist_prepend(*device_list, (gpointer) path); - - dbus_message_iter_next(&value); - } -} - -static gboolean property_changed(DBusConnection *conn, DBusMessage *msg, - void *user_data) -{ - const char *property; - DBusMessageIter iter; - - dbus_message_iter_init(msg, &iter); - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return FALSE; - - dbus_message_iter_get_basic(&iter, &property); - if (g_str_equal(property, "UUIDs") == TRUE) { - GSList *uuids = NULL; - const char *path = dbus_message_get_path(msg); - DBusMessageIter variant; - - if (!dbus_message_iter_next(&iter)) - return FALSE; - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - return FALSE; - - dbus_message_iter_recurse(&iter, &variant); - - parse_uuids(&variant, &uuids); - - /* We need the full set of properties to be able to create - * the modem properly, including Adapter and Alias, so - * refetch everything again - */ - if (uuids) - bluetooth_send_with_reply(path, BLUEZ_DEVICE_INTERFACE, - "GetProperties", NULL, - device_properties_cb, g_strdup(path), - g_free, -1, DBUS_TYPE_INVALID); - } else if (g_str_equal(property, "Alias") == TRUE) { - const char *path = dbus_message_get_path(msg); - struct bluetooth_profile *profile; - const char *alias = NULL; - DBusMessageIter variant; - GHashTableIter hash_iter; - gpointer key, value; - - if (!dbus_message_iter_next(&iter)) - return FALSE; - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - return FALSE; - - dbus_message_iter_recurse(&iter, &variant); - - parse_string(&variant, &alias); - - g_hash_table_iter_init(&hash_iter, uuid_hash); - while (g_hash_table_iter_next(&hash_iter, &key, &value)) { - profile = value; - if (profile->set_alias) - profile->set_alias(path, alias); - } - } - - return TRUE; -} - -static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - const char *path = user_data; - DBusMessage *reply; - DBusError derr; - GSList *device_list = NULL; - GSList *l; - const char *addr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Adapter.GetProperties replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, - "Devices", parse_devices, &device_list, - "Address", parse_string, &addr, - NULL); - - DBG("Adapter Address: %s, Path: %s", addr, path); - g_hash_table_insert(adapter_address_hash, - g_strdup(path), g_strdup(addr)); - - for (l = device_list; l; l = l->next) { - const char *device = l->data; - - bluetooth_send_with_reply(device, BLUEZ_DEVICE_INTERFACE, - "GetProperties", NULL, - device_properties_cb, g_strdup(device), - g_free, -1, DBUS_TYPE_INVALID); - } - -done: - g_slist_free(device_list); - dbus_message_unref(reply); -} - -static void get_adapter_properties(const char *path, const char *handle, - gpointer user_data) -{ - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); -} - -static void remove_record(struct server *server) -{ - DBusMessage *msg; - - if (server->handle == 0) - return; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, adapter_any_path, - BLUEZ_SERVICE_INTERFACE, - "RemoveRecord"); - if (msg == NULL) { - ofono_error("Unable to allocate D-Bus RemoveRecord message"); - return; - } - - dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID); - g_dbus_send_message(connection, msg); - - ofono_info("Unregistered handle for channel %d: 0x%x", - server->channel, server->handle); -} - -static void cb_data_destroy(gpointer data) -{ - struct cb_data *cb_data = data; - - if (cb_data->source != 0) - g_source_remove(cb_data->source); - - g_free(cb_data->path); - g_free(cb_data); -} - -static void cancel_authorization(struct cb_data *user_data) -{ - DBusMessage *msg; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, user_data->path, - BLUEZ_SERVICE_INTERFACE, - "CancelAuthorization"); - - if (msg == NULL) { - ofono_error("Unable to allocate D-Bus CancelAuthorization" - " message"); - return; - } - - g_dbus_send_message(connection, msg); -} - -static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data) -{ - struct cb_data *cb_data = data; - - cancel_authorization(cb_data); - cb_data->source = 0; - - return FALSE; -} - -static void auth_cb(DBusPendingCall *call, gpointer user_data) -{ - struct cb_data *cb_data = user_data; - struct server *server = cb_data->server; - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - GError *err = NULL; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("RequestAuthorization error: %s, %s", - derr.name, derr.message); - - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) - cancel_authorization(cb_data); - - dbus_error_free(&derr); - } else { - ofono_info("RequestAuthorization succeeded"); - - if (!bt_io_accept(cb_data->io, server->connect_cb, - server->user_data, NULL, &err)) { - ofono_error("%s", err->message); - g_error_free(err); - } - } - - dbus_message_unref(reply); -} - -static void new_connection(GIOChannel *io, gpointer user_data) -{ - struct server *server = user_data; - struct cb_data *cbd; - const char *addr; - GError *err = NULL; - char laddress[18], raddress[18]; - guint8 channel; - GHashTableIter iter; - gpointer key, value; - const char *path; - - bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE, laddress, - BT_IO_OPT_DEST, raddress, - BT_IO_OPT_CHANNEL, &channel, - BT_IO_OPT_INVALID); - if (err) { - ofono_error("%s", err->message); - g_error_free(err); - return; - } - - ofono_info("New connection for %s on channel %u from: %s,", laddress, - channel, raddress); - - path = NULL; - g_hash_table_iter_init(&iter, adapter_address_hash); - - while (g_hash_table_iter_next(&iter, &key, &value)) { - if (g_str_equal(laddress, value) == TRUE) { - path = key; - break; - } - } - - if (path == NULL) - return; - - cbd = g_try_new0(struct cb_data, 1); - if (cbd == NULL) { - ofono_error("Unable to allocate client cb_data structure"); - return; - } - - cbd->path = g_strdup(path); - cbd->server = server; - cbd->io = io; - - addr = raddress; - - if (bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, - "RequestAuthorization", NULL, - auth_cb, cbd, cb_data_destroy, - TIMEOUT, DBUS_TYPE_STRING, &addr, - DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID) < 0) { - ofono_error("Request Bluetooth authorization failed"); - return; - } - - ofono_info("RequestAuthorization(%s, 0x%x)", raddress, server->handle); - - cbd->source = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, - client_event, cbd); -} - -static void remove_service_handle(gpointer data, gpointer user_data) -{ - struct server *server = data; - - server->handle = 0; -} - -static void add_record_cb(DBusPendingCall *call, gpointer user_data) -{ - struct server *server = user_data; - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Replied with an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID); - - ofono_info("Registered handle for channel %d: 0x%x", - server->channel, server->handle); - -done: - dbus_message_unref(reply); -} - -static void add_record(gpointer data, gpointer user_data) -{ - struct server *server = data; - - if (server->sdp_record == NULL) - return; - - bluetooth_send_with_reply(adapter_any_path, - BLUEZ_SERVICE_INTERFACE, "AddRecord", - NULL, add_record_cb, server, NULL, -1, - DBUS_TYPE_STRING, &server->sdp_record, - DBUS_TYPE_INVALID); -} - -static void find_adapter_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - const char *path; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Replied with an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - - adapter_any_path = g_strdup(path); - - g_slist_foreach(server_list, (GFunc) add_record, NULL); - -done: - dbus_message_unref(reply); -} - -static gboolean adapter_added(DBusConnection *conn, DBusMessage *message, - void *user_data) -{ - const char *path; - - dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); - - return TRUE; -} - -static void bluetooth_remove(gpointer key, gpointer value, gpointer user_data) -{ - struct bluetooth_profile *profile = value; - - profile->remove(user_data); -} - -static gboolean adapter_removed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path; - - if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) - return FALSE; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); - g_hash_table_remove(adapter_address_hash, path); - - return TRUE; -} - -static gboolean device_removed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path; - - if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) - return FALSE; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); - - return TRUE; -} - -static void parse_adapters(DBusMessageIter *array, gpointer user_data) -{ - DBusMessageIter value; - - DBG(""); - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) - == DBUS_TYPE_OBJECT_PATH) { - const char *path; - - dbus_message_iter_get_basic(&value, &path); - - DBG("Calling GetProperties on %s", path); - - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); - - dbus_message_iter_next(&value); - } -} - -static void manager_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Manager.GetProperties() replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, "Adapters", parse_adapters, NULL, - NULL); - -done: - dbus_message_unref(reply); -} - -static void bluetooth_connect(DBusConnection *conn, void *user_data) -{ - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties", - NULL, manager_properties_cb, NULL, NULL, -1, - DBUS_TYPE_INVALID); - - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "FindAdapter", - NULL, find_adapter_cb, NULL, NULL, -1, - DBUS_TYPE_STRING, &adapter_any_name, - DBUS_TYPE_INVALID); -} - -static void bluetooth_disconnect(DBusConnection *conn, void *user_data) -{ - if (uuid_hash == NULL) - return; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, NULL); - - g_slist_foreach(server_list, (GFunc) remove_service_handle, NULL); -} - -static guint bluetooth_watch; -static guint adapter_added_watch; -static guint adapter_removed_watch; -static guint device_removed_watch; -static guint property_watch; - -static void bluetooth_ref(void) -{ - if (bluetooth_refcount > 0) - goto increment; - - connection = ofono_dbus_get_connection(); - - bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE, - bluetooth_connect, - bluetooth_disconnect, NULL, NULL); - - adapter_added_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, - NULL, BLUEZ_MANAGER_INTERFACE, - "AdapterAdded", - adapter_added, NULL, NULL); - - adapter_removed_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_MANAGER_INTERFACE, - "AdapterRemoved", - adapter_removed, NULL, NULL); - - device_removed_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_ADAPTER_INTERFACE, - "DeviceRemoved", - device_removed, NULL, NULL); - - property_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_DEVICE_INTERFACE, - "PropertyChanged", - property_changed, NULL, NULL); - - if (bluetooth_watch == 0 || adapter_added_watch == 0 || - adapter_removed_watch == 0 || property_watch == 0) { - goto remove; - } - - uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, NULL); - - adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - -increment: - g_atomic_int_inc(&bluetooth_refcount); - - return; - -remove: - g_dbus_remove_watch(connection, bluetooth_watch); - g_dbus_remove_watch(connection, adapter_added_watch); - g_dbus_remove_watch(connection, adapter_removed_watch); - g_dbus_remove_watch(connection, property_watch); -} - -static void bluetooth_unref(void) -{ - if (g_atomic_int_dec_and_test(&bluetooth_refcount) == FALSE) - return; - - g_free(adapter_any_path); - adapter_any_path = NULL; - - g_dbus_remove_watch(connection, bluetooth_watch); - g_dbus_remove_watch(connection, adapter_added_watch); - g_dbus_remove_watch(connection, adapter_removed_watch); - g_dbus_remove_watch(connection, property_watch); - - g_hash_table_destroy(uuid_hash); - g_hash_table_destroy(adapter_address_hash); -} - -void bluetooth_get_properties() -{ - g_hash_table_foreach(adapter_address_hash, - (GHFunc) get_adapter_properties, NULL); -} - -int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile) -{ - bluetooth_ref(); - - g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); - - g_hash_table_foreach(adapter_address_hash, - (GHFunc) get_adapter_properties, NULL); - - return 0; -} - -void bluetooth_unregister_uuid(const char *uuid) -{ - g_hash_table_remove(uuid_hash, uuid); - - bluetooth_unref(); -} - -struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, - ConnectFunc cb, gpointer user_data) -{ - struct server *server; - GError *err = NULL; - - server = g_try_new0(struct server, 1); - if (!server) - return NULL; - - server->channel = channel; - - server->io = bt_io_listen(BT_IO_RFCOMM, NULL, new_connection, - server, NULL, &err, - BT_IO_OPT_CHANNEL, server->channel, - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, - BT_IO_OPT_INVALID); - if (server->io == NULL) { - g_error_free(err); - g_free(server); - return NULL; - } - - bluetooth_ref(); - - if (sdp_record != NULL) - server->sdp_record = g_strdup(sdp_record); - - server->connect_cb = cb; - server->user_data = user_data; - - server_list = g_slist_prepend(server_list, server); - - if (adapter_any_path != NULL) - add_record(server, NULL); - - return server; -} - -void bluetooth_unregister_server(struct server *server) -{ - server_list = g_slist_remove(server_list, server); - - remove_record(server); - - if (server->io != NULL) { - g_io_channel_shutdown(server->io, TRUE, NULL); - g_io_channel_unref(server->io); - server->io = NULL; - } - - g_free(server->sdp_record); - g_free(server); - - bluetooth_unref(); -} - -OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION, - OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluetooth.h b/plugins/bluetooth.h deleted file mode 100644 index 4fc16ad..0000000 --- a/plugins/bluetooth.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> - * - * 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 - * - */ - -#include <ofono/modem.h> -#include <ofono/dbus.h> - -#define BLUEZ_SERVICE "org.bluez" -#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager" -#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter" -#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device" -#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service" -#define BLUEZ_SERIAL_INTERFACE BLUEZ_SERVICE ".Serial" - -#define DBUS_TIMEOUT 15 - -#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" -#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" -#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" -#define SAP_UUID "0000112d-0000-1000-8000-00805f9b34fb" - -struct bluetooth_profile { - const char *name; - int (*probe)(const char *device, const char *dev_addr, - const char *adapter_addr, const char *alias); - void (*remove)(const char *prefix); - void (*set_alias)(const char *device, const char *); -}; - -struct bluetooth_sap_driver { - const char *name; - int (*enable) (struct ofono_modem *modem, struct ofono_modem *sap_modem, - int bt_fd); - void (*pre_sim) (struct ofono_modem *modem); - void (*post_sim) (struct ofono_modem *modem); - void (*set_online) (struct ofono_modem *modem, ofono_bool_t online, - ofono_modem_online_cb_t cb, void *user_data); - void (*post_online) (struct ofono_modem *modem); - int (*disable) (struct ofono_modem *modem); -}; - -struct server; - -typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data); - -void bluetooth_get_properties(); -int bluetooth_register_uuid(const char *uuid, - struct bluetooth_profile *profile); -void bluetooth_unregister_uuid(const char *uuid); - -struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, - ConnectFunc cb, gpointer user_data); -void bluetooth_unregister_server(struct server *server); - -void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, - char *buf, int size); - -int bluetooth_send_with_reply(const char *path, const char *interface, - const char *method, DBusPendingCall **call, - DBusPendingCallNotifyFunction cb, - void *user_data, DBusFreeFunction free_func, - int timeout, int type, ...); -void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...); - -int bluetooth_sap_client_register(struct bluetooth_sap_driver *sap, - struct ofono_modem *modem); -void bluetooth_sap_client_unregister(struct ofono_modem *modem); diff --git a/plugins/bluez4.c b/plugins/bluez4.c new file mode 100644 index 0000000..6a29d9f --- /dev/null +++ b/plugins/bluez4.c @@ -0,0 +1,989 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2010 ProFUSION embedded systems + * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> + * + * 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 <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <glib.h> +#include <gdbus.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +#include <btio.h> +#include "bluez4.h" + +static DBusConnection *connection; +static GHashTable *uuid_hash = NULL; +static GHashTable *adapter_address_hash = NULL; +static gint bluetooth_refcount; +static GSList *server_list = NULL; +static const char *adapter_any_name = "any"; +static char *adapter_any_path; + +#define TIMEOUT 60 /* Timeout for user response (seconds) */ + +struct server { + guint8 channel; + char *sdp_record; + guint32 handle; + GIOChannel *io; + ConnectFunc connect_cb; + gpointer user_data; +}; + +struct cb_data { + struct server *server; + char *path; + guint source; + GIOChannel *io; +}; + +void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, + char *buf, int size) +{ + int i, j; + + for (i = 0, j = 0; adapter_addr[j] && i < size - 1; j++) + if (adapter_addr[j] >= '0' && adapter_addr[j] <= '9') + buf[i++] = adapter_addr[j]; + else if (adapter_addr[j] >= 'A' && adapter_addr[j] <= 'F') + buf[i++] = adapter_addr[j]; + + if (i < size - 1) + buf[i++] = '_'; + + for (j = 0; dev_addr[j] && i < size - 1; j++) + if (dev_addr[j] >= '0' && dev_addr[j] <= '9') + buf[i++] = dev_addr[j]; + else if (dev_addr[j] >= 'A' && dev_addr[j] <= 'F') + buf[i++] = dev_addr[j]; + + buf[i] = '\0'; +} + +int bluetooth_send_with_reply(const char *path, const char *interface, + const char *method, DBusPendingCall **call, + DBusPendingCallNotifyFunction cb, + void *user_data, DBusFreeFunction free_func, + int timeout, int type, ...) +{ + DBusMessage *msg; + DBusPendingCall *c; + va_list args; + int err; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, path, + interface, method); + if (msg == NULL) { + ofono_error("Unable to allocate new D-Bus %s message", method); + err = -ENOMEM; + goto fail; + } + + va_start(args, type); + + if (!dbus_message_append_args_valist(msg, type, args)) { + va_end(args); + err = -EIO; + goto fail; + } + + va_end(args); + + if (timeout > 0) + timeout *= 1000; + + if (!dbus_connection_send_with_reply(connection, msg, &c, timeout)) { + ofono_error("Sending %s failed", method); + err = -EIO; + goto fail; + } + + if (call != NULL) + *call = c; + + dbus_pending_call_set_notify(c, cb, user_data, free_func); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); + + return 0; + +fail: + if (free_func && user_data) + free_func(user_data); + + if (msg) + dbus_message_unref(msg); + + return err; +} + +typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data); + +struct property_handler { + const char *property; + PropertyHandler callback; + gpointer user_data; +}; + +static gint property_handler_compare(gconstpointer a, gconstpointer b) +{ + const struct property_handler *handler = a; + const char *property = b; + + return strcmp(handler->property, property); +} + +void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...) +{ + va_list args; + GSList *prop_handlers = NULL; + DBusMessageIter array, dict; + + va_start(args, property); + + while (property != NULL) { + struct property_handler *handler = + g_new0(struct property_handler, 1); + + handler->property = property; + handler->callback = va_arg(args, PropertyHandler); + handler->user_data = va_arg(args, gpointer); + + property = va_arg(args, const char *); + + prop_handlers = g_slist_prepend(prop_handlers, handler); + } + + va_end(args); + + if (dbus_message_iter_init(reply, &array) == FALSE) + goto done; + + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY) + goto done; + + dbus_message_iter_recurse(&array, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value; + const char *key; + GSList *l; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + goto done; + + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) + goto done; + + dbus_message_iter_recurse(&entry, &value); + + l = g_slist_find_custom(prop_handlers, key, + property_handler_compare); + + if (l) { + struct property_handler *handler = l->data; + + handler->callback(&value, handler->user_data); + } + + dbus_message_iter_next(&dict); + } + +done: + g_slist_foreach(prop_handlers, (GFunc) g_free, NULL); + g_slist_free(prop_handlers); +} + +static void parse_uuids(DBusMessageIter *array, gpointer user_data) +{ + GSList **uuids = user_data; + DBusMessageIter value; + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) { + const char *uuid; + + dbus_message_iter_get_basic(&value, &uuid); + + *uuids = g_slist_prepend(*uuids, (char *) uuid); + + dbus_message_iter_next(&value); + } +} + +static void parse_string(DBusMessageIter *iter, gpointer user_data) +{ + char **str = user_data; + int arg_type = dbus_message_iter_get_arg_type(iter); + + if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING) + return; + + dbus_message_iter_get_basic(iter, str); +} + +static void bluetooth_probe(GSList *uuids, const char *path, + const char *device, const char *adapter, + const char *alias) +{ + for (; uuids; uuids = uuids->next) { + struct bluetooth_profile *driver; + const char *uuid = uuids->data; + int err; + + driver = g_hash_table_lookup(uuid_hash, uuid); + if (driver == NULL) + continue; + + err = driver->probe(path, device, adapter, alias); + if (err == 0 || err == -EALREADY) + continue; + + ofono_error("%s probe: %s (%d)", driver->name, strerror(-err), + -err); + } +} + +static void device_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + const char *path = user_data; + const char *adapter = NULL; + const char *adapter_addr = NULL; + const char *device_addr = NULL; + const char *alias = NULL; + struct DBusError derr; + GSList *uuids = NULL; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Device.GetProperties replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, "UUIDs", parse_uuids, &uuids, + "Adapter", parse_string, &adapter, + "Address", parse_string, &device_addr, + "Alias", parse_string, &alias, NULL); + + if (adapter) + adapter_addr = g_hash_table_lookup(adapter_address_hash, + adapter); + + if (!device_addr || !adapter_addr) + goto done; + + bluetooth_probe(uuids, path, device_addr, adapter_addr, alias); + +done: + g_slist_free(uuids); + dbus_message_unref(reply); +} + +static void parse_devices(DBusMessageIter *array, gpointer user_data) +{ + DBusMessageIter value; + GSList **device_list = user_data; + + DBG(""); + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) + == DBUS_TYPE_OBJECT_PATH) { + const char *path; + + dbus_message_iter_get_basic(&value, &path); + + *device_list = g_slist_prepend(*device_list, (gpointer) path); + + dbus_message_iter_next(&value); + } +} + +static gboolean property_changed(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + const char *property; + DBusMessageIter iter; + + dbus_message_iter_init(msg, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return FALSE; + + dbus_message_iter_get_basic(&iter, &property); + if (g_str_equal(property, "UUIDs") == TRUE) { + GSList *uuids = NULL; + const char *path = dbus_message_get_path(msg); + DBusMessageIter variant; + + if (!dbus_message_iter_next(&iter)) + return FALSE; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return FALSE; + + dbus_message_iter_recurse(&iter, &variant); + + parse_uuids(&variant, &uuids); + + /* We need the full set of properties to be able to create + * the modem properly, including Adapter and Alias, so + * refetch everything again + */ + if (uuids) + bluetooth_send_with_reply(path, BLUEZ_DEVICE_INTERFACE, + "GetProperties", NULL, + device_properties_cb, g_strdup(path), + g_free, -1, DBUS_TYPE_INVALID); + } else if (g_str_equal(property, "Alias") == TRUE) { + const char *path = dbus_message_get_path(msg); + struct bluetooth_profile *profile; + const char *alias = NULL; + DBusMessageIter variant; + GHashTableIter hash_iter; + gpointer key, value; + + if (!dbus_message_iter_next(&iter)) + return FALSE; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return FALSE; + + dbus_message_iter_recurse(&iter, &variant); + + parse_string(&variant, &alias); + + g_hash_table_iter_init(&hash_iter, uuid_hash); + while (g_hash_table_iter_next(&hash_iter, &key, &value)) { + profile = value; + if (profile->set_alias) + profile->set_alias(path, alias); + } + } + + return TRUE; +} + +static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + const char *path = user_data; + DBusMessage *reply; + DBusError derr; + GSList *device_list = NULL; + GSList *l; + const char *addr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Adapter.GetProperties replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, + "Devices", parse_devices, &device_list, + "Address", parse_string, &addr, + NULL); + + DBG("Adapter Address: %s, Path: %s", addr, path); + g_hash_table_insert(adapter_address_hash, + g_strdup(path), g_strdup(addr)); + + for (l = device_list; l; l = l->next) { + const char *device = l->data; + + bluetooth_send_with_reply(device, BLUEZ_DEVICE_INTERFACE, + "GetProperties", NULL, + device_properties_cb, g_strdup(device), + g_free, -1, DBUS_TYPE_INVALID); + } + +done: + g_slist_free(device_list); + dbus_message_unref(reply); +} + +static void get_adapter_properties(const char *path, const char *handle, + gpointer user_data) +{ + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); +} + +static void remove_record(struct server *server) +{ + DBusMessage *msg; + + if (server->handle == 0) + return; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, adapter_any_path, + BLUEZ_SERVICE_INTERFACE, + "RemoveRecord"); + if (msg == NULL) { + ofono_error("Unable to allocate D-Bus RemoveRecord message"); + return; + } + + dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID); + g_dbus_send_message(connection, msg); + + ofono_info("Unregistered handle for channel %d: 0x%x", + server->channel, server->handle); +} + +static void cb_data_destroy(gpointer data) +{ + struct cb_data *cb_data = data; + + if (cb_data->source != 0) + g_source_remove(cb_data->source); + + g_free(cb_data->path); + g_free(cb_data); +} + +static void cancel_authorization(struct cb_data *user_data) +{ + DBusMessage *msg; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, user_data->path, + BLUEZ_SERVICE_INTERFACE, + "CancelAuthorization"); + + if (msg == NULL) { + ofono_error("Unable to allocate D-Bus CancelAuthorization" + " message"); + return; + } + + g_dbus_send_message(connection, msg); +} + +static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct cb_data *cb_data = data; + + cancel_authorization(cb_data); + cb_data->source = 0; + + return FALSE; +} + +static void auth_cb(DBusPendingCall *call, gpointer user_data) +{ + struct cb_data *cb_data = user_data; + struct server *server = cb_data->server; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + GError *err = NULL; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("RequestAuthorization error: %s, %s", + derr.name, derr.message); + + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) + cancel_authorization(cb_data); + + dbus_error_free(&derr); + } else { + ofono_info("RequestAuthorization succeeded"); + + if (!bt_io_accept(cb_data->io, server->connect_cb, + server->user_data, NULL, &err)) { + ofono_error("%s", err->message); + g_error_free(err); + } + } + + dbus_message_unref(reply); +} + +static void new_connection(GIOChannel *io, gpointer user_data) +{ + struct server *server = user_data; + struct cb_data *cbd; + const char *addr; + GError *err = NULL; + char laddress[18], raddress[18]; + guint8 channel; + GHashTableIter iter; + gpointer key, value; + const char *path; + + bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE, laddress, + BT_IO_OPT_DEST, raddress, + BT_IO_OPT_CHANNEL, &channel, + BT_IO_OPT_INVALID); + if (err) { + ofono_error("%s", err->message); + g_error_free(err); + return; + } + + ofono_info("New connection for %s on channel %u from: %s,", laddress, + channel, raddress); + + path = NULL; + g_hash_table_iter_init(&iter, adapter_address_hash); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + if (g_str_equal(laddress, value) == TRUE) { + path = key; + break; + } + } + + if (path == NULL) + return; + + cbd = g_try_new0(struct cb_data, 1); + if (cbd == NULL) { + ofono_error("Unable to allocate client cb_data structure"); + return; + } + + cbd->path = g_strdup(path); + cbd->server = server; + cbd->io = io; + + addr = raddress; + + if (bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, + "RequestAuthorization", NULL, + auth_cb, cbd, cb_data_destroy, + TIMEOUT, DBUS_TYPE_STRING, &addr, + DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID) < 0) { + ofono_error("Request Bluetooth authorization failed"); + return; + } + + ofono_info("RequestAuthorization(%s, 0x%x)", raddress, server->handle); + + cbd->source = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, + client_event, cbd); +} + +static void remove_service_handle(gpointer data, gpointer user_data) +{ + struct server *server = data; + + server->handle = 0; +} + +static void add_record_cb(DBusPendingCall *call, gpointer user_data) +{ + struct server *server = user_data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID); + + ofono_info("Registered handle for channel %d: 0x%x", + server->channel, server->handle); + +done: + dbus_message_unref(reply); +} + +static void add_record(gpointer data, gpointer user_data) +{ + struct server *server = data; + + if (server->sdp_record == NULL) + return; + + bluetooth_send_with_reply(adapter_any_path, + BLUEZ_SERVICE_INTERFACE, "AddRecord", + NULL, add_record_cb, server, NULL, -1, + DBUS_TYPE_STRING, &server->sdp_record, + DBUS_TYPE_INVALID); +} + +static void find_adapter_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + const char *path; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + adapter_any_path = g_strdup(path); + + g_slist_foreach(server_list, (GFunc) add_record, NULL); + +done: + dbus_message_unref(reply); +} + +static gboolean adapter_added(DBusConnection *conn, DBusMessage *message, + void *user_data) +{ + const char *path; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); + + return TRUE; +} + +static void bluetooth_remove(gpointer key, gpointer value, gpointer user_data) +{ + struct bluetooth_profile *profile = value; + + profile->remove(user_data); +} + +static gboolean adapter_removed(DBusConnection *conn, + DBusMessage *message, void *user_data) +{ + const char *path; + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID) == FALSE) + return FALSE; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); + g_hash_table_remove(adapter_address_hash, path); + + return TRUE; +} + +static gboolean device_removed(DBusConnection *conn, + DBusMessage *message, void *user_data) +{ + const char *path; + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID) == FALSE) + return FALSE; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); + + return TRUE; +} + +static void parse_adapters(DBusMessageIter *array, gpointer user_data) +{ + DBusMessageIter value; + + DBG(""); + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) + == DBUS_TYPE_OBJECT_PATH) { + const char *path; + + dbus_message_iter_get_basic(&value, &path); + + DBG("Calling GetProperties on %s", path); + + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); + + dbus_message_iter_next(&value); + } +} + +static void manager_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Manager.GetProperties() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, "Adapters", parse_adapters, NULL, + NULL); + +done: + dbus_message_unref(reply); +} + +static void bluetooth_connect(DBusConnection *conn, void *user_data) +{ + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties", + NULL, manager_properties_cb, NULL, NULL, -1, + DBUS_TYPE_INVALID); + + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "FindAdapter", + NULL, find_adapter_cb, NULL, NULL, -1, + DBUS_TYPE_STRING, &adapter_any_name, + DBUS_TYPE_INVALID); +} + +static void bluetooth_disconnect(DBusConnection *conn, void *user_data) +{ + if (uuid_hash == NULL) + return; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, NULL); + + g_slist_foreach(server_list, (GFunc) remove_service_handle, NULL); +} + +static guint bluetooth_watch; +static guint adapter_added_watch; +static guint adapter_removed_watch; +static guint device_removed_watch; +static guint property_watch; + +static void bluetooth_ref(void) +{ + if (bluetooth_refcount > 0) + goto increment; + + connection = ofono_dbus_get_connection(); + + bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE, + bluetooth_connect, + bluetooth_disconnect, NULL, NULL); + + adapter_added_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, + NULL, BLUEZ_MANAGER_INTERFACE, + "AdapterAdded", + adapter_added, NULL, NULL); + + adapter_removed_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_MANAGER_INTERFACE, + "AdapterRemoved", + adapter_removed, NULL, NULL); + + device_removed_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_ADAPTER_INTERFACE, + "DeviceRemoved", + device_removed, NULL, NULL); + + property_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_DEVICE_INTERFACE, + "PropertyChanged", + property_changed, NULL, NULL); + + if (bluetooth_watch == 0 || adapter_added_watch == 0 || + adapter_removed_watch == 0 || property_watch == 0) { + goto remove; + } + + uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); + + adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + +increment: + g_atomic_int_inc(&bluetooth_refcount); + + return; + +remove: + g_dbus_remove_watch(connection, bluetooth_watch); + g_dbus_remove_watch(connection, adapter_added_watch); + g_dbus_remove_watch(connection, adapter_removed_watch); + g_dbus_remove_watch(connection, property_watch); +} + +static void bluetooth_unref(void) +{ + if (g_atomic_int_dec_and_test(&bluetooth_refcount) == FALSE) + return; + + g_free(adapter_any_path); + adapter_any_path = NULL; + + g_dbus_remove_watch(connection, bluetooth_watch); + g_dbus_remove_watch(connection, adapter_added_watch); + g_dbus_remove_watch(connection, adapter_removed_watch); + g_dbus_remove_watch(connection, property_watch); + + g_hash_table_destroy(uuid_hash); + g_hash_table_destroy(adapter_address_hash); +} + +void bluetooth_get_properties() +{ + g_hash_table_foreach(adapter_address_hash, + (GHFunc) get_adapter_properties, NULL); +} + +int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile) +{ + bluetooth_ref(); + + g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); + + g_hash_table_foreach(adapter_address_hash, + (GHFunc) get_adapter_properties, NULL); + + return 0; +} + +void bluetooth_unregister_uuid(const char *uuid) +{ + g_hash_table_remove(uuid_hash, uuid); + + bluetooth_unref(); +} + +struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, + ConnectFunc cb, gpointer user_data) +{ + struct server *server; + GError *err = NULL; + + server = g_try_new0(struct server, 1); + if (!server) + return NULL; + + server->channel = channel; + + server->io = bt_io_listen(BT_IO_RFCOMM, NULL, new_connection, + server, NULL, &err, + BT_IO_OPT_CHANNEL, server->channel, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, + BT_IO_OPT_INVALID); + if (server->io == NULL) { + g_error_free(err); + g_free(server); + return NULL; + } + + bluetooth_ref(); + + if (sdp_record != NULL) + server->sdp_record = g_strdup(sdp_record); + + server->connect_cb = cb; + server->user_data = user_data; + + server_list = g_slist_prepend(server_list, server); + + if (adapter_any_path != NULL) + add_record(server, NULL); + + return server; +} + +void bluetooth_unregister_server(struct server *server) +{ + server_list = g_slist_remove(server_list, server); + + remove_record(server); + + if (server->io != NULL) { + g_io_channel_shutdown(server->io, TRUE, NULL); + g_io_channel_unref(server->io); + server->io = NULL; + } + + g_free(server->sdp_record); + g_free(server); + + bluetooth_unref(); +} + +OFONO_PLUGIN_DEFINE(bluez4, "Bluetooth Utils Plugins", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluez4.h b/plugins/bluez4.h new file mode 100644 index 0000000..4fc16ad --- /dev/null +++ b/plugins/bluez4.h @@ -0,0 +1,84 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> + * + * 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 + * + */ + +#include <ofono/modem.h> +#include <ofono/dbus.h> + +#define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager" +#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter" +#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device" +#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service" +#define BLUEZ_SERIAL_INTERFACE BLUEZ_SERVICE ".Serial" + +#define DBUS_TIMEOUT 15 + +#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" +#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" +#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" +#define SAP_UUID "0000112d-0000-1000-8000-00805f9b34fb" + +struct bluetooth_profile { + const char *name; + int (*probe)(const char *device, const char *dev_addr, + const char *adapter_addr, const char *alias); + void (*remove)(const char *prefix); + void (*set_alias)(const char *device, const char *); +}; + +struct bluetooth_sap_driver { + const char *name; + int (*enable) (struct ofono_modem *modem, struct ofono_modem *sap_modem, + int bt_fd); + void (*pre_sim) (struct ofono_modem *modem); + void (*post_sim) (struct ofono_modem *modem); + void (*set_online) (struct ofono_modem *modem, ofono_bool_t online, + ofono_modem_online_cb_t cb, void *user_data); + void (*post_online) (struct ofono_modem *modem); + int (*disable) (struct ofono_modem *modem); +}; + +struct server; + +typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data); + +void bluetooth_get_properties(); +int bluetooth_register_uuid(const char *uuid, + struct bluetooth_profile *profile); +void bluetooth_unregister_uuid(const char *uuid); + +struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, + ConnectFunc cb, gpointer user_data); +void bluetooth_unregister_server(struct server *server); + +void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, + char *buf, int size); + +int bluetooth_send_with_reply(const char *path, const char *interface, + const char *method, DBusPendingCall **call, + DBusPendingCallNotifyFunction cb, + void *user_data, DBusFreeFunction free_func, + int timeout, int type, ...); +void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...); + +int bluetooth_sap_client_register(struct bluetooth_sap_driver *sap, + struct ofono_modem *modem); +void bluetooth_sap_client_unregister(struct ofono_modem *modem); diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c index 75b62eb..fc8bde4 100644 --- a/plugins/dun_gw.c +++ b/plugins/dun_gw.c @@ -33,7 +33,7 @@ #include <ofono/modem.h> #include <gdbus.h> -#include "bluetooth.h" +#include "bluez4.h" #define DUN_GW_CHANNEL 1 diff --git a/plugins/hfp_ag.c b/plugins/hfp_ag.c index c2d1d30..12374ad 100644 --- a/plugins/hfp_ag.c +++ b/plugins/hfp_ag.c @@ -33,7 +33,7 @@ #include <ofono/modem.h> #include <gdbus.h> -#include "bluetooth.h" +#include "bluez4.h" #define HFP_AG_CHANNEL 13 diff --git a/plugins/hfp_hf.c b/plugins/hfp_hf.c deleted file mode 100644 index 7c500e3..0000000 --- a/plugins/hfp_hf.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. - * Copyright (C) 2010 ProFUSION embedded systems - * Copyright (C) 2011 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 <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <glib.h> -#include <gatchat.h> -#include <gattty.h> -#include <gdbus.h> -#include <ofono.h> - -#define OFONO_API_SUBJECT_TO_CHANGE -#include <ofono/plugin.h> -#include <ofono/log.h> -#include <ofono/modem.h> -#include <ofono/devinfo.h> -#include <ofono/netreg.h> -#include <ofono/voicecall.h> -#include <ofono/call-volume.h> -#include <ofono/handsfree.h> - -#include <drivers/hfpmodem/slc.h> - -#include "bluetooth.h" - -#define BLUEZ_GATEWAY_INTERFACE BLUEZ_SERVICE ".HandsfreeGateway" - -#define HFP_AGENT_INTERFACE "org.bluez.HandsfreeAgent" -#define HFP_AGENT_ERROR_INTERFACE "org.bluez.Error" - -#ifndef DBUS_TYPE_UNIX_FD -#define DBUS_TYPE_UNIX_FD -1 -#endif - -static DBusConnection *connection; -static GHashTable *modem_hash = NULL; - -struct hfp_data { - struct hfp_slc_info info; - char *handsfree_path; - char *handsfree_address; - DBusMessage *slc_msg; - gboolean agent_registered; - DBusPendingCall *call; -}; - -static void hfp_debug(const char *str, void *user_data) -{ - const char *prefix = user_data; - - ofono_info("%s%s", prefix, str); -} - -static void slc_established(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - ofono_modem_set_powered(modem, TRUE); - - msg = dbus_message_new_method_return(data->slc_msg); - g_dbus_send_message(connection, msg); - dbus_message_unref(data->slc_msg); - data->slc_msg = NULL; - - ofono_info("Service level connection established"); -} - -static void slc_failed(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - msg = g_dbus_create_error(data->slc_msg, HFP_AGENT_ERROR_INTERFACE - ".Failed", - "HFP Handshake failed"); - g_dbus_send_message(connection, msg); - dbus_message_unref(data->slc_msg); - data->slc_msg = NULL; - - ofono_error("Service level connection failed"); - ofono_modem_set_powered(modem, FALSE); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; -} - -static void hfp_disconnected_cb(gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - - ofono_modem_set_powered(modem, FALSE); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; -} - -/* either oFono or Phone could request SLC connection */ -static int service_level_connection(struct ofono_modem *modem, int fd) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - GIOChannel *io; - GAtSyntax *syntax; - GAtChat *chat; - - io = g_io_channel_unix_new(fd); - if (io == NULL) { - ofono_error("Service level connection failed: %s (%d)", - strerror(errno), errno); - return -EIO; - } - - syntax = g_at_syntax_new_gsm_permissive(); - chat = g_at_chat_new(io, syntax); - g_at_syntax_unref(syntax); - g_io_channel_unref(io); - - if (chat == NULL) - return -ENOMEM; - - g_at_chat_set_disconnect_function(chat, hfp_disconnected_cb, modem); - - if (getenv("OFONO_AT_DEBUG")) - g_at_chat_set_debug(chat, hfp_debug, ""); - - data->info.chat = chat; - hfp_slc_establish(&data->info, slc_established, slc_failed, modem); - - return -EINPROGRESS; -} - -static DBusMessage *hfp_agent_new_connection(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - int fd, err; - struct ofono_modem *modem = data; - struct hfp_data *hfp_data = ofono_modem_get_data(modem); - guint16 version; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UNIX_FD, &fd, - DBUS_TYPE_UINT16, &version, DBUS_TYPE_INVALID)) - return __ofono_error_invalid_args(msg); - - hfp_slc_info_init(&hfp_data->info, version); - - err = service_level_connection(modem, fd); - if (err < 0 && err != -EINPROGRESS) - return __ofono_error_failed(msg); - - hfp_data->slc_msg = msg; - dbus_message_ref(msg); - - return NULL; -} - -static DBusMessage *hfp_agent_release(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct ofono_modem *modem = data; - struct hfp_data *hfp_data = ofono_modem_get_data(modem); - const char *obj_path = ofono_modem_get_path(modem); - - g_dbus_unregister_interface(connection, obj_path, HFP_AGENT_INTERFACE); - hfp_data->agent_registered = FALSE; - - g_hash_table_remove(modem_hash, hfp_data->handsfree_path); - ofono_modem_remove(modem); - - return dbus_message_new_method_return(msg); -} - -static const GDBusMethodTable agent_methods[] = { - { GDBUS_ASYNC_METHOD("NewConnection", - GDBUS_ARGS({ "fd", "h" }, { "version", "q" }), - NULL, hfp_agent_new_connection) }, - { GDBUS_METHOD("Release", NULL, NULL, hfp_agent_release) }, - { } -}; - -static int hfp_hf_probe(const char *device, const char *dev_addr, - const char *adapter_addr, const char *alias) -{ - struct ofono_modem *modem; - struct hfp_data *data; - char buf[256]; - - /* We already have this device in our hash, ignore */ - if (g_hash_table_lookup(modem_hash, device) != NULL) - return -EALREADY; - - ofono_info("Using device: %s, devaddr: %s, adapter: %s", - device, dev_addr, adapter_addr); - - strcpy(buf, "hfp/"); - bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4); - - modem = ofono_modem_create(buf, "hfp"); - if (modem == NULL) - return -ENOMEM; - - data = g_try_new0(struct hfp_data, 1); - if (data == NULL) - goto free; - - data->handsfree_path = g_strdup(device); - if (data->handsfree_path == NULL) - goto free; - - data->handsfree_address = g_strdup(dev_addr); - if (data->handsfree_address == NULL) - goto free; - - ofono_modem_set_data(modem, data); - ofono_modem_set_name(modem, alias); - ofono_modem_register(modem); - - g_hash_table_insert(modem_hash, g_strdup(device), modem); - - return 0; - -free: - if (data != NULL) - g_free(data->handsfree_path); - - g_free(data); - ofono_modem_remove(modem); - - return -ENOMEM; -} - -static gboolean hfp_remove_modem(gpointer key, gpointer value, - gpointer user_data) -{ - struct ofono_modem *modem = value; - const char *device = key; - const char *prefix = user_data; - - if (prefix && g_str_has_prefix(device, prefix) == FALSE) - return FALSE; - - ofono_modem_remove(modem); - - return TRUE; -} - -static void hfp_hf_remove(const char *prefix) -{ - DBG("%s", prefix); - - if (modem_hash == NULL) - return; - - g_hash_table_foreach_remove(modem_hash, hfp_remove_modem, - (gpointer) prefix); -} - -static void hfp_hf_set_alias(const char *device, const char *alias) -{ - struct ofono_modem *modem; - - if (device == NULL || alias == NULL) - return; - - modem = g_hash_table_lookup(modem_hash, device); - if (modem == NULL) - return; - - ofono_modem_set_name(modem, alias); -} - -static int hfp_register_ofono_handsfree(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - DBG("Registering oFono Agent to bluetooth daemon"); - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "RegisterAgent"); - if (msg == NULL) - return -ENOMEM; - - dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, - DBUS_TYPE_INVALID); - - g_dbus_send_message(connection, msg); - return 0; -} - -static int hfp_unregister_ofono_handsfree(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - DBG("Unregistering oFono Agent from bluetooth daemon"); - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "UnregisterAgent"); - if (msg == NULL) - return -ENOMEM; - - dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, - DBUS_TYPE_INVALID); - - g_dbus_send_message(connection, msg); - return 0; -} - -static int hfp_probe(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - - if (data == NULL) - return -EINVAL; - - g_dbus_register_interface(connection, obj_path, HFP_AGENT_INTERFACE, - agent_methods, NULL, NULL, modem, NULL); - - data->agent_registered = TRUE; - - if (hfp_register_ofono_handsfree(modem) != 0) - return -EINVAL; - - return 0; -} - -static void hfp_remove(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - const char *obj_path = ofono_modem_get_path(modem); - - if (data->call != NULL) - dbus_pending_call_cancel(data->call); - - if (g_dbus_unregister_interface(connection, obj_path, - HFP_AGENT_INTERFACE)) - hfp_unregister_ofono_handsfree(modem); - - g_free(data->handsfree_address); - g_free(data->handsfree_path); - g_free(data); - - ofono_modem_set_data(modem, NULL); -} - -static void hfp_connect_reply(DBusPendingCall *call, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusError derr; - DBusMessage *reply, *msg; - - reply = dbus_pending_call_steal_reply(call); - - if (ofono_modem_get_powered(modem)) - goto done; - - dbus_error_init(&derr); - if (!dbus_set_error_from_message(&derr, reply)) - goto done; - - DBG("Connect reply: %s", derr.message); - - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { - msg = dbus_message_new_method_call(BLUEZ_SERVICE, - data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Disconnect"); - if (msg == NULL) - ofono_error("Disconnect failed"); - else - g_dbus_send_message(connection, msg); - } - - ofono_modem_set_powered(modem, FALSE); - - dbus_error_free(&derr); - -done: - dbus_message_unref(reply); - data->call = NULL; -} - -/* power up hardware */ -static int hfp_enable(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - int status; - - DBG("%p", modem); - - status = bluetooth_send_with_reply(data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Connect", - &data->call, hfp_connect_reply, - modem, NULL, - DBUS_TIMEOUT, DBUS_TYPE_INVALID); - - if (status < 0) - return -EINVAL; - - return -EINPROGRESS; -} - -static void hfp_power_down(DBusPendingCall *call, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - DBG("Disconnect reply: %s", derr.message); - dbus_error_free(&derr); - goto done; - } - - ofono_modem_set_powered(modem, FALSE); - -done: - dbus_message_unref(reply); - data->call = NULL; -} - -static int hfp_disable(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - int status; - - DBG("%p", modem); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; - - if (data->agent_registered) { - status = bluetooth_send_with_reply(data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Disconnect", - &data->call, hfp_power_down, - modem, NULL, - DBUS_TIMEOUT, DBUS_TYPE_INVALID); - - if (status < 0) - return -EINVAL; - } - - return -EINPROGRESS; -} - -static void hfp_pre_sim(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - ofono_devinfo_create(modem, 0, "hfpmodem", data->handsfree_address); - ofono_voicecall_create(modem, 0, "hfpmodem", &data->info); - ofono_netreg_create(modem, 0, "hfpmodem", &data->info); - ofono_call_volume_create(modem, 0, "hfpmodem", &data->info); - ofono_handsfree_create(modem, 0, "hfpmodem", &data->info); -} - -static void hfp_post_sim(struct ofono_modem *modem) -{ - DBG("%p", modem); -} - -static struct ofono_modem_driver hfp_driver = { - .name = "hfp", - .modem_type = OFONO_MODEM_TYPE_HFP, - .probe = hfp_probe, - .remove = hfp_remove, - .enable = hfp_enable, - .disable = hfp_disable, - .pre_sim = hfp_pre_sim, - .post_sim = hfp_post_sim, -}; - -static struct bluetooth_profile hfp_hf = { - .name = "hfp_hf", - .probe = hfp_hf_probe, - .remove = hfp_hf_remove, - .set_alias = hfp_hf_set_alias, -}; - -static int hfp_init(void) -{ - int err; - - if (DBUS_TYPE_UNIX_FD < 0) - return -EBADF; - - connection = ofono_dbus_get_connection(); - - err = ofono_modem_driver_register(&hfp_driver); - if (err < 0) - return err; - - err = bluetooth_register_uuid(HFP_AG_UUID, &hfp_hf); - if (err < 0) { - ofono_modem_driver_unregister(&hfp_driver); - return err; - } - - modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, NULL); - - return 0; -} - -static void hfp_exit(void) -{ - bluetooth_unregister_uuid(HFP_AG_UUID); - ofono_modem_driver_unregister(&hfp_driver); - - g_hash_table_destroy(modem_hash); -} - -OFONO_PLUGIN_DEFINE(hfp, "Hands-Free Profile Plugins", VERSION, - OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) diff --git a/plugins/hfp_hf_bluez4.c b/plugins/hfp_hf_bluez4.c new file mode 100644 index 0000000..450c183 --- /dev/null +++ b/plugins/hfp_hf_bluez4.c @@ -0,0 +1,552 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2010 ProFUSION embedded systems + * Copyright (C) 2011 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 <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <glib.h> +#include <gatchat.h> +#include <gattty.h> +#include <gdbus.h> +#include <ofono.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> +#include <ofono/modem.h> +#include <ofono/devinfo.h> +#include <ofono/netreg.h> +#include <ofono/voicecall.h> +#include <ofono/call-volume.h> +#include <ofono/handsfree.h> + +#include <drivers/hfpmodem/slc.h> + +#include "bluez4.h" + +#define BLUEZ_GATEWAY_INTERFACE BLUEZ_SERVICE ".HandsfreeGateway" + +#define HFP_AGENT_INTERFACE "org.bluez.HandsfreeAgent" +#define HFP_AGENT_ERROR_INTERFACE "org.bluez.Error" + +#ifndef DBUS_TYPE_UNIX_FD +#define DBUS_TYPE_UNIX_FD -1 +#endif + +static DBusConnection *connection; +static GHashTable *modem_hash = NULL; + +struct hfp_data { + struct hfp_slc_info info; + char *handsfree_path; + char *handsfree_address; + DBusMessage *slc_msg; + gboolean agent_registered; + DBusPendingCall *call; +}; + +static void hfp_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + ofono_info("%s%s", prefix, str); +} + +static void slc_established(gpointer userdata) +{ + struct ofono_modem *modem = userdata; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + ofono_modem_set_powered(modem, TRUE); + + msg = dbus_message_new_method_return(data->slc_msg); + g_dbus_send_message(connection, msg); + dbus_message_unref(data->slc_msg); + data->slc_msg = NULL; + + ofono_info("Service level connection established"); +} + +static void slc_failed(gpointer userdata) +{ + struct ofono_modem *modem = userdata; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + msg = g_dbus_create_error(data->slc_msg, HFP_AGENT_ERROR_INTERFACE + ".Failed", + "HFP Handshake failed"); + g_dbus_send_message(connection, msg); + dbus_message_unref(data->slc_msg); + data->slc_msg = NULL; + + ofono_error("Service level connection failed"); + ofono_modem_set_powered(modem, FALSE); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; +} + +static void hfp_disconnected_cb(gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + + ofono_modem_set_powered(modem, FALSE); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; +} + +/* either oFono or Phone could request SLC connection */ +static int service_level_connection(struct ofono_modem *modem, int fd) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + GIOChannel *io; + GAtSyntax *syntax; + GAtChat *chat; + + io = g_io_channel_unix_new(fd); + if (io == NULL) { + ofono_error("Service level connection failed: %s (%d)", + strerror(errno), errno); + return -EIO; + } + + syntax = g_at_syntax_new_gsm_permissive(); + chat = g_at_chat_new(io, syntax); + g_at_syntax_unref(syntax); + g_io_channel_unref(io); + + if (chat == NULL) + return -ENOMEM; + + g_at_chat_set_disconnect_function(chat, hfp_disconnected_cb, modem); + + if (getenv("OFONO_AT_DEBUG")) + g_at_chat_set_debug(chat, hfp_debug, ""); + + data->info.chat = chat; + hfp_slc_establish(&data->info, slc_established, slc_failed, modem); + + return -EINPROGRESS; +} + +static DBusMessage *hfp_agent_new_connection(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + int fd, err; + struct ofono_modem *modem = data; + struct hfp_data *hfp_data = ofono_modem_get_data(modem); + guint16 version; + + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UNIX_FD, &fd, + DBUS_TYPE_UINT16, &version, DBUS_TYPE_INVALID)) + return __ofono_error_invalid_args(msg); + + hfp_slc_info_init(&hfp_data->info, version); + + err = service_level_connection(modem, fd); + if (err < 0 && err != -EINPROGRESS) + return __ofono_error_failed(msg); + + hfp_data->slc_msg = msg; + dbus_message_ref(msg); + + return NULL; +} + +static DBusMessage *hfp_agent_release(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_modem *modem = data; + struct hfp_data *hfp_data = ofono_modem_get_data(modem); + const char *obj_path = ofono_modem_get_path(modem); + + g_dbus_unregister_interface(connection, obj_path, HFP_AGENT_INTERFACE); + hfp_data->agent_registered = FALSE; + + g_hash_table_remove(modem_hash, hfp_data->handsfree_path); + ofono_modem_remove(modem); + + return dbus_message_new_method_return(msg); +} + +static const GDBusMethodTable agent_methods[] = { + { GDBUS_ASYNC_METHOD("NewConnection", + GDBUS_ARGS({ "fd", "h" }, { "version", "q" }), + NULL, hfp_agent_new_connection) }, + { GDBUS_METHOD("Release", NULL, NULL, hfp_agent_release) }, + { } +}; + +static int hfp_hf_probe(const char *device, const char *dev_addr, + const char *adapter_addr, const char *alias) +{ + struct ofono_modem *modem; + struct hfp_data *data; + char buf[256]; + + /* We already have this device in our hash, ignore */ + if (g_hash_table_lookup(modem_hash, device) != NULL) + return -EALREADY; + + ofono_info("Using device: %s, devaddr: %s, adapter: %s", + device, dev_addr, adapter_addr); + + strcpy(buf, "hfp/"); + bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4); + + modem = ofono_modem_create(buf, "hfp"); + if (modem == NULL) + return -ENOMEM; + + data = g_try_new0(struct hfp_data, 1); + if (data == NULL) + goto free; + + data->handsfree_path = g_strdup(device); + if (data->handsfree_path == NULL) + goto free; + + data->handsfree_address = g_strdup(dev_addr); + if (data->handsfree_address == NULL) + goto free; + + ofono_modem_set_data(modem, data); + ofono_modem_set_name(modem, alias); + ofono_modem_register(modem); + + g_hash_table_insert(modem_hash, g_strdup(device), modem); + + return 0; + +free: + if (data != NULL) + g_free(data->handsfree_path); + + g_free(data); + ofono_modem_remove(modem); + + return -ENOMEM; +} + +static gboolean hfp_remove_modem(gpointer key, gpointer value, + gpointer user_data) +{ + struct ofono_modem *modem = value; + const char *device = key; + const char *prefix = user_data; + + if (prefix && g_str_has_prefix(device, prefix) == FALSE) + return FALSE; + + ofono_modem_remove(modem); + + return TRUE; +} + +static void hfp_hf_remove(const char *prefix) +{ + DBG("%s", prefix); + + if (modem_hash == NULL) + return; + + g_hash_table_foreach_remove(modem_hash, hfp_remove_modem, + (gpointer) prefix); +} + +static void hfp_hf_set_alias(const char *device, const char *alias) +{ + struct ofono_modem *modem; + + if (device == NULL || alias == NULL) + return; + + modem = g_hash_table_lookup(modem_hash, device); + if (modem == NULL) + return; + + ofono_modem_set_name(modem, alias); +} + +static int hfp_register_ofono_handsfree(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + DBG("Registering oFono Agent to bluetooth daemon"); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "RegisterAgent"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, + DBUS_TYPE_INVALID); + + g_dbus_send_message(connection, msg); + return 0; +} + +static int hfp_unregister_ofono_handsfree(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + DBG("Unregistering oFono Agent from bluetooth daemon"); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "UnregisterAgent"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, + DBUS_TYPE_INVALID); + + g_dbus_send_message(connection, msg); + return 0; +} + +static int hfp_probe(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + + if (data == NULL) + return -EINVAL; + + g_dbus_register_interface(connection, obj_path, HFP_AGENT_INTERFACE, + agent_methods, NULL, NULL, modem, NULL); + + data->agent_registered = TRUE; + + if (hfp_register_ofono_handsfree(modem) != 0) + return -EINVAL; + + return 0; +} + +static void hfp_remove(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + const char *obj_path = ofono_modem_get_path(modem); + + if (data->call != NULL) + dbus_pending_call_cancel(data->call); + + if (g_dbus_unregister_interface(connection, obj_path, + HFP_AGENT_INTERFACE)) + hfp_unregister_ofono_handsfree(modem); + + g_free(data->handsfree_address); + g_free(data->handsfree_path); + g_free(data); + + ofono_modem_set_data(modem, NULL); +} + +static void hfp_connect_reply(DBusPendingCall *call, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusError derr; + DBusMessage *reply, *msg; + + reply = dbus_pending_call_steal_reply(call); + + if (ofono_modem_get_powered(modem)) + goto done; + + dbus_error_init(&derr); + if (!dbus_set_error_from_message(&derr, reply)) + goto done; + + DBG("Connect reply: %s", derr.message); + + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { + msg = dbus_message_new_method_call(BLUEZ_SERVICE, + data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Disconnect"); + if (msg == NULL) + ofono_error("Disconnect failed"); + else + g_dbus_send_message(connection, msg); + } + + ofono_modem_set_powered(modem, FALSE); + + dbus_error_free(&derr); + +done: + dbus_message_unref(reply); + data->call = NULL; +} + +/* power up hardware */ +static int hfp_enable(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + int status; + + DBG("%p", modem); + + status = bluetooth_send_with_reply(data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Connect", + &data->call, hfp_connect_reply, + modem, NULL, + DBUS_TIMEOUT, DBUS_TYPE_INVALID); + + if (status < 0) + return -EINVAL; + + return -EINPROGRESS; +} + +static void hfp_power_down(DBusPendingCall *call, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + DBG("Disconnect reply: %s", derr.message); + dbus_error_free(&derr); + goto done; + } + + ofono_modem_set_powered(modem, FALSE); + +done: + dbus_message_unref(reply); + data->call = NULL; +} + +static int hfp_disable(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + int status; + + DBG("%p", modem); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; + + if (data->agent_registered) { + status = bluetooth_send_with_reply(data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Disconnect", + &data->call, hfp_power_down, + modem, NULL, + DBUS_TIMEOUT, DBUS_TYPE_INVALID); + + if (status < 0) + return -EINVAL; + } + + return -EINPROGRESS; +} + +static void hfp_pre_sim(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + + DBG("%p", modem); + + ofono_devinfo_create(modem, 0, "hfpmodem", data->handsfree_address); + ofono_voicecall_create(modem, 0, "hfpmodem", &data->info); + ofono_netreg_create(modem, 0, "hfpmodem", &data->info); + ofono_call_volume_create(modem, 0, "hfpmodem", &data->info); + ofono_handsfree_create(modem, 0, "hfpmodem", &data->info); +} + +static void hfp_post_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static struct ofono_modem_driver hfp_driver = { + .name = "hfp", + .modem_type = OFONO_MODEM_TYPE_HFP, + .probe = hfp_probe, + .remove = hfp_remove, + .enable = hfp_enable, + .disable = hfp_disable, + .pre_sim = hfp_pre_sim, + .post_sim = hfp_post_sim, +}; + +static struct bluetooth_profile hfp_hf = { + .name = "hfp_hf", + .probe = hfp_hf_probe, + .remove = hfp_hf_remove, + .set_alias = hfp_hf_set_alias, +}; + +static int hfp_init(void) +{ + int err; + + if (DBUS_TYPE_UNIX_FD < 0) + return -EBADF; + + connection = ofono_dbus_get_connection(); + + err = ofono_modem_driver_register(&hfp_driver); + if (err < 0) + return err; + + err = bluetooth_register_uuid(HFP_AG_UUID, &hfp_hf); + if (err < 0) { + ofono_modem_driver_unregister(&hfp_driver); + return err; + } + + modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); + + return 0; +} + +static void hfp_exit(void) +{ + bluetooth_unregister_uuid(HFP_AG_UUID); + ofono_modem_driver_unregister(&hfp_driver); + + g_hash_table_destroy(modem_hash); +} + +OFONO_PLUGIN_DEFINE(hfp_bluez4, "Hands-Free Profile Plugins", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) diff --git a/plugins/sap.c b/plugins/sap.c index d893bc1..d1913fb 100644 --- a/plugins/sap.c +++ b/plugins/sap.c @@ -37,7 +37,7 @@ #include <ofono/log.h> #include <ofono/modem.h> -#include "bluetooth.h" +#include "bluez4.h" #include "util.h" #ifndef DBUS_TYPE_UNIX_FD diff --git a/plugins/telit.c b/plugins/telit.c index 79bc421..392283a 100644 --- a/plugins/telit.c +++ b/plugins/telit.c @@ -58,7 +58,7 @@ #include <drivers/atmodem/atutil.h> #include <drivers/atmodem/vendor.h> -#include "bluetooth.h" +#include "bluez4.h" static const char *none_prefix[] = { NULL }; static const char *rsen_prefix[]= { "#RSEN:", NULL }; -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v1 3/6] bluetooth: Initial files for BlueZ 5 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi @ 2013-01-15 18:24 ` Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi ` (3 subsequent siblings) 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-15 18:24 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1927 bytes --] This patch adds the file for Bluetooth(BlueZ 5) oFono plugin. --- Makefile.am | 5 +++++ plugins/bluez5.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 plugins/bluez5.c diff --git a/Makefile.am b/Makefile.am index 85824be..2f50673 100644 --- a/Makefile.am +++ b/Makefile.am @@ -407,6 +407,11 @@ builtin_sources += plugins/samsung.c builtin_modules += sim900 builtin_sources += plugins/sim900.c +if BLUEZ5 +builtin_modules += bluez5 +builtin_sources += plugins/bluez5.c +endif + if BLUEZ4 builtin_modules += bluez4 builtin_sources += plugins/bluez4.c plugins/bluez4.h diff --git a/plugins/bluez5.c b/plugins/bluez5.c new file mode 100644 index 0000000..335331c --- /dev/null +++ b/plugins/bluez5.c @@ -0,0 +1,33 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2013 Intel Corporation. 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 <glib.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +OFONO_PLUGIN_DEFINE(bluez5, "BlueZ 5 Utils Plugin", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v1 4/6] hfp_hf: Add initial file for external HFP 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi ` (2 preceding siblings ...) 2013-01-15 18:24 ` [PATCH v1 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi @ 2013-01-15 18:24 ` Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 5/6] hfp_hf: Add hfp_driver Claudio Takahasi ` (2 subsequent siblings) 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-15 18:24 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2230 bytes --] This patch adds the initial file to support external HFP profile and BlueZ 5. "hfp_bluez5" plugin will implement an external Bluetooth profile compatible with BlueZ 5, and "hfp" plugin will keep the compatibility with BlueZ 4. Both plugins can be enabled in the system. --- Makefile.am | 3 +++ plugins/hfp_hf_bluez5.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 plugins/hfp_hf_bluez5.c diff --git a/Makefile.am b/Makefile.am index 2f50673..6d92be1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -410,6 +410,9 @@ builtin_sources += plugins/sim900.c if BLUEZ5 builtin_modules += bluez5 builtin_sources += plugins/bluez5.c + +builtin_modules += hfp_bluez5 +builtin_sources += plugins/hfp_hf_bluez5.c endif if BLUEZ4 diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c new file mode 100644 index 0000000..779f05d --- /dev/null +++ b/plugins/hfp_hf_bluez5.c @@ -0,0 +1,42 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2013 Intel Corporation. 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 <glib.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +static int hfp_init(void) +{ + return 0; +} + +static void hfp_exit(void) +{ +} + +OFONO_PLUGIN_DEFINE(hfp_bluez5, "External Hands-Free Profile Plugin", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v1 5/6] hfp_hf: Add hfp_driver 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi ` (3 preceding siblings ...) 2013-01-15 18:24 ` [PATCH v1 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi @ 2013-01-15 18:24 ` Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-15 18:24 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 7680 bytes --] Adds HFP modem driver registration. --- Makefile.am | 4 +- plugins/bluez5.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ plugins/bluez5.h | 29 +++++++++++++ plugins/hfp_hf_bluez5.c | 80 ++++++++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 plugins/bluez5.h diff --git a/Makefile.am b/Makefile.am index 6d92be1..b8dc781 100644 --- a/Makefile.am +++ b/Makefile.am @@ -409,10 +409,10 @@ builtin_sources += plugins/sim900.c if BLUEZ5 builtin_modules += bluez5 -builtin_sources += plugins/bluez5.c +builtin_sources += plugins/bluez5.c plugins/bluez5.h builtin_modules += hfp_bluez5 -builtin_sources += plugins/hfp_hf_bluez5.c +builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h endif if BLUEZ4 diff --git a/plugins/bluez5.c b/plugins/bluez5.c index 335331c..84ba47d 100644 --- a/plugins/bluez5.c +++ b/plugins/bluez5.c @@ -23,11 +23,123 @@ #include <config.h> #endif +#include <errno.h> #include <glib.h> #define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/dbus.h> #include <ofono/plugin.h> #include <ofono/log.h> +#include <gdbus/gdbus.h> +#include "bluez5.h" + +#define BLUEZ_PROFILE_MGMT_INTERFACE BLUEZ_SERVICE ".ProfileManager1" + +static void profile_register_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("RegisterProfile() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + +done: + dbus_message_unref(reply); +} + +static void unregister_profile_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("UnregisterProfile() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + +done: + dbus_message_unref(reply); +} + +int bluetooth_register_profile(DBusConnection *conn, const char *uuid, + const char *name, const char *object) +{ + DBusMessageIter iter, dict; + DBusPendingCall *c; + DBusMessage *msg; + + DBG("Bluetooth: Registering %s (%s) profile", uuid, name); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", + BLUEZ_PROFILE_MGMT_INTERFACE, "RegisterProfile"); + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &object); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uuid); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict); + ofono_dbus_dict_append(&dict, "Name", DBUS_TYPE_STRING, &name); + + dbus_message_iter_close_container(&iter, &dict); + + if (!dbus_connection_send_with_reply(conn, msg, &c, -1)) { + ofono_error("Sending RegisterProfile failed"); + dbus_message_unref(msg); + return -EIO; + } + + dbus_pending_call_set_notify(c, profile_register_cb, NULL, NULL); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); + + return 0; +} + +void bluetooth_unregister_profile(DBusConnection *conn, const char *object) +{ + DBusMessageIter iter; + DBusPendingCall *c; + DBusMessage *msg; + + DBG("Bluetooth: Unregistering profile %s", object); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", + BLUEZ_PROFILE_MGMT_INTERFACE, "UnregisterProfile"); + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &object); + + if (!dbus_connection_send_with_reply(conn, msg, &c, -1)) { + ofono_error("Sending RegisterProfile failed"); + dbus_message_unref(msg); + return; + } + + dbus_pending_call_set_notify(c, unregister_profile_cb, NULL, NULL); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); +} + OFONO_PLUGIN_DEFINE(bluez5, "BlueZ 5 Utils Plugin", VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluez5.h b/plugins/bluez5.h new file mode 100644 index 0000000..99bf896 --- /dev/null +++ b/plugins/bluez5.h @@ -0,0 +1,29 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2013 Intel Corporation. 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 + * + */ + +#define BLUEZ_SERVICE "org.bluez" + +#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" + +int bluetooth_register_profile(DBusConnection *conn, const char *uuid, + const char *name, const char *object); + +void bluetooth_unregister_profile(DBusConnection *conn, const char *object); diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c index 779f05d..0cd0d23 100644 --- a/plugins/hfp_hf_bluez5.c +++ b/plugins/hfp_hf_bluez5.c @@ -23,19 +23,99 @@ #include <config.h> #endif +#include <errno.h> #include <glib.h> #define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/modem.h> +#include <ofono/dbus.h> #include <ofono/plugin.h> #include <ofono/log.h> +#include "bluez5.h" + +#ifndef DBUS_TYPE_UNIX_FD +#define DBUS_TYPE_UNIX_FD -1 +#endif + +#define HFP_EXT_PROFILE_PATH "/bluetooth/profile/hfp_hf" + +static int hfp_probe(struct ofono_modem *modem) +{ + DBG("modem: %p", modem); + + return 0; +} + +static void hfp_remove(struct ofono_modem *modem) +{ + DBG("modem: %p", modem); +} + +/* power up hardware */ +static int hfp_enable(struct ofono_modem *modem) +{ + DBG("%p", modem); + + return 0; +} + +static int hfp_disable(struct ofono_modem *modem) +{ + DBG("%p", modem); + + return 0; +} + +static void hfp_pre_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static void hfp_post_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static struct ofono_modem_driver hfp_driver = { + .name = "hfp", + .modem_type = OFONO_MODEM_TYPE_HFP, + .probe = hfp_probe, + .remove = hfp_remove, + .enable = hfp_enable, + .disable = hfp_disable, + .pre_sim = hfp_pre_sim, + .post_sim = hfp_post_sim, +}; + static int hfp_init(void) { + DBusConnection *conn = ofono_dbus_get_connection(); + int err; + + if (DBUS_TYPE_UNIX_FD < 0) + return -EBADF; + + err = ofono_modem_driver_register(&hfp_driver); + if (err < 0) + return err; + + err = bluetooth_register_profile(conn, HFP_HS_UUID, "hfp_hf", + HFP_EXT_PROFILE_PATH); + if (err < 0) { + ofono_modem_driver_unregister(&hfp_driver); + return err; + } + return 0; } static void hfp_exit(void) { + DBusConnection *conn = ofono_dbus_get_connection(); + + bluetooth_unregister_profile(conn, HFP_EXT_PROFILE_PATH); + ofono_modem_driver_unregister(&hfp_driver); } OFONO_PLUGIN_DEFINE(hfp_bluez5, "External Hands-Free Profile Plugin", VERSION, -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v1 6/6] hfp_hf: Add BlueZ Profile handler 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi ` (4 preceding siblings ...) 2013-01-15 18:24 ` [PATCH v1 5/6] hfp_hf: Add hfp_driver Claudio Takahasi @ 2013-01-15 18:24 ` Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-15 18:24 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 4081 bytes --] This patch declares the external HFP Profile handler. It contains the initial implementation of the D-Bus Profile1 interface and methods responsible for handling Bluetooth connections. --- plugins/bluez5.h | 2 ++ plugins/hfp_hf_bluez5.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/plugins/bluez5.h b/plugins/bluez5.h index 99bf896..01ecfe8 100644 --- a/plugins/bluez5.h +++ b/plugins/bluez5.h @@ -20,6 +20,8 @@ */ #define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1" +#define BLUEZ_ERROR_INTERFACE BLUEZ_SERVICE ".Error" #define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c index 0cd0d23..e024838 100644 --- a/plugins/hfp_hf_bluez5.c +++ b/plugins/hfp_hf_bluez5.c @@ -26,6 +26,8 @@ #include <errno.h> #include <glib.h> +#include <gdbus.h> + #define OFONO_API_SUBJECT_TO_CHANGE #include <ofono/modem.h> #include <ofono/dbus.h> @@ -88,6 +90,59 @@ static struct ofono_modem_driver hfp_driver = { .post_sim = hfp_post_sim, }; +static DBusMessage *profile_new_connection(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler NewConnection"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_release(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler Release"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_cancel(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler Cancel"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_disconnection(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler RequestDisconnection"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static const GDBusMethodTable profile_methods[] = { + { GDBUS_ASYNC_METHOD("NewConnection", + GDBUS_ARGS({ "device", "o"}, { "fd", "h"}, + { "fd_properties", "a{sv}" }), + NULL, profile_new_connection) }, + { GDBUS_METHOD("Release", NULL, NULL, profile_release) }, + { GDBUS_METHOD("Cancel", NULL, NULL, profile_cancel) }, + { GDBUS_METHOD("RequestDisconnection", + GDBUS_ARGS({"device", "o"}), NULL, + profile_disconnection) }, + { } +}; + static int hfp_init(void) { DBusConnection *conn = ofono_dbus_get_connection(); @@ -96,13 +151,28 @@ static int hfp_init(void) if (DBUS_TYPE_UNIX_FD < 0) return -EBADF; + /* Registers External Profile handler */ + if (!g_dbus_register_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE, + profile_methods, NULL, + NULL, NULL, NULL)) { + ofono_error("Register Profile interface failed: %s", + HFP_EXT_PROFILE_PATH); + return -EIO; + } + err = ofono_modem_driver_register(&hfp_driver); - if (err < 0) + if (err < 0) { + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); return err; + } err = bluetooth_register_profile(conn, HFP_HS_UUID, "hfp_hf", HFP_EXT_PROFILE_PATH); if (err < 0) { + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); ofono_modem_driver_unregister(&hfp_driver); return err; } @@ -115,6 +185,8 @@ static void hfp_exit(void) DBusConnection *conn = ofono_dbus_get_connection(); bluetooth_unregister_profile(conn, HFP_EXT_PROFILE_PATH); + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); ofono_modem_driver_unregister(&hfp_driver); } -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 0/6] HFP HF: External Profile 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi ` (5 preceding siblings ...) 2013-01-15 18:24 ` [PATCH v1 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi @ 2013-01-16 13:31 ` Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi ` (6 more replies) 6 siblings, 7 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-16 13:31 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2169 bytes --] This is the first group of patches which introduces the Handsfree BlueZ external profile. The following patches contain only initial files and basic structures for the HFP HF plugin (since files and plugins names are one of the controversial points). Remaining HFP HF patches: git://git.infradead.org/users/cktakahasi/ofono.git HF-20130116 Changed between v0-v1: * Append BlueZ version to hfp_hf* files * --enable-bluez4 configure option Changed between v1-v2: * Make BLUEZ4 conditional dependent on BLUETOOTH. BlueZ 5 is enabled by default(--enable-bluetooth can be omitted), BlueZ 4 support is enabled only if --enable-bluez4 is informed. --disable-bluetooth disables all BlueZ related plugins. Claudio Takahasi (6): Makefile: Add configure option for BlueZ 4 and 5 bluetooth: Add versioning information to BlueZ plugins bluetooth: Initial files for BlueZ 5 hfp_hf: Add initial file for external HFP hfp_hf: Add hfp_driver hfp_hf: Add BlueZ Profile handler Makefile.am | 31 +- configure.ac | 20 +- dundee/bluetooth.c | 2 +- plugins/bluetooth.c | 989 ------------------------------------------------ plugins/bluetooth.h | 84 ---- plugins/bluez4.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++ plugins/bluez4.h | 84 ++++ plugins/bluez5.c | 145 +++++++ plugins/bluez5.h | 31 ++ plugins/dun_gw.c | 2 +- plugins/hfp_ag.c | 2 +- plugins/hfp_hf.c | 552 --------------------------- plugins/hfp_hf_bluez4.c | 552 +++++++++++++++++++++++++++ plugins/hfp_hf_bluez5.c | 194 ++++++++++ plugins/sap.c | 2 +- plugins/telit.c | 2 +- 16 files changed, 2035 insertions(+), 1646 deletions(-) delete mode 100644 plugins/bluetooth.c delete mode 100644 plugins/bluetooth.h create mode 100644 plugins/bluez4.c create mode 100644 plugins/bluez4.h create mode 100644 plugins/bluez5.c create mode 100644 plugins/bluez5.h delete mode 100644 plugins/hfp_hf.c create mode 100644 plugins/hfp_hf_bluez4.c create mode 100644 plugins/hfp_hf_bluez5.c -- 1.7.11.7 ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 1/6] Makefile: Add configure option for BlueZ 4 and 5 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi @ 2013-01-16 13:31 ` Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi ` (5 subsequent siblings) 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-16 13:31 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2519 bytes --] BlueZ 5 is the default option. If --enable-bluez4 is provided, oFono plugins based on BlueZ 4 are enabled prior to BlueZ 5. --disable-bluetooth configure option disables BlueZ 5 and BlueZ 4 plugins. --- Makefile.am | 7 ++++++- configure.ac | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0d2ba9f..c2bd4a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -408,6 +408,7 @@ builtin_modules += sim900 builtin_sources += plugins/sim900.c if BLUETOOTH +if BLUEZ4 builtin_modules += bluetooth builtin_sources += plugins/bluetooth.c plugins/bluetooth.h @@ -434,6 +435,7 @@ builtin_cflags += @BLUEZ_CFLAGS@ builtin_libadd += @BLUEZ_LIBS@ endif endif +endif if PROVISION builtin_sources += plugins/mbpi.h plugins/mbpi.c @@ -742,6 +744,8 @@ tools_stktest_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ endif endif +if BLUETOOTH +if BLUEZ4 if DUNDEE sbin_PROGRAMS += dundee/dundee @@ -759,7 +763,8 @@ if SYSTEMD systemdunit_DATA += dundee/dundee.service endif endif - +endif +endif endif noinst_PROGRAMS += gatchat/gsmdial gatchat/test-server gatchat/test-qcdm diff --git a/configure.ac b/configure.ac index 450352b..7db4198 100644 --- a/configure.ac +++ b/configure.ac @@ -173,14 +173,22 @@ AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem], AM_CONDITIONAL(QMIMODEM, test "${enable_qmimodem}" != "no") AC_ARG_ENABLE(bluetooth, AC_HELP_STRING([--disable-bluetooth], - [disable Bluetooth modem support]), + [disable BlueZ 4 and BlueZ 5 plugins support]), [enable_bluetooth=${enableval}]) -if (test "${enable_bluetooth}" != "no"); then - PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99, dummy=yes, - AC_MSG_ERROR(Bluetooth library >= 4.99 is required)) + +AC_ARG_ENABLE(bluez4, AC_HELP_STRING([--enable-bluez4], + [enable BlueZ 4 plugins support prior to BlueZ 5]), + [enable_bluez4=${enableval}]) + +if (test "${enable_bluez4}" = "yes"); then + PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99 bluez < 5, + enable_bluez4=yes, + AC_MSG_ERROR(Bluetooth library >= 4.99 and < 5 is required)) + AC_SUBST(BLUEZ_CFLAGS) + AC_SUBST(BLUEZ_LIBS) fi -AC_SUBST(BLUEZ_CFLAGS) -AC_SUBST(BLUEZ_LIBS) + +AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes") AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no") AC_ARG_WITH([provisiondb], AC_HELP_STRING([--with-provisiondb=FILE], -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 2/6] bluetooth: Add versioning information to BlueZ plugins 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi @ 2013-01-16 13:31 ` Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi ` (4 subsequent siblings) 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-16 13:31 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 91558 bytes --] As BlueZ 5 introduced backwards incompatible changes, and we want to keep support for BlueZ 4 based plugins for some time, we need to separate the plugins that are based on BlueZ 4 from the ones based on BlueZ 5. The HFP HF plugin is renamed to hfp_hf_bluez4 to make it easy to add a HFP HF that talks to BlueZ 5. --- Makefile.am | 18 +- dundee/bluetooth.c | 2 +- plugins/bluetooth.c | 989 ------------------------------------------------ plugins/bluetooth.h | 84 ---- plugins/bluez4.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++ plugins/bluez4.h | 84 ++++ plugins/dun_gw.c | 2 +- plugins/hfp_ag.c | 2 +- plugins/hfp_hf.c | 552 --------------------------- plugins/hfp_hf_bluez4.c | 552 +++++++++++++++++++++++++++ plugins/sap.c | 2 +- plugins/telit.c | 2 +- 12 files changed, 1639 insertions(+), 1639 deletions(-) delete mode 100644 plugins/bluetooth.c delete mode 100644 plugins/bluetooth.h create mode 100644 plugins/bluez4.c create mode 100644 plugins/bluez4.h delete mode 100644 plugins/hfp_hf.c create mode 100644 plugins/hfp_hf_bluez4.c diff --git a/Makefile.am b/Makefile.am index c2bd4a4..63e6fdb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -409,23 +409,23 @@ builtin_sources += plugins/sim900.c if BLUETOOTH if BLUEZ4 -builtin_modules += bluetooth -builtin_sources += plugins/bluetooth.c plugins/bluetooth.h +builtin_modules += bluez4 +builtin_sources += plugins/bluez4.c plugins/bluez4.h builtin_modules += telit -builtin_sources += plugins/telit.c plugins/bluetooth.h +builtin_sources += plugins/telit.c plugins/bluez4.h builtin_modules += sap -builtin_sources += plugins/sap.c plugins/bluetooth.h +builtin_sources += plugins/sap.c plugins/bluez4.h -builtin_modules += hfp -builtin_sources += plugins/hfp_hf.c plugins/bluetooth.h +builtin_modules += hfp_bluez4 +builtin_sources += plugins/hfp_hf_bluez4.c plugins/bluez4.h builtin_modules += hfp_ag -builtin_sources += plugins/hfp_ag.c plugins/bluetooth.h +builtin_sources += plugins/hfp_ag.c plugins/bluez4.h builtin_modules += dun_gw -builtin_sources += plugins/dun_gw.c plugins/bluetooth.h +builtin_sources += plugins/dun_gw.c plugins/bluez4.h builtin_modules += connman builtin_sources += plugins/connman.c @@ -750,7 +750,7 @@ if DUNDEE sbin_PROGRAMS += dundee/dundee dundee_dundee_SOURCES = $(gdbus_sources) $(gatchat_sources) $(btio_sources) \ - src/log.c src/dbus.c plugins/bluetooth.c \ + src/log.c src/dbus.c plugins/bluez4.c \ dundee/dundee.h dundee/main.c dundee/dbus.c \ dundee/manager.c dundee/device.c dundee/bluetooth.c diff --git a/dundee/bluetooth.c b/dundee/bluetooth.c index 9ddc72c..58355d3 100644 --- a/dundee/bluetooth.c +++ b/dundee/bluetooth.c @@ -32,7 +32,7 @@ #include <glib.h> -#include "plugins/bluetooth.h" +#include "plugins/bluez4.h" #include "dundee.h" diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c deleted file mode 100644 index 5d28530..0000000 --- a/plugins/bluetooth.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. - * Copyright (C) 2010 ProFUSION embedded systems - * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> - * - * 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 <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <glib.h> -#include <gdbus.h> - -#define OFONO_API_SUBJECT_TO_CHANGE -#include <ofono/plugin.h> -#include <ofono/log.h> - -#include <btio.h> -#include "bluetooth.h" - -static DBusConnection *connection; -static GHashTable *uuid_hash = NULL; -static GHashTable *adapter_address_hash = NULL; -static gint bluetooth_refcount; -static GSList *server_list = NULL; -static const char *adapter_any_name = "any"; -static char *adapter_any_path; - -#define TIMEOUT 60 /* Timeout for user response (seconds) */ - -struct server { - guint8 channel; - char *sdp_record; - guint32 handle; - GIOChannel *io; - ConnectFunc connect_cb; - gpointer user_data; -}; - -struct cb_data { - struct server *server; - char *path; - guint source; - GIOChannel *io; -}; - -void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, - char *buf, int size) -{ - int i, j; - - for (i = 0, j = 0; adapter_addr[j] && i < size - 1; j++) - if (adapter_addr[j] >= '0' && adapter_addr[j] <= '9') - buf[i++] = adapter_addr[j]; - else if (adapter_addr[j] >= 'A' && adapter_addr[j] <= 'F') - buf[i++] = adapter_addr[j]; - - if (i < size - 1) - buf[i++] = '_'; - - for (j = 0; dev_addr[j] && i < size - 1; j++) - if (dev_addr[j] >= '0' && dev_addr[j] <= '9') - buf[i++] = dev_addr[j]; - else if (dev_addr[j] >= 'A' && dev_addr[j] <= 'F') - buf[i++] = dev_addr[j]; - - buf[i] = '\0'; -} - -int bluetooth_send_with_reply(const char *path, const char *interface, - const char *method, DBusPendingCall **call, - DBusPendingCallNotifyFunction cb, - void *user_data, DBusFreeFunction free_func, - int timeout, int type, ...) -{ - DBusMessage *msg; - DBusPendingCall *c; - va_list args; - int err; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, path, - interface, method); - if (msg == NULL) { - ofono_error("Unable to allocate new D-Bus %s message", method); - err = -ENOMEM; - goto fail; - } - - va_start(args, type); - - if (!dbus_message_append_args_valist(msg, type, args)) { - va_end(args); - err = -EIO; - goto fail; - } - - va_end(args); - - if (timeout > 0) - timeout *= 1000; - - if (!dbus_connection_send_with_reply(connection, msg, &c, timeout)) { - ofono_error("Sending %s failed", method); - err = -EIO; - goto fail; - } - - if (call != NULL) - *call = c; - - dbus_pending_call_set_notify(c, cb, user_data, free_func); - dbus_pending_call_unref(c); - - dbus_message_unref(msg); - - return 0; - -fail: - if (free_func && user_data) - free_func(user_data); - - if (msg) - dbus_message_unref(msg); - - return err; -} - -typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data); - -struct property_handler { - const char *property; - PropertyHandler callback; - gpointer user_data; -}; - -static gint property_handler_compare(gconstpointer a, gconstpointer b) -{ - const struct property_handler *handler = a; - const char *property = b; - - return strcmp(handler->property, property); -} - -void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...) -{ - va_list args; - GSList *prop_handlers = NULL; - DBusMessageIter array, dict; - - va_start(args, property); - - while (property != NULL) { - struct property_handler *handler = - g_new0(struct property_handler, 1); - - handler->property = property; - handler->callback = va_arg(args, PropertyHandler); - handler->user_data = va_arg(args, gpointer); - - property = va_arg(args, const char *); - - prop_handlers = g_slist_prepend(prop_handlers, handler); - } - - va_end(args); - - if (dbus_message_iter_init(reply, &array) == FALSE) - goto done; - - if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY) - goto done; - - dbus_message_iter_recurse(&array, &dict); - - while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { - DBusMessageIter entry, value; - const char *key; - GSList *l; - - dbus_message_iter_recurse(&dict, &entry); - - if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) - goto done; - - dbus_message_iter_get_basic(&entry, &key); - - dbus_message_iter_next(&entry); - - if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) - goto done; - - dbus_message_iter_recurse(&entry, &value); - - l = g_slist_find_custom(prop_handlers, key, - property_handler_compare); - - if (l) { - struct property_handler *handler = l->data; - - handler->callback(&value, handler->user_data); - } - - dbus_message_iter_next(&dict); - } - -done: - g_slist_foreach(prop_handlers, (GFunc) g_free, NULL); - g_slist_free(prop_handlers); -} - -static void parse_uuids(DBusMessageIter *array, gpointer user_data) -{ - GSList **uuids = user_data; - DBusMessageIter value; - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) { - const char *uuid; - - dbus_message_iter_get_basic(&value, &uuid); - - *uuids = g_slist_prepend(*uuids, (char *) uuid); - - dbus_message_iter_next(&value); - } -} - -static void parse_string(DBusMessageIter *iter, gpointer user_data) -{ - char **str = user_data; - int arg_type = dbus_message_iter_get_arg_type(iter); - - if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING) - return; - - dbus_message_iter_get_basic(iter, str); -} - -static void bluetooth_probe(GSList *uuids, const char *path, - const char *device, const char *adapter, - const char *alias) -{ - for (; uuids; uuids = uuids->next) { - struct bluetooth_profile *driver; - const char *uuid = uuids->data; - int err; - - driver = g_hash_table_lookup(uuid_hash, uuid); - if (driver == NULL) - continue; - - err = driver->probe(path, device, adapter, alias); - if (err == 0 || err == -EALREADY) - continue; - - ofono_error("%s probe: %s (%d)", driver->name, strerror(-err), - -err); - } -} - -static void device_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply; - const char *path = user_data; - const char *adapter = NULL; - const char *adapter_addr = NULL; - const char *device_addr = NULL; - const char *alias = NULL; - struct DBusError derr; - GSList *uuids = NULL; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Device.GetProperties replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, "UUIDs", parse_uuids, &uuids, - "Adapter", parse_string, &adapter, - "Address", parse_string, &device_addr, - "Alias", parse_string, &alias, NULL); - - if (adapter) - adapter_addr = g_hash_table_lookup(adapter_address_hash, - adapter); - - if (!device_addr || !adapter_addr) - goto done; - - bluetooth_probe(uuids, path, device_addr, adapter_addr, alias); - -done: - g_slist_free(uuids); - dbus_message_unref(reply); -} - -static void parse_devices(DBusMessageIter *array, gpointer user_data) -{ - DBusMessageIter value; - GSList **device_list = user_data; - - DBG(""); - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) - == DBUS_TYPE_OBJECT_PATH) { - const char *path; - - dbus_message_iter_get_basic(&value, &path); - - *device_list = g_slist_prepend(*device_list, (gpointer) path); - - dbus_message_iter_next(&value); - } -} - -static gboolean property_changed(DBusConnection *conn, DBusMessage *msg, - void *user_data) -{ - const char *property; - DBusMessageIter iter; - - dbus_message_iter_init(msg, &iter); - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return FALSE; - - dbus_message_iter_get_basic(&iter, &property); - if (g_str_equal(property, "UUIDs") == TRUE) { - GSList *uuids = NULL; - const char *path = dbus_message_get_path(msg); - DBusMessageIter variant; - - if (!dbus_message_iter_next(&iter)) - return FALSE; - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - return FALSE; - - dbus_message_iter_recurse(&iter, &variant); - - parse_uuids(&variant, &uuids); - - /* We need the full set of properties to be able to create - * the modem properly, including Adapter and Alias, so - * refetch everything again - */ - if (uuids) - bluetooth_send_with_reply(path, BLUEZ_DEVICE_INTERFACE, - "GetProperties", NULL, - device_properties_cb, g_strdup(path), - g_free, -1, DBUS_TYPE_INVALID); - } else if (g_str_equal(property, "Alias") == TRUE) { - const char *path = dbus_message_get_path(msg); - struct bluetooth_profile *profile; - const char *alias = NULL; - DBusMessageIter variant; - GHashTableIter hash_iter; - gpointer key, value; - - if (!dbus_message_iter_next(&iter)) - return FALSE; - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - return FALSE; - - dbus_message_iter_recurse(&iter, &variant); - - parse_string(&variant, &alias); - - g_hash_table_iter_init(&hash_iter, uuid_hash); - while (g_hash_table_iter_next(&hash_iter, &key, &value)) { - profile = value; - if (profile->set_alias) - profile->set_alias(path, alias); - } - } - - return TRUE; -} - -static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - const char *path = user_data; - DBusMessage *reply; - DBusError derr; - GSList *device_list = NULL; - GSList *l; - const char *addr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Adapter.GetProperties replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, - "Devices", parse_devices, &device_list, - "Address", parse_string, &addr, - NULL); - - DBG("Adapter Address: %s, Path: %s", addr, path); - g_hash_table_insert(adapter_address_hash, - g_strdup(path), g_strdup(addr)); - - for (l = device_list; l; l = l->next) { - const char *device = l->data; - - bluetooth_send_with_reply(device, BLUEZ_DEVICE_INTERFACE, - "GetProperties", NULL, - device_properties_cb, g_strdup(device), - g_free, -1, DBUS_TYPE_INVALID); - } - -done: - g_slist_free(device_list); - dbus_message_unref(reply); -} - -static void get_adapter_properties(const char *path, const char *handle, - gpointer user_data) -{ - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); -} - -static void remove_record(struct server *server) -{ - DBusMessage *msg; - - if (server->handle == 0) - return; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, adapter_any_path, - BLUEZ_SERVICE_INTERFACE, - "RemoveRecord"); - if (msg == NULL) { - ofono_error("Unable to allocate D-Bus RemoveRecord message"); - return; - } - - dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID); - g_dbus_send_message(connection, msg); - - ofono_info("Unregistered handle for channel %d: 0x%x", - server->channel, server->handle); -} - -static void cb_data_destroy(gpointer data) -{ - struct cb_data *cb_data = data; - - if (cb_data->source != 0) - g_source_remove(cb_data->source); - - g_free(cb_data->path); - g_free(cb_data); -} - -static void cancel_authorization(struct cb_data *user_data) -{ - DBusMessage *msg; - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, user_data->path, - BLUEZ_SERVICE_INTERFACE, - "CancelAuthorization"); - - if (msg == NULL) { - ofono_error("Unable to allocate D-Bus CancelAuthorization" - " message"); - return; - } - - g_dbus_send_message(connection, msg); -} - -static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data) -{ - struct cb_data *cb_data = data; - - cancel_authorization(cb_data); - cb_data->source = 0; - - return FALSE; -} - -static void auth_cb(DBusPendingCall *call, gpointer user_data) -{ - struct cb_data *cb_data = user_data; - struct server *server = cb_data->server; - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - GError *err = NULL; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("RequestAuthorization error: %s, %s", - derr.name, derr.message); - - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) - cancel_authorization(cb_data); - - dbus_error_free(&derr); - } else { - ofono_info("RequestAuthorization succeeded"); - - if (!bt_io_accept(cb_data->io, server->connect_cb, - server->user_data, NULL, &err)) { - ofono_error("%s", err->message); - g_error_free(err); - } - } - - dbus_message_unref(reply); -} - -static void new_connection(GIOChannel *io, gpointer user_data) -{ - struct server *server = user_data; - struct cb_data *cbd; - const char *addr; - GError *err = NULL; - char laddress[18], raddress[18]; - guint8 channel; - GHashTableIter iter; - gpointer key, value; - const char *path; - - bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE, laddress, - BT_IO_OPT_DEST, raddress, - BT_IO_OPT_CHANNEL, &channel, - BT_IO_OPT_INVALID); - if (err) { - ofono_error("%s", err->message); - g_error_free(err); - return; - } - - ofono_info("New connection for %s on channel %u from: %s,", laddress, - channel, raddress); - - path = NULL; - g_hash_table_iter_init(&iter, adapter_address_hash); - - while (g_hash_table_iter_next(&iter, &key, &value)) { - if (g_str_equal(laddress, value) == TRUE) { - path = key; - break; - } - } - - if (path == NULL) - return; - - cbd = g_try_new0(struct cb_data, 1); - if (cbd == NULL) { - ofono_error("Unable to allocate client cb_data structure"); - return; - } - - cbd->path = g_strdup(path); - cbd->server = server; - cbd->io = io; - - addr = raddress; - - if (bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, - "RequestAuthorization", NULL, - auth_cb, cbd, cb_data_destroy, - TIMEOUT, DBUS_TYPE_STRING, &addr, - DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID) < 0) { - ofono_error("Request Bluetooth authorization failed"); - return; - } - - ofono_info("RequestAuthorization(%s, 0x%x)", raddress, server->handle); - - cbd->source = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, - client_event, cbd); -} - -static void remove_service_handle(gpointer data, gpointer user_data) -{ - struct server *server = data; - - server->handle = 0; -} - -static void add_record_cb(DBusPendingCall *call, gpointer user_data) -{ - struct server *server = user_data; - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Replied with an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &server->handle, - DBUS_TYPE_INVALID); - - ofono_info("Registered handle for channel %d: 0x%x", - server->channel, server->handle); - -done: - dbus_message_unref(reply); -} - -static void add_record(gpointer data, gpointer user_data) -{ - struct server *server = data; - - if (server->sdp_record == NULL) - return; - - bluetooth_send_with_reply(adapter_any_path, - BLUEZ_SERVICE_INTERFACE, "AddRecord", - NULL, add_record_cb, server, NULL, -1, - DBUS_TYPE_STRING, &server->sdp_record, - DBUS_TYPE_INVALID); -} - -static void find_adapter_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError derr; - const char *path; - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Replied with an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - - adapter_any_path = g_strdup(path); - - g_slist_foreach(server_list, (GFunc) add_record, NULL); - -done: - dbus_message_unref(reply); -} - -static gboolean adapter_added(DBusConnection *conn, DBusMessage *message, - void *user_data) -{ - const char *path; - - dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); - - return TRUE; -} - -static void bluetooth_remove(gpointer key, gpointer value, gpointer user_data) -{ - struct bluetooth_profile *profile = value; - - profile->remove(user_data); -} - -static gboolean adapter_removed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path; - - if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) - return FALSE; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); - g_hash_table_remove(adapter_address_hash, path); - - return TRUE; -} - -static gboolean device_removed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path; - - if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) - return FALSE; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); - - return TRUE; -} - -static void parse_adapters(DBusMessageIter *array, gpointer user_data) -{ - DBusMessageIter value; - - DBG(""); - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) - == DBUS_TYPE_OBJECT_PATH) { - const char *path; - - dbus_message_iter_get_basic(&value, &path); - - DBG("Calling GetProperties on %s", path); - - bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, - "GetProperties", NULL, adapter_properties_cb, - g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); - - dbus_message_iter_next(&value); - } -} - -static void manager_properties_cb(DBusPendingCall *call, gpointer user_data) -{ - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - - if (dbus_set_error_from_message(&derr, reply)) { - ofono_error("Manager.GetProperties() replied an error: %s, %s", - derr.name, derr.message); - dbus_error_free(&derr); - goto done; - } - - DBG(""); - - bluetooth_parse_properties(reply, "Adapters", parse_adapters, NULL, - NULL); - -done: - dbus_message_unref(reply); -} - -static void bluetooth_connect(DBusConnection *conn, void *user_data) -{ - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties", - NULL, manager_properties_cb, NULL, NULL, -1, - DBUS_TYPE_INVALID); - - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "FindAdapter", - NULL, find_adapter_cb, NULL, NULL, -1, - DBUS_TYPE_STRING, &adapter_any_name, - DBUS_TYPE_INVALID); -} - -static void bluetooth_disconnect(DBusConnection *conn, void *user_data) -{ - if (uuid_hash == NULL) - return; - - g_hash_table_foreach(uuid_hash, bluetooth_remove, NULL); - - g_slist_foreach(server_list, (GFunc) remove_service_handle, NULL); -} - -static guint bluetooth_watch; -static guint adapter_added_watch; -static guint adapter_removed_watch; -static guint device_removed_watch; -static guint property_watch; - -static void bluetooth_ref(void) -{ - if (bluetooth_refcount > 0) - goto increment; - - connection = ofono_dbus_get_connection(); - - bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE, - bluetooth_connect, - bluetooth_disconnect, NULL, NULL); - - adapter_added_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, - NULL, BLUEZ_MANAGER_INTERFACE, - "AdapterAdded", - adapter_added, NULL, NULL); - - adapter_removed_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_MANAGER_INTERFACE, - "AdapterRemoved", - adapter_removed, NULL, NULL); - - device_removed_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_ADAPTER_INTERFACE, - "DeviceRemoved", - device_removed, NULL, NULL); - - property_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_DEVICE_INTERFACE, - "PropertyChanged", - property_changed, NULL, NULL); - - if (bluetooth_watch == 0 || adapter_added_watch == 0 || - adapter_removed_watch == 0 || property_watch == 0) { - goto remove; - } - - uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, NULL); - - adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - -increment: - g_atomic_int_inc(&bluetooth_refcount); - - return; - -remove: - g_dbus_remove_watch(connection, bluetooth_watch); - g_dbus_remove_watch(connection, adapter_added_watch); - g_dbus_remove_watch(connection, adapter_removed_watch); - g_dbus_remove_watch(connection, property_watch); -} - -static void bluetooth_unref(void) -{ - if (g_atomic_int_dec_and_test(&bluetooth_refcount) == FALSE) - return; - - g_free(adapter_any_path); - adapter_any_path = NULL; - - g_dbus_remove_watch(connection, bluetooth_watch); - g_dbus_remove_watch(connection, adapter_added_watch); - g_dbus_remove_watch(connection, adapter_removed_watch); - g_dbus_remove_watch(connection, property_watch); - - g_hash_table_destroy(uuid_hash); - g_hash_table_destroy(adapter_address_hash); -} - -void bluetooth_get_properties() -{ - g_hash_table_foreach(adapter_address_hash, - (GHFunc) get_adapter_properties, NULL); -} - -int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile) -{ - bluetooth_ref(); - - g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); - - g_hash_table_foreach(adapter_address_hash, - (GHFunc) get_adapter_properties, NULL); - - return 0; -} - -void bluetooth_unregister_uuid(const char *uuid) -{ - g_hash_table_remove(uuid_hash, uuid); - - bluetooth_unref(); -} - -struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, - ConnectFunc cb, gpointer user_data) -{ - struct server *server; - GError *err = NULL; - - server = g_try_new0(struct server, 1); - if (!server) - return NULL; - - server->channel = channel; - - server->io = bt_io_listen(BT_IO_RFCOMM, NULL, new_connection, - server, NULL, &err, - BT_IO_OPT_CHANNEL, server->channel, - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, - BT_IO_OPT_INVALID); - if (server->io == NULL) { - g_error_free(err); - g_free(server); - return NULL; - } - - bluetooth_ref(); - - if (sdp_record != NULL) - server->sdp_record = g_strdup(sdp_record); - - server->connect_cb = cb; - server->user_data = user_data; - - server_list = g_slist_prepend(server_list, server); - - if (adapter_any_path != NULL) - add_record(server, NULL); - - return server; -} - -void bluetooth_unregister_server(struct server *server) -{ - server_list = g_slist_remove(server_list, server); - - remove_record(server); - - if (server->io != NULL) { - g_io_channel_shutdown(server->io, TRUE, NULL); - g_io_channel_unref(server->io); - server->io = NULL; - } - - g_free(server->sdp_record); - g_free(server); - - bluetooth_unref(); -} - -OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION, - OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluetooth.h b/plugins/bluetooth.h deleted file mode 100644 index 4fc16ad..0000000 --- a/plugins/bluetooth.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> - * - * 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 - * - */ - -#include <ofono/modem.h> -#include <ofono/dbus.h> - -#define BLUEZ_SERVICE "org.bluez" -#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager" -#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter" -#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device" -#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service" -#define BLUEZ_SERIAL_INTERFACE BLUEZ_SERVICE ".Serial" - -#define DBUS_TIMEOUT 15 - -#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" -#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" -#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" -#define SAP_UUID "0000112d-0000-1000-8000-00805f9b34fb" - -struct bluetooth_profile { - const char *name; - int (*probe)(const char *device, const char *dev_addr, - const char *adapter_addr, const char *alias); - void (*remove)(const char *prefix); - void (*set_alias)(const char *device, const char *); -}; - -struct bluetooth_sap_driver { - const char *name; - int (*enable) (struct ofono_modem *modem, struct ofono_modem *sap_modem, - int bt_fd); - void (*pre_sim) (struct ofono_modem *modem); - void (*post_sim) (struct ofono_modem *modem); - void (*set_online) (struct ofono_modem *modem, ofono_bool_t online, - ofono_modem_online_cb_t cb, void *user_data); - void (*post_online) (struct ofono_modem *modem); - int (*disable) (struct ofono_modem *modem); -}; - -struct server; - -typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data); - -void bluetooth_get_properties(); -int bluetooth_register_uuid(const char *uuid, - struct bluetooth_profile *profile); -void bluetooth_unregister_uuid(const char *uuid); - -struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, - ConnectFunc cb, gpointer user_data); -void bluetooth_unregister_server(struct server *server); - -void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, - char *buf, int size); - -int bluetooth_send_with_reply(const char *path, const char *interface, - const char *method, DBusPendingCall **call, - DBusPendingCallNotifyFunction cb, - void *user_data, DBusFreeFunction free_func, - int timeout, int type, ...); -void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...); - -int bluetooth_sap_client_register(struct bluetooth_sap_driver *sap, - struct ofono_modem *modem); -void bluetooth_sap_client_unregister(struct ofono_modem *modem); diff --git a/plugins/bluez4.c b/plugins/bluez4.c new file mode 100644 index 0000000..6a29d9f --- /dev/null +++ b/plugins/bluez4.c @@ -0,0 +1,989 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2010 ProFUSION embedded systems + * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> + * + * 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 <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <glib.h> +#include <gdbus.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +#include <btio.h> +#include "bluez4.h" + +static DBusConnection *connection; +static GHashTable *uuid_hash = NULL; +static GHashTable *adapter_address_hash = NULL; +static gint bluetooth_refcount; +static GSList *server_list = NULL; +static const char *adapter_any_name = "any"; +static char *adapter_any_path; + +#define TIMEOUT 60 /* Timeout for user response (seconds) */ + +struct server { + guint8 channel; + char *sdp_record; + guint32 handle; + GIOChannel *io; + ConnectFunc connect_cb; + gpointer user_data; +}; + +struct cb_data { + struct server *server; + char *path; + guint source; + GIOChannel *io; +}; + +void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, + char *buf, int size) +{ + int i, j; + + for (i = 0, j = 0; adapter_addr[j] && i < size - 1; j++) + if (adapter_addr[j] >= '0' && adapter_addr[j] <= '9') + buf[i++] = adapter_addr[j]; + else if (adapter_addr[j] >= 'A' && adapter_addr[j] <= 'F') + buf[i++] = adapter_addr[j]; + + if (i < size - 1) + buf[i++] = '_'; + + for (j = 0; dev_addr[j] && i < size - 1; j++) + if (dev_addr[j] >= '0' && dev_addr[j] <= '9') + buf[i++] = dev_addr[j]; + else if (dev_addr[j] >= 'A' && dev_addr[j] <= 'F') + buf[i++] = dev_addr[j]; + + buf[i] = '\0'; +} + +int bluetooth_send_with_reply(const char *path, const char *interface, + const char *method, DBusPendingCall **call, + DBusPendingCallNotifyFunction cb, + void *user_data, DBusFreeFunction free_func, + int timeout, int type, ...) +{ + DBusMessage *msg; + DBusPendingCall *c; + va_list args; + int err; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, path, + interface, method); + if (msg == NULL) { + ofono_error("Unable to allocate new D-Bus %s message", method); + err = -ENOMEM; + goto fail; + } + + va_start(args, type); + + if (!dbus_message_append_args_valist(msg, type, args)) { + va_end(args); + err = -EIO; + goto fail; + } + + va_end(args); + + if (timeout > 0) + timeout *= 1000; + + if (!dbus_connection_send_with_reply(connection, msg, &c, timeout)) { + ofono_error("Sending %s failed", method); + err = -EIO; + goto fail; + } + + if (call != NULL) + *call = c; + + dbus_pending_call_set_notify(c, cb, user_data, free_func); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); + + return 0; + +fail: + if (free_func && user_data) + free_func(user_data); + + if (msg) + dbus_message_unref(msg); + + return err; +} + +typedef void (*PropertyHandler)(DBusMessageIter *iter, gpointer user_data); + +struct property_handler { + const char *property; + PropertyHandler callback; + gpointer user_data; +}; + +static gint property_handler_compare(gconstpointer a, gconstpointer b) +{ + const struct property_handler *handler = a; + const char *property = b; + + return strcmp(handler->property, property); +} + +void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...) +{ + va_list args; + GSList *prop_handlers = NULL; + DBusMessageIter array, dict; + + va_start(args, property); + + while (property != NULL) { + struct property_handler *handler = + g_new0(struct property_handler, 1); + + handler->property = property; + handler->callback = va_arg(args, PropertyHandler); + handler->user_data = va_arg(args, gpointer); + + property = va_arg(args, const char *); + + prop_handlers = g_slist_prepend(prop_handlers, handler); + } + + va_end(args); + + if (dbus_message_iter_init(reply, &array) == FALSE) + goto done; + + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY) + goto done; + + dbus_message_iter_recurse(&array, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value; + const char *key; + GSList *l; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + goto done; + + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) + goto done; + + dbus_message_iter_recurse(&entry, &value); + + l = g_slist_find_custom(prop_handlers, key, + property_handler_compare); + + if (l) { + struct property_handler *handler = l->data; + + handler->callback(&value, handler->user_data); + } + + dbus_message_iter_next(&dict); + } + +done: + g_slist_foreach(prop_handlers, (GFunc) g_free, NULL); + g_slist_free(prop_handlers); +} + +static void parse_uuids(DBusMessageIter *array, gpointer user_data) +{ + GSList **uuids = user_data; + DBusMessageIter value; + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) { + const char *uuid; + + dbus_message_iter_get_basic(&value, &uuid); + + *uuids = g_slist_prepend(*uuids, (char *) uuid); + + dbus_message_iter_next(&value); + } +} + +static void parse_string(DBusMessageIter *iter, gpointer user_data) +{ + char **str = user_data; + int arg_type = dbus_message_iter_get_arg_type(iter); + + if (arg_type != DBUS_TYPE_OBJECT_PATH && arg_type != DBUS_TYPE_STRING) + return; + + dbus_message_iter_get_basic(iter, str); +} + +static void bluetooth_probe(GSList *uuids, const char *path, + const char *device, const char *adapter, + const char *alias) +{ + for (; uuids; uuids = uuids->next) { + struct bluetooth_profile *driver; + const char *uuid = uuids->data; + int err; + + driver = g_hash_table_lookup(uuid_hash, uuid); + if (driver == NULL) + continue; + + err = driver->probe(path, device, adapter, alias); + if (err == 0 || err == -EALREADY) + continue; + + ofono_error("%s probe: %s (%d)", driver->name, strerror(-err), + -err); + } +} + +static void device_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + const char *path = user_data; + const char *adapter = NULL; + const char *adapter_addr = NULL; + const char *device_addr = NULL; + const char *alias = NULL; + struct DBusError derr; + GSList *uuids = NULL; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Device.GetProperties replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, "UUIDs", parse_uuids, &uuids, + "Adapter", parse_string, &adapter, + "Address", parse_string, &device_addr, + "Alias", parse_string, &alias, NULL); + + if (adapter) + adapter_addr = g_hash_table_lookup(adapter_address_hash, + adapter); + + if (!device_addr || !adapter_addr) + goto done; + + bluetooth_probe(uuids, path, device_addr, adapter_addr, alias); + +done: + g_slist_free(uuids); + dbus_message_unref(reply); +} + +static void parse_devices(DBusMessageIter *array, gpointer user_data) +{ + DBusMessageIter value; + GSList **device_list = user_data; + + DBG(""); + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) + == DBUS_TYPE_OBJECT_PATH) { + const char *path; + + dbus_message_iter_get_basic(&value, &path); + + *device_list = g_slist_prepend(*device_list, (gpointer) path); + + dbus_message_iter_next(&value); + } +} + +static gboolean property_changed(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + const char *property; + DBusMessageIter iter; + + dbus_message_iter_init(msg, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return FALSE; + + dbus_message_iter_get_basic(&iter, &property); + if (g_str_equal(property, "UUIDs") == TRUE) { + GSList *uuids = NULL; + const char *path = dbus_message_get_path(msg); + DBusMessageIter variant; + + if (!dbus_message_iter_next(&iter)) + return FALSE; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return FALSE; + + dbus_message_iter_recurse(&iter, &variant); + + parse_uuids(&variant, &uuids); + + /* We need the full set of properties to be able to create + * the modem properly, including Adapter and Alias, so + * refetch everything again + */ + if (uuids) + bluetooth_send_with_reply(path, BLUEZ_DEVICE_INTERFACE, + "GetProperties", NULL, + device_properties_cb, g_strdup(path), + g_free, -1, DBUS_TYPE_INVALID); + } else if (g_str_equal(property, "Alias") == TRUE) { + const char *path = dbus_message_get_path(msg); + struct bluetooth_profile *profile; + const char *alias = NULL; + DBusMessageIter variant; + GHashTableIter hash_iter; + gpointer key, value; + + if (!dbus_message_iter_next(&iter)) + return FALSE; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return FALSE; + + dbus_message_iter_recurse(&iter, &variant); + + parse_string(&variant, &alias); + + g_hash_table_iter_init(&hash_iter, uuid_hash); + while (g_hash_table_iter_next(&hash_iter, &key, &value)) { + profile = value; + if (profile->set_alias) + profile->set_alias(path, alias); + } + } + + return TRUE; +} + +static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + const char *path = user_data; + DBusMessage *reply; + DBusError derr; + GSList *device_list = NULL; + GSList *l; + const char *addr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Adapter.GetProperties replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, + "Devices", parse_devices, &device_list, + "Address", parse_string, &addr, + NULL); + + DBG("Adapter Address: %s, Path: %s", addr, path); + g_hash_table_insert(adapter_address_hash, + g_strdup(path), g_strdup(addr)); + + for (l = device_list; l; l = l->next) { + const char *device = l->data; + + bluetooth_send_with_reply(device, BLUEZ_DEVICE_INTERFACE, + "GetProperties", NULL, + device_properties_cb, g_strdup(device), + g_free, -1, DBUS_TYPE_INVALID); + } + +done: + g_slist_free(device_list); + dbus_message_unref(reply); +} + +static void get_adapter_properties(const char *path, const char *handle, + gpointer user_data) +{ + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); +} + +static void remove_record(struct server *server) +{ + DBusMessage *msg; + + if (server->handle == 0) + return; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, adapter_any_path, + BLUEZ_SERVICE_INTERFACE, + "RemoveRecord"); + if (msg == NULL) { + ofono_error("Unable to allocate D-Bus RemoveRecord message"); + return; + } + + dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID); + g_dbus_send_message(connection, msg); + + ofono_info("Unregistered handle for channel %d: 0x%x", + server->channel, server->handle); +} + +static void cb_data_destroy(gpointer data) +{ + struct cb_data *cb_data = data; + + if (cb_data->source != 0) + g_source_remove(cb_data->source); + + g_free(cb_data->path); + g_free(cb_data); +} + +static void cancel_authorization(struct cb_data *user_data) +{ + DBusMessage *msg; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, user_data->path, + BLUEZ_SERVICE_INTERFACE, + "CancelAuthorization"); + + if (msg == NULL) { + ofono_error("Unable to allocate D-Bus CancelAuthorization" + " message"); + return; + } + + g_dbus_send_message(connection, msg); +} + +static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ + struct cb_data *cb_data = data; + + cancel_authorization(cb_data); + cb_data->source = 0; + + return FALSE; +} + +static void auth_cb(DBusPendingCall *call, gpointer user_data) +{ + struct cb_data *cb_data = user_data; + struct server *server = cb_data->server; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + GError *err = NULL; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("RequestAuthorization error: %s, %s", + derr.name, derr.message); + + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) + cancel_authorization(cb_data); + + dbus_error_free(&derr); + } else { + ofono_info("RequestAuthorization succeeded"); + + if (!bt_io_accept(cb_data->io, server->connect_cb, + server->user_data, NULL, &err)) { + ofono_error("%s", err->message); + g_error_free(err); + } + } + + dbus_message_unref(reply); +} + +static void new_connection(GIOChannel *io, gpointer user_data) +{ + struct server *server = user_data; + struct cb_data *cbd; + const char *addr; + GError *err = NULL; + char laddress[18], raddress[18]; + guint8 channel; + GHashTableIter iter; + gpointer key, value; + const char *path; + + bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE, laddress, + BT_IO_OPT_DEST, raddress, + BT_IO_OPT_CHANNEL, &channel, + BT_IO_OPT_INVALID); + if (err) { + ofono_error("%s", err->message); + g_error_free(err); + return; + } + + ofono_info("New connection for %s on channel %u from: %s,", laddress, + channel, raddress); + + path = NULL; + g_hash_table_iter_init(&iter, adapter_address_hash); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + if (g_str_equal(laddress, value) == TRUE) { + path = key; + break; + } + } + + if (path == NULL) + return; + + cbd = g_try_new0(struct cb_data, 1); + if (cbd == NULL) { + ofono_error("Unable to allocate client cb_data structure"); + return; + } + + cbd->path = g_strdup(path); + cbd->server = server; + cbd->io = io; + + addr = raddress; + + if (bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, + "RequestAuthorization", NULL, + auth_cb, cbd, cb_data_destroy, + TIMEOUT, DBUS_TYPE_STRING, &addr, + DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID) < 0) { + ofono_error("Request Bluetooth authorization failed"); + return; + } + + ofono_info("RequestAuthorization(%s, 0x%x)", raddress, server->handle); + + cbd->source = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, + client_event, cbd); +} + +static void remove_service_handle(gpointer data, gpointer user_data) +{ + struct server *server = data; + + server->handle = 0; +} + +static void add_record_cb(DBusPendingCall *call, gpointer user_data) +{ + struct server *server = user_data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID); + + ofono_info("Registered handle for channel %d: 0x%x", + server->channel, server->handle); + +done: + dbus_message_unref(reply); +} + +static void add_record(gpointer data, gpointer user_data) +{ + struct server *server = data; + + if (server->sdp_record == NULL) + return; + + bluetooth_send_with_reply(adapter_any_path, + BLUEZ_SERVICE_INTERFACE, "AddRecord", + NULL, add_record_cb, server, NULL, -1, + DBUS_TYPE_STRING, &server->sdp_record, + DBUS_TYPE_INVALID); +} + +static void find_adapter_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + const char *path; + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Replied with an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + adapter_any_path = g_strdup(path); + + g_slist_foreach(server_list, (GFunc) add_record, NULL); + +done: + dbus_message_unref(reply); +} + +static gboolean adapter_added(DBusConnection *conn, DBusMessage *message, + void *user_data) +{ + const char *path; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); + + return TRUE; +} + +static void bluetooth_remove(gpointer key, gpointer value, gpointer user_data) +{ + struct bluetooth_profile *profile = value; + + profile->remove(user_data); +} + +static gboolean adapter_removed(DBusConnection *conn, + DBusMessage *message, void *user_data) +{ + const char *path; + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID) == FALSE) + return FALSE; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); + g_hash_table_remove(adapter_address_hash, path); + + return TRUE; +} + +static gboolean device_removed(DBusConnection *conn, + DBusMessage *message, void *user_data) +{ + const char *path; + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID) == FALSE) + return FALSE; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, (gpointer) path); + + return TRUE; +} + +static void parse_adapters(DBusMessageIter *array, gpointer user_data) +{ + DBusMessageIter value; + + DBG(""); + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(array, &value); + + while (dbus_message_iter_get_arg_type(&value) + == DBUS_TYPE_OBJECT_PATH) { + const char *path; + + dbus_message_iter_get_basic(&value, &path); + + DBG("Calling GetProperties on %s", path); + + bluetooth_send_with_reply(path, BLUEZ_ADAPTER_INTERFACE, + "GetProperties", NULL, adapter_properties_cb, + g_strdup(path), g_free, -1, DBUS_TYPE_INVALID); + + dbus_message_iter_next(&value); + } +} + +static void manager_properties_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("Manager.GetProperties() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + + bluetooth_parse_properties(reply, "Adapters", parse_adapters, NULL, + NULL); + +done: + dbus_message_unref(reply); +} + +static void bluetooth_connect(DBusConnection *conn, void *user_data) +{ + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties", + NULL, manager_properties_cb, NULL, NULL, -1, + DBUS_TYPE_INVALID); + + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "FindAdapter", + NULL, find_adapter_cb, NULL, NULL, -1, + DBUS_TYPE_STRING, &adapter_any_name, + DBUS_TYPE_INVALID); +} + +static void bluetooth_disconnect(DBusConnection *conn, void *user_data) +{ + if (uuid_hash == NULL) + return; + + g_hash_table_foreach(uuid_hash, bluetooth_remove, NULL); + + g_slist_foreach(server_list, (GFunc) remove_service_handle, NULL); +} + +static guint bluetooth_watch; +static guint adapter_added_watch; +static guint adapter_removed_watch; +static guint device_removed_watch; +static guint property_watch; + +static void bluetooth_ref(void) +{ + if (bluetooth_refcount > 0) + goto increment; + + connection = ofono_dbus_get_connection(); + + bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE, + bluetooth_connect, + bluetooth_disconnect, NULL, NULL); + + adapter_added_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, + NULL, BLUEZ_MANAGER_INTERFACE, + "AdapterAdded", + adapter_added, NULL, NULL); + + adapter_removed_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_MANAGER_INTERFACE, + "AdapterRemoved", + adapter_removed, NULL, NULL); + + device_removed_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_ADAPTER_INTERFACE, + "DeviceRemoved", + device_removed, NULL, NULL); + + property_watch = g_dbus_add_signal_watch(connection, + BLUEZ_SERVICE, NULL, + BLUEZ_DEVICE_INTERFACE, + "PropertyChanged", + property_changed, NULL, NULL); + + if (bluetooth_watch == 0 || adapter_added_watch == 0 || + adapter_removed_watch == 0 || property_watch == 0) { + goto remove; + } + + uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); + + adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + +increment: + g_atomic_int_inc(&bluetooth_refcount); + + return; + +remove: + g_dbus_remove_watch(connection, bluetooth_watch); + g_dbus_remove_watch(connection, adapter_added_watch); + g_dbus_remove_watch(connection, adapter_removed_watch); + g_dbus_remove_watch(connection, property_watch); +} + +static void bluetooth_unref(void) +{ + if (g_atomic_int_dec_and_test(&bluetooth_refcount) == FALSE) + return; + + g_free(adapter_any_path); + adapter_any_path = NULL; + + g_dbus_remove_watch(connection, bluetooth_watch); + g_dbus_remove_watch(connection, adapter_added_watch); + g_dbus_remove_watch(connection, adapter_removed_watch); + g_dbus_remove_watch(connection, property_watch); + + g_hash_table_destroy(uuid_hash); + g_hash_table_destroy(adapter_address_hash); +} + +void bluetooth_get_properties() +{ + g_hash_table_foreach(adapter_address_hash, + (GHFunc) get_adapter_properties, NULL); +} + +int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile) +{ + bluetooth_ref(); + + g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); + + g_hash_table_foreach(adapter_address_hash, + (GHFunc) get_adapter_properties, NULL); + + return 0; +} + +void bluetooth_unregister_uuid(const char *uuid) +{ + g_hash_table_remove(uuid_hash, uuid); + + bluetooth_unref(); +} + +struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, + ConnectFunc cb, gpointer user_data) +{ + struct server *server; + GError *err = NULL; + + server = g_try_new0(struct server, 1); + if (!server) + return NULL; + + server->channel = channel; + + server->io = bt_io_listen(BT_IO_RFCOMM, NULL, new_connection, + server, NULL, &err, + BT_IO_OPT_CHANNEL, server->channel, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, + BT_IO_OPT_INVALID); + if (server->io == NULL) { + g_error_free(err); + g_free(server); + return NULL; + } + + bluetooth_ref(); + + if (sdp_record != NULL) + server->sdp_record = g_strdup(sdp_record); + + server->connect_cb = cb; + server->user_data = user_data; + + server_list = g_slist_prepend(server_list, server); + + if (adapter_any_path != NULL) + add_record(server, NULL); + + return server; +} + +void bluetooth_unregister_server(struct server *server) +{ + server_list = g_slist_remove(server_list, server); + + remove_record(server); + + if (server->io != NULL) { + g_io_channel_shutdown(server->io, TRUE, NULL); + g_io_channel_unref(server->io); + server->io = NULL; + } + + g_free(server->sdp_record); + g_free(server); + + bluetooth_unref(); +} + +OFONO_PLUGIN_DEFINE(bluez4, "Bluetooth Utils Plugins", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluez4.h b/plugins/bluez4.h new file mode 100644 index 0000000..4fc16ad --- /dev/null +++ b/plugins/bluez4.h @@ -0,0 +1,84 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org> + * + * 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 + * + */ + +#include <ofono/modem.h> +#include <ofono/dbus.h> + +#define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager" +#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter" +#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device" +#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service" +#define BLUEZ_SERIAL_INTERFACE BLUEZ_SERVICE ".Serial" + +#define DBUS_TIMEOUT 15 + +#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb" +#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" +#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" +#define SAP_UUID "0000112d-0000-1000-8000-00805f9b34fb" + +struct bluetooth_profile { + const char *name; + int (*probe)(const char *device, const char *dev_addr, + const char *adapter_addr, const char *alias); + void (*remove)(const char *prefix); + void (*set_alias)(const char *device, const char *); +}; + +struct bluetooth_sap_driver { + const char *name; + int (*enable) (struct ofono_modem *modem, struct ofono_modem *sap_modem, + int bt_fd); + void (*pre_sim) (struct ofono_modem *modem); + void (*post_sim) (struct ofono_modem *modem); + void (*set_online) (struct ofono_modem *modem, ofono_bool_t online, + ofono_modem_online_cb_t cb, void *user_data); + void (*post_online) (struct ofono_modem *modem); + int (*disable) (struct ofono_modem *modem); +}; + +struct server; + +typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data); + +void bluetooth_get_properties(); +int bluetooth_register_uuid(const char *uuid, + struct bluetooth_profile *profile); +void bluetooth_unregister_uuid(const char *uuid); + +struct server *bluetooth_register_server(guint8 channel, const char *sdp_record, + ConnectFunc cb, gpointer user_data); +void bluetooth_unregister_server(struct server *server); + +void bluetooth_create_path(const char *dev_addr, const char *adapter_addr, + char *buf, int size); + +int bluetooth_send_with_reply(const char *path, const char *interface, + const char *method, DBusPendingCall **call, + DBusPendingCallNotifyFunction cb, + void *user_data, DBusFreeFunction free_func, + int timeout, int type, ...); +void bluetooth_parse_properties(DBusMessage *reply, const char *property, ...); + +int bluetooth_sap_client_register(struct bluetooth_sap_driver *sap, + struct ofono_modem *modem); +void bluetooth_sap_client_unregister(struct ofono_modem *modem); diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c index 75b62eb..fc8bde4 100644 --- a/plugins/dun_gw.c +++ b/plugins/dun_gw.c @@ -33,7 +33,7 @@ #include <ofono/modem.h> #include <gdbus.h> -#include "bluetooth.h" +#include "bluez4.h" #define DUN_GW_CHANNEL 1 diff --git a/plugins/hfp_ag.c b/plugins/hfp_ag.c index c2d1d30..12374ad 100644 --- a/plugins/hfp_ag.c +++ b/plugins/hfp_ag.c @@ -33,7 +33,7 @@ #include <ofono/modem.h> #include <gdbus.h> -#include "bluetooth.h" +#include "bluez4.h" #define HFP_AG_CHANNEL 13 diff --git a/plugins/hfp_hf.c b/plugins/hfp_hf.c deleted file mode 100644 index 7c500e3..0000000 --- a/plugins/hfp_hf.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * - * oFono - Open Source Telephony - * - * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. - * Copyright (C) 2010 ProFUSION embedded systems - * Copyright (C) 2011 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 <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <glib.h> -#include <gatchat.h> -#include <gattty.h> -#include <gdbus.h> -#include <ofono.h> - -#define OFONO_API_SUBJECT_TO_CHANGE -#include <ofono/plugin.h> -#include <ofono/log.h> -#include <ofono/modem.h> -#include <ofono/devinfo.h> -#include <ofono/netreg.h> -#include <ofono/voicecall.h> -#include <ofono/call-volume.h> -#include <ofono/handsfree.h> - -#include <drivers/hfpmodem/slc.h> - -#include "bluetooth.h" - -#define BLUEZ_GATEWAY_INTERFACE BLUEZ_SERVICE ".HandsfreeGateway" - -#define HFP_AGENT_INTERFACE "org.bluez.HandsfreeAgent" -#define HFP_AGENT_ERROR_INTERFACE "org.bluez.Error" - -#ifndef DBUS_TYPE_UNIX_FD -#define DBUS_TYPE_UNIX_FD -1 -#endif - -static DBusConnection *connection; -static GHashTable *modem_hash = NULL; - -struct hfp_data { - struct hfp_slc_info info; - char *handsfree_path; - char *handsfree_address; - DBusMessage *slc_msg; - gboolean agent_registered; - DBusPendingCall *call; -}; - -static void hfp_debug(const char *str, void *user_data) -{ - const char *prefix = user_data; - - ofono_info("%s%s", prefix, str); -} - -static void slc_established(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - ofono_modem_set_powered(modem, TRUE); - - msg = dbus_message_new_method_return(data->slc_msg); - g_dbus_send_message(connection, msg); - dbus_message_unref(data->slc_msg); - data->slc_msg = NULL; - - ofono_info("Service level connection established"); -} - -static void slc_failed(gpointer userdata) -{ - struct ofono_modem *modem = userdata; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - msg = g_dbus_create_error(data->slc_msg, HFP_AGENT_ERROR_INTERFACE - ".Failed", - "HFP Handshake failed"); - g_dbus_send_message(connection, msg); - dbus_message_unref(data->slc_msg); - data->slc_msg = NULL; - - ofono_error("Service level connection failed"); - ofono_modem_set_powered(modem, FALSE); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; -} - -static void hfp_disconnected_cb(gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - - ofono_modem_set_powered(modem, FALSE); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; -} - -/* either oFono or Phone could request SLC connection */ -static int service_level_connection(struct ofono_modem *modem, int fd) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - GIOChannel *io; - GAtSyntax *syntax; - GAtChat *chat; - - io = g_io_channel_unix_new(fd); - if (io == NULL) { - ofono_error("Service level connection failed: %s (%d)", - strerror(errno), errno); - return -EIO; - } - - syntax = g_at_syntax_new_gsm_permissive(); - chat = g_at_chat_new(io, syntax); - g_at_syntax_unref(syntax); - g_io_channel_unref(io); - - if (chat == NULL) - return -ENOMEM; - - g_at_chat_set_disconnect_function(chat, hfp_disconnected_cb, modem); - - if (getenv("OFONO_AT_DEBUG")) - g_at_chat_set_debug(chat, hfp_debug, ""); - - data->info.chat = chat; - hfp_slc_establish(&data->info, slc_established, slc_failed, modem); - - return -EINPROGRESS; -} - -static DBusMessage *hfp_agent_new_connection(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - int fd, err; - struct ofono_modem *modem = data; - struct hfp_data *hfp_data = ofono_modem_get_data(modem); - guint16 version; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UNIX_FD, &fd, - DBUS_TYPE_UINT16, &version, DBUS_TYPE_INVALID)) - return __ofono_error_invalid_args(msg); - - hfp_slc_info_init(&hfp_data->info, version); - - err = service_level_connection(modem, fd); - if (err < 0 && err != -EINPROGRESS) - return __ofono_error_failed(msg); - - hfp_data->slc_msg = msg; - dbus_message_ref(msg); - - return NULL; -} - -static DBusMessage *hfp_agent_release(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct ofono_modem *modem = data; - struct hfp_data *hfp_data = ofono_modem_get_data(modem); - const char *obj_path = ofono_modem_get_path(modem); - - g_dbus_unregister_interface(connection, obj_path, HFP_AGENT_INTERFACE); - hfp_data->agent_registered = FALSE; - - g_hash_table_remove(modem_hash, hfp_data->handsfree_path); - ofono_modem_remove(modem); - - return dbus_message_new_method_return(msg); -} - -static const GDBusMethodTable agent_methods[] = { - { GDBUS_ASYNC_METHOD("NewConnection", - GDBUS_ARGS({ "fd", "h" }, { "version", "q" }), - NULL, hfp_agent_new_connection) }, - { GDBUS_METHOD("Release", NULL, NULL, hfp_agent_release) }, - { } -}; - -static int hfp_hf_probe(const char *device, const char *dev_addr, - const char *adapter_addr, const char *alias) -{ - struct ofono_modem *modem; - struct hfp_data *data; - char buf[256]; - - /* We already have this device in our hash, ignore */ - if (g_hash_table_lookup(modem_hash, device) != NULL) - return -EALREADY; - - ofono_info("Using device: %s, devaddr: %s, adapter: %s", - device, dev_addr, adapter_addr); - - strcpy(buf, "hfp/"); - bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4); - - modem = ofono_modem_create(buf, "hfp"); - if (modem == NULL) - return -ENOMEM; - - data = g_try_new0(struct hfp_data, 1); - if (data == NULL) - goto free; - - data->handsfree_path = g_strdup(device); - if (data->handsfree_path == NULL) - goto free; - - data->handsfree_address = g_strdup(dev_addr); - if (data->handsfree_address == NULL) - goto free; - - ofono_modem_set_data(modem, data); - ofono_modem_set_name(modem, alias); - ofono_modem_register(modem); - - g_hash_table_insert(modem_hash, g_strdup(device), modem); - - return 0; - -free: - if (data != NULL) - g_free(data->handsfree_path); - - g_free(data); - ofono_modem_remove(modem); - - return -ENOMEM; -} - -static gboolean hfp_remove_modem(gpointer key, gpointer value, - gpointer user_data) -{ - struct ofono_modem *modem = value; - const char *device = key; - const char *prefix = user_data; - - if (prefix && g_str_has_prefix(device, prefix) == FALSE) - return FALSE; - - ofono_modem_remove(modem); - - return TRUE; -} - -static void hfp_hf_remove(const char *prefix) -{ - DBG("%s", prefix); - - if (modem_hash == NULL) - return; - - g_hash_table_foreach_remove(modem_hash, hfp_remove_modem, - (gpointer) prefix); -} - -static void hfp_hf_set_alias(const char *device, const char *alias) -{ - struct ofono_modem *modem; - - if (device == NULL || alias == NULL) - return; - - modem = g_hash_table_lookup(modem_hash, device); - if (modem == NULL) - return; - - ofono_modem_set_name(modem, alias); -} - -static int hfp_register_ofono_handsfree(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - DBG("Registering oFono Agent to bluetooth daemon"); - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "RegisterAgent"); - if (msg == NULL) - return -ENOMEM; - - dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, - DBUS_TYPE_INVALID); - - g_dbus_send_message(connection, msg); - return 0; -} - -static int hfp_unregister_ofono_handsfree(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *msg; - - DBG("Unregistering oFono Agent from bluetooth daemon"); - - msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "UnregisterAgent"); - if (msg == NULL) - return -ENOMEM; - - dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, - DBUS_TYPE_INVALID); - - g_dbus_send_message(connection, msg); - return 0; -} - -static int hfp_probe(struct ofono_modem *modem) -{ - const char *obj_path = ofono_modem_get_path(modem); - struct hfp_data *data = ofono_modem_get_data(modem); - - if (data == NULL) - return -EINVAL; - - g_dbus_register_interface(connection, obj_path, HFP_AGENT_INTERFACE, - agent_methods, NULL, NULL, modem, NULL); - - data->agent_registered = TRUE; - - if (hfp_register_ofono_handsfree(modem) != 0) - return -EINVAL; - - return 0; -} - -static void hfp_remove(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - const char *obj_path = ofono_modem_get_path(modem); - - if (data->call != NULL) - dbus_pending_call_cancel(data->call); - - if (g_dbus_unregister_interface(connection, obj_path, - HFP_AGENT_INTERFACE)) - hfp_unregister_ofono_handsfree(modem); - - g_free(data->handsfree_address); - g_free(data->handsfree_path); - g_free(data); - - ofono_modem_set_data(modem, NULL); -} - -static void hfp_connect_reply(DBusPendingCall *call, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusError derr; - DBusMessage *reply, *msg; - - reply = dbus_pending_call_steal_reply(call); - - if (ofono_modem_get_powered(modem)) - goto done; - - dbus_error_init(&derr); - if (!dbus_set_error_from_message(&derr, reply)) - goto done; - - DBG("Connect reply: %s", derr.message); - - if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { - msg = dbus_message_new_method_call(BLUEZ_SERVICE, - data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Disconnect"); - if (msg == NULL) - ofono_error("Disconnect failed"); - else - g_dbus_send_message(connection, msg); - } - - ofono_modem_set_powered(modem, FALSE); - - dbus_error_free(&derr); - -done: - dbus_message_unref(reply); - data->call = NULL; -} - -/* power up hardware */ -static int hfp_enable(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - int status; - - DBG("%p", modem); - - status = bluetooth_send_with_reply(data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Connect", - &data->call, hfp_connect_reply, - modem, NULL, - DBUS_TIMEOUT, DBUS_TYPE_INVALID); - - if (status < 0) - return -EINVAL; - - return -EINPROGRESS; -} - -static void hfp_power_down(DBusPendingCall *call, gpointer user_data) -{ - struct ofono_modem *modem = user_data; - struct hfp_data *data = ofono_modem_get_data(modem); - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - DBG("Disconnect reply: %s", derr.message); - dbus_error_free(&derr); - goto done; - } - - ofono_modem_set_powered(modem, FALSE); - -done: - dbus_message_unref(reply); - data->call = NULL; -} - -static int hfp_disable(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - int status; - - DBG("%p", modem); - - g_at_chat_unref(data->info.chat); - data->info.chat = NULL; - - if (data->agent_registered) { - status = bluetooth_send_with_reply(data->handsfree_path, - BLUEZ_GATEWAY_INTERFACE, "Disconnect", - &data->call, hfp_power_down, - modem, NULL, - DBUS_TIMEOUT, DBUS_TYPE_INVALID); - - if (status < 0) - return -EINVAL; - } - - return -EINPROGRESS; -} - -static void hfp_pre_sim(struct ofono_modem *modem) -{ - struct hfp_data *data = ofono_modem_get_data(modem); - - DBG("%p", modem); - - ofono_devinfo_create(modem, 0, "hfpmodem", data->handsfree_address); - ofono_voicecall_create(modem, 0, "hfpmodem", &data->info); - ofono_netreg_create(modem, 0, "hfpmodem", &data->info); - ofono_call_volume_create(modem, 0, "hfpmodem", &data->info); - ofono_handsfree_create(modem, 0, "hfpmodem", &data->info); -} - -static void hfp_post_sim(struct ofono_modem *modem) -{ - DBG("%p", modem); -} - -static struct ofono_modem_driver hfp_driver = { - .name = "hfp", - .modem_type = OFONO_MODEM_TYPE_HFP, - .probe = hfp_probe, - .remove = hfp_remove, - .enable = hfp_enable, - .disable = hfp_disable, - .pre_sim = hfp_pre_sim, - .post_sim = hfp_post_sim, -}; - -static struct bluetooth_profile hfp_hf = { - .name = "hfp_hf", - .probe = hfp_hf_probe, - .remove = hfp_hf_remove, - .set_alias = hfp_hf_set_alias, -}; - -static int hfp_init(void) -{ - int err; - - if (DBUS_TYPE_UNIX_FD < 0) - return -EBADF; - - connection = ofono_dbus_get_connection(); - - err = ofono_modem_driver_register(&hfp_driver); - if (err < 0) - return err; - - err = bluetooth_register_uuid(HFP_AG_UUID, &hfp_hf); - if (err < 0) { - ofono_modem_driver_unregister(&hfp_driver); - return err; - } - - modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, NULL); - - return 0; -} - -static void hfp_exit(void) -{ - bluetooth_unregister_uuid(HFP_AG_UUID); - ofono_modem_driver_unregister(&hfp_driver); - - g_hash_table_destroy(modem_hash); -} - -OFONO_PLUGIN_DEFINE(hfp, "Hands-Free Profile Plugins", VERSION, - OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) diff --git a/plugins/hfp_hf_bluez4.c b/plugins/hfp_hf_bluez4.c new file mode 100644 index 0000000..450c183 --- /dev/null +++ b/plugins/hfp_hf_bluez4.c @@ -0,0 +1,552 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2010 ProFUSION embedded systems + * Copyright (C) 2011 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 <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <glib.h> +#include <gatchat.h> +#include <gattty.h> +#include <gdbus.h> +#include <ofono.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> +#include <ofono/modem.h> +#include <ofono/devinfo.h> +#include <ofono/netreg.h> +#include <ofono/voicecall.h> +#include <ofono/call-volume.h> +#include <ofono/handsfree.h> + +#include <drivers/hfpmodem/slc.h> + +#include "bluez4.h" + +#define BLUEZ_GATEWAY_INTERFACE BLUEZ_SERVICE ".HandsfreeGateway" + +#define HFP_AGENT_INTERFACE "org.bluez.HandsfreeAgent" +#define HFP_AGENT_ERROR_INTERFACE "org.bluez.Error" + +#ifndef DBUS_TYPE_UNIX_FD +#define DBUS_TYPE_UNIX_FD -1 +#endif + +static DBusConnection *connection; +static GHashTable *modem_hash = NULL; + +struct hfp_data { + struct hfp_slc_info info; + char *handsfree_path; + char *handsfree_address; + DBusMessage *slc_msg; + gboolean agent_registered; + DBusPendingCall *call; +}; + +static void hfp_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + ofono_info("%s%s", prefix, str); +} + +static void slc_established(gpointer userdata) +{ + struct ofono_modem *modem = userdata; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + ofono_modem_set_powered(modem, TRUE); + + msg = dbus_message_new_method_return(data->slc_msg); + g_dbus_send_message(connection, msg); + dbus_message_unref(data->slc_msg); + data->slc_msg = NULL; + + ofono_info("Service level connection established"); +} + +static void slc_failed(gpointer userdata) +{ + struct ofono_modem *modem = userdata; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + msg = g_dbus_create_error(data->slc_msg, HFP_AGENT_ERROR_INTERFACE + ".Failed", + "HFP Handshake failed"); + g_dbus_send_message(connection, msg); + dbus_message_unref(data->slc_msg); + data->slc_msg = NULL; + + ofono_error("Service level connection failed"); + ofono_modem_set_powered(modem, FALSE); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; +} + +static void hfp_disconnected_cb(gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + + ofono_modem_set_powered(modem, FALSE); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; +} + +/* either oFono or Phone could request SLC connection */ +static int service_level_connection(struct ofono_modem *modem, int fd) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + GIOChannel *io; + GAtSyntax *syntax; + GAtChat *chat; + + io = g_io_channel_unix_new(fd); + if (io == NULL) { + ofono_error("Service level connection failed: %s (%d)", + strerror(errno), errno); + return -EIO; + } + + syntax = g_at_syntax_new_gsm_permissive(); + chat = g_at_chat_new(io, syntax); + g_at_syntax_unref(syntax); + g_io_channel_unref(io); + + if (chat == NULL) + return -ENOMEM; + + g_at_chat_set_disconnect_function(chat, hfp_disconnected_cb, modem); + + if (getenv("OFONO_AT_DEBUG")) + g_at_chat_set_debug(chat, hfp_debug, ""); + + data->info.chat = chat; + hfp_slc_establish(&data->info, slc_established, slc_failed, modem); + + return -EINPROGRESS; +} + +static DBusMessage *hfp_agent_new_connection(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + int fd, err; + struct ofono_modem *modem = data; + struct hfp_data *hfp_data = ofono_modem_get_data(modem); + guint16 version; + + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UNIX_FD, &fd, + DBUS_TYPE_UINT16, &version, DBUS_TYPE_INVALID)) + return __ofono_error_invalid_args(msg); + + hfp_slc_info_init(&hfp_data->info, version); + + err = service_level_connection(modem, fd); + if (err < 0 && err != -EINPROGRESS) + return __ofono_error_failed(msg); + + hfp_data->slc_msg = msg; + dbus_message_ref(msg); + + return NULL; +} + +static DBusMessage *hfp_agent_release(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_modem *modem = data; + struct hfp_data *hfp_data = ofono_modem_get_data(modem); + const char *obj_path = ofono_modem_get_path(modem); + + g_dbus_unregister_interface(connection, obj_path, HFP_AGENT_INTERFACE); + hfp_data->agent_registered = FALSE; + + g_hash_table_remove(modem_hash, hfp_data->handsfree_path); + ofono_modem_remove(modem); + + return dbus_message_new_method_return(msg); +} + +static const GDBusMethodTable agent_methods[] = { + { GDBUS_ASYNC_METHOD("NewConnection", + GDBUS_ARGS({ "fd", "h" }, { "version", "q" }), + NULL, hfp_agent_new_connection) }, + { GDBUS_METHOD("Release", NULL, NULL, hfp_agent_release) }, + { } +}; + +static int hfp_hf_probe(const char *device, const char *dev_addr, + const char *adapter_addr, const char *alias) +{ + struct ofono_modem *modem; + struct hfp_data *data; + char buf[256]; + + /* We already have this device in our hash, ignore */ + if (g_hash_table_lookup(modem_hash, device) != NULL) + return -EALREADY; + + ofono_info("Using device: %s, devaddr: %s, adapter: %s", + device, dev_addr, adapter_addr); + + strcpy(buf, "hfp/"); + bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4); + + modem = ofono_modem_create(buf, "hfp"); + if (modem == NULL) + return -ENOMEM; + + data = g_try_new0(struct hfp_data, 1); + if (data == NULL) + goto free; + + data->handsfree_path = g_strdup(device); + if (data->handsfree_path == NULL) + goto free; + + data->handsfree_address = g_strdup(dev_addr); + if (data->handsfree_address == NULL) + goto free; + + ofono_modem_set_data(modem, data); + ofono_modem_set_name(modem, alias); + ofono_modem_register(modem); + + g_hash_table_insert(modem_hash, g_strdup(device), modem); + + return 0; + +free: + if (data != NULL) + g_free(data->handsfree_path); + + g_free(data); + ofono_modem_remove(modem); + + return -ENOMEM; +} + +static gboolean hfp_remove_modem(gpointer key, gpointer value, + gpointer user_data) +{ + struct ofono_modem *modem = value; + const char *device = key; + const char *prefix = user_data; + + if (prefix && g_str_has_prefix(device, prefix) == FALSE) + return FALSE; + + ofono_modem_remove(modem); + + return TRUE; +} + +static void hfp_hf_remove(const char *prefix) +{ + DBG("%s", prefix); + + if (modem_hash == NULL) + return; + + g_hash_table_foreach_remove(modem_hash, hfp_remove_modem, + (gpointer) prefix); +} + +static void hfp_hf_set_alias(const char *device, const char *alias) +{ + struct ofono_modem *modem; + + if (device == NULL || alias == NULL) + return; + + modem = g_hash_table_lookup(modem_hash, device); + if (modem == NULL) + return; + + ofono_modem_set_name(modem, alias); +} + +static int hfp_register_ofono_handsfree(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + DBG("Registering oFono Agent to bluetooth daemon"); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "RegisterAgent"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, + DBUS_TYPE_INVALID); + + g_dbus_send_message(connection, msg); + return 0; +} + +static int hfp_unregister_ofono_handsfree(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *msg; + + DBG("Unregistering oFono Agent from bluetooth daemon"); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "UnregisterAgent"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &obj_path, + DBUS_TYPE_INVALID); + + g_dbus_send_message(connection, msg); + return 0; +} + +static int hfp_probe(struct ofono_modem *modem) +{ + const char *obj_path = ofono_modem_get_path(modem); + struct hfp_data *data = ofono_modem_get_data(modem); + + if (data == NULL) + return -EINVAL; + + g_dbus_register_interface(connection, obj_path, HFP_AGENT_INTERFACE, + agent_methods, NULL, NULL, modem, NULL); + + data->agent_registered = TRUE; + + if (hfp_register_ofono_handsfree(modem) != 0) + return -EINVAL; + + return 0; +} + +static void hfp_remove(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + const char *obj_path = ofono_modem_get_path(modem); + + if (data->call != NULL) + dbus_pending_call_cancel(data->call); + + if (g_dbus_unregister_interface(connection, obj_path, + HFP_AGENT_INTERFACE)) + hfp_unregister_ofono_handsfree(modem); + + g_free(data->handsfree_address); + g_free(data->handsfree_path); + g_free(data); + + ofono_modem_set_data(modem, NULL); +} + +static void hfp_connect_reply(DBusPendingCall *call, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusError derr; + DBusMessage *reply, *msg; + + reply = dbus_pending_call_steal_reply(call); + + if (ofono_modem_get_powered(modem)) + goto done; + + dbus_error_init(&derr); + if (!dbus_set_error_from_message(&derr, reply)) + goto done; + + DBG("Connect reply: %s", derr.message); + + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { + msg = dbus_message_new_method_call(BLUEZ_SERVICE, + data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Disconnect"); + if (msg == NULL) + ofono_error("Disconnect failed"); + else + g_dbus_send_message(connection, msg); + } + + ofono_modem_set_powered(modem, FALSE); + + dbus_error_free(&derr); + +done: + dbus_message_unref(reply); + data->call = NULL; +} + +/* power up hardware */ +static int hfp_enable(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + int status; + + DBG("%p", modem); + + status = bluetooth_send_with_reply(data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Connect", + &data->call, hfp_connect_reply, + modem, NULL, + DBUS_TIMEOUT, DBUS_TYPE_INVALID); + + if (status < 0) + return -EINVAL; + + return -EINPROGRESS; +} + +static void hfp_power_down(DBusPendingCall *call, gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct hfp_data *data = ofono_modem_get_data(modem); + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + DBG("Disconnect reply: %s", derr.message); + dbus_error_free(&derr); + goto done; + } + + ofono_modem_set_powered(modem, FALSE); + +done: + dbus_message_unref(reply); + data->call = NULL; +} + +static int hfp_disable(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + int status; + + DBG("%p", modem); + + g_at_chat_unref(data->info.chat); + data->info.chat = NULL; + + if (data->agent_registered) { + status = bluetooth_send_with_reply(data->handsfree_path, + BLUEZ_GATEWAY_INTERFACE, "Disconnect", + &data->call, hfp_power_down, + modem, NULL, + DBUS_TIMEOUT, DBUS_TYPE_INVALID); + + if (status < 0) + return -EINVAL; + } + + return -EINPROGRESS; +} + +static void hfp_pre_sim(struct ofono_modem *modem) +{ + struct hfp_data *data = ofono_modem_get_data(modem); + + DBG("%p", modem); + + ofono_devinfo_create(modem, 0, "hfpmodem", data->handsfree_address); + ofono_voicecall_create(modem, 0, "hfpmodem", &data->info); + ofono_netreg_create(modem, 0, "hfpmodem", &data->info); + ofono_call_volume_create(modem, 0, "hfpmodem", &data->info); + ofono_handsfree_create(modem, 0, "hfpmodem", &data->info); +} + +static void hfp_post_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static struct ofono_modem_driver hfp_driver = { + .name = "hfp", + .modem_type = OFONO_MODEM_TYPE_HFP, + .probe = hfp_probe, + .remove = hfp_remove, + .enable = hfp_enable, + .disable = hfp_disable, + .pre_sim = hfp_pre_sim, + .post_sim = hfp_post_sim, +}; + +static struct bluetooth_profile hfp_hf = { + .name = "hfp_hf", + .probe = hfp_hf_probe, + .remove = hfp_hf_remove, + .set_alias = hfp_hf_set_alias, +}; + +static int hfp_init(void) +{ + int err; + + if (DBUS_TYPE_UNIX_FD < 0) + return -EBADF; + + connection = ofono_dbus_get_connection(); + + err = ofono_modem_driver_register(&hfp_driver); + if (err < 0) + return err; + + err = bluetooth_register_uuid(HFP_AG_UUID, &hfp_hf); + if (err < 0) { + ofono_modem_driver_unregister(&hfp_driver); + return err; + } + + modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); + + return 0; +} + +static void hfp_exit(void) +{ + bluetooth_unregister_uuid(HFP_AG_UUID); + ofono_modem_driver_unregister(&hfp_driver); + + g_hash_table_destroy(modem_hash); +} + +OFONO_PLUGIN_DEFINE(hfp_bluez4, "Hands-Free Profile Plugins", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) diff --git a/plugins/sap.c b/plugins/sap.c index d893bc1..d1913fb 100644 --- a/plugins/sap.c +++ b/plugins/sap.c @@ -37,7 +37,7 @@ #include <ofono/log.h> #include <ofono/modem.h> -#include "bluetooth.h" +#include "bluez4.h" #include "util.h" #ifndef DBUS_TYPE_UNIX_FD diff --git a/plugins/telit.c b/plugins/telit.c index 79bc421..392283a 100644 --- a/plugins/telit.c +++ b/plugins/telit.c @@ -58,7 +58,7 @@ #include <drivers/atmodem/atutil.h> #include <drivers/atmodem/vendor.h> -#include "bluetooth.h" +#include "bluez4.h" static const char *none_prefix[] = { NULL }; static const char *rsen_prefix[]= { "#RSEN:", NULL }; -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 3/6] bluetooth: Initial files for BlueZ 5 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi @ 2013-01-16 13:31 ` Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi ` (3 subsequent siblings) 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-16 13:31 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1873 bytes --] This patch adds the file for Bluetooth(BlueZ 5) oFono plugin. --- Makefile.am | 3 +++ plugins/bluez5.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 plugins/bluez5.c diff --git a/Makefile.am b/Makefile.am index 63e6fdb..3c4b588 100644 --- a/Makefile.am +++ b/Makefile.am @@ -433,6 +433,9 @@ builtin_sources += plugins/connman.c builtin_sources += $(btio_sources) builtin_cflags += @BLUEZ_CFLAGS@ builtin_libadd += @BLUEZ_LIBS@ +else +builtin_modules += bluez5 +builtin_sources += plugins/bluez5.c endif endif endif diff --git a/plugins/bluez5.c b/plugins/bluez5.c new file mode 100644 index 0000000..335331c --- /dev/null +++ b/plugins/bluez5.c @@ -0,0 +1,33 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2013 Intel Corporation. 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 <glib.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +OFONO_PLUGIN_DEFINE(bluez5, "BlueZ 5 Utils Plugin", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 4/6] hfp_hf: Add initial file for external HFP 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi ` (2 preceding siblings ...) 2013-01-16 13:31 ` [PATCH v2 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi @ 2013-01-16 13:31 ` Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 5/6] hfp_hf: Add hfp_driver Claudio Takahasi ` (2 subsequent siblings) 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-16 13:31 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2178 bytes --] This patch adds the initial file to support external HFP profile and BlueZ 5. "hfp_bluez5" plugin will implement an external Bluetooth profile compatible with BlueZ 5, and "hfp" plugin will keep the compatibility with BlueZ 4. --- Makefile.am | 3 +++ plugins/hfp_hf_bluez5.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 plugins/hfp_hf_bluez5.c diff --git a/Makefile.am b/Makefile.am index 3c4b588..072b386 100644 --- a/Makefile.am +++ b/Makefile.am @@ -436,6 +436,9 @@ builtin_libadd += @BLUEZ_LIBS@ else builtin_modules += bluez5 builtin_sources += plugins/bluez5.c + +builtin_modules += hfp_bluez5 +builtin_sources += plugins/hfp_hf_bluez5.c endif endif endif diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c new file mode 100644 index 0000000..779f05d --- /dev/null +++ b/plugins/hfp_hf_bluez5.c @@ -0,0 +1,42 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2013 Intel Corporation. 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 <glib.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> + +static int hfp_init(void) +{ + return 0; +} + +static void hfp_exit(void) +{ +} + +OFONO_PLUGIN_DEFINE(hfp_bluez5, "External Hands-Free Profile Plugin", VERSION, + OFONO_PLUGIN_PRIORITY_DEFAULT, hfp_init, hfp_exit) -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 5/6] hfp_hf: Add hfp_driver 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi ` (3 preceding siblings ...) 2013-01-16 13:31 ` [PATCH v2 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi @ 2013-01-16 13:31 ` Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi 2013-01-16 20:16 ` [PATCH v2 0/6] HFP HF: External Profile Denis Kenzior 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-16 13:31 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 7703 bytes --] Adds HFP modem driver registration. --- Makefile.am | 4 +- plugins/bluez5.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ plugins/bluez5.h | 29 +++++++++++++ plugins/hfp_hf_bluez5.c | 80 ++++++++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 plugins/bluez5.h diff --git a/Makefile.am b/Makefile.am index 072b386..ad12c0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -435,10 +435,10 @@ builtin_cflags += @BLUEZ_CFLAGS@ builtin_libadd += @BLUEZ_LIBS@ else builtin_modules += bluez5 -builtin_sources += plugins/bluez5.c +builtin_sources += plugins/bluez5.c plugins/bluez5.h builtin_modules += hfp_bluez5 -builtin_sources += plugins/hfp_hf_bluez5.c +builtin_sources += plugins/hfp_hf_bluez5.c plugins/bluez5.h endif endif endif diff --git a/plugins/bluez5.c b/plugins/bluez5.c index 335331c..84ba47d 100644 --- a/plugins/bluez5.c +++ b/plugins/bluez5.c @@ -23,11 +23,123 @@ #include <config.h> #endif +#include <errno.h> #include <glib.h> #define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/dbus.h> #include <ofono/plugin.h> #include <ofono/log.h> +#include <gdbus/gdbus.h> +#include "bluez5.h" + +#define BLUEZ_PROFILE_MGMT_INTERFACE BLUEZ_SERVICE ".ProfileManager1" + +static void profile_register_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("RegisterProfile() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + +done: + dbus_message_unref(reply); +} + +static void unregister_profile_cb(DBusPendingCall *call, gpointer user_data) +{ + DBusMessage *reply; + DBusError derr; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("UnregisterProfile() replied an error: %s, %s", + derr.name, derr.message); + dbus_error_free(&derr); + goto done; + } + + DBG(""); + +done: + dbus_message_unref(reply); +} + +int bluetooth_register_profile(DBusConnection *conn, const char *uuid, + const char *name, const char *object) +{ + DBusMessageIter iter, dict; + DBusPendingCall *c; + DBusMessage *msg; + + DBG("Bluetooth: Registering %s (%s) profile", uuid, name); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", + BLUEZ_PROFILE_MGMT_INTERFACE, "RegisterProfile"); + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &object); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uuid); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict); + ofono_dbus_dict_append(&dict, "Name", DBUS_TYPE_STRING, &name); + + dbus_message_iter_close_container(&iter, &dict); + + if (!dbus_connection_send_with_reply(conn, msg, &c, -1)) { + ofono_error("Sending RegisterProfile failed"); + dbus_message_unref(msg); + return -EIO; + } + + dbus_pending_call_set_notify(c, profile_register_cb, NULL, NULL); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); + + return 0; +} + +void bluetooth_unregister_profile(DBusConnection *conn, const char *object) +{ + DBusMessageIter iter; + DBusPendingCall *c; + DBusMessage *msg; + + DBG("Bluetooth: Unregistering profile %s", object); + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", + BLUEZ_PROFILE_MGMT_INTERFACE, "UnregisterProfile"); + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &object); + + if (!dbus_connection_send_with_reply(conn, msg, &c, -1)) { + ofono_error("Sending RegisterProfile failed"); + dbus_message_unref(msg); + return; + } + + dbus_pending_call_set_notify(c, unregister_profile_cb, NULL, NULL); + dbus_pending_call_unref(c); + + dbus_message_unref(msg); +} + OFONO_PLUGIN_DEFINE(bluez5, "BlueZ 5 Utils Plugin", VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL) diff --git a/plugins/bluez5.h b/plugins/bluez5.h new file mode 100644 index 0000000..99bf896 --- /dev/null +++ b/plugins/bluez5.h @@ -0,0 +1,29 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2013 Intel Corporation. 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 + * + */ + +#define BLUEZ_SERVICE "org.bluez" + +#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" + +int bluetooth_register_profile(DBusConnection *conn, const char *uuid, + const char *name, const char *object); + +void bluetooth_unregister_profile(DBusConnection *conn, const char *object); diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c index 779f05d..0cd0d23 100644 --- a/plugins/hfp_hf_bluez5.c +++ b/plugins/hfp_hf_bluez5.c @@ -23,19 +23,99 @@ #include <config.h> #endif +#include <errno.h> #include <glib.h> #define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/modem.h> +#include <ofono/dbus.h> #include <ofono/plugin.h> #include <ofono/log.h> +#include "bluez5.h" + +#ifndef DBUS_TYPE_UNIX_FD +#define DBUS_TYPE_UNIX_FD -1 +#endif + +#define HFP_EXT_PROFILE_PATH "/bluetooth/profile/hfp_hf" + +static int hfp_probe(struct ofono_modem *modem) +{ + DBG("modem: %p", modem); + + return 0; +} + +static void hfp_remove(struct ofono_modem *modem) +{ + DBG("modem: %p", modem); +} + +/* power up hardware */ +static int hfp_enable(struct ofono_modem *modem) +{ + DBG("%p", modem); + + return 0; +} + +static int hfp_disable(struct ofono_modem *modem) +{ + DBG("%p", modem); + + return 0; +} + +static void hfp_pre_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static void hfp_post_sim(struct ofono_modem *modem) +{ + DBG("%p", modem); +} + +static struct ofono_modem_driver hfp_driver = { + .name = "hfp", + .modem_type = OFONO_MODEM_TYPE_HFP, + .probe = hfp_probe, + .remove = hfp_remove, + .enable = hfp_enable, + .disable = hfp_disable, + .pre_sim = hfp_pre_sim, + .post_sim = hfp_post_sim, +}; + static int hfp_init(void) { + DBusConnection *conn = ofono_dbus_get_connection(); + int err; + + if (DBUS_TYPE_UNIX_FD < 0) + return -EBADF; + + err = ofono_modem_driver_register(&hfp_driver); + if (err < 0) + return err; + + err = bluetooth_register_profile(conn, HFP_HS_UUID, "hfp_hf", + HFP_EXT_PROFILE_PATH); + if (err < 0) { + ofono_modem_driver_unregister(&hfp_driver); + return err; + } + return 0; } static void hfp_exit(void) { + DBusConnection *conn = ofono_dbus_get_connection(); + + bluetooth_unregister_profile(conn, HFP_EXT_PROFILE_PATH); + ofono_modem_driver_unregister(&hfp_driver); } OFONO_PLUGIN_DEFINE(hfp_bluez5, "External Hands-Free Profile Plugin", VERSION, -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 6/6] hfp_hf: Add BlueZ Profile handler 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi ` (4 preceding siblings ...) 2013-01-16 13:31 ` [PATCH v2 5/6] hfp_hf: Add hfp_driver Claudio Takahasi @ 2013-01-16 13:31 ` Claudio Takahasi 2013-01-16 20:16 ` [PATCH v2 0/6] HFP HF: External Profile Denis Kenzior 6 siblings, 0 replies; 26+ messages in thread From: Claudio Takahasi @ 2013-01-16 13:31 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 4081 bytes --] This patch declares the external HFP Profile handler. It contains the initial implementation of the D-Bus Profile1 interface and methods responsible for handling Bluetooth connections. --- plugins/bluez5.h | 2 ++ plugins/hfp_hf_bluez5.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/plugins/bluez5.h b/plugins/bluez5.h index 99bf896..01ecfe8 100644 --- a/plugins/bluez5.h +++ b/plugins/bluez5.h @@ -20,6 +20,8 @@ */ #define BLUEZ_SERVICE "org.bluez" +#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1" +#define BLUEZ_ERROR_INTERFACE BLUEZ_SERVICE ".Error" #define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb" diff --git a/plugins/hfp_hf_bluez5.c b/plugins/hfp_hf_bluez5.c index 0cd0d23..e024838 100644 --- a/plugins/hfp_hf_bluez5.c +++ b/plugins/hfp_hf_bluez5.c @@ -26,6 +26,8 @@ #include <errno.h> #include <glib.h> +#include <gdbus.h> + #define OFONO_API_SUBJECT_TO_CHANGE #include <ofono/modem.h> #include <ofono/dbus.h> @@ -88,6 +90,59 @@ static struct ofono_modem_driver hfp_driver = { .post_sim = hfp_post_sim, }; +static DBusMessage *profile_new_connection(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler NewConnection"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_release(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler Release"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_cancel(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler Cancel"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static DBusMessage *profile_disconnection(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBG("Profile handler RequestDisconnection"); + + return g_dbus_create_error(msg, BLUEZ_ERROR_INTERFACE + ".NotImplemented", + "Implementation not provided"); +} + +static const GDBusMethodTable profile_methods[] = { + { GDBUS_ASYNC_METHOD("NewConnection", + GDBUS_ARGS({ "device", "o"}, { "fd", "h"}, + { "fd_properties", "a{sv}" }), + NULL, profile_new_connection) }, + { GDBUS_METHOD("Release", NULL, NULL, profile_release) }, + { GDBUS_METHOD("Cancel", NULL, NULL, profile_cancel) }, + { GDBUS_METHOD("RequestDisconnection", + GDBUS_ARGS({"device", "o"}), NULL, + profile_disconnection) }, + { } +}; + static int hfp_init(void) { DBusConnection *conn = ofono_dbus_get_connection(); @@ -96,13 +151,28 @@ static int hfp_init(void) if (DBUS_TYPE_UNIX_FD < 0) return -EBADF; + /* Registers External Profile handler */ + if (!g_dbus_register_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE, + profile_methods, NULL, + NULL, NULL, NULL)) { + ofono_error("Register Profile interface failed: %s", + HFP_EXT_PROFILE_PATH); + return -EIO; + } + err = ofono_modem_driver_register(&hfp_driver); - if (err < 0) + if (err < 0) { + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); return err; + } err = bluetooth_register_profile(conn, HFP_HS_UUID, "hfp_hf", HFP_EXT_PROFILE_PATH); if (err < 0) { + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); ofono_modem_driver_unregister(&hfp_driver); return err; } @@ -115,6 +185,8 @@ static void hfp_exit(void) DBusConnection *conn = ofono_dbus_get_connection(); bluetooth_unregister_profile(conn, HFP_EXT_PROFILE_PATH); + g_dbus_unregister_interface(conn, HFP_EXT_PROFILE_PATH, + BLUEZ_PROFILE_INTERFACE); ofono_modem_driver_unregister(&hfp_driver); } -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v2 0/6] HFP HF: External Profile 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi ` (5 preceding siblings ...) 2013-01-16 13:31 ` [PATCH v2 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi @ 2013-01-16 20:16 ` Denis Kenzior 6 siblings, 0 replies; 26+ messages in thread From: Denis Kenzior @ 2013-01-16 20:16 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2469 bytes --] Hi Claudio, On 01/16/2013 07:31 AM, Claudio Takahasi wrote: > This is the first group of patches which introduces the Handsfree > BlueZ external profile. > > The following patches contain only initial files and basic structures > for the HFP HF plugin (since files and plugins names are one of the > controversial points). > > Remaining HFP HF patches: > git://git.infradead.org/users/cktakahasi/ofono.git HF-20130116 > > Changed between v0-v1: > * Append BlueZ version to hfp_hf* files > * --enable-bluez4 configure option > > Changed between v1-v2: > * Make BLUEZ4 conditional dependent on BLUETOOTH. BlueZ 5 is enabled by > default(--enable-bluetooth can be omitted), BlueZ 4 support is enabled > only if --enable-bluez4 is informed. --disable-bluetooth disables all > BlueZ related plugins. > > Claudio Takahasi (6): > Makefile: Add configure option for BlueZ 4 and 5 > bluetooth: Add versioning information to BlueZ plugins > bluetooth: Initial files for BlueZ 5 > hfp_hf: Add initial file for external HFP > hfp_hf: Add hfp_driver > hfp_hf: Add BlueZ Profile handler > > Makefile.am | 31 +- > configure.ac | 20 +- > dundee/bluetooth.c | 2 +- > plugins/bluetooth.c | 989 ------------------------------------------------ > plugins/bluetooth.h | 84 ---- > plugins/bluez4.c | 989 ++++++++++++++++++++++++++++++++++++++++++++++++ > plugins/bluez4.h | 84 ++++ > plugins/bluez5.c | 145 +++++++ > plugins/bluez5.h | 31 ++ > plugins/dun_gw.c | 2 +- > plugins/hfp_ag.c | 2 +- > plugins/hfp_hf.c | 552 --------------------------- > plugins/hfp_hf_bluez4.c | 552 +++++++++++++++++++++++++++ > plugins/hfp_hf_bluez5.c | 194 ++++++++++ > plugins/sap.c | 2 +- > plugins/telit.c | 2 +- > 16 files changed, 2035 insertions(+), 1646 deletions(-) > delete mode 100644 plugins/bluetooth.c > delete mode 100644 plugins/bluetooth.h > create mode 100644 plugins/bluez4.c > create mode 100644 plugins/bluez4.h > create mode 100644 plugins/bluez5.c > create mode 100644 plugins/bluez5.h > delete mode 100644 plugins/hfp_hf.c > create mode 100644 plugins/hfp_hf_bluez4.c > create mode 100644 plugins/hfp_hf_bluez5.c > All 6 patches have been applied. I did split patch 5 and 6, so it resulted in 8 commits. Regards, -Denis ^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2013-01-16 20:16 UTC | newest] Thread overview: 26+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-01-10 14:44 [PATCH v0 0/6] HFP HF: External Profile Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 1/6] Makefile: Enable BlueZ 4 and BlueZ 5 Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 5/6] hfp_hf: Add hfp_driver Claudio Takahasi 2013-01-10 14:44 ` [PATCH v0 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi 2013-01-11 9:27 ` [PATCH v0 0/6] HFP HF: External Profile Mikel Astiz 2013-01-11 14:26 ` Claudio Takahasi 2013-01-11 16:05 ` Mikel Astiz 2013-01-15 18:24 ` [PATCH v1 " Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi 2013-01-15 19:01 ` Marcel Holtmann 2013-01-15 18:24 ` [PATCH v1 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 5/6] hfp_hf: Add hfp_driver Claudio Takahasi 2013-01-15 18:24 ` [PATCH v1 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 0/6] HFP HF: External Profile Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 1/6] Makefile: Add configure option for BlueZ 4 and 5 Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 2/6] bluetooth: Add versioning information to BlueZ plugins Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 3/6] bluetooth: Initial files for BlueZ 5 Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 4/6] hfp_hf: Add initial file for external HFP Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 5/6] hfp_hf: Add hfp_driver Claudio Takahasi 2013-01-16 13:31 ` [PATCH v2 6/6] hfp_hf: Add BlueZ Profile handler Claudio Takahasi 2013-01-16 20:16 ` [PATCH v2 0/6] HFP HF: External Profile Denis Kenzior
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.