Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 03/10] battery: Add GATT Battery Client Service skeleton
From: chen.ganir @ 2012-09-11  7:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347349100-24228-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 |   61 ++++++++++++++++++++++++++++++
 profiles/battery/manager.h |   24 ++++++++++++
 7 files changed, 259 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 4977a05..af5d8a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -212,7 +212,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 \
@@ -241,7 +241,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..72878b2
--- /dev/null
+++ b/profiles/battery/manager.c
@@ -0,0 +1,61 @@
+/*
+ *
+ *  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 "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 04/10] battery: Add client connection logic
From: chen.ganir @ 2012-09-11  7:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347349100-24228-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 |   92 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 7702e39..37cbce4 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -30,17 +30,29 @@
 
 #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 +68,100 @@ 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->svc_range);
 	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 05/10] battery: Discover Characteristic Descriptors
From: chen.ganir @ 2012-09-11  7:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347349100-24228-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 37cbce4..3a24a7b 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -51,6 +51,13 @@ 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)
@@ -64,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);
@@ -82,7 +98,47 @@ static void battery_free(gpointer user_data)
 	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)
 {
 	struct battery *batt = user_data;
@@ -97,6 +153,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;
@@ -106,6 +163,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 06/10] battery: Get Battery ID
From: chen.ganir @ 2012-09-11  7:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347349100-24228-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 |  100 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 79 insertions(+), 22 deletions(-)

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 3a24a7b..d1e0b6e 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,55 @@ 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) {
+		error("Presentation Format desc read failed: Protocol error\n");
+		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 +182,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);
@@ -152,31 +204,35 @@ 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;
-		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);
-
-		start = c->value_handle + 1;
-
-		if (l->next != NULL) {
-			struct gatt_char *c = l->next->data;
-			if (start == c->handle)
+		if (g_strcmp0(c->uuid, BATTERY_LEVEL_UUID) == 0) {
+			struct characteristic *ch;
+			uint16_t start, end;
+
+			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);
+
+			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;
-			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);
+			gatt_find_info(batt->attrib, start, end,
+							discover_desc_cb, ch);
+		}
 	}
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 07/10] battery: Add Battery to device
From: chen.ganir @ 2012-09-11  7:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347349100-24228-1-git-send-email-chen.ganir@ti.com>

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

Add/Remove battery from device
---
 profiles/battery/battery.c |   14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index d1e0b6e..31f2297 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -49,8 +49,9 @@ struct battery {
 static GSList *servers;
 
 struct characteristic {
-	struct gatt_char	attr;	/* Characteristic */
-	struct battery		*batt;	/* Parent Battery Service */
+	struct device_battery  *devbatt;	/* device_battery pointer */
+	struct gatt_char	attr;		/* Characteristic */
+	struct battery		*batt;		/* Parent Battery Service */
 	GSList				*desc;	/* Descriptors */
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
@@ -79,6 +80,8 @@ static void char_free(gpointer user_data)
 
 	g_slist_free_full(c->desc, g_free);
 
+	btd_device_remove_battery(c->devbatt);
+
 	g_free(c);
 }
 
@@ -160,12 +163,12 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 	if (status != 0) {
 		error("Discover all characteristic descriptors failed [%s]: %s",
 					ch->attr.uuid, att_ecode2str(status));
-		return;
+		goto update_char;
 	}
 
 	list = dec_find_info_resp(pdu, len, &format);
 	if (list == NULL)
-		return;
+		goto update_char;
 
 	for (i = 0; i < list->num; i++) {
 		struct descriptor *desc;
@@ -186,6 +189,9 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 	}
 
 	att_data_list_free(list);
+
+update_char:
+	ch->devbatt = btd_device_add_battery(ch->batt->dev);
 }
 
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 08/10] battery: Read Battery level characteristic
From: chen.ganir @ 2012-09-11  7:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347349100-24228-1-git-send-email-chen.ganir@ti.com>

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

Implement support for reading the battery level characteristic on
connection establishment.
---
 profiles/battery/battery.c |   87 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 85 insertions(+), 2 deletions(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 31f2297..a93b352 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -55,6 +55,7 @@ struct characteristic {
 	GSList				*desc;	/* Descriptors */
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
+	uint8_t        level;
 };
 
 struct descriptor {
@@ -103,6 +104,80 @@ static void battery_free(gpointer user_data)
 	g_free(batt);
 }
 
+static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	uint8_t value[ATT_MAX_MTU];
+	int vlen;
+
+	if (status != 0) {
+		error("Failed to read Battery Level:%s", att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (!vlen) {
+		error("Failed to read Battery Level: Protocol error\n");
+		return;
+	}
+
+	if (vlen < 1) {
+		error("Failed to read Battery Level: Wrong pdu len");
+		return;
+	}
+
+	ch->level = value[0];
+	btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_LEVEL, ch->level,
+						BATTERY_OPT_INVALID);
+}
+
+static void process_batteryservice_char(struct characteristic *ch)
+{
+	if (g_strcmp0(ch->attr.uuid, BATTERY_LEVEL_UUID) == 0) {
+		gatt_read_char(ch->batt->attrib, ch->attr.value_handle, 0,
+						read_batterylevel_cb, ch);
+	}
+}
+
+static gint device_battery_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const struct device_battery *batt = b;
+
+	if (batt == ch->devbatt)
+		return 0;
+
+	return -1;
+}
+
+static struct characteristic *find_battery_char(struct device_battery *db)
+{
+	GSList *l, *b;
+
+	for (l = servers; l != NULL; l = g_slist_next(l)) {
+		struct battery *batt = l->data;
+
+		b = g_slist_find_custom(batt->chars, db, device_battery_cmp);
+		if (!b)
+			return NULL;
+
+		return b->data;
+	}
+
+	return NULL;
+}
+
+static void batterylevel_refresh_cb(struct device_battery *batt)
+{
+	struct characteristic *ch;
+
+	ch = find_battery_char(batt);
+
+	if (ch)
+		process_batteryservice_char(ch);
+}
+
 static void batterylevel_presentation_format_desc_cb(guint8 status,
 						const guint8 *pdu, guint16 len,
 						gpointer user_data)
@@ -151,7 +226,6 @@ static void process_batterylevel_desc(struct descriptor *desc)
 	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)
 {
@@ -192,8 +266,11 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
 
 update_char:
 	ch->devbatt = btd_device_add_battery(ch->batt->dev);
-}
+	btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_REFRESH_FUNC,
+			      batterylevel_refresh_cb, BATTERY_OPT_INVALID);
 
+	process_batteryservice_char(ch);
+}
 
 static void configure_battery_cb(GSList *characteristics, guint8 status,
 
@@ -252,6 +329,12 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 		gatt_discover_char(batt->attrib, batt->svc_range->start,
 					batt->svc_range->end, NULL,
 					configure_battery_cb, batt);
+	} else {
+		GSList *l;
+		for (l = batt->chars; l; l = l->next) {
+			struct characteristic *c = l->data;
+			process_batteryservice_char(c);
+		}
 	}
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 09/10] battery: Add support for notifications
From: chen.ganir @ 2012-09-11  7:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1347349100-24228-1-git-send-email-chen.ganir@ti.com>

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

