* [PATCH v3 11/17] heartrate: Read Heart Rate Control Point characteristics
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
This patch reads and stores Heart Rate Control Point characteristics value.
---
profiles/heartrate/heartrate.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 150a675..4591e56 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -58,6 +58,7 @@ struct heartrate {
GSList *chars;
gboolean has_location;
uint8_t location;
+ gboolean has_cp_reset;
};
struct characteristic {
@@ -420,6 +421,7 @@ static void process_heartrate_char(struct characteristic *ch)
{
if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0) {
DBG("Heart Rate Control Point reset supported by client");
+ ch->hr->has_cp_reset = TRUE;
} else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
DBG("Body Sensor Location supported by client");
gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 10/17] heartrate: Read Body Sensor Location characteristics
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch reads and stores Body Sensor Location characteristics value.
---
profiles/heartrate/heartrate.c | 40 +++++++++++++++++++++++++++++++++++++---
1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 9d29ee0..150a675 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -56,6 +56,8 @@ struct heartrate {
guint attioid;
struct att_range *svc_range;
GSList *chars;
+ gboolean has_location;
+ uint8_t location;
};
struct characteristic {
@@ -385,12 +387,44 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
{ }
};
+static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
+ guint16 len, gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ struct heartrate *hr = ch->hr;
+ uint8_t value;
+ ssize_t vlen;
+
+ if (status != 0) {
+ error("Body Sensor Location value read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, &value, sizeof(value));
+ if (vlen < 0) {
+ error("Protocol error.");
+ return;
+ }
+
+ if (vlen != 1) {
+ error("Invalid length for Body Sensor Location");
+ return;
+ }
+
+ hr->has_location = TRUE;
+ hr->location = value;
+}
+
static void process_heartrate_char(struct characteristic *ch)
{
- if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
- DBG("Heart Rate Control Point supported by client");
- else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0)
+ if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0) {
+ DBG("Heart Rate Control Point reset supported by client");
+ } else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
DBG("Body Sensor Location supported by client");
+ gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
+ read_sensor_location_cb, ch);
+ }
}
static void process_heartrate_desc(struct descriptor *desc)
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 09/17] heartrate: Enable measurement when watchers are registered
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
This patch will enable measurement notification when first watcher is
registered or when device is connected and watcher is already registered.
Measurement will be disabled when last watcher is unregistered.
---
profiles/heartrate/heartrate.c | 129 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 1 deletion(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index a223fe0..9d29ee0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -101,6 +101,22 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
return -1;
}
+static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
+{
+ const struct characteristic *ch = a;
+ const char *uuid = b;
+
+ return g_strcmp0(ch->attr.uuid, uuid);
+}
+
+static gint cmp_descriptor(gconstpointer a, gconstpointer b)
+{
+ const struct descriptor *desc = a;
+ const bt_uuid_t *uuid = b;
+
+ return bt_uuid_cmp(&desc->uuid, uuid);
+}
+
static gint cmp_watcher(gconstpointer a, gconstpointer b)
{
const struct watcher *watcher = a;
@@ -181,6 +197,91 @@ static void destroy_heartrate_adapter(gpointer user_data)
g_free(hra);
}
+static struct characteristic *get_characteristic(struct heartrate *hr,
+ const char *uuid)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(hr->chars, uuid, cmp_char_uuid);
+ if (l == NULL)
+ return NULL;
+
+ return l->data;
+}
+
+static struct descriptor *get_descriptor(struct characteristic *ch,
+ const bt_uuid_t *uuid)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
+ if (l == NULL)
+ return NULL;
+
+ return l->data;
+}
+
+static void 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 measurement_toggle(struct heartrate *hr, gboolean enable)
+{
+ struct characteristic *ch;
+ struct descriptor *desc;
+ bt_uuid_t btuuid;
+ uint8_t atval[2];
+ char *msg;
+
+ if (hr->attrib == NULL)
+ return;
+
+ ch = get_characteristic(hr, HEART_RATE_MEASUREMENT_UUID);
+ if (ch == NULL) {
+ DBG("Heart Rate Measurement characteristic not found");
+ return;
+ }
+
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ desc = get_descriptor(ch, &btuuid);
+ if (desc == NULL) {
+ DBG("Client Characteristic Configuration descriptor not found");
+ return;
+ }
+
+ if (enable) {
+ att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, atval);
+ msg = g_strdup("Enable measurement");
+ } else {
+ att_put_u16(0x0000, atval);
+ msg = g_strdup("Disable measurement");
+ }
+
+ gatt_write_char(hr->attrib, desc->handle, atval, 2, char_write_cb, msg);
+
+}
+
+static void measurement_enable(gpointer data, gpointer user_data)
+{
+ struct heartrate *hr = data;
+
+ measurement_toggle(hr, TRUE);
+}
+
+static void measurement_disable(gpointer data, gpointer user_data)
+{
+ struct heartrate *hr = data;
+
+ measurement_toggle(hr, FALSE);
+}
+
static void watcher_exit(DBusConnection *conn, void *user_data)
{
struct watcher *watcher = user_data;
@@ -190,6 +291,9 @@ static void watcher_exit(DBusConnection *conn, void *user_data)
hr->watchers = g_slist_remove(hr->watchers, watcher);
g_dbus_remove_watch(conn, watcher->id);
+
+ if (g_slist_length(hr->watchers) == 0)
+ g_slist_foreach(hr->devices, measurement_disable, 0);
}
static struct watcher *find_watcher(GSList *list, const char *sender,
@@ -236,6 +340,9 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
watcher, destroy_watcher);
+ if (g_slist_length(hra->watchers) == 0)
+ g_slist_foreach(hra->devices, measurement_enable, 0);
+
hra->watchers = g_slist_prepend(hra->watchers, watcher);
return dbus_message_new_method_return(msg);
@@ -262,6 +369,9 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
hr->watchers = g_slist_remove(hr->watchers, watcher);
g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+ if (g_slist_length(hr->watchers) == 0)
+ g_slist_foreach(hr->devices, measurement_disable, 0);
+
return dbus_message_new_method_return(msg);
}
@@ -291,9 +401,26 @@ static void process_heartrate_desc(struct descriptor *desc)
bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0)
+ if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+ uint8_t atval[2];
+ char *msg;
+
+ if (g_strcmp0(ch->attr.uuid, HEART_RATE_MEASUREMENT_UUID) != 0)
+ goto done;
+
+ if (g_slist_length(ch->hr->hra->watchers) == 0)
+ return;
+
+ att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, atval);
+ msg = g_strdup("Enable measurement");
+
+ gatt_write_char(ch->hr->attrib, desc->handle,
+ atval, 2, char_write_cb, msg);
+
return;
+ }
+done:
bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
DBG("Ignored descriptor %s in characteristic %s", uuidstr,
ch->attr.uuid);
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 08/17] heartrate: Add HeartRateManager interface
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch adds support for org.bluez.HeartRateManager interface on adapters
which allows to register and unregister per-adapter watcher.
---
profiles/heartrate/heartrate.c | 155 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 154 insertions(+), 1 deletion(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index eec8ae0..a223fe0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -24,13 +24,16 @@
#include <config.h>
#endif
+#include <gdbus.h>
#include <errno.h>
#include <stdbool.h>
#include <glib.h>
#include <bluetooth/uuid.h>
#include "adapter.h"
+#include "dbus-common.h"
#include "device.h"
+#include "error.h"
#include "gattrib.h"
#include "attio.h"
#include "att.h"
@@ -38,9 +41,12 @@
#include "heartrate.h"
#include "log.h"
+#define HEART_RATE_MANAGER_IFACE "org.bluez.HeartRateManager"
+
struct heartrate_adapter {
struct btd_adapter *adapter;
GSList *devices;
+ GSList *watchers;
};
struct heartrate {
@@ -64,6 +70,13 @@ struct descriptor {
bt_uuid_t uuid;
};
+struct watcher {
+ struct heartrate_adapter *hra;
+ guint id;
+ char *srv;
+ char *path;
+};
+
static GSList *heartrate_adapters = NULL;
static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -88,6 +101,19 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
return -1;
}
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+ const struct watcher *watcher = a;
+ const struct watcher *match = b;
+ int ret;
+
+ ret = g_strcmp0(watcher->srv, match->srv);
+ if (ret != 0)
+ return ret;
+
+ return g_strcmp0(watcher->path, match->path);
+}
+
static struct heartrate_adapter *
find_heartrate_adapter(struct btd_adapter *adapter)
{
@@ -108,6 +134,22 @@ static void destroy_char(gpointer user_data)
g_free(c);
}
+static void remove_watcher(gpointer user_data)
+{
+ struct watcher *watcher = user_data;
+
+ g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+ struct watcher *watcher = user_data;
+
+ g_free(watcher->path);
+ g_free(watcher->srv);
+ g_free(watcher);
+}
+
static void destroy_heartrate_device(gpointer user_data)
{
struct heartrate *hr = user_data;
@@ -133,9 +175,106 @@ static void destroy_heartrate_adapter(gpointer user_data)
if (hra->devices != NULL)
g_slist_free_full(hra->devices, destroy_heartrate_device);
+ if (hra->watchers != NULL)
+ g_slist_free_full(hra->watchers, remove_watcher);
+
g_free(hra);
}
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+ struct watcher *watcher = user_data;
+ struct heartrate_adapter *hr = watcher->hra;
+
+ DBG("Heart Rate watcher %s disconnected", watcher->path);
+
+ hr->watchers = g_slist_remove(hr->watchers, watcher);
+ g_dbus_remove_watch(conn, watcher->id);
+}
+
+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 DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct heartrate_adapter *hra = data;
+ struct watcher *watcher;
+ char *path;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ watcher = find_watcher(hra->watchers, sender, path);
+ if (watcher != NULL)
+ return btd_error_already_exists(msg);
+
+ DBG("Heart Rate watcher %s registered", path);
+
+ watcher = g_new0(struct watcher, 1);
+ watcher->srv = g_strdup(sender);
+ watcher->path = g_strdup(path);
+ watcher->hra = hra;
+ watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+ watcher, destroy_watcher);
+
+ hra->watchers = g_slist_prepend(hra->watchers, watcher);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct heartrate_adapter *hr = data;
+ struct watcher *watcher;
+ char *path;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ watcher = find_watcher(hr->watchers, sender, path);
+ if (watcher == NULL)
+ return btd_error_does_not_exist(msg);
+
+ DBG("Heart Rate watcher %s unregistered", path);
+
+ hr->watchers = g_slist_remove(hr->watchers, watcher);
+ g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_manager_methods[] = {
+ { GDBUS_METHOD("RegisterWatcher",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ register_watcher) },
+ { GDBUS_METHOD("UnregisterWatcher",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ unregister_watcher) },
+ { }
+};
+
static void process_heartrate_char(struct characteristic *ch)
{
if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
@@ -275,6 +414,18 @@ int heartrate_adapter_register(struct btd_adapter *adapter)
hra = g_new0(struct heartrate_adapter, 1);
hra->adapter = adapter;
+ if (!g_dbus_register_interface(get_dbus_connection(),
+ adapter_get_path(adapter),
+ HEART_RATE_MANAGER_IFACE,
+ heartrate_manager_methods,
+ NULL, NULL, hra,
+ destroy_heartrate_adapter)) {
+ error("D-Bus failed to register %s interface",
+ HEART_RATE_MANAGER_IFACE);
+ destroy_heartrate_adapter(hra);
+ return -EIO;
+ }
+
heartrate_adapters = g_slist_prepend(heartrate_adapters, hra);
return 0;
@@ -290,7 +441,9 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
heartrate_adapters = g_slist_remove(heartrate_adapters, hra);
- destroy_heartrate_adapter(hra);
+ g_dbus_unregister_interface(get_dbus_connection(),
+ adapter_get_path(hra->adapter),
+ HEART_RATE_MANAGER_IFACE);
}
int heartrate_device_register(struct btd_device *device,
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 07/17] heartrate: Process characteristics descriptors
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch adds stub to process discovered characteristics descriptors.
---
lib/uuid.h | 1 +
profiles/heartrate/heartrate.c | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/lib/uuid.h b/lib/uuid.h
index 0a9db51..15a80a0 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,7 @@ extern "C" {
#define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb"
#define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_MEASUREMENT_UUID "00002a37-0000-1000-8000-00805f9b34fb"
#define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb"
#define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 69d6d51..eec8ae0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -144,6 +144,22 @@ static void process_heartrate_char(struct characteristic *ch)
DBG("Body Sensor Location supported by client");
}
+static void process_heartrate_desc(struct descriptor *desc)
+{
+ struct characteristic *ch = desc->ch;
+ char uuidstr[MAX_LEN_UUID_STR];
+ bt_uuid_t btuuid;
+
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+ if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0)
+ return;
+
+ bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+ DBG("Ignored descriptor %s in characteristic %s", uuidstr,
+ ch->attr.uuid);
+}
+
static void discover_desc_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
@@ -177,6 +193,8 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
desc->uuid = att_get_uuid128(value + 2);
ch->desc = g_slist_append(ch->desc, desc);
+
+ process_heartrate_desc(desc);
}
att_data_list_free(list);
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 06/17] heartrate: Discover characteristics descriptors
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
---
profiles/heartrate/heartrate.c | 72 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 02a4617..69d6d51 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -55,6 +55,13 @@ struct heartrate {
struct characteristic {
struct gatt_char attr;
struct heartrate *hr;
+ GSList *desc;
+};
+
+struct descriptor {
+ struct characteristic *ch;
+ uint16_t handle;
+ bt_uuid_t uuid;
};
static GSList *heartrate_adapters = NULL;
@@ -92,6 +99,15 @@ find_heartrate_adapter(struct btd_adapter *adapter)
return l->data;
}
+static void destroy_char(gpointer user_data)
+{
+ struct characteristic *c = user_data;
+
+ g_slist_free_full(c->desc, g_free);
+
+ g_free(c);
+}
+
static void destroy_heartrate_device(gpointer user_data)
{
struct heartrate *hr = user_data;
@@ -103,7 +119,7 @@ static void destroy_heartrate_device(gpointer user_data)
g_attrib_unref(hr->attrib);
if (hr->chars != NULL)
- g_slist_free_full(hr->chars, g_free);
+ g_slist_free_full(hr->chars, destroy_char);
btd_device_unref(hr->dev);
g_free(hr->svc_range);
@@ -128,6 +144,44 @@ static void process_heartrate_char(struct characteristic *ch)
DBG("Body Sensor Location supported by client");
}
+static void discover_desc_cb(guint8 status, const guint8 *pdu,
+ guint16 len, gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ struct att_data_list *list;
+ uint8_t format;
+ int i;
+
+ if (status != 0) {
+ error("Discover all characteristic descriptors failed [%s]: %s",
+ ch->attr.uuid, att_ecode2str(status));
+ return;
+ }
+
+ list = dec_find_info_resp(pdu, len, &format);
+ if (list == NULL)
+ return;
+
+ for (i = 0; i < list->num; i++) {
+ struct descriptor *desc;
+ uint8_t *value;
+
+ value = list->data[i];
+ desc = g_new0(struct descriptor, 1);
+ desc->handle = att_get_u16(value);
+ desc->ch = ch;
+
+ if (format == 0x01)
+ desc->uuid = att_get_uuid16(value + 2);
+ else
+ desc->uuid = att_get_uuid128(value + 2);
+
+ ch->desc = g_slist_append(ch->desc, desc);
+ }
+
+ att_data_list_free(list);
+}
+
static void configure_heartrate_cb(GSList *characteristics, guint8 status,
gpointer user_data)
{
@@ -143,6 +197,7 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
for (l = characteristics; l; l = l->next) {
struct gatt_char *c = l->data;
struct characteristic *ch;
+ uint16_t start, end;
ch = g_new0(struct characteristic, 1);
ch->attr.handle = c->handle;
@@ -154,6 +209,21 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
hr->chars = g_slist_append(hr->chars, ch);
process_heartrate_char(ch);
+
+ start = c->value_handle + 1;
+
+ if (l->next != NULL) {
+ struct gatt_char *c = l->next->data;
+ if (start == c->handle)
+ continue;
+ end = c->handle - 1;
+ } else if (c->value_handle != hr->svc_range->end) {
+ end = hr->svc_range->end;
+ } else {
+ continue;
+ }
+
+ gatt_find_info(hr->attrib, start, end, discover_desc_cb, ch);
}
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 05/17] heartrate: Process characteristics
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch adds stub to process discovered characteristics.
---
lib/uuid.h | 2 ++
profiles/heartrate/heartrate.c | 10 ++++++++++
2 files changed, 12 insertions(+)
diff --git a/lib/uuid.h b/lib/uuid.h
index 3488e66..0a9db51 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,8 @@ extern "C" {
#define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb"
#define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb"
+#define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb"
#define HEALTH_THERMOMETER_UUID "00001809-0000-1000-8000-00805f9b34fb"
#define TEMPERATURE_MEASUREMENT_UUID "00002a1c-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index e4147cf..02a4617 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -120,6 +120,14 @@ static void destroy_heartrate_adapter(gpointer user_data)
g_free(hra);
}
+static void process_heartrate_char(struct characteristic *ch)
+{
+ if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
+ DBG("Heart Rate Control Point supported by client");
+ else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0)
+ DBG("Body Sensor Location supported by client");
+}
+
static void configure_heartrate_cb(GSList *characteristics, guint8 status,
gpointer user_data)
{
@@ -144,6 +152,8 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
ch->hr = hr;
hr->chars = g_slist_append(hr->chars, ch);
+
+ process_heartrate_char(ch);
}
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 04/17] heartrate: Discover characteristics
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch adds support to discover Heart Rate Service characteristics when
connected to remote device.
---
profiles/heartrate/heartrate.c | 49 +++++++++++++++++++++++++++++++++++++++++-
profiles/heartrate/heartrate.h | 3 ++-
profiles/heartrate/manager.c | 22 ++++++++++++++++++-
3 files changed, 71 insertions(+), 3 deletions(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 918546e..e4147cf 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -48,6 +48,13 @@ struct heartrate {
struct heartrate_adapter *hra;
GAttrib *attrib;
guint attioid;
+ struct att_range *svc_range;
+ GSList *chars;
+};
+
+struct characteristic {
+ struct gatt_char attr;
+ struct heartrate *hr;
};
static GSList *heartrate_adapters = NULL;
@@ -95,7 +102,11 @@ static void destroy_heartrate_device(gpointer user_data)
if (hr->attrib != NULL)
g_attrib_unref(hr->attrib);
+ if (hr->chars != NULL)
+ g_slist_free_full(hr->chars, g_free);
+
btd_device_unref(hr->dev);
+ g_free(hr->svc_range);
g_free(hr);
}
@@ -109,6 +120,33 @@ static void destroy_heartrate_adapter(gpointer user_data)
g_free(hra);
}
+static void configure_heartrate_cb(GSList *characteristics, guint8 status,
+ gpointer user_data)
+{
+ struct heartrate *hr = user_data;
+ GSList *l;
+
+ if (status != 0) {
+ error("Discover Heart Rate characteristics: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ for (l = characteristics; l; l = l->next) {
+ struct gatt_char *c = l->data;
+ struct characteristic *ch;
+
+ ch = g_new0(struct characteristic, 1);
+ ch->attr.handle = c->handle;
+ ch->attr.properties = c->properties;
+ ch->attr.value_handle = c->value_handle;
+ memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+ ch->hr = hr;
+
+ hr->chars = g_slist_append(hr->chars, ch);
+ }
+}
+
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
{
struct heartrate *hr = user_data;
@@ -116,6 +154,10 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
DBG("GATT Connected");
hr->attrib = g_attrib_ref(attrib);
+
+ gatt_discover_char(hr->attrib, hr->svc_range->start,
+ hr->svc_range->end, NULL,
+ configure_heartrate_cb, hr);
}
static void attio_disconnected_cb(gpointer user_data)
@@ -153,7 +195,8 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
destroy_heartrate_adapter(hra);
}
-int heartrate_device_register(struct btd_device *device)
+int heartrate_device_register(struct btd_device *device,
+ struct gatt_primary *pattr)
{
struct heartrate_adapter *hra;
struct btd_adapter *adapter;
@@ -172,6 +215,10 @@ int heartrate_device_register(struct btd_device *device)
hra->devices = g_slist_prepend(hra->devices, hr);
+ hr->svc_range = g_new0(struct att_range, 1);
+ hr->svc_range->start = pattr->range.start;
+ hr->svc_range->end = pattr->range.end;
+
hr->attioid = btd_device_add_attio_callback(device,
attio_connected_cb,
attio_disconnected_cb,
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
index 486f5b3..ec3ed7a 100644
--- a/profiles/heartrate/heartrate.h
+++ b/profiles/heartrate/heartrate.h
@@ -22,5 +22,6 @@
int heartrate_adapter_register(struct btd_adapter *adapter);
void heartrate_adapter_unregister(struct btd_adapter *adapter);
-int heartrate_device_register(struct btd_device *device);
+int heartrate_device_register(struct btd_device *device,
+ struct gatt_primary *pattr);
void heartrate_device_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
index 9d2446c..ff2da21 100644
--- a/profiles/heartrate/manager.c
+++ b/profiles/heartrate/manager.c
@@ -33,6 +33,14 @@
#include "heartrate.h"
#include "manager.h"
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_primary *prim = a;
+ const char *uuid = b;
+
+ return g_strcmp0(prim->uuid, uuid);
+}
+
static int heartrate_adapter_probe(struct btd_adapter *adapter)
{
return heartrate_adapter_register(adapter);
@@ -45,7 +53,19 @@ static void heartrate_adapter_remove(struct btd_adapter *adapter)
static int heartrate_device_probe(struct btd_device *device, GSList *uuids)
{
- return heartrate_device_register(device);
+ struct gatt_primary *pattr;
+ GSList *primaries, *l;
+
+ primaries = btd_device_get_primaries(device);
+
+ l = g_slist_find_custom(primaries, HEART_RATE_UUID,
+ primary_uuid_cmp);
+ if (l == NULL)
+ return -EINVAL;
+
+ pattr = l->data;
+
+ return heartrate_device_register(device, pattr);
}
static void heartrate_device_remove(struct btd_device *device)
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 03/17] heartrate: Add attio callbacks
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
---
profiles/heartrate/heartrate.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 17514c0..918546e 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -31,7 +31,12 @@
#include "adapter.h"
#include "device.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gatt.h"
#include "heartrate.h"
+#include "log.h"
struct heartrate_adapter {
struct btd_adapter *adapter;
@@ -41,6 +46,8 @@ struct heartrate_adapter {
struct heartrate {
struct btd_device *dev;
struct heartrate_adapter *hra;
+ GAttrib *attrib;
+ guint attioid;
};
static GSList *heartrate_adapters = NULL;
@@ -82,6 +89,12 @@ static void destroy_heartrate_device(gpointer user_data)
{
struct heartrate *hr = user_data;
+ if (hr->attioid > 0)
+ btd_device_remove_attio_callback(hr->dev, hr->attioid);
+
+ if (hr->attrib != NULL)
+ g_attrib_unref(hr->attrib);
+
btd_device_unref(hr->dev);
g_free(hr);
}
@@ -90,9 +103,31 @@ static void destroy_heartrate_adapter(gpointer user_data)
{
struct heartrate_adapter *hra = user_data;
+ if (hra->devices != NULL)
+ g_slist_free_full(hra->devices, destroy_heartrate_device);
+
g_free(hra);
}
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+ struct heartrate *hr = user_data;
+
+ DBG("GATT Connected");
+
+ hr->attrib = g_attrib_ref(attrib);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+ struct heartrate *hr = user_data;
+
+ DBG("GATT Disconnected");
+
+ g_attrib_unref(hr->attrib);
+ hr->attrib = NULL;
+}
+
int heartrate_adapter_register(struct btd_adapter *adapter)
{
struct heartrate_adapter *hra;
@@ -137,6 +172,11 @@ int heartrate_device_register(struct btd_device *device)
hra->devices = g_slist_prepend(hra->devices, hr);
+ hr->attioid = btd_device_add_attio_callback(device,
+ attio_connected_cb,
+ attio_disconnected_cb,
+ hr);
+
return 0;
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 02/17] heartrate: Add Heart Rate Profile client
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch adds initial support for the Heart Rate Profile client.
---
Makefile.am | 9 ++-
lib/uuid.h | 2 +
profiles/heartrate/heartrate.c | 165 +++++++++++++++++++++++++++++++++++++++++
profiles/heartrate/heartrate.h | 26 +++++++
profiles/heartrate/main.c | 52 +++++++++++++
profiles/heartrate/manager.c | 75 +++++++++++++++++++
profiles/heartrate/manager.h | 24 ++++++
7 files changed, 351 insertions(+), 2 deletions(-)
create mode 100644 profiles/heartrate/heartrate.c
create mode 100644 profiles/heartrate/heartrate.h
create mode 100644 profiles/heartrate/main.c
create mode 100644 profiles/heartrate/manager.c
create mode 100644 profiles/heartrate/manager.h
diff --git a/Makefile.am b/Makefile.am
index 4977a05..cb36d91 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -212,7 +212,7 @@ endif
if GATTMODULES
builtin_modules += thermometer alert time gatt_example proximity deviceinfo \
- gatt
+ gatt heartrate
builtin_sources += profiles/thermometer/main.c \
profiles/thermometer/manager.h \
profiles/thermometer/manager.c \
@@ -241,7 +241,12 @@ builtin_sources += profiles/thermometer/main.c \
profiles/deviceinfo/deviceinfo.c \
profiles/gatt/main.c profiles/gatt/manager.h \
profiles/gatt/manager.c profiles/gatt/gas.h \
- profiles/gatt/gas.c
+ profiles/gatt/gas.c \
+ profiles/heartrate/main.c \
+ profiles/heartrate/manager.c \
+ profiles/heartrate/manager.h \
+ profiles/heartrate/heartrate.c \
+ profiles/heartrate/heartrate.h
endif
builtin_modules += formfactor
diff --git a/lib/uuid.h b/lib/uuid.h
index aa6efdf..3488e66 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -63,6 +63,8 @@ extern "C" {
#define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb"
+
#define HEALTH_THERMOMETER_UUID "00001809-0000-1000-8000-00805f9b34fb"
#define TEMPERATURE_MEASUREMENT_UUID "00002a1c-0000-1000-8000-00805f9b34fb"
#define TEMPERATURE_TYPE_UUID "00002a1d-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
new file mode 100644
index 0000000..17514c0
--- /dev/null
+++ b/profiles/heartrate/heartrate.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * 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 "heartrate.h"
+
+struct heartrate_adapter {
+ struct btd_adapter *adapter;
+ GSList *devices;
+};
+
+struct heartrate {
+ struct btd_device *dev;
+ struct heartrate_adapter *hra;
+};
+
+static GSList *heartrate_adapters = NULL;
+
+static gint cmp_adapter(gconstpointer a, gconstpointer b)
+{
+ const struct heartrate_adapter *hra = a;
+ const struct btd_adapter *adapter = b;
+
+ if (adapter == hra->adapter)
+ return 0;
+
+ return -1;
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+ const struct heartrate *hr = a;
+ const struct btd_device *dev = b;
+
+ if (dev == hr->dev)
+ return 0;
+
+ return -1;
+}
+
+static struct heartrate_adapter *
+find_heartrate_adapter(struct btd_adapter *adapter)
+{
+ GSList *l = g_slist_find_custom(heartrate_adapters, adapter,
+ cmp_adapter);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
+static void destroy_heartrate_device(gpointer user_data)
+{
+ struct heartrate *hr = user_data;
+
+ btd_device_unref(hr->dev);
+ g_free(hr);
+}
+
+static void destroy_heartrate_adapter(gpointer user_data)
+{
+ struct heartrate_adapter *hra = user_data;
+
+ g_free(hra);
+}
+
+int heartrate_adapter_register(struct btd_adapter *adapter)
+{
+ struct heartrate_adapter *hra;
+
+ hra = g_new0(struct heartrate_adapter, 1);
+ hra->adapter = adapter;
+
+ heartrate_adapters = g_slist_prepend(heartrate_adapters, hra);
+
+ return 0;
+}
+
+void heartrate_adapter_unregister(struct btd_adapter *adapter)
+{
+ struct heartrate_adapter *hra;
+
+ hra = find_heartrate_adapter(adapter);
+ if (hra == NULL)
+ return;
+
+ heartrate_adapters = g_slist_remove(heartrate_adapters, hra);
+
+ destroy_heartrate_adapter(hra);
+}
+
+int heartrate_device_register(struct btd_device *device)
+{
+ struct heartrate_adapter *hra;
+ struct btd_adapter *adapter;
+ struct heartrate *hr;
+
+ adapter = device_get_adapter(device);
+
+ hra = find_heartrate_adapter(adapter);
+
+ if (hra == NULL)
+ return -1;
+
+ hr = g_new0(struct heartrate, 1);
+ hr->dev = btd_device_ref(device);
+ hr->hra = hra;
+
+ hra->devices = g_slist_prepend(hra->devices, hr);
+
+ return 0;
+}
+
+void heartrate_device_unregister(struct btd_device *device)
+{
+ struct heartrate_adapter *hra;
+ struct btd_adapter *adapter;
+ struct heartrate *hr;
+ GSList *l;
+
+ adapter = device_get_adapter(device);
+
+ hra = find_heartrate_adapter(adapter);
+ if (hra == NULL)
+ return;
+
+ l = g_slist_find_custom(hra->devices, device, cmp_device);
+ if (l == NULL)
+ return;
+
+ hr = l->data;
+
+ hra->devices = g_slist_remove(hra->devices, hr);
+
+ destroy_heartrate_device(hr);
+}
diff --git a/profiles/heartrate/heartrate.h b/profiles/heartrate/heartrate.h
new file mode 100644
index 0000000..486f5b3
--- /dev/null
+++ b/profiles/heartrate/heartrate.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 heartrate_adapter_register(struct btd_adapter *adapter);
+void heartrate_adapter_unregister(struct btd_adapter *adapter);
+int heartrate_device_register(struct btd_device *device);
+void heartrate_device_unregister(struct btd_device *device);
diff --git a/profiles/heartrate/main.c b/profiles/heartrate/main.c
new file mode 100644
index 0000000..40f34bc
--- /dev/null
+++ b/profiles/heartrate/main.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Tieto Poland
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static int heartrate_init(void)
+{
+ if (!main_opts.gatt_enabled) {
+ DBG("GATT is disabled");
+ return -ENOTSUP;
+ }
+
+ return heartrate_manager_init();
+}
+
+static void heartrate_exit(void)
+{
+ heartrate_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(heartrate, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ heartrate_init, heartrate_exit)
diff --git a/profiles/heartrate/manager.c b/profiles/heartrate/manager.c
new file mode 100644
index 0000000..9d2446c
--- /dev/null
+++ b/profiles/heartrate/manager.c
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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 "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "heartrate.h"
+#include "manager.h"
+
+static int heartrate_adapter_probe(struct btd_adapter *adapter)
+{
+ return heartrate_adapter_register(adapter);
+}
+
+static void heartrate_adapter_remove(struct btd_adapter *adapter)
+{
+ heartrate_adapter_unregister(adapter);
+}
+
+static int heartrate_device_probe(struct btd_device *device, GSList *uuids)
+{
+ return heartrate_device_register(device);
+}
+
+static void heartrate_device_remove(struct btd_device *device)
+{
+ heartrate_device_unregister(device);
+}
+
+static struct btd_profile hrp_profile = {
+ .name = "Heart Rate GATT Driver",
+ .remote_uuids = BTD_UUIDS(HEART_RATE_UUID),
+
+ .device_probe = heartrate_device_probe,
+ .device_remove = heartrate_device_remove,
+
+ .adapter_probe = heartrate_adapter_probe,
+ .adapter_remove = heartrate_adapter_remove,
+};
+
+int heartrate_manager_init(void)
+{
+ return btd_profile_register(&hrp_profile);
+}
+
+void heartrate_manager_exit(void)
+{
+ btd_profile_unregister(&hrp_profile);
+}
diff --git a/profiles/heartrate/manager.h b/profiles/heartrate/manager.h
new file mode 100644
index 0000000..de799f6
--- /dev/null
+++ b/profiles/heartrate/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Tieto Poland
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int heartrate_manager_init(void);
+void heartrate_manager_exit(void);
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 01/17] Heart Rate Profile API
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1346931171-18968-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Santiago Carot-Nemesio <sancane@gmail.com>
---
doc/heartrate-api.txt | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
create mode 100644 doc/heartrate-api.txt
diff --git a/doc/heartrate-api.txt b/doc/heartrate-api.txt
new file mode 100644
index 0000000..4ce96d8
--- /dev/null
+++ b/doc/heartrate-api.txt
@@ -0,0 +1,84 @@
+ Heart Rate API description
+****************************************
+
+Copyright (C) 2012 Santiago Carot-Nemesio <sancane@gmail.com>
+Copyright (C) 2012 Tieto Poland
+
+Heart Rate Manager hierarchy
+============================
+
+Service org.bluez
+Interface org.bluez.HeartRateManager
+Object path [variable prefix]/{hci0,hci1,...}
+
+Methods RegisterWatcher(object agent)
+
+ Registers a watcher to monitor heart rate measurements.
+
+ Possible Errors: org.bluez.Error.InvalidArguments
+
+ UnregisterWatcher(object agent)
+
+ Unregisters a watcher.
+
+Heart Rate Profile hierarchy
+============================
+
+Service org.bluez
+Interface org.bluez.HeartRate
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods dict GetProperties()
+
+ Returns all properties for the interface. See the
+ Properties section for the available properties.
+
+ Reset()
+
+ Restart the accumulation of energy expended from zero.
+
+ Possible Errors: org.bluez.Error.NotSupported
+
+Properties String Location (optional) [readonly]
+
+ Possible values: "Other", "Chest", "Wrist","Finger",
+ "Hand", "Earlobe", "Foot"
+
+ boolean ResetSupported [readonly]
+
+ True if energy expended is supported.
+
+Heart Rate Watcher hierarchy
+
+============================
+Service unique name
+Interface org.bluez.HeartRateWatcher
+Object path freely definable
+
+Methods void MeasurementReceived(object device, dict measurement)
+
+ This callback is called whenever a heart rate
+ measurement is received from the heart rate device.
+
+ Measurement:
+
+ uint16 Value:
+
+ Measurement value expressed in beats per
+ minute (bpm)
+
+ uint16 Energy (optional):
+
+ Accumulated energy expended in kilo Joules
+
+ boolean Contact (optional):
+
+ true if skin contact is detected by sensor,
+ false otherwise
+
+ array{uint16} Interval (optional):
+
+ RR-Interval values which represent the time
+ between two consecutive R waves in an ECG.
+ Values are ordered starting from oldest to
+ most recent.
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3 00/17] Heart Rate Profile plugin
From: Andrzej Kaczmarek @ 2012-09-06 11:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
Hi,
Changes since v2:
* rewritten MeasurementReceived description in API
* minor coding style fix
(both suggested by Vinicius, thanks)
Andrzej Kaczmarek (6):
heartrate: Add attio callbacks
heartrate: Enable measurement when watchers are registered
heartrate: Read Heart Rate Control Point characteristics
heartrate: Handle characteristics value changed notification
heartrate: Process Heart Rate Measurement characteristics
heartrate: Add Reset method
Rafal Garbat (10):
heartrate: Add Heart Rate Profile client
heartrate: Discover characteristics
heartrate: Process characteristics
heartrate: Discover characteristics descriptors
heartrate: Process characteristics descriptors
heartrate: Add HeartRateManager interface
heartrate: Read Body Sensor Location characteristics
heartrate: Add GetProperties method
heartrate: Add HeartRateWatcher interface to default policy
heartrate: Add test script
Santiago Carot-Nemesio (1):
Heart Rate Profile API
Makefile.am | 9 +-
Makefile.tools | 4 +-
doc/heartrate-api.txt | 84 ++++
lib/uuid.h | 5 +
profiles/heartrate/heartrate.c | 971 +++++++++++++++++++++++++++++++++++++++++
profiles/heartrate/heartrate.h | 27 ++
profiles/heartrate/main.c | 52 +++
profiles/heartrate/manager.c | 95 ++++
profiles/heartrate/manager.h | 24 +
src/bluetooth.conf | 1 +
test/test-heartrate | 103 +++++
11 files changed, 1371 insertions(+), 4 deletions(-)
create mode 100644 doc/heartrate-api.txt
create mode 100644 profiles/heartrate/heartrate.c
create mode 100644 profiles/heartrate/heartrate.h
create mode 100644 profiles/heartrate/main.c
create mode 100644 profiles/heartrate/manager.c
create mode 100644 profiles/heartrate/manager.h
create mode 100755 test/test-heartrate
--
1.7.11.3
^ permalink raw reply
* [PATCH] Fix endian safe issue, make driver work on both little and big endian cpu.
From: Peng Chen @ 2012-09-06 11:30 UTC (permalink / raw)
To: gustavo; +Cc: linux-bluetooth, marcel, Peng Chen
Signed-off-by: Peng Chen <pengchen@qca.qualcomm.com>
---
drivers/bluetooth/ath3k.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 10308cd..e63aee1 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -299,7 +299,7 @@ static int ath3k_load_patch(struct usb_device *udev)
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
- fw_version.rom_version);
+ le32_to_cpu(fw_version.rom_version));
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
@@ -361,7 +361,7 @@ static int ath3k_load_syscfg(struct usb_device *udev)
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
- fw_version.rom_version, clk_value, ".dfu");
+ le32_to_cpu(fw_version.rom_version), clk_value, ".dfu");
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
--
1.7.9.5
^ permalink raw reply related
* [PATCH] gatt: Remove reading Service Changed characteristic after connected
From: Andrzej Kaczmarek @ 2012-09-06 10:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
Service Changed characteristic is a control-point attribute thus it cannot be
read and attempting to do so will fail. Instead, server shall send indication
once enabled in CCC.
---
profiles/gatt/gas.c | 37 -------------------------------------
1 file changed, 37 deletions(-)
diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index 28d7fbf..d189221 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -161,37 +161,6 @@ static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
btd_device_gatt_set_service_changed(gas->device, start, end);
}
-static void gatt_service_changed_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- struct gas *gas = user_data;
- uint16_t start, end;
-
- if (status) {
- error("Read GATT Service Changed failed: %s",
- att_ecode2str(status));
- return;
- }
-
- if (plen != 5) {
- error("Service Changed: PDU length mismatch");
- return;
- }
-
- start = att_get_u16(&pdu[1]);
- end = att_get_u16(&pdu[3]);
-
- if (gas->changed.start == start && gas->changed.end == end)
- return;
-
- gas->changed.start = start;
- gas->changed.end = end;
-
- DBG("GATT Service Changed start: 0x%04X end: 0x%04X", start, end);
-
- btd_device_gatt_set_service_changed(gas->device, start, end);
-}
-
static void gatt_descriptors_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
@@ -311,8 +280,6 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
/* TODO: Read other GAP characteristics - See Core spec page 1739 */
/*
- * Always read the characteristic value in the first connection
- * since attribute handles caching is not supported at the moment.
* When re-connecting <<Service Changed>> handle and characteristic
* value doesn't need to read again: known information from the
* previous interaction.
@@ -322,10 +289,6 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
- gatt_read_char_by_uuid(gas->attrib, gas->gatt.start,
- gas->gatt.end, &uuid,
- gatt_service_changed_cb, gas);
-
gatt_discover_char(gas->attrib, gas->gatt.start, gas->gatt.end,
&uuid, gatt_characteristic_cb, gas);
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH obexd 7/7 v3] client-doc: Update documentation of PhonebookAccess interface
From: Luiz Augusto von Dentz @ 2012-09-06 9:26 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
doc/client-api.txt | 62 +++++++++++++++++++++++++++++++-----------------------
1 file changed, 36 insertions(+), 26 deletions(-)
diff --git a/doc/client-api.txt b/doc/client-api.txt
index 7ca65cc..f447789 100644
--- a/doc/client-api.txt
+++ b/doc/client-api.txt
@@ -206,7 +206,7 @@ Methods void Select(string location, string phonebook)
"mch": missing call history
"cch": combination of ich och mch
- object, dict PullAll(string targetfile)
+ object, dict PullAll(string targetfile, dict filters)
Return the entire phonebook object from the PSE server
in plain string with vcard format, and store it in
@@ -222,14 +222,21 @@ Methods void Select(string location, string phonebook)
The properties of this transfer are also returned along
with the object path, to avoid a call to GetProperties.
- array{string vcard, string name} List()
+ Possible filters: Format, Order, Offset, MaxCount and
+ Fields
+
+ array{string vcard, string name} List(dict filters)
Return an array of vcard-listing data where every entry
consists of a pair of strings containing the vcard
handle and the contact name. For example:
"1.vcf" : "John"
- object, dict Pull(string vcard, string targetfile)
+ Possible filters: Order, Offset and MaxCount
+
+
+ object, dict
+ Pull(string vcard, string targetfile, dict filters)
Given a vcard handle, retrieve the vcard in the current
phonebook object and store it in a local file.
@@ -244,8 +251,11 @@ Methods void Select(string location, string phonebook)
The properties of this transfer are also returned along
with the object path, to avoid a call to GetProperties.
+ Possbile filters: Format and Fields
+
+
array{string vcard, string name}
- Search(string field, string value)
+ Search(string field, string value, dict filters)
Search for entries matching the given condition and
return an array of vcard-listing data where every entry
@@ -258,47 +268,47 @@ Methods void Select(string location, string phonebook)
{ "name" (default) | "number" | "sound" }
value : the string value to search for
+
+ Possible filters: Order, Offset and MaxCount
+
uint16 GetSize()
Return the number of entries in the selected phonebook
object that are actually used (i.e. indexes that
correspond to non-NULL entries).
- void SetFormat(string format)
+ array{string} ListFilterFields()
- Indicate the format of the vcard that should be return
- by related methods.
+ Return All Available fields that can be used in Fields
+ filter.
- format : { "vcard21" (default) | "vcard30" }
+Filter: string Format:
- void SetOrder(string order)
+ Items vcard format
- Indicate the sorting method of the vcard-listing data
- returned by List and Search methods.
+ Possible values: "vcard21" (default) or "vcard30"
- order : { "indexed" (default) | "alphanumeric" |
- "phonetic" }
+ string Order:
- void SetFilter(array{string})
+ Items order
- Indicate fields that should be contained in vcards
- return by related methods.
+ Possible values: "indexed" (default), "alphanumeric" or
+ "phonetic"
- Give an empty array will clear the filter and return
- all fields available in vcards. And this is the default
- behavior.
+ uint16 Offset:
- Possible filter fields : "VERSION", "FN", ..., "ALL",
- "bit[0-63]"
+ Offset of the first item, default is 0
- array{string} ListFilterFields()
+ uint16 MaxCount:
+
+ Maximum number of items, default is unlimited (65535)
+
+ array{string} Fields:
- Return All Available fields that can be used in
- SetFilter method.
+ Item vcard fields, default is all values.
- array{string} GetFilter()
+ Possible values can be query with ListFilterFields.
- Return the current filter setting
Synchronization hierarchy
=======================
--
1.7.11.4
^ permalink raw reply related
* [PATCH obexd 6/7 v3] client: Move common code to pull_phonebook
From: Luiz Augusto von Dentz @ 2012-09-06 9:26 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
client/pbap.c | 79 +++++++++++++++++++++++------------------------------------
1 file changed, 30 insertions(+), 49 deletions(-)
diff --git a/client/pbap.c b/client/pbap.c
index a90d515..16778f8 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -523,22 +523,29 @@ static GObexApparam *parse_filters(GObexApparam *apparam,
return apparam;
}
-static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
+static DBusMessage *pull_phonebook(struct pbap_data *pbap,
DBusMessage *message,
- guint8 type, const char *name,
+ guint8 type,
const char *targetfile,
- GObexApparam *apparam,
- GError **err)
+ GObexApparam *apparam)
{
struct pending_request *request;
struct obc_transfer *transfer;
+ char *name;
guint8 buf[32];
gsize len;
session_callback_t func;
+ DBusMessage *reply;
+ GError *err = NULL;
+
+ name = g_strconcat(pbap->path, ".vcf", NULL);
+
+ len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+ g_obex_apparam_free(apparam);
- transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, err);
+ transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, &err);
if (transfer == NULL)
- return NULL;
+ goto fail;
switch (type) {
case PULLPHONEBOOK:
@@ -554,19 +561,28 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
return NULL;
}
- len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-
obc_transfer_set_params(transfer, buf, len);
- if (!obc_session_queue(pbap->session, transfer, func, request, err)) {
+ if (!obc_session_queue(pbap->session, transfer, func, request, &err)) {
if (request != NULL)
pending_request_free(request);
- return NULL;
+ goto fail;
}
+ g_free(name);
+
+ if (targetfile == NULL)
+ return NULL;
- return transfer;
+ return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+ g_free(name);
+ reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+ err->message);
+ g_error_free(err);
+ return reply;
}
static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
@@ -654,11 +670,8 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
struct pbap_data *pbap = user_data;
- struct obc_transfer *transfer;
const char *targetfile;
- char *name;
GObexApparam *apparam;
- GError *err = NULL;
DBusMessageIter args;
if (!pbap->path)
@@ -686,22 +699,8 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
ERROR_INTERFACE ".InvalidArguments", NULL);
}
- name = g_strconcat(pbap->path, ".vcf", NULL);
-
- transfer = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
- targetfile, apparam, &err);
- g_free(name);
- g_obex_apparam_free(apparam);
-
- if (transfer == NULL) {
- DBusMessage *reply = g_dbus_create_error(message,
- ERROR_INTERFACE ".Failed", "%s",
- err->message);
- g_error_free(err);
- return reply;
- }
-
- return obc_transfer_create_dbus_reply(transfer, message);
+ return pull_phonebook(pbap, message, PULLPHONEBOOK, targetfile,
+ apparam);
}
static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
@@ -877,11 +876,7 @@ static DBusMessage *pbap_get_size(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
struct pbap_data *pbap = user_data;
- DBusMessage *reply;
- struct obc_transfer *transfer;
- char *name;
GObexApparam *apparam;
- GError *err = NULL;
DBusMessageIter args;
if (!pbap->path)
@@ -891,25 +886,11 @@ static DBusMessage *pbap_get_size(DBusConnection *connection,
dbus_message_iter_init(message, &args);
- name = g_strconcat(pbap->path, ".vcf", NULL);
-
apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG, 0);
apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
DEFAULT_OFFSET);
- transfer = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name, NULL,
- apparam, &err);
-
- g_free(name);
- g_obex_apparam_free(apparam);
-
- if (transfer != NULL)
- return NULL;
-
- reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
- err->message);
- g_error_free(err);
- return reply;
+ return pull_phonebook(pbap, message, GETPHONEBOOKSIZE, NULL, apparam);
}
static gchar **get_filter_strs(uint64_t filter, gint *size)
--
1.7.11.4
^ permalink raw reply related
* [PATCH obexd 5/7 v3] test: Update pbap-client to work with changes in PhonebookAcess
From: Luiz Augusto von Dentz @ 2012-09-06 9:26 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
test/pbap-client | 21 +++++++++------------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/test/pbap-client b/test/pbap-client
index 498f8a3..7dd54ef 100755
--- a/test/pbap-client
+++ b/test/pbap-client
@@ -70,16 +70,16 @@ class PbapClient:
print "Transfer finished with error %s: %s" % (code, message)
mainloop.quit()
- def pull(self, vcard, func):
+ def pull(self, vcard, params, func):
req = Transfer(func)
- self.pbap.Pull(vcard, "",
+ self.pbap.Pull(vcard, "", params,
reply_handler=lambda r: self.register(r, req),
error_handler=self.error)
self.transfers += 1
- def pull_all(self, func):
+ def pull_all(self, params, func):
req = Transfer(func)
- self.pbap.PullAll("",
+ self.pbap.PullAll("", params,
reply_handler=lambda r: self.register(r, req),
error_handler=self.error)
self.transfers += 1
@@ -135,18 +135,15 @@ if __name__ == '__main__':
print "Size = %d\n" % (ret)
print "\n--- List vCard ---\n"
- ret = pbap_client.interface().List()
+ ret = pbap_client.interface().List(dbus.Dictionary())
+ params = dbus.Dictionary({ "Format" : "vcard30",
+ "Fields" : [ "VERSION", "FN", "TEL"] })
for item in ret:
print "%s : %s" % (item[0], item[1])
- pbap_client.interface().SetFormat("vcard30")
- pbap_client.interface().SetFilter(["VERSION", "FN",
- "TEL"]);
- pbap_client.pull(item[0],
+ pbap_client.pull(item[0], params,
lambda x: process_result(x, None))
- pbap_client.interface().SetFormat("vcard30")
- pbap_client.interface().SetFilter(["VERSION", "FN", "TEL"]);
- pbap_client.pull_all(lambda x: process_result(x,
+ pbap_client.pull_all(params, lambda x: process_result(x,
"\n--- PullAll ---\n"))
pbap_client.flush_transfers(lambda: test_paths(paths[1:]))
--
1.7.11.4
^ permalink raw reply related
* [PATCH obexd 4/7 v3] client: Remove deprecated methods from PhonebookAccess
From: Luiz Augusto von Dentz @ 2012-09-06 9:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
SetFormat, SetOrder, SetFilter and GetFilter methods are no longer
necessary as other methods now take them as parameters to avoid round
trips.
---
client/pbap.c | 197 +++++-----------------------------------------------------
1 file changed, 14 insertions(+), 183 deletions(-)
diff --git a/client/pbap.c b/client/pbap.c
index b1157e3..a90d515 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -116,9 +116,6 @@ static const char *filter_list[] = {
struct pbap_data {
struct obc_session *session;
char *path;
- guint8 format;
- guint8 order;
- uint64_t filter;
};
struct pending_request {
@@ -606,91 +603,6 @@ fail:
return reply;
}
-static int set_format(struct pbap_data *pbap, const char *formatstr)
-{
- if (!formatstr || g_str_equal(formatstr, "")) {
- pbap->format = FORMAT_VCARD21;
- return 0;
- }
-
- if (!g_ascii_strcasecmp(formatstr, "vcard21"))
- pbap->format = FORMAT_VCARD21;
- else if (!g_ascii_strcasecmp(formatstr, "vcard30"))
- pbap->format = FORMAT_VCARD30;
- else
- return -EINVAL;
-
- return 0;
-}
-
-static int set_order(struct pbap_data *pbap, const char *orderstr)
-{
- if (!orderstr || g_str_equal(orderstr, "")) {
- pbap->order = ORDER_INDEXED;
- return 0;
- }
-
- if (!g_ascii_strcasecmp(orderstr, "indexed"))
- pbap->order = ORDER_INDEXED;
- else if (!g_ascii_strcasecmp(orderstr, "alphanumeric"))
- pbap->order = ORDER_ALPHANUMERIC;
- else if (!g_ascii_strcasecmp(orderstr, "phonetic"))
- pbap->order = ORDER_PHONETIC;
- else
- return -EINVAL;
-
- return 0;
-}
-
-static int add_filter(struct pbap_data *pbap, const char *filterstr)
-{
- uint64_t mask;
-
- mask = get_filter_mask(filterstr);
-
- if (mask == 0)
- return -EINVAL;
-
- pbap->filter |= mask;
- return 0;
-}
-
-static int remove_filter(struct pbap_data *pbap, const char *filterstr)
-{
- uint64_t mask;
-
- mask = get_filter_mask(filterstr);
-
- if (mask == 0)
- return -EINVAL;
-
- pbap->filter &= ~mask;
- return 0;
-}
-
-static gchar **get_filter_strs(uint64_t filter, gint *size)
-{
- gchar **list, **item;
- gint i;
- gint filter_list_size = sizeof(filter_list) / sizeof(filter_list[0]) - 1;
-
- list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
-
- item = list;
-
- for (i = 0; i < filter_list_size; i++)
- if (filter & (1ULL << i))
- *(item++) = g_strdup(filter_list[i]);
-
- for (i = filter_list_size; i <= FILTER_BIT_MAX; i++)
- if (filter & (1ULL << i))
- *(item++) = g_strdup_printf("%s%d", "BIT", i);
-
- *item = NULL;
- *size = item - list;
- return list;
-}
-
static DBusMessage *pbap_select(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
@@ -1000,95 +912,26 @@ static DBusMessage *pbap_get_size(DBusConnection *connection,
return reply;
}
-static DBusMessage *pbap_set_format(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- struct pbap_data *pbap = user_data;
- const char *format;
-
- if (dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &format,
- DBUS_TYPE_INVALID) == FALSE)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".InvalidArguments", NULL);
-
- if (set_format(pbap, format) < 0)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".InvalidArguments",
- "InvalidFormat");
-
- return dbus_message_new_method_return(message);
-}
-
-static DBusMessage *pbap_set_order(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- struct pbap_data *pbap = user_data;
- const char *order;
-
- if (dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &order,
- DBUS_TYPE_INVALID) == FALSE)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".InvalidArguments", NULL);
-
- if (set_order(pbap, order) < 0)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".InvalidArguments",
- "InvalidFilter");
-
- return dbus_message_new_method_return(message);
-}
-
-static DBusMessage *pbap_set_filter(DBusConnection *connection,
- DBusMessage *message, void *user_data)
+static gchar **get_filter_strs(uint64_t filter, gint *size)
{
- struct pbap_data *pbap = user_data;
- char **filters, **item;
- gint size;
- uint64_t oldfilter = pbap->filter;
-
- if (dbus_message_get_args(message, NULL, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING, &filters, &size,
- DBUS_TYPE_INVALID) == FALSE)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".InvalidArguments", NULL);
-
- remove_filter(pbap, "ALL");
- if (size == 0)
- goto done;
+ gchar **list, **item;
+ gint i;
- for (item = filters; *item; item++) {
- if (add_filter(pbap, *item) < 0) {
- pbap->filter = oldfilter;
- g_strfreev(filters);
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".InvalidArguments",
- "InvalidFilters");
- }
- }
+ list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
-done:
- g_strfreev(filters);
- return dbus_message_new_method_return(message);
-}
+ item = list;
-static DBusMessage *pbap_get_filter(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- struct pbap_data *pbap = user_data;
- gchar **filters = NULL;
- gint size;
- DBusMessage *reply;
+ for (i = 0; filter_list[i] != NULL; i++)
+ if (filter & (1ULL << i))
+ *(item++) = g_strdup(filter_list[i]);
- filters = get_filter_strs(pbap->filter, &size);
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING, &filters, size,
- DBUS_TYPE_INVALID);
+ for (; i <= FILTER_BIT_MAX; i++)
+ if (filter & (1ULL << i))
+ *(item++) = g_strdup_printf("%s%d", "BIT", i);
- g_strfreev(filters);
- return reply;
+ *item = NULL;
+ *size = item - list;
+ return list;
}
static DBusMessage *pbap_list_filter_fields(DBusConnection *connection,
@@ -1136,18 +979,6 @@ static const GDBusMethodTable pbap_methods[] = {
{ GDBUS_ASYNC_METHOD("GetSize",
NULL, GDBUS_ARGS({ "size", "q" }),
pbap_get_size) },
- { GDBUS_METHOD("SetFormat",
- GDBUS_ARGS({ "format", "s" }), NULL,
- pbap_set_format) },
- { GDBUS_METHOD("SetOrder",
- GDBUS_ARGS({ "order", "s" }), NULL,
- pbap_set_order) },
- { GDBUS_METHOD("SetFilter",
- GDBUS_ARGS({ "fields", "as" }), NULL,
- pbap_set_filter) },
- { GDBUS_METHOD("GetFilter",
- NULL, GDBUS_ARGS({ "fields", "as" }),
- pbap_get_filter) },
{ GDBUS_METHOD("ListFilterFields",
NULL, GDBUS_ARGS({ "fields", "as" }),
pbap_list_filter_fields) },
--
1.7.11.4
^ permalink raw reply related
* [PATCH obexd 3/7 v3] client: Add filters to PhonebookAccess.List and PhonebookAccess.Search
From: Luiz Augusto von Dentz @ 2012-09-06 9:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This avoid D-Bus round trips and is more aligned with what has been
proposed for MessageAccess interface.
---
client/pbap.c | 115 ++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 76 insertions(+), 39 deletions(-)
diff --git a/client/pbap.c b/client/pbap.c
index 3fb1443..b1157e3 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -574,35 +574,24 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
DBusMessage *message, const char *name,
- guint8 order, char *searchval, guint8 attrib,
- guint16 count, guint16 offset)
+ GObexApparam *apparam)
{
struct pending_request *request;
struct obc_transfer *transfer;
guint8 buf[272];
gsize len;
GError *err = NULL;
- GObexApparam *apparam;
DBusMessage *reply;
+ len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+ g_obex_apparam_free(apparam);
+
transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
if (transfer == NULL)
goto fail;
- apparam = g_obex_apparam_set_uint8(NULL, ORDER_TAG, order);
- apparam = g_obex_apparam_set_uint8(apparam, SEARCHATTRIB_TAG, attrib);
- apparam = g_obex_apparam_set_string(apparam, SEARCHVALUE_TAG,
- searchval);
- apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, count);
- apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
- offset);
-
- len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-
obc_transfer_set_params(transfer, buf, len);
- g_obex_apparam_free(apparam);
-
request = pending_request_new(pbap, message);
if (obc_session_queue(pbap->session, transfer,
pull_vcard_listing_callback, request, &err))
@@ -881,34 +870,33 @@ static DBusMessage *pbap_list(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
struct pbap_data *pbap = user_data;
+ GObexApparam *apparam;
+ DBusMessageIter args;
if (!pbap->path)
return g_dbus_create_error(message,
ERROR_INTERFACE ".Forbidden",
"Call Select first of all");
- return pull_vcard_listing(pbap, message, "", pbap->order, "",
- ATTRIB_NAME, DEFAULT_COUNT, DEFAULT_OFFSET);
-}
+ dbus_message_iter_init(message, &args);
-static DBusMessage *pbap_search(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- struct pbap_data *pbap = user_data;
- char *field, *value;
- guint8 attrib;
+ apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+ DEFAULT_COUNT);
+ apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+ DEFAULT_OFFSET);
- if (dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &field,
- DBUS_TYPE_STRING, &value,
- DBUS_TYPE_INVALID) == FALSE)
+ if (parse_filters(apparam, &args) == NULL) {
+ g_obex_apparam_free(apparam);
return g_dbus_create_error(message,
ERROR_INTERFACE ".InvalidArguments", NULL);
+ }
- if (!pbap->path)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".Forbidden",
- "Call Select first of all");
+ return pull_vcard_listing(pbap, message, "", apparam);
+}
+
+static GObexApparam *parse_attribute(GObexApparam *apparam, const char *field)
+{
+ guint8 attrib;
if (!field || g_str_equal(field, ""))
attrib = ATTRIB_NAME;
@@ -919,11 +907,58 @@ static DBusMessage *pbap_search(DBusConnection *connection,
else if (!g_ascii_strcasecmp(field, "sound"))
attrib = ATTRIB_SOUND;
else
+ return NULL;
+
+ return g_obex_apparam_set_uint8(apparam, SEARCHATTRIB_TAG, attrib);
+}
+
+static DBusMessage *pbap_search(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct pbap_data *pbap = user_data;
+ char *field, *value;
+ GObexApparam *apparam;
+ DBusMessageIter args;
+
+ if (!pbap->path)
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".Forbidden",
+ "Call Select first of all");
+
+ dbus_message_iter_init(message, &args);
+
+ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+
+ dbus_message_iter_get_basic(&args, &field);
+ dbus_message_iter_next(&args);
+
+ apparam = parse_attribute(NULL, field);
+ if (apparam == NULL)
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+
+ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+
+ dbus_message_iter_get_basic(&args, &value);
+ dbus_message_iter_next(&args);
+
+ apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG,
+ DEFAULT_COUNT);
+ apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+ DEFAULT_OFFSET);
+ apparam = g_obex_apparam_set_string(apparam, SEARCHVALUE_TAG, value);
+
+ if (parse_filters(apparam, &args) == NULL) {
+ g_obex_apparam_free(apparam);
return g_dbus_create_error(message,
ERROR_INTERFACE ".InvalidArguments", NULL);
+ }
- return pull_vcard_listing(pbap, message, "", pbap->order, value,
- attrib, DEFAULT_COUNT, DEFAULT_OFFSET);
+ return pull_vcard_listing(pbap, message, "", apparam);
}
static DBusMessage *pbap_get_size(DBusConnection *connection,
@@ -1090,12 +1125,14 @@ static const GDBusMethodTable pbap_methods[] = {
{ "properties", "a{sv}" }),
pbap_pull_vcard) },
{ GDBUS_ASYNC_METHOD("List",
- NULL, GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
- pbap_list) },
+ GDBUS_ARGS({ "filters", "a{sv}" }),
+ GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+ pbap_list) },
{ GDBUS_ASYNC_METHOD("Search",
- GDBUS_ARGS({ "field", "s" }, { "value", "s" }),
- GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
- pbap_search) },
+ GDBUS_ARGS({ "field", "s" }, { "value", "s" },
+ { "filters", "a{sv}" }),
+ GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+ pbap_search) },
{ GDBUS_ASYNC_METHOD("GetSize",
NULL, GDBUS_ARGS({ "size", "q" }),
pbap_get_size) },
--
1.7.11.4
^ permalink raw reply related
* [PATCH obexd 2/7 v2] client: Add filters to PhonebookAccess.Pull
From: Luiz Augusto von Dentz @ 2012-09-06 9:25 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1346923562-2654-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This avoid D-Bus round trips and is more aligned with what has been
proposed for MessageAccess interface.
---
client/pbap.c | 78 +++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 52 insertions(+), 26 deletions(-)
diff --git a/client/pbap.c b/client/pbap.c
index f40f04b..3fb1443 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -803,43 +803,25 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
return obc_transfer_create_dbus_reply(transfer, message);
}
-static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
- DBusMessage *message, void *user_data)
+static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
+ const char *name, const char *targetfile,
+ GObexApparam *apparam)
{
- struct pbap_data *pbap = user_data;
struct obc_transfer *transfer;
- GObexApparam *apparam;
- guint8 buf[32];
- gsize len;
- const char *name, *targetfile;
DBusMessage *reply;
GError *err = NULL;
+ guint8 buf[32];
+ gsize len;
- if (!pbap->path)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".Forbidden",
- "Call Select first of all");
-
- if (dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &targetfile,
- DBUS_TYPE_INVALID) == FALSE)
- return g_dbus_create_error(message,
- ERROR_INTERFACE ".InvalidArguments", NULL);
+ len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+ g_obex_apparam_free(apparam);
transfer = obc_transfer_get("x-bt/vcard", name, targetfile, &err);
if (transfer == NULL)
goto fail;
- apparam = g_obex_apparam_set_uint64(NULL, FILTER_TAG, pbap->filter);
- apparam = g_obex_apparam_set_uint8(apparam, FORMAT_TAG, pbap->format);
-
- len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
-
obc_transfer_set_params(transfer, buf, len);
- g_obex_apparam_free(apparam);
-
if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
goto fail;
@@ -852,6 +834,49 @@ fail:
return reply;
}
+static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct pbap_data *pbap = user_data;
+ GObexApparam *apparam;
+ const char *name, *targetfile;
+ DBusMessageIter args;
+
+ if (!pbap->path)
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".Forbidden",
+ "Call Select first of all");
+
+ dbus_message_iter_init(message, &args);
+
+ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+
+ dbus_message_iter_get_basic(&args, &name);
+ dbus_message_iter_next(&args);
+
+ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+
+ dbus_message_iter_get_basic(&args, &targetfile);
+ dbus_message_iter_next(&args);
+
+ apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+ DEFAULT_COUNT);
+ apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+ DEFAULT_OFFSET);
+
+ if (parse_filters(apparam, &args) == NULL) {
+ g_obex_apparam_free(apparam);
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+ }
+
+ return pull_vcard(pbap, message, name, targetfile, apparam);
+}
+
static DBusMessage *pbap_list(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
@@ -1059,7 +1084,8 @@ static const GDBusMethodTable pbap_methods[] = {
{ "properties", "a{sv}" }),
pbap_pull_all) },
{ GDBUS_METHOD("Pull",
- GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" }),
+ GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" },
+ { "filters", "a{sv}" }),
GDBUS_ARGS({ "transfer", "o" },
{ "properties", "a{sv}" }),
pbap_pull_vcard) },
--
1.7.11.4
^ permalink raw reply related
* [PATCH obexd 1/7 v3] client: Add filters to Phonebook.PullAll
From: Luiz Augusto von Dentz @ 2012-09-06 9:25 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This avoid D-Bus round trips and is more aligned with what has been
proposed for MessageAccess interface.
---
v3: Fix patch 2/7
client/pbap.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 209 insertions(+), 46 deletions(-)
diff --git a/client/pbap.c b/client/pbap.c
index ebd6320..f40f04b 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -351,18 +351,190 @@ send:
pending_request_free(request);
}
+static GObexApparam *parse_format(GObexApparam *apparam, DBusMessageIter *iter)
+{
+ const char *string;
+ guint8 format;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return NULL;
+
+ dbus_message_iter_get_basic(iter, &string);
+
+ if (!string || g_str_equal(string, ""))
+ format = FORMAT_VCARD21;
+ else if (!g_ascii_strcasecmp(string, "vcard21"))
+ format = FORMAT_VCARD21;
+ else if (!g_ascii_strcasecmp(string, "vcard30"))
+ format = FORMAT_VCARD30;
+ else
+ return NULL;
+
+ return g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
+}
+
+static GObexApparam *parse_order(GObexApparam *apparam, DBusMessageIter *iter)
+{
+ const char *string;
+ guint8 order;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return NULL;
+
+ dbus_message_iter_get_basic(iter, &string);
+
+ if (!string || g_str_equal(string, ""))
+ order = ORDER_INDEXED;
+ else if (!g_ascii_strcasecmp(string, "indexed"))
+ order = ORDER_INDEXED;
+ else if (!g_ascii_strcasecmp(string, "alphanumeric"))
+ order = ORDER_ALPHANUMERIC;
+ else if (!g_ascii_strcasecmp(string, "phonetic"))
+ order = ORDER_PHONETIC;
+ else
+ return NULL;
+
+ return g_obex_apparam_set_uint8(apparam, ORDER_TAG, order);
+}
+
+static GObexApparam *parse_offset(GObexApparam *apparam, DBusMessageIter *iter)
+{
+ guint16 num;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+ return NULL;
+
+ dbus_message_iter_get_basic(iter, &num);
+
+ return g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG, num);
+}
+
+static GObexApparam *parse_max_count(GObexApparam *apparam,
+ DBusMessageIter *iter)
+{
+ guint16 num;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+ return NULL;
+
+ dbus_message_iter_get_basic(iter, &num);
+
+ return g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, num);
+}
+
+static uint64_t get_filter_mask(const char *filterstr)
+{
+ int i, bit = -1;
+
+ if (!filterstr)
+ return 0;
+
+ if (!g_ascii_strcasecmp(filterstr, "ALL"))
+ return FILTER_ALL;
+
+ for (i = 0; filter_list[i] != NULL; i++)
+ if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
+ return 1ULL << i;
+
+ if (strlen(filterstr) < 4 || strlen(filterstr) > 5
+ || g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
+ return 0;
+
+ sscanf(&filterstr[3], "%d", &bit);
+ if (bit >= 0 && bit <= FILTER_BIT_MAX)
+ return 1ULL << bit;
+ else
+ return 0;
+}
+
+static int set_field(guint64 *filter, const char *filterstr)
+{
+ guint64 mask;
+
+ mask = get_filter_mask(filterstr);
+
+ if (mask == 0)
+ return -EINVAL;
+
+ *filter |= mask;
+ return 0;
+}
+
+static GObexApparam *parse_fields(GObexApparam *apparam, DBusMessageIter *iter)
+{
+ DBusMessageIter array;
+ guint64 filter = 0;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return NULL;
+
+ dbus_message_iter_recurse(iter, &array);
+
+ while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+ const char *string;
+
+ dbus_message_iter_get_basic(&array, &string);
+
+ if (set_field(&filter, string) < 0)
+ return NULL;
+
+ dbus_message_iter_next(&array);
+ }
+
+ return g_obex_apparam_set_uint64(apparam, FILTER_TAG, filter);
+}
+static GObexApparam *parse_filters(GObexApparam *apparam,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter array;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return NULL;
+
+ dbus_message_iter_recurse(iter, &array);
+
+ while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+ const char *key;
+ DBusMessageIter value, entry;
+
+ dbus_message_iter_recurse(&array, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (strcasecmp(key, "Format") == 0) {
+ if (parse_format(apparam, &value) == NULL)
+ return NULL;
+ } else if (strcasecmp(key, "Order") == 0) {
+ if (parse_order(apparam, &value) == NULL)
+ return NULL;
+ } else if (strcasecmp(key, "Offset") == 0) {
+ if (parse_offset(apparam, &value) == NULL)
+ return NULL;
+ } else if (strcasecmp(key, "MaxCount") == 0) {
+ if (parse_max_count(apparam, &value) == NULL)
+ return NULL;
+ } else if (strcasecmp(key, "Fields") == 0) {
+ if (parse_fields(apparam, &value) == NULL)
+ return NULL;
+ }
+
+ dbus_message_iter_next(&array);
+ }
+
+ return apparam;
+}
+
static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
DBusMessage *message,
guint8 type, const char *name,
const char *targetfile,
- uint64_t filter, guint8 format,
- guint16 maxlistcount,
- guint16 liststartoffset,
+ GObexApparam *apparam,
GError **err)
{
struct pending_request *request;
struct obc_transfer *transfer;
- GObexApparam *apparam;
guint8 buf[32];
gsize len;
session_callback_t func;
@@ -371,13 +543,6 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
if (transfer == NULL)
return NULL;
- apparam = g_obex_apparam_set_uint64(NULL, FILTER_TAG, filter);
- apparam = g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
- apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG,
- maxlistcount);
- apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
- liststartoffset);
-
switch (type) {
case PULLPHONEBOOK:
func = NULL;
@@ -396,8 +561,6 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
obc_transfer_set_params(transfer, buf, len);
- g_obex_apparam_free(apparam);
-
if (!obc_session_queue(pbap->session, transfer, func, request, err)) {
if (request != NULL)
pending_request_free(request);
@@ -490,31 +653,6 @@ static int set_order(struct pbap_data *pbap, const char *orderstr)
return 0;
}
-static uint64_t get_filter_mask(const char *filterstr)
-{
- int i, bit = -1;
-
- if (!filterstr)
- return 0;
-
- if (!g_ascii_strcasecmp(filterstr, "ALL"))
- return FILTER_ALL;
-
- for (i = 0; filter_list[i] != NULL; i++)
- if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
- return 1ULL << i;
-
- if (strlen(filterstr) < 4 || strlen(filterstr) > 5
- || g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
- return 0;
-
- sscanf(&filterstr[3], "%d", &bit);
- if (bit >= 0 && bit <= FILTER_BIT_MAX)
- return 1ULL << bit;
- else
- return 0;
-}
-
static int add_filter(struct pbap_data *pbap, const char *filterstr)
{
uint64_t mask;
@@ -618,25 +756,41 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
struct obc_transfer *transfer;
const char *targetfile;
char *name;
+ GObexApparam *apparam;
GError *err = NULL;
+ DBusMessageIter args;
if (!pbap->path)
return g_dbus_create_error(message,
ERROR_INTERFACE ".Forbidden",
"Call Select first of all");
- if (dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &targetfile,
- DBUS_TYPE_INVALID) == FALSE)
+ dbus_message_iter_init(message, &args);
+
+ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
return g_dbus_create_error(message,
ERROR_INTERFACE ".InvalidArguments", NULL);
+ dbus_message_iter_get_basic(&args, &targetfile);
+ dbus_message_iter_next(&args);
+
+ apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+ DEFAULT_COUNT);
+ apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+ DEFAULT_OFFSET);
+
+ if (parse_filters(apparam, &args) == NULL) {
+ g_obex_apparam_free(apparam);
+ return g_dbus_create_error(message,
+ ERROR_INTERFACE ".InvalidArguments", NULL);
+ }
+
name = g_strconcat(pbap->path, ".vcf", NULL);
transfer = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
- targetfile, pbap->filter, pbap->format,
- DEFAULT_COUNT, DEFAULT_OFFSET, &err);
+ targetfile, apparam, &err);
g_free(name);
+ g_obex_apparam_free(apparam);
if (transfer == NULL) {
DBusMessage *reply = g_dbus_create_error(message,
@@ -754,20 +908,28 @@ static DBusMessage *pbap_get_size(DBusConnection *connection,
DBusMessage *reply;
struct obc_transfer *transfer;
char *name;
+ GObexApparam *apparam;
GError *err = NULL;
+ DBusMessageIter args;
if (!pbap->path)
return g_dbus_create_error(message,
ERROR_INTERFACE ".Forbidden",
"Call Select first of all");
+ dbus_message_iter_init(message, &args);
+
name = g_strconcat(pbap->path, ".vcf", NULL);
+ apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG, 0);
+ apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+ DEFAULT_OFFSET);
+
transfer = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name, NULL,
- pbap->filter, pbap->format, 0,
- DEFAULT_OFFSET, &err);
+ apparam, &err);
g_free(name);
+ g_obex_apparam_free(apparam);
if (transfer != NULL)
return NULL;
@@ -891,7 +1053,8 @@ static const GDBusMethodTable pbap_methods[] = {
GDBUS_ARGS({ "location", "s" }, { "phonebook", "s" }),
NULL, pbap_select) },
{ GDBUS_METHOD("PullAll",
- GDBUS_ARGS({ "targetfile", "s" }),
+ GDBUS_ARGS({ "targetfile", "s" },
+ { "filters", "a{sv}" }),
GDBUS_ARGS({ "transfer", "o" },
{ "properties", "a{sv}" }),
pbap_pull_all) },
--
1.7.11.4
^ permalink raw reply related
* [PATCH] gatt: Fix reading Service Changed CCC
From: Andrzej Kaczmarek @ 2012-09-06 9:15 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
Find Information Request is only sent when there are no more attributes
following Service Changed Value (incorrect) and thus will never find CCC.
---
profiles/gatt/gas.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index ddd4e70..28d7fbf 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -245,7 +245,7 @@ static void gatt_characteristic_cb(GSList *characteristics, guint8 status,
start = chr->value_handle + 1;
end = gas->gatt.end;
- if (start <= end) {
+ if (start > end) {
error("Inconsistent database: Service Changed CCC missing");
return;
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH v2] Bluetooth: mgmt: Implement support for passkey notification
From: Johan Hedberg @ 2012-09-06 8:09 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1346832850-25061-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds support for Secure Simple Pairing with devices that have
KeyboardOnly as their IO capability. Such devices will cause a passkey
notification on our side and optionally also keypress notifications.
Without this patch some keyboards cannot be paired using the mgmt
interface.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
v2: Make the keypress switch statement consistent with the rest of the code
include/net/bluetooth/hci.h | 18 ++++++++++
include/net/bluetooth/hci_core.h | 5 +++
include/net/bluetooth/mgmt.h | 7 ++++
net/bluetooth/hci_event.c | 67 ++++++++++++++++++++++++++++++++++++++
net/bluetooth/mgmt.c | 16 +++++++++
5 files changed, 113 insertions(+)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 0f28f70..76b2b6b 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1249,6 +1249,24 @@ struct hci_ev_simple_pair_complete {
bdaddr_t bdaddr;
} __packed;
+#define HCI_EV_USER_PASSKEY_NOTIFY 0x3b
+struct hci_ev_user_passkey_notify {
+ bdaddr_t bdaddr;
+ __le32 passkey;
+} __packed;
+
+#define HCI_KEYPRESS_STARTED 0
+#define HCI_KEYPRESS_ENTERED 1
+#define HCI_KEYPRESS_ERASED 2
+#define HCI_KEYPRESS_CLEARED 3
+#define HCI_KEYPRESS_COMPLETED 4
+
+#define HCI_EV_KEYPRESS_NOTIFY 0x3c
+struct hci_ev_keypress_notify {
+ bdaddr_t bdaddr;
+ __u8 type;
+} __packed;
+
#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
struct hci_ev_remote_host_features {
bdaddr_t bdaddr;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index fa807a3..b998b9c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -303,6 +303,8 @@ struct hci_conn {
__u8 pin_length;
__u8 enc_key_size;
__u8 io_capability;
+ __u32 passkey_notify;
+ __u8 passkey_entered;
__u16 disc_timeout;
unsigned long flags;
@@ -1016,6 +1018,9 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status);
int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u32 passkey,
+ u8 entered);
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status);
int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 1b48eff..22980a7 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -478,3 +478,10 @@ struct mgmt_ev_device_unblocked {
struct mgmt_ev_device_unpaired {
struct mgmt_addr_info addr;
} __packed;
+
+#define MGMT_EV_PASSKEY_NOTIFY 0x0017
+struct mgmt_ev_passkey_notify {
+ struct mgmt_addr_info addr;
+ __le32 passkey;
+ __u8 entered;
+} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 48d7302..ccca88f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3263,6 +3263,65 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
}
+static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_user_passkey_notify *ev = (void *) skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s", hdev->name);
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+ if (!conn)
+ return;
+
+ conn->passkey_notify = __le32_to_cpu(ev->passkey);
+ conn->passkey_entered = 0;
+
+ if (test_bit(HCI_MGMT, &hdev->dev_flags))
+ mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+ conn->dst_type, conn->passkey_notify,
+ conn->passkey_entered);
+}
+
+static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_keypress_notify *ev = (void *) skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s", hdev->name);
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+ if (!conn)
+ return;
+
+ switch (ev->type) {
+ case HCI_KEYPRESS_STARTED:
+ conn->passkey_entered = 0;
+ return;
+
+ case HCI_KEYPRESS_ENTERED:
+ conn->passkey_entered++;
+ break;
+
+ case HCI_KEYPRESS_ERASED:
+ conn->passkey_entered--;
+ break;
+
+ case HCI_KEYPRESS_CLEARED:
+ conn->passkey_entered = 0;
+ break;
+
+ case HCI_KEYPRESS_COMPLETED:
+ return;
+ }
+
+ if (test_bit(HCI_MGMT, &hdev->dev_flags))
+ mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+ conn->dst_type, conn->passkey_notify,
+ conn->passkey_entered);
+}
+
static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -3627,6 +3686,14 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_user_passkey_request_evt(hdev, skb);
break;
+ case HCI_EV_USER_PASSKEY_NOTIFY:
+ hci_user_passkey_notify_evt(hdev, skb);
+ break;
+
+ case HCI_EV_KEYPRESS_NOTIFY:
+ hci_keypress_notify_evt(hdev, skb);
+ break;
+
case HCI_EV_SIMPLE_PAIR_COMPLETE:
hci_simple_pair_complete_evt(hdev, skb);
break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 05d4b83..4c04c1e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3276,6 +3276,22 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
MGMT_OP_USER_PASSKEY_NEG_REPLY);
}
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 link_type, u8 addr_type, u32 passkey,
+ u8 entered)
+{
+ struct mgmt_ev_passkey_notify ev;
+
+ BT_DBG("%s", hdev->name);
+
+ bacpy(&ev.addr.bdaddr, bdaddr);
+ ev.addr.type = link_to_bdaddr(link_type, addr_type);
+ ev.passkey = __cpu_to_le32(passkey);
+ ev.entered = entered;
+
+ return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
+}
+
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status)
{
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH] Bluetooth: Add support for BCM20702A0 [04ca, 2003]
From: Al Cho @ 2012-09-06 7:32 UTC (permalink / raw)
To: marcel, gustavo, johan.hedberg, linux-bluetooth
Cc: oneukum, acho, jlee, resler
In-Reply-To: <1346914639-11040-1-git-send-email-acho@suse.com>
Sent a new patch that have new FROM tag
On Thu, Sep 6, 2012 at 2:57 PM, <acho@suse.com> wrote:
> From: "Cho, Yu-Chen" <acho@suse.com>
>
> Add another vendor specific ID for BCM20702A0.
>
> output of usb-devices:
> T: Bus=01 Lev=02 Prnt=02 Port=03 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
> D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
> P: Vendor=04ca ProdID=2003 Rev= 1.12
> S: Manufacturer=Broadcom Corp
> S: Product=BCM20702A0
> S: SerialNumber=446D57861623
> C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
> E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
> E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
> I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
> I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
> I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
> I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
> I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
> I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
> E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
> E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
> I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
> E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
> E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
> I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
>
> Signed-off-by: Cho, Yu-Chen <acho@suse.com>
> ---
> drivers/bluetooth/btusb.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index f077f4d..75943c3 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -93,6 +93,7 @@ static struct usb_device_id btusb_table[] = {
> { USB_DEVICE(0x0c10, 0x0000) },
>
> /* Broadcom BCM20702A0 */
> + { USB_DEVICE(0x04ca, 0x2003) },
> { USB_DEVICE(0x0489, 0xe042) },
> { USB_DEVICE(0x0a5c, 0x21e3) },
> { USB_DEVICE(0x0a5c, 0x21e6) },
> --
> 1.7.7
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Al Yu-Chen Cho
Software Engineer
Room B, 26/F, No. 216 Tun-Hwa S. Road, Sec. 2
Taipei, 106
+8862-2376-0010 X20031
acho@suse.com
SUSE
^ permalink raw reply
* [PATCH] Bluetooth: Add support for BCM20702A0 [04ca, 2003]
From: acho @ 2012-09-06 6:57 UTC (permalink / raw)
To: marcel, gustavo, johan.hedberg, linux-bluetooth
Cc: oneukum, acho, jlee, resler
From: "Cho, Yu-Chen" <acho@suse.com>
Add another vendor specific ID for BCM20702A0.
output of usb-devices:
T: Bus=01 Lev=02 Prnt=02 Port=03 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=04ca ProdID=2003 Rev= 1.12
S: Manufacturer=Broadcom Corp
S: Product=BCM20702A0
S: SerialNumber=446D57861623
C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
Signed-off-by: Cho, Yu-Chen <acho@suse.com>
---
drivers/bluetooth/btusb.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index f077f4d..75943c3 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -93,6 +93,7 @@ static struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */
+ { USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x0a5c, 0x21e3) },
{ USB_DEVICE(0x0a5c, 0x21e6) },
--
1.7.7
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox