Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v4 06/10] battery: Get Battery ID
From: chen.ganir @ 2012-09-24  7:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348470919-25567-1-git-send-email-chen.ganir@ti.com>

From: Chen Ganir <chen.ganir@ti.com>

Read the battery level format characteristic descriptor to get the
unique namespace and description values.
---
 lib/uuid.h                 |    1 +
 profiles/battery/battery.c |   53 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 58ad0b3..5c1b3ff 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -57,6 +57,7 @@ extern "C" {
 #define DEVICE_INFORMATION_UUID	"0000180a-0000-1000-8000-00805f9b34fb"
 
 #define BATTERY_SERVICE_UUID	"0000180f-0000-1000-8000-00805f9b34fb"
+#define BATTERY_LEVEL_UUID	"00002a19-0000-1000-8000-00805f9b34fb"
 
 #define GATT_UUID		"00001801-0000-1000-8000-00805f9b34fb"
 #define IMMEDIATE_ALERT_UUID	"00001802-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index dada15b..2fbf26e 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -52,6 +52,8 @@ struct characteristic {
 	struct gatt_char	attr;		/* Characteristic */
 	struct battery		*batt;		/* Parent Battery Service */
 	GSList			*desc;		/* Descriptors */
+	uint8_t			ns;		/* Battery Namespace */
+	uint16_t		description;	/* Battery description */
 };
 
 struct descriptor {
@@ -98,6 +100,53 @@ static void battery_free(gpointer user_data)
 	g_free(batt);
 }
 
+static void batterylevel_presentation_format_desc_cb(guint8 status,
+						const guint8 *pdu, guint16 len,
+						gpointer user_data)
+{
+	struct descriptor *desc = user_data;
+	uint8_t value[ATT_MAX_MTU];
+	int vlen;
+
+	if (status != 0) {
+		error("Presentation Format desc read failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (vlen < 0) {
+		error("Presentation Format desc read failed: Protocol error");
+		return;
+	}
+
+	if (vlen < 7) {
+		error("Presentation Format desc read failed: Invalid range");
+		return;
+	}
+
+	desc->ch->ns = value[4];
+	desc->ch->description = att_get_u16(&value[5]);
+}
+
+static void process_batterylevel_desc(struct descriptor *desc)
+{
+	struct characteristic *ch = desc->ch;
+	char uuidstr[MAX_LEN_UUID_STR];
+	bt_uuid_t btuuid;
+
+	bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
+
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+		gatt_read_char(ch->batt->attrib, desc->handle, 0,
+				batterylevel_presentation_format_desc_cb, desc);
+		return;
+	}
+
+	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+	DBG("Ignored descriptor %s characteristic %s", uuidstr,	ch->attr.uuid);
+}
+
 static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 							gpointer user_data)
 {
@@ -131,6 +180,7 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 			desc->uuid = att_get_uuid128(&value[2]);
 
 		ch->desc = g_slist_append(ch->desc, desc);
+		process_batterylevel_desc(desc);
 	}
 
 	att_data_list_free(list);
@@ -153,6 +203,9 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 		struct characteristic *ch;
 		uint16_t start, end;
 
+		if (g_strcmp0(c->uuid, BATTERY_LEVEL_UUID) != 0)
+			continue;
+
 		ch = g_new0(struct characteristic, 1);
 		ch->attr.handle = c->handle;
 		ch->attr.properties = c->properties;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 05/10] battery: Discover Characteristic Descriptors
From: chen.ganir @ 2012-09-24  7:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348470919-25567-1-git-send-email-chen.ganir@ti.com>

From: Chen Ganir <chen.ganir@ti.com>

Discover all characteristic descriptors, and build a descriptor
list. Presentation Format Descriptor and Client Characteristic
Configuration descriptors are searched.
---
 profiles/battery/battery.c |   73 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 72 insertions(+), 1 deletion(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 5e52275..dada15b 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -51,7 +51,15 @@ static GSList *servers;
 struct characteristic {
 	struct gatt_char	attr;		/* Characteristic */
 	struct battery		*batt;		/* Parent Battery Service */
+	GSList			*desc;		/* Descriptors */
 };
+
+struct descriptor {
+	struct characteristic	*ch;		/* Parent Characteristic */
+	uint16_t		handle;		/* Descriptor Handle */
+	bt_uuid_t		uuid;		/* UUID */
+};
+
 static gint cmp_device(gconstpointer a, gconstpointer b)
 {
 	const struct battery *batt = a;
@@ -63,12 +71,21 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static void char_free(gpointer user_data)
+{
+	struct characteristic *c = user_data;
+
+	g_slist_free_full(c->desc, g_free);
+
+	g_free(c);
+}
+
 static void battery_free(gpointer user_data)
 {
 	struct battery *batt = user_data;
 
 	if (batt->chars != NULL)
-		g_slist_free_full(batt->chars, g_free);
+		g_slist_free_full(batt->chars, char_free);
 
 	if (batt->attioid > 0)
 		btd_device_remove_attio_callback(batt->dev, batt->attioid);
@@ -77,9 +94,48 @@ static void battery_free(gpointer user_data)
 		g_attrib_unref(batt->attrib);
 
 	btd_device_unref(batt->dev);
+	g_free(batt->svc_range);
 	g_free(batt);
 }
 
+static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct att_data_list *list;
+	uint8_t format;
+	int i;
+
+	if (status != 0) {
+		error("Discover all characteristic descriptors failed [%s]: %s",
+					ch->attr.uuid, att_ecode2str(status));
+		return;
+	}
+
+	list = dec_find_info_resp(pdu, len, &format);
+	if (list == NULL)
+		return;
+
+	for (i = 0; i < list->num; i++) {
+		struct descriptor *desc;
+		uint8_t *value;
+
+		value = list->data[i];
+		desc = g_new0(struct descriptor, 1);
+		desc->handle = att_get_u16(value);
+		desc->ch = ch;
+
+		if (format == 0x01)
+			desc->uuid = att_get_uuid16(&value[2]);
+		else
+			desc->uuid = att_get_uuid128(&value[2]);
+
+		ch->desc = g_slist_append(ch->desc, desc);
+	}
+
+	att_data_list_free(list);
+}
+
 static void configure_battery_cb(GSList *characteristics, guint8 status,
 							gpointer user_data)
 {
@@ -95,6 +151,7 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 	for (l = characteristics; l; l = l->next) {
 		struct gatt_char *c = l->data;
 		struct characteristic *ch;
+		uint16_t start, end;
 
 		ch = g_new0(struct characteristic, 1);
 		ch->attr.handle = c->handle;
@@ -104,6 +161,20 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 		ch->batt = batt;
 
 		batt->chars = g_slist_append(batt->chars, ch);
+
+		start = c->value_handle + 1;
+
+		if (l->next != NULL) {
+			struct gatt_char *c = l->next->data;
+			if (start == c->handle)
+				continue;
+			end = c->handle - 1;
+		} else if (c->value_handle != batt->svc_range->end)
+			end = batt->svc_range->end;
+		else
+			continue;
+
+		gatt_find_info(batt->attrib, start, end, discover_desc_cb, ch);
 	}
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 04/10] battery: Add client connection logic
From: chen.ganir @ 2012-09-24  7:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348470919-25567-1-git-send-email-chen.ganir@ti.com>

From: Chen Ganir <chen.ganir@ti.com>

Add connection logic to the Battery Plugin. When the driver is
loaded, it will request a connection to the remote device and
release the connection request when destroyed.
---
 profiles/battery/battery.c |   90 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 7702e39..5e52275 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -30,17 +30,28 @@
 
 #include "adapter.h"
 #include "device.h"
+#include "gattrib.h"
+#include "attio.h"
 #include "att.h"
 #include "gattrib.h"
 #include "gatt.h"
 #include "battery.h"
+#include "log.h"
 
 struct battery {
 	struct btd_device	*dev;		/* Device reference */
+	GAttrib			*attrib;	/* GATT connection */
+	guint			attioid;	/* Att watcher id */
+	struct att_range	*svc_range;	/* Battery range */
+	GSList			*chars;		/* Characteristics */
 };
 
 static GSList *servers;
 
+struct characteristic {
+	struct gatt_char	attr;		/* Characteristic */
+	struct battery		*batt;		/* Parent Battery Service */
+};
 static gint cmp_device(gconstpointer a, gconstpointer b)
 {
 	const struct battery *batt = a;
@@ -56,20 +67,99 @@ static void battery_free(gpointer user_data)
 {
 	struct battery *batt = user_data;
 
+	if (batt->chars != NULL)
+		g_slist_free_full(batt->chars, g_free);
+
+	if (batt->attioid > 0)
+		btd_device_remove_attio_callback(batt->dev, batt->attioid);
+
+	if (batt->attrib != NULL)
+		g_attrib_unref(batt->attrib);
+
 	btd_device_unref(batt->dev);
 	g_free(batt);
 }
 
+static void configure_battery_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct battery *batt = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover Battery characteristics: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	for (l = characteristics; l; l = l->next) {
+		struct gatt_char *c = l->data;
+		struct characteristic *ch;
+
+		ch = g_new0(struct characteristic, 1);
+		ch->attr.handle = c->handle;
+		ch->attr.properties = c->properties;
+		ch->attr.value_handle = c->value_handle;
+		memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+		ch->batt = batt;
+
+		batt->chars = g_slist_append(batt->chars, ch);
+	}
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct battery *batt = user_data;
+
+	batt->attrib = g_attrib_ref(attrib);
+
+	if (batt->chars == NULL) {
+		gatt_discover_char(batt->attrib, batt->svc_range->start,
+					batt->svc_range->end, NULL,
+					configure_battery_cb, batt);
+	}
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct battery *batt = user_data;
+
+	g_attrib_unref(batt->attrib);
+	batt->attrib = NULL;
+}
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct gatt_primary *prim = a;
+	const char *uuid = b;
+
+	return g_strcmp0(prim->uuid, uuid);
+}
 
 int battery_register(struct btd_device *device)
 {
 	struct battery *batt;
+	struct gatt_primary *prim;
+	GSList *primaries, *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, BATTERY_SERVICE_UUID,
+							primary_uuid_cmp);
+	prim = l->data;
 
 	batt = g_new0(struct battery, 1);
 	batt->dev = btd_device_ref(device);
 
+	batt->svc_range = g_new0(struct att_range, 1);
+	batt->svc_range->start = prim->range.start;
+	batt->svc_range->end = prim->range.end;
+
 	servers = g_slist_prepend(servers, batt);
 
+	batt->attioid = btd_device_add_attio_callback(device,
+				attio_connected_cb, attio_disconnected_cb,
+				batt);
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 03/10] battery: Add GATT Battery Client Service skeleton
From: chen.ganir @ 2012-09-24  7:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348470919-25567-1-git-send-email-chen.ganir@ti.com>

From: Chen Ganir <chen.ganir@ti.com>

Add support for the Battery Service Gatt Client side. Implement
the basic skeleton.
---
 Makefile.am                |    9 ++++-
 lib/uuid.h                 |    2 +
 profiles/battery/battery.c |   89 ++++++++++++++++++++++++++++++++++++++++++++
 profiles/battery/battery.h |   24 ++++++++++++
 profiles/battery/main.c    |   52 ++++++++++++++++++++++++++
 profiles/battery/manager.c |   62 ++++++++++++++++++++++++++++++
 profiles/battery/manager.h |   24 ++++++++++++
 7 files changed, 260 insertions(+), 2 deletions(-)
 create mode 100644 profiles/battery/battery.c
 create mode 100644 profiles/battery/battery.h
 create mode 100644 profiles/battery/main.c
 create mode 100644 profiles/battery/manager.c
 create mode 100644 profiles/battery/manager.h

diff --git a/Makefile.am b/Makefile.am
index 372111a..21b5ebf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -211,7 +211,7 @@ endif
 
 if GATTMODULES
 builtin_modules += thermometer alert time gatt_example proximity deviceinfo \
-			gatt
+			gatt battery
 builtin_sources += profiles/thermometer/main.c \
 			profiles/thermometer/manager.h \
 			profiles/thermometer/manager.c \
@@ -240,7 +240,12 @@ builtin_sources += profiles/thermometer/main.c \
 			profiles/deviceinfo/deviceinfo.c \
 			profiles/gatt/main.c profiles/gatt/manager.h \
 			profiles/gatt/manager.c profiles/gatt/gas.h \
-			profiles/gatt/gas.c
+			profiles/gatt/gas.c \
+			profiles/battery/main.c \
+			profiles/battery/manager.c \
+			profiles/battery/manager.h \
+			profiles/battery/battery.c \
+			profiles/battery/battery.h
 endif
 
 builtin_modules += formfactor
diff --git a/lib/uuid.h b/lib/uuid.h
index aa6efdf..58ad0b3 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -56,6 +56,8 @@ extern "C" {
 #define PNPID_UUID		"00002a50-0000-1000-8000-00805f9b34fb"
 #define DEVICE_INFORMATION_UUID	"0000180a-0000-1000-8000-00805f9b34fb"
 
+#define BATTERY_SERVICE_UUID	"0000180f-0000-1000-8000-00805f9b34fb"
+
 #define GATT_UUID		"00001801-0000-1000-8000-00805f9b34fb"
 #define IMMEDIATE_ALERT_UUID	"00001802-0000-1000-8000-00805f9b34fb"
 #define LINK_LOSS_UUID		"00001803-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
new file mode 100644
index 0000000..7702e39
--- /dev/null
+++ b/profiles/battery/battery.c
@@ -0,0 +1,89 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  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 <glib.h>
+#include <bluetooth/uuid.h>
+#include <stdbool.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "battery.h"
+
+struct battery {
+	struct btd_device	*dev;		/* Device reference */
+};
+
+static GSList *servers;
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+	const struct battery *batt = a;
+	const struct btd_device *dev = b;
+
+	if (dev == batt->dev)
+		return 0;
+
+	return -1;
+}
+
+static void battery_free(gpointer user_data)
+{
+	struct battery *batt = user_data;
+
+	btd_device_unref(batt->dev);
+	g_free(batt);
+}
+
+
+int battery_register(struct btd_device *device)
+{
+	struct battery *batt;
+
+	batt = g_new0(struct battery, 1);
+	batt->dev = btd_device_ref(device);
+
+	servers = g_slist_prepend(servers, batt);
+
+	return 0;
+}
+
+void battery_unregister(struct btd_device *device)
+{
+	struct battery *batt;
+	GSList *l;
+
+	l = g_slist_find_custom(servers, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	batt = l->data;
+	servers = g_slist_remove(servers, batt);
+
+	battery_free(batt);
+}
diff --git a/profiles/battery/battery.h b/profiles/battery/battery.h
new file mode 100644
index 0000000..9933343
--- /dev/null
+++ b/profiles/battery/battery.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  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
+ *
+ */
+
+int battery_register(struct btd_device *device);
+void battery_unregister(struct btd_device *device);
diff --git a/profiles/battery/main.c b/profiles/battery/main.c
new file mode 100644
index 0000000..d4a23c9
--- /dev/null
+++ b/profiles/battery/main.c
@@ -0,0 +1,52 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  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 <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "hcid.h"
+#include "plugin.h"
+#include "manager.h"
+#include "log.h"
+
+static int battery_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		error("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return battery_manager_init();
+}
+
+static void battery_exit(void)
+{
+	battery_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(battery, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+						battery_init, battery_exit)
diff --git a/profiles/battery/manager.c b/profiles/battery/manager.c
new file mode 100644
index 0000000..9abb31a
--- /dev/null
+++ b/profiles/battery/manager.c
@@ -0,0 +1,62 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  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
+ *
+ */
+
+#include <glib.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+#include <stdbool.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "battery.h"
+#include "manager.h"
+
+static int battery_driver_probe(struct btd_device *device, GSList *uuids)
+{
+	return battery_register(device);
+}
+
+static void battery_driver_remove(struct btd_device *device)
+{
+	battery_unregister(device);
+}
+
+static struct btd_profile battery_profile = {
+	.name		= "battery",
+	.remote_uuids	= BTD_UUIDS(BATTERY_SERVICE_UUID),
+	.device_probe	= battery_driver_probe,
+	.device_remove	= battery_driver_remove
+};
+
+int battery_manager_init(void)
+{
+	return btd_profile_register(&battery_profile);
+}
+
+void battery_manager_exit(void)
+{
+	btd_profile_unregister(&battery_profile);
+}
diff --git a/profiles/battery/manager.h b/profiles/battery/manager.h
new file mode 100644
index 0000000..b2c849f
--- /dev/null
+++ b/profiles/battery/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  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
+ *
+ */
+
+int battery_manager_init(void);
+void battery_manager_exit(void);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 02/10] battery: Implement Generic device battery
From: chen.ganir @ 2012-09-24  7:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348470919-25567-1-git-send-email-chen.ganir@ti.com>

From: Chen Ganir <chen.ganir@ti.com>

Add implementation for the generic battery in bluetooth device.
This patch adds new D-Bus interface for adding/removing/changing
peer device battery status, allowing management of remote device
batteries.
---
 src/device.c     |  175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/device.h     |   14 +++++
 test/test-device |   13 ++++
 3 files changed, 202 insertions(+)

diff --git a/src/device.c b/src/device.c
index aa3a607..750d3a8 100644
--- a/src/device.c
+++ b/src/device.c
@@ -163,6 +163,7 @@ struct btd_device {
 
 	gboolean	authorizing;
 	gint		ref;
+	GSList		*batteries;
 
 	GIOChannel      *att_io;
 	guint		cleanup_id;
@@ -175,6 +176,24 @@ static uint16_t uuid_list[] = {
 	0
 };
 
+struct btd_battery {
+	uint16_t		level;
+	char			*path;
+	struct btd_device	*device;
+	refresh_battery_cb	refresh;
+};
+
+static void battery_free(gpointer user_data)
+{
+	struct btd_battery *b = user_data;
+
+	g_dbus_unregister_interface(btd_get_dbus_connection(), b->path, BATTERY_INTERFACE);
+	btd_device_unref(b->device);
+	g_free(b->path);
+	g_free(b);
+
+}
+
 static void browse_request_free(struct browse_req *req)
 {
 	if (req->listener_id)
@@ -253,6 +272,7 @@ static void device_free(gpointer user_data)
 	g_slist_free_full(device->primaries, g_free);
 	g_slist_free_full(device->attios, g_free);
 	g_slist_free_full(device->attios_offline, g_free);
+	g_slist_free_full(device->batteries, battery_free);
 
 	attio_cleanup(device);
 
@@ -426,6 +446,15 @@ static DBusMessage *get_properties(DBusConnection *conn,
 	ptr = adapter_get_path(adapter);
 	dict_append_entry(&dict, "Adapter", DBUS_TYPE_OBJECT_PATH, &ptr);
 
+	/* Batteries */
+	str = g_new0(char *, g_slist_length(device->batteries) + 1);
+	for (i = 0, l = device->batteries; l; l = l->next, i++) {
+		struct btd_battery *b = l->data;
+		str[i] = b->path;
+	}
+	dict_append_array(&dict, "Batteries", DBUS_TYPE_OBJECT_PATH, &str, i);
+	g_free(str);
+
 	dbus_message_iter_close_container(&iter, &dict);
 
 	return reply;
@@ -3177,3 +3206,149 @@ void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
 	device_set_version(device, product_ver);
 }
 
+static void batteries_changed(struct btd_device *device)
+{
+	char **batteries;
+	GSList *l;
+	int i;
+
+	batteries = g_new0(char *, g_slist_length(device->batteries) + 1);
+	for (i = 0, l = device->batteries; l; l = l->next, i++) {
+		struct btd_battery *batt = l->data;
+		batteries[i] = batt->path;
+	}
+
+	emit_array_property_changed(device->path, DEVICE_INTERFACE, "Batteries",
+					  DBUS_TYPE_OBJECT_PATH, &batteries, i);
+
+	g_free(batteries);
+}
+
+static DBusMessage *refresh_batt_level(DBusConnection *conn,
+						  DBusMessage *msg, void *data)
+{
+	struct btd_battery *b = data;
+
+	if (!b->refresh)
+		return btd_error_not_supported(msg);
+
+	b->refresh(b);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *get_batt_properties(DBusConnection *conn,
+						  DBusMessage *msg, void *data)
+{
+	struct btd_battery *b = data;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(msg);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	dict_append_entry(&dict, "Level", DBUS_TYPE_UINT16, &b->level);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
+static GDBusMethodTable battery_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+		NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+		get_batt_properties) },
+	{ GDBUS_METHOD("Refresh",
+		NULL, NULL,
+		refresh_batt_level) },
+	{ }
+};
+
+static GDBusSignalTable battery_signals[] = {
+	{ GDBUS_SIGNAL("PropertyChanged",
+		GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+	{ }
+};
+
+struct btd_battery *btd_device_add_battery(struct btd_device *device)
+{
+	struct btd_battery *batt;
+
+	batt = g_new0(struct btd_battery, 1);
+	batt->path = g_strdup_printf("%s/BATT%04X", device->path,
+					     g_slist_length(device->batteries));
+
+	if (!g_dbus_register_interface(btd_get_dbus_connection(), batt->path,
+			BATTERY_INTERFACE, battery_methods, battery_signals,
+			NULL, batt, NULL)) {
+		error("D-Bus register interface %s failed", BATTERY_INTERFACE);
+		g_free(batt->path);
+		g_free(batt);
+		return NULL;
+	}
+
+	batt->device = btd_device_ref(device);
+	device->batteries = g_slist_append(device->batteries, batt);
+	batteries_changed(device);
+
+	return batt;
+}
+
+void btd_device_remove_battery(struct btd_battery *batt)
+{
+	struct btd_device *dev = batt->device;
+
+	dev->batteries = g_slist_remove(dev->batteries, batt);
+
+	battery_free(batt);
+
+	batteries_changed(dev);
+}
+
+gboolean btd_device_set_battery_opt(struct btd_battery *batt,
+						    battery_option_t opt1, ...)
+{
+	va_list args;
+	battery_option_t opt = opt1;
+	int level;
+
+	if (!batt)
+		return FALSE;
+
+	va_start(args, opt1);
+
+	while (opt != BATTERY_OPT_INVALID) {
+		switch (opt) {
+		case BATTERY_OPT_LEVEL:
+			level = va_arg(args, int);
+			if (level != batt->level) {
+				batt->level = level;
+				emit_property_changed(batt->path,
+						BATTERY_INTERFACE, "Level",
+						DBUS_TYPE_UINT16, &level);
+			}
+			break;
+		case BATTERY_OPT_REFRESH_FUNC:
+			batt->refresh = va_arg(args, refresh_battery_cb);
+			break;
+		default:
+			error("Unknown option %d", opt);
+			return FALSE;
+		}
+
+		opt = va_arg(args, int);
+	}
+
+	va_end(args);
+
+	return TRUE;
+}
diff --git a/src/device.h b/src/device.h
index aee6d13..a82ae74 100644
--- a/src/device.h
+++ b/src/device.h
@@ -23,8 +23,10 @@
  */
 
 #define DEVICE_INTERFACE	"org.bluez.Device"
+#define BATTERY_INTERFACE      "org.bluez.Battery"
 
 struct btd_device;
+struct btd_battery;
 
 typedef enum {
 	AUTH_TYPE_PINCODE,
@@ -34,6 +36,14 @@ typedef enum {
 	AUTH_TYPE_NOTIFY_PINCODE,
 } auth_type_t;
 
+typedef void (*refresh_battery_cb) (struct btd_battery *batt);
+
+typedef enum {
+	BATTERY_OPT_INVALID = 0,
+	BATTERY_OPT_LEVEL,
+	BATTERY_OPT_REFRESH_FUNC,
+} battery_option_t;
+
 struct btd_device *device_create(struct btd_adapter *adapter,
 				const char *address, uint8_t bdaddr_type);
 
@@ -125,3 +135,7 @@ void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
 			uint16_t vendor_id, uint16_t product_id,
 			uint16_t product_ver);
 gboolean device_att_connect(gpointer user_data);
+struct btd_battery *btd_device_add_battery(struct btd_device *device);
+void btd_device_remove_battery(struct btd_battery *batt);
+gboolean btd_device_set_battery_opt(struct btd_battery *batt,
+						    battery_option_t opt1, ...);
diff --git a/test/test-device b/test/test-device
index 63a96d3..7edb7b8 100755
--- a/test/test-device
+++ b/test/test-device
@@ -37,6 +37,7 @@ if (len(args) < 1):
 	print("")
 	print("  list")
 	print("  services <address>")
+	print("  batteries <address>")
 	print("  create <address>")
 	print("  remove <address|path>")
 	print("  disconnect <address>")
@@ -205,5 +206,17 @@ if (args[0] == "services"):
 			print(path)
 	sys.exit(0)
 
+if (args[0] == "batteries"):
+	if (len(args) < 2):
+		print("Need address parameter")
+	else:
+		path = adapter.FindDevice(args[1])
+		device = dbus.Interface(bus.get_object("org.bluez", path),
+							"org.bluez.Device")
+		properties = device.GetProperties()
+		for path in properties["Batteries"]:
+			print(path)
+	sys.exit(0)
+
 print("Unknown command")
 sys.exit(1)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 01/10] battery: Add generic device battery documentation
From: chen.ganir @ 2012-09-24  7:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348470919-25567-1-git-send-email-chen.ganir@ti.com>

From: Chen Ganir <chen.ganir@ti.com>

Add documentation for the generic battery D-Bus interface.
---
 doc/battery-api.txt |   31 +++++++++++++++++++++++++++++++
 doc/device-api.txt  |    5 +++++
 2 files changed, 36 insertions(+)
 create mode 100644 doc/battery-api.txt

diff --git a/doc/battery-api.txt b/doc/battery-api.txt
new file mode 100644
index 0000000..7e1b94f
--- /dev/null
+++ b/doc/battery-api.txt
@@ -0,0 +1,31 @@
+BlueZ D-Bus Battery API description
+****************************************
+
+	Texas Instruments, Inc. <chen.ganir@ti.com>
+
+Device Battery hierarchy
+=====================================
+
+Service		org.bluez
+Interface	org.bluez.Battery
+Object path	[variable prefix]/{hci0,..}/dev_XX_XX_XX_XX_XX_XX/BATTYYYY
+YYYY is numeric value between 0 and 9999.
+
+Methods	dict GetProperties()
+
+			Returns all properties for the interface. See the
+			Properties section for the available properties.
+
+		void Refresh()
+
+			Refresh the batterty level. If the battery level changed, the
+			PropertyChanged signal will be sent with the new value.
+
+Signals		PropertyChanged(string name, variant value)
+
+			This signal indicates a changed value of the given
+			property.
+
+Properties	uint16 Level [readonly]
+
+			Battery level (0-100).
diff --git a/doc/device-api.txt b/doc/device-api.txt
index 1f0dc96..c98d539 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -179,3 +179,8 @@ Properties	string Address [readonly]
 			Note that this property can exhibit false-positives
 			in the case of Bluetooth 2.1 (or newer) devices that
 			have disabled Extended Inquiry Response support.
+
+		array{object} Batteries [readonly]
+
+			List of device battery object paths that represents the available
+			batteries on the remote device.
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v4 00/10] Implement Generic battery and LE Battery client
From: chen.ganir @ 2012-09-24  7:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir

From: Chen Ganir <chen.ganir@ti.com>

This patch set replaces previous patch sets which implemented the LE battery
GATT Client. This patch set implements a generic device battery D-Bus interface
that can be used to get remote device battery status using D-Bus. In addition,
This patch set also implements the GATT Battery client, which uses the generic
device battery to expose LE device battery status.

see doc/battery-api.txt and doc/device-api.txt for more information.

This is version 4 of the patch set, including multiple style and other comments
reported on the ML. This version is rebased on the latest code.

Chen Ganir (10):
  battery: Add generic device battery documentation
  battery: Implement Generic device battery
  battery: Add GATT Battery Client Service skeleton
  battery: Add client connection logic
  battery: Discover Characteristic Descriptors
  battery: Get Battery ID
  battery: Add Battery to device
  battery: Read Battery level characteristic
  battery: Add support for notifications
  battery: Support persistent battery level

 Makefile.am                |    9 +-
 doc/battery-api.txt        |   31 +++
 doc/device-api.txt         |    5 +
 lib/uuid.h                 |    3 +
 profiles/battery/battery.c |  592 ++++++++++++++++++++++++++++++++++++++++++++
 profiles/battery/battery.h |   24 ++
 profiles/battery/main.c    |   52 ++++
 profiles/battery/manager.c |   62 +++++
 profiles/battery/manager.h |   24 ++
 src/device.c               |  175 +++++++++++++
 src/device.h               |   14 ++
 test/test-device           |   13 +
 12 files changed, 1002 insertions(+), 2 deletions(-)
 create mode 100644 doc/battery-api.txt
 create mode 100644 profiles/battery/battery.c
 create mode 100644 profiles/battery/battery.h
 create mode 100644 profiles/battery/main.c
 create mode 100644 profiles/battery/manager.c
 create mode 100644 profiles/battery/manager.h

-- 
1.7.9.5


^ permalink raw reply

* [RFC 2/2] Bluetooth: Add BT USB mini driver template
From: Tedd Ho-Jeong An @ 2012-09-22  1:59 UTC (permalink / raw)
  To: linux-bluetooth, marcel; +Cc: johan.hedberg, albert.o.ho, tedd.hj.an

From: Tedd Ho-Jeong An <tedd.an@intel.com>

This patch adds BT USB mini driver template.

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
---
 drivers/bluetooth/Makefile         |    1 +
 drivers/bluetooth/btusb.c          |    3 ++
 drivers/bluetooth/btusb_template.c |   78 ++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)
 create mode 100644 drivers/bluetooth/btusb_template.c

diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 4afae20..b4daa01 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_BT_HCIBLUECARD)	+= bluecard_cs.o
 obj-$(CONFIG_BT_HCIBTUART)	+= btuart_cs.o
 
 obj-$(CONFIG_BT_HCIBTUSB)	+= btusb.o
+obj-$(CONFIG_BT_HCIBTUSB)	+= btusb_template.o
 obj-$(CONFIG_BT_HCIBTSDIO)	+= btsdio.o
 
 obj-$(CONFIG_BT_ATH3K)		+= ath3k.o
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index afa1558..864eb77 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -235,6 +235,9 @@ static struct usb_device_id blacklist_table[] = {
 	/* Frontline ComProbe Bluetooth Sniffer */
 	{ USB_DEVICE(0x16d3, 0x0002), .driver_info = (unsigned long) &sniffer },
 
+	/* BT USB mini driver template */
+	{ USB_DEVICE(0x1234, 0x5678), .driver_info = (unsigned long) &ignore },
+
 	{ }	/* Terminating entry */
 };
 
diff --git a/drivers/bluetooth/btusb_template.c b/drivers/bluetooth/btusb_template.c
new file mode 100644
index 0000000..1e1d2da
--- /dev/null
+++ b/drivers/bluetooth/btusb_template.c
@@ -0,0 +1,78 @@
+/*
+ *
+ *  Bluetooth USB Mini Driver - Template
+ *
+ *  Copyright (C) 2012  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btusb.h"
+
+int btusb_template_init(struct hci_dev *hdev)
+{
+	/*
+	 * TOOD: Implement vendor specific initialization
+	 */
+	return 0;
+}
+
+void btusb_template_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	/*
+	 * TODO: Implement vendor specific event handler routine
+	 */
+	return;
+}
+
+static const struct btusb_driver_info template_info = {
+	.description	= "BT USB mini driver template",
+	.vsdev_init	= btusb_template_init,
+	.vsdev_event	= btusb_template_event,
+};
+
+static const struct usb_device_id products[] = {
+	{
+		USB_DEVICE(0x1234, 0x5678),
+		.driver_info = (unsigned long) &template_info,
+	},
+	{},	/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver btusb_template_minidriver = {
+	.name		= "btusb_template mini driver",
+	.probe		= btusb_probe,
+	.disconnect	= btusb_disconnect,
+#ifdef CONFIG_PM
+	.suspend	= btusb_suspend,
+	.resume		= btusb_resume,
+#endif
+	.id_table	= products,
+	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
+};
+module_usb_driver(btusb_template_minidriver);
+
+MODULE_AUTHOR("Tedd Ho-Jeong An <tedd.an@intel.com>");
+MODULE_DESCRIPTION("Sample BT USB mini driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5



^ permalink raw reply related

* [RFC 1/2] Bluetooth: Add driver extension for vendor specific init
From: Tedd Ho-Jeong An @ 2012-09-22  1:59 UTC (permalink / raw)
  To: linux-bluetooth, marcel; +Cc: johan.hedberg, albert.o.ho, tedd.hj.an

From: Tedd Ho-Jeong An <tedd.an@intel.com>

This patch provides an extension of btusb to support device vendor
can implement their own module to execute the vendor specific
device initialization before the stack sends generic BT device
initialization.

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
---
 drivers/bluetooth/btusb.c        |  191 +++++++++++++++++++++++++-------------
 drivers/bluetooth/btusb.h        |   53 +++++++++++
 include/net/bluetooth/hci_core.h |   10 ++
 net/bluetooth/hci_core.c         |   15 ++-
 4 files changed, 204 insertions(+), 65 deletions(-)
 create mode 100644 drivers/bluetooth/btusb.h

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index f637c25..afa1558 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -26,6 +26,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include "btusb.h"
 
 #define VERSION "0.6"
 
@@ -39,14 +40,59 @@ static bool reset = 1;
 
 static struct usb_driver btusb_driver;
 
-#define BTUSB_IGNORE		0x01
-#define BTUSB_DIGIANSWER	0x02
-#define BTUSB_CSR		0x04
-#define BTUSB_SNIFFER		0x08
-#define BTUSB_BCM92035		0x10
-#define BTUSB_BROKEN_ISOC	0x20
-#define BTUSB_WRONG_SCO_MTU	0x40
-#define BTUSB_ATH3012		0x80
+/*
+ * Create btusb_driver_info struct for each driver_info flags used by
+ * blacklist since vendor's btusb driver will return btusb_driver_info struct.
+ */
+
+/*
+ * if the device is set to this, this menas that the device is generic and
+ * doesn't require any vendor specific handling
+ */
+static const struct btusb_driver_info generic = {
+	.description	= "BTUSB Generic",
+	.flags		= BTUSB_GENERIC,
+};
+
+static const struct btusb_driver_info ignore = {
+	.description	= "BTUSB Ignore",
+	.flags		= BTUSB_IGNORE,
+};
+
+static const struct btusb_driver_info digianswer = {
+	.description	= "BTUSB DIGIANSWER",
+	.flags		= BTUSB_DIGIANSWER,
+};
+
+static const struct btusb_driver_info csr = {
+	.description	= "BTUSB CSR",
+	.flags		= BTUSB_CSR,
+};
+
+static const struct btusb_driver_info sniffer = {
+	.description	= "BTUSB Sniffer",
+	.flags		= BTUSB_SNIFFER,
+};
+
+static const struct btusb_driver_info bcm92035 = {
+	.description	= "BTUSB BCM92035",
+	.flags		= BTUSB_BCM92035,
+};
+
+static const struct btusb_driver_info broken_isoc = {
+	.description	= "BTUSB Broken ISOC",
+	.flags		= BTUSB_BROKEN_ISOC,
+};
+
+static const struct btusb_driver_info wrong_sco_mtu = {
+	.description	= "BTUSB Wrong SCO MTU",
+	.flags		= BTUSB_WRONG_SCO_MTU,
+};
+
+static const struct btusb_driver_info ath3012 = {
+	.description	= "BTUSB Ath3012",
+	.flags		= BTUSB_ATH3012,
+};
 
 static struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
@@ -105,90 +151,89 @@ static struct usb_device_id btusb_table[] = {
 
 	{ }	/* Terminating entry */
 };
-
 MODULE_DEVICE_TABLE(usb, btusb_table);
 
 static struct usb_device_id blacklist_table[] = {
 	/* CSR BlueCore devices */
-	{ USB_DEVICE(0x0a12, 0x0001), .driver_info = BTUSB_CSR },
+	{ USB_DEVICE(0x0a12, 0x0001), .driver_info = (unsigned long) &csr },
 
 	/* Broadcom BCM2033 without firmware */
-	{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
+	{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = (unsigned long) &ignore },
 
 	/* Atheros 3011 with sflash firmware */
-	{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
-	{ USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE },
-	{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
-	{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
-	{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
+	{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = (unsigned long) &ignore },
+	{ USB_DEVICE(0x0cf3, 0xe019), .driver_info = (unsigned long) &ignore },
+	{ USB_DEVICE(0x13d3, 0x3304), .driver_info = (unsigned long) &ignore },
+	{ USB_DEVICE(0x0930, 0x0215), .driver_info = (unsigned long) &ignore },
+	{ USB_DEVICE(0x0489, 0xe03d), .driver_info = (unsigned long) &ignore },
 
 	/* Atheros AR9285 Malbec with sflash firmware */
-	{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
+	{ USB_DEVICE(0x03f0, 0x311d), .driver_info = (unsigned long) &ignore },
 
 	/* Atheros 3012 with sflash firmware */
-	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
-	{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
-	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
-	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
-	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
-	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
-	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = (unsigned long) &ath3012 },
+	{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = (unsigned long) &ath3012 },
+	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = (unsigned long) &ath3012 },
+	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = (unsigned long) &ath3012 },
+	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = (unsigned long) &ath3012 },
+	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = (unsigned long) &ath3012 },
+	{ USB_DEVICE(0x0930, 0x0219), .driver_info = (unsigned long) &ath3012 },
 
 	/* Atheros AR5BBU12 with sflash firmware */
-	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
+	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = (unsigned long) &ignore },
 
 	/* Atheros AR5BBU12 with sflash firmware */
-	{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0489, 0xe03c), .driver_info = (unsigned long) &ath3012 },
 
 	/* Broadcom BCM2035 */
-	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
+	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = (unsigned long) &wrong_sco_mtu },
+	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = (unsigned long) &wrong_sco_mtu },
+	{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = (unsigned long) &bcm92035 },
 
 	/* Broadcom BCM2045 */
-	{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = (unsigned long) &wrong_sco_mtu },
+	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = (unsigned long) &wrong_sco_mtu },
 
 	/* IBM/Lenovo ThinkPad with Broadcom chip */
-	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = (unsigned long) &wrong_sco_mtu },
+	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = (unsigned long) &wrong_sco_mtu },
 
 	/* HP laptop with Broadcom chip */
-	{ USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x03f0, 0x171d), .driver_info = (unsigned long) &wrong_sco_mtu },
 
 	/* Dell laptop with Broadcom chip */
-	{ USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x413c, 0x8126), .driver_info = (unsigned long) &wrong_sco_mtu },
 
 	/* Dell Wireless 370 and 410 devices */
-	{ USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x413c, 0x8152), .driver_info = (unsigned long) &wrong_sco_mtu },
+	{ USB_DEVICE(0x413c, 0x8156), .driver_info = (unsigned long) &wrong_sco_mtu },
 
 	/* Belkin F8T012 and F8T013 devices */
-	{ USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_WRONG_SCO_MTU },
-	{ USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x050d, 0x0012), .driver_info = (unsigned long) &wrong_sco_mtu },
+	{ USB_DEVICE(0x050d, 0x0013), .driver_info = (unsigned long) &wrong_sco_mtu },
 
 	/* Asus WL-BTD202 device */
-	{ USB_DEVICE(0x0b05, 0x1715), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x0b05, 0x1715), .driver_info = (unsigned long) &wrong_sco_mtu },
 
 	/* Kensington Bluetooth USB adapter */
-	{ USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_WRONG_SCO_MTU },
+	{ USB_DEVICE(0x047d, 0x105e), .driver_info = (unsigned long) &wrong_sco_mtu },
 
 	/* RTX Telecom based adapters with buggy SCO support */
-	{ USB_DEVICE(0x0400, 0x0807), .driver_info = BTUSB_BROKEN_ISOC },
-	{ USB_DEVICE(0x0400, 0x080a), .driver_info = BTUSB_BROKEN_ISOC },
+	{ USB_DEVICE(0x0400, 0x0807), .driver_info = (unsigned long) &broken_isoc },
+	{ USB_DEVICE(0x0400, 0x080a), .driver_info = (unsigned long) &broken_isoc },
 
 	/* CONWISE Technology based adapters with buggy SCO support */
-	{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
+	{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = (unsigned long) &broken_isoc },
 
 	/* Digianswer devices */
-	{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
-	{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
+	{ USB_DEVICE(0x08fd, 0x0001), .driver_info = (unsigned long) &digianswer },
+	{ USB_DEVICE(0x08fd, 0x0002), .driver_info = (unsigned long) &ignore },
 
 	/* CSR BlueCore Bluetooth Sniffer */
-	{ USB_DEVICE(0x0a12, 0x0002), .driver_info = BTUSB_SNIFFER },
+	{ USB_DEVICE(0x0a12, 0x0002), .driver_info = (unsigned long) &sniffer },
 
 	/* Frontline ComProbe Bluetooth Sniffer */
-	{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },
+	{ USB_DEVICE(0x16d3, 0x0002), .driver_info = (unsigned long) &sniffer },
 
 	{ }	/* Terminating entry */
 };
@@ -910,12 +955,12 @@ static void btusb_waker(struct work_struct *work)
 	usb_autopm_put_interface(data->intf);
 }
 
-static int btusb_probe(struct usb_interface *intf,
-				const struct usb_device_id *id)
+int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_endpoint_descriptor *ep_desc;
 	struct btusb_data *data;
 	struct hci_dev *hdev;
+	struct btusb_driver_info *info;
 	int i, err;
 
 	BT_DBG("intf %p id %p", intf, id);
@@ -931,19 +976,28 @@ static int btusb_probe(struct usb_interface *intf,
 			id = match;
 	}
 
-	if (id->driver_info == BTUSB_IGNORE)
+	/*
+	 * Make sure the driver_info is not null or 0 because the code below
+	 * need to access the flags
+	 */
+	if (!id->driver_info)
+		info = (struct btusb_driver_info *) &generic;
+	else
+		info = (struct btusb_driver_info *) id->driver_info;
+
+	if (info->flags == BTUSB_IGNORE)
 		return -ENODEV;
 
-	if (ignore_dga && id->driver_info & BTUSB_DIGIANSWER)
+	if (ignore_dga && (info->flags & BTUSB_DIGIANSWER))
 		return -ENODEV;
 
-	if (ignore_csr && id->driver_info & BTUSB_CSR)
+	if (ignore_csr && (info->flags & BTUSB_CSR))
 		return -ENODEV;
 
-	if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER)
+	if (ignore_sniffer && (info->flags & BTUSB_SNIFFER))
 		return -ENODEV;
 
-	if (id->driver_info & BTUSB_ATH3012) {
+	if (info->flags & BTUSB_ATH3012) {
 		struct usb_device *udev = interface_to_usbdev(intf);
 
 		/* Old firmware would otherwise let ath3k driver load
@@ -1012,26 +1066,30 @@ static int btusb_probe(struct usb_interface *intf,
 	hdev->send     = btusb_send_frame;
 	hdev->notify   = btusb_notify;
 
+	/* vendor specific device initialization routines */
+	hdev->vsdev_init = info->vsdev_init;
+	hdev->vsdev_event = info->vsdev_event;
+
 	/* Interface numbers are hardcoded in the specification */
 	data->isoc = usb_ifnum_to_if(data->udev, 1);
 
 	if (!reset)
 		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
-	if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
+	if (force_scofix || (info->flags & BTUSB_WRONG_SCO_MTU)) {
 		if (!disable_scofix)
 			set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
 	}
 
-	if (id->driver_info & BTUSB_BROKEN_ISOC)
+	if (info->flags & BTUSB_BROKEN_ISOC)
 		data->isoc = NULL;
 
-	if (id->driver_info & BTUSB_DIGIANSWER) {
+	if (info->flags & BTUSB_DIGIANSWER) {
 		data->cmdreq_type = USB_TYPE_VENDOR;
 		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 	}
 
-	if (id->driver_info & BTUSB_CSR) {
+	if (info->flags & BTUSB_CSR) {
 		struct usb_device *udev = data->udev;
 
 		/* Old firmware would otherwise execute USB reset */
@@ -1039,7 +1097,7 @@ static int btusb_probe(struct usb_interface *intf,
 			set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 	}
 
-	if (id->driver_info & BTUSB_SNIFFER) {
+	if (info->flags & BTUSB_SNIFFER) {
 		struct usb_device *udev = data->udev;
 
 		/* New sniffer firmware has crippled HCI interface */
@@ -1049,7 +1107,7 @@ static int btusb_probe(struct usb_interface *intf,
 		data->isoc = NULL;
 	}
 
-	if (id->driver_info & BTUSB_BCM92035) {
+	if (info->flags & BTUSB_BCM92035) {
 		unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 };
 		struct sk_buff *skb;
 
@@ -1079,8 +1137,9 @@ static int btusb_probe(struct usb_interface *intf,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(btusb_probe);
 
-static void btusb_disconnect(struct usb_interface *intf)
+void btusb_disconnect(struct usb_interface *intf)
 {
 	struct btusb_data *data = usb_get_intfdata(intf);
 	struct hci_dev *hdev;
@@ -1105,9 +1164,10 @@ static void btusb_disconnect(struct usb_interface *intf)
 
 	hci_free_dev(hdev);
 }
+EXPORT_SYMBOL_GPL(btusb_disconnect);
 
 #ifdef CONFIG_PM
-static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
+int btusb_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct btusb_data *data = usb_get_intfdata(intf);
 
@@ -1133,6 +1193,7 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(btusb_suspend);
 
 static void play_deferred(struct btusb_data *data)
 {
@@ -1149,7 +1210,7 @@ static void play_deferred(struct btusb_data *data)
 	usb_scuttle_anchored_urbs(&data->deferred);
 }
 
-static int btusb_resume(struct usb_interface *intf)
+int btusb_resume(struct usb_interface *intf)
 {
 	struct btusb_data *data = usb_get_intfdata(intf);
 	struct hci_dev *hdev = data->hdev;
@@ -1205,8 +1266,10 @@ done:
 
 	return err;
 }
+EXPORT_SYMBOL_GPL(btusb_resume);
 #endif
 
+
 static struct usb_driver btusb_driver = {
 	.name		= "btusb",
 	.probe		= btusb_probe,
diff --git a/drivers/bluetooth/btusb.h b/drivers/bluetooth/btusb.h
new file mode 100644
index 0000000..c26a845
--- /dev/null
+++ b/drivers/bluetooth/btusb.h
@@ -0,0 +1,53 @@
+/*
+ *
+ *  Generic Bluetooth USB driver
+ *
+ *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _BTUSB_H
+#define _BTUSB_H
+
+struct btusb_driver_info {
+	char	*description;
+	int	flags;
+#define BTUSB_GENERIC		0x00
+#define BTUSB_IGNORE		0x01
+#define BTUSB_DIGIANSWER	0x02
+#define BTUSB_CSR		0x04
+#define BTUSB_SNIFFER		0x08
+#define BTUSB_BCM92035		0x10
+#define BTUSB_BROKEN_ISOC	0x20
+#define BTUSB_WRONG_SCO_MTU	0x40
+#define BTUSB_ATH3012		0x80
+
+	/* entry point for vendor specific device initialization */
+	int	(*vsdev_init)(struct hci_dev *hdev);
+
+	/* event handler during vendor specific device initiation phase */
+	void	(*vsdev_event)(struct hci_dev *hdev, struct sk_buff *skb);
+};
+
+extern int btusb_probe(struct usb_interface *, const struct usb_device_id *);
+extern void btusb_disconnect(struct usb_interface *);
+#ifdef CONFIG_PM
+extern int btusb_suspend(struct usb_interface *, pm_message_t);
+extern int btusb_resume(struct usb_interface *);
+#endif
+
+#endif /* _BTUSB_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6a3337e..4af601d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -275,6 +275,16 @@ struct hci_dev {
 	int (*send)(struct sk_buff *skb);
 	void (*notify)(struct hci_dev *hdev, unsigned int evt);
 	int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
+
+	/*
+	 * TODO: Added following members for vendor specific initialization to
+	 * make the bluetooth.ko transparent to the interface.
+	 * These members are set by the vendor provided driver
+	 */
+	int			vsdev_init_done;
+	void			*vsdev_priv_data;
+	int (*vsdev_init)(struct hci_dev *hdev);
+	void (*vsdev_event)(struct hci_dev *hdev, struct sk_buff *skb);
 };
 
 struct hci_conn {
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e407051..80aa13f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -685,6 +685,15 @@ int hci_dev_open(__u16 dev)
 		set_bit(HCI_INIT, &hdev->flags);
 		hdev->init_last_cmd = 0;
 
+		/* vendor specific device initialization */
+		if (hdev->vsdev_init) {
+			ret = hdev->vsdev_init(hdev);
+			hdev->vsdev_init_done = 1;
+			hdev->vsdev_event = NULL;
+			if (ret < 0)
+				goto done;
+		}
+
 		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
 
 		if (lmp_host_le_capable(hdev))
@@ -2119,6 +2128,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 
 	return 0;
 }
+EXPORT_SYMBOL(hci_send_cmd);
 
 /* Get data from the previously sent command */
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
@@ -2800,7 +2810,10 @@ static void hci_rx_work(struct work_struct *work)
 		switch (bt_cb(skb)->pkt_type) {
 		case HCI_EVENT_PKT:
 			BT_DBG("%s Event packet", hdev->name);
-			hci_event_packet(hdev, skb);
+			if (hdev->vsdev_event && !hdev->vsdev_init_done)
+				hdev->vsdev_event(hdev, skb);
+			else
+				hci_event_packet(hdev, skb);
 			break;
 
 		case HCI_ACLDATA_PKT:
-- 
1.7.9.5

^ permalink raw reply related

* [RFC 0/2] Bluetooth: Add support for BT USB mini driver for vendeor specific init
From: Tedd Ho-Jeong An @ 2012-09-22  1:59 UTC (permalink / raw)
  To: linux-bluetooth, marcel; +Cc: johan.hedberg, albert.o.ho, tedd.hj.an

From: Tedd Ho-Jeong An <tedd.an@intel.com>

These RFC patches allow vendors to add their own BT USB mini driver to
configure the device before the BT stack sends common device
initialization.

Tedd Ho-Jeong An (2):
  Bluetooth: Add driver extension for vendor specific init
  Bluetooth: Add BT USB mini driver template

 drivers/bluetooth/Makefile         |    1 +
 drivers/bluetooth/btusb.c          |  194 ++++++++++++++++++++++++------------
 drivers/bluetooth/btusb.h          |   53 ++++++++++
 drivers/bluetooth/btusb_template.c |   78 +++++++++++++++
 include/net/bluetooth/hci_core.h   |   10 ++
 net/bluetooth/hci_core.c           |   15 ++-
 6 files changed, 286 insertions(+), 65 deletions(-)
 create mode 100644 drivers/bluetooth/btusb.h
 create mode 100644 drivers/bluetooth/btusb_template.c

-- 
1.7.9.5

^ permalink raw reply

* Re: pull request: bluetooth-next 2012-09-18
From: Luis R. Rodriguez @ 2012-09-22  1:06 UTC (permalink / raw)
  To: Gustavo Padovan, linville, linux-wireless, linux-bluetooth,
	linux-kernel
In-Reply-To: <20120919013113.GG24689@joana>

On Tue, Sep 18, 2012 at 6:31 PM, Gustavo Padovan <gustavo@padovan.org> wrote:

> Johan Hedberg (2):
>       Bluetooth: mgmt: Implement support for passkey notification

Too late now... but why did we allow this a stable fix? I get its a
feature that is important and likely overlooked / someone had a brain
fart, but from what I gather this is not on v3.5.4 and yet may make it
to v3.5.5. At least for backporting this was a bitch:

/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3290:52:
error: dereferencing pointer to incomplete type
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3294:6:
error: ‘struct hci_conn’ has no member named ‘passkey_notify’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3294:25:
error: dereferencing pointer to incomplete type
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3295:6:
error: ‘struct hci_conn’ has no member named ‘passkey_entered’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3298:3:
error: implicit declaration of function ‘mgmt_user_passkey_notify’
[-Werror=implicit-function-declaration]
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3299:27:
error: ‘struct hci_conn’ has no member named ‘passkey_notify’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3300:11:
error: ‘struct hci_conn’ has no member named ‘passkey_entered’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:
In function ‘hci_keypress_notify_evt’:
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3310:52:
error: dereferencing pointer to incomplete type
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3314:12:
error: dereferencing pointer to incomplete type
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3315:7:
error: ‘HCI_KEYPRESS_STARTED’ undeclared (first use in this function)
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3315:7:
note: each undeclared identifier is reported only once for each
function it appears in
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3316:7:
error: ‘struct hci_conn’ has no member named ‘passkey_entered’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3319:7:
error: ‘HCI_KEYPRESS_ENTERED’ undeclared (first use in this function)
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3320:7:
error: ‘struct hci_conn’ has no member named ‘passkey_entered’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3323:7:
error: ‘HCI_KEYPRESS_ERASED’ undeclared (first use in this function)
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3324:7:
error: ‘struct hci_conn’ has no member named ‘passkey_entered’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3327:7:
error: ‘HCI_KEYPRESS_CLEARED’ undeclared (first use in this function)
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3328:7:
error: ‘struct hci_conn’ has no member named ‘passkey_entered’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3331:7:
error: ‘HCI_KEYPRESS_COMPLETED’ undeclared (first use in this
function)
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3337:27:
error: ‘struct hci_conn’ has no member named ‘passkey_notify’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3338:11:
error: ‘struct hci_conn’ has no member named ‘passkey_entered’
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:
In function ‘hci_event_packet’:
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3701:7:
error: ‘HCI_EV_USER_PASSKEY_NOTIFY’ undeclared (first use in this
function)
/home/mcgrof/staging/v3.5.4/compat-wireless-3.5.3-2-snpc/net/bluetooth/hci_event.c:3705:7:
error: ‘HCI_EV_KEYPRESS_NOTIFY’ undeclared (first use in this
function)

I'd much prefer to see things like these identified as 'important' but
not 'fuck, this fixes that crash'. The fact that kernel maintainers
may be anal about these sorts of patches is *good* for many reasons
and figuring out a way to categorize, identify and allow users to reap
benefits of backporting suck fixes / cherry picking a full solution is
what something that should not interfere and hopefully be transparent
to Linux upstream development.

Here's one way I dealt with these type of patches:

https://backports.wiki.kernel.org/index.php/Documentation/compat-drivers/additional-patches

If you look at the patch 'Bluetooth: mgmt: Implement support for
passkey' its  a clear "feature" implementation, not a fucking fix.

  Luis

^ permalink raw reply

* Re: [PATCH v2] HID: Add support for Sony PS3 BD Remote Control
From: Bastien Nocera @ 2012-09-21 20:45 UTC (permalink / raw)
  To: Antonio Ospite
  Cc: David Dillow, linux-bluetooth, David Herrmann,
	Luiz Augusto von Dentz, linux-input, jkosina
In-Reply-To: <20120921220659.1e257048fed597061efb07f9@studenti.unina.it>

Em Fri, 2012-09-21 às 22:06 +0200, Antonio Ospite escreveu:
> From a user point of view there is still some "set up" happening,
> the gnome bluetooth-applet tells "Successfully set up new device '%
> s'", so maybe we can just call this "set up" in the comment above too,
> I
> mentioned the PIN because Gnome bluetooth does something about
> that[1],
> Bastien in gnome-bt case pin="NULL" means that there will be no
> pin request at all by the device, right?

Yep. That means we don't try to pair, we just connect to it. No
security, first come first serve.


^ permalink raw reply

* ATH3012 bluetooth not working in kernel-3.2.x
From: Giorgio Cardarelli @ 2012-09-21 20:45 UTC (permalink / raw)
  To: Marcel Holtmann, Gustavo F. Padovan, linux-bluetooth


[-- Attachment #1.1: Type: text/plain, Size: 1046 bytes --]

Hello,

I have an Atheros ATH3012 bluetooth chip not working under Ubuntu 12.04
(kernel 3.2.0-30, Ubuntu patched).

This is an excerpt from lsusb -v:

Bus 001 Device 004: ID 0489:e036 Foxconn / Hon Hai
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 224 Wireless
bDeviceSubClass 1 Radio Frequency
bDeviceProtocol 1 Bluetooth
bMaxPacketSize0 64
idVendor 0x0489 Foxconn / Hon Hai
idProduct 0xe036
bcdDevice 0.02
iManufacturer 1 Atheros Communications
iProduct 2 Bluetooth USB Host Controller
iSerial 3 Alaska Day 2006
bNumConfigurations 1

Basicly following what's explained here
http://wireless.kernel.org/en/users/Drivers/ath3k I've produced the patch
attached to this e-mail, which fixes the problem for my chip.

I've checked with vanilla kernel v3.2.30, and the patch applies for that
kernel too. Vanilla v3.5.4 is slightly different, but I think the problem
is still there.

I hope I've followed the right steps for submitting a bugfix.

HTH,
Giorgio

Signed-off-by: Giorgio Cardarelli <giorgio.cardarelli@gmail.com>

[-- Attachment #1.2: Type: text/html, Size: 1664 bytes --]

[-- Attachment #2: ATH3012.patch --]
[-- Type: application/octet-stream, Size: 1283 bytes --]

--- drivers/bluetooth/btusb.c.old	2012-09-21 21:29:32.463398623 +0200
+++ drivers/bluetooth/btusb.c	2012-09-21 21:32:44.239390604 +0200
@@ -141,6 +141,7 @@
 	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
--- drivers/bluetooth/ath3k.c.old	2012-09-21 21:29:21.643399077 +0200
+++ drivers/bluetooth/ath3k.c	2012-09-21 21:33:04.291389764 +0200
@@ -76,6 +76,7 @@
 	{ USB_DEVICE(0x04CA, 0x3005) },
 	{ USB_DEVICE(0x13d3, 0x3362) },
 	{ USB_DEVICE(0x0CF3, 0xE004) },
+	{ USB_DEVICE(0x0489, 0xE036) },
 
 	/* Atheros AR5BBU12 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xE02C) },
@@ -100,6 +101,7 @@
 	{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
 
 	/* Atheros AR5BBU22 with sflash firmware */
 	{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },

^ permalink raw reply

* Re: [PATCH v2] HID: Add support for Sony PS3 BD Remote Control
From: Antonio Ospite @ 2012-09-21 20:06 UTC (permalink / raw)
  To: David Dillow
  Cc: linux-bluetooth, David Herrmann, Luiz Augusto von Dentz,
	Bastien Nocera, linux-input, jkosina
In-Reply-To: <1348073986.10827.21.camel@frustration.ornl.gov>

On Wed, 19 Sep 2012 12:59:46 -0400
David Dillow <dave@thedillows.org> wrote:

> On Wed, 2012-09-19 at 18:48 +0200, Antonio Ospite wrote:
> > On Mon, 17 Sep 2012 21:33:58 -0400
> > David Dillow <dave@thedillows.org> wrote:
> 
> > While on the remote I see:
> > 
> > I press '1' and keep it pressed:
> > Event: time 1348069656.505528, type 1 (EV_KEY), code 2 (KEY_1), value 1
> > 1111111111...
> > 
> > I press '2' and release it ('1' is sent):
> > Event: time 1348069666.025543, type 1 (EV_KEY), code 2 (KEY_1), value 0
> > Event: time 1348069668.395531, type 1 (EV_KEY), code 2 (KEY_1), value 1
> > 1111111111...
> > 
> > I release '1':
> > Event: time 1348069671.625541, type 1 (EV_KEY), code 2 (KEY_1), value 0
> > 
> > I don't know at what level this behavior is enforced.
> > 
> > I will test later with the old raw_event callback and the fix to the
> > descriptor you suggested in the other mail.
> 
> Please capture the raw reports
> from /sys/kernel/debug/hid/0005:*:0306:*/events when pressing multiple
> keys -- and tell me which ones they were. You may need to mount debugfs
> to get to this path.
>

I used hidraw which is equivalent in this case.

$ sudo cat /dev/hidraw1 | hexdump -e '12/1 "%02X " "\n"'

I press and release 'Play'
01 00 00 00 32 FF FF FF FF FF 01 05
01 00 00 00 FF FF FF FF FF FF 00 05

I press and release 'Stop'
01 00 00 00 32 FF FF FF FF FF 01 05
01 00 00 00 FF FF FF FF FF FF 00 05

I press 'Play', keep it pressed and press 'Stop'
01 00 00 00 32 FF FF FF FF FF 01 05
01 00 00 00 FF FF FF FF FF FF 01 05
I release 'Stop' and then release 'Play'
01 00 00 00 32 FF FF FF FF FF 01 05
01 00 00 00 FF FF FF FF FF FF 00 05

So this combination cannot be detected at all, but:

I press and release 'Triangle'
01 00 10 00 5C FF FF FF FF FF 01 05
01 00 00 00 FF FF FF FF FF FF 00 05

I press and release 'Circle'
01 00 20 00 5D FF FF FF FF FF 01 05
01 00 00 00 FF FF FF FF FF FF 00 05

I press 'Triangle', keep it pressed and press 'Circle'
01 00 10 00 5C FF FF FF FF FF 01 05
01 00 30 00 FF FF FF FF FF FF 01 05
I release 'Circle' and then release 'Triangle'
01 00 10 00 5C FF FF FF FF FF 01 05
01 00 00 00 FF FF FF FF FF FF 00 05

So using the third byte (actually second, third and fourth right?) this
combination of multiple key presses can be detected, that happens to be
true for the "joypad buttons" which makes sense.

We can express the decoding of a bitfield in terms of HID descriptor,
right? Maybe copying from the Sixaxis report descriptor as the raw
report data for the first four bytes looks the same as the Sixaxis.
I'll try modifying the descriptor later.

David D. if you want you could send the version with the raw_event
callback first and get that merged and we can improve the descriptor
later, that would be fine to me.

BTW Some three keys combinations also produce a 03 in the one to last
byte: 01 00 00 00 FF FF FF FF FF FF 03 05
combinations like "Play+Stop+Next" do but some other do not and I could
not find a rule about that, so I don't know what the 03 really means.

> It looks like this simple approach isn't going to work when you press
> multiple keys, so I'll need more information to see if I can do
> something else -- my Harmony can only do one key press at a time, as it
> is converting IR to an emulated BD remote.
> 
> > > +config HID_PS3REMOTE
> > > +	tristate "Sony PS3 BD Remote"
> > 
> > If you are going for a v3, consider using "Sony PS3 BD Remote Control"
> > here too, not a big deal but that's the name on the user manual.
> 
> Will do, thanks.
> 
> > For the note about the association procedure I had in mind something
> > like this:
> > 
> > /* NOTE: in order to associate the Sony PS3 BD Remote with a Bluetooth host
> >  * the key combination Start+Enter has to be kept pressed for about 7 seconds,
> >  * with the host BT Controller in discovering mode.
> >  *
> >  * Also the pin request should be ignored by the BT Controller (NULL pin).
> >  */
> > 
> > Could someone more into BT please check the terminology here? Thanks.
> 
> Will add something along these lines, though I think you mean there is
> no authentication step rather than a NULL pin, which implies we still
> need to do auth. Or maybe that's just how the Harmony needed it...
>

>From a user point of view there is still some "set up" happening,
the gnome bluetooth-applet tells "Successfully set up new device '%
s'", so maybe we can just call this "set up" in the comment above too, I
mentioned the PIN because Gnome bluetooth does something about that[1],
Bastien in gnome-bt case pin="NULL" means that there will be no
pin request at all by the device, right?

Thanks,
   Antonio

[1]
http://git.gnome.org/browse/gnome-bluetooth/tree/wizard/pin-code-database.xml#n59

-- 
Antonio Ospite
http://ao2.it

A: Because it messes up the order in which people normally read text.
   See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?

^ permalink raw reply

* Re: bluetoothd: Refusing input device connect: Operation already in progress (114)
From: Johan Hedberg @ 2012-09-21 19:07 UTC (permalink / raw)
  To: Pacho Ramos; +Cc: linux-bluetooth
In-Reply-To: <1348254019.2085.2.camel@belkin4>

Hi Pacho,

On Fri, Sep 21, 2012, Pacho Ramos wrote:
> > > Searching, I found this thread that pointed to the culprit, but I
> > > haven't found what finally occurred with it, if patch was reverted or a
> > > different fix was pulled in:
> > > http://www.spinics.net/lists/linux-bluetooth/msg26442.html
> > 
> > This is a different issue but the cause seems to be similar. You don't
> > need to patch bluetoothd though but just disable the mgmt part by
> > passing -P mgmtops to bluetoothd. For whatever reason the connection
> > state isn't cleaned up with mgmt (which shouldn't be dependent on mgmt
> > to begin with) and the input_device_set_channel function returns
> > -EALREADY when accepting a connection.
> 
> But it sounds like a workaround as mgmt is still broken as compared with
> bluetoothd previous above change was committed, no? Thanks for the
> info :)

Yes, it's still a workaround and the real cause needs to be figured out
and fixed (either with more detailed logs or by the developers
reproducing this themselves).

Johan

^ permalink raw reply

* Re: bluetoothd: Refusing input device connect: Operation already in progress (114)
From: Pacho Ramos @ 2012-09-21 19:00 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <20120921124323.GA14885@x220>

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

El vie, 21-09-2012 a las 15:43 +0300, Johan Hedberg escribió:
> Hi,
> 
> On Sat, Sep 15, 2012, Pacho Ramos wrote:
> > Downstream we got the following report:
> > https://bugs.gentoo.org/show_bug.cgi?id=431624
> > 
> > After adding mouse (via Blueman's "Add device" dialog) it works fine
> > until sleeping or powering off. After that it fails reconnecting.
> > In /var/log/messages appears strings like these:
> > 
> > Aug 16 15:40:31 user bluetoothd[3222]: Refusing input device connect:
> > Operation already in progress (114)
> > Aug 16 15:45:13 user bluetoothd[3222]: Refusing input device connect:
> > Operation already in progress (114)
> > Aug 16 15:45:16 user bluetoothd[3222]: Refusing input device connect:
> > Operation already in progress (114)
> > Aug 16 15:45:17 user bluetoothd[3222]: Refusing input device connect:
> > Operation already in progress (114)
> > Aug 16 15:45:19 user bluetoothd[3222]: Refusing input device connect:
> > Operation already in progress (114)
> > Aug 16 15:47:46 user bluetoothd[3222]: Refusing input device connect:
> > Operation already in progress (114)
> > 
> > Searching, I found this thread that pointed to the culprit, but I
> > haven't found what finally occurred with it, if patch was reverted or a
> > different fix was pulled in:
> > http://www.spinics.net/lists/linux-bluetooth/msg26442.html
> 
> This is a different issue but the cause seems to be similar. You don't
> need to patch bluetoothd though but just disable the mgmt part by
> passing -P mgmtops to bluetoothd. For whatever reason the connection
> state isn't cleaned up with mgmt (which shouldn't be dependent on mgmt
> to begin with) and the input_device_set_channel function returns
> -EALREADY when accepting a connection.
> 
> Johan
> 

But it sounds like a workaround as mgmt is still broken as compared with
bluetoothd previous above change was committed, no? Thanks for the
info :)

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH] Cycling Speed and Cadence profile (CSCP) API
From: Anderson Lizardo @ 2012-09-21 15:51 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth
In-Reply-To: <1348218561-24509-2-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

On Fri, Sep 21, 2012 at 5:09 AM, Andrzej Kaczmarek
<andrzej.kaczmarek@tieto.com> wrote:
> +Cycling Speed and Cadence API description
> +****************************************
> +
> +Copyright (C) 2012     Tieto Poland
> +
> +Cycling Manager hierarchy
> +============================
> +
> +Service                org.bluez
> +Interface      org.bluez.CyclingManager

I don't have much to comment on the API as I haven't had time to read
the CSCP spec yet, but about the name prefix, what about
"CyclingSpeed" (and "RunningSpeed" for the future RSCP) ? Too long?

The "Cycling" name is slightly uncommon, but still not that bad IMHO.

> +Properties     String Location (optional) [readwrite]

String -> string

> +                               uint16 LastWheelEventTime (optional):
> +
> +                                       Value of Last Wheel Event time

Better specify that this is in "1/1024 second units" (just checked on
developer.bluetooth.org).

> +
> +                               uint16 CrankRevolutions (optional):
> +
> +                                       Cumulative number of crank revolutions
> +
> +                               uint16 LastCrankEventTime (optional):
> +
> +                                       Value of Last Crank Event time

Same here.

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* [PATCH v7 13/13] heartrate: Add test script
From: Andrzej Kaczmarek @ 2012-09-21 15:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348240570-7532-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

---
 Makefile.tools      |   4 +-
 test/test-heartrate | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 2 deletions(-)
 create mode 100755 test/test-heartrate

diff --git a/Makefile.tools b/Makefile.tools
index d3b6f57..f59a7c4 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -209,7 +209,7 @@ EXTRA_DIST += test/sap_client.py test/hsplay test/hsmicro \
 		test/test-network test/simple-agent test/simple-service \
 		test/simple-endpoint test/test-audio test/test-input \
 		test/test-sap-server test/test-oob test/test-attrib \
-		test/test-proximity test/test-thermometer test/test-health \
-		test/test-health-sink test/service-record.dtd \
+		test/test-proximity test/test-thermometer test/test-heartrate \
+		test/test-health test/test-health-sink test/service-record.dtd \
 		test/service-did.xml test/service-spp.xml test/service-opp.xml \
 		test/service-ftp.xml test/simple-player test/test-nap
diff --git a/test/test-heartrate b/test/test-heartrate
new file mode 100755
index 0000000..316375d
--- /dev/null
+++ b/test/test-heartrate
@@ -0,0 +1,103 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+'''
+Heart Rate Monitor test script
+'''
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+
+class Watcher(dbus.service.Object):
+	@dbus.service.method("org.bluez.HeartRateWatcher",
+					in_signature="oa{sv}", out_signature="")
+	def MeasurementReceived(self, device, measure):
+		print("Measurement received from %s" % device)
+		print("Value: ", measure["Value"])
+
+		if "Energy" in measure:
+			print("Energy: ", measure["Energy"])
+
+		if "Contact" in measure:
+			print("Contact: ", measure["Contact"])
+
+		if "Interval" in measure:
+			for i in measure["Interval"]:
+				print("Interval: ", i)
+
+if __name__ == "__main__":
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SystemBus()
+
+	manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+					"org.bluez.Manager")
+
+	option_list = [
+		make_option("-i", "--adapter", action="store",
+			type="string", dest="adapter"),
+		make_option("-b", "--device", action="store",
+			type="string", dest="address"),
+		]
+
+	parser = OptionParser(option_list=option_list)
+
+	(options, args) = parser.parse_args()
+
+	if not options.address:
+		print("Usage: %s [-i <adapter>] -b <bdaddr> [cmd]" % (sys.argv[0]))
+		print("Possible commands:")
+		print("\tReset")
+		sys.exit(1)
+
+	if options.adapter:
+		adapter_path = manager.FindAdapter(options.adapter)
+	else:
+		adapter_path = manager.DefaultAdapter()
+
+	adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+							"org.bluez.Adapter")
+
+	heartrateManager = dbus.Interface(bus.get_object("org.bluez",
+				adapter_path), "org.bluez.HeartRateManager")
+
+	path = "/test/watcher"
+	heartrateManager.RegisterWatcher(path)
+
+	device_path = adapter.FindDevice(options.address)
+
+	device = dbus.Interface(bus.get_object("org.bluez", device_path),
+							"org.bluez.Device")
+
+	heartrate = dbus.Interface(bus.get_object("org.bluez",
+					device_path), "org.bluez.HeartRate")
+
+	watcher = Watcher(bus, path)
+
+	properties = heartrate.GetProperties()
+
+	if "Location" in properties:
+		print("Sensor location: %s" % properties["Location"])
+	else:
+		print("Sensor location is not supported")
+
+	if len(args) > 0:
+		if args[0] == "Reset":
+			reset_sup = properties["ResetSupported"]
+			if reset_sup:
+				heartrate.Reset()
+			else:
+				print("Reset not supported")
+				sys.exit(1)
+		else:
+			print("unknown command")
+			sys.exit(1)
+
+	mainloop = gobject.MainLoop()
+	mainloop.run()
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v7 12/13] heartrate: Add HeartRateWatcher interface to default policy
From: Andrzej Kaczmarek @ 2012-09-21 15:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348240570-7532-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

---
 src/bluetooth.conf | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 664dbd9..77a9371 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -16,6 +16,7 @@
     <allow send_interface="org.bluez.MediaPlayer"/>
     <allow send_interface="org.bluez.Watcher"/>
     <allow send_interface="org.bluez.ThermometerWatcher"/>
+    <allow send_interface="org.bluez.HeartRateWatcher"/>
   </policy>
 
   <policy at_console="true">
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v7 11/13] heartrate: Add GetProperties method
From: Andrzej Kaczmarek @ 2012-09-21 15:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348240570-7532-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

---
 profiles/heartrate/heartrate.c | 61 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index add34b8..81dd5cc 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -94,6 +94,25 @@ struct measurement {
 
 static GSList *heartrate_adapters = NULL;
 
+static const char * const location_enum[] = {
+	"Other",
+	"Chest",
+	"Wrist",
+	"Finger",
+	"Hand",
+	"Earlobe",
+	"Foot",
+};
+
+static const gchar *location2str(uint8_t value)
+{
+	 if (value < G_N_ELEMENTS(location_enum))
+		return location_enum[value];
+
+	error("Body Sensor Location [%d] is RFU", value);
+	return NULL;
+}
+
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
 {
 	const struct heartrate_adapter *hradapter = a;
@@ -629,6 +648,45 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
 	{ }
 };
 
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate *hr = data;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *reply;
+	gboolean has_reset;
+
+	reply = dbus_message_new_method_return(msg);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	if (hr->has_location) {
+		char *loc = g_strdup(location2str(hr->location));
+
+		if (loc) {
+			dict_append_entry(&dict, "Location",
+						DBUS_TYPE_STRING, &loc);
+			g_free(loc);
+		}
+	}
+
+	has_reset = !!hr->hrcp_val_handle;
+	dict_append_entry(&dict, "ResetSupported", DBUS_TYPE_BOOLEAN,
+								&has_reset);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
 static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
@@ -653,6 +711,9 @@ static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg,
 }
 
 static const GDBusMethodTable heartrate_device_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+			get_properties) },
 	{ GDBUS_METHOD("Reset", NULL, NULL,
 			hrcp_reset) },
 	{ }
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v7 10/13] heartrate: Add support to reset Energy Expended
From: Andrzej Kaczmarek @ 2012-09-21 15:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348240570-7532-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds Reset method on HeartRate interface to reset Energy
Expended.
---
 profiles/heartrate/heartrate.c | 45 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index ba1c1fa..add34b8 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -41,6 +41,7 @@
 #include "log.h"
 #include "heartrate.h"
 
+#define HEART_RATE_INTERFACE		"org.bluez.HeartRate"
 #define HEART_RATE_MANAGER_INTERFACE	"org.bluez.HeartRateManager"
 #define HEART_RATE_WATCHER_INTERFACE	"org.bluez.HeartRateWatcher"
 
@@ -628,6 +629,35 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
 	{ }
 };
 
