Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2 16/20] doc: Remove Get-/SetProperties from CSC API document
From: Andrzej Kaczmarek @ 2012-11-05  8:55 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

cyclingspeed plugin uses DBus.Properties instead of custom methods.
---
 doc/cycling-api.txt | 20 +-------------------
 1 file changed, 1 insertion(+), 19 deletions(-)

diff --git a/doc/cycling-api.txt b/doc/cycling-api.txt
index adbcd33..08e11c8 100644
--- a/doc/cycling-api.txt
+++ b/doc/cycling-api.txt
@@ -28,31 +28,13 @@ Service		org.bluez
 Interface	org.bluez.CyclingSpeed
 Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
 
-Methods		void SetProperty(string name, variant value)
-
-			Changes the value of the specified property. Only
-			read-write properties can be changed. On success
-			this will emit a PropertyChanged signal.
-
-			Possible Errors: org.bluez.Error.InvalidArguments
-
-		dict GetProperties()
-
-			Returns all properties for the interface. See the
-			Properties section for the available properties.
-
-		SetCumulativeWheelRevolutions(uint32 value)
+Methods		SetCumulativeWheelRevolutions(uint32 value)
 
 			Sets cumulative wheel revolutions value if
 			Cumulative Wheel Revolutions feature is supported.
 
 			Possible Errors: org.bluez.Error.NotSupported
 
-Signals		PropertyChanged(string name, variant value)
-
-			This signal indicates a changed value of the given
-			property.
-
 Properties	string Location (optional) [readwrite]
 
 			Current sensor location, if supported.
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 15/20] core: Add CyclingSpeedWatcher interface to default policy
From: Andrzej Kaczmarek @ 2012-11-05  8:55 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

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

diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 2db43d9..a1269a4 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -19,6 +19,7 @@
     <allow send_interface="org.bluez.AlertAgent"/>
     <allow send_interface="org.bluez.Profile"/>
     <allow send_interface="org.bluez.HeartRateWatcher"/>
+    <allow send_interface="org.bluez.CyclingSpeedWatcher"/>
   </policy>
 
   <policy at_console="true">
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 14/20] cyclingspeed: Add support for Set Cumulative Value
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 92 +++++++++++++++++++++++++++++++++++-
 1 file changed, 91 insertions(+), 1 deletion(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index d899c00..0a2cb52 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -75,6 +75,7 @@ struct controlpoint_req {
 	uint8_t			opcode;
 	guint			timeout;
 	GDBusPendingReply	reply_id;
+	DBusMessage		*msg;
 
 	uint8_t			pending_location;
 };
@@ -289,6 +290,15 @@ static gboolean controlpoint_timeout(gpointer user_data)
 		g_dbus_pending_property_error(req->reply_id,
 				ERROR_INTERFACE ".Failed",
 				"Operation failed (timeout)");
+	} else if (req->opcode == SET_CUMULATIVE_VALUE) {
+		DBusMessage *reply;
+
+		reply = btd_error_failed(req->msg,
+						"Operation failed (timeout)");
+
+		g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+		dbus_message_unref(req->msg);
 	}
 
 	req->csc->pending_req = NULL;
@@ -309,6 +319,15 @@ static void controlpoint_write_cb(guint8 status, const guint8 *pdu, guint16 len,
 			g_dbus_pending_property_error(req->reply_id,
 					ERROR_INTERFACE ".Failed",
 					"Operation failed (%d)", status);
+		} else if  (req->opcode == SET_CUMULATIVE_VALUE) {
+			DBusMessage *reply;
+
+			reply = btd_error_failed(req->msg,
+						"Operation failed");
+
+			g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+			dbus_message_unref(req->msg);
 		}
 
 		req->csc->pending_req = NULL;
@@ -623,6 +642,34 @@ static void controlpoint_property_reply(struct controlpoint_req *req,
 	}
 }
 
