Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH] input: Implement idle timeout for fakehid
From: Jeff Hansen @ 2012-08-13 17:40 UTC (permalink / raw)
  To: linux-bluetooth

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

(bump)

The batteries on my BD remote would die in a few days without this
patch.  The idle timeout needs to be enforced for fakehid devices as
well as normal HID devices.



[-- Attachment #2: 0001-input-Implement-idle-timeout-for-fakehid.patch --]
[-- Type: text/x-patch, Size: 2950 bytes --]

>From a96f67cb6268e34e677e5d288f2c3b89acfca7fe Mon Sep 17 00:00:00 2001
From: Jeff Hansen <x@jeffhansen.com>
Date: Tue, 31 Jul 2012 22:45:23 -0600
Subject: [PATCH] input: Implement idle timeout for fakehid.

The batteries on my BD remote would die in a few days without this patch.

Signed-off-by: Jeff Hansen <x@jeffhansen.com>
---
 input/device.c  |    6 ++++++
 input/device.h  |    4 ++++
 input/fakehid.c |   18 ++++++++++++++++++
 3 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/input/device.c b/input/device.c
index 0ab63c0..ae11a13 100644
--- a/input/device.c
+++ b/input/device.c
@@ -609,6 +609,7 @@ static int hidp_add_connection(const struct input_device *idev,
 		fake->disconnect = fake_hid_disconnect;
 		fake->priv = fake_hid;
 		fake->idev = idev;
+		fake->timeout = iconn->timeout * 1000;
 		fake = fake_hid_connadd(fake, iconn->intr_io, fake_hid);
 		if (fake == NULL)
 			err = -ENOMEM;
@@ -1257,3 +1258,8 @@ int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst)
 
 	return 0;
 }
+
+void input_device_request_disconnect(const struct input_device *idev)
+{
+	device_request_disconnect(idev->device, NULL);
+}
diff --git a/input/device.h b/input/device.h
index 14c0f97..416cc9c 100644
--- a/input/device.h
+++ b/input/device.h
@@ -40,6 +40,8 @@ struct fake_input {
 	int		(*disconnect) (struct input_conn *iconn);
 	void		*priv;
 	const struct input_device *idev;
+	guint		idle_timeout;
+	uint32_t	timeout;
 };
 
 int fake_input_register(DBusConnection *conn, struct btd_device *device,
@@ -54,3 +56,5 @@ int input_device_unregister(const char *path, const char *uuid);
 int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
 							GIOChannel *io);
 int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst);
+
+void input_device_request_disconnect(const struct input_device *idev);
diff --git a/input/fakehid.c b/input/fakehid.c
index b809870..0407ae3 100644
--- a/input/fakehid.c
+++ b/input/fakehid.c
@@ -208,6 +208,13 @@ error:
 	return -1;
 }
 
+static gboolean ps3remote_idle(gpointer data)
+{
+	struct fake_input *fake = data;
+	input_device_request_disconnect(fake->idev);
+	return FALSE;
+}
+
 static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
 				gpointer data)
 {
@@ -218,6 +225,13 @@ static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
 	char buff[50];
 	int fd;
 
+	if (fake->idle_timeout) {
+		g_source_remove(fake->idle_timeout);
+		fake->idle_timeout = 0;
+	}
+	if (fake->timeout)
+		fake->idle_timeout = g_timeout_add(fake->timeout, ps3remote_idle, fake);
+
 	if (cond & G_IO_NVAL)
 		return FALSE;
 
@@ -337,6 +351,10 @@ static gboolean fake_hid_common_connect(struct fake_input *fake, GError **err)
 
 static int fake_hid_common_disconnect(struct fake_input *fake)
 {
+	if (fake->idle_timeout) {
+		g_source_remove(fake->idle_timeout);
+		fake->idle_timeout = 0;
+	}
 	return 0;
 }
 
-- 
1.7.8.6



^ permalink raw reply related

* [PATCH v2 13/13] heartrate: Add Heart Rate test script
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

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

diff --git a/Makefile.tools b/Makefile.tools
index 5579b86..77b0a3f 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -222,7 +222,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..4945583
--- /dev/null
+++ b/test/test-heartrate
@@ -0,0 +1,91 @@
+#!/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="a{sv}", out_signature="")
+	def MeasurementReceived(self, measure):
+		print("Measurement received")
+		print("Value", measure["Value"])
+		print("Energy", measure["Energy"])
+		print("Contact", measure["Contact"])
+		print("Location", measure["Location"])
+
+		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")
+
+	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")
+
+	path = "/test/watcher"
+	watcher = Watcher(bus, path)
+
+	heartrate.RegisterWatcher(path)
+
+	properties = heartrate.GetProperties()
+	reset_sup = properties["ResetSupported"]
+
+	if len(args) > 0:
+		if args[0] == "Reset":
+			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.9.5


^ permalink raw reply related

* [PATCH v2 12/13] heartrate: Add org.bluez.HeartRateWatcher iface to default policy
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-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.9.5


^ permalink raw reply related

* [PATCH v2 11/13] heartrate: Add GetProperties method handle
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Add method to return Heart Rate Service properties.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 267ad54..0eb6ee8 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -238,6 +238,33 @@ static struct descriptor *get_descriptor(struct characteristic *ch,
 	return l->data;
 }
 
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate *hr = 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, "ResetSupported", DBUS_TYPE_BOOLEAN,
+							&hr->cp_reset);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
 static void measurement_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -417,6 +444,9 @@ static DBusMessage *control_point_reset(DBusConnection *conn, DBusMessage *msg,
 }
 
 static const GDBusMethodTable heartrate_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+			get_properties) },
 	{ GDBUS_METHOD("RegisterWatcher",
 			GDBUS_ARGS({ "agent", "o" }), NULL,
 			watcher_register) },
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 10/13] heartrate: Add support for Control Point Reset
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Handle Control Point reset if server supports it.

---
 profiles/heartrate/heartrate.c |   50 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 46 insertions(+), 4 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 587438b..267ad54 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -63,6 +63,7 @@ struct heartrate {
 	GSList			*watchers; /*Watchers*/
 	gboolean		has_location;
 	uint8_t		location; /*Body Sensor location*/
+	gboolean		cp_reset; /*Control Point Reset support*/
 };
 
 struct characteristic {
@@ -378,6 +379,43 @@ static DBusMessage *watcher_unregister(DBusConnection *conn, DBusMessage *msg,
 	return dbus_message_new_method_return(msg);
 }
 
+static gint process_att_reset(struct heartrate *hr)
+{
+	struct characteristic *ch;
+	char *msg;
+	uint8_t atval;
+
+	if (hr->attrib == NULL)
+		return -1;
+
+	ch = get_characteristic(hr, HEART_RATE_CONTROL_POINT_UUID);
+	if (ch == NULL)
+		return -1;
+
+	atval = 0x01;
+	msg = g_strdup("Reset Control Point");
+
+	gatt_write_char(hr->attrib, ch->attr.value_handle, &atval, 1,
+						measurement_cb, msg);
+	return 0;
+}
+
+static DBusMessage *control_point_reset(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct heartrate *hr = data;
+
+	if (!hr->cp_reset)
+		return btd_error_not_supported(msg);
+
+	if (process_att_reset(hr) < 0)
+		return btd_error_not_available(msg);
+
+	DBG("Energy Expended Value has been reset");
+
+	return dbus_message_new_method_return(msg);
+}
+
 static const GDBusMethodTable heartrate_methods[] = {
 	{ GDBUS_METHOD("RegisterWatcher",
 			GDBUS_ARGS({ "agent", "o" }), NULL,
@@ -385,6 +423,8 @@ static const GDBusMethodTable heartrate_methods[] = {
 	{ GDBUS_METHOD("UnregisterWatcher",
 			GDBUS_ARGS({ "agent", "o" }), NULL,
 			watcher_unregister) },
+	{ GDBUS_METHOD("Reset", NULL, NULL,
+			control_point_reset) },
 	{ }
 };
 
@@ -420,12 +460,14 @@ static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
 static void process_heartrate_char(struct characteristic *ch)
 {
 	if (g_strcmp0(ch->attr.uuid,
-				HEART_RATE_CONTROL_POINT_UUID) == 0)
-		DBG("Heart Rate Control Point reset not supported by client");
-	 else if (g_strcmp0(ch->attr.uuid,
-					BODY_SENSOR_LOCATION_UUID) == 0)
+				HEART_RATE_CONTROL_POINT_UUID) == 0) {
+		ch->hr->cp_reset = TRUE;
+		DBG("Heart Rate Control Point reset supported by server");
+	 } else if (g_strcmp0(ch->attr.uuid,
+					BODY_SENSOR_LOCATION_UUID) == 0) {
 		gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
 						read_sensor_location_cb, ch);
+	 }
 }
 
 static void process_heartrate_desc(struct descriptor *desc)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 09/13] heartrate: Process measurements
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Enable or disable measurement while watcher is registered
or unregistered. Process measurement data when notification
is received and update watcher.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index e88d4bc..587438b 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -46,6 +46,12 @@
 
 #define SENSOR_LOCATION_SIZE 1
 