+static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate *hr = data;
+	uint8_t value;
+	char *vmsg;
+
+	if (!hr->hrcp_val_handle)
+		return btd_error_not_supported(msg);
+
+	if (!hr->attrib)
+		return btd_error_not_available(msg);
+
+	value = 0x01;
+	vmsg = g_strdup("Reset Control Point");
+	gatt_write_char(hr->attrib, hr->hrcp_val_handle, &value,
+					sizeof(value), char_write_cb, vmsg);
+
+	DBG("Energy Expended Value has been reset");
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_device_methods[] = {
+	{ GDBUS_METHOD("Reset", NULL, NULL,
+			hrcp_reset) },
+	{ }
+};
+
 int heartrate_adapter_register(struct btd_adapter *adapter)
 {
 	struct heartrate_adapter *hradapter;
@@ -685,6 +715,18 @@ int heartrate_device_register(struct btd_device *device,
 	hr->dev = btd_device_ref(device);
 	hr->hradapter = hradapter;
 
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+						device_get_path(device),
+						HEART_RATE_INTERFACE,
+						heartrate_device_methods,
+						NULL, NULL, hr,
+						destroy_heartrate)) {
+		error("D-Bus failed to register %s interface",
+						HEART_RATE_INTERFACE);
+		destroy_heartrate(hr);
+		return -EIO;
+	}
+
 	hr->svc_range = g_new0(struct att_range, 1);
 	hr->svc_range->start = prim->range.start;
 	hr->svc_range->end = prim->range.end;