+static void controlpoint_method_reply(struct controlpoint_req *req,
+								uint8_t code)
+{
+	DBusMessage *reply;
+
+	switch (code) {
+	case RSP_SUCCESS:
+		reply = dbus_message_new_method_return(req->msg);
+		break;
+	case RSP_NOT_SUPPORTED:
+		reply = btd_error_not_supported(req->msg);
+		break;
+	case RSP_INVALID_PARAM:
+		reply = btd_error_invalid_args(req->msg);
+		break;
+	case RSP_FAILED:
+		reply = btd_error_failed(req->msg, "Failed");
+		break;
+	default:
+		reply = btd_error_failed(req->msg, "Unknown error");
+		break;
+	}
+
+	g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+	dbus_message_unref(req->msg);
+}
+
 static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
 							gpointer user_data)
 {
@@ -674,6 +721,10 @@ static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
 	}
 
 	switch (req->opcode) {
+	case SET_CUMULATIVE_VALUE:
+		controlpoint_method_reply(req, rsp_code);
+		break;
+
 	case REQUEST_SUPPORTED_SENSOR_LOC:
 		if (rsp_code == RSP_SUCCESS) {
 			csc->num_locations = len;
@@ -1081,6 +1132,44 @@ static const GDBusPropertyTable cyclingspeed_device_properties[] = {
 	{ }
 };
 
+static DBusMessage *set_cumulative_wheel_rev(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	struct csc *csc = data;
+	dbus_uint32_t value;
+	struct controlpoint_req *req;
+	uint8_t att_val[5]; /* uint8 opcode + uint32 value */
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &value,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	if (csc->pending_req != NULL)
+		return btd_error_in_progress(msg);
+
+	req = g_new(struct controlpoint_req, 1);
+	req->csc = csc;
+	req->opcode = SET_CUMULATIVE_VALUE;
+	req->msg = dbus_message_ref(msg);
+
+	csc->pending_req = req;
+
+	att_val[0] = SET_CUMULATIVE_VALUE;
+	att_put_u32(value, att_val + 1);
+
+	gatt_write_char(csc->attrib, csc->controlpoint_val_handle, att_val,
+		sizeof(att_val), controlpoint_write_cb, req);
+
+	return NULL;
+}
+
+static const GDBusMethodTable cyclingspeed_device_methods[] = {
+	{ GDBUS_ASYNC_METHOD("SetCumulativeWheelRevolutions",
+			GDBUS_ARGS({ "value", "u" }), NULL,
+			set_cumulative_wheel_rev) },
+	{ }
+};
+
 int csc_device_register(struct btd_device *device, struct gatt_primary *prim)
 {
 	struct btd_adapter *adapter;
@@ -1100,7 +1189,8 @@ int csc_device_register(struct btd_device *device, struct gatt_primary *prim)
 	if (!g_dbus_register_interface(btd_get_dbus_connection(),
 						device_get_path(device),
 						CYCLINGSPEED_INTERFACE,
-						NULL, NULL,
+						cyclingspeed_device_methods,
+						NULL,
 						cyclingspeed_device_properties,
 						csc, destroy_csc)) {
 		error("D-Bus failed to register %s interface",
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 13/20] cyclingspeed: Add support for Update Sensor Location
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 122 ++++++++++++++++++++++++++++++++++-
 1 file changed, 121 insertions(+), 1 deletion(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index 3222a9b..d899c00 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -74,6 +74,9 @@ struct controlpoint_req {
 	struct csc		*csc;
 	uint8_t			opcode;
 	guint			timeout;
+	GDBusPendingReply	reply_id;
+
+	uint8_t			pending_location;
 };
 
 struct csc_adapter {
@@ -148,6 +151,17 @@ static const gchar *location2str(uint8_t value)
 	return location_enum[0];
 }
 
+static int str2location(const char *location)
+{
+	size_t i;
+
+	for (i = 0; i < G_N_ELEMENTS(location_enum); i++)
+		if (!strcmp(location_enum[i], location))
+			return i;
+
+	return -1;
+}
+
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
 {
 	const struct csc_adapter *cadapter = a;
@@ -271,6 +285,12 @@ static gboolean controlpoint_timeout(gpointer user_data)
 {
 	struct controlpoint_req *req = user_data;
 
+	if (req->opcode == UPDATE_SENSOR_LOC) {
+		g_dbus_pending_property_error(req->reply_id,
+				ERROR_INTERFACE ".Failed",
+				"Operation failed (timeout)");
+	}
+
 	req->csc->pending_req = NULL;
 	g_free(req);
 
@@ -285,6 +305,12 @@ static void controlpoint_write_cb(guint8 status, const guint8 *pdu, guint16 len,
 	if (status != 0) {
 		error("SC Control Point write failed (opcode=%d)", req->opcode);
 
+		if (req->opcode == UPDATE_SENSOR_LOC) {
+			g_dbus_pending_property_error(req->reply_id,
+					ERROR_INTERFACE ".Failed",
+					"Operation failed (%d)", status);
+		}
+
 		req->csc->pending_req = NULL;
 		g_free(req);
 
@@ -563,6 +589,40 @@ static void measurement_notify_handler(const uint8_t *pdu, uint16_t len,
 	process_measurement(csc, pdu + 3, len - 3);
 }
 
+static void controlpoint_property_reply(struct controlpoint_req *req,
+								uint8_t code)
+{
+	switch (code) {
+	case RSP_SUCCESS:
+		g_dbus_pending_property_success(req->reply_id);
+		break;
+
+	case RSP_NOT_SUPPORTED:
+		g_dbus_pending_property_error(req->reply_id,
+					ERROR_INTERFACE ".NotSupported",
+					"Feature is not supported");
+		break;
+
+	case RSP_INVALID_PARAM:
+		g_dbus_pending_property_error(req->reply_id,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
+		break;
+
+	case RSP_FAILED:
+		g_dbus_pending_property_error(req->reply_id,
+					ERROR_INTERFACE ".Failed",
+					"Operation failed");
+		break;
+
+	default:
+		g_dbus_pending_property_error(req->reply_id,
+					ERROR_INTERFACE ".Failed",
+					"Operation failed (%d)", code);
+		break;
+	}
+}
+
 static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
 							gpointer user_data)
 {
@@ -622,6 +682,16 @@ static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
 			error("Failed to read Supported Sendor Locations");
 		}
 		break;
+
+	case UPDATE_SENSOR_LOC:
+		csc->location = req->pending_location;
+
+		controlpoint_property_reply(req, rsp_code);
+
+		g_dbus_emit_property_changed(btd_get_dbus_connection(),
+					device_get_path(csc->dev),
+					CYCLINGSPEED_INTERFACE, "Location");
+		break;
 	}
 
 	csc->pending_req = NULL;
@@ -888,6 +958,56 @@ static gboolean property_get_location(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static void property_set_location(const GDBusPropertyTable *property,
+					DBusMessageIter *iter,
+					GDBusPendingPropertySet id, void *data)
+{
+	struct csc *csc = data;
+	char *loc;
+	int loc_val;
+	uint8_t att_val[2];
+	struct controlpoint_req *req;
+
+	if (csc->pending_req != NULL)
+		return g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InProgress",
+					"Operation already in progress");
+
+	if (!(csc->feature & MULTI_SENSOR_LOC_SUPPORT))
+		return g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".NotSupported",
+					"Feature is not supported");
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
+
+	dbus_message_iter_get_basic(iter, &loc);
+
+	loc_val = str2location(loc);
+
+	if (loc_val < 0)
+		return g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
+
+	req = g_new(struct controlpoint_req, 1);
+	req->csc = csc;
+	req->reply_id = id;
+	req->opcode = UPDATE_SENSOR_LOC;
+	req->pending_location = loc_val;
+
+	csc->pending_req = req;
+
+	att_val[0] = UPDATE_SENSOR_LOC;
+	att_val[1] = loc_val;
+
+	gatt_write_char(csc->attrib, csc->controlpoint_val_handle, att_val,
+		sizeof(att_val), controlpoint_write_cb, req);
+
+}
+
 static gboolean property_exists_location(const GDBusPropertyTable *property,
 								void *data)
 {
@@ -952,7 +1072,7 @@ static gboolean property_get_multi_loc_sup(const GDBusPropertyTable *property,
 }
 
 static const GDBusPropertyTable cyclingspeed_device_properties[] = {
-	{ "Location", "s", property_get_location, NULL,
+	{ "Location", "s", property_get_location, property_set_location,
 						property_exists_location },
 	{ "SupportedLocations", "as", property_get_locations, NULL,
 						property_exists_locations },
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 12/20] cyclingspeed: Add support for Request Supported Sensor Locations
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 61 +++++++++++++++++++++++++++++++++---
 1 file changed, 57 insertions(+), 4 deletions(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index ffef6ae..3222a9b 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -101,6 +101,8 @@ struct csc {
 	uint16_t		feature;
 	gboolean		has_location;
 	uint8_t			location;
+	uint8_t			num_locations;
+	uint8_t			*locations;
 
 	struct controlpoint_req	*pending_req;
 };
@@ -250,6 +252,7 @@ static void destroy_csc(gpointer user_data)
 
 	btd_device_unref(csc->dev);
 	g_free(csc->svc_range);
+	g_free(csc->locations);
 	g_free(csc);
 }
 
@@ -274,7 +277,6 @@ static gboolean controlpoint_timeout(gpointer user_data)
 	return FALSE;
 }
 
-__attribute__((unused)) /* TODO: remove once controlpoint ops are implemented */
 static void controlpoint_write_cb(guint8 status, const guint8 *pdu, guint16 len,
 							gpointer user_data)
 {
@@ -293,6 +295,20 @@ static void controlpoint_write_cb(guint8 status, const guint8 *pdu, guint16 len,
 									req);
 }
 
+static void read_supported_locations(struct csc *csc)
+{
+	struct controlpoint_req *req;
+
+	req = g_new0(struct controlpoint_req, 1);
+	req->csc = csc;
+	req->opcode = REQUEST_SUPPORTED_SENSOR_LOC;
+
+	csc->pending_req = req;
+
+	gatt_write_char(csc->attrib, csc->controlpoint_val_handle, &req->opcode,
+			sizeof(req->opcode), controlpoint_write_cb, req);
+}
+
 static void read_feature_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -317,6 +333,10 @@ static void read_feature_cb(guint8 status, const guint8 *pdu,
 	}
 
 	csc->feature = att_get_u16(value);
+
+	if ((csc->feature & MULTI_SENSOR_LOC_SUPPORT)
+						&& (csc->locations == NULL))
+		read_supported_locations(csc);
 }
 
 static void read_location_cb(guint8 status, const guint8 *pdu,
@@ -550,6 +570,7 @@ static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
 	struct controlpoint_req *req = csc->pending_req;
 	uint8_t opcode;
 	uint8_t req_opcode;
+	uint8_t rsp_code;
 	uint8_t *opdu;
 	uint16_t olen;
 	size_t plen;
@@ -583,7 +604,7 @@ static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
 	}
 
 	req_opcode = *pdu;
-	/* skip response code for now */
+	rsp_code = *(pdu + 1);
 	pdu += 2;
 	len -= 2;
 
@@ -592,7 +613,16 @@ static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
 		goto done;
 	}
 
-	/* TODO: handle response */
+	switch (req->opcode) {
+	case REQUEST_SUPPORTED_SENSOR_LOC:
+		if (rsp_code == RSP_SUCCESS) {
+			csc->num_locations = len;
+			csc->locations = g_memdup(pdu, len);
+		} else {
+			error("Failed to read Supported Sendor Locations");
+		}
+		break;
+	}
 
 	csc->pending_req = NULL;
 	g_source_remove(req->timeout);
@@ -866,6 +896,29 @@ static gboolean property_exists_location(const GDBusPropertyTable *property,
 	return csc->has_location;
 }
 
+static gboolean property_get_locations(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct csc *csc = data;
+	DBusMessageIter entry;
+	int i;
+
+	if (!(csc->feature & MULTI_SENSOR_LOC_SUPPORT))
+		return FALSE;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+					DBUS_TYPE_STRING_AS_STRING, &entry);
+	for (i = 0; i < csc->num_locations; i++) {
+		char *loc = g_strdup(location2str(csc->locations[i]));
+		dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &loc);
+		g_free(loc);
+	}
+
+	dbus_message_iter_close_container(iter, &entry);
+
+	return TRUE;
+}
+
 static gboolean property_exists_locations(const GDBusPropertyTable *property,
 								void *data)
 {
@@ -901,7 +954,7 @@ static gboolean property_get_multi_loc_sup(const GDBusPropertyTable *property,
 static const GDBusPropertyTable cyclingspeed_device_properties[] = {
 	{ "Location", "s", property_get_location, NULL,
 						property_exists_location },
-	{ "SupportedLocations", "as", NULL, NULL,
+	{ "SupportedLocations", "as", property_get_locations, NULL,
 						property_exists_locations },
 	{ "WheelRevolutionDataSupported", "b", property_get_wheel_rev_sup },
 	{ "MultipleLocationsSupported", "b", property_get_multi_loc_sup },
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 11/20] cyclingspeed: Add stub to use SC Control Point
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch implements common functions to use SC Control Point.
Individual procedures will be implemented in subsequent patches.
---
 profiles/cyclingspeed/cyclingspeed.c | 145 +++++++++++++++++++++++++++++++++--
 1 file changed, 140 insertions(+), 5 deletions(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index 5a65507..ffef6ae 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -41,6 +41,11 @@
 #include "log.h"
 #include "cyclingspeed.h"
 
+/* min length for ATT indication or notification: opcode (1b) + handle (2b) */
+#define ATT_HDR_LEN 3
+
+#define ATT_TIMEOUT 30
+
 #define CYCLINGSPEED_INTERFACE		"org.bluez.CyclingSpeed"
 #define CYCLINGSPEED_MANAGER_INTERFACE	"org.bluez.CyclingSpeedManager"
 #define CYCLINGSPEED_WATCHER_INTERFACE	"org.bluez.CyclingSpeedWatcher"
@@ -52,6 +57,25 @@
 #define WHEEL_REV_PRESENT	0x01
 #define CRANK_REV_PRESENT	0x02
 
+#define SET_CUMULATIVE_VALUE		0x01
+#define START_SENSOR_CALIBRATION	0x02
+#define UPDATE_SENSOR_LOC		0x03
+#define REQUEST_SUPPORTED_SENSOR_LOC	0x04
+#define RESPONSE_CODE			0x10
+
+#define RSP_SUCCESS		0x01
+#define RSP_NOT_SUPPORTED	0x02
+#define RSP_INVALID_PARAM	0x03
+#define RSP_FAILED		0x04
+
+struct csc;
+
+struct controlpoint_req {
+	struct csc		*csc;
+	uint8_t			opcode;
+	guint			timeout;
+};
+
 struct csc_adapter {
 	struct btd_adapter	*adapter;
 	GSList			*devices;	/* list of registered devices */
@@ -66,6 +90,8 @@ struct csc {
 	guint			attioid;
 	/* attio id for measurement characteristics value notifications */
 	guint			attio_measurement_id;
+	/* attio id for SC Control Point characteristics value indications */
+	guint			attio_controlpoint_id;
 
 	struct att_range	*svc_range;
 
@@ -75,6 +101,8 @@ struct csc {
 	uint16_t		feature;
 	gboolean		has_location;
 	uint8_t			location;
+
+	struct controlpoint_req	*pending_req;
 };
 
 struct watcher {
@@ -216,6 +244,7 @@ static void destroy_csc(gpointer user_data)
 
 	if (csc->attrib != NULL) {
 		g_attrib_unregister(csc->attrib, csc->attio_measurement_id);
+		g_attrib_unregister(csc->attrib, csc->attio_controlpoint_id);
 		g_attrib_unref(csc->attrib);
 	}
 
@@ -235,6 +264,35 @@ static void char_write_cb(guint8 status, const guint8 *pdu, guint16 len,
 	g_free(msg);
 }
 
+static gboolean controlpoint_timeout(gpointer user_data)
+{
+	struct controlpoint_req *req = user_data;
+
+	req->csc->pending_req = NULL;
+	g_free(req);
+
+	return FALSE;
+}
+
+__attribute__((unused)) /* TODO: remove once controlpoint ops are implemented */
+static void controlpoint_write_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct controlpoint_req *req = user_data;
+
+	if (status != 0) {
+		error("SC Control Point write failed (opcode=%d)", req->opcode);
+
+		req->csc->pending_req = NULL;
+		g_free(req);
+
+		return;
+	}
+
+	req->timeout = g_timeout_add_seconds(ATT_TIMEOUT, controlpoint_timeout,
+									req);
+}
+
 static void read_feature_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -316,6 +374,8 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
 	for (i = 0; i < list->num; i++) {
 		uint8_t *value;
 		uint16_t handle, uuid;
+		uint8_t attr_val[2];
+		char *msg;
 
 		value = list->data[i];
 		handle = att_get_u16(value);
@@ -325,9 +385,6 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
 			continue;
 
 		if (g_strcmp0(ch->uuid, CSC_MEASUREMENT_UUID) == 0) {
-			char *msg;
-			uint8_t attr_val[2];
-
 			ch->csc->measurement_ccc_handle = handle;
 
 			if (g_slist_length(ch->csc->cadapter->watchers) == 0) {
@@ -339,10 +396,16 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
 				msg = g_strdup("Enable measurement");
 			}
 
-			gatt_write_char(ch->csc->attrib, handle, attr_val,
-					sizeof(attr_val), char_write_cb, msg);
+		} else if (g_strcmp0(ch->uuid, SC_CONTROL_POINT_UUID) == 0) {
+			att_put_u16(GATT_CLIENT_CHARAC_CFG_IND_BIT, attr_val);
+			msg = g_strdup("Enable SC Control Point indications");
+		} else {
+			break;
 		}
 
+		gatt_write_char(ch->csc->attrib, handle, attr_val,
+					sizeof(attr_val), char_write_cb, msg);
+
 		/* We only want CCC, can break here */
 		break;
 	}
@@ -480,6 +543,67 @@ static void measurement_notify_handler(const uint8_t *pdu, uint16_t len,
 	process_measurement(csc, pdu + 3, len - 3);
 }
 
+static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
+							gpointer user_data)
+{
+	struct csc *csc = user_data;
+	struct controlpoint_req *req = csc->pending_req;
+	uint8_t opcode;
+	uint8_t req_opcode;
+	uint8_t *opdu;
+	uint16_t olen;
+	size_t plen;
+
+	if (len < ATT_HDR_LEN) {
+		error("Invalid PDU received");
+		return;
+	}
+
+	/* skip ATT header */
+	pdu += ATT_HDR_LEN;
+	len -= ATT_HDR_LEN;
+
+	if (len < 1) {
+		error("Op Code missing");
+		goto done;
+	}
+
+	opcode = *pdu;
+	pdu++;
+	len--;
+
+	if (opcode != RESPONSE_CODE) {
+		DBG("Unsupported Op Code received (%d)", opcode);
+		goto done;
+	}
+
+	if (len < 2) {
+		error("Invalid Response Code PDU received");
+		goto done;
+	}
+
+	req_opcode = *pdu;
+	/* skip response code for now */
+	pdu += 2;
+	len -= 2;
+
+	if (req == NULL || req->opcode != req_opcode) {
+		DBG("Indication received without pending request");
+		goto done;
+	}
+
+	/* TODO: handle response */
+
+	csc->pending_req = NULL;
+	g_source_remove(req->timeout);
+	g_free(req);
+
+done:
+	opdu = g_attrib_get_buffer(csc->attrib, &plen);
+	olen = enc_confirmation(opdu, plen);
+	if (olen > 0)
+		g_attrib_send(csc->attrib, 0, opdu, olen, NULL, NULL, NULL);
+}
 
 static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 {
@@ -513,6 +637,12 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 		} else if (g_strcmp0(c->uuid, SC_CONTROL_POINT_UUID) == 0) {
 			DBG("SC Control Point supported");
 			csc->controlpoint_val_handle = c->value_handle;
+
+			csc->attio_controlpoint_id = g_attrib_register(
+					csc->attrib, ATT_OP_HANDLE_IND,
+					c->value_handle,
+					controlpoint_ind_handler, csc, NULL);
+
 			discover_desc(csc, c, c_next);
 		}
 	}
@@ -580,6 +710,11 @@ static void attio_disconnected_cb(gpointer user_data)
 		csc->attio_measurement_id = 0;
 	}
 
+	if (csc->attio_controlpoint_id > 0) {
+		g_attrib_unregister(csc->attrib, csc->attio_controlpoint_id);
+		csc->attio_controlpoint_id = 0;
+	}
+
 	g_attrib_unref(csc->attrib);
 	csc->attrib = NULL;
 }
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 10/20] cyclingspeed: Add DBus.Properties for org.bluez.CyclingSpeed interface
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 96 +++++++++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 1 deletion(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index ae058f2..5a65507 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -103,6 +103,21 @@ struct characteristic {
 
 static GSList *csc_adapters = NULL;
 
+static const char * const location_enum[] = {
+	"other", "top-of-shoe", "in-shoe", "hip", "front-wheel", "left-crank",
+	"right-crank", "left-pedal", "right-pedal", "front-hub",
+	"rear-dropout", "chainstay", "rear-wheel", "rear-hub"
+};
+
+static const gchar *location2str(uint8_t value)
+{
+	if (value < G_N_ELEMENTS(location_enum))
+		return location_enum[value];
+
+	info("Body Sensor Location [%d] is RFU", value);
+	return location_enum[0];
+}
+
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
 {
 	const struct csc_adapter *cadapter = a;
@@ -692,6 +707,72 @@ void csc_adapter_unregister(struct btd_adapter *adapter)
 					CYCLINGSPEED_MANAGER_INTERFACE);
 }
 
+static gboolean property_get_location(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct csc *csc = data;
+	const char *loc;
+
+	if (!csc->has_location)
+		return FALSE;
+
+	loc = location2str(csc->location);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &loc);
+
+	return TRUE;
+}
+
+static gboolean property_exists_location(const GDBusPropertyTable *property,
+								void *data)
+{
+	struct csc *csc = data;
+
+	return csc->has_location;
+}
+
+static gboolean property_exists_locations(const GDBusPropertyTable *property,
+								void *data)
+{
+	struct csc *csc = data;
+
+	return !!(csc->feature & MULTI_SENSOR_LOC_SUPPORT);
+}
+
+static gboolean property_get_wheel_rev_sup(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct csc *csc = data;
+	dbus_bool_t val;
+
+	val = !!(csc->feature & WHEEL_REV_SUPPORT);
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
+
+	return TRUE;
+}
+
+static gboolean property_get_multi_loc_sup(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct csc *csc = data;
+	dbus_bool_t val;
+
+	val = !!(csc->feature & MULTI_SENSOR_LOC_SUPPORT);
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
+
+	return TRUE;
+}
+
+static const GDBusPropertyTable cyclingspeed_device_properties[] = {
+	{ "Location", "s", property_get_location, NULL,
+						property_exists_location },
+	{ "SupportedLocations", "as", NULL, NULL,
+						property_exists_locations },
+	{ "WheelRevolutionDataSupported", "b", property_get_wheel_rev_sup },
+	{ "MultipleLocationsSupported", "b", property_get_multi_loc_sup },
+	{ }
+};
+
 int csc_device_register(struct btd_device *device, struct gatt_primary *prim)
 {
 	struct btd_adapter *adapter;
@@ -708,6 +789,18 @@ int csc_device_register(struct btd_device *device, struct gatt_primary *prim)
 	csc->dev = btd_device_ref(device);
 	csc->cadapter = cadapter;
 
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+						device_get_path(device),
+						CYCLINGSPEED_INTERFACE,
+						NULL, NULL,
+						cyclingspeed_device_properties,
+						csc, destroy_csc)) {
+		error("D-Bus failed to register %s interface",
+						CYCLINGSPEED_INTERFACE);
+		destroy_csc(csc);
+		return -EIO;
+	}
+
 	csc->svc_range = g_new0(struct att_range, 1);
 	csc->svc_range->start = prim->range.start;
 	csc->svc_range->end = prim->range.end;
@@ -741,5 +834,6 @@ void csc_device_unregister(struct btd_device *device)
 
 	cadapter->devices = g_slist_remove(cadapter->devices, csc);
 
-	destroy_csc(csc);
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+			device_get_path(device), CYCLINGSPEED_INTERFACE);
 }
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 09/20] cyclingspeed: Process measurement notifications
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 139 ++++++++++++++++++++++++++++++++++-
 1 file changed, 138 insertions(+), 1 deletion(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index 4f0a0a5..ae058f2 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -43,6 +43,14 @@
 
 #define CYCLINGSPEED_INTERFACE		"org.bluez.CyclingSpeed"
 #define CYCLINGSPEED_MANAGER_INTERFACE	"org.bluez.CyclingSpeedManager"
+#define CYCLINGSPEED_WATCHER_INTERFACE	"org.bluez.CyclingSpeedWatcher"
+
+#define WHEEL_REV_SUPPORT		0x01
+#define CRANK_REV_SUPPORT		0x02
+#define MULTI_SENSOR_LOC_SUPPORT	0x04
+
+#define WHEEL_REV_PRESENT	0x01
+#define CRANK_REV_PRESENT	0x02
 
 struct csc_adapter {
 	struct btd_adapter	*adapter;
@@ -56,6 +64,8 @@ struct csc {
 
 	GAttrib			*attrib;
 	guint			attioid;
+	/* attio id for measurement characteristics value notifications */
+	guint			attio_measurement_id;
 
 	struct att_range	*svc_range;
 
@@ -74,6 +84,18 @@ struct watcher {
 	char			*path;
 };
 
+struct measurement {
+	struct csc	*csc;
+
+	bool		has_wheel_rev;
+	uint32_t	wheel_rev;
+	uint16_t	last_wheel_time;
+
+	bool		has_crank_rev;
+	uint16_t	crank_rev;
+	uint16_t	last_crank_time;
+};
+
 struct characteristic {
 	struct csc	*csc;
 	char		uuid[MAX_LEN_UUID_STR + 1];
@@ -177,8 +199,10 @@ static void destroy_csc(gpointer user_data)
 	if (csc->attioid > 0)
 		btd_device_remove_attio_callback(csc->dev, csc->attioid);
 
-	if (csc->attrib != NULL)
+	if (csc->attrib != NULL) {
+		g_attrib_unregister(csc->attrib, csc->attio_measurement_id);
 		g_attrib_unref(csc->attrib);
+	}
 
 	btd_device_unref(csc->dev);
 	g_free(csc->svc_range);
@@ -339,6 +363,109 @@ static void discover_desc(struct csc *csc, struct gatt_char *c,
 	gatt_find_info(csc->attrib, start, end, discover_desc_cb, ch);
 }
 
+static void update_watcher(gpointer data, gpointer user_data)
+{
+	struct watcher *w = data;
+	struct measurement *m = user_data;
+	struct csc *csc = m->csc;
+	const gchar *path = device_get_path(csc->dev);
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(w->srv, w->path,
+			CYCLINGSPEED_WATCHER_INTERFACE, "MeasurementReceived");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	if (m->has_wheel_rev) {
+		dict_append_entry(&dict, "WheelRevolutions",
+					DBUS_TYPE_UINT32, &m->wheel_rev);
+		dict_append_entry(&dict, "LastWheelEventTime",
+					DBUS_TYPE_UINT16, &m->last_wheel_time);
+	}
+
+	if (m->has_crank_rev) {
+		dict_append_entry(&dict, "CrankRevolutions",
+					DBUS_TYPE_UINT16, &m->crank_rev);
+		dict_append_entry(&dict, "LastCrankEventTime",
+					DBUS_TYPE_UINT16, &m->last_crank_time);
+	}
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void process_measurement(struct csc *csc, const uint8_t *pdu,
+								uint16_t len)
+{
+	struct measurement m;
+	uint8_t flags;
+
+	flags = *pdu;
+
+	pdu++;
+	len--;
+
+	memset(&m, 0, sizeof(m));
+
+	if ((flags & WHEEL_REV_PRESENT) && (csc->feature & WHEEL_REV_SUPPORT)) {
+		if (len < 6) {
+			error("Wheel revolutions data fields missing");
+			return;
+		}
+
+		m.has_wheel_rev = true;
+		m.wheel_rev = att_get_u32(pdu);
+		m.last_wheel_time = att_get_u16(pdu + 4);
+		pdu += 6;
+		len -= 6;
+	}
+
+	if ((flags & CRANK_REV_PRESENT) && (csc->feature & CRANK_REV_SUPPORT)) {
+		if (len < 4) {
+			error("Crank revolutions data fields missing");
+			return;
+		}
+
+		m.has_crank_rev = true;
+		m.crank_rev = att_get_u16(pdu);
+		m.last_crank_time = att_get_u16(pdu + 2);
+		pdu += 4;
+		len -= 4;
+	}
+
+	/* Notify all registered watchers */
+	m.csc = csc;
+	g_slist_foreach(csc->cadapter->watchers, update_watcher, &m);
+}
+
+static void measurement_notify_handler(const uint8_t *pdu, uint16_t len,
+							gpointer user_data)
+{
+	struct csc *csc = user_data;
+
+	/* should be at least opcode (1b) + handle (2b) */
+	if (len < 3) {
+		error("Invalid PDU received");
+		return;
+	}
+
+	process_measurement(csc, pdu + 3, len - 3);
+}
+
+
 static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 {
 	struct csc *csc = user_data;
@@ -356,6 +483,11 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 				(chars->next ? chars->next->data : NULL);
 
 		if (g_strcmp0(c->uuid, CSC_MEASUREMENT_UUID) == 0) {
+			csc->attio_measurement_id =
+				g_attrib_register(csc->attrib,
+					ATT_OP_HANDLE_NOTIFY, c->value_handle,
+					measurement_notify_handler, csc, NULL);
+
 			discover_desc(csc, c, c_next);
 		} else if (g_strcmp0(c->uuid, CSC_FEATURE_UUID) == 0) {
 			feature_val_handle = c->value_handle;
@@ -428,6 +560,11 @@ static void attio_disconnected_cb(gpointer user_data)
 
 	DBG("");
 
+	if (csc->attio_measurement_id > 0) {
+		g_attrib_unregister(csc->attrib, csc->attio_measurement_id);
+		csc->attio_measurement_id = 0;
+	}
+
 	g_attrib_unref(csc->attrib);
 	csc->attrib = NULL;
 }
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 08/20] cyclingspeed: Add support to enable measurement notifications
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 72 +++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index deae8a9..4f0a0a5 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -185,6 +185,17 @@ static void destroy_csc(gpointer user_data)
 	g_free(csc);
 }
 
+static void char_write_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	char *msg = user_data;
+
+	if (status != 0)
+		error("%s failed", msg);
+
+	g_free(msg);
+}
+
 static void read_feature_cb(guint8 status, const guint8 *pdu,
 						guint16 len, gpointer user_data)
 {
@@ -274,9 +285,25 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
 		if (uuid != GATT_CLIENT_CHARAC_CFG_UUID)
 			continue;
 
-		if (g_strcmp0(ch->uuid, CSC_MEASUREMENT_UUID) == 0)
+		if (g_strcmp0(ch->uuid, CSC_MEASUREMENT_UUID) == 0) {
+			char *msg;
+			uint8_t attr_val[2];
+
 			ch->csc->measurement_ccc_handle = handle;
 
+			if (g_slist_length(ch->csc->cadapter->watchers) == 0) {
+				att_put_u16(0x0000, attr_val);
+				msg = g_strdup("Disable measurement");
+			} else {
+				att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT,
+								attr_val);
+				msg = g_strdup("Enable measurement");
+			}
+
+			gatt_write_char(ch->csc->attrib, handle, attr_val,
+					sizeof(attr_val), char_write_cb, msg);
+		}
+
 		/* We only want CCC, can break here */
 		break;
 	}
@@ -348,6 +375,40 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 							read_feature_cb, csc);
 }
 
+static void enable_measurement(gpointer data, gpointer user_data)
+{
+	struct csc *csc = data;
+	uint16_t handle = csc->measurement_ccc_handle;
+	uint8_t value[2];
+	char *msg;
+
+	if (csc->attrib == NULL || !handle)
+		return;
+
+	att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+	msg = g_strdup("Enable measurement");
+
+	gatt_write_char(csc->attrib, handle, value, sizeof(value),
+							char_write_cb, msg);
+}
+
+static void disable_measurement(gpointer data, gpointer user_data)
+{
+	struct csc *csc = data;
+	uint16_t handle = csc->measurement_ccc_handle;
+	uint8_t value[2];
+	char *msg;
+
+	if (csc->attrib == NULL || !handle)
+		return;
+
+	att_put_u16(0x0000, value);
+	msg = g_strdup("Disable measurement");
+
+	gatt_write_char(csc->attrib, handle, value, sizeof(value),
+							char_write_cb, msg);
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct csc *csc = user_data;
@@ -380,6 +441,9 @@ static void watcher_exit_cb(DBusConnection *conn, void *user_data)
 
 	cadapter->watchers = g_slist_remove(cadapter->watchers, watcher);
 	g_dbus_remove_watch(conn, watcher->id);
+
+	if (g_slist_length(cadapter->watchers) == 0)
+		g_slist_foreach(cadapter->devices, disable_measurement, 0);
 }
 
 static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
@@ -405,6 +469,9 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
 	watcher->srv = g_strdup(sender);
 	watcher->path = g_strdup(path);
 
+	if (g_slist_length(cadapter->watchers) == 0)
+		g_slist_foreach(cadapter->devices, enable_measurement, 0);
+
 	cadapter->watchers = g_slist_prepend(cadapter->watchers, watcher);
 
 	DBG("cycling watcher [%s] registered", path);
@@ -431,6 +498,9 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
 	cadapter->watchers = g_slist_remove(cadapter->watchers, watcher);
 	g_dbus_remove_watch(conn, watcher->id);
 
+	if (g_slist_length(cadapter->watchers) == 0)
+		g_slist_foreach(cadapter->devices, disable_measurement, 0);
+
 	DBG("cycling watcher [%s] unregistered", path);
 
 	return dbus_message_new_method_return(msg);
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 07/20] cyclingspeed: Add CyclingSpeedManager interface
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch registers org.bluez.CyclingSpeedManager interface for each
adapter to allow registration and deregistration of measurement watchers.
---
 profiles/cyclingspeed/cyclingspeed.c | 151 ++++++++++++++++++++++++++++++++++-
 1 file changed, 150 insertions(+), 1 deletion(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index 95e3b98..deae8a9 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -33,6 +33,7 @@
 #include "adapter.h"
 #include "device.h"
 #include "dbus-common.h"
+#include "error.h"
 #include "gattrib.h"
 #include "att.h"
 #include "gatt.h"
@@ -41,10 +42,12 @@
 #include "cyclingspeed.h"
 
 #define CYCLINGSPEED_INTERFACE		"org.bluez.CyclingSpeed"
+#define CYCLINGSPEED_MANAGER_INTERFACE	"org.bluez.CyclingSpeedManager"
 
 struct csc_adapter {
 	struct btd_adapter	*adapter;
 	GSList			*devices;	/* list of registered devices */
+	GSList			*watchers;
 };
 
 struct csc {
@@ -64,6 +67,13 @@ struct csc {
 	uint8_t			location;
 };
 
+struct watcher {
+	struct csc_adapter	*cadapter;
+	guint			id;
+	char			*srv;
+	char			*path;
+};
+
 struct characteristic {
 	struct csc	*csc;
 	char		uuid[MAX_LEN_UUID_STR + 1];
@@ -93,6 +103,19 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
 	return -1;
 }
 
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+	const struct watcher *watcher = a;
+	const struct watcher *match = b;
+	int ret;
+
+	ret = g_strcmp0(watcher->srv, match->srv);
+	if (ret != 0)
+		return ret;
+
+	return g_strcmp0(watcher->path, match->path);
+}
+
 static struct csc_adapter *find_csc_adapter(struct btd_adapter *adapter)
 {
 	GSList *l = g_slist_find_custom(csc_adapters, adapter, cmp_adapter);
@@ -103,10 +126,47 @@ static struct csc_adapter *find_csc_adapter(struct btd_adapter *adapter)
 	return l->data;
 }
 
+static void destroy_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_free(watcher->path);
+	g_free(watcher->srv);
+	g_free(watcher);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+							const char *path)
+{
+	struct watcher *match;
+	GSList *l;
+
+	match = g_new0(struct watcher, 1);
+	match->srv = g_strdup(sender);
+	match->path = g_strdup(path);
+
+	l = g_slist_find_custom(list, match, cmp_watcher);
+	destroy_watcher(match);
+
+	if (l != NULL)
+		return l->data;
+
+	return NULL;
+}
+
+static void remove_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
+}
+
 static void destroy_csc_adapter(gpointer user_data)
 {
 	struct csc_adapter *cadapter = user_data;
 
+	g_slist_free_full(cadapter->watchers, remove_watcher);
+
 	g_free(cadapter);
 }
 