+#define HR_VALUE_FORMAT	0x01
+#define SENSOR_SUPPORTED	0x02
+#define CONTACT_DETECTED	0x04
+#define ENERGY_EXP_STATUS	0x08
+#define RR_INTERVAL		0x10
+
 struct heartrate {
 	struct btd_device	*dev;  /*Device reference*/
 	DBusConnection		*conn; /*DBus conn*/
@@ -78,8 +84,38 @@ struct watcher {
 	char			*path;
 };
 
+struct measurement {
+	gboolean	u16_val_fmt; /*Heart Rate Value Format*/
+	uint16_t	value;
+	uint16_t	energy;
+	gboolean	energy_sup; /*Energy Status Supported*/
+	gboolean	contact;
+	char		*location;
+	gboolean	interval_sup; /*RR-Interval Supported*/
+	GSList		*interval;
+};
+
+const char *location_type[] = {
+	"Other",
+	"Chest",
+	"Wrist",
+	"Finger",
+	"Hand",
+	"Earlobe",
+	"Foot"
+};
+
 static GSList *hr_servers = NULL;
 
+static const gchar *location2str(uint8_t value)
+{
+	 if (value < G_N_ELEMENTS(location_type))
+		return location_type[value];
+
+	error("Location type %d reserved for future use", value);
+	return NULL;
+}
+
 static gint cmp_device(gconstpointer a, gconstpointer b)
 {
 	const struct heartrate *hr = a;
@@ -91,6 +127,30 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const char *uuid = b;
+
+	return g_strcmp0(ch->attr.uuid, uuid);
+}
+
+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 gint cmp_descriptor(gconstpointer a, gconstpointer b)
+{
+	const struct descriptor *desc = a;
+	const bt_uuid_t *uuid = b;
+
+	return bt_uuid_cmp(&desc->uuid, uuid);
+}
+
 static gint cmp_watcher(gconstpointer a, gconstpointer b)
 {
 	const struct watcher *watcher = a;
@@ -153,6 +213,78 @@ static void heartrate_destroy(gpointer user_data)
 	g_free(hr);
 }
 
+static struct characteristic *get_characteristic(struct heartrate *hr,
+							const char *uuid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(hr->chars, uuid, cmp_char_uuid);
+	if (l == NULL)
+		return NULL;
+
+	return l->data;
+}
+
+static struct descriptor *get_descriptor(struct characteristic *ch,
+							const bt_uuid_t *uuid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
+	if (l == NULL)
+		return NULL;
+
+	return l->data;
+}
+
+static void measurement_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 measurement_toggle(struct heartrate *hr, gboolean enable)
+{
+	struct characteristic *ch;
+	struct descriptor *desc;
+	bt_uuid_t btuuid;
+	uint8_t atval[2];
+	uint16_t val;
+	char *msg;
+
+	if (hr->attrib == NULL)
+		return;
+
+	ch = get_characteristic(hr, HEART_RATE_MEASUREMENT_UUID);
+	if (ch == NULL) {
+		DBG("Temperature measurement characteristic not found");
+		return;
+	}
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	desc = get_descriptor(ch, &btuuid);
+	if (desc == NULL) {
+		DBG("Client characteristic configuration descriptor not found");
+		return;
+	}
+
+	val = enable ? GATT_CLIENT_CHARAC_CFG_NOTIF_BIT : 0x0000;
+
+	msg = enable ? g_strdup("Enable measurement") :
+				g_strdup("Disable measurement");
+
+	att_put_u16(val, atval);
+
+	gatt_write_char(hr->attrib, desc->handle, atval, 2,
+							measurement_cb, msg);
+
+}
+
 static void watcher_exit(DBusConnection *conn, void *user_data)
 {
 	struct watcher *watcher = user_data;
@@ -162,6 +294,9 @@ static void watcher_exit(DBusConnection *conn, void *user_data)
 
 	hr->watchers = g_slist_remove(hr->watchers, watcher);
 	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
+
+	if (g_slist_length(hr->watchers) == 0)
+		measurement_toggle(hr, FALSE);
 }
 
 static struct watcher *watcher_find(GSList *list, const char *sender,
@@ -208,6 +343,9 @@ static DBusMessage *watcher_register(DBusConnection *conn, DBusMessage *msg,
 	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
 						watcher, watcher_destroy);
 
+	if (g_slist_length(hr->watchers) == 0)
+		measurement_toggle(hr, TRUE);
+
 	hr->watchers = g_slist_prepend(hr->watchers, watcher);
 
 	return dbus_message_new_method_return(msg);
@@ -234,6 +372,9 @@ static DBusMessage *watcher_unregister(DBusConnection *conn, DBusMessage *msg,
 	hr->watchers = g_slist_remove(hr->watchers, watcher);
 	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
 
+	if (g_slist_length(hr->watchers) == 0)
+		measurement_toggle(hr, FALSE);
+
 	return dbus_message_new_method_return(msg);
 }
 
@@ -393,12 +534,189 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 	}
 }
 
+static void update_watcher(gpointer data, gpointer user_data)
+{
+	struct watcher *w = data;
+	struct measurement *m = user_data;
+	DBusConnection *conn = w->hr->conn;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *msg;
+	GSList *l;
+	uint16_t *interval;
+	guint n_elem;
+	guint i;
+
+	msg = dbus_message_new_method_call(w->srv, w->path,
+				"org.bluez.HeartRateWatcher",
+				"MeasurementReceived");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &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, "Value", DBUS_TYPE_UINT16, &m->value);
+	dict_append_entry(&dict, "Energy", DBUS_TYPE_UINT16, &m->energy);
+	dict_append_entry(&dict, "Contact", DBUS_TYPE_BOOLEAN, &m->contact);
+	dict_append_entry(&dict, "Location", DBUS_TYPE_STRING, &m->location);
+
+	n_elem = g_slist_length(m->interval);
+
+	interval = g_new(uint16_t, n_elem);
+
+	if (interval != NULL) {
+
+		for (i = 0, l = m->interval; l; l = l->next, i++)
+			interval[i] =  GPOINTER_TO_UINT(l->data);
+
+		dict_append_array(&dict, "Interval", DBUS_TYPE_UINT16,
+							&interval, n_elem);
+	}
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(conn, msg);
+
+	if (interval != NULL)
+		g_free(interval);
+}
+
+static void recv_measurement(struct heartrate *hr, struct measurement *m)
+{
+	GSList *wlist = hr->watchers;
+
+	g_slist_foreach(wlist, update_watcher, m);
+}
+
+static void get_flags(struct measurement *m, uint8_t pdu)
+{
+	uint8_t flags = pdu;
+
+	if (flags & HR_VALUE_FORMAT)
+		m->u16_val_fmt = TRUE;  /*value format set to uint16*/
+
+	if ((flags & SENSOR_SUPPORTED) && (flags & CONTACT_DETECTED))
+		m->contact = TRUE;
+
+	if (flags & ENERGY_EXP_STATUS)
+		m->energy_sup = TRUE;
+
+	if (flags & RR_INTERVAL)
+		m->interval_sup = TRUE;
+}
+
+static void proc_measurement(struct heartrate *hr, const uint8_t *pdu,
+						uint16_t len)
+{
+	struct measurement m;
+	const char *loc;
+	gint pdu_idx;
+	gint min_pdu_len;
+
+	if (len < 4) {
+		error("Mandatory flags are not provided");
+		return;
+	}
+
+	memset(&m, 0, sizeof(struct measurement));
+
+	get_flags(&m, pdu[3]);
+
+	pdu_idx = 4;
+	min_pdu_len = len - 4;
+
+	if (m.u16_val_fmt) {
+
+		if (min_pdu_len < 2) {
+			error("Heart Rate measurement value is not provided");
+			return;
+		}
+
+		m.value = att_get_u16(&pdu[pdu_idx]);
+		pdu_idx += 2;
+		min_pdu_len -= 2;
+	} else {
+
+		if (min_pdu_len < 1) {
+			error("Heart Rate measurement value is not provided");
+			return;
+		}
+
+		m.value = pdu[pdu_idx];
+		pdu_idx++;
+		min_pdu_len--;
+	}
+
+	if (m.energy_sup) {
+
+		if (min_pdu_len < 2) {
+			error("Can't get Energy Expended field");
+			return;
+		}
+
+		m.energy = att_get_u16(&pdu[pdu_idx]);
+		pdu_idx += 2;
+		min_pdu_len -= 2;
+	}
+
+	if (m.interval_sup) {
+		gint i;
+
+		if (min_pdu_len < 0) {
+			error("Can't get RR-interval");
+			return;
+		}
+
+		for (i = len - pdu_idx; i > 0; i--) {
+			uint16_t val = att_get_u16(&pdu[pdu_idx++]);
+			m.interval = g_slist_append(m.interval,
+						GUINT_TO_POINTER(val));
+		}
+	}
+
+	if (hr->has_location) {
+		loc = location2str(hr->location);
+		m.location =  g_strdup(loc);
+	} else {
+		m.location = NULL;
+	}
+
+	recv_measurement(hr, &m);
+
+	g_free(m.location);
+
+	if (m.interval != NULL)
+		g_slist_free(m.interval);
+}
+
 static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
 {
+	struct heartrate *hr = user_data;
+	const struct characteristic *ch;
+	uint16_t handle;
+	GSList *l;
+
 	if (len < MIN_NOTIFICATION_LEN) {
 		error("Bad pdu received");
 		return;
 	}
+
+	handle = att_get_u16(&pdu[1]);
+	l = g_slist_find_custom(hr->chars, &handle, cmp_char_val_handle);
+	if (l == NULL) {
+		error("Unexpected handle: 0x%04x", handle);
+		return;
+	}
+
+	ch = l->data;
+	if (g_strcmp0(ch->attr.uuid, HEART_RATE_MEASUREMENT_UUID) == 0)
+		proc_measurement(hr, pdu, len);
 }
 
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 08/13] heartrate: Add notification support
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Add handling notification event.

---
 profiles/heartrate/heartrate.c |   20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index d0bcd57..e88d4bc 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -42,6 +42,8 @@
 
 #define HEART_RATE_INTERFACE "org.bluez.HeartRate"
 
+#define MIN_NOTIFICATION_LEN 3  /* 1-byte opcode + 2-byte handle */
+
 #define SENSOR_LOCATION_SIZE 1
 
 struct heartrate {
@@ -49,6 +51,7 @@ struct heartrate {
 	DBusConnection		*conn; /*DBus conn*/
 	GAttrib			*attrib; /*GATT connection*/
 	guint			attioid; /*ATT watcher id*/
+	guint			attionotid; /*ATT notification watcher id*/
 	struct att_range	*svc_range; /*Heart Rate range*/
 	GSList			*chars; /*Characteristics*/
 	GSList			*watchers; /*Watchers*/
@@ -136,8 +139,10 @@ static void heartrate_destroy(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);
+	}
 
 	if (hr->watchers != NULL)
 		g_slist_free_full(hr->watchers, watcher_remove);
@@ -388,6 +393,14 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 	}
 }
 
+static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	if (len < MIN_NOTIFICATION_LEN) {
+		error("Bad pdu received");
+		return;
+	}
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct heartrate *hr = user_data;
@@ -396,6 +409,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);
+
 	if (hr->chars == NULL)
 		gatt_discover_char(hr->attrib, hr->svc_range->start,
 						hr->svc_range->end, NULL,
@@ -408,6 +424,8 @@ static void attio_disconnected_cb(gpointer user_data)
 
 	DBG("GATT Disconnected");
 
+	g_attrib_unregister(hr->attrib, hr->attionotid);
+	hr->attionotid = 0;
 	g_attrib_unref(hr->attrib);
 	hr->attrib = NULL;
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 07/13] heartrate: Process Heart Rate Characteristics
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Read and store Sensor Location characteristic.