Add support for emitting PropertyChanged when a battery level
characteristic notification is sent from the peer device.
---
 profiles/battery/battery.c |   95 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 2 deletions(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index a93b352..95f548e 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -43,6 +43,7 @@ struct battery {
 	GAttrib			*attrib;	/* GATT connection */
 	guint			attioid;	/* Att watcher id */
 	struct att_range	*svc_range;	/* Battery range */
+	guint                   attnotid;       /* Att notifications id */
 	GSList			*chars;		/* Characteristics */
 };
 
@@ -56,6 +57,7 @@ struct characteristic {
 	uint8_t			ns;		/* Battery Namespace */
 	uint16_t		description;	/* Battery description */
 	uint8_t        level;
+	gboolean		canNotify;
 };
 
 struct descriptor {
@@ -86,6 +88,14 @@ static void char_free(gpointer user_data)
 	g_free(c);
 }
 
+static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const uint16_t *handle = b;
+
+	return ch->attr.value_handle - *handle;
+}
+
 static void battery_free(gpointer user_data)
 {
 	struct battery *batt = user_data;
@@ -99,6 +109,10 @@ static void battery_free(gpointer user_data)
 	if (batt->attrib != NULL)
 		g_attrib_unref(batt->attrib);
 
+	if (batt->attrib != NULL) {
+		g_attrib_unregister(batt->attrib, batt->attnotid);
+		g_attrib_unref(batt->attrib);
+	}
 	btd_device_unref(batt->dev);
 	g_free(batt->svc_range);
 	g_free(batt);
@@ -140,6 +154,18 @@ static void process_batteryservice_char(struct characteristic *ch)
 	}
 }
 
+static void batterylevel_enable_notify_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct characteristic *ch = (struct characteristic *)user_data;
+
+	if (status != 0) {
+		error("Could not enable batt level notification.");
+		ch->canNotify = FALSE;
+		process_batteryservice_char(ch);
+	}
+}
+
 static gint device_battery_cmp(gconstpointer a, gconstpointer b)
 {
 	const struct characteristic *ch = a;
@@ -178,6 +204,19 @@ static void batterylevel_refresh_cb(struct device_battery *batt)
 		process_batteryservice_char(ch);
 }
 
+static void enable_battery_notification(struct characteristic *ch,
+								uint16_t handle)
+{
+	uint8_t atval[2];
+	uint16_t val;
+
+	val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+
+	att_put_u16(val, atval);
+	gatt_write_char(ch->batt->attrib, handle, atval, 2,
+				batterylevel_enable_notify_cb, ch);
+}
+
 static void batterylevel_presentation_format_desc_cb(guint8 status,
 						const guint8 *pdu, guint16 len,
 						gpointer user_data)
@@ -207,13 +246,20 @@ static void batterylevel_presentation_format_desc_cb(guint8 status,
 	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_CLIENT_CHARAC_CFG_UUID);
+
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
+						BATTERY_LEVEL_UUID) == 0) {
+		enable_battery_notification(ch, desc->handle);
+		return;
+	}
+
 	bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
 
 	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
@@ -319,12 +365,54 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
 	}
 }
 
+static void proc_batterylevel(struct characteristic *c, const uint8_t *pdu,
+						uint16_t len, gboolean final)
+{
+	if (!pdu) {
+		error("Battery level notification: Invalid pdu length");
+		return;
+	}
+
+	c->level = pdu[1];
+
+	btd_device_set_battery_opt(c->devbatt, BATTERY_OPT_LEVEL, c->level,
+							BATTERY_OPT_INVALID);
+}
+
+static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct battery *batt = user_data;
+	struct characteristic *ch;
+	uint16_t handle;
+	GSList *l;
+
+	if (len < 3) {
+		error("notif_handler: Bad pdu received");
+		return;
+	}
+
+	handle = att_get_u16(&pdu[1]);
+	l = g_slist_find_custom(batt->chars, &handle, cmp_char_val_handle);
+	if (l == NULL) {
+		error("notif_handler: Unexpected handle 0x%04x", handle);
+		return;
+	}
+
+	ch = l->data;
+	if (g_strcmp0(ch->attr.uuid, BATTERY_LEVEL_UUID) == 0) {
+		proc_batterylevel(ch, pdu, len, FALSE);
+	}
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct battery *batt = user_data;
 
 	batt->attrib = g_attrib_ref(attrib);
 
+	batt->attnotid = g_attrib_register(batt->attrib, ATT_OP_HANDLE_NOTIFY,
+						notif_handler, batt, NULL);
+
 	if (batt->chars == NULL) {
 		gatt_discover_char(batt->attrib, batt->svc_range->start,
 					batt->svc_range->end, NULL,
@@ -333,7 +421,8 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 		GSList *l;
 		for (l = batt->chars; l; l = l->next) {
 			struct characteristic *c = l->data;
-			process_batteryservice_char(c);
+			if (!c->canNotify)
+				process_batteryservice_char(c);
 		}
 	}
 }
@@ -342,6 +431,8 @@ static void attio_disconnected_cb(gpointer user_data)
 {
 	struct battery *batt = user_data;
 
+	g_attrib_unregister(batt->attrib, batt->attnotid);
+	batt->attnotid = 0;
 	g_attrib_unref(batt->attrib);
 	batt->attrib = NULL;
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 10/10] battery: Support persistent battery level
From: chen.ganir @ 2012-09-11  7:39 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir

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

Store battery level when read, and use the level from storage
when connecting, to reduce GATT traffic.
---
 profiles/battery/battery.c |  106 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 104 insertions(+), 2 deletions(-)

diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 95f548e..bae9487 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -27,6 +27,8 @@
 #include <glib.h>
 #include <bluetooth/uuid.h>
 #include <stdbool.h>
+#include <sys/file.h>
+#include <stdlib.h>
 
 #include "adapter.h"
 #include "device.h"
@@ -37,6 +39,10 @@
 #include "gatt.h"
 #include "battery.h"
 #include "log.h"
+#include "storage.h"
+
+#define BATTERY_KEY_FORMAT	"%17s#%04X"
+#define BATTERY_LEVEL_FORMAT	"%03d"
 
 struct battery {
 	struct btd_device	*dev;		/* Device reference */
@@ -77,10 +83,103 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static inline int create_filename(char *buf, size_t size,
+				const bdaddr_t *bdaddr, const char *name)
+{
+	char addr[18];
+
+	ba2str(bdaddr, addr);
+
+	return create_name(buf, size, STORAGEDIR, addr, name);
+}
+
+static int store_battery_char(struct characteristic *chr)
+{
+	char filename[PATH_MAX + 1], addr[18], key[23];
+	bdaddr_t sba, dba;
+	char level[4];
+
+	adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+	device_get_address(chr->batt->dev, &dba, NULL);
+
+	create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+	ba2str(&dba, addr);
+
+	snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+	snprintf(level, sizeof(level), BATTERY_LEVEL_FORMAT, chr->level);
+
+	return textfile_caseput(filename, key, level);
+}
+
+static char *read_battery_char(struct characteristic *chr)
+{
+	char filename[PATH_MAX + 1], addr[18], key[23];
+	char *str, *strnew;
+	bdaddr_t sba, dba;
+
+	adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+	device_get_address(chr->batt->dev, &dba, NULL);
+
+	create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+	ba2str(&dba, addr);
+	snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+
+	str = textfile_caseget(filename, key);
+	if (str == NULL)
+		return NULL;
+
+	strnew = g_strdup(str);
+	g_free(str);
+
+	return strnew;
+}
+
+static void del_battery_char(struct characteristic *chr)
+{
+	char filename[PATH_MAX + 1], addr[18], key[23];
+	bdaddr_t sba, dba;
+
+	adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+	device_get_address(chr->batt->dev, &dba, NULL);
+
+	create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+	ba2str(&dba, addr);
+	snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+
+	textfile_casedel(filename, key);
+}
+
+static gboolean read_battery_level_value(struct characteristic *chr)
+{
+	char *str;
+
+	if (!chr)
+		return FALSE;
+
+	str = read_battery_char(chr);
+	if (!str)
+		return FALSE;
+
+	chr->level = atoi(str);
+
+	btd_device_set_battery_opt(chr->devbatt, BATTERY_OPT_LEVEL, chr->level,
+						BATTERY_OPT_INVALID);
+
+	g_free(str);
+	return TRUE;
+}
+
 static void char_free(gpointer user_data)
 {
 	struct characteristic *c = user_data;
 
+	del_battery_char(c);
+
 	g_slist_free_full(c->desc, g_free);
 
 	btd_device_remove_battery(c->devbatt);
@@ -144,6 +243,8 @@ static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
 	ch->level = value[0];
 	btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_LEVEL, ch->level,
 						BATTERY_OPT_INVALID);
+
+	store_battery_char(ch);
 }
 
 static void process_batteryservice_char(struct characteristic *ch)