@@ -311,6 +371,81 @@ static void attio_disconnected_cb(gpointer user_data)
 	csc->attrib = NULL;
 }
 
+static void watcher_exit_cb(DBusConnection *conn, void *user_data)
+{
+	struct watcher *watcher = user_data;
+	struct csc_adapter *cadapter = watcher->cadapter;
+
+	DBG("cycling watcher [%s] disconnected", watcher->path);
+
+	cadapter->watchers = g_slist_remove(cadapter->watchers, watcher);
+	g_dbus_remove_watch(conn, watcher->id);
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct csc_adapter *cadapter = data;
+	struct watcher *watcher;
+	const char *sender = dbus_message_get_sender(msg);
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(cadapter->watchers, sender, path);
+	if (watcher != NULL)
+		return btd_error_already_exists(msg);
+
+	watcher = g_new0(struct watcher, 1);
+	watcher->cadapter = cadapter;
+	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit_cb,
+						watcher, destroy_watcher);
+	watcher->srv = g_strdup(sender);
+	watcher->path = g_strdup(path);
+
+	cadapter->watchers = g_slist_prepend(cadapter->watchers, watcher);
+
+	DBG("cycling watcher [%s] registered", path);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct csc_adapter *cadapter = data;
+	struct watcher *watcher;
+	const char *sender = dbus_message_get_sender(msg);
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(cadapter->watchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	cadapter->watchers = g_slist_remove(cadapter->watchers, watcher);
+	g_dbus_remove_watch(conn, watcher->id);
+
+	DBG("cycling watcher [%s] unregistered", path);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable cyclingspeed_manager_methods[] = {
+	{ GDBUS_METHOD("RegisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			register_watcher) },
+	{ GDBUS_METHOD("UnregisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			unregister_watcher) },
+	{ }
+};
+
 int csc_adapter_register(struct btd_adapter *adapter)
 {
 	struct csc_adapter *cadapter;
@@ -320,6 +455,18 @@ int csc_adapter_register(struct btd_adapter *adapter)
 
 	csc_adapters = g_slist_prepend(csc_adapters, cadapter);
 
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+						adapter_get_path(adapter),
+						CYCLINGSPEED_MANAGER_INTERFACE,
+						cyclingspeed_manager_methods,
+						NULL, NULL, cadapter,
+						destroy_csc_adapter)) {
+		error("D-Bus failed to register %s interface",
+						CYCLINGSPEED_MANAGER_INTERFACE);
+		destroy_csc_adapter(cadapter);
+		return -EIO;
+	}
+
 	return 0;
 }
 
@@ -333,7 +480,9 @@ void csc_adapter_unregister(struct btd_adapter *adapter)
 
 	csc_adapters = g_slist_remove(csc_adapters, cadapter);
 
-	destroy_csc_adapter(cadapter);
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+					adapter_get_path(cadapter->adapter),
+					CYCLINGSPEED_MANAGER_INTERFACE);
 }
 
 int csc_device_register(struct btd_device *device, struct gatt_primary *prim)
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 06/20] cyclingspeed: Read Sensor Location characteristic value
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 40 +++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index fa97911..95e3b98 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #endif
 