---
 lib/uuid.h                     |    2 ++
 profiles/heartrate/heartrate.c |   46 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 5d81856..5d1e091 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -65,6 +65,8 @@ extern "C" {
 
 #define HEART_RATE_UUID		"0000180d-0000-1000-8000-00805f9b34fb"
 #define HEART_RATE_MEASUREMENT_UUID	"00002a37-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_CONTROL_POINT_UUID	"00002a39-0000-1000-8000-00805f9b34fb"
+#define BODY_SENSOR_LOCATION_UUID	"00002a38-0000-1000-8000-00805f9b34fb"
 
 #define HEALTH_THERMOMETER_UUID		"00001809-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_MEASUREMENT_UUID	"00002a1c-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 31b4232..d0bcd57 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -42,6 +42,8 @@
 
 #define HEART_RATE_INTERFACE "org.bluez.HeartRate"
 
+#define SENSOR_LOCATION_SIZE 1
+
 struct heartrate {
 	struct btd_device	*dev;  /*Device reference*/
 	DBusConnection		*conn; /*DBus conn*/
@@ -50,6 +52,8 @@ struct heartrate {
 	struct att_range	*svc_range; /*Heart Rate range*/
 	GSList			*chars; /*Characteristics*/
 	GSList			*watchers; /*Watchers*/
+	gboolean		has_location;
+	uint8_t		location; /*Body Sensor location*/
 };
 
 struct characteristic {
@@ -238,6 +242,46 @@ static const GDBusMethodTable heartrate_methods[] = {
 	{ }
 };
 
+static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct heartrate *hr = ch->hr;
+	uint8_t value[SENSOR_LOCATION_SIZE];
+	ssize_t vlen;
+
+	if (status != 0) {
+		error("Body Sensor Location value 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 != 1) {
+		error("Invalid length for Body Sensor Location");
+		return;
+	}
+
+	hr->has_location = TRUE;
+	hr->location = value[0];
+}
+
+static void process_heartrate_char(struct characteristic *ch)
+{
+	if (g_strcmp0(ch->attr.uuid,
+				HEART_RATE_CONTROL_POINT_UUID) == 0)
+		DBG("Heart Rate Control Point reset not supported by client");
+	 else if (g_strcmp0(ch->attr.uuid,
+					BODY_SENSOR_LOCATION_UUID) == 0)
+		gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
+						read_sensor_location_cb, ch);
+}
+
 static void process_heartrate_desc(struct descriptor *desc)
 {
 	struct characteristic *ch = desc->ch;
@@ -325,6 +369,8 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 
 		hr->chars = g_slist_append(hr->chars, ch);
 
+		process_heartrate_char(ch);
+
 		start = c->value_handle + 1;
 
 		if (l->next != NULL) {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 06/13] heartrate: Add DBus connection logic
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Add DBus connection logic and watcher methods.

---
 profiles/heartrate/heartrate.c |  157 +++++++++++++++++++++++++++++++++++++++-
 profiles/heartrate/heartrate.h |    3 +-
 profiles/heartrate/main.c      |   18 ++++-
 profiles/heartrate/manager.c   |   19 ++++-
 profiles/heartrate/manager.h   |    2 +-
 5 files changed, 191 insertions(+), 8 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 4c313b2..31b4232 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -24,12 +24,15 @@
 #include <config.h>
 #endif
 
+#include <gdbus.h>
 #include <errno.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 "attio.h"
 #include "att.h"
@@ -37,12 +40,16 @@
 #include "heartrate.h"
 #include "log.h"
 
+#define HEART_RATE_INTERFACE "org.bluez.HeartRate"
+
 struct heartrate {
 	struct btd_device	*dev;  /*Device reference*/
+	DBusConnection		*conn; /*DBus conn*/
 	GAttrib			*attrib; /*GATT connection*/
 	guint			attioid; /*ATT watcher id*/
 	struct att_range	*svc_range; /*Heart Rate range*/
 	GSList			*chars; /*Characteristics*/
+	GSList			*watchers; /*Watchers*/
 };
 
 struct characteristic {
@@ -57,6 +64,13 @@ struct descriptor {
 	bt_uuid_t		uuid;
 };
 
+struct watcher {
+	struct heartrate	*hr;
+	guint			id;
+	char			*srv;
+	char			*path;
+};
+
 static GSList *hr_servers = NULL;
 
 static gint cmp_device(gconstpointer a, gconstpointer b)
@@ -70,6 +84,35 @@ 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 void watcher_remove(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
+}
+
+static void watcher_destroy(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_free(watcher->path);
+	g_free(watcher->srv);
+	g_free(watcher);
+}
+
 static void char_destroy(gpointer user_data)
 {
 	struct characteristic *c = user_data;
@@ -92,12 +135,109 @@ static void heartrate_destroy(gpointer user_data)
 	if (hr->attrib != NULL)
 		g_attrib_unref(hr->attrib);
 
+	if (hr->watchers != NULL)
+		g_slist_free_full(hr->watchers, watcher_remove);
+
 	btd_device_unref(hr->dev);
+	dbus_connection_unref(hr->conn);
 	g_free(hr->svc_range);
 	g_free(hr);
+}
+
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+	struct watcher *watcher = user_data;
+	struct heartrate *hr = watcher->hr;
+
+	DBG("Heart Rate watcher %s disconnected", watcher->path);
+
+	hr->watchers = g_slist_remove(hr->watchers, watcher);
+	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
+}
+
+static struct watcher *watcher_find(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);
+	watcher_destroy(match);
+
+	if (l != NULL)
+		return l->data;
+
+	return NULL;
+}
+
+static DBusMessage *watcher_register(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct heartrate *hr = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = watcher_find(hr->watchers, sender, path);
+	if (watcher != NULL)
+		return btd_error_already_exists(msg);
+
+	DBG("Heart Rate watcher %s registered", path);
+
+	watcher = g_new0(struct watcher, 1);
+	watcher->srv = g_strdup(sender);
+	watcher->path = g_strdup(path);
+	watcher->hr = hr;
+	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+						watcher, watcher_destroy);
+
+	hr->watchers = g_slist_prepend(hr->watchers, watcher);
 
+	return dbus_message_new_method_return(msg);
 }
 
+static DBusMessage *watcher_unregister(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct heartrate *hr = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = watcher_find(hr->watchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	DBG("Heart Rate watcher %s unregistered", path);
+
+	hr->watchers = g_slist_remove(hr->watchers, watcher);
+	g_dbus_remove_watch(watcher->hr->conn, watcher->id);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_methods[] = {
+	{ GDBUS_METHOD("RegisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			watcher_register) },
+	{ GDBUS_METHOD("UnregisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			watcher_unregister) },
+	{ }
+};
+
 static void process_heartrate_desc(struct descriptor *desc)
 {
 	struct characteristic *ch = desc->ch;
@@ -226,17 +366,29 @@ static void attio_disconnected_cb(gpointer user_data)
 	hr->attrib = NULL;
 }
 
-int heartrate_register(struct btd_device *device, struct gatt_primary *pattr)
+int heartrate_register(DBusConnection *connection, struct btd_device *device,
+						struct gatt_primary *pattr)
 {
+	const gchar *path = device_get_path(device);
 	struct heartrate *hr;
 
 	hr = g_new0(struct heartrate, 1);
 	hr->dev = btd_device_ref(device);
 
+	hr->conn = dbus_connection_ref(connection);
 	hr->svc_range = g_new0(struct att_range, 1);
 	hr->svc_range->start = pattr->range.start;
 	hr->svc_range->end = pattr->range.end;
 
+	if (!g_dbus_register_interface(hr->conn, path, HEART_RATE_INTERFACE,
+						heartrate_methods, NULL, NULL,
+						hr, heartrate_destroy)) {
+		error("D-Bus failed to register %s interface",
+							HEART_RATE_INTERFACE);
+		heartrate_destroy(hr);
+		return -EIO;
+	}
+
 	hr_servers = g_slist_prepend(hr_servers, hr);
 
 	hr->attioid = btd_device_add_attio_callback(device,
@@ -257,5 +409,6 @@ void heartrate_unregister(struct btd_device *device)
 	hr = l->data;
 	hr_servers = g_slist_remove(hr_servers, hr);
 
-	heartrate_destroy(hr);
+	g_dbus_unregister_interface(hr->conn, device_get_path(hr->dev),
+							HEART_RATE_INTERFACE);
 }
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 1d2ba89..08e2c92 100644
--- a/profiles/heartrate/heartrate.h
+++ b/profiles/heartrate/heartrate.h
@@ -20,5 +20,6 @@
  *
  */
 
-int heartrate_register(struct btd_device *device, struct gatt_primary *pattr);
+int heartrate_register(DBusConnection *connection, struct btd_device *device,
+						struct gatt_primary *tattr);
 void heartrate_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/main.c b/profiles/heartrate/main.c
index 40f34bc..8e8fde9 100644
--- a/profiles/heartrate/main.c
+++ b/profiles/heartrate/main.c
@@ -27,12 +27,15 @@
 #include <stdint.h>
 #include <glib.h>
 #include <errno.h>
+#include <gdbus.h>
 
 #include "plugin.h"
 #include "manager.h"
 #include "hcid.h"
 #include "log.h"
 
+static DBusConnection *connection = NULL;
+
 static int heartrate_init(void)
 {
 	if (!main_opts.gatt_enabled) {
@@ -40,12 +43,25 @@ static int heartrate_init(void)
 		return -ENOTSUP;
 	}
 
-	return heartrate_manager_init();
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (connection == NULL)
+		return -EIO;
+
+	if (heartrate_manager_init(connection) < 0) {
+		dbus_connection_unref(connection);
+		connection = NULL;
+		return -EIO;
+	}
+
+	return 0;
 }
 
 static void heartrate_exit(void)
 {
 	heartrate_manager_exit();
+
+	dbus_connection_unref(connection);
+	connection = NULL;
 }
 
 BLUETOOTH_PLUGIN_DEFINE(heartrate, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index 6ba059d..c373f86 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -32,6 +32,8 @@
 #include "heartrate.h"
 #include "manager.h"
 
+static DBusConnection *connection = NULL;
+
 static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
 {
 	const struct gatt_primary *prim = a;
@@ -54,7 +56,7 @@ static int heartrate_driver_probe(struct btd_device *device, GSList *uuids)
 
 	pattr = l->data;
 
-	return heartrate_register(device, pattr);
+	return heartrate_register(connection, device, pattr);
 }
 
 static void heartrate_driver_remove(struct btd_device *device)
@@ -69,12 +71,23 @@ static struct btd_device_driver heartrate_device_driver = {
 	.remove	= heartrate_driver_remove
 };
 
-int heartrate_manager_init(void)
+int heartrate_manager_init(DBusConnection *conn)
+
 {
-	return btd_register_device_driver(&heartrate_device_driver);
+	int ret;
+
+	ret = btd_register_device_driver(&heartrate_device_driver);
+	if (ret < 0)
+		return ret;
+
+	connection = dbus_connection_ref(conn);
+	return 0;
 }
 
 void heartrate_manager_exit(void)
 {
 	btd_unregister_device_driver(&heartrate_device_driver);
+
+	dbus_connection_unref(connection);
+	connection = NULL;
 }
diff --git a/profiles/heartrate/manager.h b/profiles/heartrate/manager.h
index de799f6..5e9c8b2 100644
--- a/profiles/heartrate/manager.h
+++ b/profiles/heartrate/manager.h
@@ -20,5 +20,5 @@
  *
  */
 
-int heartrate_manager_init(void);
+int heartrate_manager_init(DBusConnection *conn);
 void heartrate_manager_exit(void);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 05/13] heartrate: Process Heart Rate Descriptors
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Process Heart Rate service descriptors and write
client specific characteristic configuration.

---
 lib/uuid.h                     |    1 +
 profiles/heartrate/heartrate.c |   34 +++++++++++++++++++++++++++++++++-
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/lib/uuid.h b/lib/uuid.h
index 99b88cc..5d81856 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,7 @@ extern "C" {
 #define SAP_UUID		"0000112D-0000-1000-8000-00805f9b34fb"
 
 #define HEART_RATE_UUID		"0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_MEASUREMENT_UUID	"00002a37-0000-1000-8000-00805f9b34fb"
 
 #define HEALTH_THERMOMETER_UUID		"00001809-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_MEASUREMENT_UUID	"00002a1c-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index e917f27..4c313b2 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -70,12 +70,21 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static void char_destroy(gpointer user_data)
+{
+	struct characteristic *c = user_data;
+
+	g_slist_free_full(c->desc, g_free);
+
+	g_free(c);
+}
+
 static void heartrate_destroy(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
 
 	if (hr->chars != NULL)
-		g_slist_free_full(hr->chars, g_free);
+		g_slist_free_full(hr->chars, char_destroy);
 
 	if (hr->attioid > 0)
 		btd_device_remove_attio_callback(hr->dev, hr->attioid);
@@ -89,6 +98,28 @@ static void heartrate_destroy(gpointer user_data)
 
 }
 
+static void process_heartrate_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,
+				HEART_RATE_MEASUREMENT_UUID) == 0) {
+
+		DBG("Heart Rate Measurement notification" \
+						" supported");
+		return;
+	}
+
+	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+	DBG("Ignored descriptor %s in characteristic %s", uuidstr,
+							ch->attr.uuid);
+}
+
 static void discover_desc_cb(guint8 status, const guint8 *pdu,
 					guint16 len, gpointer user_data)
 {
@@ -122,6 +153,7 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
 			desc->uuid = att_get_uuid128(&value[2]);
 
 		ch->desc = g_slist_append(ch->desc, desc);
+		process_heartrate_desc(desc);
 	}
 
 	att_data_list_free(list);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 04/13] heartrate: Discover Characteristic Descriptors
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Discover and store each of the Heart Rate Service
characteristic descriptors.

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

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 1114cff..e917f27 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -47,9 +47,16 @@ struct heartrate {
 
 struct characteristic {
 	struct gatt_char	attr; /*Characteristic*/
+	GSList			*desc; /*Descriptors*/
 	struct heartrate	*hr; /*Parent Heart Rate Service*/
 };
 
+struct descriptor {
+	struct characteristic	*ch;
+	uint16_t		handle;
+	bt_uuid_t		uuid;
+};
+
 static GSList *hr_servers = NULL;
 
 static gint cmp_device(gconstpointer a, gconstpointer b)
@@ -82,6 +89,44 @@ static void heartrate_destroy(gpointer user_data)
 
 }
 
+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_heartrate_cb(GSList *characteristics, guint8 status,
 							gpointer user_data)
 {
@@ -97,6 +142,7 @@ static void configure_heartrate_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 +152,21 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
 		ch->hr = hr;
 
 		hr->chars = g_slist_append(hr->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 != hr->svc_range->end) {
+			end = hr->svc_range->end;
+		} else {
+			continue;
+		}
+
+		gatt_find_info(hr->attrib, start, end, discover_desc_cb, ch);
 	}
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 03/13] heartrate: Add conn logic and attio callbacks
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Handle connection to the remote device when the
Heart Rate plugin is loaded.

---
 profiles/heartrate/heartrate.c |   86 +++++++++++++++++++++++++++++++++++++++-
 profiles/heartrate/heartrate.h |    2 +-
 profiles/heartrate/manager.c   |   22 +++++++++-
 3 files changed, 107 insertions(+), 3 deletions(-)

diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 9bd93c5..1114cff 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -30,10 +30,24 @@
 
 #include "adapter.h"
 #include "device.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gatt.h"
 #include "heartrate.h"
+#include "log.h"
 
 struct heartrate {
 	struct btd_device	*dev;  /*Device reference*/
+	GAttrib			*attrib; /*GATT connection*/
+	guint			attioid; /*ATT watcher id*/
+	struct att_range	*svc_range; /*Heart Rate range*/
+	GSList			*chars; /*Characteristics*/
+};
+
+struct characteristic {
+	struct gatt_char	attr; /*Characteristic*/
+	struct heartrate	*hr; /*Parent Heart Rate Service*/
 };
 
 static GSList *hr_servers = NULL;
@@ -53,19 +67,89 @@ static void heartrate_destroy(gpointer user_data)
 {
 	struct heartrate *hr = user_data;
 
+	if (hr->chars != NULL)
+		g_slist_free_full(hr->chars, g_free);
+
+	if (hr->attioid > 0)
+		btd_device_remove_attio_callback(hr->dev, hr->attioid);
+
+	if (hr->attrib != NULL)
+		g_attrib_unref(hr->attrib);
+
 	btd_device_unref(hr->dev);
+	g_free(hr->svc_range);
 	g_free(hr);
+
+}
+
+static void configure_heartrate_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover heartrate 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->hr = hr;
+
+		hr->chars = g_slist_append(hr->chars, ch);
+	}
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("GATT Connected");
+
+	hr->attrib = g_attrib_ref(attrib);
+
+	if (hr->chars == NULL)
+		gatt_discover_char(hr->attrib, hr->svc_range->start,
+						hr->svc_range->end, NULL,
+						configure_heartrate_cb, hr);
 }
 
-int heartrate_register(struct btd_device *device)
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	DBG("GATT Disconnected");
+
+	g_attrib_unref(hr->attrib);
+	hr->attrib = NULL;
+}
+
+int heartrate_register(struct btd_device *device, struct gatt_primary *pattr)
 {
 	struct heartrate *hr;
 
 	hr = g_new0(struct heartrate, 1);
 	hr->dev = btd_device_ref(device);
 
+	hr->svc_range = g_new0(struct att_range, 1);
+	hr->svc_range->start = pattr->range.start;
+	hr->svc_range->end = pattr->range.end;
+
 	hr_servers = g_slist_prepend(hr_servers, hr);
 
+	hr->attioid = btd_device_add_attio_callback(device,
+						attio_connected_cb,
+						attio_disconnected_cb ,
+						hr);
 	return 0;
 }
 void heartrate_unregister(struct btd_device *device)
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 8d4271c..1d2ba89 100644
--- a/profiles/heartrate/heartrate.h
+++ b/profiles/heartrate/heartrate.h
@@ -20,5 +20,5 @@
  *
  */
 
-int heartrate_register(struct btd_device *device);
+int heartrate_register(struct btd_device *device, struct gatt_primary *pattr);
 void heartrate_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index da6c7ef..6ba059d 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -32,9 +32,29 @@
 #include "heartrate.h"
 #include "manager.h"
 
+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);
+}
+
 static int heartrate_driver_probe(struct btd_device *device, GSList *uuids)
 {
-	return heartrate_register(device);
+	struct gatt_primary *pattr;
+	GSList *primaries, *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, HEART_RATE_UUID,
+							primary_uuid_cmp);
+	if (l == NULL)
+		return -EINVAL;
+
+	pattr = l->data;
+
+	return heartrate_register(device, pattr);
 }
 
 static void heartrate_driver_remove(struct btd_device *device)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 02/13] heartrate: Add Heart Rate Service GATT client skeleton
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