@@ -315,7 +416,8 @@ update_char:
 	btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_REFRESH_FUNC,
 			      batterylevel_refresh_cb, BATTERY_OPT_INVALID);
 
-	process_batteryservice_char(ch);
+	if (!read_battery_level_value(ch))
+		process_batteryservice_char(ch);
 }
 
 static void configure_battery_cb(GSList *characteristics, guint8 status,
@@ -421,7 +523,7 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 		GSList *l;
 		for (l = batt->chars; l; l = l->next) {
 			struct characteristic *c = l->data;
-			if (!c->canNotify)
+			if (!read_battery_level_value(c) && !c->canNotify)
 				process_batteryservice_char(c);
 		}
 	}
-- 
1.7.9.5


^ permalink raw reply related

* Re: [RFCv1 01/15] Bluetooth: Set Exended Flowspec flag for HS chan
From: Andrei Emeltchenko @ 2012-09-11  8:15 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth
In-Reply-To: <alpine.DEB.2.02.1209101647520.2859@mathewm-linux>

Hi Mat,

On Mon, Sep 10, 2012 at 04:49:36PM -0700, Mat Martineau wrote:
> 
> Andrei -
> 
> On Tue, 4 Sep 2012, Andrei Emeltchenko wrote:
> 
> >From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >
> >For AMP we always assume EFS L2CAP option.
> >
> >Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >---
> >include/net/bluetooth/l2cap.h |    2 ++
> >net/bluetooth/l2cap_core.c    |    7 ++++++-
> >2 files changed, 8 insertions(+), 1 deletion(-)
> >
> >diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> >index 161be83..3ec8679 100644
> >--- a/include/net/bluetooth/l2cap.h
> >+++ b/include/net/bluetooth/l2cap.h
> >@@ -508,6 +508,8 @@ struct l2cap_chan {
> >	__u32		remote_acc_lat;
> >	__u32		remote_flush_to;
> >
> >+	__u8		ctrl_id;
> >+
> 
> How about "remote_amp_id" instead of ctrl_id?  The channel move code
> tracks local_amp_id.  
> Why does the remote controller id need to be
> tracked?

I think you are right, I think it shall be local AMP controller id. So we
can keep this name ctrl_id for local one or do you think local_amp_id is
better?

Best regards 
Andrei Emeltchenko 


^ permalink raw reply

* Re: [PATCH] avctp: Fix reply for message with invalid PID
From: Luiz Augusto von Dentz @ 2012-09-11  8:22 UTC (permalink / raw)
  To: Par-Gunnar Hjalmdahl; +Cc: linux-bluetooth, Anurag Gupta
In-Reply-To: <1347344186-8517-1-git-send-email-par-gunnar.hjalmdahl@stericsson.com>

Hi,

On Tue, Sep 11, 2012 at 9:16 AM, Par-Gunnar Hjalmdahl
<par-gunnar.hjalmdahl@stericsson.com> wrote:
> Reply for control message with invalid (not registered for reception
> of messages) PID should not have message information field present.
>
> This was affecting AVCTP qualification test case TP/NFR/BI-01-C.
> ---
>  audio/avctp.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/audio/avctp.c b/audio/avctp.c
> index 03f3e7f..4e0e8dc 100644
> --- a/audio/avctp.c
> +++ b/audio/avctp.c
> @@ -500,7 +500,7 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
>
>         if (avctp->pid != htons(AV_REMOTE_SVCLASS_ID)) {
>                 avctp->ipid = 1;
> -               avc->code = AVC_CTYPE_REJECTED;
> +               packet_size = AVCTP_HEADER_LENGTH;
>                 goto done;
>         }
>
> --
> 1.7.11.3

Pushed, thanks.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH v2] gatt: Delay D-Bus reply on char discovery
From: chen.ganir @ 2012-09-11  8:47 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: chen.ganir

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

Delay sending the D-Bus reply for the discover_characteristics
command. The D-Bus reply for characteristics is sent before all
the relevant characteristic information is gathered. This can
cause problems, when trying to get characteristic information too
soon. This patch moves the D-Bus reply to the end of the char
discovery process. Only after all descriptors are discovered and
read, the D-Bus reply is sent.
---
 attrib/client.c |  138 +++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 93 insertions(+), 45 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index d5d40a1..7ee99e5 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -79,6 +79,11 @@ struct gatt_service {
 	struct query *query;
 };
 
+struct characteristic_descriptor {
+	uint16_t handle;
+	bt_uuid_t uuid;
+};
+
 struct characteristic {
 	struct gatt_service *gatt;
 	char *path;
@@ -91,6 +96,8 @@ struct characteristic {
 	struct format *format;
 	uint8_t *value;
 	size_t vlen;
+
+	GSList *descriptors;
 };
 
 struct query_data {
@@ -185,6 +192,7 @@ static void characteristic_free(void *user_data)
 	g_free(chr->format);
 	g_free(chr->value);
 	g_free(chr->name);
+	g_slist_free_full(chr->descriptors, g_free);
 	g_free(chr);
 }
 
@@ -333,6 +341,58 @@ static void update_watchers(gpointer data, gpointer user_data)
 	g_dbus_send_message(conn, msg);
 }
 
+static DBusMessage *create_discover_char_reply(DBusMessage *msg, GSList *chars)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter, array_iter;
+	GSList *l;
+
+	reply = dbus_message_new_method_return(msg);
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+				DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
+
+	for (l = chars; l; l = l->next) {
+		struct characteristic *chr = l->data;
+
+		dbus_message_iter_append_basic(&array_iter,
+					DBUS_TYPE_OBJECT_PATH, &chr->path);
+	}
+
+	dbus_message_iter_close_container(&iter, &array_iter);
+
+	return reply;
+}
+
+
+static void send_chr_discovery_complete(struct gatt_service *gatt)
+{
+	DBusMessage *reply;
+
+	reply = create_discover_char_reply(gatt->query->msg, gatt->chars);
+
+	dbus_message_unref(gatt->query->msg);
+	gatt->query->msg = NULL;
+
+	g_dbus_send_message(gatt->conn, reply);
+}
+
+static void add_descriptor(struct gatt_service *gatt,
+			      struct characteristic *chr, uint16_t handle,
+			      bt_uuid_t uuid)
+{
+	struct characteristic_descriptor *desc;
+
+	desc = g_new0(struct characteristic_descriptor, 1);
+
+	desc->handle = handle;
+	desc->uuid = uuid;
+
+	chr->descriptors = g_slist_append(chr->descriptors, desc);
+}
+
 static void events_handler(const uint8_t *pdu, uint16_t len,
 							gpointer user_data)
 {
@@ -748,6 +808,7 @@ static void query_list_remove(struct gatt_service *gatt, struct query_data *data
 	if (query->list != NULL)
 		return;
 
+	send_chr_discovery_complete(gatt);
 	g_free(query);
 	gatt->query = NULL;
 
@@ -760,6 +821,7 @@ static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
 	struct query_data *current = user_data;
 	struct gatt_service *gatt = current->gatt;
 	struct characteristic *chr = current->chr;
+	bt_uuid_t uuid;
 
 	if (status == 0) {
 
@@ -790,6 +852,9 @@ static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
 		}
 	}
 
+	bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
+	add_descriptor(current->gatt, chr, current->handle, uuid);
+
 	query_list_remove(gatt, current);
 	g_free(current);
 }
