Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2 8/8] sdp: Decouple Device ID profile implementation
From: Szymon Janc @ 2013-09-19 14:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-1-git-send-email-szymon.janc@tieto.com>

Make DeviceID profile similar to other profiles implementations. Use
btd_profile for handling DeviceID profile while adding/removing
adapters. The nice drawback is that SDP code no longer depends on
main_opts.
---
 Makefile.plugins             |   3 +
 profiles/deviceid/deviceid.c | 187 +++++++++++++++++++++++++++++++++++++++++++
 src/adapter.c                |  26 +++---
 src/adapter.h                |   3 +
 src/sdpd-server.c            |   4 -
 src/sdpd-service.c           |  58 --------------
 src/sdpd.h                   |   2 -
 7 files changed, 204 insertions(+), 79 deletions(-)
 create mode 100644 profiles/deviceid/deviceid.c

diff --git a/Makefile.plugins b/Makefile.plugins
index 7c5f71d..df5d2a1 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -82,6 +82,9 @@ builtin_sources += profiles/scanparam/scan.c
 builtin_modules += deviceinfo
 builtin_sources += profiles/deviceinfo/deviceinfo.c
 
+builtin_modules += deviceid
+builtin_sources += profiles/deviceid/deviceid.c
+
 if EXPERIMENTAL
 builtin_modules += alert
 builtin_sources += profiles/alert/server.c
diff --git a/profiles/deviceid/deviceid.c b/profiles/deviceid/deviceid.c
new file mode 100644
index 0000000..be5df80
--- /dev/null
+++ b/profiles/deviceid/deviceid.c
@@ -0,0 +1,187 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "sdpd.h"
+#include "hcid.h"
+#include "adapter.h"
+#include "profile.h"
+#include "plugin.h"
+#include "log.h"
+
+struct deviceid_adapter {
+	struct btd_adapter *adapter;
+	uint32_t handle;
+};
+
+static GSList *deviceid_adapters = NULL;
+
+static struct deviceid_adapter *find_adapter(struct btd_adapter *adapter)
+{
+	GSList *list;
+
+	for (list = deviceid_adapters; list; list = list->next) {
+		struct deviceid_adapter *da = list->data;
+
+		if (da->adapter == adapter)
+			return da;
+	}
+
+	return NULL;
+}
+
+static sdp_record_t *create_record(uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version)
+{
+	const uint16_t spec = 0x0103;
+	const uint8_t primary = 1;
+	sdp_list_t *class_list, *group_list, *profile_list;
+	uuid_t class_uuid, group_uuid;
+	sdp_data_t *sdp_data, *primary_data, *source_data;
+	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
+	sdp_profile_desc_t profile;
+	sdp_record_t *record = sdp_record_alloc();
+
+	DBG("%04x:%04x:%04x:%04x", source, vendor, product, version);
+
+	record->handle = sdp_next_handle();
+
+	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
+	class_list = sdp_list_append(0, &class_uuid);
+	sdp_set_service_classes(record, class_list);
+	sdp_list_free(class_list, NULL);
+
+	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
+	group_list = sdp_list_append(NULL, &group_uuid);
+	sdp_set_browse_groups(record, group_list);
+	sdp_list_free(group_list, NULL);
+
+	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
+	profile.version = spec;
+	profile_list = sdp_list_append(NULL, &profile);
+	sdp_set_profile_descs(record, profile_list);
+	sdp_list_free(profile_list, NULL);
+
+	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
+	sdp_attr_add(record, 0x0200, spec_data);
+
+	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
+	sdp_attr_add(record, 0x0201, vendor_data);
+
+	product_data = sdp_data_alloc(SDP_UINT16, &product);
+	sdp_attr_add(record, 0x0202, product_data);
+
+	version_data = sdp_data_alloc(SDP_UINT16, &version);
+	sdp_attr_add(record, 0x0203, version_data);
+
+	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
+	sdp_attr_add(record, 0x0204, primary_data);
+
+	source_data = sdp_data_alloc(SDP_UINT16, &source);
+	sdp_attr_add(record, 0x0205, source_data);
+
+	return record;
+}
+
+static int deviceid_adapter_probe(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct deviceid_adapter *dadapter;
+	sdp_record_t *rec;
+	int ret;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	rec = create_record(main_opts.did_source, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version);
+
+	ret = adapter_service_add(adapter, rec);
+	if (ret < 0) {
+		sdp_record_free(rec);
+		return ret;
+	}
+
+	btd_adapter_set_did(adapter, main_opts.did_source, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version);
+
+	dadapter = g_new0(struct deviceid_adapter, 1);
+	dadapter->adapter = btd_adapter_ref(adapter);
+	dadapter->handle = rec->handle;
+
+	deviceid_adapters = g_slist_prepend(deviceid_adapters, dadapter);
+
+	return 0;
+}
+
+static void deviceid_adapter_remove(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct deviceid_adapter *dadapter;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	dadapter = find_adapter(adapter);
+	if (!dadapter)
+		return;
+
+	adapter_service_remove(dadapter->adapter, dadapter->handle);
+
+	btd_adapter_unref(dadapter->adapter);
+	g_free(dadapter);
+}
+
+struct btd_profile deviceid_profile = {
+	.name		= "deviceid",
+	.adapter_probe	= deviceid_adapter_probe,
+	.adapter_remove	= deviceid_adapter_remove,
+};
+
+static int deviceid_init(void)
+{
+	if (main_opts.did_source == 0) {
+		info("Device ID information disabled");
+		return -1;
+	}
+
+	return btd_profile_register(&deviceid_profile);
+}
+
+static void deviceid_exit(void)
+{
+	btd_profile_unregister(&deviceid_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(deviceid, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+			deviceid_init, deviceid_exit)
diff --git a/src/adapter.c b/src/adapter.c
index b99bff9..ed4824c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3929,17 +3929,12 @@ static struct btd_adapter *btd_adapter_new(uint16_t index)
 	adapter->system_name = g_strdup(main_opts.name);
 	adapter->major_class = (main_opts.class & 0x001f00) >> 8;
 	adapter->minor_class = (main_opts.class & 0x0000fc) >> 2;
-	adapter->modalias = bt_modalias(main_opts.did_source,
-						main_opts.did_vendor,
-						main_opts.did_product,
-						main_opts.did_version);
 	adapter->discoverable_timeout = main_opts.discovto;
 	adapter->pairable_timeout = main_opts.pairto;
 
 	DBG("System name: %s", adapter->system_name);
 	DBG("Major class: %u", adapter->major_class);
 	DBG("Minor class: %u", adapter->minor_class);
-	DBG("Modalias: %s", adapter->modalias);
 	DBG("Discoverable timeout: %u seconds", adapter->discoverable_timeout);
 	DBG("Pairable timeout: %u seconds", adapter->pairable_timeout);
 
@@ -5566,14 +5561,23 @@ void adapter_foreach(adapter_cb func, gpointer user_data)
 	g_slist_foreach(adapters, (GFunc) func, user_data);
 }
 
-static int set_did(struct btd_adapter *adapter, uint16_t vendor,
-			uint16_t product, uint16_t version, uint16_t source)
+int btd_adapter_set_did(struct btd_adapter *adapter,
+					uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version)
 {
 	struct mgmt_cp_set_device_id cp;
 
 	DBG("hci%u source %x vendor %x product %x version %x",
 			adapter->dev_id, source, vendor, product, version);
 
+	g_free(adapter->modalias);
+	adapter->modalias = bt_modalias(source, vendor, product, version);
+
+	DBG("Modalias: %s", adapter->modalias);
+
+	g_dbus_emit_property_changed(dbus_conn, adapter->path,
+						ADAPTER_INTERFACE, "Modalias");
+
 	memset(&cp, 0, sizeof(cp));
 
 	cp.source = htobs(source);
@@ -5638,14 +5642,6 @@ static int adapter_register(struct btd_adapter *adapter)
 
 	adapter->initialized = TRUE;
 
-	if (main_opts.did_source) {
-		/* DeviceID record is added by sdpd-server before any other
-		 * record is registered. */
-		adapter_service_insert(adapter, sdp_record_find(0x10000));
-		set_did(adapter, main_opts.did_vendor, main_opts.did_product,
-				main_opts.did_version, main_opts.did_source);
-	}
-
 	DBG("Adapter %s registered", adapter->path);
 
 	return 0;
diff --git a/src/adapter.h b/src/adapter.h
index 5d124e7..a6fb340 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -113,6 +113,9 @@ void btd_adapter_unref(struct btd_adapter *adapter);
 
 void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
 							uint8_t minor);
+int btd_adapter_set_did(struct btd_adapter *adapter,
+					uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version);
 
 struct btd_adapter_driver {
 	const char *name;
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index 7b1351f..de5aef1 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -238,10 +238,6 @@ int start_sdp_server(uint16_t mtu, uint32_t flags)
 		return -1;
 	}
 
-	if (main_opts.did_source > 0)
-		register_device_id(main_opts.did_source, main_opts.did_vendor,
-				main_opts.did_product, main_opts.did_version);
-
 	io = g_io_channel_unix_new(l2cap_sock);
 	g_io_channel_set_close_on_unref(io, TRUE);
 
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index 09f6c0a..2da70b5 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -176,64 +176,6 @@ void register_server_service(void)
 	update_db_timestamp();
 }
 
-void register_device_id(uint16_t source, uint16_t vendor,
-					uint16_t product, uint16_t version)
-{
-	const uint16_t spec = 0x0103;
-	const uint8_t primary = 1;
-	sdp_list_t *class_list, *group_list, *profile_list;
-	uuid_t class_uuid, group_uuid;
-	sdp_data_t *sdp_data, *primary_data, *source_data;
-	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
-	sdp_profile_desc_t profile;
-	sdp_record_t *record = sdp_record_alloc();
-
-	DBG("Adding device id record for %04x:%04x:%04x:%04x",
-					source, vendor, product, version);
-
-	record->handle = sdp_next_handle();
-
-	sdp_record_add(BDADDR_ANY, record);
-	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
-	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
-
-	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
-	class_list = sdp_list_append(0, &class_uuid);
-	sdp_set_service_classes(record, class_list);
-	sdp_list_free(class_list, NULL);
-
-	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
-	group_list = sdp_list_append(NULL, &group_uuid);
-	sdp_set_browse_groups(record, group_list);
-	sdp_list_free(group_list, NULL);
-
-	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
-	profile.version = spec;
-	profile_list = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(record, profile_list);
-	sdp_list_free(profile_list, NULL);
-
-	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
-	sdp_attr_add(record, 0x0200, spec_data);
-
-	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
-	sdp_attr_add(record, 0x0201, vendor_data);
-
-	product_data = sdp_data_alloc(SDP_UINT16, &product);
-	sdp_attr_add(record, 0x0202, product_data);
-
-	version_data = sdp_data_alloc(SDP_UINT16, &version);
-	sdp_attr_add(record, 0x0203, version_data);
-
-	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
-	sdp_attr_add(record, 0x0204, primary_data);
-
-	source_data = sdp_data_alloc(SDP_UINT16, &source);
-	sdp_attr_add(record, 0x0205, source_data);
-
-	update_db_timestamp();
-}
-
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
 {
 	sdp_data_t *data;
diff --git a/src/sdpd.h b/src/sdpd.h
index 3c6ee01..174a4d7 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -54,8 +54,6 @@ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
 
 void register_public_browse_group(void);
 void register_server_service(void);
-void register_device_id(uint16_t source, uint16_t vendor,
-					uint16_t product, uint16_t version);
 
 int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v3 8/8] sdp: Decouple Device ID profile implementation
From: Szymon Janc @ 2013-09-19 14:11 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1379599248-7923-9-git-send-email-szymon.janc@tieto.com>

Make DeviceID profile similar to other profiles implementations. Use
btd_profile for handling DeviceID profile while adding/removing
adapters. The nice drawback is that SDP code no longer depends on
main_opts.
---

Fixed missing g_slist_remove.

 Makefile.plugins             |   3 +
 profiles/deviceid/deviceid.c | 189 +++++++++++++++++++++++++++++++++++++++++++
 src/adapter.c                |  26 +++---
 src/adapter.h                |   3 +
 src/sdpd-server.c            |   4 -
 src/sdpd-service.c           |  58 -------------
 src/sdpd.h                   |   2 -
 7 files changed, 206 insertions(+), 79 deletions(-)
 create mode 100644 profiles/deviceid/deviceid.c

diff --git a/Makefile.plugins b/Makefile.plugins
index 7c5f71d..df5d2a1 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -82,6 +82,9 @@ builtin_sources += profiles/scanparam/scan.c
 builtin_modules += deviceinfo
 builtin_sources += profiles/deviceinfo/deviceinfo.c
 
+builtin_modules += deviceid
+builtin_sources += profiles/deviceid/deviceid.c
+
 if EXPERIMENTAL
 builtin_modules += alert
 builtin_sources += profiles/alert/server.c
diff --git a/profiles/deviceid/deviceid.c b/profiles/deviceid/deviceid.c
new file mode 100644
index 0000000..1ace475
--- /dev/null
+++ b/profiles/deviceid/deviceid.c
@@ -0,0 +1,189 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "sdpd.h"
+#include "hcid.h"
+#include "adapter.h"
+#include "profile.h"
+#include "plugin.h"
+#include "log.h"
+
+struct deviceid_adapter {
+	struct btd_adapter *adapter;
+	uint32_t handle;
+};
+
+static GSList *deviceid_adapters = NULL;
+
+static struct deviceid_adapter *find_adapter(struct btd_adapter *adapter)
+{
+	GSList *list;
+
+	for (list = deviceid_adapters; list; list = list->next) {
+		struct deviceid_adapter *da = list->data;
+
+		if (da->adapter == adapter)
+			return da;
+	}
+
+	return NULL;
+}
+
+static sdp_record_t *create_record(uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version)
+{
+	const uint16_t spec = 0x0103;
+	const uint8_t primary = 1;
+	sdp_list_t *class_list, *group_list, *profile_list;
+	uuid_t class_uuid, group_uuid;
+	sdp_data_t *sdp_data, *primary_data, *source_data;
+	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
+	sdp_profile_desc_t profile;
+	sdp_record_t *record = sdp_record_alloc();
+
+	DBG("%04x:%04x:%04x:%04x", source, vendor, product, version);
+
+	record->handle = sdp_next_handle();
+
+	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
+	class_list = sdp_list_append(0, &class_uuid);
+	sdp_set_service_classes(record, class_list);
+	sdp_list_free(class_list, NULL);
+
+	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
+	group_list = sdp_list_append(NULL, &group_uuid);
+	sdp_set_browse_groups(record, group_list);
+	sdp_list_free(group_list, NULL);
+
+	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
+	profile.version = spec;
+	profile_list = sdp_list_append(NULL, &profile);
+	sdp_set_profile_descs(record, profile_list);
+	sdp_list_free(profile_list, NULL);
+
+	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
+	sdp_attr_add(record, 0x0200, spec_data);
+
+	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
+	sdp_attr_add(record, 0x0201, vendor_data);
+
+	product_data = sdp_data_alloc(SDP_UINT16, &product);
+	sdp_attr_add(record, 0x0202, product_data);
+
+	version_data = sdp_data_alloc(SDP_UINT16, &version);
+	sdp_attr_add(record, 0x0203, version_data);
+
+	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
+	sdp_attr_add(record, 0x0204, primary_data);
+
+	source_data = sdp_data_alloc(SDP_UINT16, &source);
+	sdp_attr_add(record, 0x0205, source_data);
+
+	return record;
+}
+
+static int deviceid_adapter_probe(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct deviceid_adapter *dadapter;
+	sdp_record_t *rec;
+	int ret;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	rec = create_record(main_opts.did_source, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version);
+
+	ret = adapter_service_add(adapter, rec);
+	if (ret < 0) {
+		sdp_record_free(rec);
+		return ret;
+	}
+
+	btd_adapter_set_did(adapter, main_opts.did_source, main_opts.did_vendor,
+				main_opts.did_product, main_opts.did_version);
+
+	dadapter = g_new0(struct deviceid_adapter, 1);
+	dadapter->adapter = btd_adapter_ref(adapter);
+	dadapter->handle = rec->handle;
+
+	deviceid_adapters = g_slist_prepend(deviceid_adapters, dadapter);
+
+	return 0;
+}
+
+static void deviceid_adapter_remove(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	struct deviceid_adapter *dadapter;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	dadapter = find_adapter(adapter);
+	if (!dadapter)
+		return;
+
+	deviceid_adapters = g_slist_remove(deviceid_adapters, dadapter);
+
+	adapter_service_remove(dadapter->adapter, dadapter->handle);
+
+	btd_adapter_unref(dadapter->adapter);
+	g_free(dadapter);
+}
+
+struct btd_profile deviceid_profile = {
+	.name		= "deviceid",
+	.adapter_probe	= deviceid_adapter_probe,
+	.adapter_remove	= deviceid_adapter_remove,
+};
+
+static int deviceid_init(void)
+{
+	if (main_opts.did_source == 0) {
+		info("Device ID information disabled");
+		return -1;
+	}
+
+	return btd_profile_register(&deviceid_profile);
+}
+
+static void deviceid_exit(void)
+{
+	btd_profile_unregister(&deviceid_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(deviceid, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+			deviceid_init, deviceid_exit)
diff --git a/src/adapter.c b/src/adapter.c
index b99bff9..ed4824c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3929,17 +3929,12 @@ static struct btd_adapter *btd_adapter_new(uint16_t index)
 	adapter->system_name = g_strdup(main_opts.name);
 	adapter->major_class = (main_opts.class & 0x001f00) >> 8;
 	adapter->minor_class = (main_opts.class & 0x0000fc) >> 2;
-	adapter->modalias = bt_modalias(main_opts.did_source,
-						main_opts.did_vendor,
-						main_opts.did_product,
-						main_opts.did_version);
 	adapter->discoverable_timeout = main_opts.discovto;
 	adapter->pairable_timeout = main_opts.pairto;
 
 	DBG("System name: %s", adapter->system_name);
 	DBG("Major class: %u", adapter->major_class);
 	DBG("Minor class: %u", adapter->minor_class);
-	DBG("Modalias: %s", adapter->modalias);
 	DBG("Discoverable timeout: %u seconds", adapter->discoverable_timeout);
 	DBG("Pairable timeout: %u seconds", adapter->pairable_timeout);
 
@@ -5566,14 +5561,23 @@ void adapter_foreach(adapter_cb func, gpointer user_data)
 	g_slist_foreach(adapters, (GFunc) func, user_data);
 }
 
-static int set_did(struct btd_adapter *adapter, uint16_t vendor,
-			uint16_t product, uint16_t version, uint16_t source)
+int btd_adapter_set_did(struct btd_adapter *adapter,
+					uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version)
 {
 	struct mgmt_cp_set_device_id cp;
 
 	DBG("hci%u source %x vendor %x product %x version %x",
 			adapter->dev_id, source, vendor, product, version);
 
+	g_free(adapter->modalias);
+	adapter->modalias = bt_modalias(source, vendor, product, version);
+
+	DBG("Modalias: %s", adapter->modalias);
+
+	g_dbus_emit_property_changed(dbus_conn, adapter->path,
+						ADAPTER_INTERFACE, "Modalias");
+
 	memset(&cp, 0, sizeof(cp));
 
 	cp.source = htobs(source);
@@ -5638,14 +5642,6 @@ static int adapter_register(struct btd_adapter *adapter)
 
 	adapter->initialized = TRUE;
 
-	if (main_opts.did_source) {
-		/* DeviceID record is added by sdpd-server before any other
-		 * record is registered. */
-		adapter_service_insert(adapter, sdp_record_find(0x10000));
-		set_did(adapter, main_opts.did_vendor, main_opts.did_product,
-				main_opts.did_version, main_opts.did_source);
-	}
-
 	DBG("Adapter %s registered", adapter->path);
 
 	return 0;
diff --git a/src/adapter.h b/src/adapter.h
index 5d124e7..a6fb340 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -113,6 +113,9 @@ void btd_adapter_unref(struct btd_adapter *adapter);
 
 void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
 							uint8_t minor);
+int btd_adapter_set_did(struct btd_adapter *adapter,
+					uint16_t source, uint16_t vendor,
+					uint16_t product, uint16_t version);
 
 struct btd_adapter_driver {
 	const char *name;
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index 7b1351f..de5aef1 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -238,10 +238,6 @@ int start_sdp_server(uint16_t mtu, uint32_t flags)
 		return -1;
 	}
 
-	if (main_opts.did_source > 0)
-		register_device_id(main_opts.did_source, main_opts.did_vendor,
-				main_opts.did_product, main_opts.did_version);
-
 	io = g_io_channel_unix_new(l2cap_sock);
 	g_io_channel_set_close_on_unref(io, TRUE);
 
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index 09f6c0a..2da70b5 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -176,64 +176,6 @@ void register_server_service(void)
 	update_db_timestamp();
 }
 