+#include <gdbus.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <glib.h>
@@ -31,6 +32,7 @@
 
 #include "adapter.h"
 #include "device.h"
+#include "dbus-common.h"
 #include "gattrib.h"
 #include "att.h"
 #include "gatt.h"
@@ -38,6 +40,8 @@
 #include "log.h"
 #include "cyclingspeed.h"
 
+#define CYCLINGSPEED_INTERFACE		"org.bluez.CyclingSpeed"
+
 struct csc_adapter {
 	struct btd_adapter	*adapter;
 	GSList			*devices;	/* list of registered devices */
@@ -56,6 +60,8 @@ struct csc {
 	uint16_t		controlpoint_val_handle;
 
 	uint16_t		feature;
+	gboolean		has_location;
+	uint8_t			location;
 };
 
 struct characteristic {
@@ -145,6 +151,37 @@ static void read_feature_cb(guint8 status, const guint8 *pdu,
 	csc->feature = att_get_u16(value);
 }
 
+static void read_location_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct csc *csc = user_data;
+	uint8_t value;
+	ssize_t vlen;
+
+	if (status) {
+		error("Sensor Location read failed: %s", att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, &value, sizeof(value));
+	if (vlen < 0) {
+		error("Protocol error");
+		return;
+	}
+
+	if (vlen != sizeof(value)) {
+		error("Invalid value length for Sensor Location");
+		return;
+	}
+
+	csc->has_location = TRUE;
+	csc->location = value;
+
+	g_dbus_emit_property_changed(btd_get_dbus_connection(),
+					device_get_path(csc->dev),
+					CYCLINGSPEED_INTERFACE, "Location");
+}
+
 static void discover_desc_cb(guint8 status, const guint8 *pdu,
 					guint16 len, gpointer user_data)
 {
@@ -237,7 +274,8 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 			feature_val_handle = c->value_handle;
 		} else if (g_strcmp0(c->uuid, SENSOR_LOCATION_UUID) == 0) {
 			DBG("Sensor Location supported");
-			/* TODO: read characterictic value */
+			gatt_read_char(csc->attrib, c->value_handle,
+							read_location_cb, csc);
 		} else if (g_strcmp0(c->uuid, SC_CONTROL_POINT_UUID) == 0) {
 			DBG("SC Control Point supported");
 			csc->controlpoint_val_handle = c->value_handle;
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 05/20] cyclingspeed: Read CSC Feature characteristic value
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index 0191f1b..fa97911 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -54,6 +54,8 @@ struct csc {
 
 	uint16_t		measurement_ccc_handle;
 	uint16_t		controlpoint_val_handle;
+
+	uint16_t		feature;
 };
 
 struct characteristic {
@@ -117,6 +119,32 @@ static void destroy_csc(gpointer user_data)
 	g_free(csc);
 }
 
+static void read_feature_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	struct csc *csc = user_data;
+	uint8_t value[2];
+	ssize_t vlen;
+
+	if (status) {
+		error("CSC Feature read failed: %s", att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (vlen < 0) {
+		error("Protocol error");
+		return;
+	}
+
+	if (vlen != sizeof(value)) {
+		error("Invalid value length for CSC Feature");
+		return;
+	}
+
+	csc->feature = att_get_u16(value);
+}
+
 static void discover_desc_cb(guint8 status, const guint8 *pdu,
 					guint16 len, gpointer user_data)
 {
@@ -190,6 +218,7 @@ static void discover_desc(struct csc *csc, struct gatt_char *c,
 static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 {
 	struct csc *csc = user_data;
+	uint16_t feature_val_handle = 0;
 
 	if (status) {
 		error("Discover CSCS characteristics: %s",
@@ -205,7 +234,7 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 		if (g_strcmp0(c->uuid, CSC_MEASUREMENT_UUID) == 0) {
 			discover_desc(csc, c, c_next);
 		} else if (g_strcmp0(c->uuid, CSC_FEATURE_UUID) == 0) {
-			/* TODO: read characterictic value */
+			feature_val_handle = c->value_handle;
 		} else if (g_strcmp0(c->uuid, SENSOR_LOCATION_UUID) == 0) {
 			DBG("Sensor Location supported");
 			/* TODO: read characterictic value */
@@ -215,6 +244,10 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 			discover_desc(csc, c, c_next);
 		}
 	}
+
+	if (feature_val_handle > 0)
+		gatt_read_char(csc->attrib, feature_val_handle,
+							read_feature_cb, csc);
 }
 
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 04/20] cyclingspeed: Discover characteristics CCC
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 82 +++++++++++++++++++++++++++++++++++-
 1 file changed, 80 insertions(+), 2 deletions(-)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index 5744891..0191f1b 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -52,9 +52,15 @@ struct csc {
 
 	struct att_range	*svc_range;
 
+	uint16_t		measurement_ccc_handle;
 	uint16_t		controlpoint_val_handle;
 };
 
+struct characteristic {
+	struct csc	*csc;
+	char		uuid[MAX_LEN_UUID_STR + 1];
+};
+
 static GSList *csc_adapters = NULL;
 
 static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -111,6 +117,76 @@ static void destroy_csc(gpointer user_data)
 	g_free(csc);
 }
 
+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 = NULL;
+	uint8_t format;
+	int i;
+
+	if (status != 0) {
+		error("Discover %s descriptors failed: %s", ch->uuid,
+							att_ecode2str(status));
+		goto done;
+	}
+
+	list = dec_find_info_resp(pdu, len, &format);
+	if (list == NULL)
+		goto done;
+
+	if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+		goto done;
+
+	for (i = 0; i < list->num; i++) {
+		uint8_t *value;
+		uint16_t handle, uuid;
+
+		value = list->data[i];
+		handle = att_get_u16(value);
+		uuid = att_get_u16(value + 2);
+
+		if (uuid != GATT_CLIENT_CHARAC_CFG_UUID)
+			continue;
+
+		if (g_strcmp0(ch->uuid, CSC_MEASUREMENT_UUID) == 0)
+			ch->csc->measurement_ccc_handle = handle;
+
+		/* We only want CCC, can break here */
+		break;
+	}
+
+done:
+	if (list)
+		att_data_list_free(list);
+	g_free(ch);
+}
+
+static void discover_desc(struct csc *csc, struct gatt_char *c,
+						struct gatt_char *c_next)
+{
+	struct characteristic *ch;
+	uint16_t start, end;
+
+	start = c->value_handle + 1;
+
+	if (c_next != NULL) {
+		if (start == c_next->handle)
+			return;
+		end = c_next->handle - 1;
+	} else if (c->value_handle != csc->svc_range->end) {
+		end = csc->svc_range->end;
+	} else {
+		return;
+	}
+
+	ch = g_new0(struct characteristic, 1);
+	ch->csc = csc;
+	memcpy(ch->uuid, c->uuid, sizeof(c->uuid));
+
+	gatt_find_info(csc->attrib, start, end, discover_desc_cb, ch);
+}
+
 static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 {
 	struct csc *csc = user_data;
@@ -123,9 +199,11 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 
 	for (; chars; chars = chars->next) {
 		struct gatt_char *c = chars->data;
+		struct gatt_char *c_next =
+				(chars->next ? chars->next->data : NULL);
 
 		if (g_strcmp0(c->uuid, CSC_MEASUREMENT_UUID) == 0) {
-			/* TODO: discover CCC handle */
+			discover_desc(csc, c, c_next);
 		} else if (g_strcmp0(c->uuid, CSC_FEATURE_UUID) == 0) {
 			/* TODO: read characterictic value */
 		} else if (g_strcmp0(c->uuid, SENSOR_LOCATION_UUID) == 0) {
@@ -134,7 +212,7 @@ static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
 		} else if (g_strcmp0(c->uuid, SC_CONTROL_POINT_UUID) == 0) {
 			DBG("SC Control Point supported");
 			csc->controlpoint_val_handle = c->value_handle;
-			/* TODO: discover CCC handle */
+			discover_desc(csc, c, c_next);
 		}
 	}
 }
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 03/20] cyclingspeed: Discover CSCS characteristics
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 lib/uuid.h                           |  4 ++++
 profiles/cyclingspeed/cyclingspeed.c | 43 +++++++++++++++++++++++++++++++++++-
 profiles/cyclingspeed/cyclingspeed.h |  2 +-
 profiles/cyclingspeed/manager.c      | 19 +++++++++++++++-
 4 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/lib/uuid.h b/lib/uuid.h
index ebc6d27..def4fea 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -75,6 +75,10 @@ extern "C" {
 #define MEASUREMENT_INTERVAL_UUID	"00002a21-0000-1000-8000-00805f9b34fb"
 
 #define CYCLING_SC_UUID		"00001816-0000-1000-8000-00805f9b34fb"
+#define CSC_MEASUREMENT_UUID	"00002a5b-0000-1000-8000-00805f9b34fb"
+#define CSC_FEATURE_UUID	"00002a5c-0000-1000-8000-00805f9b34fb"
+#define SENSOR_LOCATION_UUID	"00002a5d-0000-1000-8000-00805f9b34fb"
+#define SC_CONTROL_POINT_UUID	"00002a55-0000-1000-8000-00805f9b34fb"
 
 #define RFCOMM_UUID_STR		"00000003-0000-1000-8000-00805f9b34fb"
 
diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index 4d98810..5744891 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -49,6 +49,10 @@ struct csc {
 
 	GAttrib			*attrib;
 	guint			attioid;
+
+	struct att_range	*svc_range;
+
+	uint16_t		controlpoint_val_handle;
 };
 
 static GSList *csc_adapters = NULL;
@@ -103,9 +107,38 @@ static void destroy_csc(gpointer user_data)
 		g_attrib_unref(csc->attrib);
 
 	btd_device_unref(csc->dev);
+	g_free(csc->svc_range);
 	g_free(csc);
 }
 
+static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
+{
+	struct csc *csc = user_data;
+
+	if (status) {
+		error("Discover CSCS characteristics: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	for (; chars; chars = chars->next) {
+		struct gatt_char *c = chars->data;
+
+		if (g_strcmp0(c->uuid, CSC_MEASUREMENT_UUID) == 0) {
+			/* TODO: discover CCC handle */
+		} else if (g_strcmp0(c->uuid, CSC_FEATURE_UUID) == 0) {
+			/* TODO: read characterictic value */
+		} else if (g_strcmp0(c->uuid, SENSOR_LOCATION_UUID) == 0) {
+			DBG("Sensor Location supported");
+			/* TODO: read characterictic value */
+		} else if (g_strcmp0(c->uuid, SC_CONTROL_POINT_UUID) == 0) {
+			DBG("SC Control Point supported");
+			csc->controlpoint_val_handle = c->value_handle;
+			/* TODO: discover CCC handle */
+		}
+	}
+}
+
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
 	struct csc *csc = user_data;
@@ -113,6 +146,10 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 	DBG("");
 
 	csc->attrib = g_attrib_ref(attrib);
+
+	gatt_discover_char(csc->attrib, csc->svc_range->start,
+				csc->svc_range->end, NULL,
+				discover_char_cb, csc);
 }
 
 static void attio_disconnected_cb(gpointer user_data)
@@ -150,7 +187,7 @@ void csc_adapter_unregister(struct btd_adapter *adapter)
 	destroy_csc_adapter(cadapter);
 }
 
-int csc_device_register(struct btd_device *device)
+int csc_device_register(struct btd_device *device, struct gatt_primary *prim)
 {
 	struct btd_adapter *adapter;
 	struct csc_adapter *cadapter;
@@ -166,6 +203,10 @@ int csc_device_register(struct btd_device *device)
 	csc->dev = btd_device_ref(device);
 	csc->cadapter = cadapter;
 
+	csc->svc_range = g_new0(struct att_range, 1);
+	csc->svc_range->start = prim->range.start;
+	csc->svc_range->end = prim->range.end;
+
 	cadapter->devices = g_slist_prepend(cadapter->devices, csc);
 
 	csc->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
diff --git a/profiles/cyclingspeed/cyclingspeed.h b/profiles/cyclingspeed/cyclingspeed.h
index b83fa9e..3400d5f 100644
--- a/profiles/cyclingspeed/cyclingspeed.h
+++ b/profiles/cyclingspeed/cyclingspeed.h
@@ -22,5 +22,5 @@
 
 int csc_adapter_register(struct btd_adapter *adapter);
 void csc_adapter_unregister(struct btd_adapter *adapter);
-int csc_device_register(struct btd_device *device);
+int csc_device_register(struct btd_device *device, struct gatt_primary *prim);
 void csc_device_unregister(struct btd_device *device);
diff --git a/profiles/cyclingspeed/manager.c b/profiles/cyclingspeed/manager.c
index e5f7553..c147af2 100644
--- a/profiles/cyclingspeed/manager.c
+++ b/profiles/cyclingspeed/manager.c
@@ -34,6 +34,14 @@
 #include "cyclingspeed.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 csc_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter)
 {
 	return csc_adapter_register(adapter);
@@ -48,7 +56,16 @@ static void csc_adapter_remove(struct btd_profile *p,
 static int csc_device_probe(struct btd_profile *p,
 				struct btd_device *device, GSList *uuids)
 {
-	return csc_device_register(device);
+	GSList *primaries;
+	GSList *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, CYCLING_SC_UUID, primary_uuid_cmp);
+	if (l == NULL)
+		return -EINVAL;
+
+	return csc_device_register(device, l->data);
 }
 
 static void csc_device_remove(struct btd_profile *p,
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 02/20] cyclingspeed: Add attio callbacks
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

---
 profiles/cyclingspeed/cyclingspeed.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
index 9674a94..4d98810 100644
--- a/profiles/cyclingspeed/cyclingspeed.c
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -31,6 +31,11 @@
 
 #include "adapter.h"
 #include "device.h"
+#include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "attio.h"
+#include "log.h"
 #include "cyclingspeed.h"
 
 struct csc_adapter {
@@ -41,6 +46,9 @@ struct csc_adapter {
 struct csc {
 	struct btd_device	*dev;
 	struct csc_adapter	*cadapter;
+
+	GAttrib			*attrib;
+	guint			attioid;
 };
 
 static GSList *csc_adapters = NULL;
@@ -88,10 +96,35 @@ static void destroy_csc(gpointer user_data)
 {
 	struct csc *csc = user_data;
 
+	if (csc->attioid > 0)
+		btd_device_remove_attio_callback(csc->dev, csc->attioid);
+
+	if (csc->attrib != NULL)
+		g_attrib_unref(csc->attrib);
+
 	btd_device_unref(csc->dev);
 	g_free(csc);
 }
 
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct csc *csc = user_data;
+
+	DBG("");
+
+	csc->attrib = g_attrib_ref(attrib);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct csc *csc = user_data;
+
+	DBG("");
+
+	g_attrib_unref(csc->attrib);
+	csc->attrib = NULL;
+}
+
 int csc_adapter_register(struct btd_adapter *adapter)
 {
 	struct csc_adapter *cadapter;
@@ -135,6 +168,9 @@ int csc_device_register(struct btd_device *device)
 
 	cadapter->devices = g_slist_prepend(cadapter->devices, csc);
 
+	csc->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+						attio_disconnected_cb, csc);
+
 	return 0;
 }
 
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 01/20] cyclingspeed: Add CSC profile plugin skeleton
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1352105705-13988-1-git-send-email-andrzej.kaczmarek@tieto.com>

This patch adds stub profile driver plugin for CSC profile.
---
 Makefile.am                          |   9 +-
 lib/uuid.h                           |   2 +
 profiles/cyclingspeed/cyclingspeed.c | 163 +++++++++++++++++++++++++++++++++++
 profiles/cyclingspeed/cyclingspeed.h |  26 ++++++
 profiles/cyclingspeed/main.c         |  53 ++++++++++++
 profiles/cyclingspeed/manager.c      |  79 +++++++++++++++++
 profiles/cyclingspeed/manager.h      |  24 ++++++
 7 files changed, 354 insertions(+), 2 deletions(-)
 create mode 100644 profiles/cyclingspeed/cyclingspeed.c
 create mode 100644 profiles/cyclingspeed/cyclingspeed.h
 create mode 100644 profiles/cyclingspeed/main.c
 create mode 100644 profiles/cyclingspeed/manager.c
 create mode 100644 profiles/cyclingspeed/manager.h

diff --git a/Makefile.am b/Makefile.am
index 1001ad2..092ac6f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -216,7 +216,7 @@ endif
 
 if GATTMODULES
 builtin_modules += thermometer alert time gatt_example proximity deviceinfo \
-			gatt scanparam heartrate
+			gatt scanparam heartrate cyclingspeed
 builtin_sources += profiles/thermometer/main.c \
 			profiles/thermometer/manager.h \
 			profiles/thermometer/manager.c \
@@ -255,7 +255,12 @@ builtin_sources += profiles/thermometer/main.c \
 			profiles/heartrate/manager.c \
 			profiles/heartrate/manager.h \
 			profiles/heartrate/heartrate.c \
-			profiles/heartrate/heartrate.h
+			profiles/heartrate/heartrate.h \
+			profiles/cyclingspeed/main.c \
+			profiles/cyclingspeed/manager.c \
+			profiles/cyclingspeed/manager.h \
+			profiles/cyclingspeed/cyclingspeed.c \
+			profiles/cyclingspeed/cyclingspeed.h
 
 endif
 
diff --git a/lib/uuid.h b/lib/uuid.h
index a812309..ebc6d27 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -74,6 +74,8 @@ extern "C" {
 #define INTERMEDIATE_TEMPERATURE_UUID	"00002a1e-0000-1000-8000-00805f9b34fb"
 #define MEASUREMENT_INTERVAL_UUID	"00002a21-0000-1000-8000-00805f9b34fb"
 
+#define CYCLING_SC_UUID		"00001816-0000-1000-8000-00805f9b34fb"
+
 #define RFCOMM_UUID_STR		"00000003-0000-1000-8000-00805f9b34fb"
 
 #define HDP_UUID		"00001400-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
new file mode 100644
index 0000000..9674a94
--- /dev/null
+++ b/profiles/cyclingspeed/cyclingspeed.c
@@ -0,0 +1,163 @@
+/*
+ *
+ *  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 <stdbool.h>
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "cyclingspeed.h"
+
+struct csc_adapter {
+	struct btd_adapter	*adapter;
+	GSList			*devices;	/* list of registered devices */
+};
+
+struct csc {
+	struct btd_device	*dev;
+	struct csc_adapter	*cadapter;
+};
+
+static GSList *csc_adapters = NULL;
+
+static gint cmp_adapter(gconstpointer a, gconstpointer b)
+{
+	const struct csc_adapter *cadapter = a;
+	const struct btd_adapter *adapter = b;
+
+	if (adapter == cadapter->adapter)
+		return 0;
+
+	return -1;
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+	const struct csc *csc = a;
+	const struct btd_device *dev = b;
+
+	if (dev == csc->dev)
+		return 0;
+
+	return -1;
+}
+
+static struct csc_adapter *find_csc_adapter(struct btd_adapter *adapter)
+{
+	GSList *l = g_slist_find_custom(csc_adapters, adapter, cmp_adapter);
+
+	if (!l)
+		return NULL;
+
+	return l->data;
+}
+
+static void destroy_csc_adapter(gpointer user_data)
+{
+	struct csc_adapter *cadapter = user_data;
+
+	g_free(cadapter);
+}
+
+static void destroy_csc(gpointer user_data)
+{
+	struct csc *csc = user_data;
+
+	btd_device_unref(csc->dev);
+	g_free(csc);
+}
+
+int csc_adapter_register(struct btd_adapter *adapter)
+{
+	struct csc_adapter *cadapter;
+
+	cadapter = g_new0(struct csc_adapter, 1);
+	cadapter->adapter = adapter;
+
+	csc_adapters = g_slist_prepend(csc_adapters, cadapter);
+
+	return 0;
+}
+
+void csc_adapter_unregister(struct btd_adapter *adapter)
+{
+	struct csc_adapter *cadapter;
+
+	cadapter = find_csc_adapter(adapter);
+	if (cadapter == NULL)
+		return;
+
+	csc_adapters = g_slist_remove(csc_adapters, cadapter);
+
+	destroy_csc_adapter(cadapter);
+}
+
+int csc_device_register(struct btd_device *device)
+{
+	struct btd_adapter *adapter;
+	struct csc_adapter *cadapter;
+	struct csc *csc;
+
+	adapter = device_get_adapter(device);
+
+	cadapter = find_csc_adapter(adapter);
+	if (cadapter == NULL)
+		return -1;
+
+	csc = g_new0(struct csc, 1);
+	csc->dev = btd_device_ref(device);
+	csc->cadapter = cadapter;
+
+	cadapter->devices = g_slist_prepend(cadapter->devices, csc);
+
+	return 0;
+}
+
+void csc_device_unregister(struct btd_device *device)
+{
+	struct btd_adapter *adapter;
+	struct csc_adapter *cadapter;
+	struct csc *csc;
+	GSList *l;
+
+	adapter = device_get_adapter(device);
+
+	cadapter = find_csc_adapter(adapter);
+	if (cadapter == NULL)
+		return;
+
+	l = g_slist_find_custom(cadapter->devices, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	csc = l->data;
+
+	cadapter->devices = g_slist_remove(cadapter->devices, csc);
+
+	destroy_csc(csc);
+}
diff --git a/profiles/cyclingspeed/cyclingspeed.h b/profiles/cyclingspeed/cyclingspeed.h
new file mode 100644
index 0000000..b83fa9e
--- /dev/null
+++ b/profiles/cyclingspeed/cyclingspeed.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *  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 csc_adapter_register(struct btd_adapter *adapter);
+void csc_adapter_unregister(struct btd_adapter *adapter);
+int csc_device_register(struct btd_device *device);
+void csc_device_unregister(struct btd_device *device);
diff --git a/profiles/cyclingspeed/main.c b/profiles/cyclingspeed/main.c
new file mode 100644
index 0000000..c2ef765
--- /dev/null
+++ b/profiles/cyclingspeed/main.c
@@ -0,0 +1,53 @@
+/*
+ *
+ *  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 cyclingspeed_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		DBG("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return cyclingspeed_manager_init();
+}
+
+static void cyclingspeed_exit(void)
+{
+	cyclingspeed_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(cyclingspeed, VERSION,
+					BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+					cyclingspeed_init, cyclingspeed_exit)
diff --git a/profiles/cyclingspeed/manager.c b/profiles/cyclingspeed/manager.c
new file mode 100644
index 0000000..e5f7553
--- /dev/null
+++ b/profiles/cyclingspeed/manager.c
@@ -0,0 +1,79 @@
+/*
+ *
+ *  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 <stdbool.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "cyclingspeed.h"
+#include "manager.h"
+
+static int csc_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+	return csc_adapter_register(adapter);
+}
+
+static void csc_adapter_remove(struct btd_profile *p,
+						struct btd_adapter *adapter)
+{
+	csc_adapter_unregister(adapter);
+}
+
+static int csc_device_probe(struct btd_profile *p,
+				struct btd_device *device, GSList *uuids)
+{
+	return csc_device_register(device);
+}
+
+static void csc_device_remove(struct btd_profile *p,
+						struct btd_device *device)
+{
+	csc_device_unregister(device);
+}
+
+static struct btd_profile cscp_profile = {
+	.name		= "Cycling Speed and Cadence GATT Driver",
+	.remote_uuids	= BTD_UUIDS(CYCLING_SC_UUID),
+
+	.adapter_probe	= csc_adapter_probe,
+	.adapter_remove	= csc_adapter_remove,
+
+	.device_probe	= csc_device_probe,
+	.device_remove	= csc_device_remove,
+};
+
+int cyclingspeed_manager_init(void)
+{
+	return btd_profile_register(&cscp_profile);
+}
+
+void cyclingspeed_manager_exit(void)
+{
+	btd_profile_unregister(&cscp_profile);
+}
diff --git a/profiles/cyclingspeed/manager.h b/profiles/cyclingspeed/manager.h
new file mode 100644
index 0000000..7d25ae4
--- /dev/null
+++ b/profiles/cyclingspeed/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 cyclingspeed_manager_init(void);
+void cyclingspeed_manager_exit(void);
-- 
1.8.0


^ permalink raw reply related

* [PATCH v2 00/20] CSCP plugin
From: Andrzej Kaczmarek @ 2012-11-05  8:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Hi,

Here are v2 patches for CSC profile implementation (cyclingspeed plugin).

Changes since v1:
- signal is emited when Location property is changed
- supported locations CP procedure is done only once (see notes below)
- test script can now calculate instantenous speed and cadence
- few minor fixes found during testing and review

It's now also tested with PTS - can pass all CSCP testcases but there are
few things to remember if someone want to retest:
- testcases in 4.5.3 are broken, look into erratas for updated ets file
- TP/SPL/CO/BV-01-I shall be run after device is removed because Request
  Supported Sensor Location procedure is done only once and then result
  is cached - this is because running it every time device is connected
  will make other testcases using SC Control Point fail due to unexpected
  opcode written (and CSCP spec requires this value to be cached anyway)
- as for now watcher shall be registered before running testcases using
  SC Control Point to make them work - this is because PTS expects that
  measurement notifications are enabled before control point indications,
  otherwise it will wait for writing control point CCC even though it
  was written before. Errata for this is already accepted and TS will be
  changed so both CCC can be written in any order.
- TP/SPS/CO/BV-02-I seems to be broken as it expected different value to
  be written than what is displayed to tester - issue in PTS for this is
  in progress


Comments are welcome.


Andrzej Kaczmarek (20):
  cyclingspeed: Add CSC profile plugin skeleton
  cyclingspeed: Add attio callbacks
  cyclingspeed: Discover CSCS characteristics
  cyclingspeed: Discover characteristics CCC
  cyclingspeed: Read CSC Feature characteristic value
  cyclingspeed: Read Sensor Location characteristic value
  cyclingspeed: Add CyclingSpeedManager interface
  cyclingspeed: Add support to enable measurement notifications
  cyclingspeed: Process measurement notifications
  cyclingspeed: Add DBus.Properties for org.bluez.CyclingSpeed
    interface
  cyclingspeed: Add stub to use SC Control Point
  cyclingspeed: Add support for Request Supported Sensor Locations
  cyclingspeed: Add support for Update Sensor Location
  cyclingspeed: Add support for Set Cumulative Value
  core: Add CyclingSpeedWatcher interface to default policy
  doc: Remove Get-/SetProperties from CSC API document
  doc: Rename cycling API to cyclingspeed
  build: Add CSCP API document to EXTRA_DIST
  test: Add cyclingspeed test script
  test: Enable speed and cadence calculation in test-cyclingspeed

 Makefile.am                          |   11 +-
 Makefile.tools                       |    2 +-
 doc/cycling-api.txt                  |  118 ----
 doc/cyclingspeed-api.txt             |  100 +++
 lib/uuid.h                           |    6 +
 profiles/cyclingspeed/cyclingspeed.c | 1237 ++++++++++++++++++++++++++++++++++
 profiles/cyclingspeed/cyclingspeed.h |   26 +
 profiles/cyclingspeed/main.c         |   53 ++
 profiles/cyclingspeed/manager.c      |   96 +++
 profiles/cyclingspeed/manager.h      |   24 +
 src/bluetooth.conf                   |    1 +
 test/test-cyclingspeed               |  191 ++++++
 12 files changed, 1743 insertions(+), 122 deletions(-)
 delete mode 100644 doc/cycling-api.txt
 create mode 100644 doc/cyclingspeed-api.txt
 create mode 100644 profiles/cyclingspeed/cyclingspeed.c
 create mode 100644 profiles/cyclingspeed/cyclingspeed.h
 create mode 100644 profiles/cyclingspeed/main.c
 create mode 100644 profiles/cyclingspeed/manager.c
 create mode 100644 profiles/cyclingspeed/manager.h
 create mode 100755 test/test-cyclingspeed

-- 
1.8.0


^ permalink raw reply

* Re: [PATCH BlueZ] Enable reconnection in Proximity monitor
From: Johan Hedberg @ 2012-11-05  8:30 UTC (permalink / raw)
  To: Andre Guedes; +Cc: linux-bluetooth
In-Reply-To: <1352061107-23757-1-git-send-email-andre.guedes@openbossa.org>

Hi Andre,

On Sun, Nov 04, 2012, Andre Guedes wrote:
> According to Proximity Profile spec, when a connection is terminated
> due to link loss a Proximity Monitor should attempt to reconnect.
> ---
>  profiles/proximity/monitor.c | 2 ++
>  1 file changed, 2 insertions(+)

Applied. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH hcidump] Change maximum pkt size for High Speed max pkt
From: Johan Hedberg @ 2012-11-05  6:49 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1351689401-3650-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Wed, Oct 31, 2012, Andrei Emeltchenko wrote:
> For AMP, L2CAP packets might be of bigger size, up to 1492 bytes.
> Without the change hcidump cuts AMP data packets.
> ---
>  lib/hci.h |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Applied to bluez-hcidump.git and bluez.git. Thanks.

Johan

^ permalink raw reply

* [PATCH BlueZ] Enable reconnection in Proximity monitor
From: Andre Guedes @ 2012-11-04 20:31 UTC (permalink / raw)
  To: linux-bluetooth

According to Proximity Profile spec, when a connection is terminated
due to link loss a Proximity Monitor should attempt to reconnect.
---
 profiles/proximity/monitor.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/profiles/proximity/monitor.c b/profiles/proximity/monitor.c
index 1a14265..e45fa4a 100644
--- a/profiles/proximity/monitor.c
+++ b/profiles/proximity/monitor.c
@@ -652,6 +652,8 @@ int monitor_register(struct btd_device *device,
 							attio_disconnected_cb,
 							monitor);
 
+	device_set_auto_connect(device, TRUE);
+
 	return 0;
 }
 
-- 
1.8.0


^ permalink raw reply related

* [RFCv3 3/3] Bluetooth: Add sample BT USB mini-driver
From: Tedd Ho-Jeong An @ 2012-11-02 20:54 UTC (permalink / raw)
  To: linux-bluetooth, marcel; +Cc: albert.o.ho, johan.hedberg, tedd.hj.an

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

This patch adds sample BT USB mini-driver

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
---
 drivers/bluetooth/btusb.c        |    3 +
 drivers/bluetooth/btusb_sample.c |  189 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 192 insertions(+)
 create mode 100644 drivers/bluetooth/btusb_sample.c

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 39a1e6c..630d938 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -193,6 +193,9 @@ static struct usb_device_id blacklist_table[] = {
 	/* Frontline ComProbe Bluetooth Sniffer */
 	{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },
 
+	/* BT USB sample mini-driver */
+	{ USB_DEVICE(0x1234, 0x5678), .driver_info = BTUSB_IGNORE },
+
 	{ }	/* Terminating entry */
 };
 
diff --git a/drivers/bluetooth/btusb_sample.c b/drivers/bluetooth/btusb_sample.c
new file mode 100644
index 0000000..6f4a9e0
--- /dev/null
+++ b/drivers/bluetooth/btusb_sample.c
@@ -0,0 +1,189 @@
+/*
+ *
+ *  Bluetooth USB Mini Driver - Sample
+ *
+ *  Copyright (C) 2012  Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btusb.h"
+
+/*
+ * This is sample BT USB mini-driver to demonstrate how a vendor can execute
+ * the vendor specific device initialization routine and handle vendor specific
+ * events.
+ *
+ * In this sample, it will send one vendor HCI command (but not limited to 1)
+ * as an example.
+ */
+
+#define VENDOR_HCI_SAMPLE_CMD_1   0xfc01
+
+/* mini-driver context */
+struct btusb_sample_data {
+	struct hci_dev		*hdev;
+
+	/* for synchronization */
+	struct completion	wait_evt_complete;
+};
+
+/*
+ * Entry point for device setup.
+ */
+int btusb_sample_setup(struct hci_dev *hdev)
+{
+	int ret;
+	struct btusb_sample_data *data;
+
+	/* initialize the sample data */
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		BT_ERR("failed to allocate the memory for data");
+		return -ENOMEM;
+	}
+
+	hdev->vendor_data = data;
+	data->hdev = hdev;
+
+	init_completion(&data->wait_evt_complete);
+
+	/* send command */
+	ret = hci_send_cmd(hdev, VENDOR_HCI_SAMPLE_CMD_1, 0, NULL);
+	if (ret < 0) {
+		BT_ERR("failed to send command: %d", ret);
+		kfree(data);
+		return ret;
+	}
+
+	/* waiting for event */
+	ret = wait_for_completion_interruptible(&data->wait_evt_complete);
+	if (ret < 0) {
+		BT_ERR("wait completion error: %d", ret);
+		kfree(data);
+		return ret;
+	}
+
+
+	/* done */
+	kfree(data);
+
+	return 0;
+}
+
+/*
+ * Vendor specific event handler
+ *
+ * During the vendor setup mode, this function is responsible for handling all
+ * received HCI events.
+ */
+void btusb_sample_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct btusb_sample_data *data;
+	struct hci_event_hdr *hdr;
+	struct hci_ev_cmd_complete *cc;
+	u16 opcode;
+
+	data = hdev->vendor_data;
+
+	/* event header */
+	hdr = (void *)skb->data;
+	if (hdr->evt != HCI_EV_CMD_COMPLETE) {
+		BT_ERR("invalid event code: %02x", hdr->evt);
+		goto exit_error;
+	}
+	skb_pull(skb, sizeof(*hdr));
+
+	/* command complete event */
+	cc = (void *)skb->data;
+	opcode =le16_to_cpu(cc->opcode);
+	if (opcode != VENDOR_HCI_SAMPLE_CMD_1) {
+		BT_ERR("invalid opcode: %04x", opcode);
+		goto exit_error;
+	}
+	skb_pull(skb, sizeof(*cc));
+
+	/* check status */
+	if ((u8)skb->data[0]) {
+		BT_ERR("evt status failed: %02x", (u8)skb->data[0]);
+		goto exit_error;
+	}
+
+exit_error:
+	/* this is for handling the flow control */
+	del_timer(&hdev->cmd_timer);
+	atomic_set(&hdev->cmd_cnt, 1);
+
+	/* consume the event here */
+	kfree_skb(skb);
+
+	/* complete the wait */
+	complete(&data->wait_evt_complete);
+}
+
+/*
+ * Bind this mini-driver to btusb.ko
+ */
+int btusb_sample_bind(struct hci_dev *hdev)
+{
+	/* set the vendor_setup and vendor_event handlers */
+	hdev->vendor_setup = btusb_sample_setup;
+	hdev->vendor_event = btusb_sample_event;
+
+	return 0;
+}
+
+/*
+ * Unbind this mini-driver to btusb.ko
+ */
+void btusb_sample_unbind(struct hci_dev *hdev)
+{
+
+	return;
+}
+
+static const struct btusb_driver_info sample_info = {
+	.description	= "BT USB mini driver sample",
+	.bind		= btusb_sample_bind,
+	.unbind		= btusb_sample_unbind,
+};
+
+static const struct usb_device_id products[] = {
+	{
+		USB_DEVICE(0x1234, 0x5678),
+		.driver_info = (unsigned long) &sample_info,
+	},
+	{},	/* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver btusb_sample_minidriver = {
+	.name		= "btusb sample mini-driver",
+	.probe		= btusb_probe_one,
+	.disconnect	= btusb_disconnect,
+	.id_table	= products,
+};
+module_usb_driver(btusb_sample_minidriver);
+
+MODULE_AUTHOR("Tedd Ho-Jeong An <tedd.an@intel.com>");
+MODULE_DESCRIPTION("BT USB sample mini driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5

^ permalink raw reply related

* [RFCv3 2/3] Bluetooth: Add support vendor specific device setup
From: Tedd Ho-Jeong An @ 2012-11-02 20:54 UTC (permalink / raw)
  To: linux-bluetooth, marcel; +Cc: albert.o.ho, johan.hedberg, tedd.hj.an

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

This patch adds support vendors to execute their specific device
setup before the BT stack sends generic BT device initialization.

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
---
 include/net/bluetooth/hci.h      |    2 ++
 include/net/bluetooth/hci_core.h |    7 +++++++
 net/bluetooth/hci_core.c         |   27 ++++++++++++++++++++++++++-
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 0f28f70..3e9949b 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -117,7 +117,9 @@ enum {
 	HCI_DISCOVERABLE,
 	HCI_LINK_SECURITY,
 	HCI_PENDING_CLASS,
+
 	HCI_PERIODIC_INQ,
+	HCI_VENDOR,		/* for mini-driver vendor specific setup */
 };
 
 /* HCI ioctl defines */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6a3337e..ad4a099 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -275,6 +275,13 @@ struct hci_dev {
 	int (*send)(struct sk_buff *skb);
 	void (*notify)(struct hci_dev *hdev, unsigned int evt);
 	int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
+
+/* CHECKME: Added following members for vendor specific setup in order to make
+ * the bluetooth.ko transparent to the interface below.
+ * These members are set/used by the vendor provided mini-driver. */
+	void			*vendor_data;
+	int (*vendor_setup)(struct hci_dev *hdev);
+	void (*vendor_event)(struct hci_dev *hdev, struct sk_buff *skb);
 };
 
 struct hci_conn {
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e407051..09e7fa2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -685,6 +685,21 @@ int hci_dev_open(__u16 dev)
 		set_bit(HCI_INIT, &hdev->flags);
 		hdev->init_last_cmd = 0;
 
+/* CHECKME: this is the required spot for executing the vendor setup code.
+ * We need btusb_open() to complete so HCI event can be received and
+ * processed by vendor_event() handler. vendor_setup() must be done first
+ * before hci_init_req.
+ * vendor_setup() runs once only.*/
+		if (hdev->vendor_setup) {
+			set_bit(HCI_VENDOR, &hdev->dev_flags);
+			ret = hdev->vendor_setup(hdev);
+			hdev->vendor_event = NULL;
+			hdev->vendor_setup = NULL;
+			clear_bit(HCI_VENDOR, &hdev->dev_flags);
+			if (ret < 0)
+				goto done;
+		}
+
 		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
 
 		if (lmp_host_le_capable(hdev))
@@ -2119,6 +2134,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 
 	return 0;
 }