@@ -800,6 +865,7 @@ static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
 	struct query_data *current = user_data;
 	struct gatt_service *gatt = current->gatt;
 	struct characteristic *chr = current->chr;
+	bt_uuid_t uuid;
 
 	if (status != 0)
 		goto done;
@@ -816,6 +882,9 @@ static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
 				(void *) chr->format, sizeof(*chr->format));
 
 done:
+	bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
+	add_descriptor(current->gatt, chr, current->handle, uuid);
+
 	query_list_remove(gatt, current);
 	g_free(current);
 }
@@ -859,6 +928,7 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
 {
 	struct query_data *current = user_data;
 	struct gatt_service *gatt = current->gatt;
+	struct characteristic *chr = current->chr;
 	struct att_data_list *list;
 	guint8 format;
 	int i;
@@ -877,6 +947,7 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
 		bt_uuid_t uuid;
 		uint8_t *info = list->data[i];
 		struct query_data *qfmt;
+		guint ret = 0;
 
 		handle = att_get_u16(info);
 
@@ -887,6 +958,7 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
 			 * format" descriptors are used, and both have 16-bit
 			 * UUIDs. Therefore there is no need to support format
 			 * 0x02 yet. */
+			add_descriptor(gatt, chr, current->handle, uuid);
 			continue;
 		}
 		qfmt = g_new0(struct query_data, 1);
@@ -896,14 +968,17 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
 
 		if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) {
 			query_list_append(gatt, qfmt);
-			gatt_read_char(gatt->attrib, handle, 0, update_char_desc,
-									qfmt);
+			ret = gatt_read_char(gatt->attrib, handle, 0,
+							update_char_desc, qfmt);
 		} else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) {
 			query_list_append(gatt, qfmt);
-			gatt_read_char(gatt->attrib, handle, 0,
+			ret = gatt_read_char(gatt->attrib, handle, 0,
 						update_char_format, qfmt);
 		} else
 			g_free(qfmt);
+
+		if (ret == 0)
+			add_descriptor(gatt, chr, current->handle, uuid);
 	}
 
 	att_data_list_free(list);
@@ -918,53 +993,30 @@ static void update_all_chars(gpointer data, gpointer user_data)
 	struct characteristic *chr = data;
 	struct gatt_service *gatt = user_data;
 
-	qdesc = g_new0(struct query_data, 1);
-	qdesc->gatt = gatt;
-	qdesc->chr = chr;
-
-	query_list_append(gatt, qdesc);
-
-	gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
-									qdesc);
-
 	qvalue = g_new0(struct query_data, 1);
 	qvalue->gatt = gatt;
 	qvalue->chr = chr;
 
+	g_slist_free_full(chr->descriptors, g_free);
+	chr->descriptors = NULL;
+
 	query_list_append(gatt, qvalue);
 
 	gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, qvalue);
-}
-
-static DBusMessage *create_discover_char_reply(DBusMessage *msg, GSList *chars)
-{
-	DBusMessage *reply;
-	DBusMessageIter iter, array_iter;
-	GSList *l;
-
-	reply = dbus_message_new_method_return(msg);
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-				DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
-
-	for (l = chars; l; l = l->next) {
-		struct characteristic *chr = l->data;
 
-		dbus_message_iter_append_basic(&array_iter,
-					DBUS_TYPE_OBJECT_PATH, &chr->path);
-	}
+	qdesc = g_new0(struct query_data, 1);
+	qdesc->gatt = gatt;
+	qdesc->chr = chr;
 
-	dbus_message_iter_close_container(&iter, &array_iter);
+	query_list_append(gatt, qdesc);
 
-	return reply;
+	gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
+									qdesc);
 }
 
 static void char_discovered_cb(GSList *characteristics, guint8 status,
 							gpointer user_data)
 {
-	DBusMessage *reply;
 	struct query_data *current = user_data;
 	struct gatt_service *gatt = current->gatt;
 	struct gatt_primary *prim = gatt->prim;
@@ -975,10 +1027,13 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
 
 	if (status != 0) {
 		const char *str = att_ecode2str(status);
+		DBusMessage *reply = btd_error_failed(gatt->query->msg, str);
 
 		DBG("Discover all characteristics failed: %s", str);
-		reply = btd_error_failed(gatt->query->msg, str);
-		goto fail;
+		dbus_message_unref(gatt->query->msg);
+		g_dbus_send_message(gatt->conn, reply);
+
+		goto done;
 	}
 
 	for (l = characteristics; l; l = l->next) {
@@ -1013,16 +1068,9 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
 	gatt_get_address(gatt, &sba, &dba, &bdaddr_type);
 	store_characteristics(&sba, &dba, bdaddr_type, prim->range.start,
 								gatt->chars);
-
 	g_slist_foreach(gatt->chars, update_all_chars, gatt);
 
-	reply = create_discover_char_reply(gatt->query->msg, gatt->chars);
-
-fail:
-	dbus_message_unref(gatt->query->msg);
-	gatt->query->msg = NULL;
-
-	g_dbus_send_message(gatt->conn, reply);
+done:
 	query_list_remove(gatt, current);
 	g_free(current);
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH] Bluetooth: Add support for BCM20702A0 [04ca, 2003]
From: acho @ 2012-09-11  9:25 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg, linux-bluetooth
  Cc: linux-kernel, oneukum, acho, jlee, resler

From: Jaroslav Resler <resler@cs.cas.cz>

Add another vendor specific ID for BCM20702A0.

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

Signed-off-by: Cho, Yu-Chen <acho@suse.com>
---
 drivers/bluetooth/btusb.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index fbfb069..5f74ad9 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = {
 	{ USB_DEVICE(0x0c10, 0x0000) },
 
 	/* Broadcom BCM20702A0 */
+	{ USB_DEVICE(0x04ca, 0x2003) }
 	{ USB_DEVICE(0x0489, 0xe042) },
 	{ USB_DEVICE(0x413c, 0x8197) },
 
-- 
1.7.7

^ permalink raw reply related

* Re: [PATCH v2] gatt: Delay D-Bus reply on char discovery
From: Anderson Lizardo @ 2012-09-11 11:44 UTC (permalink / raw)
  To: chen.ganir; +Cc: linux-bluetooth
In-Reply-To: <1347353240-1942-1-git-send-email-chen.ganir@ti.com>

Hi Chen,

On Tue, Sep 11, 2012 at 4:47 AM,  <chen.ganir@ti.com> wrote:
> From: Chen Ganir <chen.ganir@ti.com>
>
> Delay sending the D-Bus reply for the discover_characteristics
> command. The D-Bus reply for characteristics is sent before all
> the relevant characteristic information is gathered. This can
> cause problems, when trying to get characteristic information too
> soon. This patch moves the D-Bus reply to the end of the char
> discovery process. Only after all descriptors are discovered and
> read, the D-Bus reply is sent.
> ---

I see you populate chr->descriptors, but I can't find where the list
is actually used. Do you plan to use this information in some other
patch?

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

^ permalink raw reply

* Re: [PATCH v2] gatt: Delay D-Bus reply on char discovery
From: Chen Ganir @ 2012-09-11 12:22 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <CAJdJm_OZZ+SrYdfbpqy+yFmppx9xAs-YMmDtn3PzQbU1JD_pOA@mail.gmail.com>

Anderson,

On 09/11/2012 02:44 PM, Anderson Lizardo wrote:
> Hi Chen,
>
> On Tue, Sep 11, 2012 at 4:47 AM,  <chen.ganir@ti.com> wrote:
>> From: Chen Ganir <chen.ganir@ti.com>
>>
>> Delay sending the D-Bus reply for the discover_characteristics
>> command. The D-Bus reply for characteristics is sent before all
>> the relevant characteristic information is gathered. This can
>> cause problems, when trying to get characteristic information too
>> soon. This patch moves the D-Bus reply to the end of the char
>> discovery process. Only after all descriptors are discovered and
>> read, the D-Bus reply is sent.
>> ---
>
> I see you populate chr->descriptors, but I can't find where the list
> is actually used. Do you plan to use this information in some other
> patch?
>
> Regards,
>

The plan is to replace characteristic::format, and add CCC, SCC and any 
other descriptor we find in the future to this list. This way we have a 
unified list of descriptors and the data contained in them. This is 
already done in some patches i already have, which rely on this patch. 
Next patch set includes notification/indication implementation to the 
D-Bus API (Auto registration to notification/indication if CCC is found).

-- 
BR,
Chen Ganir


^ permalink raw reply

* Re: [PATCH v2] gatt: Delay D-Bus reply on char discovery
From: Anderson Lizardo @ 2012-09-11 12:27 UTC (permalink / raw)
  To: Chen Ganir; +Cc: linux-bluetooth
In-Reply-To: <504F2CF9.7060900@ti.com>

Hi Chen,

On Tue, Sep 11, 2012 at 8:22 AM, Chen Ganir <chen.ganir@ti.com> wrote:
> The plan is to replace characteristic::format, and add CCC, SCC and any
> other descriptor we find in the future to this list. This way we have a
> unified list of descriptors and the data contained in them. This is already
> done in some patches i already have, which rely on this patch. Next patch
> set includes notification/indication implementation to the D-Bus API (Auto
> registration to notification/indication if CCC is found).

Do you have patches ready for adding CCC support on GATT D-Bus API ?
Are you planning to send soon to the list, or could send it as RFC?

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

^ permalink raw reply

* Re: [PATCH v2] gatt: Delay D-Bus reply on char discovery
From: Chen Ganir @ 2012-09-11 12:36 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <CAJdJm_OMtRy08-55cxrWH-0WM06r0M8JAH8wHw0a8S11k2hO+Q@mail.gmail.com>

Anderson,
On 09/11/2012 03:27 PM, Anderson Lizardo wrote:
> Hi Chen,
>
> On Tue, Sep 11, 2012 at 8:22 AM, Chen Ganir <chen.ganir@ti.com> wrote:
>> The plan is to replace characteristic::format, and add CCC, SCC and any
>> other descriptor we find in the future to this list. This way we have a
>> unified list of descriptors and the data contained in them. This is already
>> done in some patches i already have, which rely on this patch. Next patch
>> set includes notification/indication implementation to the D-Bus API (Auto
>> registration to notification/indication if CCC is found).
>
> Do you have patches ready for adding CCC support on GATT D-Bus API ?
> Are you planning to send soon to the list, or could send it as RFC?
>
> Best Regards,
>
I already have those patches running. Some cleanup is still needed, and 
this patch also needs to be upstreamed.

Basically what i did was discover the CCC, SCC and extended properties. 
I save them (current value and handle) in the descriptor list. Once the 
entire characteristic range is discovered, and a watcher is registered, 
i check the characteristic properties and cross it with the availability 
of the CCC. Then, i try to automatically enable indication or 
notification according to the characteristic properties.

when the watcher is abandoned or unregistered, i unset the 
notification/indication for all the characters of that service.

In addition, i plan to add a property called "Broadcast" which will be 
read/write, and it will set/get the SCC descriptor of the char.



-- 
BR,
Chen Ganir


^ permalink raw reply

* [PATCH BlueZ v6 01/11] core: Control connections based on adapter state
From: João Paulo Rechi Vita @ 2012-09-11 13:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch disable automatic ATTIO connections when the adapter is
powered down and enable automatic connection when the adapter is powered
on.
---
 src/adapter.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 4b675e8..6b8435e 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2113,6 +2113,14 @@ static int get_pairable_timeout(const char *src)
 	return main_opts.pairto;
 }
 
+static void set_auto_connect(gpointer data, gpointer user_data)
+{
+	struct btd_device *device = data;
+	gboolean *enable = user_data;
+
+	device_set_auto_connect(device, *enable);
+}
+
 static void call_adapter_powered_callbacks(struct btd_adapter *adapter,
 						gboolean powered)
 {
@@ -2122,7 +2130,9 @@ static void call_adapter_powered_callbacks(struct btd_adapter *adapter,
 		btd_adapter_powered_cb cb = l->data;
 
 		cb(adapter, powered);
-       }
+	}
+
+	g_slist_foreach(adapter->devices, set_auto_connect, &powered);
 }
 
 static void emit_device_disappeared(gpointer data, gpointer user_data)