Add initial support for the Heart Rate Service GATT
Client side.

---
 Makefile.am                    |   10 ++++-
 lib/uuid.h                     |    2 +
 profiles/heartrate/heartrate.c |   84 ++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |   24 ++++++++++++
 profiles/heartrate/main.c      |   52 +++++++++++++++++++++++++
 profiles/heartrate/manager.c   |   60 ++++++++++++++++++++++++++++
 profiles/heartrate/manager.h   |   24 ++++++++++++
 7 files changed, 254 insertions(+), 2 deletions(-)
 create mode 100644 profiles/heartrate/heartrate.c
 create mode 100644 profiles/heartrate/heartrate.h
 create mode 100644 profiles/heartrate/main.c
 create mode 100644 profiles/heartrate/manager.c
 create mode 100644 profiles/heartrate/manager.h

diff --git a/Makefile.am b/Makefile.am
index 45a811c..594ea56 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -211,7 +211,8 @@ builtin_sources += profiles/health/hdp_main.c profiles/health/hdp_types.h \
 endif
 
 if GATTMODULES
-builtin_modules += thermometer alert time gatt_example proximity deviceinfo
+builtin_modules += thermometer alert time gatt_example proximity deviceinfo \
+	heartrate
 builtin_sources += profiles/thermometer/main.c \
 			profiles/thermometer/manager.h \
 			profiles/thermometer/manager.c \