+EXPORT_SYMBOL(hci_send_cmd);
 
 /* Get data from the previously sent command */
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
@@ -2800,7 +2816,16 @@ static void hci_rx_work(struct work_struct *work)
 		switch (bt_cb(skb)->pkt_type) {
 		case HCI_EVENT_PKT:
 			BT_DBG("%s Event packet", hdev->name);
-			hci_event_packet(hdev, skb);
+/* CHECKME: If we are in vendor mode, all HCI events are handled by
+ * vendor_event() and not handled by normal stack flows. vendor_event() shall
+ * also be responsible for handling flow control.
+ *
+ * Please see the mini-driver sample code. */
+			if (test_bit(HCI_VENDOR, &hdev->dev_flags)
+					&& hdev->vendor_event)
+				hdev->vendor_event(hdev, skb);
+			else
+				hci_event_packet(hdev, skb);
 			break;
 
 		case HCI_ACLDATA_PKT:
-- 
1.7.9.5

^ permalink raw reply related

* [RFCv3 1/3] Bluetooth: Add support BT mini-driver
From: Tedd Ho-Jeong An @ 2012-11-02 20:54 UTC (permalink / raw)
  To: linux-bluetooth, marcel; +Cc: albert.o.ho, johan.hedberg, tedd.hj.an

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

This patch add mini-driver support in BTUSB

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
---
 drivers/bluetooth/btusb.c |   68 +++++++++++++++++++++++++++++++++++++++++----
 drivers/bluetooth/btusb.h |   44 +++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+), 6 deletions(-)
 create mode 100644 drivers/bluetooth/btusb.h

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index f637c25..39a1e6c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -27,6 +27,8 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
+#include "btusb.h"
+
 #define VERSION "0.6"
 
 static bool ignore_dga;