@@ -718,5 +760,6 @@ void heartrate_device_unregister(struct btd_device *device)
 
 	hradapter->devices = g_slist_remove(hradapter->devices, hr);
 
-	destroy_heartrate(hr);
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+				device_get_path(device), HEART_RATE_INTERFACE);
 }
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v7 09/13] heartrate: Process measurement notifications
From: Andrzej Kaczmarek @ 2012-09-21 15:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348240570-7532-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds processing of received Heart Rate Measurement
characteristic notifications and sends processed data to registered
watchers.
---
 profiles/heartrate/heartrate.c | 167 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 166 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index dda030b..ba1c1fa 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -42,6 +42,13 @@
 #include "heartrate.h"
 
 #define HEART_RATE_MANAGER_INTERFACE	"org.bluez.HeartRateManager"
+#define HEART_RATE_WATCHER_INTERFACE	"org.bluez.HeartRateWatcher"
+
+#define HR_VALUE_FORMAT		0x01
+#define SENSOR_CONTACT_DETECTED	0x02
+#define SENSOR_CONTACT_SUPPORT	0x04
+#define ENERGY_EXP_STATUS	0x08
+#define RR_INTERVAL		0x10
 
 struct heartrate_adapter {
 	struct btd_adapter	*adapter;
@@ -54,6 +61,7 @@ struct heartrate {
 	struct heartrate_adapter	*hradapter;
 	GAttrib				*attrib;
 	guint				attioid;
+	guint				attionotid;
 
 	struct att_range		*svc_range;	/* primary svc range */
 
@@ -72,6 +80,17 @@ struct watcher {
 	char				*path;
 };
 
+struct measurement {
+	struct heartrate	*hr;
+	uint16_t		value;
+	gboolean		has_energy;
+	uint16_t		energy;
+	gboolean		has_contact;
+	gboolean		contact;
+	uint16_t		num_interval;
+	uint16_t		*interval;
+};
+
 static GSList *heartrate_adapters = NULL;
 
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -155,8 +174,10 @@ static void destroy_heartrate(gpointer user_data)
 	if (hr->attioid > 0)
 		btd_device_remove_attio_callback(hr->dev, hr->attioid);
 
-	if (hr->attrib != NULL)
+	if (hr->attrib != NULL) {
+		g_attrib_unregister(hr->attrib, hr->attionotid);
 		g_attrib_unref(hr->attrib);
+	}
 
 	btd_device_unref(hr->dev);
 	g_free(hr->svc_range);
@@ -357,6 +378,142 @@ static void disable_measurement(gpointer data, gpointer user_data)
 							char_write_cb, msg);
 }
 
+static void update_watcher(gpointer data, gpointer user_data)
+{
+	struct watcher *w = data;
+	struct measurement *m = user_data;
+	struct heartrate *hr = m->hr;
+	const gchar *path = device_get_path(hr->dev);
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(w->srv, w->path,
+			HEART_RATE_WATCHER_INTERFACE, "MeasurementReceived");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	dict_append_entry(&dict, "Value", DBUS_TYPE_UINT16, &m->value);
+
+	if (m->has_energy)
+		dict_append_entry(&dict, "Energy", DBUS_TYPE_UINT16,
+								&m->energy);
+
+	if (m->has_contact)
+		dict_append_entry(&dict, "Contact", DBUS_TYPE_BOOLEAN,
+								&m->contact);
+
+	if (m->num_interval > 0)
+		dict_append_array(&dict, "Interval", DBUS_TYPE_UINT16,
+						&m->interval, m->num_interval);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void process_measurement(struct heartrate *hr, const uint8_t *pdu,
+								uint16_t len)
+{
+	struct measurement m;
+	uint8_t flags;
+
+	flags = *pdu;
+
+	pdu++;
+	len--;
+
+	memset(&m, 0, sizeof(m));
+
+	if (flags & HR_VALUE_FORMAT) {
+		if (len < 2) {
+			error("Heart Rate Measurement field missing");
+			return;
+		}
+
+		m.value = att_get_u16(pdu);
+		pdu += 2;
+		len -= 2;
+	} else {
+		if (len < 1) {
+			error("Heart Rate Measurement field missing");
+			return;
+		}
+
+		m.value = *pdu;
+		pdu++;
+		len--;
+	}
+
+	if (flags & ENERGY_EXP_STATUS) {
+		if (len < 2) {
+			error("Energy Expended field missing");
+			return;
+		}
+
+		m.has_energy = TRUE;
+		m.energy = att_get_u16(pdu);
+		pdu += 2;
+		len -= 2;
+	}
+
+	if (flags & RR_INTERVAL) {
+		int i;
+
+		if (len == 0 || (len % 2 != 0)) {
+			error("RR-Interval field malformed");
+			return;
+		}
+
+		m.num_interval = len / 2;
+		m.interval = g_new(uint16_t, m.num_interval);
+
+		for (i = 0; i < m.num_interval; pdu += 2, i++)
+			m.interval[i] = att_get_u16(pdu);
+	}
+
+	if (flags & SENSOR_CONTACT_SUPPORT) {
+		m.has_contact = TRUE;
+		m.contact = !!(flags & SENSOR_CONTACT_DETECTED);
+	}
+
+	/* Notify all registered watchers */
+	m.hr = hr;
+	g_slist_foreach(hr->hradapter->watchers, update_watcher, &m);
+
+	g_free(m.interval);
+}
+
+static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	uint16_t handle;
+
+	/* should be at least opcode (1b) + handle (2b) */
+	if (len < 3) {
+		error("Invalid PDU received");
+		return;
+	}
+
+	handle = att_get_u16(pdu + 1);
+	if (handle != hr->measurement_val_handle) {
+		error("Unexpected handle: 0x%04x", handle);
+		return;
+	}
+
+	process_measurement(hr, pdu + 3, len - 3);
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -365,6 +522,9 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 
 	hr->attrib = g_attrib_ref(attrib);
 
+	hr->attionotid = g_attrib_register(hr->attrib, ATT_OP_HANDLE_NOTIFY,
+						notify_handler, hr, NULL);
+
 	gatt_discover_char(hr->attrib, hr->svc_range->start, hr->svc_range->end,
 						NULL, discover_char_cb, hr);
 }