@@ -3401,15 +3411,10 @@ static gboolean disable_auto(gpointer user_data)
 	return FALSE;
 }
 
-static void set_auto_connect(gpointer data, gpointer user_data)
-{
-	struct btd_device *device = data;
-
-	device_set_auto_connect(device, TRUE);
-}
-
 void btd_adapter_enable_auto_connect(struct btd_adapter *adapter)
 {
+	gboolean enable = TRUE;
+
 	if (!adapter->up)
 		return;
 
@@ -3418,7 +3423,7 @@ void btd_adapter_enable_auto_connect(struct btd_adapter *adapter)
 	if (adapter->auto_timeout_id)
 		return;
 
-	g_slist_foreach(adapter->devices, set_auto_connect, NULL);
+	g_slist_foreach(adapter->devices, set_auto_connect, &enable);
 
 	adapter->auto_timeout_id = g_timeout_add_seconds(main_opts.autoto,
 						disable_auto, adapter);
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v6 02/11] core: Use adapter connect list for LE connections
From: João Paulo Rechi Vita @ 2012-09-11 13:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1347370387-17670-1-git-send-email-jprvita@openbossa.org>

When a connection is needed for a LE device it is added to the adapter
connect list instead of directly connecting the ATT io channel.
---
 src/adapter.c |  2 +-
 src/device.c  | 45 +++++++++++----------------------------------
 src/device.h  |  1 +
 3 files changed, 13 insertions(+), 35 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 6b8435e..e3994a8 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2915,7 +2915,7 @@ static gboolean connect_pending_cb(gpointer user_data)
 	if (adapter->discovering)
 		return TRUE;
 
-	/* TODO: call device connect callback */
+	device_att_connect(device);
 
 	return FALSE;
 }
diff --git a/src/device.c b/src/device.c
index 02ef35e..c69b578 100644
--- a/src/device.c
+++ b/src/device.c
@@ -68,8 +68,6 @@
 #define DISCONNECT_TIMER	2
 #define DISCOVERY_TIMER		2
 
-#define AUTO_CONNECTION_INTERVAL	5 /* Next connection attempt */
-
 struct btd_disconnect_data {
 	guint id;
 	disconnect_watch watch;
@@ -1804,15 +1802,6 @@ static void attio_disconnected(gpointer data, gpointer user_data)
 		attio->dcfunc(attio->user_data);
 }
 
-static void att_connect_dispatched(gpointer user_data)
-{
-	struct btd_device *device = user_data;
-
-	device->auto_id = 0;
-}
-
-static gboolean att_connect(gpointer user_data);
-
 static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
@@ -1832,10 +1821,7 @@ static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
 	if (device->auto_connect == FALSE || err != ETIMEDOUT)
 		goto done;
 
-	device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE,
-						AUTO_CONNECTION_INTERVAL,
-						att_connect, device,
-						att_connect_dispatched);
+	adapter_connect_list_add(device_get_adapter(device), device);
 
 done:
 	attio_cleanup(device);
@@ -1935,11 +1921,7 @@ static void att_error_cb(const GError *gerr, gpointer user_data)
 	if (device->auto_connect == FALSE)
 		return;
 
-	device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE,
-						AUTO_CONNECTION_INTERVAL,
-						att_connect, device,
-						att_connect_dispatched);
-
+	adapter_connect_list_add(device_get_adapter(device), device);
 	DBG("Enabling automatic connections");
 }
 