@@ -237,7 +238,12 @@ builtin_sources += profiles/thermometer/main.c \
 			profiles/deviceinfo/manager.h \
 			profiles/deviceinfo/manager.c \
 			profiles/deviceinfo/deviceinfo.h \
-			profiles/deviceinfo/deviceinfo.c
+			profiles/deviceinfo/deviceinfo.c \
+			profiles/heartrate/main.c \
+			profiles/heartrate/manager.c \
+			profiles/heartrate/manager.h \
+			profiles/heartrate/heartrate.c \
+			profiles/heartrate/heartrate.h
 endif
 
 builtin_modules += formfactor
diff --git a/lib/uuid.h b/lib/uuid.h
index 2c2b351..99b88cc 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -63,6 +63,8 @@ extern "C" {
 
 #define SAP_UUID		"0000112D-0000-1000-8000-00805f9b34fb"
 
+#define HEART_RATE_UUID		"0000180d-0000-1000-8000-00805f9b34fb"
+
 #define HEALTH_THERMOMETER_UUID		"00001809-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_MEASUREMENT_UUID	"00002a1c-0000-1000-8000-00805f9b34fb"
 #define TEMPERATURE_TYPE_UUID		"00002a1d-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
new file mode 100644
index 0000000..9bd93c5
--- /dev/null
+++ b/profiles/heartrate/heartrate.c
@@ -0,0 +1,84 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 <errno.h>
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "heartrate.h"
+
+struct heartrate {
+	struct btd_device	*dev;  /*Device reference*/
+};
+
+static GSList *hr_servers = NULL;
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+	const struct heartrate *hr = a;
+	const struct btd_device *dev = b;
+
+	if (dev == hr->dev)
+		return 0;
+
+	return -1;
+}
+
+static void heartrate_destroy(gpointer user_data)
+{
+	struct heartrate *hr = user_data;
+
+	btd_device_unref(hr->dev);
+	g_free(hr);
+}
+
+int heartrate_register(struct btd_device *device)
+{
+	struct heartrate *hr;
+
+	hr = g_new0(struct heartrate, 1);
+	hr->dev = btd_device_ref(device);
+
+	hr_servers = g_slist_prepend(hr_servers, hr);
+
+	return 0;
+}
+void heartrate_unregister(struct btd_device *device)
+{
+	struct heartrate *hr;
+	GSList *l;
+
+	l = g_slist_find_custom(hr_servers, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	hr = l->data;
+	hr_servers = g_slist_remove(hr_servers, hr);
+
+	heartrate_destroy(hr);
+}
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
new file mode 100644
index 0000000..8d4271c
--- /dev/null
+++ b/profiles/heartrate/heartrate.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 heartrate_register(struct btd_device *device);
+void heartrate_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/main.c b/profiles/heartrate/main.c
new file mode 100644
index 0000000..40f34bc
--- /dev/null
+++ b/profiles/heartrate/main.c
@@ -0,0 +1,52 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static int heartrate_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		DBG("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return heartrate_manager_init();
+}
+
+static void heartrate_exit(void)
+{
+	heartrate_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(heartrate, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+					heartrate_init, heartrate_exit)
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
new file mode 100644
index 0000000..da6c7ef
--- /dev/null
+++ b/profiles/heartrate/manager.c
@@ -0,0 +1,60 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 <gdbus.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "heartrate.h"
+#include "manager.h"
+
+static int heartrate_driver_probe(struct btd_device *device, GSList *uuids)
+{
+	return heartrate_register(device);
+}
+
+static void heartrate_driver_remove(struct btd_device *device)
+{
+	heartrate_unregister(device);
+}
+
+static struct btd_device_driver heartrate_device_driver = {
+	.name	= "heart-rate-driver",
+	.uuids	= BTD_UUIDS(HEART_RATE_UUID),
+	.probe	= heartrate_driver_probe,
+	.remove	= heartrate_driver_remove
+};
+
+int heartrate_manager_init(void)
+{
+	return btd_register_device_driver(&heartrate_device_driver);
+}
+
+void heartrate_manager_exit(void)
+{
+	btd_unregister_device_driver(&heartrate_device_driver);
+}
diff --git a/profiles/heartrate/manager.h b/profiles/heartrate/manager.h
new file mode 100644
index 0000000..de799f6
--- /dev/null
+++ b/profiles/heartrate/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  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 heartrate_manager_init(void);
+void heartrate_manager_exit(void);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 01/13] Heart Rate Profile API
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat, Santiago Carot-Nemesio
In-Reply-To: <1344870497-6929-1-git-send-email-rafal.garbat@tieto.com>

From: Santiago Carot-Nemesio <sancane@gmail.com>

---
 doc/heartrate-api.txt |   74 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 doc/heartrate-api.txt

diff --git a/doc/heartrate-api.txt b/doc/heartrate-api.txt
new file mode 100644
index 0000000..2738e20
--- /dev/null
+++ b/doc/heartrate-api.txt
@@ -0,0 +1,74 @@
+BlueZ D-Bus Heart Rate API description
+****************************************
+
+Copyright (C) 2012	Santiago Carot-Nemesio <sancane@gmail.com>
+
+Heart Rate Profile hierarchy
+============================
+
+Service		org.bluez
+Interface	org.bluez.HeartRate
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods		dict GetProperties()
+
+			Returns all properties for the interface. See the
+			Properties section for the available properties.
+
+		RegisterWatcher(object agent)
+
+			Registers a watcher to monitor heart rate measurements.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		UnregisterWatcher(object agent)
+
+			Unregisters a watcher.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+					org.bluez.Error.NotFound
+
+		Reset()
+
+			Restart the accumulation of energy expended from zero.
+
+			Possible Errors: org.bluez.Error.NotSupported
+
+Properties	boolean ResetSupported [readonly]
+
+			True if energy expended is supported.
+
+Heart Rate Watcher hierarchy
+
+============================
+Service		unique name
+Interface	org.bluez.HeartRateWatcher
+Object path	freely definable
+
+Methods		void MeasurementReceived(dict measure)
+
+			This callback is called whenever a heart rate
+			measurement is received from the heart rate device.
+			The unit for the Value is expressed in beats per
+			minute (bpm). The energy field is optional and
+			represents the accumulated energy expended in
+			kilo Joules since last time it was reset. Furthermore,
+			the device will be automatically reset when it
+			is needed.
+			The Contact field, if present, indicates
+			that the device supports contact sensor, besides it
+			will be true if skin contact is detected. The optional
+			interval field is an array containing RR-Interval
+			values which represent the time between two R-Wave
+			detections, where the RR-Interval value 0 is older
+			than the value 1 and so on.
+
+			Dict is defined as below:
+			{
+				"Value" : uint16,
+				"Energy" : uint16,
+				"Contact" : boolean,
+				"Location" : ("Other", "Chest", "Wrist","Finger",
+					"Hand", "Earlobe", "Foot"),
+				"Interval" : array{uint16}
+			}
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v2 00/13] Add Heart Rate Service
From: Rafal Garbat @ 2012-08-13 15:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rafal.garbat

Add support for GATT Client Heart Rate Service.

This patchset adds Heart Rate client service, exposed on Heart Rate 
DBus API by Santiago Carot-Nemesio <sancane@gmail.com>. It allows 
registering and unregistering watchers, handling measurement notifications
and reseting Control Point. It bases on Thermometer service. Python 
test script is included. Tested against Polar H7 Heart Rate Sensor.

Patchset v2 fixes some bugs in parsing measurement notification
and checking pdu length. Test script has been extended by 
Reset cmd support. Enabling measurement has been disabled by default
at the new connection.

Rafal Garbat (12):
  heartrate: Add Heart Rate Service GATT client skeleton
  heartrate: Add conn logic and attio callbacks
  heartrate: Discover Characteristic Descriptors
  heartrate: Process Heart Rate Descriptors
  heartrate: Add DBus connection logic
  heartrate: Process Heart Rate Characteristics
  heartrate: Add notification support
  heartrate: Process measurements
  heartrate: Add support for Control Point Reset
  heartrate: Add GetProperties method handle
  heartrate: Add org.bluez.HeartRateWatcher iface to default policy
  heartrate: Add Heart Rate test script

Santiago Carot-Nemesio (1):
  Heart Rate Profile API

 Makefile.am                    |   10 +-
 Makefile.tools                 |    4 +-
 doc/heartrate-api.txt          |   74 ++++
 lib/uuid.h                     |    5 +
 profiles/heartrate/heartrate.c |  868 ++++++++++++++++++++++++++++++++++++++++
 profiles/heartrate/heartrate.h |   25 ++
 profiles/heartrate/main.c      |   68 ++++
 profiles/heartrate/manager.c   |   93 +++++
 profiles/heartrate/manager.h   |   24 ++
 src/bluetooth.conf             |    1 +
 test/test-heartrate            |   91 +++++
 11 files changed, 1259 insertions(+), 4 deletions(-)
 create mode 100644 doc/heartrate-api.txt
 create mode 100644 profiles/heartrate/heartrate.c
 create mode 100644 profiles/heartrate/heartrate.h
 create mode 100644 profiles/heartrate/main.c
 create mode 100644 profiles/heartrate/manager.c
 create mode 100644 profiles/heartrate/manager.h
 create mode 100755 test/test-heartrate

-- 
1.7.9.5


^ permalink raw reply

* Re: [PATCH] Bluetooth: debug: Correct the PSM printing
From: Syam Sidhardhan @ 2012-08-13 14:37 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, jaganath.k
In-Reply-To: <20120806094607.GB2819@aemeltch-MOBL1>

Hi,

----- Original Message ----- 
From: "Andrei Emeltchenko" <andrei.emeltchenko.news@gmail.com>
To: "Syam Sidhardhan" <s.syam@samsung.com>
Cc: <linux-bluetooth@vger.kernel.org>; <jaganath.k@samsung.com>
Sent: Monday, August 06, 2012 3:16 PM
Subject: Re: [PATCH] Bluetooth: debug: Correct the PSM printing