@@ -375,6 +535,11 @@ static void attio_disconnected_cb(gpointer user_data)
 
 	DBG("");
 
+	if (hr->attionotid > 0) {
+		g_attrib_unregister(hr->attrib, hr->attionotid);
+		hr->attionotid = 0;
+	}
+
 	g_attrib_unref(hr->attrib);
 	hr->attrib = NULL;
 }
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v7 08/13] heartrate: Add support to enable notifications
From: Andrzej Kaczmarek @ 2012-09-21 15:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1348240570-7532-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds support to enable notifications for Heart Rate Measurement
characteristic value. Notifications are enabled automatically when at
least one watcher is registered and disabled otherwise.
---
 profiles/heartrate/heartrate.c | 67 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index b07a343..dda030b 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -207,6 +207,17 @@ static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
 	hr->location = value;
 }
 
+static void char_write_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	char *msg = user_data;
+
+	if (status != 0)
+		error("%s failed", msg);
+
+	g_free(msg);
+}
+
 static void discover_ccc_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -237,7 +248,20 @@ static void discover_ccc_cb(guint8 status, const guint8 *pdu,
 		uuid = att_get_u16(value + 2);
 
 		if (uuid == GATT_CLIENT_CHARAC_CFG_UUID) {
+			uint8_t value[2];
+			char *msg;
+
 			hr->measurement_ccc_handle = handle;
+
+			if (g_slist_length(hr->hradapter->watchers) == 0)
+				break;
+
+			att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+			msg = g_strdup("Enable measurement");
+
+			gatt_write_char(hr->attrib, handle, value,
+					sizeof(value), char_write_cb, msg);
+
 			break;
 		}
 	}
@@ -299,6 +323,40 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 	}
 }
 
+static void enable_measurement(gpointer data, gpointer user_data)
+{
+	struct heartrate *hr = data;
+	uint16_t handle = hr->measurement_ccc_handle;
+	uint8_t value[2];
+	char *msg;
+
+	if (hr->attrib == NULL || !handle)
+		return;
+
+	att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+	msg = g_strdup("Enable measurement");
+
+	gatt_write_char(hr->attrib, handle, value, sizeof(value),
+							char_write_cb, msg);
+}
+
+static void disable_measurement(gpointer data, gpointer user_data)
+{
+	struct heartrate *hr = data;
+	uint16_t handle = hr->measurement_ccc_handle;
+	uint8_t value[2];
+	char *msg;
+
+	if (hr->attrib == NULL || !handle)
+		return;
+
+	att_put_u16(0x0000, value);
+	msg = g_strdup("Disable measurement");
+
+	gatt_write_char(hr->attrib, handle, value, sizeof(value),
+							char_write_cb, msg);
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -330,6 +388,9 @@ static void watcher_exit_cb(DBusConnection *conn, void *user_data)
 
 	hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
 	g_dbus_remove_watch(conn, watcher->id);
+
+	if (g_slist_length(hradapter->watchers) == 0)
+		g_slist_foreach(hradapter->devices, disable_measurement, 0);
 }
 
 static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
@@ -355,6 +416,9 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
 	watcher->srv = g_strdup(sender);
 	watcher->path = g_strdup(path);
 
+	if (g_slist_length(hradapter->watchers) == 0)
+		g_slist_foreach(hradapter->devices, enable_measurement, 0);
+
 	hradapter->watchers = g_slist_prepend(hradapter->watchers, watcher);
 
 	DBG("heartrate watcher [%s] registered", path);
@@ -381,6 +445,9 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
 	hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
 	g_dbus_remove_watch(conn, watcher->id);
 
+	if (g_slist_length(hradapter->watchers) == 0)
+		g_slist_foreach(hradapter->devices, disable_measurement, 0);
+
 	DBG("heartrate watcher [%s] unregistered", path);
 
 	return dbus_message_new_method_return(msg);
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v7 07/13] heartrate: Add HeartRateManager interface
From: Andrzej Kaczmarek @ 2012-09-21 15:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348240570-7532-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds support for org.bluez.HeartRateManager interface on
adapters which allows to register and unregister per-adapter watcher.
---
 profiles/heartrate/heartrate.c | 154 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 2547f9b..b07a343 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -24,13 +24,16 @@
 #include <config.h>
 #endif
 
+#include <gdbus.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <glib.h>
 #include <bluetooth/uuid.h>
 
 #include "adapter.h"
+#include "dbus-common.h"
 #include "device.h"
+#include "error.h"
 #include "gattrib.h"
 #include "att.h"
 #include "gatt.h"
@@ -38,9 +41,12 @@
 #include "log.h"
 #include "heartrate.h"
 
+#define HEART_RATE_MANAGER_INTERFACE	"org.bluez.HeartRateManager"
+
 struct heartrate_adapter {
 	struct btd_adapter	*adapter;
 	GSList			*devices;
+	GSList			*watchers;
 };
 
 struct heartrate {
@@ -59,6 +65,13 @@ struct heartrate {
 	uint8_t				location;
 };
 
+struct watcher {
+	struct heartrate_adapter	*hradapter;
+	guint				id;
+	char				*srv;
+	char				*path;
+};
+
 static GSList *heartrate_adapters = NULL;
 
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -83,6 +96,19 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+	const struct watcher *watcher = a;
+	const struct watcher *match = b;
+	int ret;
+
+	ret = g_strcmp0(watcher->srv, match->srv);
+	if (ret != 0)
+		return ret;
+
+	return g_strcmp0(watcher->path, match->path);
+}
+
 static struct heartrate_adapter *
 find_heartrate_adapter(struct btd_adapter *adapter)
 {
@@ -94,6 +120,34 @@ find_heartrate_adapter(struct btd_adapter *adapter)
 	return l->data;
 }
 
+static void destroy_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_free(watcher->path);
+	g_free(watcher->srv);
+	g_free(watcher);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+							const char *path)
+{
+	struct watcher *match;
+	GSList *l;
+
+	match = g_new0(struct watcher, 1);
+	match->srv = g_strdup(sender);
+	match->path = g_strdup(path);
+
+	l = g_slist_find_custom(list, match, cmp_watcher);
+	destroy_watcher(match);
+
+	if (l != NULL)
+		return l->data;
+
+	return NULL;
+}
+
 static void destroy_heartrate(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -109,10 +163,19 @@ static void destroy_heartrate(gpointer user_data)
 	g_free(hr);
 }
 
+static void remove_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
+}
+
 static void destroy_heartrate_adapter(gpointer user_data)
 {
 	struct heartrate_adapter *hradapter = user_data;
 
+	g_slist_free_full(hradapter->watchers, remove_watcher);
+
 	g_free(hradapter);
 }
 
@@ -258,6 +321,81 @@ static void attio_disconnected_cb(gpointer user_data)
 	hr->attrib = NULL;
 }
 
+static void watcher_exit_cb(DBusConnection *conn, void *user_data)
+{
+	struct watcher *watcher = user_data;
+	struct heartrate_adapter *hradapter = watcher->hradapter;
+
+	DBG("heartrate watcher [%s] disconnected", watcher->path);
+
+	hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
+	g_dbus_remove_watch(conn, watcher->id);
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate_adapter *hradapter = data;
+	struct watcher *watcher;
+	const char *sender = dbus_message_get_sender(msg);
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(hradapter->watchers, sender, path);
+	if (watcher != NULL)
+		return btd_error_already_exists(msg);
+
+	watcher = g_new0(struct watcher, 1);
+	watcher->hradapter = hradapter;
+	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit_cb,
+						watcher, destroy_watcher);
+	watcher->srv = g_strdup(sender);
+	watcher->path = g_strdup(path);
+
+	hradapter->watchers = g_slist_prepend(hradapter->watchers, watcher);
+
+	DBG("heartrate watcher [%s] registered", path);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate_adapter *hradapter = data;
+	struct watcher *watcher;
+	const char *sender = dbus_message_get_sender(msg);
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(hradapter->watchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
+	g_dbus_remove_watch(conn, watcher->id);
+
+	DBG("heartrate watcher [%s] unregistered", path);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_manager_methods[] = {
+	{ GDBUS_METHOD("RegisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			register_watcher) },
+	{ GDBUS_METHOD("UnregisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			unregister_watcher) },
+	{ }
+};
+
 int heartrate_adapter_register(struct btd_adapter *adapter)
 {
 	struct heartrate_adapter *hradapter;
@@ -267,6 +405,18 @@ int heartrate_adapter_register(struct btd_adapter *adapter)
 
 	heartrate_adapters = g_slist_prepend(heartrate_adapters, hradapter);
 
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+						adapter_get_path(adapter),
+						HEART_RATE_MANAGER_INTERFACE,
+						heartrate_manager_methods,
+						NULL, NULL, hradapter,
+						destroy_heartrate_adapter)) {
+		error("D-Bus failed to register %s interface",
+						HEART_RATE_MANAGER_INTERFACE);
+		destroy_heartrate_adapter(hradapter);
+		return -EIO;
+	}
+
 	return 0;
 }
 
@@ -280,7 +430,9 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
 
 	heartrate_adapters = g_slist_remove(heartrate_adapters, hradapter);
 
-	destroy_heartrate_adapter(hradapter);
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+					adapter_get_path(hradapter->adapter),
+					HEART_RATE_MANAGER_INTERFACE);
 }
 
 int heartrate_device_register(struct btd_device *device,
-- 
1.7.11.3


^ permalink raw reply related

* [PATCH v7 06/13] heartrate: Read Body Sensor Location characteristics
From: Andrzej Kaczmarek @ 2012-09-21 15:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1348240570-7532-1-git-send-email-andrzej.kaczmarek@tieto.com>

From: Rafal Garbat <rafal.garbat@tieto.com>

This patch adds support to read and store Body Sensor Location
characteristic value.
---
 profiles/heartrate/heartrate.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index d3d6d43..2547f9b 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -54,6 +54,9 @@ struct heartrate {
 	uint16_t			measurement_val_handle;
 	uint16_t			measurement_ccc_handle;
 	uint16_t			hrcp_val_handle;
+
+	gboolean			has_location;
+	uint8_t				location;
 };
 
 static GSList *heartrate_adapters = NULL;
@@ -113,6 +116,34 @@ static void destroy_heartrate_adapter(gpointer user_data)
 	g_free(hradapter);
 }
 
+static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	uint8_t value;
+	ssize_t vlen;
+
+	if (status != 0) {
+		error("Body Sensor Location read failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, &value, sizeof(value));
+	if (vlen < 0) {
+		error("Protocol error");
+		return;
+	}
+
+	if (vlen != sizeof(value)) {
+		error("Invalid length for Body Sensor Location");
+		return;
+	}
+
+	hr->has_location = TRUE;
+	hr->location = value;
+}
+
 static void discover_ccc_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -194,7 +225,9 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 			discover_measurement_ccc(hr, c, c_next);
 		} else if (g_strcmp0(c->uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
 			DBG("Body Sensor Location supported");
-			/* TODO: read characterictic value */
+
+			gatt_read_char(hr->attrib, c->value_handle, 0,
+						read_sensor_location_cb, hr);
 		} else if (g_strcmp0(c->uuid,
 					HEART_RATE_CONTROL_POINT_UUID) == 0) {
 			DBG("Heart Rate Control Point supported");
-- 
1.7.11.3


^ permalink raw reply related


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