@@ -1954,7 +1936,7 @@ static void att_success_cb(gpointer user_data)
 	g_slist_foreach(device->attios, attio_connected, device->attrib);
 }
 
-static gboolean att_connect(gpointer user_data)
+gboolean device_att_connect(gpointer user_data)
 {
 	struct btd_device *device = user_data;
 	struct btd_adapter *adapter = device->adapter;
@@ -2216,6 +2198,9 @@ void device_set_temporary(struct btd_device *device, gboolean temporary)
 
 	DBG("temporary %d", temporary);
 
+	if (temporary)
+		adapter_connect_list_remove(device_get_adapter(device), device);
+
 	device->temporary = temporary;
 }
 
@@ -2231,6 +2216,7 @@ void device_set_bonded(struct btd_device *device, gboolean bonded)
 
 void device_set_auto_connect(struct btd_device *device, gboolean enable)
 {
+	struct btd_adapter *adapter = device_get_adapter(device);
 	char addr[18];
 
 	if (!device)
@@ -2244,15 +2230,10 @@ void device_set_auto_connect(struct btd_device *device, gboolean enable)
 
 	/* Disabling auto connect */
 	if (enable == FALSE) {
-		if (device->auto_id)
-			g_source_remove(device->auto_id);
+		adapter_connect_list_remove(adapter, device);
 		return;
 	}
 
-	/* Enabling auto connect */
-	if (device->auto_id != 0)
-		return;
-
 	if (device->attrib) {
 		DBG("Already connected");
 		return;
@@ -2261,9 +2242,8 @@ void device_set_auto_connect(struct btd_device *device, gboolean enable)
 	if (device->attios == NULL && device->attios_offline == NULL)
 		return;
 
-	device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
-						att_connect, device,
-						att_connect_dispatched);
+	/* Enabling auto connect */
+	adapter_connect_list_add(adapter, device);
 }
 
 static gboolean start_discovery(gpointer user_data)
@@ -3164,10 +3144,7 @@ guint btd_device_add_attio_callback(struct btd_device *device,
 
 	device->attios = g_slist_append(device->attios, attio);
 
-	if (device->auto_id == 0)
-		device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
-						att_connect, device,
-						att_connect_dispatched);
+	adapter_connect_list_add(device_get_adapter(device), device);
 
 	return attio->id;
 }
diff --git a/src/device.h b/src/device.h
index f1d95c6..ab70f90 100644
--- a/src/device.h
+++ b/src/device.h
@@ -158,3 +158,4 @@ int device_unblock(DBusConnection *conn, struct btd_device *device,
 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);
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v6 03/11] core: Mutually exclude concurrent connections
From: João Paulo Rechi Vita @ 2012-09-11 13:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1347370387-17670-1-git-send-email-jprvita@openbossa.org>

Since controllers don't support more than one ongoing connection
procedure at the same time, new connection attempts needs to yield if
there is an ongoing connection procedure already.
---
 src/adapter.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 src/device.c  |  6 +++---
 src/device.h  |  2 +-
 3 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index e3994a8..9dbd306 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -136,6 +136,8 @@ struct btd_adapter {
 	GSList *connect_list;		/* Devices to connect when found */
 	guint discov_id;		/* Discovery timer */
 	gboolean discovering;		/* Discovery active */
+	gboolean connecting;		/* Connect active */
+	guint waiting_to_connect;	/* # of devices waiting to connect */
 	gboolean discov_suspended;	/* Discovery suspended */
 	guint auto_timeout_id;		/* Automatic connections timeout */
 	sdp_list_t *services;		/* Services associated to adapter */
@@ -2256,6 +2258,9 @@ void btd_adapter_start(struct btd_adapter *adapter)
 	call_adapter_powered_callbacks(adapter, TRUE);
 
 	info("Adapter %s has been enabled", adapter->path);
+
+	if (g_slist_length(adapter->connect_list))
+		mgmt_start_discovery(adapter->dev_id);
 }
 
 static void reply_pending_requests(struct btd_adapter *adapter)
@@ -2579,6 +2584,7 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 						gboolean discovering)
 {
 	const char *path = adapter->path;
+	guint connect_list_size;
 
 	adapter->discovering = discovering;
 
@@ -2593,11 +2599,17 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 	g_slist_free_full(adapter->oor_devices, dev_info_free);
 	adapter->oor_devices = g_slist_copy(adapter->found_devices);
 
-	if (!adapter_has_discov_sessions(adapter) || adapter->discov_suspended)
+	if (adapter->discov_suspended)
+		return;
+
+	connect_list_size = g_slist_length(adapter->connect_list);
+
+	if (!adapter_has_discov_sessions(adapter) && !connect_list_size)
 		return;
 
-	DBG("hci%u restarting discovery, disc_sessions %u", adapter->dev_id,
-					g_slist_length(adapter->disc_sessions));
+	DBG("hci%u restarting discovery: disc_sessions %u, connect_list size "
+		"%u", adapter->dev_id, g_slist_length(adapter->disc_sessions),
+							connect_list_size);
 
 	adapter->discov_id = g_idle_add(discovery_cb, adapter);
 }
@@ -2905,18 +2917,44 @@ static char *read_stored_data(bdaddr_t *local, bdaddr_t *peer,
 	return textfile_get(filename, key);
 }
 
+static gboolean clean_connecting_state(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+	struct btd_device *device = user_data;
+	struct btd_adapter *adapter = device_get_adapter(device);
+
+	adapter->connecting = FALSE;
+
+	if (adapter->waiting_to_connect == 0 &&
+					g_slist_length(adapter->connect_list))
+		mgmt_start_discovery(adapter->dev_id);
+
+	btd_device_unref(device);
+	return FALSE;
+}
+
 static gboolean connect_pending_cb(gpointer user_data)
 {
 	struct btd_device *device = user_data;
 	struct btd_adapter *adapter = device_get_adapter(device);
+	GIOChannel *io;
 
 	/* in the future we may want to check here if the controller supports
 	 * scanning and connecting at the same time */
 	if (adapter->discovering)
 		return TRUE;
 
-	device_att_connect(device);
+	if (adapter->connecting)
+		return TRUE;
+
+	adapter->connecting = TRUE;
+	adapter->waiting_to_connect--;
 
+	io = device_att_connect(device);
+	g_io_add_watch(io, G_IO_OUT | G_IO_ERR, clean_connecting_state,
+						btd_device_ref(device));
+	g_io_channel_unref(io);
+
+	btd_device_unref(device);
 	return FALSE;
 }
 
@@ -3008,12 +3046,19 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 
 	if (bdaddr_type == BDADDR_LE_PUBLIC ||
 					bdaddr_type == BDADDR_LE_RANDOM) {
+		struct btd_device *device;
+
 		l = g_slist_find_custom(adapter->connect_list, bdaddr,
 					(GCompareFunc) device_bdaddr_cmp);
-		if (l) {
-			g_idle_add(connect_pending_cb, l->data);
-			stop_discovery(adapter);
-		}
+		if (!l)
+			goto done;
+
+		device = l->data;
+		adapter_connect_list_remove(adapter, device);
+
+		g_idle_add(connect_pending_cb,  btd_device_ref(device));
+		stop_discovery(adapter);
+		adapter->waiting_to_connect++;
 	}
 
 done:
diff --git a/src/device.c b/src/device.c
index c69b578..96afc37 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1936,7 +1936,7 @@ static void att_success_cb(gpointer user_data)
 	g_slist_foreach(device->attios, attio_connected, device->attrib);
 }
 