> Hi Syam,
>
> On Fri, Jul 27, 2012 at 11:51:22PM +0530, Syam Sidhardhan wrote:
>> Earlier we were printing chan->psm before assigning any value.
>>
>> Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
>
> Acked-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
>> ---
>>  net/bluetooth/l2cap_core.c |    2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index bedc960..0912a63 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -1447,7 +1447,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, 
>> __le16 psm, u16 cid,
>>  int err;
>>
>>  BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst),
>> -        dst_type, __le16_to_cpu(chan->psm));
>> +        dst_type, __le16_to_cpu(psm));
>>
>>  hdev = hci_get_route(dst, src);
>>  if (!hdev)
>> -- 
>> 1.7.4.1
>>

ping..

Regards,
Syam 


^ permalink raw reply

* Re: [PATCH] Bluetooth: Use kref for l2cap channel reference counting
From: Syam Sidhardhan @ 2012-08-13 14:35 UTC (permalink / raw)
  To: Syam Sidhardhan, linux-bluetooth; +Cc: jaganath.k
In-Reply-To: <1343413282-8901-1-git-send-email-s.syam@samsung.com>

Hi,

----- Original Message ----- 
From: "Syam Sidhardhan" <s.syam@samsung.com>
To: <linux-bluetooth@vger.kernel.org>
Cc: <jaganath.k@samsung.com>; "Syam Sidhardhan" <s.syam@samsung.com>
Sent: Friday, July 27, 2012 11:51 PM
Subject: [PATCH] Bluetooth: Use kref for l2cap channel reference counting


> This patch changes the struct l2cap_chan and associated code to use
> kref api for object refcounting and freeing.
>
> Suggested-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> Signed-off-by: Jaganath Kanakkassery <jaganath.k@samsung.com>
> Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
> ---
> include/net/bluetooth/l2cap.h |    3 +--
> net/bluetooth/l2cap_core.c    |   15 ++++++++-------
> 2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index d206296..7ed8e35 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -433,11 +433,10 @@ struct l2cap_chan {
>  struct sock *sk;
>
>  struct l2cap_conn *conn;
> + struct kref kref;
>
>  __u8 state;
>
> - atomic_t refcnt;
> -
>  __le16 psm;
>  __u16 dcid;
>  __u16 scid;
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 6dde7c5..bedc960 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -406,7 +406,7 @@ struct l2cap_chan *l2cap_chan_create(void)
>
>  chan->state = BT_OPEN;
>
> - atomic_set(&chan->refcnt, 1);
> + kref_init(&chan->kref);
>
>  /* This flag is cleared in l2cap_chan_ready() */
>  set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
> @@ -416,8 +416,10 @@ struct l2cap_chan *l2cap_chan_create(void)
>  return chan;
> }
>
> -static void l2cap_chan_destroy(struct l2cap_chan *chan)
> +static void l2cap_chan_destroy(struct kref *kref)
> {
> + struct l2cap_chan *chan = container_of(kref, struct l2cap_chan, kref);
> +
>  BT_DBG("chan %p", chan);
>
>  write_lock(&chan_list_lock);
> @@ -429,17 +431,16 @@ static void l2cap_chan_destroy(struct l2cap_chan 
> *chan)
>
> void l2cap_chan_hold(struct l2cap_chan *c)
> {
> - BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
> + BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount));
>
> - atomic_inc(&c->refcnt);
> + kref_get(&c->kref);
> }
>
> void l2cap_chan_put(struct l2cap_chan *c)
> {
> - BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
> + BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount));
>
> - if (atomic_dec_and_test(&c->refcnt))
> - l2cap_chan_destroy(c);
> + kref_put(&c->kref, l2cap_chan_destroy);
> }
>
> void l2cap_chan_set_defaults(struct l2cap_chan *chan)
> -- 

ping

Regards,
Syam


^ permalink raw reply

* Re: [PATCH BlueZ v0] gdbus: Fix compilation error if macro "error" is defined
From: Lucas De Marchi @ 2012-08-13 14:03 UTC (permalink / raw)
  To: Jaganath Kanakkassery; +Cc: linux-bluetooth
In-Reply-To: <1343816803-16228-1-git-send-email-jaganath.k@samsung.com>

On Wed, Aug 1, 2012 at 7:26 AM, Jaganath Kanakkassery
<jaganath.k@samsung.com> wrote:
> The variable "signature" used in error is not defined.
> ---
> v0 -> Made error message as per Lucas's suggestion
>
>  gdbus/object.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/gdbus/object.c b/gdbus/object.c
> index 900e7ab..9689006 100644
> --- a/gdbus/object.c
> +++ b/gdbus/object.c
> @@ -645,8 +645,8 @@ static dbus_bool_t emit_signal_valist(DBusConnection *conn,
>                 goto fail;
>
>         if (g_dbus_args_have_signature(args, signal) == FALSE) {
> -               error("%s.%s: expected signature'%s' but got '%s'",
> -                               interface, name, args, signature);
> +               error("%s.%s: got unexpected signature '%s'", interface, name,
> +                                       dbus_message_get_signature(signal));
>                 ret = FALSE;
>                 goto fail;

Ack.

Lucas De Marchi

^ permalink raw reply

* Re: [RFCv2 02/20] Bluetooth: Process HCI callbacks in a workqueue
From: Andrei Emeltchenko @ 2012-08-13 13:51 UTC (permalink / raw)
  To: Gustavo Padovan, linux-bluetooth
In-Reply-To: <20120724203647.GB20029@joana>

Hi Gustavo,

On Tue, Jul 24, 2012 at 05:36:47PM -0300, Gustavo Padovan wrote:
> Hi Andrei,
> 
> * Andrei Emeltchenko <Andrei.Emeltchenko.news@gmail.com> [2012-07-24 16:21:43 +0300]:
> 
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> > 
> > Use workqueue to process HCI callbacks.
> 
> Could elaborate more on why a new workqueue is needed, I tried to figure this
> out this but was unable to find a user for this function in the following
> patches.

workqueue processing was removed in RFCv3.

Best regards 
Andrei Emeltchenko 

^ permalink raw reply

* [RFCv3 20/20] Bluetooth: AMP: Process physical link complete event
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Add new hci_conn for representing AMP physical link.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/hci.h |    1 +
 net/bluetooth/hci_event.c   |   43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 7335fe1..581b9c3 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -207,6 +207,7 @@ enum {
 #define ESCO_LINK	0x02
 /* Low Energy links do not have defined link type. Use invented one */
 #define LE_LINK		0x80
+#define AMP_LINK	0x81
 
 /* LMP features */
 #define LMP_3SLOT	0x01
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index bb52a0e..66a0df2 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3394,6 +3394,45 @@ unlock:
 	hci_dev_unlock(hdev);
 }
 
+static void hci_phy_link_complete_evt(struct hci_dev *hdev,
+				      struct sk_buff *skb)
+{
+	struct hci_ev_phy_link_complete *ev = (void *) skb->data;
+	struct hci_conn *conn;
+	struct phy_link *plink;
+
+	BT_DBG("%s handle 0x%2.2x status 0x%2.2x", hdev->name, ev->phy_handle,
+	       ev->status);
+
+	if (ev->status)
+		return;
+
+	plink = phylink_lookup_by_handle(ev->phy_handle);
+	if (!plink)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_add(hdev, AMP_LINK, BDADDR_ANY);
+	if (conn) {
+		conn->handle = ev->phy_handle;
+		conn->state = BT_CONNECTED;
+
+		hci_conn_hold(conn);
+		conn->disc_timeout = HCI_DISCONN_TIMEOUT/2;
+		hci_conn_put(conn);
+
+		hci_conn_hold_device(conn);
+		hci_conn_add_sysfs(conn);
+	} else {
+		BT_ERR("Cannot add connection");
+	}
+
+	hci_dev_unlock(hdev);
+
+	phylink_put(plink);
+}
+
 static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -3716,6 +3755,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_remote_oob_data_request_evt(hdev, skb);
 		break;
 
+	case HCI_EV_PHY_LINK_COMPLETE:
+		hci_phy_link_complete_evt(hdev, skb);
+		break;
+
 	case HCI_EV_NUM_COMP_BLOCKS:
 		hci_num_comp_blocks_evt(hdev, skb);
 		break;
-- 
1.7.9.5


^ permalink raw reply related

* [RFCv3 19/20] Bluetooth: AMP: Process Chan Selected event
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Channel Selected event indicates that link information data is available.
Read it with Read Local AMP Assoc command. The data shall be sent in the
A2MP Create Physical Link Request.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |    1 +
 include/net/bluetooth/amp.h      |    2 ++
 include/net/bluetooth/hci_core.h |    6 ++++
 net/bluetooth/a2mp.c             |    2 +-
 net/bluetooth/amp.c              |   71 ++++++++++++++++++++++++++++++++++----
 net/bluetooth/hci_core.c         |   14 ++++----
 net/bluetooth/hci_event.c        |   23 ++++++++++++
 7 files changed, 105 insertions(+), 14 deletions(-)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index eaaa3e4..c8ecbe5 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -131,6 +131,7 @@ extern struct mutex amp_mgr_list_lock;
 
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
+u8 __next_ident(struct amp_mgr *mgr);
 struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
 				       struct sk_buff *skb);
 void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index b376cc3..ab4e195 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -19,6 +19,8 @@
 void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
 void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
 void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
+				   struct phy_link *plink);
 void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
 			struct phy_link *plink);
 
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index fbf929a..e106e17 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1117,6 +1117,12 @@ int hci_cancel_le_scan(struct hci_dev *hdev);
 
 u8 bdaddr_to_le(u8 bdaddr_type);
 struct hci_cb_cmd *hci_callback_find(struct hci_dev *hdev, __u16 opcode);
+int hci_callback_add(struct hci_dev *hdev, __u16 opcode,
+		     void (*cb)(struct hci_dev *hdev, struct hci_cb_cmd *cmd),
+		     void *opt,
+		     void (*destructor)(struct hci_dev *hdev,
+					struct hci_cb_cmd *cmd),
+		     gfp_t flags);
 int hci_callback_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
 			  void *param,
 			  void (*cb)(struct hci_dev *hdev,
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 4b6350f..c92ab54 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -70,7 +70,7 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
 	kfree(cmd);
 }
 