-void register_device_id(uint16_t source, uint16_t vendor,
-					uint16_t product, uint16_t version)
-{
-	const uint16_t spec = 0x0103;
-	const uint8_t primary = 1;
-	sdp_list_t *class_list, *group_list, *profile_list;
-	uuid_t class_uuid, group_uuid;
-	sdp_data_t *sdp_data, *primary_data, *source_data;
-	sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
-	sdp_profile_desc_t profile;
-	sdp_record_t *record = sdp_record_alloc();
-
-	DBG("Adding device id record for %04x:%04x:%04x:%04x",
-					source, vendor, product, version);
-
-	record->handle = sdp_next_handle();
-
-	sdp_record_add(BDADDR_ANY, record);
-	sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
-	sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
-
-	sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
-	class_list = sdp_list_append(0, &class_uuid);
-	sdp_set_service_classes(record, class_list);
-	sdp_list_free(class_list, NULL);
-
-	sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
-	group_list = sdp_list_append(NULL, &group_uuid);
-	sdp_set_browse_groups(record, group_list);
-	sdp_list_free(group_list, NULL);
-
-	sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
-	profile.version = spec;
-	profile_list = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(record, profile_list);
-	sdp_list_free(profile_list, NULL);
-
-	spec_data = sdp_data_alloc(SDP_UINT16, &spec);
-	sdp_attr_add(record, 0x0200, spec_data);
-
-	vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
-	sdp_attr_add(record, 0x0201, vendor_data);
-
-	product_data = sdp_data_alloc(SDP_UINT16, &product);
-	sdp_attr_add(record, 0x0202, product_data);
-
-	version_data = sdp_data_alloc(SDP_UINT16, &version);
-	sdp_attr_add(record, 0x0203, version_data);
-
-	primary_data = sdp_data_alloc(SDP_BOOL, &primary);
-	sdp_attr_add(record, 0x0204, primary_data);
-
-	source_data = sdp_data_alloc(SDP_UINT16, &source);
-	sdp_attr_add(record, 0x0205, source_data);
-
-	update_db_timestamp();
-}
-
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
 {
 	sdp_data_t *data;
diff --git a/src/sdpd.h b/src/sdpd.h
index 3c6ee01..174a4d7 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -54,8 +54,6 @@ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
 
 void register_public_browse_group(void);
 void register_server_service(void);
-void register_device_id(uint16_t source, uint16_t vendor,
-					uint16_t product, uint16_t version);
 
 int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
-- 
1.8.4


^ permalink raw reply related

* Re: [PATCH 2/2] Bluetooth: Add event mask page 2 setting support
From: Gustavo Padovan @ 2013-09-19 15:22 UTC (permalink / raw)
  To: johan.hedberg; +Cc: linux-bluetooth
In-Reply-To: <1379061602-8290-3-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

2013-09-13 johan.hedberg@gmail.com <johan.hedberg@gmail.com>:

> From: Johan Hedberg <johan.hedberg@intel.com>
> 
> For those controller that support the HCI_Set_Event_Mask_Page_2 command
> we should include it in the init sequence. This patch implements sending
> of the command and enables the events in it based on supported features
> (currently only CSB is checked).
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
>  include/net/bluetooth/hci.h |  2 ++
>  net/bluetooth/hci_core.c    | 32 ++++++++++++++++++++++++++++++++
>  2 files changed, 34 insertions(+)

Patch has been applied to bluetooth-next. Thanks.

	Gustavo

^ permalink raw reply

* Re: [PATCH] rfcomm: don't release the port in rfcomm_dev_state_change()
From: Gustavo Padovan @ 2013-09-19 16:24 UTC (permalink / raw)
  To: Gianluca Anzolin; +Cc: peter, marcel, linux-bluetooth, gregkh, jslaby
In-Reply-To: <1377620926-23370-1-git-send-email-gianluca@sottospazio.it>

Hi Gianluca,

2013-08-27 Gianluca Anzolin <gianluca@sottospazio.it>:

> When the dlc is closed, rfcomm_dev_state_change() tries to release the
> port in the case it cannot get a reference to the tty. However this is
> racy and not even needed.
> 
> Infact as Peter Hurley points out:
> 
> 1. Only consider dlcs that are 'stolen' from a connected socket, ie.
>    reused. Allocated dlcs cannot have been closed prior to port
>    activate and so for these dlcs a tty reference will always be avail
>    in rfcomm_dev_state_change() -- except for the conditions covered by
>    #2b below.
> 2. If a tty was at some point previously created for this rfcomm, then
>    either
>    (a) the tty reference is still avail, so rfcomm_dev_state_change()
>        will perform a hangup. So nothing to do, or,
>    (b) the tty reference is no longer avail, and the tty_port will be
>        destroyed by the last tty_port_put() in rfcomm_tty_cleanup.
>        Again, no action required.
> 3. Prior to obtaining the dlc lock in rfcomm_dev_add(),
>    rfcomm_dev_state_change() will not 'see' a rfcomm_dev so nothing to
>    do here.
> 4. After releasing the dlc lock in rfcomm_dev_add(),
>    rfcomm_dev_state_change() will 'see' an incomplete rfcomm_dev if a
>    tty reference could not be obtained. Again, the best thing to do here
>    is nothing. Any future attempted open() will block on
>    rfcomm_dev_carrier_raised(). The unconnected device will exist until
>    released by ioctl(RFCOMMRELEASEDEV).
> 
> The patch removes the aforementioned code and uses the
> tty_port_tty_hangup() helper to hangup the tty.
> 
> Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
> ---
>  net/bluetooth/rfcomm/tty.c | 35 ++---------------------------------
>  1 file changed, 2 insertions(+), 33 deletions(-)

Patch has been applied to bluetooth.git. Thanks.

	Gustavo

^ permalink raw reply

* [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 17:06 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Belkin bluetooth device's usb device id added to generic usb bluetooth driver.

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..117b90c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
 
 	/*Broadcom devices with vendor specific id */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+
+	/* Belkin F8T065bf */
+	{ USB_DEVICE(0x050d, 0x065a) },
 
 	{ }	/* Terminating entry */
 };
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 17:21 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Belkin bluetooth device's usb device id added to generic usb bluetooth driver.

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..117b90c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
 
 	/*Broadcom devices with vendor specific id */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+
+	/* Belkin F8T065bf */
+	{ USB_DEVICE(0x050d, 0x065a) },
 
 	{ }	/* Terminating entry */
 };
-- 
1.8.1.4

^ permalink raw reply related

* Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Gustavo Padovan @ 2013-09-19 19:24 UTC (permalink / raw)
  To: Ken O'Brien; +Cc: marcel, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <1379610373-2640-1-git-send-email-kernel@kenobrien.org>

Hi Ken,

2013-09-19 Ken O'Brien <kernel@kenobrien.org>:

> Belkin bluetooth device's usb device id added to generic usb bluetooth driver.
> 
> Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
> ---
>  drivers/bluetooth/btusb.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 8e16f0a..117b90c 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
>  
>  	/*Broadcom devices with vendor specific id */
>  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
> +
> +	/* Belkin F8T065bf */
> +	{ USB_DEVICE(0x050d, 0x065a) },

Could you please add the output of /sys/kernel/debug/usb/devices for this
bluetooth controller to the commit messages, like we do for any new device id
we add to btusb. Thanks.

	Gustavo

^ permalink raw reply

* Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 20:56 UTC (permalink / raw)
  To: Gustavo Padovan, Ken O'Brien, marcel, johan.hedberg,
	linux-bluetooth, linux-kernel
In-Reply-To: <20130919192403.GH4006@joana>

Sure thing. Here's the output:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

On Thu, Sep 19, 2013 at 02:24:03PM -0500, Gustavo Padovan wrote:
> Hi Ken,
> 
> 2013-09-19 Ken O'Brien <kernel@kenobrien.org>:
> 
> > Belkin bluetooth device's usb device id added to generic usb bluetooth driver.
> > 
> > Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
> > ---
> >  drivers/bluetooth/btusb.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> > index 8e16f0a..117b90c 100644
> > --- a/drivers/bluetooth/btusb.c
> > +++ b/drivers/bluetooth/btusb.c
> > @@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
> >  
> >  	/*Broadcom devices with vendor specific id */
> >  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
> > +
> > +	/* Belkin F8T065bf */
> > +	{ USB_DEVICE(0x050d, 0x065a) },
> 
> Could you please add the output of /sys/kernel/debug/usb/devices for this
> bluetooth controller to the commit messages, like we do for any new device id
> we add to btusb. Thanks.
> 
> 	Gustavo
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 22:07 UTC (permalink / raw)
  To: Gustavo Padovan; +Cc: marcel, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <20130919192403.GH4006@joana>

Here is the output:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)


On Thu, 2013-09-19 at 14:24 -0500, Gustavo Padovan wrote:
> Hi Ken,
> 
> 2013-09-19 Ken O'Brien <kernel@kenobrien.org>:
> 
> > Belkin bluetooth device's usb device id added to generic usb bluetooth driver.
> > 
> > Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
> > ---
> >  drivers/bluetooth/btusb.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> > index 8e16f0a..117b90c 100644
> > --- a/drivers/bluetooth/btusb.c
> > +++ b/drivers/bluetooth/btusb.c
> > @@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
> >  
> >  	/*Broadcom devices with vendor specific id */
> >  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
> > +
> > +	/* Belkin F8T065bf */
> > +	{ USB_DEVICE(0x050d, 0x065a) },
> 
> Could you please add the output of /sys/kernel/debug/usb/devices for this
> bluetooth controller to the commit messages, like we do for any new device id
> we add to btusb. Thanks.
> 
> 	Gustavo
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



^ permalink raw reply

* Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-19 22:44 UTC (permalink / raw)
  To: Ken O'Brien, Gustavo Padovan
  Cc: marcel, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <1379628457.2494.1.camel@mjolnir.site>

[-- Attachment #1: Type: text/plain, Size: 3629 bytes --]

 Apologies. This was supposed to be in the commit log. I'll resubmit
the patch and I notice it's another instance of an existing bcm
device. I'll update the patch accordingly. 
Ken

----- Original Message -----
From: "Ken O'Brien" 
To:"Gustavo Padovan" 
Cc:, , , 
Sent:Thu, 19 Sep 2013 23:07:37 +0100
Subject:Re: [PATCH] bluetooth: btusb: Added support for Belkin F8065bf
usb bluetooth device

 Here is the output:

 T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
 P: Vendor=050d ProdID=065a Rev= 1.12
 S: Manufacturer=Broadcom Corp
 S: Product=BCM20702A0
 S: SerialNumber=0002723E2D29
 C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
 I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
 E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
 E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
 I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
 I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
 I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
 I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
 I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
 I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
 E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
 E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
 I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
 E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
 E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
 I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

 On Thu, 2013-09-19 at 14:24 -0500, Gustavo Padovan wrote:
 > Hi Ken,
 > 
 > 2013-09-19 Ken O'Brien :
 > 
 > > Belkin bluetooth device's usb device id added to generic usb
bluetooth driver.
 > > 
 > > Signed-off-by: Ken O'Brien 
 > > ---
 > > drivers/bluetooth/btusb.c | 3 +++
 > > 1 file changed, 3 insertions(+)
 > > 
 > > diff --git a/drivers/bluetooth/btusb.c
b/drivers/bluetooth/btusb.c
 > > index 8e16f0a..117b90c 100644
 > > --- a/drivers/bluetooth/btusb.c
 > > +++ b/drivers/bluetooth/btusb.c
 > > @@ -111,6 +111,9 @@ static struct usb_device_id btusb_table[] = {
 > > 
 > > /*Broadcom devices with vendor specific id */
 > > { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
 > > +
 > > + /* Belkin F8T065bf */
 > > + { USB_DEVICE(0x050d, 0x065a) },
 > 
 > Could you please add the output of /sys/kernel/debug/usb/devices
for this
 > bluetooth controller to the commit messages, like we do for any new
device id
 > we add to btusb. Thanks.
 > 
 > Gustavo
 > --
 > To unsubscribe from this list: send the line "unsubscribe
linux-kernel" in
 > the body of a message to majordomo@vger.kernel.org
 > More majordomo info at http://vger.kernel.org/majordomo-info.html
 > Please read the FAQ at http://www.tux.org/lkml/

 --
 To unsubscribe from this list: send the line "unsubscribe
linux-kernel" in
 the body of a message to majordomo@vger.kernel.org
 More majordomo info at http://vger.kernel.org/majordomo-info.html
 Please read the FAQ at http://www.tux.org/lkml/


[-- Attachment #2: Type: text/html, Size: 4834 bytes --]

^ permalink raw reply

* [PATCH 1/2] android: Add skeleton of BlueZ Android daemon
From: Frederic Danis @ 2013-09-20 12:24 UTC (permalink / raw)
  To: linux-bluetooth

Define local mapping to glib path, otherwise this has to be inside central
place in the build repository.

Retrieve Bluetooth version from configure.ac.
---
 .gitignore         |    2 +
 Android.mk         |    9 ++++
 Makefile.am        |    1 +
 Makefile.android   |    7 ++++
 android/Android.mk |   24 +++++++++++
 android/main.c     |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac       |    5 +++
 7 files changed, 167 insertions(+)
 create mode 100644 Android.mk
 create mode 100644 Makefile.android
 create mode 100644 android/Android.mk
 create mode 100644 android/main.c

diff --git a/.gitignore b/.gitignore
index 8a25a3e..331a18b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -98,3 +98,5 @@ unit/test-gobex-packet
 unit/test-gobex-transfer
 unit/test-*.log
 unit/test-*.trs
+
+android/bluezd
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..5ec3bb7
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH := $(call my-dir)
+
+# Retrieve BlueZ version from configure.ac file
+BLUEZ_VERSION := $(shell grep AC_INIT $(LOCAL_PATH)/configure.ac | tr -d ' ' | sed -e 's/.*(.*,\(.*\))/\1/')
+
+# Specify pathmap for glib
+pathmap_INCL += glib:external/bluetooth/glib
+
+include $(call all-subdir-makefiles)
diff --git a/Makefile.am b/Makefile.am
index 4e4b1c5..2c048bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -179,6 +179,7 @@ test_scripts =
 
 include Makefile.tools
 include Makefile.obexd
+include Makefile.android
 
 if HID2HCI
 rulesdir = @UDEV_DIR@/rules.d
diff --git a/Makefile.android b/Makefile.android
new file mode 100644
index 0000000..7b901ff
--- /dev/null
+++ b/Makefile.android
@@ -0,0 +1,7 @@
+
+if ANDROID_DAEMON
+noinst_PROGRAMS += android/bluezd
+
+android_bluezd_SOURCES = android/main.c
+android_bluezd_LDADD = @GLIB_LIBS@
+endif
diff --git a/android/Android.mk b/android/Android.mk
new file mode 100644
index 0000000..50f3c36
--- /dev/null
+++ b/android/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH := $(call my-dir)
+
+#
+# Android BlueZ daemon (bluezd)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	main.c \
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, glib) \
+	$(call include-path-for, glib)/glib \
+	$(LOCAL_PATH)/../src \
+
+LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
+
+LOCAL_SHARED_LIBRARIES := \
+	libglib \
+
+LOCAL_MODULE := bluezd
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/main.c b/android/main.c
new file mode 100644
index 0000000..37a64c1
--- /dev/null
+++ b/android/main.c
@@ -0,0 +1,119 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "hcid.h"
+
+#define SHUTDOWN_GRACE_SECONDS 10
+
+static GMainLoop *event_loop;
+
+void btd_exit(void)
+{
+	g_main_loop_quit(event_loop);
+}
+
+static gboolean quit_eventloop(gpointer user_data)
+{
+	btd_exit();
+	return FALSE;
+}
+
+static void signal_handler(int sig)
+{
+	static unsigned int __terminated = 0;
+
+	switch (sig) {
+	case SIGINT:
+	case SIGTERM:
+		if (__terminated == 0) {
+			g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
+							quit_eventloop, NULL);
+		}
+
+		__terminated = 1;
+		break;
+	}
+}
+
+static gboolean option_detach = TRUE;
+static gboolean option_version = FALSE;
+
+static GOptionEntry options[] = {
+	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
+				G_OPTION_ARG_NONE, &option_detach,
+				"Run with logging in foreground", NULL },
+	{ "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+				"Show version information and exit", NULL },
+	{ NULL }
+};
+
+int main(int argc, char *argv[])
+{
+	GOptionContext *context;
+	GError *err = NULL;
+	struct sigaction sa;
+
+	context = g_option_context_new(NULL);
+	g_option_context_add_main_entries(context, options, NULL);
+
+	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
+		if (err != NULL) {
+			g_printerr("%s\n", err->message);
+			g_error_free(err);
+		} else
+			g_printerr("An unknown error occurred\n");
+		exit(1);
+	}
+
+	g_option_context_free(context);
+
+	if (option_version == TRUE) {
+		printf("%s\n", VERSION);
+		exit(0);
+	}
+
+	event_loop = g_main_loop_new(NULL, FALSE);
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = signal_handler;
+	sigaction(SIGINT, &sa, NULL);
+	sigaction(SIGTERM, &sa, NULL);
+
+	g_main_loop_run(event_loop);
+
+	g_main_loop_unref(event_loop);
+
+	return 0;
+}
diff --git a/configure.ac b/configure.ac
index 41c2935..3b7a5d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -242,4 +242,9 @@ AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}",
 			[Directory for the configuration files])
 AC_SUBST(CONFIGDIR, "${configdir}")
 