@@ -47,6 +49,7 @@ static struct usb_driver btusb_driver;
 #define BTUSB_BROKEN_ISOC	0x20
 #define BTUSB_WRONG_SCO_MTU	0x40
 #define BTUSB_ATH3012		0x80
+#define BTUSB_VENDOR		0x100
 
 static struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
@@ -206,6 +209,7 @@ struct btusb_data {
 	struct usb_device    *udev;
 	struct usb_interface *intf;
 	struct usb_interface *isoc;
+	struct btusb_driver_info *driver_info;
 
 	spinlock_t lock;
 
@@ -952,9 +956,15 @@ static int btusb_probe(struct usb_interface *intf,
 			return -ENODEV;
 	}
 
-	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
+/* CHECKME: if mini-driver invokes btusb_probe, btusb_data already has been
+ * allocated. If btusb_probe is directly invoked by usb core, then allocate
+ * here. */
+	data = usb_get_intfdata(intf);
+	if (!data) {
+		data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+	}
 
 	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
 		ep_desc = &intf->cur_altsetting->endpoint[i].desc;
@@ -1012,6 +1022,17 @@ static int btusb_probe(struct usb_interface *intf,
 	hdev->send     = btusb_send_frame;
 	hdev->notify   = btusb_notify;
 
+	/* bind the vendor specific mini-driver */
+	if ((id->driver_info & BTUSB_VENDOR) && data->driver_info) {
+		if (data->driver_info->bind) {
+			err = data->driver_info->bind(hdev);
+			if (err < 0) {
+				hci_free_dev(hdev);
+				return err;
+			}
+		}
+	}
+
 	/* Interface numbers are hardcoded in the specification */
 	data->isoc = usb_ifnum_to_if(data->udev, 1);
 
@@ -1080,7 +1101,35 @@ static int btusb_probe(struct usb_interface *intf,
 	return 0;
 }
 
-static void btusb_disconnect(struct usb_interface *intf)
+/*
+ * CHECKME: vendor's mini-driver should call this function to setup
+ * the vendor specific btusb_driver_info struct
+ */
+int btusb_probe_one(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device_id *vendor_id = (struct usb_device_id *)id;
+	struct btusb_data *data;
+
+	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (vendor_id->driver_info) {
+/* CHECKME: store the driver_info (btusb_driver_info struct) from mini-driver
+ * to btusb_data for later use and change it to BTUSB_VENDOR flag. */
+		data->driver_info =
+			(struct btusb_driver_info *)vendor_id->driver_info;
+		vendor_id->driver_info = BTUSB_VENDOR;
+	}
+
+	usb_set_intfdata(intf, data);
+
+	return btusb_probe(intf, vendor_id);
+}
+EXPORT_SYMBOL(btusb_probe_one);
+
+void btusb_disconnect(struct usb_interface *intf)
 {
 	struct btusb_data *data = usb_get_intfdata(intf);
 	struct hci_dev *hdev;
@@ -1103,11 +1152,16 @@ static void btusb_disconnect(struct usb_interface *intf)
 	else if (data->isoc)
 		usb_driver_release_interface(&btusb_driver, data->isoc);
 
+	/* unbind the vendor specific mini-driver */
+	if (data->driver_info && data->driver_info->unbind)
+		data->driver_info->unbind(hdev);
+
 	hci_free_dev(hdev);
 }
+EXPORT_SYMBOL(btusb_disconnect);
 
 #ifdef CONFIG_PM
-static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
+int btusb_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct btusb_data *data = usb_get_intfdata(intf);
 
@@ -1133,6 +1187,7 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
 
 	return 0;
 }
+EXPORT_SYMBOL(btusb_suspend);
 
 static void play_deferred(struct btusb_data *data)
 {
@@ -1149,7 +1204,7 @@ static void play_deferred(struct btusb_data *data)
 	usb_scuttle_anchored_urbs(&data->deferred);
 }
 
-static int btusb_resume(struct usb_interface *intf)
+int btusb_resume(struct usb_interface *intf)
 {
 	struct btusb_data *data = usb_get_intfdata(intf);
 	struct hci_dev *hdev = data->hdev;
@@ -1205,6 +1260,7 @@ done:
 
 	return err;
 }
+EXPORT_SYMBOL(btusb_resume);
 #endif
 
 static struct usb_driver btusb_driver = {
diff --git a/drivers/bluetooth/btusb.h b/drivers/bluetooth/btusb.h
new file mode 100644
index 0000000..35bcfa9
--- /dev/null
+++ b/drivers/bluetooth/btusb.h
@@ -0,0 +1,44 @@
+/*
+ *
+ *  Generic Bluetooth USB driver
+ *
+ *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _BTUSB_H
+#define _BTUSB_H
+
+struct btusb_driver_info {
+	char	*description;
+
+	/* initialize the vendor setup routines */
+	int	(*bind)(struct hci_dev *);
+
+	/* clean up */
+	void	(*unbind)(struct hci_dev *);
+};
+
+extern int btusb_probe_one(struct usb_interface *,
+				const struct usb_device_id *);
+extern void btusb_disconnect(struct usb_interface *);
+#ifdef CONFIG_PM
+extern int btusb_suspend(struct usb_interface *, pm_message_t);
+extern int btusb_resume(struct usb_interface *);
+#endif
+
+#endif /* _BTUSB_H */
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCHv1 11/12] Bluetooth: AMP: Use l2cap_physical_cfm in phylink complete evt
From: Mat Martineau @ 2012-11-02 15:39 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <20121102074844.GA4171@aemeltch-MOBL1>