-static u8 __next_ident(struct amp_mgr *mgr)
+u8 __next_ident(struct amp_mgr *mgr)
 {
 	if (++mgr->ident == 0)
 		mgr->ident = 1;
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 409ca3d..72991c3 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -124,7 +124,59 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
 			      cb_destructor, GFP_KERNEL);
 }
 
-static void amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
+/* Read Local AMP Assoc final link information data callback */
+static void amp_read_loc_assoc_complete_final_cb(struct hci_dev *hdev,
+						 struct hci_cb_cmd *cmd)
+{
+	struct amp_mgr *mgr = cmd->opt;
+	struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+	struct a2mp_physlink_req *req;
+	struct phy_link *plink;
+	size_t len;
+
+	len = sizeof(*req) + loc_assoc->len;
+
+	BT_DBG("%s mgr %p assoc_len %zu", hdev->name, mgr, len);
+
+	req = kzalloc(len, GFP_KERNEL);
+	if (!req)
+		return;
+
+	plink = phylink_lookup(mgr, hdev->id, 0);
+	if (!plink)
+		goto clean;
+
+	req->local_id = plink->local_id;
+	req->remote_id = plink->remote_id;
+	memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len);
+
+	phylink_put(plink);
+
+	a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req);
+
+clean:
+	kfree(req);
+}
+
+void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
+				   struct phy_link *plink)
+{
+	struct hci_cp_read_local_amp_assoc cp;
+	struct amp_mgr *mgr = plink->mgr;
+
+	cp.phy_handle = plink->handle;
+	cp.len_so_far = cpu_to_le16(0);
+	cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+
+	amp_mgr_get(mgr);
+
+	/* Read Local AMP Assoc final link information data */
+	hci_callback_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp),
+			      &cp, amp_read_loc_assoc_complete_final_cb,
+			      mgr, cb_destructor, GFP_KERNEL);
+}
+
+static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
 				     struct phy_link *plink);
 
 static void amp_write_rem_assoc_cs_cb(struct hci_dev *hdev,
@@ -142,12 +194,16 @@ static void amp_write_rem_assoc_cs_cb(struct hci_dev *hdev,
 	if (!plink)
 		return;
 
-	amp_write_rem_assoc_frag(hdev, mgr, plink);
+	/* All fragments are written */
+	if (amp_write_rem_assoc_frag(hdev, mgr, plink)) {
+		/* Expect Channel Select event */
+	}
 
 	phylink_put(plink);
 }
 
-static void amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
+/* Write AMP Assoc data fragments, returns true with last fragment written*/
+static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
 				     struct phy_link *plink)
 {
 	struct hci_cp_write_remote_amp_assoc *cp;
@@ -156,7 +212,7 @@ static void amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
 
 	ctrl = amp_ctrl_lookup(mgr, plink->remote_id);
 	if (!ctrl)
-		return;
+		return false;
 
 	if (!ctrl->assoc_rem_len) {
 		BT_DBG("all fragments are written");
@@ -164,7 +220,7 @@ static void amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
 		ctrl->assoc_len_so_far = 0;
 
 		amp_ctrl_put(ctrl);
-		return;
+		return true;
 	}
 
 	frag_len = min_t(u16, 248, ctrl->assoc_rem_len);
@@ -173,7 +229,7 @@ static void amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
 	cp = kzalloc(len, GFP_KERNEL);
 	if (!cp) {
 		amp_ctrl_put(ctrl);
-		return;
+		return false;
 	}
 
 	BT_DBG("plink %p ctrl %p frag_len %u assoc_len %u rem_len %u",
@@ -196,6 +252,8 @@ static void amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
 			      GFP_KERNEL);
 
 	kfree(cp);
+
+	return false;
 }
 
 static void amp_create_phylink_cs_cb(struct hci_dev *hdev,
@@ -209,6 +267,7 @@ static void amp_create_phylink_cs_cb(struct hci_dev *hdev,
 	/* Write Remote AMP Assoc */
 	plink = phylink_lookup(mgr, hdev->id, 0);
 	if (plink) {
+		hci_dev_hold(hdev);
 		amp_write_rem_assoc_frag(hdev, mgr, plink);
 		phylink_put(plink);
 	}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 60ba01f..688ea40 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2121,13 +2121,13 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 	return 0;
 }
 
-static int hci_callback_add(struct hci_dev *hdev, __u16 opcode,
-			    void (*cb)(struct hci_dev *hdev,
-				       struct hci_cb_cmd *cmd),
-			    void *opt,
-			    void (*destructor)(struct hci_dev *hdev,
-					       struct hci_cb_cmd *cmd),
-			    gfp_t flags)
+int hci_callback_add(struct hci_dev *hdev, __u16 opcode,
+		     void (*cb)(struct hci_dev *hdev,
+				struct hci_cb_cmd *cmd),
+		     void *opt,
+		     void (*destructor)(struct hci_dev *hdev,
+					struct hci_cb_cmd *cmd),
+		     gfp_t flags)
 {
 	struct hci_cb_cmd *cmd;
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 2f54e76..bb52a0e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3533,6 +3533,25 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	}
 }
 
+static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_ev_channel_selected *ev = (void *) skb->data;
+	__u8 phy_handle = ev->phy_handle;
+	struct phy_link *plink;
+
+	BT_DBG("%s handle 0x%2.2x", hdev->name, phy_handle);
+
+	skb_pull(skb, sizeof(*ev));
+
+	plink = phylink_lookup_by_handle(phy_handle);
+	if (!plink)
+		return;
+
+	amp_read_loc_assoc_final_data(hdev, plink);
+
+	phylink_put(plink);
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_event_hdr *hdr = (void *) skb->data;
@@ -3689,6 +3708,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_le_meta_evt(hdev, skb);
 		break;
 
+	case HCI_EV_CHANNEL_SELECTED:
+		hci_chan_selected_evt(hdev, skb);
+		break;
+
 	case HCI_EV_REMOTE_OOB_DATA_REQUEST:
 		hci_remote_oob_data_request_evt(hdev, skb);
 		break;
-- 
1.7.9.5


^ permalink raw reply related

* [RFCv3 18/20] Bluetooth: A2MP: Create amp_mgr global list
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Create amp_mgr_list which is used for query for phy_link by
phy_link handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    4 ++++
 include/net/bluetooth/pal.h  |    1 +
 net/bluetooth/a2mp.c         |   12 ++++++++++++
 net/bluetooth/pal.c          |   28 ++++++++++++++++++++++++++++
 4 files changed, 45 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index f3f0d7e..eaaa3e4 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -20,6 +20,7 @@
 #define A2MP_FEAT_EXT	0x8000
 
 struct amp_mgr {
+	struct list_head	list;
 	struct l2cap_conn	*l2cap_conn;
 	struct l2cap_chan	*a2mp_chan;
 	struct l2cap_chan	*bredr_chan;
@@ -125,6 +126,9 @@ struct a2mp_physlink_rsp {
 #define A2MP_STATUS_PHYS_LINK_EXISTS		0x05
 #define A2MP_STATUS_SECURITY_VIOLATION		0x06
 
+extern struct list_head amp_mgr_list;
+extern struct mutex amp_mgr_list_lock;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
index d9eb87e..55f4d5b 100644
--- a/include/net/bluetooth/pal.h
+++ b/include/net/bluetooth/pal.h
@@ -48,6 +48,7 @@ void amp_ctrl_list_flush(struct amp_mgr *mgr);
 struct phy_link *phylink_add(struct amp_mgr *mgr, u8 local_id, u8 remote_id,
 			     u8 *rem_assoc, u16 assoc_size);
 struct phy_link *phylink_lookup(struct amp_mgr *mgr, u8 local_id, u8 remote_id);
+struct phy_link *phylink_lookup_by_handle(u8 handle);
 int phylink_put(struct phy_link *plink);
 void phylink_get(struct phy_link *plink);
 void phylink_list_flush(struct amp_mgr *mgr);
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index b143331..4b6350f 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -21,6 +21,10 @@
 
 static struct workqueue_struct *amp_workqueue;
 
+/* Global AMP Manager list */
+LIST_HEAD(amp_mgr_list);
+DEFINE_MUTEX(amp_mgr_list_lock);
+
 /* A2MP build & send command helper functions */
 static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
 {
@@ -736,6 +740,10 @@ static void amp_mgr_destroy(struct kref *kref)
 
 	BT_DBG("mgr %p", mgr);
 
+	mutex_lock(&amp_mgr_list_lock);
+	list_del(&mgr->list);
+	mutex_unlock(&amp_mgr_list_lock);
+
 	amp_ctrl_list_flush(mgr);
 	phylink_list_flush(mgr);
 	kfree(mgr);
@@ -780,6 +788,10 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 	INIT_LIST_HEAD(&mgr->amp_ctrls);
 	mutex_init(&mgr->amp_ctrls_lock);
 
+	mutex_lock(&amp_mgr_list_lock);
+	list_add(&mgr->list, &amp_mgr_list);
+	mutex_unlock(&amp_mgr_list_lock);
+
 	kref_init(&mgr->kref);
 
 	return mgr;
diff --git a/net/bluetooth/pal.c b/net/bluetooth/pal.c
index b4eeb6a..f8bb66c 100644
--- a/net/bluetooth/pal.c
+++ b/net/bluetooth/pal.c
@@ -222,6 +222,34 @@ struct phy_link *phylink_lookup(struct amp_mgr *mgr, u8 local_id, u8 remote_id)
 	return found;
 }
 
+/* Returns phy_link referenced if found */
+struct phy_link *phylink_lookup_by_handle(u8 handle)
+{
+	struct amp_mgr *mgr;
+	struct phy_link *found = NULL;
+
+	mutex_lock(&amp_mgr_list_lock);
+	list_for_each_entry(mgr, &amp_mgr_list, list) {
+		struct phy_link *plink;
+
+		mutex_lock(&mgr->phy_links_lock);
+		list_for_each_entry(plink, &mgr->phy_links, list) {
+			if (plink->handle == handle) {
+				phylink_get(plink);
+				found = plink;
+				break;
+			}
+		}
+		mutex_unlock(&mgr->phy_links_lock);
+
+		if (found)
+			break;
+	}
+	mutex_unlock(&amp_mgr_list_lock);
+
+	return found;
+}
+
 int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
 {
 	int ret = 0;
-- 
1.7.9.5


^ permalink raw reply related

* [RFCv3 17/20] Bluetooth: A2MP: Add fallback to normal l2cap init sequence
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

When there is no remote AMP controller found fallback to normal
L2CAP sequence.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/a2mp.c          |   28 ++++++++++++++++++++++++++++
 net/bluetooth/l2cap_core.c    |    2 +-
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 26f1163..a5d6d16 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -775,5 +775,6 @@ void l2cap_conn_set_timer(struct l2cap_conn *conn, struct delayed_work *work,
 			  long timeout);
 bool l2cap_conn_clear_timer(struct l2cap_conn *conn,
 			    struct delayed_work *work);
+void l2cap_send_conn_req(struct l2cap_chan *chan);
 
 #endif /* __L2CAP_H */
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index fedfdb9..b143331 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -179,6 +179,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 	u16 len = le16_to_cpu(hdr->len);
 	struct a2mp_cl *cl;
 	u16 ext_feat;
+	bool found = false;
 
 	if (len < sizeof(*rsp))
 		return -EINVAL;
@@ -209,6 +210,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 		if (cl->id != HCI_BREDR_ID && cl->type == HCI_AMP) {
 			struct a2mp_info_req req;
 
+			found = true;
 			req.id = cl->id;
 			a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr),
 				  sizeof(req), &req);
@@ -218,6 +220,32 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 		cl = (void *) skb_pull(skb, sizeof(*cl));
 	}
 
+	/* Fall back to L2CAP init sequence */
+	if (!found) {
+		struct l2cap_conn *conn = mgr->l2cap_conn;
+		struct l2cap_chan *chan;
+
+		mutex_lock(&conn->chan_lock);
+
+		list_for_each_entry(chan, &conn->chan_l, list) {
+
+			BT_DBG("chan %p state %s", chan,
+			       state_to_string(chan->state));
+
+			if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
+				continue;
+
+			l2cap_chan_lock(chan);
+
+			if (chan->state == BT_CONNECT)
+				l2cap_send_conn_req(chan);
+
+			l2cap_chan_unlock(chan);
+		}
+
+		mutex_unlock(&conn->chan_lock);
+	}
+
 	return 0;
 }
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a4a512e..c34fcd0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1017,7 +1017,7 @@ static bool __amp_capable(struct l2cap_chan *chan)
 		return false;
 }
 