-gboolean device_att_connect(gpointer user_data)
+GIOChannel *device_att_connect(gpointer user_data)
 {
 	struct btd_device *device = user_data;
 	struct btd_adapter *adapter = device->adapter;
@@ -1979,12 +1979,12 @@ gboolean device_att_connect(gpointer user_data)
 		error("ATT bt_io_connect(%s): %s", addr, gerr->message);
 		g_error_free(gerr);
 		g_free(attcb);
-		return FALSE;
+		return NULL;
 	}
 
 	device->att_io = io;
 
-	return FALSE;
+	return g_io_channel_ref(io);
 }
 
 static void att_browse_error_cb(const GError *gerr, gpointer user_data)
diff --git a/src/device.h b/src/device.h
index ab70f90..1b5be4e 100644
--- a/src/device.h
+++ b/src/device.h
@@ -158,4 +158,4 @@ int device_unblock(DBusConnection *conn, struct btd_device *device,
 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);
+GIOChannel *device_att_connect(gpointer user_data);
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v6 04/11] mgmt: Add LE scanning callback
From: João Paulo Rechi Vita @ 2012-09-11 13:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1347370387-17670-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch adds a new callback to allow the adapter to control LE
scanning. The current approach uses the active scanning with default
windows and intervals defined by the core spec without any filtering.
---
 src/mgmt.c | 34 ++++++++++++++++++++++++++++++++++
 src/mgmt.h |  1 +
 2 files changed, 35 insertions(+)

diff --git a/src/mgmt.c b/src/mgmt.c
index 3f83fdf..db1eaed 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -2043,6 +2043,40 @@ int mgmt_start_discovery(int index)
 	return 0;
 }
 
+int mgmt_start_scanning(int index)
+{
+	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_start_discovery)];
+	struct mgmt_hdr *hdr = (void *) buf;
+	struct mgmt_cp_start_discovery *cp = (void *) &buf[sizeof(*hdr)];
+	struct controller_info *info = &controllers[index];
+
+	DBG("index %d", index);
+
+	if (!mgmt_low_energy(info->current_settings)) {
+		error("scanning failed: Low Energy not enabled/supported");
+		return -ENOTSUP;
+	}
+
+	info->discov_type = 0;
+	hci_set_bit(BDADDR_LE_PUBLIC, &info->discov_type);
+	hci_set_bit(BDADDR_LE_RANDOM, &info->discov_type);
+
+	memset(buf, 0, sizeof(buf));
+	hdr->opcode = htobs(MGMT_OP_START_DISCOVERY);
+	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
+
+	cp->type = info->discov_type;
+
+	if (write(mgmt_sock, buf, sizeof(buf)) < 0) {
+		int err = -errno;
+		error("failed to write to MGMT socket: %s", strerror(-err));
+		return err;
+	}
+
+	return 0;
+}
+
 int mgmt_stop_discovery(int index)
 {
 	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_start_discovery)];
diff --git a/src/mgmt.h b/src/mgmt.h
index 95245d2..eb7434a 100644
--- a/src/mgmt.h
+++ b/src/mgmt.h
@@ -33,6 +33,7 @@ int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor);
 int mgmt_set_fast_connectable(int index, gboolean enable);
 
 int mgmt_start_discovery(int index);
+int mgmt_start_scanning(int index);
 int mgmt_stop_discovery(int index);
 
 int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout,
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v6 05/11] core: Replace interleaved by LE scanning
From: João Paulo Rechi Vita @ 2012-09-11 13:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1347370387-17670-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patches replaces the interleaved discovery by LE scanning when LE
re-connection is required.
---
 src/adapter.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 9dbd306..2bba1ac 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2260,7 +2260,7 @@ void btd_adapter_start(struct btd_adapter *adapter)
 	info("Adapter %s has been enabled", adapter->path);
 
 	if (g_slist_length(adapter->connect_list))
-		mgmt_start_discovery(adapter->dev_id);
+		mgmt_start_scanning(adapter->dev_id);
 }
 
 static void reply_pending_requests(struct btd_adapter *adapter)
@@ -2604,14 +2604,22 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 
 	connect_list_size = g_slist_length(adapter->connect_list);
 
-	if (!adapter_has_discov_sessions(adapter) && !connect_list_size)
+	if (adapter_has_discov_sessions(adapter)) {
+		adapter->discov_id = g_idle_add(discovery_cb, adapter);
+
+		DBG("hci%u restarting discovery: disc_sessions %u",
+				adapter->dev_id,
+				g_slist_length(adapter->disc_sessions));
 		return;
+	}
 
-	DBG("hci%u restarting discovery: disc_sessions %u, connect_list size "
-		"%u", adapter->dev_id, g_slist_length(adapter->disc_sessions),
-							connect_list_size);
+	if (connect_list_size) {
+		mgmt_start_scanning(adapter->dev_id);
 
-	adapter->discov_id = g_idle_add(discovery_cb, adapter);
+		DBG("hci%u restarting scanning connect_list size %u",
+				adapter->dev_id, connect_list_size);
+		return;
+	}
 }
 
 static void suspend_discovery(struct btd_adapter *adapter)
@@ -2926,7 +2934,7 @@ static gboolean clean_connecting_state(GIOChannel *io, GIOCondition cond, gpoint
 
 	if (adapter->waiting_to_connect == 0 &&
 					g_slist_length(adapter->connect_list))
-		mgmt_start_discovery(adapter->dev_id);
+		mgmt_start_scanning(adapter->dev_id);
 
 	btd_device_unref(device);
 	return FALSE;
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v6 06/11] core: Start LE scanning when a device requests
From: João Paulo Rechi Vita @ 2012-09-11 13:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1347370387-17670-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch enables the LE scanning when a device requires connection and
there isn't discovery sessions, triggering the General Connection
Establishment Procedure.
---
 src/adapter.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 2bba1ac..62f92c6 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2214,6 +2214,11 @@ void adapter_connect_list_add(struct btd_adapter *adapter,
 						btd_device_ref(device));
 	DBG("%s added to %s's connect_list", device_get_path(device),
 								adapter->name);
+
+	if (adapter->disc_sessions)
+		return;
+
+	mgmt_start_scanning(adapter->dev_id);
 }
 
 void adapter_connect_list_remove(struct btd_adapter *adapter,
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v6 07/11] core: Queue discovery if scanning is active
From: João Paulo Rechi Vita @ 2012-09-11 13:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1347370387-17670-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch manages BR/EDR inquiry and BLE scanning discovery sessions.
A scanning session is added in the discovery session list when there is
a bonded device which requires re-connection.