+AC_ARG_ENABLE(android-daemon, AC_HELP_STRING([--enable-android-daemon],
+			[enable BlueZ Android daemon]),
+					[android_daemon=${enableval}])
+AM_CONDITIONAL(ANDROID_DAEMON, test "${android_daemon}" = "yes")
+
 AC_OUTPUT(Makefile src/bluetoothd.8 lib/bluez.pc)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 2/2] android: Android version of log.c
From: Frederic Danis @ 2013-09-20 12:24 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1379679871-29623-1-git-send-email-frederic.danis@linux.intel.com>

Add logging system to BlueZ Android daemon.
Android build will use android/log.c file while autotools build will use
src/log.c instead.
---
 Makefile.android   |    2 +-
 android/Android.mk |    1 +
 android/log.c      |  184 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 android/main.c     |   39 +++++++++++
 4 files changed, 225 insertions(+), 1 deletion(-)
 create mode 100644 android/log.c

diff --git a/Makefile.android b/Makefile.android
index 7b901ff..8f65dbf 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -2,6 +2,6 @@
 if ANDROID_DAEMON
 noinst_PROGRAMS += android/bluezd
 
-android_bluezd_SOURCES = android/main.c
+android_bluezd_SOURCES = android/main.c src/log.c
 android_bluezd_LDADD = @GLIB_LIBS@
 endif
diff --git a/android/Android.mk b/android/Android.mk
index 50f3c36..25099b3 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -8,6 +8,7 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
 	main.c \
+	log.c \
 
 LOCAL_C_INCLUDES := \
 	$(call include-path-for, glib) \
diff --git a/android/log.c b/android/log.c
new file mode 100644
index 0000000..1f98196
--- /dev/null
+++ b/android/log.c
@@ -0,0 +1,184 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  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 as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 <fcntl.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+#define LOG_DEBUG	3
+#define LOG_INFO	4
+#define LOG_WARN	5
+#define LOG_ERR		6
+
+const char tag[] = "BlueZ";
+int system_fd;
+int detached;
+
+static void android_log(int pri, const char *fmt, va_list ap)
+{
+	char *msg;
+	struct iovec vec[3];
+
+	msg = g_strdup_vprintf(fmt, ap);
+
+	if (!detached) {
+		vec[0].iov_base = (void *) msg;
+		vec[0].iov_len = strlen(msg) + 1;
+		vec[1].iov_base = "\n";
+		vec[1].iov_len = 1;
+		writev(STDERR_FILENO, vec, 2);
+	}
+
+	if (system_fd == -1)
+		goto done;
+
+	vec[0].iov_base = (unsigned char *) &pri;
+	vec[0].iov_len = 1;
+	vec[1].iov_base = (void *) tag;
+	vec[1].iov_len = strlen(tag) + 1;
+	vec[2].iov_base = (void *) msg;
+	vec[2].iov_len = strlen(msg) + 1;
+
+	writev(system_fd, vec, 3);
+
+done:
+	g_free(msg);
+}
+
+void info(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	android_log(LOG_INFO, format, ap);
+
+	va_end(ap);
+}
+
+void warn(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	android_log(LOG_WARN, format, ap);
+
+	va_end(ap);
+}
+
+void error(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	android_log(LOG_ERR, format, ap);
+
+	va_end(ap);
+}
+
+void btd_debug(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	android_log(LOG_DEBUG, format, ap);
+
+	va_end(ap);
+}
+
+extern struct btd_debug_desc __start___debug[];
+extern struct btd_debug_desc __stop___debug[];
+
+static char **enabled = NULL;
+
+static gboolean is_enabled(struct btd_debug_desc *desc)
+{
+	int i;
+
+	if (enabled == NULL)
+		return 0;
+
+	for (i = 0; enabled[i] != NULL; i++)
+		if (desc->file != NULL && g_pattern_match_simple(enabled[i],
+							desc->file) == TRUE)
+			return 1;
+
+	return 0;
+}
+
+void __btd_enable_debug(struct btd_debug_desc *start,
+					struct btd_debug_desc *stop)
+{
+	struct btd_debug_desc *desc;
+
+	if (start == NULL || stop == NULL)
+		return;
+
+	for (desc = start; desc < stop; desc++) {
+		if (is_enabled(desc))
+			desc->flags |= BTD_DEBUG_FLAG_PRINT;
+	}
+}
+
+void __btd_toggle_debug(void)
+{
+	struct btd_debug_desc *desc;
+
+	for (desc = __start___debug; desc < __stop___debug; desc++)
+		desc->flags |= BTD_DEBUG_FLAG_PRINT;
+}
+
+void __btd_log_init(const char *debug, int detach)
+{
+	if (debug != NULL)
+		enabled = g_strsplit_set(debug, ":, ", 0);
+
+	__btd_enable_debug(__start___debug, __stop___debug);
+
+	detached = detach;
+
+	system_fd = open("/dev/log/system", O_WRONLY);
+
+	info("Bluetooth daemon %s", VERSION);
+}
+
+void __btd_log_cleanup(void)
+{
+	close(system_fd);
+	system_fd = -1;
+
+	g_strfreev(enabled);
+}
diff --git a/android/main.c b/android/main.c
index 37a64c1..ef62b3d 100644
--- a/android/main.c
+++ b/android/main.c
@@ -33,6 +33,7 @@
 
 #include <glib.h>
 
+#include "log.h"
 #include "hcid.h"
 
 #define SHUTDOWN_GRACE_SECONDS 10
@@ -58,19 +59,45 @@ static void signal_handler(int sig)
 	case SIGINT:
 	case SIGTERM:
 		if (__terminated == 0) {
+			info("Terminating");
 			g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
 							quit_eventloop, NULL);
 		}
 
 		__terminated = 1;
 		break;
+
+	case SIGUSR2:
+		__btd_toggle_debug();
+		break;
 	}
 }
 
+static char *option_debug = NULL;
 static gboolean option_detach = TRUE;
 static gboolean option_version = FALSE;
 
+static void free_options(void)
+{
+	g_free(option_debug);
+	option_debug = NULL;
+}
+
+static gboolean parse_debug(const char *key, const char *value,
+				gpointer user_data, GError **error)
+{
+	if (value)
+		option_debug = g_strdup(value);
+	else
+		option_debug = g_strdup("*");
+
+	return TRUE;
+}
+
 static GOptionEntry options[] = {
+	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
+				G_OPTION_ARG_CALLBACK, parse_debug,
+				"Specify debug options to enable", "DEBUG" },
 	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
 				G_OPTION_ARG_NONE, &option_detach,
 				"Run with logging in foreground", NULL },
@@ -110,10 +137,22 @@ int main(int argc, char *argv[])
 	sa.sa_handler = signal_handler;
 	sigaction(SIGINT, &sa, NULL);
 	sigaction(SIGTERM, &sa, NULL);
+	sigaction(SIGUSR2, &sa, NULL);
+
+	__btd_log_init(option_debug, option_detach);
+
+	/* no need to keep parsed option in memory */
+	free_options();
+
+	DBG("Entering main loop");
 
 	g_main_loop_run(event_loop);
 
 	g_main_loop_unref(event_loop);
 
+	info("Exit");
+
+	__btd_log_cleanup();
+
 	return 0;
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH] Bluetooth: Add hci_h4p driver
From: Pali Rohár @ 2013-09-20 19:01 UTC (permalink / raw)
  To: Marcel Holtmann, Gustavo Padovan, Johan Hedberg
  Cc: Pavel Machek, linux-kernel, linux-bluetooth, Ville Tervo,
	Pali Rohár

From: Ville Tervo <ville.tervo@nokia.com>

This driver adding support for Nokia N900 bluetooth hardware

Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
---
 drivers/bluetooth/Kconfig             |   10 +
 drivers/bluetooth/Makefile            |    2 +
 drivers/bluetooth/hci_h4p/Makefile    |    7 +
 drivers/bluetooth/hci_h4p/core.c      | 1085 +++++++++++++++++++++++++++++++++
 drivers/bluetooth/hci_h4p/fw-bcm.c    |  149 +++++
 drivers/bluetooth/hci_h4p/fw-csr.c    |  152 +++++
 drivers/bluetooth/hci_h4p/fw-ti1273.c |  113 ++++
 drivers/bluetooth/hci_h4p/fw.c        |  166 +++++
 drivers/bluetooth/hci_h4p/hci_h4p.h   |  238 ++++++++
 drivers/bluetooth/hci_h4p/uart.c      |  203 ++++++
 include/linux/bluetooth/hci_h4p.h     |   41 ++
 11 files changed, 2166 insertions(+)
 create mode 100644 drivers/bluetooth/hci_h4p/Makefile
 create mode 100644 drivers/bluetooth/hci_h4p/core.c
 create mode 100644 drivers/bluetooth/hci_h4p/fw-bcm.c
 create mode 100644 drivers/bluetooth/hci_h4p/fw-csr.c
 create mode 100644 drivers/bluetooth/hci_h4p/fw-ti1273.c
 create mode 100644 drivers/bluetooth/hci_h4p/fw.c
 create mode 100644 drivers/bluetooth/hci_h4p/hci_h4p.h
 create mode 100644 drivers/bluetooth/hci_h4p/uart.c
 create mode 100644 include/linux/bluetooth/hci_h4p.h

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 11a6104..95155c3 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -242,4 +242,14 @@ config BT_WILINK
 
 	  Say Y here to compile support for Texas Instrument's WiLink7 driver
 	  into the kernel or say M to compile it as module.
+
+config BT_HCIH4P
+	tristate "HCI driver with H4 Nokia extensions"
+	depends on BT && ARCH_OMAP
+	help
+	  Bluetooth HCI driver with H4 extensions.  This driver provides
+	  support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+	  Say Y here to compile support for h4 extended devices into the kernel
+	  or say M to compile it as module (hci_h4p).
 endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 4afae20..a5e6e19 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -30,3 +30,5 @@ hci_uart-$(CONFIG_BT_HCIUART_LL)	+= hci_ll.o
 hci_uart-$(CONFIG_BT_HCIUART_ATH3K)	+= hci_ath.o
 hci_uart-$(CONFIG_BT_HCIUART_3WIRE)	+= hci_h5.o
 hci_uart-objs				:= $(hci_uart-y)