Andrei -

On Fri, 2 Nov 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> On Thu, Nov 01, 2012 at 10:51:19AM -0700, Mat Martineau wrote:
>>
>> Andrei -
>>
>> On Wed, 31 Oct 2012, Andrei Emeltchenko wrote:
>>
>>> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>>>
>>> When receiving HCI Phylink Complete event run amp_physical_cfm
>>> which initialize BR/EDR L2CAP channel associated with High Speed
>>> link and run l2cap_physical_cfm which shall send L2CAP Create
>>> Chan Request.
>>>
>>> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>>> Acked-by: Marcel Holtmann <marcel@holtmann.org>
>>> ---
>>> include/net/bluetooth/amp.h   |    1 +
>>> include/net/bluetooth/l2cap.h |    1 +
>>> net/bluetooth/amp.c           |   24 ++++++++++++++++++++++++
>>> net/bluetooth/hci_event.c     |   15 ++-------------
>>> 4 files changed, 28 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
>>> index f1c0017..7ea3db7 100644
>>> --- a/include/net/bluetooth/amp.h
>>> +++ b/include/net/bluetooth/amp.h
>>> @@ -46,6 +46,7 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
>>> 			struct hci_conn *hcon);
>>> void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
>>> void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
>>> +void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon);
>>> void amp_create_logical_link(struct l2cap_chan *chan);
>>> void amp_disconnect_logical_link(struct hci_chan *hchan);
>>> void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason);
>>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>>> index 24c61ef..18149c8 100644
>>> --- a/include/net/bluetooth/l2cap.h
>>> +++ b/include/net/bluetooth/l2cap.h
>>> @@ -812,5 +812,6 @@ void l2cap_send_conn_req(struct l2cap_chan *chan);
>>> void l2cap_move_start(struct l2cap_chan *chan);
>>> void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
>>> 		       u8 status);
>>> +void l2cap_physical_cfm(struct l2cap_chan *chan, int result);
>>>
>>> #endif /* __L2CAP_H */
>>> diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
>>> index 917e034..650bb8d 100644
>>> --- a/net/bluetooth/amp.c
>>> +++ b/net/bluetooth/amp.c
>>> @@ -373,6 +373,30 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
>>> 	hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
>>> }
>>>
>>> +void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
>>> +{
>>> +	struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev);
>>> +	struct amp_mgr *mgr = hs_hcon->amp_mgr;
>>> +	struct l2cap_chan *bredr_chan;
>>> +
>>> +	BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr);
>>> +
>>> +	if (!bredr_hdev || !mgr || !mgr->bredr_chan)
>>> +		return;
>>> +
>>> +	bredr_chan = mgr->bredr_chan;
>>> +
>>> +	set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags);
>>> +	bredr_chan->ctrl_id = hs_hcon->remote_id;
>>> +	bredr_chan->hs_hcon = hs_hcon;
>>> +	bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu;
>>> +	bredr_chan->fcs = L2CAP_FCS_NONE;