bluetoothd decides if interleaved or scanning needs to be executed based
on the queued discovery sessions. Interleaved discovery has higher
priority, scanning only is executed when there is only a scanning
session active.
---
 src/adapter.c | 67 +++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 47 insertions(+), 20 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 62f92c6..8ee6a50 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -133,6 +133,7 @@ struct btd_adapter {
 	GSList *devices;		/* Devices structure pointers */
 	GSList *mode_sessions;		/* Request Mode sessions */
 	GSList *disc_sessions;		/* Discovery sessions */
+	struct session_req *scanning_session;
 	GSList *connect_list;		/* Devices to connect when found */
 	guint discov_id;		/* Discovery timer */
 	gboolean discovering;		/* Discovery active */
@@ -222,18 +223,19 @@ static struct session_req *create_session(struct btd_adapter *adapter,
 					DBusConnection *conn, DBusMessage *msg,
 					uint8_t mode, GDBusWatchFunction cb)
 {
-	const char *sender = dbus_message_get_sender(msg);
+	const char *sender;
 	struct session_req *req;
 
 	req = g_new0(struct session_req, 1);
 	req->adapter = adapter;
-	req->conn = dbus_connection_ref(conn);
-	req->msg = dbus_message_ref(msg);
 	req->mode = mode;
 
-	if (cb == NULL)
+	if (conn == NULL || cb == NULL || msg == NULL)
 		return session_ref(req);
 
+	req->conn = dbus_connection_ref(conn);
+	req->msg = dbus_message_ref(msg);
+	sender = dbus_message_get_sender(msg);
 	req->owner = g_strdup(sender);
 	req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req, NULL);
 
@@ -445,7 +447,9 @@ static struct session_req *find_session(GSList *list, const char *sender)
 	for (; list; list = list->next) {
 		struct session_req *req = list->data;
 
-		if (g_str_equal(req->owner, sender))
+		/* req->owner may be NULL if the session has been added by the
+		 * daemon itself, so we use g_strcmp0 instead of g_str_equal */
+		if (g_strcmp0(req->owner, sender) == 0)
 			return req;
 	}
 
@@ -520,7 +524,7 @@ static void session_remove(struct session_req *req)
 	struct btd_adapter *adapter = req->adapter;
 
 	/* Ignore set_mode session */
-	if (req->owner == NULL)
+	if (req->owner == NULL && adapter->pending_mode)
 		return;
 
 	DBG("%s session %p with %s deactivated",
@@ -1009,7 +1013,12 @@ static gboolean discovery_cb(gpointer user_data)
 	struct btd_adapter *adapter = user_data;
 
 	adapter->discov_id = 0;
-	mgmt_start_discovery(adapter->dev_id);
+
+	if (adapter->scanning_session &&
+			(g_slist_length(adapter->disc_sessions) == 1))
+		mgmt_start_scanning(adapter->dev_id);
+	else
+		mgmt_start_discovery(adapter->dev_id);
 
 	return FALSE;
 }
@@ -2204,6 +2213,8 @@ const char *btd_adapter_get_name(struct btd_adapter *adapter)
 void adapter_connect_list_add(struct btd_adapter *adapter,
 					struct btd_device *device)
 {
+	struct session_req *req;
+
 	if (g_slist_find(adapter->connect_list, device)) {
 		DBG("ignoring already added device %s",
 						device_get_path(device));
@@ -2215,10 +2226,21 @@ void adapter_connect_list_add(struct btd_adapter *adapter,
 	DBG("%s added to %s's connect_list", device_get_path(device),
 								adapter->name);
 
-	if (adapter->disc_sessions)
+	if (!adapter->up)
+		return;
+
+	if (adapter->off_requested)
+		return;
+
+	if (adapter->scanning_session)
 		return;
 
-	mgmt_start_scanning(adapter->dev_id);
+	if (adapter->disc_sessions == NULL)
+		adapter->discov_id = g_idle_add(discovery_cb, adapter);
+
+	req = create_session(adapter, NULL, NULL, 0, NULL);
+	adapter->disc_sessions = g_slist_append(adapter->disc_sessions, req);
+	adapter->scanning_session = req;
 }
 
 void adapter_connect_list_remove(struct btd_adapter *adapter,
@@ -2238,6 +2260,7 @@ void adapter_connect_list_remove(struct btd_adapter *adapter,
 
 void btd_adapter_start(struct btd_adapter *adapter)
 {
+	struct session_req *req;
 	char address[18];
 	gboolean powered;
 
@@ -2264,8 +2287,15 @@ void btd_adapter_start(struct btd_adapter *adapter)
 
 	info("Adapter %s has been enabled", adapter->path);
 
-	if (g_slist_length(adapter->connect_list))
-		mgmt_start_scanning(adapter->dev_id);
+	if (g_slist_length(adapter->connect_list) == 0 ||
+					adapter->disc_sessions)
+		return;
+
+	req = create_session(adapter, NULL, NULL, 0, NULL);
+	adapter->disc_sessions = g_slist_append(adapter->disc_sessions, req);
+	adapter->scanning_session = req;
+
+	adapter->discov_id = g_idle_add(discovery_cb, adapter);
 }
 
 static void reply_pending_requests(struct btd_adapter *adapter)
@@ -2609,6 +2639,11 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 
 	connect_list_size = g_slist_length(adapter->connect_list);
 
+	if (connect_list_size == 0 && adapter->scanning_session) {
+		session_unref(adapter->scanning_session);
+		adapter->scanning_session = NULL;
+	}
+
 	if (adapter_has_discov_sessions(adapter)) {
 		adapter->discov_id = g_idle_add(discovery_cb, adapter);
 
@@ -2617,14 +2652,6 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 				g_slist_length(adapter->disc_sessions));
 		return;
 	}
-
-	if (connect_list_size) {
-		mgmt_start_scanning(adapter->dev_id);
-
-		DBG("hci%u restarting scanning connect_list size %u",
-				adapter->dev_id, connect_list_size);
-		return;
-	}
 }
 
 static void suspend_discovery(struct btd_adapter *adapter)
@@ -2939,7 +2966,7 @@ static gboolean clean_connecting_state(GIOChannel *io, GIOCondition cond, gpoint
 
 	if (adapter->waiting_to_connect == 0 &&
 					g_slist_length(adapter->connect_list))
-		mgmt_start_scanning(adapter->dev_id);
+		adapter->discov_id = g_idle_add(discovery_cb, adapter);
 
 	btd_device_unref(device);
 	return FALSE;
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v6 08/11] core: Disable unnecessary auto connections
From: João Paulo Rechi Vita @ 2012-09-11 13:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Paulo Alcantara
In-Reply-To: <1347370387-17670-1-git-send-email-jprvita@openbossa.org>

From: Paulo Alcantara <paulo.alcantara@openbossa.org>

BlueZ host disconnects the link when encryption fails. ECONNABORTED
error is returned by the kernel when the connection is terminated by the
local host. This scenario commonly happens when authentication fails due
PIN or Key Missing.
---
 src/device.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/device.c b/src/device.c
index 96afc37..e46ea2b 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1918,6 +1918,9 @@ static void att_error_cb(const GError *gerr, gpointer user_data)
 	struct att_callbacks *attcb = user_data;
 	struct btd_device *device = attcb->user_data;
 
+	if (g_error_matches(gerr, BT_IO_ERROR, ECONNABORTED))
+		return;
+
 	if (device->auto_connect == FALSE)
 		return;
 
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ v6 09/11] core: Re-connect for ECONNRESET or ECONNABORTED
From: João Paulo Rechi Vita @ 2012-09-11 13:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1347370387-17670-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch keeps scanning and re-connections active if the disconnection
reason is ECONNRESET(Remote Initiated Disconnection).

Re-connection is a behaviour determined by Profiles or by the upper
layer(user actions). For instance, HoG requires re-connection always
active, no matter if the previous disconnection reason was page timeout
or remote initiated disconnection (ECONNRESET). Some devices disconnects
after some idle time, connectable advertises are sent by the peripheral
when commanded by the user(eg: key pressed). Disconnection can be also
triggered by the local host (ECONNABORTED) using command line tools or
Disconnect method in the Device interface.

The peripheral dictates the re-connection controlling the connectable
advertises, BlueZ(central) needs to keep the scanning always active to
able to detect the advertises and trigger the connection.
---
 src/device.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/device.c b/src/device.c
index e46ea2b..04ed96f 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1818,10 +1818,18 @@ static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
 
 	g_slist_foreach(device->attios, attio_disconnected, NULL);
 
-	if (device->auto_connect == FALSE || err != ETIMEDOUT)
+	if (device->auto_connect == FALSE) {
+		DBG("Automatic connection disabled");
 		goto done;
+	}
 
-	adapter_connect_list_add(device_get_adapter(device), device);
+	/*
+	 * Keep scanning/re-connection active if disconnection reason
+	 * is page timeout, remote user terminated connection or local
+	 * initiated disconnection.
+	 */
+	if (err == ETIMEDOUT || err == ECONNRESET || err == ECONNABORTED)
+		adapter_connect_list_add(device_get_adapter(device), device);
 
 done:
 	attio_cleanup(device);
-- 
1.7.11.4


^ 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