-static void l2cap_send_conn_req(struct l2cap_chan *chan)
+void l2cap_send_conn_req(struct l2cap_chan *chan)
 {
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_conn_req req;
-- 
1.7.9.5


^ permalink raw reply related

* [RFCv3 16/20] Bluetooth: AMP: Write remote AMP Assoc
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

When receiving HCI Command Status after HCI Create Physical Link
execute HCI Write Remote AMP Assoc command to AMP controller.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/hci_core.h |    2 +
 net/bluetooth/amp.c              |   80 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_event.c        |   15 +++++++
 3 files changed, 97 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 2094e02..fbf929a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -138,6 +138,8 @@ struct hci_cb_cmd {
 struct amp_assoc {
 	__u16	len;
 	__u16	offset;
+	__u16	rem_len;
+	__u16	len_so_far;
 	__u8	data[HCI_MAX_AMP_ASSOC_SIZE];
 };
 
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 7f2c0fa..409ca3d 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -124,14 +124,94 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
 			      cb_destructor, GFP_KERNEL);
 }
 
+static void amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
+				     struct phy_link *plink);
+
+static void amp_write_rem_assoc_cs_cb(struct hci_dev *hdev,
+				      struct hci_cb_cmd *cmd)
+{
+	struct amp_mgr *mgr = cmd->opt;
+	struct phy_link *plink;
+
+	BT_DBG("mgr %p status 0x%2.2x", mgr, cmd->status);
+
+	if (cmd->status)
+		return;
+
+	plink = phylink_lookup(mgr, hdev->id, 0);
+	if (!plink)
+		return;
+
+	amp_write_rem_assoc_frag(hdev, mgr, plink);
+
+	phylink_put(plink);
+}
+
+static void amp_write_rem_assoc_frag(struct hci_dev *hdev, struct amp_mgr *mgr,
+				     struct phy_link *plink)
+{
+	struct hci_cp_write_remote_amp_assoc *cp;
+	struct amp_ctrl *ctrl;
+	u16 frag_len, len;
+
+	ctrl = amp_ctrl_lookup(mgr, plink->remote_id);
+	if (!ctrl)
+		return;
+
+	if (!ctrl->assoc_rem_len) {
+		BT_DBG("all fragments are written");
+		ctrl->assoc_rem_len = ctrl->assoc_len;
+		ctrl->assoc_len_so_far = 0;
+
+		amp_ctrl_put(ctrl);
+		return;
+	}
+
+	frag_len = min_t(u16, 248, ctrl->assoc_rem_len);
+	len = frag_len + sizeof(*cp);
+
+	cp = kzalloc(len, GFP_KERNEL);
+	if (!cp) {
+		amp_ctrl_put(ctrl);
+		return;
+	}
+
+	BT_DBG("plink %p ctrl %p frag_len %u assoc_len %u rem_len %u",
+	       plink, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len);
+
+	cp->phy_handle = plink->handle;
+	cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far);
+	cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len);
+	memcpy(cp->frag, ctrl->assoc, frag_len);
+
+	ctrl->assoc_len_so_far += frag_len;
+	ctrl->assoc_rem_len -= frag_len;
+
+	amp_ctrl_put(ctrl);
+
+	amp_mgr_get(mgr);
+
+	hci_callback_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp,
+			      amp_write_rem_assoc_cs_cb, mgr, cb_destructor,
+			      GFP_KERNEL);
+
+	kfree(cp);
+}
+
 static void amp_create_phylink_cs_cb(struct hci_dev *hdev,
 				     struct hci_cb_cmd *cmd)
 {
 	struct amp_mgr *mgr = cmd->opt;
+	struct phy_link *plink;
 
 	BT_DBG("mgr %p", mgr);
 
 	/* Write Remote AMP Assoc */
+	plink = phylink_lookup(mgr, hdev->id, 0);
+	if (plink) {
+		amp_write_rem_assoc_frag(hdev, mgr, plink);
+		phylink_put(plink);
+	}
 }
 
 void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8110b94..2f54e76 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1214,6 +1214,17 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
 	hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
 }
 
+static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
+					  struct sk_buff *skb)
+{
+	struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
+	       hdev->name, rp->status, rp->phy_handle);
+
+	hci_callback_process(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, rp->status);
+}
+
 static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
 	BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@ -2401,6 +2412,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_cc_write_le_host_supported(hdev, skb);
 		break;
 
+	case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
+		hci_cc_write_remote_amp_assoc(hdev, skb);
+		break;
+
 	default:
 		BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
 		break;
-- 
1.7.9.5


^ permalink raw reply related

* [RFCv3 15/20] Bluetooth: AMP: Create Physical Link
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

When receiving A2MP Get AMP Assoc Response execute HCI Create Physical
Link to AMP controller. Define callback which will run when receiving
HCI Command Status.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/amp.h |    4 ++++
 include/net/bluetooth/pal.h |    1 -
 net/bluetooth/a2mp.c        |    4 ++++
 net/bluetooth/amp.c         |   31 +++++++++++++++++++++++++++++++
 net/bluetooth/hci_event.c   |   11 +++++++++++
 5 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index e861675..b376cc3 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -14,8 +14,12 @@
 #ifndef __AMP_H
 #define __AMP_H
 
+#include <net/bluetooth/pal.h>
+
 void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
 void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
 void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+			struct phy_link *plink);
 
 #endif /* __AMP_H */
diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
index 8799285..d9eb87e 100644
--- a/include/net/bluetooth/pal.h
+++ b/include/net/bluetooth/pal.h
@@ -18,7 +18,6 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/a2mp.h>
-#include <net/bluetooth/amp.h>
 
 struct phy_link {
 	struct list_head	list;
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index c252c63..fedfdb9 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -378,9 +378,13 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 
 	plink = phylink_add(mgr, hdev->id, rsp->id, ctrl->assoc,
 			    ctrl->assoc_len);
+	if (!plink)
+		goto done;
 
 	BT_DBG("Created plink %p: loc:%d -> rem:%d", plink, hdev->id, rsp->id);
 
+	amp_create_phylink(hdev, mgr, plink);
+
 done:
 	skb_pull(skb, len);
 	return 0;
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 725a9f0..7f2c0fa 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -17,6 +17,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/a2mp.h>
 #include <net/bluetooth/amp.h>
+#include <net/bluetooth/pal.h>
 
 static void amp_read_loc_info_complete_cb(struct hci_dev *hdev,
 					  struct hci_cb_cmd *cmd)
@@ -122,3 +123,33 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
 			      &cp, amp_read_loc_assoc_complete_cb, mgr,
 			      cb_destructor, GFP_KERNEL);
 }
+
+static void amp_create_phylink_cs_cb(struct hci_dev *hdev,
+				     struct hci_cb_cmd *cmd)
+{
+	struct amp_mgr *mgr = cmd->opt;
+
+	BT_DBG("mgr %p", mgr);
+
+	/* Write Remote AMP Assoc */
+}
+
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+			struct phy_link *plink)
+{
+	struct hci_cp_create_phy_link cp;
+
+	cp.phy_handle = plink->handle;
+
+	if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
+			    &cp.key_type)) {
+		BT_DBG("Cannot create link key");
+		return;
+	}
+
+	amp_mgr_get(mgr);
+
+	hci_callback_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp,
+			      amp_create_phylink_cs_cb, mgr, cb_destructor,
+			      GFP_KERNEL);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5f68c70..8110b94 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1685,6 +1685,13 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
 	BT_DBG("%s status 0x%2.2x", hdev->name, status);
 }
 
+static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
+{
+	BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+	hci_callback_process(hdev, HCI_OP_CREATE_PHY_LINK, status);
+}
+
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	__u8 status = *((__u8 *) skb->data);
@@ -2475,6 +2482,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_cs_le_start_enc(hdev, ev->status);
 		break;
 
+	case HCI_OP_CREATE_PHY_LINK:
+		hci_cs_create_phylink(hdev, ev->status);
+		break;
+
 	default:
 		BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
 		break;
-- 
1.7.9.5


^ 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