+
+obj-y				+= hci_h4p/
diff --git a/drivers/bluetooth/hci_h4p/Makefile b/drivers/bluetooth/hci_h4p/Makefile
new file mode 100644
index 0000000..f20bd9a
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux Bluetooth HCI device drivers.
+#
+
+obj-$(CONFIG_BT_HCIH4P)		+= hci_h4p.o
+
+hci_h4p-objs := core.o fw.o uart.o fw-csr.o fw-bcm.o fw-ti1273.o
diff --git a/drivers/bluetooth/hci_h4p/core.c b/drivers/bluetooth/hci_h4p/core.c
new file mode 100644
index 0000000..7ed9d4e
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/core.c
@@ -0,0 +1,1085 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2010 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/timer.h>
+#include <linux/bluetooth/hci_h4p.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "hci_h4p.h"
+
+static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->clocks_lock, flags);
+	if (enable && !*clock) {
+		NBT_DBG_POWER("Enabling %p\n", clock);
+		clk_prepare_enable(info->uart_fclk);
+		clk_prepare_enable(info->uart_iclk);
+		if (atomic_read(&info->clk_users) == 0)
+			hci_h4p_restore_regs(info);
+		atomic_inc(&info->clk_users);
+	}
+
+	if (!enable && *clock) {
+		NBT_DBG_POWER("Disabling %p\n", clock);
+		if (atomic_dec_and_test(&info->clk_users))
+			hci_h4p_store_regs(info);
+		clk_disable_unprepare(info->uart_fclk);
+		clk_disable_unprepare(info->uart_iclk);
+	}
+
+	*clock = enable;
+	spin_unlock_irqrestore(&info->clocks_lock, flags);
+}
+
+/* Power management functions */
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable)
+{
+	u8 v;
+
+	return;
+
+	v = hci_h4p_inb(info, UART_OMAP_SYSC);
+	v &= ~(UART_OMAP_SYSC_IDLEMASK);
+
+	if (enable)
+		v |= UART_OMAP_SYSC_SMART_IDLE;
+	else
+		v |= UART_OMAP_SYSC_NO_IDLE;
+
+	hci_h4p_outb(info, UART_OMAP_SYSC, v);
+}
+
+static void hci_h4p_disable_tx(struct hci_h4p_info *info)
+{
+	NBT_DBG_POWER("\n");
+
+	if (!info->pm_enabled)
+		return;
+
+	hci_h4p_smart_idle(info, 1);
+
+	info->bt_wakeup(0);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+	info->tx_enabled = 0;
+}
+
+void hci_h4p_enable_tx(struct hci_h4p_info *info)
+{
+	NBT_DBG_POWER("\n");
+
+	if (!info->pm_enabled)
+		return;
+
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+	info->tx_enabled = 1;
+	hci_h4p_smart_idle(info, 0);
+	info->bt_wakeup(1);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+		     UART_IER_THRI);
+}
+
+static void hci_h4p_disable_rx(struct hci_h4p_info *info)
+{
+	if (!info->pm_enabled)
+		return;
+
+	info->rx_enabled = 0;
+
+	if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+		NBT_DBG("data ready postpone autorts");
+		return;
+	}
+
+	if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) {
+		NBT_DBG("trasmitter not empty postpone autorts");
+		return;
+	}
+
+	hci_h4p_set_rts(info, info->rx_enabled);
+	__hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+	info->autorts = 0;
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+}
+
+static void hci_h4p_enable_rx(struct hci_h4p_info *info)
+{
+	if (!info->pm_enabled)
+		return;
+
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+	info->rx_enabled = 1;
+
+	hci_h4p_set_rts(info, 1);
+
+	if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) {
+		NBT_DBG("trasmitter not empty postpone autorts");
+		return;
+	}
+
+	if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+		NBT_DBG("data ready postpone autorts");
+		return;
+	}
+
+	__hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+	info->autorts = 1;
+}
+
+/* Negotiation functions */
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info)
+{
+	struct hci_h4p_alive_hdr *alive_hdr;
+	struct hci_h4p_alive_msg *alive_cmd;
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	NBT_DBG("Sending alive packet\n");
+
+	skb = bt_skb_alloc(HCI_H4P_ALIVE_HDR_SIZE + HCI_H4P_ALIVE_MSG_SIZE, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	alive_hdr = (void *) skb_put(skb, HCI_H4P_ALIVE_HDR_SIZE);
+	alive_hdr->dlen = HCI_H4P_ALIVE_MSG_SIZE;
+	alive_cmd = (void *) skb_put(skb, HCI_H4P_ALIVE_MSG_SIZE);
+	alive_cmd->message_id = HCI_H4P_ALIVE_IND_REQ;
+	alive_cmd->unused = 0x00;
+	*skb_push(skb, 1) = H4_ALIVE_PKT;
+
+	skb_queue_tail(&info->txq, skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+		     UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	NBT_DBG("Alive packet sent\n");
+
+	return 0;
+}
+
+static void hci_h4p_alive_packet(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	struct hci_h4p_alive_hdr *alive_hdr = (void *) skb->data;
+	struct hci_h4p_alive_msg *alive_evt;
+
+	if (alive_hdr->dlen > skb->len) {
+		info->init_error = -EPROTO;
+		complete(&info->init_completion);
+		return;
+	}
+
+	alive_evt = (void *) skb_pull(skb, HCI_H4P_ALIVE_HDR_SIZE);
+
+	NBT_DBG("Received alive packet\n");
+	if (alive_evt->message_id != HCI_H4P_ALIVE_IND_RESP) {
+		dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+		info->init_error = -EINVAL;
+	}
+
+	complete(&info->init_completion);
+	kfree_skb(skb);
+}
+
+static int hci_h4p_send_negotiation(struct hci_h4p_info *info)
+{
+	struct hci_h4p_init_cmd *init_cmd;
+	struct hci_h4p_init_hdr *init_hdr;
+	struct sk_buff *skb;
+	unsigned long flags;
+	int err;
+
+	NBT_DBG("Sending negotiation..\n");
+
+	skb = bt_skb_alloc(HCI_H4P_INIT_HDR_SIZE + HCI_H4P_INIT_CMD_SIZE, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	init_hdr = (void *)skb_put(skb, HCI_H4P_INIT_HDR_SIZE);
+	init_hdr->dlen = HCI_H4P_INIT_CMD_SIZE;
+	init_cmd = (void *)skb_put(skb, HCI_H4P_INIT_CMD_SIZE);
+	init_cmd->ack = 0x00;
+	init_cmd->baudrate = cpu_to_le16(0x01a1);
+	init_cmd->unused = cpu_to_le16(0x0000);
+	init_cmd->mode = HCI_H4P_MODE;
+	init_cmd->sys_clk = cpu_to_le16(0x9600);
+	init_cmd->unused2 = cpu_to_le16(0x0000);
+	*skb_push(skb, 1) = H4_NEG_PKT;
+
+	hci_h4p_change_speed(info, INIT_SPEED);
+
+	hci_h4p_set_rts(info, 1);
+	info->init_error = 0;
+	init_completion(&info->init_completion);
+	skb_queue_tail(&info->txq, skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+				msecs_to_jiffies(1000)))
+		return -ETIMEDOUT;
+
+	if (info->init_error < 0)
+		return info->init_error;
+
+	/* Change to operational settings */
+	hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+	hci_h4p_set_rts(info, 0);
+	hci_h4p_change_speed(info, MAX_BAUD_RATE);
+
+	err = hci_h4p_wait_for_cts(info, 1, 100);
+	if (err < 0)
+		return err;
+
+	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+	init_completion(&info->init_completion);
+	err = hci_h4p_send_alive_packet(info);
+
+	if (err < 0)
+		return err;
+
+	if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+				msecs_to_jiffies(1000)))
+		return -ETIMEDOUT;
+
+	if (info->init_error < 0)
+		return info->init_error;
+
+	NBT_DBG("Negotiation succesful\n");
+	return 0;
+}
+
+static void hci_h4p_negotiation_packet(struct hci_h4p_info *info,
+				       struct sk_buff *skb)
+{
+	struct hci_h4p_init_hdr *init_hdr = (void *) skb->data;
+	struct hci_h4p_init_evt *init_evt;
+
+	if (init_hdr->dlen > skb->len) {
+		kfree_skb(skb);
+		info->init_error = -EPROTO;
+		complete(&info->init_completion);
+		return;
+	}
+
+	init_evt = (void *)skb_pull(skb, HCI_H4P_INIT_HDR_SIZE);
+
+	if (init_evt->ack != HCI_H4P_ACK) {
+		dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+		info->init_error = -EINVAL;
+	}
+
+	info->man_id = init_evt->man_id;
+	info->ver_id = init_evt->ver_id;
+
+	complete(&info->init_completion);
+	kfree_skb(skb);
+}
+
+/* H4 packet handling functions */
+static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, u8 pkt_type)
+{
+	long retval;
+
+	switch (pkt_type) {
+	case H4_EVT_PKT:
+		retval = HCI_EVENT_HDR_SIZE;
+		break;
+	case H4_ACL_PKT:
+		retval = HCI_ACL_HDR_SIZE;
+		break;
+	case H4_SCO_PKT:
+		retval = HCI_SCO_HDR_SIZE;
+		break;
+	case H4_NEG_PKT:
+		retval = HCI_H4P_INIT_HDR_SIZE;
+		break;
+	case H4_ALIVE_PKT:
+		retval = HCI_H4P_ALIVE_HDR_SIZE;
+		break;
+	case H4_RADIO_PKT:
+		retval = H4_RADIO_HDR_SIZE;
+		break;
+	default:
+		dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type);
+		retval = -1;
+		break;
+	}
+
+	return retval;
+}
+
+static unsigned int hci_h4p_get_data_len(struct hci_h4p_info *info,
+					 struct sk_buff *skb)
+{
+	long retval = -1;
+	struct hci_event_hdr *evt_hdr;
+	struct hci_acl_hdr *acl_hdr;
+	struct hci_sco_hdr *sco_hdr;
+	struct hci_h4p_radio_hdr *radio_hdr;
+	struct hci_h4p_init_hdr *init_hdr;
+	struct hci_h4p_alive_hdr *alive_hdr;
+
+	switch (bt_cb(skb)->pkt_type) {
+	case H4_EVT_PKT:
+		evt_hdr = (struct hci_event_hdr *)skb->data;
+		retval = evt_hdr->plen;
+		break;
+	case H4_ACL_PKT:
+		acl_hdr = (struct hci_acl_hdr *)skb->data;
+		retval = le16_to_cpu(acl_hdr->dlen);
+		break;
+	case H4_SCO_PKT:
+		sco_hdr = (struct hci_sco_hdr *)skb->data;
+		retval = sco_hdr->dlen;
+		break;
+	case H4_RADIO_PKT:
+		radio_hdr = (struct hci_h4p_radio_hdr *)skb->data;
+		retval = radio_hdr->dlen;
+		break;
+	case H4_NEG_PKT:
+		init_hdr = (struct hci_h4p_init_hdr *)skb->data;
+		retval = init_hdr->dlen;
+		break;
+	case H4_ALIVE_PKT:
+		alive_hdr = (struct hci_h4p_alive_hdr *)skb->data;
+		retval = alive_hdr->dlen;
+		break;
+	}
+
+	return retval;
+}
+
+static inline void hci_h4p_recv_frame(struct hci_h4p_info *info,
+				      struct sk_buff *skb)
+{
+
+	if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+		NBT_DBG("fw_event\n");
+		if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+			hci_h4p_negotiation_packet(info, info->rx_skb);
+			return;
+		}
+		if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+			hci_h4p_alive_packet(info, info->rx_skb);
+			return;
+		}
+		hci_h4p_parse_fw_event(info, skb);
+	} else {
+		hci_recv_frame(skb);
+		NBT_DBG("Frame sent to upper layer\n");
+	}
+}
+
+static inline void hci_h4p_handle_byte(struct hci_h4p_info *info, u8 byte)
+{
+	switch (info->rx_state) {
+	case WAIT_FOR_PKT_TYPE:
+		bt_cb(info->rx_skb)->pkt_type = byte;
+		info->rx_count = hci_h4p_get_hdr_len(info, byte);
+		if (info->rx_count < 0) {
+			info->hdev->stat.err_rx++;
+			kfree_skb(info->rx_skb);
+			info->rx_skb = NULL;
+		} else {
+			info->rx_state = WAIT_FOR_HEADER;
+		}
+		break;
+	case WAIT_FOR_HEADER:
+		info->rx_count--;
+		*skb_put(info->rx_skb, 1) = byte;
+		if (info->rx_count != 0)
+			break;
+
+		info->rx_count = hci_h4p_get_data_len(info,
+				info->rx_skb);
+		if (info->rx_count > skb_tailroom(info->rx_skb)) {
+			dev_err(info->dev, "Too long frame.\n");
+			info->garbage_bytes = info->rx_count -
+				skb_tailroom(info->rx_skb);
+			kfree_skb(info->rx_skb);
+			info->rx_skb = NULL;
+			break;
+		}
+		info->rx_state = WAIT_FOR_DATA;
+		break;
+	case WAIT_FOR_DATA:
+		info->rx_count--;
+		*skb_put(info->rx_skb, 1) = byte;
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+
+	if (info->rx_count == 0) {
+		/* H4+ devices should allways send word aligned
+		 * packets */
+		if (!(info->rx_skb->len % 2))
+			info->garbage_bytes++;
+		hci_h4p_recv_frame(info, info->rx_skb);
+		info->rx_skb = NULL;
+	}
+}
+
+static void hci_h4p_rx(unsigned long data)
+{
+	u8 byte;
+	struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+	NBT_DBG("rx woke up\n");
+
+	while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+		byte = hci_h4p_inb(info, UART_RX);
+		if (info->garbage_bytes) {
+			info->garbage_bytes--;
+			continue;
+		}
+		if (info->rx_skb == NULL) {
+			info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
+						    GFP_ATOMIC);
+			if (!info->rx_skb) {
+				dev_err(info->dev,
+					"No memory for new packet\n");
+				return;
+			}
+			info->rx_state = WAIT_FOR_PKT_TYPE;
+			info->rx_skb->dev = (void *)info->hdev;
+		}
+		info->hdev->stat.byte_rx++;
+		NBT_DBG_TRANSFER_NF("0x%.2x  ", byte);
+		hci_h4p_handle_byte(info, byte);
+	}
+
+	if (info->rx_enabled == info->autorts)
+		return;
+
+	if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT))
+		return;
+
+	if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)
+		return;
+
+	hci_h4p_set_rts(info, info->rx_enabled);
+	__hci_h4p_set_auto_ctsrts(info, info->rx_enabled, UART_EFR_RTS);
+	info->autorts = info->rx_enabled;
+
+	/* Flush posted write to avoid spurious interrupts */
+	hci_h4p_inb(info, UART_OMAP_SCR);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+}
+
+static void hci_h4p_tx(unsigned long data)
+{
+	unsigned int sent = 0;
+	struct sk_buff *skb;
+	struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+	NBT_DBG("tx woke up\n");
+	NBT_DBG_TRANSFER("data ");
+
+	if (info->autorts != info->rx_enabled) {
+		NBT_DBG("rts unbalanced.. autorts %d rx_enabled %d", info->autorts, info->rx_enabled);
+		if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT &&
+		    !(hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)) {
+			__hci_h4p_set_auto_ctsrts(info, info->rx_enabled,
+							  UART_EFR_RTS);
+			info->autorts = info->rx_enabled;
+			hci_h4p_set_rts(info, info->rx_enabled);
+			hci_h4p_set_clk(info, &info->rx_clocks_en,
+					info->rx_enabled);
+			NBT_DBG("transmitter empty. setinng into balance\n");
+		} else {
+			hci_h4p_outb(info, UART_OMAP_SCR,
+				     hci_h4p_inb(info, UART_OMAP_SCR) |
+				     UART_OMAP_SCR_EMPTY_THR);
+			NBT_DBG("transmitter/receiver was not empty waiting for next irq\n");
+			hci_h4p_set_rts(info, 1);
+			goto finish_tx;
+		}
+	}
+
+	skb = skb_dequeue(&info->txq);
+	if (!skb) {
+		/* No data in buffer */
+		NBT_DBG("skb ready\n");
+		if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+			hci_h4p_outb(info, UART_IER,
+				     hci_h4p_inb(info, UART_IER) &
+				     ~UART_IER_THRI);
+			hci_h4p_inb(info, UART_OMAP_SCR);
+			hci_h4p_disable_tx(info);
+			NBT_DBG("transmitter was empty. cleaning up\n");
+			return;
+		}
+		hci_h4p_outb(info, UART_OMAP_SCR,
+				hci_h4p_inb(info, UART_OMAP_SCR) |
+				UART_OMAP_SCR_EMPTY_THR);
+		NBT_DBG("transmitter was not empty waiting for next irq\n");
+		goto finish_tx;
+	}
+
+	/* Copy data to tx fifo */
+	while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+	       (sent < skb->len)) {
+		NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+		hci_h4p_outb(info, UART_TX, skb->data[sent]);
+		sent++;
+	}
+
+	info->hdev->stat.byte_tx += sent;
+	if (skb->len == sent) {
+		kfree_skb(skb);
+	} else {
+		skb_pull(skb, sent);
+		skb_queue_head(&info->txq, skb);
+	}
+
+	hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) &
+						     ~UART_OMAP_SCR_EMPTY_THR);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+						 UART_IER_THRI);
+
+finish_tx:
+	/* Flush posted write to avoid spurious interrupts */
+	hci_h4p_inb(info, UART_OMAP_SCR);
+
+}
+
+static irqreturn_t hci_h4p_interrupt(int irq, void *data)
+{
+	struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+	u8 iir, msr;
+	int ret;
+
+	ret = IRQ_NONE;
+
+	iir = hci_h4p_inb(info, UART_IIR);
+	if (iir & UART_IIR_NO_INT)
+		return IRQ_HANDLED;
+
+	NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+	iir &= UART_IIR_ID;
+
+	if (iir == UART_IIR_MSI) {
+		msr = hci_h4p_inb(info, UART_MSR);
+		ret = IRQ_HANDLED;
+	}
+	if (iir == UART_IIR_RLSI) {
+		hci_h4p_inb(info, UART_RX);
+		hci_h4p_inb(info, UART_LSR);
+		ret = IRQ_HANDLED;
+	}
+
+	if (iir == UART_IIR_RDI) {
+		hci_h4p_rx((unsigned long)data);
+		ret = IRQ_HANDLED;
+	}
+
+	if (iir == UART_IIR_THRI) {
+		hci_h4p_tx((unsigned long)data);
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst)
+{
+	struct hci_h4p_info *info = dev_inst;
+	int should_wakeup;
+	struct hci_dev *hdev;
+
+	if (!info->hdev)
+		return IRQ_HANDLED;
+
+	hdev = info->hdev;
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return IRQ_HANDLED;
+
+	should_wakeup = info->host_wakeup();
+	NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+
+	/* Check if wee have missed some interrupts */
+	if (info->rx_enabled == should_wakeup)
+		return IRQ_HANDLED;
+
+	if (should_wakeup)
+		hci_h4p_enable_rx(info);
+	else
+		hci_h4p_disable_rx(info);
+
+	return IRQ_HANDLED;
+}
+
+static int hci_h4p_reset(struct hci_h4p_info *info)
+{
+	int err;
+
+	err = hci_h4p_reset_uart(info);
+	if (err < 0) {
+		dev_err(info->dev, "Uart reset failed\n");
+		return err;
+	}
+	hci_h4p_init_uart(info);
+	hci_h4p_set_rts(info, 0);
+
+	info->reset(0);
+	info->bt_wakeup(1);
+	msleep(10);
+	info->reset(1);
+
+	err = hci_h4p_wait_for_cts(info, 1, 100);
+	if (err < 0) {
+		dev_err(info->dev, "No cts from bt chip\n");
+		return err;
+	}
+
+	hci_h4p_set_rts(info, 1);
+
+	return 0;
+}
+
+/* hci callback functions */
+static int hci_h4p_hci_flush(struct hci_dev *hdev)
+{
+	struct hci_h4p_info *info;
+	info = hci_get_drvdata(hdev);
+
+	skb_queue_purge(&info->txq);
+
+	return 0;
+}
+
+static int hci_h4p_hci_open(struct hci_dev *hdev)
+{
+	struct hci_h4p_info *info;
+	int err;
+	struct sk_buff_head fw_queue;
+	unsigned long flags;
+
+	info = hci_get_drvdata(hdev);
+
+	if (test_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	info->rx_enabled = 1;
+	info->rx_state = WAIT_FOR_PKT_TYPE;
+	info->rx_count = 0;
+	info->garbage_bytes = 0;
+	info->rx_skb = NULL;
+	info->pm_enabled = 0;
+	init_completion(&info->fw_completion);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+	skb_queue_head_init(&fw_queue);
+
+	err = hci_h4p_reset(info);
+	if (err < 0)
+		goto err_clean;
+
+	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+	info->autorts = 1;
+	err = hci_h4p_send_negotiation(info);
+	if (err < 0)
+		goto err_clean;
+
+	skb_queue_head_init(&fw_queue);
+	err = hci_h4p_read_fw(info, &fw_queue);
+	if (err < 0) {
+		dev_err(info->dev, "Cannot read firmware\n");
+		return err;
+	}
+
+	/* FW image contains also unneeded negoation and alive msgs */
+	skb_dequeue(&fw_queue);
+	skb_dequeue(&fw_queue);
+
+	err = hci_h4p_send_fw(info, &fw_queue);
+	if (err < 0) {
+		dev_err(info->dev, "Sending firmware failed.\n");
+		goto err_clean;
+	}
+
+	info->pm_enabled = 1;
+
+	spin_lock_irqsave(&info->lock, flags);
+	info->rx_enabled = info->host_wakeup();
+	hci_h4p_set_clk(info, &info->rx_clocks_en, info->rx_enabled);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+	set_bit(HCI_RUNNING, &hdev->flags);
+
+	NBT_DBG("hci up and running\n");
+	return 0;
+
+err_clean:
+	hci_h4p_hci_flush(hdev);
+	hci_h4p_reset_uart(info);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+	info->reset(0);
+	info->bt_wakeup(0);
+	skb_queue_purge(&fw_queue);
+	kfree_skb(info->rx_skb);
+
+	return err;
+}
+
+static int hci_h4p_hci_close(struct hci_dev *hdev)
+{
+	struct hci_h4p_info *info = hci_get_drvdata(hdev);
+
+	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	hci_h4p_hci_flush(hdev);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+	hci_h4p_reset_uart(info);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+	hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+	info->reset(0);
+	info->bt_wakeup(0);
+	kfree_skb(info->rx_skb);
+
+	return 0;
+}
+
+static int hci_h4p_hci_send_frame(struct sk_buff *skb)
+{
+	struct hci_h4p_info *info;
+	struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+	int err = 0;
+	unsigned long flags;
+
+	if (!hdev) {
+		printk(KERN_WARNING "hci_h4p: Frame for unknown device\n");
+		return -ENODEV;
+	}
+
+	NBT_DBG("dev %p, skb %p\n", hdev, skb);
+
+	info = hci_get_drvdata(hdev);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+		dev_warn(info->dev, "Frame for non-running device\n");
+		return -EIO;
+	}
+
+	switch (bt_cb(skb)->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	}
+
+	/* Push frame type to skb */
+	*skb_push(skb, 1) = (bt_cb(skb)->pkt_type);
+	/* We should allways send word aligned data to h4+ devices */
+	if (skb->len % 2) {
+		err = skb_pad(skb, 1);
+		if (!err)
+			*skb_put(skb, 1) = 0x00;
+	}
+	if (err)
+		return err;
+
+	spin_lock_irqsave(&info->lock, flags);
+	skb_queue_tail(&info->txq, skb);
+	hci_h4p_enable_tx(info);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	return 0;
+}
+
+static int hci_h4p_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,
+			     unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+static int hci_h4p_register_hdev(struct hci_h4p_info *info)
+{
+	struct hci_dev *hdev;
+
+	/* Initialize and register HCI device */
+
+	hdev = hci_alloc_dev();
+	if (!hdev) {
+		dev_err(info->dev, "Can't allocate memory for device\n");
+		return -ENOMEM;
+	}
+	info->hdev = hdev;
+
+	hdev->bus = HCI_UART;
+	hci_set_drvdata(hdev, info);
+
+	hdev->open = hci_h4p_hci_open;
+	hdev->close = hci_h4p_hci_close;
+	hdev->flush = hci_h4p_hci_flush;
+	hdev->send = hci_h4p_hci_send_frame;
+	hdev->ioctl = hci_h4p_hci_ioctl;
+	set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+	SET_HCIDEV_DEV(hdev, info->dev);
+
+	if (hci_register_dev(hdev) < 0) {
+		dev_err(info->dev, "hci_register failed %s.\n", hdev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static ssize_t hci_h4p_store_bdaddr(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct hci_h4p_info *info = dev_get_drvdata(dev);
+	unsigned int bdaddr[6];
+	int ret, i;
+
+	ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+			&bdaddr[0], &bdaddr[1], &bdaddr[2],
+			&bdaddr[3], &bdaddr[4], &bdaddr[5]);
+
+	if (ret != 6)
+		return -EINVAL;
+
+	for (i = 0; i < 6; i++)
+		info->bd_addr[i] = bdaddr[i] & 0xff;
+
+	return count;
+}
+
+static ssize_t hci_h4p_show_bdaddr(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct hci_h4p_info *info = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+		       info->bd_addr[0], info->bd_addr[1], info->bd_addr[2],
+		       info->bd_addr[3], info->bd_addr[4], info->bd_addr[5]);
+}
+
+static DEVICE_ATTR(bdaddr, S_IRUGO | S_IWUSR, hci_h4p_show_bdaddr,
+		   hci_h4p_store_bdaddr);
+
+static int hci_h4p_sysfs_create_files(struct device *dev)
+{
+	return device_create_file(dev, &dev_attr_bdaddr);
+}
+
+static void hci_h4p_sysfs_remove_files(struct device *dev)
+{
+	device_remove_file(dev, &dev_attr_bdaddr);
+}
+
+static int hci_h4p_probe(struct platform_device *pdev)
+{
+	struct hci_h4p_platform_data *bt_plat_data;
+	struct hci_h4p_info *info;
+	int err;
+
+	dev_info(&pdev->dev, "Registering HCI H4P device\n");
+	info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = &pdev->dev;
+	info->pm_enabled = 0;
+	info->tx_enabled = 1;
+	info->rx_enabled = 1;
+	info->garbage_bytes = 0;
+	info->tx_clocks_en = 0;
+	info->rx_clocks_en = 0;
+	spin_lock_init(&info->lock);
+	spin_lock_init(&info->clocks_lock);
+	skb_queue_head_init(&info->txq);
+
+	if (pdev->dev.platform_data == NULL) {
+		dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
+		kfree(info);
+		return -ENODATA;
+	}
+
+	bt_plat_data = pdev->dev.platform_data;
+	info->chip_type = 3;
+	info->bt_wakeup = bt_plat_data->bt_wu;
+	info->host_wakeup = bt_plat_data->host_wu;
+	info->reset = bt_plat_data->reset;
+	info->uart_base = bt_plat_data->uart_base;
+	info->host_wakeup_gpio = bt_plat_data->host_wu_gpio;
+
+	NBT_DBG("RESET gpio: %p\n", info->reset);
+	NBT_DBG("BTWU gpio: %p\n", info->bt_wakeup);
+	NBT_DBG("HOSTWU gpio: %p\n", info->host_wakeup);
+
+	info->irq = bt_plat_data->uart_irq;
+	err = request_irq(info->irq, hci_h4p_interrupt, IRQF_DISABLED | IRQF_SHARED,
+			"hci_h4p", info);
+	if (err < 0) {
+		dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", info->irq);
+		goto cleanup;
+	}
+
+	err = request_irq(gpio_to_irq(info->host_wakeup_gpio),
+			  hci_h4p_wakeup_interrupt,  IRQF_TRIGGER_FALLING |
+			  IRQF_TRIGGER_RISING | IRQF_DISABLED,
+			  "hci_h4p_wkup", info);
+	if (err < 0) {
+		dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
+			  gpio_to_irq(info->host_wakeup_gpio));
+		free_irq(info->irq, info);
+		goto cleanup;
+	}
+
+	err = irq_set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1);
+	if (err < 0) {
+		dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n",
+				gpio_to_irq(info->host_wakeup_gpio));
+		free_irq(info->irq, info);
+		free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+		goto cleanup;
+	}
+
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+	err = hci_h4p_reset_uart(info);
+	if (err < 0)
+		goto cleanup_irq;
+	hci_h4p_init_uart(info);
+	hci_h4p_set_rts(info, 0);
+	err = hci_h4p_reset(info);
+	hci_h4p_reset_uart(info);
+	if (err < 0)
+		goto cleanup_irq;
+	info->reset(0);
+	hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+	platform_set_drvdata(pdev, info);
+
+	if (hci_h4p_sysfs_create_files(info->dev) < 0) {
+		dev_err(info->dev, "failed to create sysfs files\n");
+		goto cleanup_irq;
+	}
+
+	if (hci_h4p_register_hdev(info) < 0) {
+		dev_err(info->dev, "failed to register hci_h4p hci device\n");
+		goto cleanup_sysfs;
+	}
+
+	return 0;
+
+cleanup_sysfs:
+	hci_h4p_sysfs_remove_files(info->dev);
+cleanup_irq:
+	free_irq(info->irq, (void *)info);
+	free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+cleanup:
+	info->reset(0);
+	kfree(info);
+	return err;
+
+}
+
+static int hci_h4p_remove(struct platform_device *pdev)
+{
+	struct hci_h4p_info *info;
+
+	info = platform_get_drvdata(pdev);
+
+	hci_h4p_sysfs_remove_files(info->dev);
+	hci_h4p_hci_close(info->hdev);
+	free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+	hci_unregister_dev(info->hdev);
+	hci_free_dev(info->hdev);
+	free_irq(info->irq, (void *) info);
+	kfree(info);
+
+	return 0;
+}
+
+static struct platform_driver hci_h4p_driver = {
+	.probe		= hci_h4p_probe,
+	.remove		= hci_h4p_remove,
+	.driver		= {
+		.name	= "hci_h4p",
+	},
+};
+
+static int __init hci_h4p_init(void)
+{
+	int err = 0;
+
+	/* Register the driver with LDM */
+	err = platform_driver_register(&hci_h4p_driver);
+	if (err < 0)
+		printk(KERN_WARNING "failed to register hci_h4p driver\n");
+
+	return err;
+}
+
+static void __exit hci_h4p_exit(void)
+{
+	platform_driver_unregister(&hci_h4p_driver);
+}
+
+module_init(hci_h4p_init);
+module_exit(hci_h4p_exit);
+
+MODULE_ALIAS("platform:hci_h4p");
+MODULE_DESCRIPTION("Bluetooth h4 driver with nokia extensions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo");
+MODULE_FIRMWARE(FW_NAME_CSR);
+MODULE_FIRMWARE(FW_NAME_TI);
+MODULE_FIRMWARE(FW_NAME_BCM);
diff --git a/drivers/bluetooth/hci_h4p/fw-bcm.c b/drivers/bluetooth/hci_h4p/fw-bcm.c
new file mode 100644
index 0000000..56684f8
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-bcm.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * 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 <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
+	int not_valid;
+	int i;
+
+	not_valid = 1;
+	for (i = 0; i < 6; i++) {
+		if (info->bd_addr[i] != 0x00) {
+			not_valid = 0;
+			break;
+		}
+	}
+
+	if (not_valid) {
+		dev_info(info->dev, "Valid bluetooth address not found, setting some random\n");
+		/* When address is not valid, use some random but Nokia MAC */
+		memcpy(info->bd_addr, nokia_oui, 3);
+		get_random_bytes(info->bd_addr + 3, 3);
+	}
+
+	for (i = 0; i < 6; i++)
+		skb->data[9 - i] = info->bd_addr[i];
+
+	return 0;
+}
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	struct sk_buff *fw_skb;
+	int err;
+	unsigned long flags;
+
+	if (skb->data[5] != 0x00) {
+		dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+			skb->data[5]);
+		info->fw_error = -EPROTO;
+	}
+
+	kfree_skb(skb);
+
+	fw_skb = skb_dequeue(info->fw_q);
+	if (fw_skb == NULL || info->fw_error) {
+		complete(&info->fw_completion);
+		return;
+	}
+
+	if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && fw_skb->len >= 10) {
+		NBT_DBG_FW("Setting bluetooth address\n");
+		err = hci_h4p_bcm_set_bdaddr(info, fw_skb);
+		if (err < 0) {
+			kfree_skb(fw_skb);
+			info->fw_error = err;
+			complete(&info->fw_completion);
+			return;
+		}
+	}
+
+	skb_queue_tail(&info->txq, fw_skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue)
+{
+	struct sk_buff *skb;
+	unsigned long flags, time;
+
+	info->fw_error = 0;
+
+	NBT_DBG_FW("Sending firmware\n");
+
+	time = jiffies;
+
+	info->fw_q = fw_queue;
+	skb = skb_dequeue(fw_queue);
+	if (!skb)
+		return -ENODATA;
+
+	NBT_DBG_FW("Sending commands\n");
+
+	/*
+	 * Disable smart-idle as UART TX interrupts
+	 * are not wake-up capable
+	 */
+	hci_h4p_smart_idle(info, 0);
+
+	/* Check if this is bd_address packet */
+	init_completion(&info->fw_completion);
+	skb_queue_tail(&info->txq, skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	if (!wait_for_completion_timeout(&info->fw_completion,
+				msecs_to_jiffies(2000))) {
+		dev_err(info->dev, "No reply to fw command\n");
+		return -ETIMEDOUT;
+	}
+
+	if (info->fw_error) {
+		dev_err(info->dev, "FW error\n");
+		return -EPROTO;
+	}
+
+	NBT_DBG_FW("Firmware sent in %d msecs\n",
+		   jiffies_to_msecs(jiffies-time));
+
+	hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+	hci_h4p_set_rts(info, 0);
+	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+	return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw-csr.c b/drivers/bluetooth/hci_h4p/fw-csr.c
new file mode 100644
index 0000000..af880d9
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-csr.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * 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 <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	/* Check if this is fw packet */
+	if (skb->data[0] != 0xff) {
+		hci_recv_frame(skb);
+		return;
+	}
+
+	if (skb->data[11] || skb->data[12]) {
+		dev_err(info->dev, "Firmware sending command failed\n");
+		info->fw_error = -EPROTO;
+	}
+
+	kfree_skb(skb);
+	complete(&info->fw_completion);
+}
+
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue)
+{
+	static const u8 nokia_oui[3] = {0x00, 0x19, 0x4F};
+	struct sk_buff *skb;
+	unsigned int offset;
+	int retries, count, i, not_valid;
+	unsigned long flags;
+
+	info->fw_error = 0;
+
+	NBT_DBG_FW("Sending firmware\n");
+	skb = skb_dequeue(fw_queue);
+
+	if (!skb)
+		return -ENOMSG;
+
+	/* Check if this is bd_address packet */
+	if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
+		offset = 21;
+		skb->data[offset + 1] = 0x00;
+		skb->data[offset + 5] = 0x00;
+
+		not_valid = 1;
+		for (i = 0; i < 6; i++) {
+			if (info->bd_addr[i] != 0x00) {
+				not_valid = 0;
+				break;
+			}
+		}
+
+		if (not_valid) {
+			dev_info(info->dev, "Valid bluetooth address not found,"
+					" setting some random\n");
+			/* When address is not valid, use some random */
+			memcpy(info->bd_addr, nokia_oui, 3);
+			get_random_bytes(info->bd_addr + 3, 3);
+		}
+
+		skb->data[offset + 7] = info->bd_addr[0];
+		skb->data[offset + 6] = info->bd_addr[1];
+		skb->data[offset + 4] = info->bd_addr[2];
+		skb->data[offset + 0] = info->bd_addr[3];
+		skb->data[offset + 3] = info->bd_addr[4];
+		skb->data[offset + 2] = info->bd_addr[5];
+	}
+
+	for (count = 1; ; count++) {
+		NBT_DBG_FW("Sending firmware command %d\n", count);
+		init_completion(&info->fw_completion);
+		skb_queue_tail(&info->txq, skb);
+		spin_lock_irqsave(&info->lock, flags);
+		hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+							 UART_IER_THRI);
+		spin_unlock_irqrestore(&info->lock, flags);
+
+		skb = skb_dequeue(fw_queue);
+		if (!skb)
+			break;
+
+		if (!wait_for_completion_timeout(&info->fw_completion,
+						 msecs_to_jiffies(1000))) {
+			dev_err(info->dev, "No reply to fw command\n");
+			return -ETIMEDOUT;
+		}
+
+		if (info->fw_error) {
+			dev_err(info->dev, "FW error\n");
+			return -EPROTO;
+		}
+	};
+
+	/* Wait for chip warm reset */
+	retries = 100;
+	while ((!skb_queue_empty(&info->txq) ||
+	       !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
+	       retries--) {
+		msleep(10);
+	}
+	if (!retries) {
+		dev_err(info->dev, "Transmitter not empty\n");
+		return -ETIMEDOUT;
+	}
+
+	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+
+	if (hci_h4p_wait_for_cts(info, 1, 100)) {
+		dev_err(info->dev, "cts didn't deassert after final speed\n");
+		return -ETIMEDOUT;
+	}
+
+	retries = 100;
+	do {
+		init_completion(&info->init_completion);
+		hci_h4p_send_alive_packet(info);
+		retries--;
+	} while (!wait_for_completion_timeout(&info->init_completion, 100) &&
+		 retries > 0);
+
+	if (!retries) {
+		dev_err(info->dev, "No alive reply after speed change\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw-ti1273.c b/drivers/bluetooth/hci_h4p/fw-ti1273.c
new file mode 100644
index 0000000..d46c3a0
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-ti1273.c
@@ -0,0 +1,113 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * 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 <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static struct sk_buff_head *fw_q;
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+			struct sk_buff *skb)
+{
+	struct sk_buff *fw_skb;
+	unsigned long flags;
+
+	if (skb->data[5] != 0x00) {
+		dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+			skb->data[5]);
+		info->fw_error = -EPROTO;
+	}
+
+	kfree_skb(skb);
+
+	fw_skb = skb_dequeue(fw_q);
+	if (fw_skb == NULL || info->fw_error) {
+		complete(&info->fw_completion);
+		return;
+	}
+
+	hci_h4p_enable_tx(info);
+	skb_queue_tail(&info->txq, fw_skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue)
+{
+	struct sk_buff *skb;
+	unsigned long flags, time;
+
+	info->fw_error = 0;
+
+	NBT_DBG_FW("Sending firmware\n");
+
+	time = jiffies;
+
+	fw_q = fw_queue;
+	skb = skb_dequeue(fw_queue);
+	if (!skb)
+		return -ENODATA;
+
+	NBT_DBG_FW("Sending commands\n");
+	/* Check if this is bd_address packet */
+	init_completion(&info->fw_completion);
+	hci_h4p_enable_tx(info);
+	skb_queue_tail(&info->txq, skb);
+	spin_lock_irqsave(&info->lock, flags);
+	hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+			UART_IER_THRI);
+	spin_unlock_irqrestore(&info->lock, flags);
+
+	if (!wait_for_completion_timeout(&info->fw_completion,
+				msecs_to_jiffies(40000))) {
+		dev_err(info->dev, "No reply to fw command\n");
+		return -ETIMEDOUT;
+	}
+
+	if (info->fw_error) {
+		dev_err(info->dev, "FW error\n");
+		return -EPROTO;
+	}
+
+	NBT_DBG_FW("Firmware sent in %d msecs\n",
+		   jiffies_to_msecs(jiffies-time));
+
+	hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+	hci_h4p_set_rts(info, 0);
+	hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+	if (hci_h4p_wait_for_cts(info, 1, 100)) {
+		dev_err(info->dev,
+			"cts didn't go down after final speed change\n");
+		return -ETIMEDOUT;
+	}
+	hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+	return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw.c b/drivers/bluetooth/hci_h4p/fw.c
new file mode 100644
index 0000000..b767a12
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw.c
@@ -0,0 +1,166 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * 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 <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+#include "hci_h4p.h"
+
+static int fw_pos;
+
+/* Firmware handling */
+static int hci_h4p_open_firmware(struct hci_h4p_info *info,
+				 const struct firmware **fw_entry)
+{
+	int err;
+
+	fw_pos = 0;
+	NBT_DBG_FW("Opening %d/%d firmware\n", info->man_id, info->ver_id);
+	switch (info->man_id) {
+	case BT_CHIP_TI:
+		err = request_firmware(fw_entry, FW_NAME_TI, info->dev);
+		break;
+	case BT_CHIP_CSR:
+		err = request_firmware(fw_entry, FW_NAME_CSR, info->dev);
+		break;
+	case BT_CHIP_BCM:
+		err = request_firmware(fw_entry, FW_NAME_BCM, info->dev);
+		break;
+	default:
+		dev_err(info->dev, "Invalid chip type %d\n", info->man_id);
+		*fw_entry = NULL;
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+static void hci_h4p_close_firmware(const struct firmware *fw_entry)
+{
+	release_firmware(fw_entry);
+}
+
+/* Read fw. Return length of the command. If no more commands in
+ * fw 0 is returned. In error case return value is negative.
+ */
+static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
+			       const struct firmware *fw_entry, gfp_t how)
+{
+	unsigned int cmd_len;
+
+	if (fw_pos >= fw_entry->size)
+		return 0;
+
+	if (fw_pos + 2 > fw_entry->size) {
+		dev_err(info->dev, "Corrupted firmware image 1\n");
+		return -EMSGSIZE;
+	}
+
+	cmd_len = fw_entry->data[fw_pos++];
+	cmd_len += fw_entry->data[fw_pos++] << 8;
+	if (cmd_len == 0)
+		return 0;
+
+	if (fw_pos + cmd_len > fw_entry->size) {
+		dev_err(info->dev, "Corrupted firmware image 2\n");
+		return -EMSGSIZE;
+	}
+
+	*skb = bt_skb_alloc(cmd_len, how);
+	if (!*skb) {
+		dev_err(info->dev, "Cannot reserve memory for buffer\n");
+		return -ENOMEM;
+	}
+	memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
+
+	fw_pos += cmd_len;
+
+	return (*skb)->len;
+}
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+	const struct firmware *fw_entry = NULL;
+	struct sk_buff *skb = NULL;
+	int err;
+
+	err = hci_h4p_open_firmware(info, &fw_entry);
+	if (err < 0 || !fw_entry)
+		goto err_clean;
+
+	while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
+		if (err < 0 || !skb)
+			goto err_clean;
+
+		skb_queue_tail(fw_queue, skb);
+	}
+
+err_clean:
+	hci_h4p_close_firmware(fw_entry);
+	return err;
+}
+
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+	int err;
+
+	switch (info->man_id) {
+	case BT_CHIP_CSR:
+		err = hci_h4p_bc4_send_fw(info, fw_queue);
+		break;
+	case BT_CHIP_TI:
+		err = hci_h4p_ti1273_send_fw(info, fw_queue);
+		break;
+	case BT_CHIP_BCM:
+		err = hci_h4p_bcm_send_fw(info, fw_queue);
+		break;
+	default:
+		dev_err(info->dev, "Don't know how to send firmware\n");
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+	switch (info->man_id) {
+	case BT_CHIP_CSR:
+		hci_h4p_bc4_parse_fw_event(info, skb);
+		break;
+	case BT_CHIP_TI:
+		hci_h4p_ti1273_parse_fw_event(info, skb);
+		break;
+	case BT_CHIP_BCM:
+		hci_h4p_bcm_parse_fw_event(info, skb);
+		break;
+	default:
+		dev_err(info->dev, "Don't know how to parse fw event\n");
+		info->fw_error = -EINVAL;
+	}
+
+	return;
+}
diff --git a/drivers/bluetooth/hci_h4p/hci_h4p.h b/drivers/bluetooth/hci_h4p/hci_h4p.h
new file mode 100644
index 0000000..ebafd37
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/hci_h4p.h
@@ -0,0 +1,238 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2010 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * 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 <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
+#define __DRIVERS_BLUETOOTH_HCI_H4P_H
+
+#define BT_CHIP_CSR		0x02
+#define BT_CHIP_TI		0x30
+#define BT_CHIP_BCM		0x04
+
+#define FW_NAME_CSR		"bc4fw.bin"
+#define FW_NAME_TI		"ti1273.bin"
+#define FW_NAME_BCM		"bcmfw.bin"
+
+#define UART_SYSC_OMAP_RESET	0x03
+#define UART_SYSS_RESETDONE	0x01
+#define UART_OMAP_SCR_EMPTY_THR	0x08
+#define UART_OMAP_SCR_WAKEUP	0x10
+#define UART_OMAP_SSR_WAKEUP	0x02
+#define UART_OMAP_SSR_TXFULL	0x01
+
+#define UART_OMAP_SYSC_IDLEMODE		0x03
+#define UART_OMAP_SYSC_IDLEMASK		(3 << UART_OMAP_SYSC_IDLEMODE)
+
+#define UART_OMAP_SYSC_FORCE_IDLE	(0 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_NO_IDLE		(1 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_SMART_IDLE	(2 << UART_OMAP_SYSC_IDLEMODE)
+
+#define NBT_DBG(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_FW(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_POWER(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_TRANSFER(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_TRANSFER_NF(fmt, arg...) \
+		pr_debug(fmt "" , ## arg)
+
+#define NBT_DBG_DMA(fmt, arg...) \
+		pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+struct hci_h4p_info {
+	struct hci_dev *hdev;
+	spinlock_t lock;
+
+	void __iomem *uart_base;
+	unsigned long uart_phys_base;
+	int irq;
+	struct device *dev;
+	u8 chip_type;
+	void (*bt_wakeup)(bool enable);
+	bool (*host_wakeup)(void);
+	void (*reset)(bool enable);
+	int host_wakeup_gpio;
+	int man_id;
+	int ver_id;
+
+	struct sk_buff_head fw_queue;
+	struct completion init_completion;
+	struct completion fw_completion;
+	int fw_error;
+	int init_error;
+
+	struct sk_buff_head txq;
+
+	struct sk_buff *rx_skb;
+	long rx_count;
+	unsigned long rx_state;
+	unsigned long garbage_bytes;
+
+	u8 bd_addr[6];
+	struct sk_buff_head *fw_q;
+
+	int pm_enabled;
+	int tx_enabled;
+	int autorts;
+	int rx_enabled;
+
+	int tx_clocks_en;
+	int rx_clocks_en;
+	spinlock_t clocks_lock;
+	struct clk *uart_iclk;
+	struct clk *uart_fclk;
+	atomic_t clk_users;
+	u16 dll;
+	u16 dlh;
+	u16 ier;
+	u16 mdr1;
+	u16 efr;
+};
+
+struct hci_h4p_radio_hdr {
+	__u8 evt;
+	__u8 dlen;
+} __attribute__ ((packed));
+
+
+struct hci_h4p_init_hdr {
+	__u8 dlen;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_HDR_SIZE 1
+
+struct hci_h4p_init_cmd {
+	__u8 ack;
+	__u16 baudrate;
+	__u16 unused;
+	__u8 mode;
+	__u16 sys_clk;
+	__u16 unused2;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_CMD_SIZE 10
+
+struct hci_h4p_init_evt {
+	__u8 ack;
+	__u16 baudrate;
+	__u16 unused;
+	__u8 mode;
+	__u16 sys_clk;
+	__u16 unused2;
+	__u8 man_id;
+	__u8 ver_id;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_EVT_SIZE 12
+
+struct hci_h4p_alive_hdr {
+	__u8 dlen;
+} __attribute__ ((packed));
+#define HCI_H4P_ALIVE_HDR_SIZE 1
+
+struct hci_h4p_alive_msg {
+	__u8 message_id;
+	__u8 unused;
+} __attribute__ ((packed));
+#define HCI_H4P_ALIVE_MSG_SIZE 2
+
+#define MAX_BAUD_RATE		921600
+#define BC4_MAX_BAUD_RATE	3692300
+#define UART_CLOCK		48000000
+#define BT_INIT_DIVIDER		320
+#define BT_BAUDRATE_DIVIDER	384000000
+#define BT_SYSCLK_DIV		1000
+#define INIT_SPEED		120000
+
+#define HCI_H4P_MODE		0x4c
+
+#define HCI_H4P_ACK		0x20
+#define HCI_H4P_NACK		0x40
+#define HCI_H4P_ALIVE_IND_REQ	0x55
+#define HCI_H4P_ALIVE_IND_RESP	0xCC
+
+#define H4_TYPE_SIZE		1
+#define H4_RADIO_HDR_SIZE	2
+
+/* H4+ packet types */
+#define H4_CMD_PKT		0x01
+#define H4_ACL_PKT		0x02
+#define H4_SCO_PKT		0x03
+#define H4_EVT_PKT		0x04
+#define H4_NEG_PKT		0x06
+#define H4_ALIVE_PKT		0x07
+#define H4_RADIO_PKT		0x08
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE	1
+#define WAIT_FOR_HEADER		2
+#define WAIT_FOR_DATA		3
+
+struct hci_fw_event {
+	struct hci_event_hdr hev;
+	struct hci_ev_cmd_complete cmd;
+	u8 status;
+} __attribute__ ((packed));
+
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info,
+				struct sk_buff *skb);
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue);
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
+				struct sk_buff *skb);
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+			struct sk_buff_head *fw_queue);
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+				    struct sk_buff *skb);
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+			    struct sk_buff_head *fw_queue);
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
+
+void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+int hci_h4p_reset_uart(struct hci_h4p_info *info);
+void hci_h4p_init_uart(struct hci_h4p_info *info);
+void hci_h4p_enable_tx(struct hci_h4p_info *info);
+void hci_h4p_store_regs(struct hci_h4p_info *info);
+void hci_h4p_restore_regs(struct hci_h4p_info *info);
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable);
+
+#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
diff --git a/drivers/bluetooth/hci_h4p/uart.c b/drivers/bluetooth/hci_h4p/uart.c
new file mode 100644
index 0000000..033825f
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/uart.c
@@ -0,0 +1,203 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * 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 <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <linux/io.h>
+
+#include "hci_h4p.h"
+
+inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
+{
+	__raw_writeb(val, info->uart_base + (offset << 2));
+}
+
+inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+{
+	return __raw_readb(info->uart_base + (offset << 2));
+}
+
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
+{
+	u8 b;
+
+	b = hci_h4p_inb(info, UART_MCR);
+	if (active)
+		b |= UART_MCR_RTS;
+	else
+		b &= ~UART_MCR_RTS;
+	hci_h4p_outb(info, UART_MCR, b);
+}
+
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
+			 int timeout_ms)
+{
+	unsigned long timeout;
+	int state;
+
+	timeout = jiffies + msecs_to_jiffies(timeout_ms);
+	for (;;) {
+		state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
+		if (active) {
+			if (state)
+				return 0;
+		} else {
+			if (!state)
+				return 0;
+		}
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+		msleep(1);
+	}
+}
+
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+	u8 lcr, b;
+
+	lcr = hci_h4p_inb(info, UART_LCR);
+	hci_h4p_outb(info, UART_LCR, 0xbf);
+	b = hci_h4p_inb(info, UART_EFR);
+	if (on)
+		b |= which;
+	else
+		b &= ~which;
+	hci_h4p_outb(info, UART_EFR, b);
+	hci_h4p_outb(info, UART_LCR, lcr);
+}
+
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock, flags);
+	__hci_h4p_set_auto_ctsrts(info, on, which);
+	spin_unlock_irqrestore(&info->lock, flags);
+}
+
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
+{
+	unsigned int divisor;
+	u8 lcr, mdr1;
+
+	NBT_DBG("Setting speed %lu\n", speed);
+
+	if (speed >= 460800) {
+		divisor = UART_CLOCK / 13 / speed;
+		mdr1 = 3;
+	} else {
+		divisor = UART_CLOCK / 16 / speed;
+		mdr1 = 0;
+	}
+
+	/* Make sure UART mode is disabled */
+	hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+
+	lcr = hci_h4p_inb(info, UART_LCR);
+	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
+	hci_h4p_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
+	hci_h4p_outb(info, UART_DLM, divisor >> 8);
+	hci_h4p_outb(info, UART_LCR, lcr);
+
+	/* Make sure UART mode is enabled */
+	hci_h4p_outb(info, UART_OMAP_MDR1, mdr1);
+}
+
+int hci_h4p_reset_uart(struct hci_h4p_info *info)
+{
+	int count = 0;
+
+	/* Reset the  UART */
+	hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+	while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+		if (count++ > 100) {
+			dev_err(info->dev, "hci_h4p: UART reset timeout\n");
+			return -ENODEV;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+
+void hci_h4p_store_regs(struct hci_h4p_info *info)
+{
+	u16 lcr = 0;
+
+	lcr = hci_h4p_inb(info, UART_LCR);
+	hci_h4p_outb(info, UART_LCR, 0xBF);
+	info->dll = hci_h4p_inb(info, UART_DLL);
+	info->dlh = hci_h4p_inb(info, UART_DLM);
+	info->efr = hci_h4p_inb(info, UART_EFR);
+	hci_h4p_outb(info, UART_LCR, lcr);
+	info->mdr1 = hci_h4p_inb(info, UART_OMAP_MDR1);
+	info->ier = hci_h4p_inb(info, UART_IER);
+}
+
+void hci_h4p_restore_regs(struct hci_h4p_info *info)
+{
+	u16 lcr = 0;
+
+	hci_h4p_init_uart(info);
+
+	hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+	lcr = hci_h4p_inb(info, UART_LCR);
+	hci_h4p_outb(info, UART_LCR, 0xBF);
+	hci_h4p_outb(info, UART_DLL, info->dll);    /* Set speed */
+	hci_h4p_outb(info, UART_DLM, info->dlh);
+	hci_h4p_outb(info, UART_EFR, info->efr);
+	hci_h4p_outb(info, UART_LCR, lcr);
+	hci_h4p_outb(info, UART_OMAP_MDR1, info->mdr1);
+	hci_h4p_outb(info, UART_IER, info->ier);
+}
+
+void hci_h4p_init_uart(struct hci_h4p_info *info)
+{
+	u8 mcr, efr;
+
+	/* Enable and setup FIFO */
+	hci_h4p_outb(info, UART_OMAP_MDR1, 0x00);
+
+	hci_h4p_outb(info, UART_LCR, 0xbf);
+	efr = hci_h4p_inb(info, UART_EFR);
+	hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
+	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+	mcr = hci_h4p_inb(info, UART_MCR);
+	hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
+	hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+			UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+			(3 << 6) | (0 << 4));
+	hci_h4p_outb(info, UART_LCR, 0xbf);
+	hci_h4p_outb(info, UART_TI752_TLR, 0xed);
+	hci_h4p_outb(info, UART_TI752_TCR, 0xef);
+	hci_h4p_outb(info, UART_EFR, efr);
+	hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+	hci_h4p_outb(info, UART_MCR, 0x00);
+	hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
+	hci_h4p_outb(info, UART_IER, UART_IER_RDI | UART_IER_RLSI);
+	hci_h4p_outb(info, UART_OMAP_WER, 0xff);
+	hci_h4p_outb(info, UART_OMAP_SYSC, (0 << 0) | (1 << 2) | (1 << 3));
+}
diff --git a/include/linux/bluetooth/hci_h4p.h b/include/linux/bluetooth/hci_h4p.h
new file mode 100644
index 0000000..ba1d764
--- /dev/null
+++ b/include/linux/bluetooth/hci_h4p.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Contact: Roger Quadros <roger.quadros@nokia.com>
+ *
+ * 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
+ *
+ */
+
+
+/**
+ * struct hci_h4p_platform data - hci_h4p Platform data structure
+ * @uart_base:	UART base address
+ * @uart_irq:	UART Interrupt number
+ * @host_wu:	Function hook determine if Host should wakeup or not.
+ * @bt_wu:	Function hook to enable/disable Bluetooth transmission
+ * @reset:	Function hook to set/clear reset conditiona
+ * @host_wu_gpio:	Gpio used to wakeup host
+ */
+struct hci_h4p_platform_data {
+	void *uart_base;
+	unsigned int uart_irq;
+	bool (*host_wu)(void);
+	void (*bt_wu)(bool);
+	void (*reset)(bool);
+	unsigned int host_wu_gpio;
+};
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-20 19:16 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Belkin bluetooth device's usb device id added to generic usb bluetooth driver.

It's another instance of Broadcom's BCM20702A0.

Relevant section from /sys/kernel/debug/usb/devices:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..fa05faf 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -105,7 +105,8 @@ static struct usb_device_id btusb_table[] = {
 	{ USB_DEVICE(0x04ca, 0x2003) },
 	{ USB_DEVICE(0x0489, 0xe042) },
 	{ USB_DEVICE(0x413c, 0x8197) },
-
+	{ USB_DEVICE(0x050d, 0x065a) },
+
 	/* Foxconn - Hon Hai */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
 
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-20 19:24 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Belkin bluetooth device's usb device id added to generic usb bluetooth driver.

It's another instance of Broadcom's BCM20702A0.

Relevant section from /sys/kernel/debug/usb/devices:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..fa05faf 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -105,7 +105,8 @@ static struct usb_device_id btusb_table[] = {
 	{ USB_DEVICE(0x04ca, 0x2003) },
 	{ USB_DEVICE(0x0489, 0xe042) },
 	{ USB_DEVICE(0x413c, 0x8197) },
-
+	{ USB_DEVICE(0x050d, 0x065a) },
+
 	/* Foxconn - Hon Hai */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
 
-- 
1.8.1.4

^ permalink raw reply related

* Re: [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Marcel Holtmann @ 2013-09-20 19:24 UTC (permalink / raw)
  To: Ken O'Brien; +Cc: gustavo, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <1379704619-27691-1-git-send-email-kernel@kenobrien.org>

Hi Ken,

> Belkin bluetooth device's usb device id added to generic usb bluetooth driver.
> 
> It's another instance of Broadcom's BCM20702A0.
> 
> Relevant section from /sys/kernel/debug/usb/devices:
> 
> T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
> D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
> P:  Vendor=050d ProdID=065a Rev= 1.12
> S:  Manufacturer=Broadcom Corp
> S:  Product=BCM20702A0
> S:  SerialNumber=0002723E2D29
> C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
> E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms

we might consider a generic rule for this:

	/* comment of the device vendor and type goes here */
        { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },

Regards

Marcel


^ permalink raw reply

* [PATCH v5 1/2] Bluetooth: btmrvl: add setup handler
From: Bing Zhao @ 2013-09-20 22:21 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, linux-wireless,
	Mike Frysinger, Hyuckjoo Lee, Bing Zhao, Amitkumar Karwar

From: Amitkumar Karwar <akarwar@marvell.com>

Move initialization code to hdev's setup handler. New flag
setup_done is added to make sure that initialization is done only
during driver load time. Our firmware doesn't expect
re-initialization later when interface is re-enabled.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
---
v5: make use of hdev's setup handler (Marcel Holtmann)

 drivers/bluetooth/btmrvl_drv.h  |    1 +
 drivers/bluetooth/btmrvl_main.c |   23 +++++++++++++++++++++--
 drivers/bluetooth/btmrvl_sdio.c |    6 ------
 3 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 27068d1..e776b8b 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -68,6 +68,7 @@ struct btmrvl_adapter {
 	wait_queue_head_t cmd_wait_q;
 	u8 cmd_complete;
 	bool is_suspended;
+	bool setup_done;
 };
 
 struct btmrvl_private {
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index 9a9f518..e352f8e 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -479,6 +479,27 @@ static int btmrvl_open(struct hci_dev *hdev)
 	return 0;
 }
 
+static int btmrvl_setup(struct hci_dev *hdev)
+{
+	struct btmrvl_private *priv = hci_get_drvdata(hdev);
+	struct btmrvl_adapter *adapter = priv->adapter;
+
+	if (adapter->setup_done)
+		return 0;
+
+	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+
+	priv->btmrvl_dev.psmode = 1;
+	btmrvl_enable_ps(priv);
+
+	priv->btmrvl_dev.gpio_gap = 0xffff;
+	btmrvl_send_hscfg_cmd(priv);
+
+	adapter->setup_done = true;
+
+	return 0;
+}
+
 /*
  * This function handles the event generated by firmware, rx data
  * received from firmware, and tx data sent from kernel.
@@ -572,8 +592,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
 	hdev->flush = btmrvl_flush;
 	hdev->send = btmrvl_send_frame;
 	hdev->ioctl = btmrvl_ioctl;
-
-	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+	hdev->setup = btmrvl_setup;
 
 	hdev->dev_type = priv->btmrvl_dev.dev_type;
 
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 75c2626..c526915 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -1046,12 +1046,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 		goto disable_host_int;
 	}
 
-	priv->btmrvl_dev.psmode = 1;
-	btmrvl_enable_ps(priv);
-
-	priv->btmrvl_dev.gpio_gap = 0xffff;
-	btmrvl_send_hscfg_cmd(priv);
-
 	return 0;
 
 disable_host_int:
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v5 2/2] Bluetooth: btmrvl: add calibration data download support
From: Bing Zhao @ 2013-09-20 22:21 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, linux-wireless,
	Mike Frysinger, Hyuckjoo Lee, Bing Zhao, Amitkumar Karwar
In-Reply-To: <1379715667-22424-1-git-send-email-bzhao@marvell.com>

From: Amitkumar Karwar <akarwar@marvell.com>

A text file containing calibration data in hex format can
be provided at following path:

/lib/firmware/mrvl/sd8797_caldata.conf

The data will be downloaded to firmware during initialization.

Reviewed-by: Mike Frysinger <vapier@chromium.org>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Hyuckjoo Lee <hyuckjoo.lee@samsung.com>
---
v2: Remove module parameter. The calibration data will be downloaded
    only when the device speicific data file is provided.
    (Marcel Holtmann)
v3: Fix crash (misaligned memory access) on ARM
v4: Simplify white space parsing and save some CPU cycles (Mike Frysinger)
v5: Improvements in cal data parsing logic. Add explanatory comments.
    Replace GFP_ATOMIC flag with GFP_KERNEL (Mike Frysinger)

 drivers/bluetooth/btmrvl_drv.h  |   10 +++-
 drivers/bluetooth/btmrvl_main.c |  144 ++++++++++++++++++++++++++++++++++++++-
 drivers/bluetooth/btmrvl_sdio.c |    9 ++-
 drivers/bluetooth/btmrvl_sdio.h |    2 +
 4 files changed, 161 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index e776b8b..dcd3468 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -23,6 +23,8 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <net/bluetooth/bluetooth.h>
+#include <linux/ctype.h>
+#include <linux/firmware.h>
 
 #define BTM_HEADER_LEN			4
 #define BTM_UPLD_SIZE			2312
@@ -41,6 +43,8 @@ struct btmrvl_thread {
 struct btmrvl_device {
 	void *card;
 	struct hci_dev *hcidev;
+	struct device *dev;
+	const char *cal_data;
 
 	u8 dev_type;
 
@@ -92,6 +96,7 @@ struct btmrvl_private {
 #define BT_CMD_HOST_SLEEP_CONFIG	0x59
 #define BT_CMD_HOST_SLEEP_ENABLE	0x5A
 #define BT_CMD_MODULE_CFG_REQ		0x5B
+#define BT_CMD_LOAD_CONFIG_DATA		0x61
 
 /* Sub-commands: Module Bringup/Shutdown Request/Response */
 #define MODULE_BRINGUP_REQ		0xF1
@@ -117,10 +122,13 @@ struct btmrvl_private {
 #define PS_SLEEP			0x01
 #define PS_AWAKE			0x00
 
+#define BT_CMD_DATA_SIZE		32
+#define BT_CAL_DATA_SIZE		28
+
 struct btmrvl_cmd {
 	__le16 ocf_ogf;
 	u8 length;
-	u8 data[4];
+	u8 data[BT_CMD_DATA_SIZE];
 } __packed;
 
 struct btmrvl_event {
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index e352f8e..6eea188 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -57,8 +57,9 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
 		ocf = hci_opcode_ocf(opcode);
 		ogf = hci_opcode_ogf(opcode);
 
-		if (ocf == BT_CMD_MODULE_CFG_REQ &&
-					priv->btmrvl_dev.sendcmdflag) {
+		if ((ocf == BT_CMD_MODULE_CFG_REQ ||
+		     ocf == BT_CMD_LOAD_CONFIG_DATA) &&
+		    priv->btmrvl_dev.sendcmdflag) {
 			priv->btmrvl_dev.sendcmdflag = false;
 			priv->adapter->cmd_complete = true;
 			wake_up_interruptible(&priv->adapter->cmd_wait_q);
@@ -479,6 +480,142 @@ static int btmrvl_open(struct hci_dev *hdev)
 	return 0;
 }
 
+/*
+ * This function parses provided calibration data input. It should contain
+ * hex bytes separated by space or new line character. Here is an example.
+ * 00 1C 01 37 FF FF FF FF 02 04 7F 01
+ * CE BA 00 00 00 2D C6 C0 00 00 00 00
+ * 00 F0 00 00
+ */
+static int btmrvl_parse_cal_cfg(const u8 *src, u32 len, u8 *dst, u32 dst_size)
+{
+	const u8 *s = src;
+	u8 *d = dst;
+	int ret;
+	u8 tmp[3];
+
+	tmp[2] = '\0';
+	while ((s - src) <= len - 2) {
+		if (isspace(*s) || *s == '\n') {
+			s++;
+			continue;
+		}
+
+		if (isxdigit(*s)) {
+			if ((d - dst) >= dst_size) {
+				BT_ERR("calibration data file too big!!!");
+				return -EINVAL;
+			}
+
+			memcpy(tmp, s, 2);
+
+			ret = kstrtou8(tmp, 16, d++);
+			if (ret < 0)
+				return ret;
+
+			s += 2;
+		} else {
+			return -EINVAL;
+		}
+	}
+	if (d == dst)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int btmrvl_load_cal_data(struct btmrvl_private *priv,
+				u8 *config_data)
+{
+	struct sk_buff *skb;
+	struct btmrvl_cmd *cmd;
+	int i;
+
+	skb = bt_skb_alloc(sizeof(*cmd), GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct btmrvl_cmd *)skb->data;
+	cmd->ocf_ogf =
+		cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_LOAD_CONFIG_DATA));
+	cmd->length = BT_CMD_DATA_SIZE;
+	cmd->data[0] = 0x00;
+	cmd->data[1] = 0x00;
+	cmd->data[2] = 0x00;
+	cmd->data[3] = BT_CMD_DATA_SIZE - 4;
+
+	/* Swap cal-data bytes. Each four bytes are swapped. Considering 4
+	 * byte SDIO header offset, mapping of input and output bytes will be
+	 * {3, 2, 1, 0} -> {0+4, 1+4, 2+4, 3+4},
+	 * {7, 6, 5, 4} -> {4+4, 5+4, 6+4, 7+4} */
+	for (i = 4; i < BT_CMD_DATA_SIZE; i++)
+		cmd->data[i] = config_data[(i / 4) * 8 - 1 - i];
+
+	bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+	skb_put(skb, sizeof(*cmd));
+	skb->dev = (void *)priv->btmrvl_dev.hcidev;
+	skb_queue_head(&priv->adapter->tx_queue, skb);
+	priv->btmrvl_dev.sendcmdflag = true;
+	priv->adapter->cmd_complete = false;
+
+	print_hex_dump_bytes("Calibration data: ",
+			     DUMP_PREFIX_OFFSET, cmd->data, BT_CMD_DATA_SIZE);
+
+	wake_up_interruptible(&priv->main_thread.wait_q);
+	if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
+					      priv->adapter->cmd_complete,
+				       msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) {
+		BT_ERR("Timeout while loading calibration data");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int
+btmrvl_process_cal_cfg(struct btmrvl_private *priv, u8 *data, u32 size)
+{
+	u8 cal_data[BT_CAL_DATA_SIZE];
+	int ret;
+
+	ret = btmrvl_parse_cal_cfg(data, size, cal_data, sizeof(cal_data));
+	if (ret)
+		return ret;
+
+	ret = btmrvl_load_cal_data(priv, cal_data);
+	if (ret) {
+		BT_ERR("Fail to load calibrate data");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int btmrvl_cal_data_config(struct btmrvl_private *priv)
+{
+	const struct firmware *cfg;
+	int ret;
+	const char *cal_data = priv->btmrvl_dev.cal_data;
+
+	if (!cal_data)
+		return 0;
+
+	ret = request_firmware(&cfg, cal_data, priv->btmrvl_dev.dev);
+	if (ret < 0) {
+		BT_DBG("Failed to get %s file, skipping cal data download",
+		       cal_data);
+		ret = 0;
+		goto done;
+	}
+
+	ret = btmrvl_process_cal_cfg(priv, (u8 *)cfg->data, cfg->size);
+done:
+	if (cfg)
+		release_firmware(cfg);
+
+	return ret;
+}
+
 static int btmrvl_setup(struct hci_dev *hdev)
 {
 	struct btmrvl_private *priv = hci_get_drvdata(hdev);
@@ -489,6 +626,9 @@ static int btmrvl_setup(struct hci_dev *hdev)
 
 	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
 
+	if (btmrvl_cal_data_config(priv))
+		BT_ERR("Set cal data failed");
+
 	priv->btmrvl_dev.psmode = 1;
 	btmrvl_enable_ps(priv);
 
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index c526915..51e95ed 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -18,7 +18,6 @@
  * this warranty disclaimer.
  **/
 
-#include <linux/firmware.h>
 #include <linux/slab.h>
 
 #include <linux/mmc/sdio_ids.h>
@@ -102,6 +101,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
 	.helper		= "mrvl/sd8688_helper.bin",
 	.firmware	= "mrvl/sd8688.bin",
+	.cal_data	= NULL,
 	.reg		= &btmrvl_reg_8688,
 	.sd_blksz_fw_dl	= 64,
 };
@@ -109,6 +109,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
 	.helper		= NULL,
 	.firmware	= "mrvl/sd8787_uapsta.bin",
+	.cal_data	= NULL,
 	.reg		= &btmrvl_reg_87xx,
 	.sd_blksz_fw_dl	= 256,
 };
@@ -116,6 +117,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
 	.helper		= NULL,
 	.firmware	= "mrvl/sd8797_uapsta.bin",
+	.cal_data	= "mrvl/sd8797_caldata.conf",
 	.reg		= &btmrvl_reg_87xx,
 	.sd_blksz_fw_dl	= 256,
 };
@@ -123,6 +125,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
 	.helper		= NULL,
 	.firmware	= "mrvl/sd8897_uapsta.bin",
+	.cal_data	= NULL,
 	.reg		= &btmrvl_reg_88xx,
 	.sd_blksz_fw_dl	= 256,
 };
@@ -1006,6 +1009,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 		struct btmrvl_sdio_device *data = (void *) id->driver_data;
 		card->helper = data->helper;
 		card->firmware = data->firmware;
+		card->cal_data = data->cal_data;
 		card->reg = data->reg;
 		card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
 	}
@@ -1034,6 +1038,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 	}
 
 	card->priv = priv;
+	priv->btmrvl_dev.dev = &card->func->dev;
+	priv->btmrvl_dev.cal_data = card->cal_data;
 
 	/* Initialize the interface specific function pointers */
 	priv->hw_host_to_card = btmrvl_sdio_host_to_card;
@@ -1216,4 +1222,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
 MODULE_FIRMWARE("mrvl/sd8688.bin");
 MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
+MODULE_FIRMWARE("mrvl/sd8797_caldata.conf");
 MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
index 43d35a6..6872d9e 100644
--- a/drivers/bluetooth/btmrvl_sdio.h
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -85,6 +85,7 @@ struct btmrvl_sdio_card {
 	u32 ioport;
 	const char *helper;
 	const char *firmware;
+	const char *cal_data;
 	const struct btmrvl_sdio_card_reg *reg;
 	u16 sd_blksz_fw_dl;
 	u8 rx_unit;
@@ -94,6 +95,7 @@ struct btmrvl_sdio_card {
 struct btmrvl_sdio_device {
 	const char *helper;
 	const char *firmware;
+	const char *cal_data;
 	const struct btmrvl_sdio_card_reg *reg;
 	u16 sd_blksz_fw_dl;
 };
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Ken O'Brien @ 2013-09-20 23:10 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg
  Cc: linux-bluetooth, linux-kernel, Ken O'Brien

Adding generic rule for broadcom devices to generic usb bluetooth driver on encountering another instance of Broadcom's BCM20702A0.

Relevant section from /sys/kernel/debug/usb/devices:

T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=050d ProdID=065a Rev= 1.12
S:  Manufacturer=Broadcom Corp
S:  Product=BCM20702A0
S:  SerialNumber=0002723E2D29
C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
---
 drivers/bluetooth/btusb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8e16f0a..6d33dca 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -111,6 +111,7 @@ static struct usb_device_id btusb_table[] = {
 
 	/*Broadcom devices with vendor specific id */
 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+	{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
 
 	{ }	/* Terminating entry */
 };
-- 
1.8.1.4

^ permalink raw reply related

* Re: [PATCH] drivers: bluetooth: btusb: Added support for Belkin F8065bf usb bluetooth device
From: Marcel Holtmann @ 2013-09-21 16:19 UTC (permalink / raw)
  To: Ken O'Brien; +Cc: gustavo, johan.hedberg, linux-bluetooth, linux-kernel
In-Reply-To: <1379718623-1845-1-git-send-email-kernel@kenobrien.org>

Hi Ken,

> Adding generic rule for broadcom devices to generic usb bluetooth driver on encountering another instance of Broadcom's BCM20702A0.
> 
> Relevant section from /sys/kernel/debug/usb/devices:
> 
> T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
> D:  Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
> P:  Vendor=050d ProdID=065a Rev= 1.12
> S:  Manufacturer=Broadcom Corp
> S:  Product=BCM20702A0
> S:  SerialNumber=0002723E2D29
> C:* #Ifs= 4 Cfg#= 1 Atr=a0 MxPwr=100mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
> E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> I:  If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> I:  If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> I:  If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> I:  If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> I:  If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
> E:  Ad=84(I) Atr=02(Bulk) MxPS=  32 Ivl=0ms
> E:  Ad=04(O) Atr=02(Bulk) MxPS=  32 Ivl=0ms
> I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
> 
> Signed-off-by: Ken O'Brien <kernel@kenobrien.org>
> ---
> drivers/bluetooth/btusb.c | 1 +
> 1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 8e16f0a..6d33dca 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -111,6 +111,7 @@ static struct usb_device_id btusb_table[] = {
> 
> 	/*Broadcom devices with vendor specific id */
> 	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
> +	{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },

this is not correct. These devices are Broadcom based, but they are actually from Belkin. Same as the controllers from Apple. So it needs its own line and a comment that mentions Belkin.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH v5 1/2] Bluetooth: btmrvl: add setup handler
From: Marcel Holtmann @ 2013-09-21 17:00 UTC (permalink / raw)
  To: Bing Zhao
  Cc: linux-bluetooth, Gustavo Padovan, Johan Hedberg, linux-wireless,
	Mike Frysinger, Hyuckjoo Lee, Amitkumar Karwar
In-Reply-To: <1379715667-22424-1-git-send-email-bzhao@marvell.com>

Hi Bing,

> Move initialization code to hdev's setup handler. New flag
> setup_done is added to make sure that initialization is done only
> during driver load time. Our firmware doesn't expect
> re-initialization later when interface is re-enabled.
> 
> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> Signed-off-by: Bing Zhao <bzhao@marvell.com>
> ---
> v5: make use of hdev's setup handler (Marcel Holtmann)
> 
> drivers/bluetooth/btmrvl_drv.h  |    1 +
> drivers/bluetooth/btmrvl_main.c |   23 +++++++++++++++++++++--
> drivers/bluetooth/btmrvl_sdio.c |    6 ------
> 3 files changed, 22 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
> index 27068d1..e776b8b 100644
> --- a/drivers/bluetooth/btmrvl_drv.h
> +++ b/drivers/bluetooth/btmrvl_drv.h
> @@ -68,6 +68,7 @@ struct btmrvl_adapter {
> 	wait_queue_head_t cmd_wait_q;
> 	u8 cmd_complete;
> 	bool is_suspended;
> +	bool setup_done;
> };
> 
> struct btmrvl_private {
> diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
> index 9a9f518..e352f8e 100644
> --- a/drivers/bluetooth/btmrvl_main.c
> +++ b/drivers/bluetooth/btmrvl_main.c
> @@ -479,6 +479,27 @@ static int btmrvl_open(struct hci_dev *hdev)
> 	return 0;
> }
> 
> +static int btmrvl_setup(struct hci_dev *hdev)
> +{
> +	struct btmrvl_private *priv = hci_get_drvdata(hdev);
> +	struct btmrvl_adapter *adapter = priv->adapter;
> +
> +	if (adapter->setup_done)
> +		return 0;
> +
> +	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
> +
> +	priv->btmrvl_dev.psmode = 1;
> +	btmrvl_enable_ps(priv);
> +
> +	priv->btmrvl_dev.gpio_gap = 0xffff;
> +	btmrvl_send_hscfg_cmd(priv);
> +
> +	adapter->setup_done = true;
> +
> +	return 0;
> +}
> +
> /*
>  * This function handles the event generated by firmware, rx data
>  * received from firmware, and tx data sent from kernel.
> @@ -572,8 +592,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
> 	hdev->flush = btmrvl_flush;
> 	hdev->send = btmrvl_send_frame;
> 	hdev->ioctl = btmrvl_ioctl;
> -
> -	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
> +	hdev->setup = btmrvl_setup;

just to make sure you guys understand how ->setup() works. It is only called once. Bringing the adapter down and up again does not call ->setup() a second time. So do you guys need this setup_done variable and if so, then you need to be a bit more verbose and help me understand why.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH v5 2/2] Bluetooth: btmrvl: add calibration data download support
From: Marcel Holtmann @ 2013-09-21 17:03 UTC (permalink / raw)
  To: Bing Zhao
  Cc: linux-bluetooth, Gustavo Padovan, Johan Hedberg, linux-wireless,
	Mike Frysinger, Hyuckjoo Lee, Amitkumar Karwar
In-Reply-To: <1379715667-22424-2-git-send-email-bzhao@marvell.com>

Hi Bing,

> A text file containing calibration data in hex format can
> be provided at following path:
> 
> /lib/firmware/mrvl/sd8797_caldata.conf
> 
> The data will be downloaded to firmware during initialization.
> 
> Reviewed-by: Mike Frysinger <vapier@chromium.org>
> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> Signed-off-by: Bing Zhao <bzhao@marvell.com>
> Signed-off-by: Hyuckjoo Lee <hyuckjoo.lee@samsung.com>
> ---
> v2: Remove module parameter. The calibration data will be downloaded
>    only when the device speicific data file is provided.
>    (Marcel Holtmann)
> v3: Fix crash (misaligned memory access) on ARM
> v4: Simplify white space parsing and save some CPU cycles (Mike Frysinger)
> v5: Improvements in cal data parsing logic. Add explanatory comments.
>    Replace GFP_ATOMIC flag with GFP_KERNEL (Mike Frysinger)
> 
> drivers/bluetooth/btmrvl_drv.h  |   10 +++-
> drivers/bluetooth/btmrvl_main.c |  144 ++++++++++++++++++++++++++++++++++++++-
> drivers/bluetooth/btmrvl_sdio.c |    9 ++-
> drivers/bluetooth/btmrvl_sdio.h |    2 +
> 4 files changed, 161 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
> index e776b8b..dcd3468 100644
> --- a/drivers/bluetooth/btmrvl_drv.h
> +++ b/drivers/bluetooth/btmrvl_drv.h
> @@ -23,6 +23,8 @@
> #include <linux/bitops.h>
> #include <linux/slab.h>
> #include <net/bluetooth/bluetooth.h>
> +#include <linux/ctype.h>
> +#include <linux/firmware.h>
> 
> #define BTM_HEADER_LEN			4
> #define BTM_UPLD_SIZE			2312
> @@ -41,6 +43,8 @@ struct btmrvl_thread {
> struct btmrvl_device {
> 	void *card;
> 	struct hci_dev *hcidev;
> +	struct device *dev;
> +	const char *cal_data;
> 
> 	u8 dev_type;
> 
> @@ -92,6 +96,7 @@ struct btmrvl_private {
> #define BT_CMD_HOST_SLEEP_CONFIG	0x59
> #define BT_CMD_HOST_SLEEP_ENABLE	0x5A
> #define BT_CMD_MODULE_CFG_REQ		0x5B
> +#define BT_CMD_LOAD_CONFIG_DATA		0x61
> 
> /* Sub-commands: Module Bringup/Shutdown Request/Response */
> #define MODULE_BRINGUP_REQ		0xF1
> @@ -117,10 +122,13 @@ struct btmrvl_private {
> #define PS_SLEEP			0x01
> #define PS_AWAKE			0x00
> 
> +#define BT_CMD_DATA_SIZE		32
> +#define BT_CAL_DATA_SIZE		28
> +
> struct btmrvl_cmd {
> 	__le16 ocf_ogf;
> 	u8 length;
> -	u8 data[4];
> +	u8 data[BT_CMD_DATA_SIZE];
> } __packed;
> 
> struct btmrvl_event {
> diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
> index e352f8e..6eea188 100644
> --- a/drivers/bluetooth/btmrvl_main.c
> +++ b/drivers/bluetooth/btmrvl_main.c
> @@ -57,8 +57,9 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
> 		ocf = hci_opcode_ocf(opcode);
> 		ogf = hci_opcode_ogf(opcode);
> 
> -		if (ocf == BT_CMD_MODULE_CFG_REQ &&
> -					priv->btmrvl_dev.sendcmdflag) {
> +		if ((ocf == BT_CMD_MODULE_CFG_REQ ||
> +		     ocf == BT_CMD_LOAD_CONFIG_DATA) &&
> +		    priv->btmrvl_dev.sendcmdflag) {
> 			priv->btmrvl_dev.sendcmdflag = false;
> 			priv->adapter->cmd_complete = true;
> 			wake_up_interruptible(&priv->adapter->cmd_wait_q);
> @@ -479,6 +480,142 @@ static int btmrvl_open(struct hci_dev *hdev)
> 	return 0;
> }
> 
> +/*
> + * This function parses provided calibration data input. It should contain
> + * hex bytes separated by space or new line character. Here is an example.
> + * 00 1C 01 37 FF FF FF FF 02 04 7F 01
> + * CE BA 00 00 00 2D C6 C0 00 00 00 00
> + * 00 F0 00 00
> + */
> +static int btmrvl_parse_cal_cfg(const u8 *src, u32 len, u8 *dst, u32 dst_size)
> +{
> +	const u8 *s = src;
> +	u8 *d = dst;
> +	int ret;
> +	u8 tmp[3];
> +
> +	tmp[2] = '\0';
> +	while ((s - src) <= len - 2) {
> +		if (isspace(*s) || *s == '\n') {
> +			s++;
> +			continue;
> +		}
> +
> +		if (isxdigit(*s)) {
> +			if ((d - dst) >= dst_size) {
> +				BT_ERR("calibration data file too big!!!");
> +				return -EINVAL;
> +			}
> +
> +			memcpy(tmp, s, 2);
> +
> +			ret = kstrtou8(tmp, 16, d++);
> +			if (ret < 0)
> +				return ret;
> +
> +			s += 2;
> +		} else {
> +			return -EINVAL;
> +		}
> +	}
> +	if (d == dst)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int btmrvl_load_cal_data(struct btmrvl_private *priv,
> +				u8 *config_data)
> +{
> +	struct sk_buff *skb;
> +	struct btmrvl_cmd *cmd;
> +	int i;
> +
> +	skb = bt_skb_alloc(sizeof(*cmd), GFP_KERNEL);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct btmrvl_cmd *)skb->data;
> +	cmd->ocf_ogf =
> +		cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_LOAD_CONFIG_DATA));
> +	cmd->length = BT_CMD_DATA_SIZE;
> +	cmd->data[0] = 0x00;
> +	cmd->data[1] = 0x00;
> +	cmd->data[2] = 0x00;
> +	cmd->data[3] = BT_CMD_DATA_SIZE - 4;

why not use __hci_cmd_sync() here. It is designed to be used from ->setup() where it is guaranteed that the HCI request lock is held. And it is guaranteed that ->setup() is executed in a workqueue.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 1/2] android: Add skeleton of BlueZ Android daemon
From: Marcel Holtmann @ 2013-09-21 17:14 UTC (permalink / raw)
  To: Frederic Danis; +Cc: linux-bluetooth
In-Reply-To: <1379679871-29623-1-git-send-email-frederic.danis@linux.intel.com>

Hi Fred,

> Define local mapping to glib path, otherwise this has to be inside central
> place in the build repository.
> 
> Retrieve Bluetooth version from configure.ac.
> ---
> .gitignore         |    2 +
> Android.mk         |    9 ++++
> Makefile.am        |    1 +
> Makefile.android   |    7 ++++
> android/Android.mk |   24 +++++++++++
> android/main.c     |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> configure.ac       |    5 +++
> 7 files changed, 167 insertions(+)
> create mode 100644 Android.mk
> create mode 100644 Makefile.android
> create mode 100644 android/Android.mk
> create mode 100644 android/main.c

lets split this out a little bit. Code additions should not be intermixed with additions to the build system and especially configure options.

I rather not have a top-level Android.mk. It should be enough to provide an android/Android.mk.

> diff --git a/.gitignore b/.gitignore
> index 8a25a3e..331a18b 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -98,3 +98,5 @@ unit/test-gobex-packet
> unit/test-gobex-transfer
> unit/test-*.log
> unit/test-*.trs
> +
> +android/bluezd

If we keep using prefix btd_ for certain set of functions, then it might be better if the daemon is build as android/bluetoothd or android/btd.

<snip>

> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <signal.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <glib.h>
> +
> +#include "hcid.h"

I do not think we need to include hcid.h here. If we for some reason still do, then please try to cleanup that first.

> +
> +#define SHUTDOWN_GRACE_SECONDS 10
> +
> +static GMainLoop *event_loop;
> +
> +void btd_exit(void)
> +{
> +	g_main_loop_quit(event_loop);
> +}
> +
> +static gboolean quit_eventloop(gpointer user_data)
> +{
> +	btd_exit();
> +	return FALSE;
> +}
> +
> +static void signal_handler(int sig)
> +{
> +	static unsigned int __terminated = 0;

Make this static volatile bool __terminated = false instead. Remember that you are actually using signals here and not signalfd.

> +
> +	switch (sig) {
> +	case SIGINT:
> +	case SIGTERM:
> +		if (__terminated == 0) {
> +			g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
> +							quit_eventloop, NULL);
> +		}
> +
> +		__terminated = 1;
> +		break;
> +	}
> +}
> +
> +static gboolean option_detach = TRUE;
> +static gboolean option_version = FALSE;
> +
> +static GOptionEntry options[] = {
> +	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
> +				G_OPTION_ARG_NONE, &option_detach,
> +				"Run with logging in foreground", NULL },

Do we need this option at all. I think we should always run in foreground and the system manager need to make sure we are spawned.

> +	{ "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
> +				"Show version information and exit", NULL },
> +	{ NULL }
> +};
> +
> +int main(int argc, char *argv[])
> +{
> +	GOptionContext *context;
> +	GError *err = NULL;
> +	struct sigaction sa;
> +
> +	context = g_option_context_new(NULL);
> +	g_option_context_add_main_entries(context, options, NULL);
> +
> +	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
> +		if (err != NULL) {
> +			g_printerr("%s\n", err->message);
> +			g_error_free(err);
> +		} else
> +			g_printerr("An unknown error occurred\n");
> +		exit(1);
> +	}
> +
> +	g_option_context_free(context);
> +
> +	if (option_version == TRUE) {
> +		printf("%s\n", VERSION);
> +		exit(0);

I prefer if we start using return EXIT_SUCCESS and in error case EXIT_FAILURE.

> +	}
> +
> +	event_loop = g_main_loop_new(NULL, FALSE);
> +
> +	memset(&sa, 0, sizeof(sa));
> +	sa.sa_handler = signal_handler;
> +	sigaction(SIGINT, &sa, NULL);
> +	sigaction(SIGTERM, &sa, NULL);
> +
> +	g_main_loop_run(event_loop);
> +
> +	g_main_loop_unref(event_loop);
> +
> +	return 0;
> +}
> diff --git a/configure.ac b/configure.ac
> index 41c2935..3b7a5d9 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -242,4 +242,9 @@ AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}",
> 			[Directory for the configuration files])
> AC_SUBST(CONFIGDIR, "${configdir}")
> 
> +AC_ARG_ENABLE(android-daemon, AC_HELP_STRING([--enable-android-daemon],
> +			[enable BlueZ Android daemon]),
> +					[android_daemon=${enableval}])
> +AM_CONDITIONAL(ANDROID_DAEMON, test "${android_daemon}" = "yes")
> +

This needs to be a separate patch. And it should just say --enable-android.

In addition it needs to be added to bootstrap-configure and distcheck handling.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 2/2] android: Android version of log.c
From: Marcel Holtmann @ 2013-09-21 17:20 UTC (permalink / raw)
  To: Frederic Danis; +Cc: linux-bluetooth
In-Reply-To: <1379679871-29623-2-git-send-email-frederic.danis@linux.intel.com>

Hi Fred,

> Add logging system to BlueZ Android daemon.
> Android build will use android/log.c file while autotools build will use
> src/log.c instead.
> ---
> Makefile.android   |    2 +-
> android/Android.mk |    1 +
> android/log.c      |  184 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> android/main.c     |   39 +++++++++++
> 4 files changed, 225 insertions(+), 1 deletion(-)
> create mode 100644 android/log.c
> 
> diff --git a/Makefile.android b/Makefile.android
> index 7b901ff..8f65dbf 100644
> --- a/Makefile.android
> +++ b/Makefile.android
> @@ -2,6 +2,6 @@
> if ANDROID_DAEMON
> noinst_PROGRAMS += android/bluezd
> 
> -android_bluezd_SOURCES = android/main.c
> +android_bluezd_SOURCES = android/main.c src/log.c
> android_bluezd_LDADD = @GLIB_LIBS@
> endif
> diff --git a/android/Android.mk b/android/Android.mk
> index 50f3c36..25099b3 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -8,6 +8,7 @@ include $(CLEAR_VARS)
> 
> LOCAL_SRC_FILES := \
> 	main.c \
> +	log.c \
> 
> LOCAL_C_INCLUDES := \
> 	$(call include-path-for, glib) \
> diff --git a/android/log.c b/android/log.c
> new file mode 100644
> index 0000000..1f98196
> --- /dev/null
> +++ b/android/log.c
> @@ -0,0 +1,184 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  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 as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  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 <fcntl.h>
> +#include <stdio.h>
> +#include <stdarg.h>
> +#include <unistd.h>
> +#include <sys/uio.h>
> +
> +#include <glib.h>
> +
> +#include "log.h"
> +
> +#define LOG_DEBUG	3
> +#define LOG_INFO	4
> +#define LOG_WARN	5
> +#define LOG_ERR		6
> +
> +const char tag[] = "BlueZ";
> +int system_fd;
> +int detached;

Local variables should be static.

> +
> +static void android_log(int pri, const char *fmt, va_list ap)
> +{
> +	char *msg;
> +	struct iovec vec[3];
> +
> +	msg = g_strdup_vprintf(fmt, ap);
> +
> +	if (!detached) {
> +		vec[0].iov_base = (void *) msg;
> +		vec[0].iov_len = strlen(msg) + 1;
> +		vec[1].iov_base = "\n";
> +		vec[1].iov_len = 1;
> +		writev(STDERR_FILENO, vec, 2);
> +	}

Lets not worry about logging to stderr at all.

> +
> +	if (system_fd == -1)
> +		goto done;
> +
> +	vec[0].iov_base = (unsigned char *) &pri;
> +	vec[0].iov_len = 1;
> +	vec[1].iov_base = (void *) tag;
> +	vec[1].iov_len = strlen(tag) + 1;
> +	vec[2].iov_base = (void *) msg;
> +	vec[2].iov_len = strlen(msg) + 1;
> +
> +	writev(system_fd, vec, 3);
> +
> +done:
> +	g_free(msg);
> +}
> +
> +void info(const char *format, ...)
> +{
> +	va_list ap;
> +
> +	va_start(ap, format);
> +
> +	android_log(LOG_INFO, format, ap);
> +
> +	va_end(ap);
> +}
> +
> +void warn(const char *format, ...)
> +{
> +	va_list ap;
> +
> +	va_start(ap, format);
> +
> +	android_log(LOG_WARN, format, ap);
> +
> +	va_end(ap);
> +}
> +
> +void error(const char *format, ...)
> +{
> +	va_list ap;
> +
> +	va_start(ap, format);
> +
> +	android_log(LOG_ERR, format, ap);
> +
> +	va_end(ap);
> +}
> +
> +void btd_debug(const char *format, ...)
> +{
> +	va_list ap;
> +
> +	va_start(ap, format);
> +
> +	android_log(LOG_DEBUG, format, ap);
> +
> +	va_end(ap);
> +}
> +
> +extern struct btd_debug_desc __start___debug[];
> +extern struct btd_debug_desc __stop___debug[];
> +
> +static char **enabled = NULL;
> +
> +static gboolean is_enabled(struct btd_debug_desc *desc)
> +{
> +	int i;
> +
> +	if (enabled == NULL)
> +		return 0;
> +
> +	for (i = 0; enabled[i] != NULL; i++)
> +		if (desc->file != NULL && g_pattern_match_simple(enabled[i],
> +							desc->file) == TRUE)
> +			return 1;
> +
> +	return 0;
> +}
> +
> +void __btd_enable_debug(struct btd_debug_desc *start,
> +					struct btd_debug_desc *stop)
> +{
> +	struct btd_debug_desc *desc;
> +
> +	if (start == NULL || stop == NULL)
> +		return;
> +
> +	for (desc = start; desc < stop; desc++) {
> +		if (is_enabled(desc))
> +			desc->flags |= BTD_DEBUG_FLAG_PRINT;
> +	}
> +}
> +
> +void __btd_toggle_debug(void)
> +{
> +	struct btd_debug_desc *desc;
> +
> +	for (desc = __start___debug; desc < __stop___debug; desc++)
> +		desc->flags |= BTD_DEBUG_FLAG_PRINT;
> +}
> +
> +void __btd_log_init(const char *debug, int detach)
> +{
> +	if (debug != NULL)
> +		enabled = g_strsplit_set(debug, ":, ", 0);
> +
> +	__btd_enable_debug(__start___debug, __stop___debug);
> +
> +	detached = detach;
> +
> +	system_fd = open("/dev/log/system", O_WRONLY);
> +
> +	info("Bluetooth daemon %s", VERSION);
> +}
> +
> +void __btd_log_cleanup(void)
> +{
> +	close(system_fd);
> +	system_fd = -1;
> +
> +	g_strfreev(enabled);
> +}
> diff --git a/android/main.c b/android/main.c
> index 37a64c1..ef62b3d 100644
> --- a/android/main.c
> +++ b/android/main.c
> @@ -33,6 +33,7 @@
> 
> #include <glib.h>
> 
> +#include "log.h"
> #include "hcid.h"
> 
> #define SHUTDOWN_GRACE_SECONDS 10
> @@ -58,19 +59,45 @@ static void signal_handler(int sig)
> 	case SIGINT:
> 	case SIGTERM:
> 		if (__terminated == 0) {
> +			info("Terminating");

Since you are in a signal handler and not using signalfd, this is racy.

> 			g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
> 							quit_eventloop, NULL);
> 		}
> 
> 		__terminated = 1;
> 		break;
> +
> +	case SIGUSR2:
> +		__btd_toggle_debug();
> +		break;
> 	}