Changing FCS requires L2CAP reconfiguration for the channel, and 
chan->fcs shouldn't be modified until reconfiguration happens.  While 
it doesn't make much sense to do so, the remote device may want to 
keep FCS enabled.  The move may also fail and you don't want to forget 
the original FCS setting in that case.

>>
>> Sorry I missed this earlier: bredr_chan needs to be locked before
>> changing it.  I suggest passing the information to
>> l2cap_physical_cfm and letting that function update the structure
>> members while it holds the lock.
>
> what about locking here and changing l2cap_physical_cfm to unlocked
> __l2cap_physical_cfm ?

My preference is to not manipulate l2cap_chan too much outside of 
l2cap_core, and to keep the channel move or channel create state 
machines inside l2cap_core.  l2cap_physical_cfm checks the channel 
state before modifying it.  The move or new connection may have been 
canceled or be in the wrong state, in which case the structure should 
not be modified even though the physical link was completed.

>
>>
>>
>>> +
>>> +	l2cap_physical_cfm(bredr_chan, 0);
>>> +
>>> +	hci_dev_put(bredr_hdev);
>>> +}

Regards,

--
Mat Martineau

Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply

* Cybertan MM230-M issue
From: Yegor Yefremov @ 2012-11-02  9:55 UTC (permalink / raw)
  To: linux-bluetooth

I'm using this WLAN-BT-combo card with linux 3.2 and TI am335x based
board. WLAN (88W8686/B1 (Marvell) ) is working, but Bluetooth
(BC4ROM/21e (CSR)) only partly.

I can connect to the card via hciattach ttyO5 bcsp and then I can
bring it up and enable pscan. But hcitool scan delivers nothing.

I get following values via bccmd:

Chip revision: 0x0030 (BC4-ROM)
Build name: odj_4hci_rom_bt2.0_21e_0604241634_encr128 2006-04-24

bccmd -t BCSP -d /dev/ttyO5 -b 115200 enabletx returns with error:
Can't execute command: No such device or address (6)

Any idea how to get the card working?

Regards,
Yegor

^ permalink raw reply


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