Lets leave this handling out right now. I know that bluetoothd historically supported it, but that is historic baggage. Neither oFono nor ConnMan does it that way. So just do no bother with this. If it becomes useful, we will add it.

> }
> 
> +static char *option_debug = NULL;
> static gboolean option_detach = TRUE;
> static gboolean option_version = FALSE;
> 
> +static void free_options(void)
> +{
> +	g_free(option_debug);
> +	option_debug = NULL;
> +}
> +
> +static gboolean parse_debug(const char *key, const char *value,
> +				gpointer user_data, GError **error)
> +{
> +	if (value)
> +		option_debug = g_strdup(value);
> +	else
> +		option_debug = g_strdup("*");
> +
> +	return TRUE;
> +}
> +
> static GOptionEntry options[] = {
> +	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
> +				G_OPTION_ARG_CALLBACK, parse_debug,
> +				"Specify debug options to enable", "DEBUG" },
> 	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
> 				G_OPTION_ARG_NONE, &option_detach,
> 				"Run with logging in foreground", NULL },
> @@ -110,10 +137,22 @@ int main(int argc, char *argv[])
> 	sa.sa_handler = signal_handler;
> 	sigaction(SIGINT, &sa, NULL);
> 	sigaction(SIGTERM, &sa, NULL);
> +	sigaction(SIGUSR2, &sa, NULL);
> +
> +	__btd_log_init(option_debug, option_detach);
> +
> +	/* no need to keep parsed option in memory */
> +	free_options();
> +
> +	DBG("Entering main loop");

Don't do this debug. It is not helpful. The main() is so short, no point in logging that.

> 
> 	g_main_loop_run(event_loop);
> 
> 	g_main_loop_unref(event_loop);
> 
> +	info("Exit");
> +
> +	__btd_log_cleanup();
> +
> 	return 0;
> }

Regards

Marcel


^ permalink raw reply

* Re: [PATCH v3 8/8] sdp: Decouple Device ID profile implementation
From: Marcel Holtmann @ 2013-09-21 17:23 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1379599910-8666-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

> Make DeviceID profile similar to other profiles implementations. Use
> btd_profile for handling DeviceID profile while adding/removing
> adapters. The nice drawback is that SDP code no longer depends on
> main_opts.
> ---
> 
> Fixed missing g_slist_remove.
> 
> Makefile.plugins             |   3 +
> profiles/deviceid/deviceid.c | 189 +++++++++++++++++++++++++++++++++++++++++++
> src/adapter.c                |  26 +++---
> src/adapter.h                |   3 +
> src/sdpd-server.c            |   4 -
> src/sdpd-service.c           |  58 -------------
> src/sdpd.h                   |   2 -
> 7 files changed, 206 insertions(+), 79 deletions(-)
> create mode 100644 profiles/deviceid/deviceid.c

please do not intermix profiles/ code with src/ code in the same commit.

Regards

Marcel


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox