2012-04-26 19:45:31

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 01/15] HoG: Register HID over GATT device driver

From: Claudio Takahasi <[email protected]>

---
Makefile.am | 5 +++++
acinclude.m4 | 1 +
input/hog_device.h | 25 +++++++++++++++++++++++++
input/main.c | 13 +++++++++++++
input/manager.c | 34 ++++++++++++++++++++++++++++++++++
input/manager.h | 3 +++
6 files changed, 81 insertions(+), 0 deletions(-)
create mode 100644 input/hog_device.h

diff --git a/Makefile.am b/Makefile.am
index 62705f6..6e152f4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -183,6 +183,11 @@ builtin_sources += input/main.c \
input/fakehid.c input/fakehid.h
endif

+if HOGPLUGIN
+builtin_modules += hog
+builtin_sources += input/hog_device.h
+endif
+
if SERIALPLUGIN
builtin_modules += serial
builtin_sources += serial/main.c \
diff --git a/acinclude.m4 b/acinclude.m4
index dcf9a48..8656379 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -392,4 +392,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(DBUSOOBPLUGIN, test "${dbusoob_enable}" = "yes")
AM_CONDITIONAL(WIIMOTEPLUGIN, test "${wiimote_enable}" = "yes")
AM_CONDITIONAL(GATTMODULES, test "${gatt_enable}" = "yes")
+ AM_CONDITIONAL(HOGPLUGIN, test "${gatt_enable}" = "yes" && test "${input_enable}" = "yes")
])
diff --git a/input/hog_device.h b/input/hog_device.h
new file mode 100644
index 0000000..a0158ea
--- /dev/null
+++ b/input/hog_device.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * 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
+ *
+ */
+
+#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
diff --git a/input/main.c b/input/main.c
index da09b86..2aac3db 100644
--- a/input/main.c
+++ b/input/main.c
@@ -84,3 +84,16 @@ static void input_exit(void)

BLUETOOTH_PLUGIN_DEFINE(input, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
input_init, input_exit)
+
+static int hog_init(void)
+{
+ return hog_manager_init();
+}
+
+static void hog_exit(void)
+{
+ hog_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(hog, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ hog_init, hog_exit)
diff --git a/input/manager.c b/input/manager.c
index 4ac5686..e1d1f81 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -39,6 +39,7 @@
#include "../src/device.h"

#include "device.h"
+#include "hog_device.h"
#include "server.h"
#include "manager.h"

@@ -194,3 +195,36 @@ void input_manager_exit(void)

connection = NULL;
}
+
+static int hog_device_probe(struct btd_device *device, GSList *uuids)
+{
+ const char *path = device_get_path(device);
+
+ DBG("path %s", path);
+
+ return 0;
+}
+
+static void hog_device_remove(struct btd_device *device)
+{
+ const gchar *path = device_get_path(device);
+
+ DBG("path %s", path);
+}
+
+static struct btd_device_driver hog_driver = {
+ .name = "input-hog",
+ .uuids = BTD_UUIDS(HOG_UUID),
+ .probe = hog_device_probe,
+ .remove = hog_device_remove,
+};
+
+int hog_manager_init(void)
+{
+ return btd_register_device_driver(&hog_driver);
+}
+
+void hog_manager_exit(void)
+{
+ btd_unregister_device_driver(&hog_driver);
+}
diff --git a/input/manager.h b/input/manager.h
index 7b93c5b..468de64 100644
--- a/input/manager.h
+++ b/input/manager.h
@@ -23,3 +23,6 @@

int input_manager_init(DBusConnection *conn, GKeyFile *config);
void input_manager_exit(void);
+
+int hog_manager_init(void);
+void hog_manager_exit(void);
--
1.7.7.6



2012-04-26 19:45:45

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 15/15] HoG: Prepend report id to the HID report

If the report descriptor has a report id tag it has to be prepended
to the report data to construct the report itself.
---
input/hog_device.c | 74 ++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index 99de25c..081f33c 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -59,10 +59,6 @@
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif

-struct report {
- struct gatt_char *decl;
-};
-
struct hog_device {
char *path;
struct btd_device *device;
@@ -72,16 +68,35 @@ struct hog_device {
struct gatt_primary *hog_primary;
GSList *reports;
int uhid_fd;
+ gboolean prepend_id;
+};
+
+struct report {
+ uint8_t id;
+ uint8_t type;
+ struct gatt_char *decl;
+ struct hog_device *hogdev;
};

static GSList *devices = NULL;

+static gint report_handle_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct report *report = a;
+ uint16_t handle = GPOINTER_TO_UINT(b);
+
+ return report->decl->value_handle - handle;
+}
+
static void report_value_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
struct hog_device *hogdev = user_data;
struct uhid_event ev;
uint16_t handle;
uint16_t report_size = len - 3;
+ GSList *l;
+ struct report *report;
+ uint8_t *buf;

if (len < 3) { /* 1-byte opcode + 2-byte handle */
error("Malformed ATT notification");
@@ -90,10 +105,26 @@ static void report_value_cb(const uint8_t *pdu, uint16_t len, gpointer user_data

handle = att_get_u16(&pdu[1]);

+ l = g_slist_find_custom(hogdev->reports, GUINT_TO_POINTER(handle),
+ report_handle_cmp);
+ if (!l) {
+ error("Invalid report");
+ return;
+ }
+ report = l->data;
+
memset(&ev, 0, sizeof(ev));
ev.type = UHID_INPUT;
ev.u.input.size = MIN(report_size, UHID_DATA_MAX);
- memcpy(ev.u.input.data, &pdu[3], MIN(report_size, UHID_DATA_MAX));
+
+ buf = ev.u.input.data;
+ if (hogdev->prepend_id) {
+ *buf = report->id;
+ buf++;
+ ev.u.input.size++;
+ }
+
+ memcpy(buf, &pdu[3], MIN(report_size, UHID_DATA_MAX));

if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
error("UHID write failed: %s", strerror(errno));
@@ -123,6 +154,8 @@ static void write_ccc(uint16_t handle, gpointer user_data)
static void report_reference_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
+ struct report *report = user_data;
+
if (status != 0) {
error("Read Report Reference descriptor failed: %s",
att_ecode2str(status));
@@ -134,13 +167,16 @@ static void report_reference_cb(guint8 status, const guint8 *pdu,
return;
}

+ report->id = pdu[1];
+ report->type = pdu[2];
DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]);
}

static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
- struct hog_device *hogdev = user_data;
+ struct report *report = user_data;
+ struct hog_device *hogdev = report->hogdev;
struct att_data_list *list;
uint8_t format;
int i;
@@ -167,10 +203,10 @@ static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
uuid16 = att_get_u16(&value[2]);

if (uuid16 == GATT_CLIENT_CHARAC_CFG_UUID)
- write_ccc(handle, user_data);
+ write_ccc(handle, hogdev);
else if (uuid16 == GATT_REPORT_REFERENCE)
gatt_read_char(hogdev->attrib, handle, 0,
- report_reference_cb, hogdev);
+ report_reference_cb, report);
}

done:
@@ -211,11 +247,20 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
}

DBG("Report MAP:");
- for (i = 0; i < vlen; i += 2) {
- if (i + 1 == vlen)
- DBG("\t %02x", value[i]);
- else
- DBG("\t %02x %02x", value[i], value[i + 1]);
+ for (i = 0; i < vlen; i++) {
+ switch (value[i]) {
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ hogdev->prepend_id = TRUE;
+ }
+
+ if (i % 2 == 0) {
+ if (i + 1 == vlen)
+ DBG("\t %02x", value[i]);
+ else
+ DBG("\t %02x %02x", value[i], value[i + 1]);
+ }
}

vendor_src = btd_device_get_vendor_src(hogdev->device);
@@ -271,10 +316,11 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)

if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
report = g_new0(struct report, 1);
+ report->hogdev = hogdev;
report->decl = g_memdup(chr, sizeof(*chr));
hogdev->reports = g_slist_append(hogdev->reports,
report);
- discover_descriptor(hogdev->attrib, chr, next, hogdev);
+ discover_descriptor(hogdev->attrib, chr, next, report);
} else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0)
gatt_read_char(hogdev->attrib, chr->value_handle, 0,
report_map_read_cb, hogdev);
--
1.7.7.6


2012-04-26 19:45:44

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 14/15] GATT: Move GATT assigned numbers to GATT header

From: Claudio Takahasi <[email protected]>

---
attrib/att.h | 28 ----------------------------
attrib/gatt-service.c | 3 ++-
attrib/gatt.h | 29 +++++++++++++++++++++++++++++
plugins/gatt-example.c | 1 +
proximity/immalert.c | 3 ++-
proximity/linkloss.c | 3 ++-
proximity/reporter.c | 3 ++-
src/attrib-server.c | 3 ++-
time/server.c | 3 ++-
9 files changed, 42 insertions(+), 34 deletions(-)

diff --git a/attrib/att.h b/attrib/att.h
index ba11da7..d12a7f2 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -22,30 +22,6 @@
*
*/

-/* GATT Profile Attribute types */
-#define GATT_PRIM_SVC_UUID 0x2800
-#define GATT_SND_SVC_UUID 0x2801
-#define GATT_INCLUDE_UUID 0x2802
-#define GATT_CHARAC_UUID 0x2803
-
-/* GATT Characteristic Types */
-#define GATT_CHARAC_DEVICE_NAME 0x2A00
-#define GATT_CHARAC_APPEARANCE 0x2A01
-#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02
-#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
-#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
-#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
-
-/* GATT Characteristic Descriptors */
-#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
-#define GATT_CHARAC_USER_DESC_UUID 0x2901
-#define GATT_CLIENT_CHARAC_CFG_UUID 0x2902
-#define GATT_SERVER_CHARAC_CFG_UUID 0x2903
-#define GATT_CHARAC_FMT_UUID 0x2904
-#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
-#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
-#define GATT_REPORT_REFERENCE 0x2908
-
/* Attribute Protocol Opcodes */
#define ATT_OP_ERROR 0x01
#define ATT_OP_MTU_REQ 0x02
@@ -107,10 +83,6 @@
#define ATT_CHAR_PROPER_AUTH 0x40
#define ATT_CHAR_PROPER_EXT_PROPER 0x80

-/* Client Characteristic Configuration bit field */
-#define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001
-#define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002
-
#define ATT_MAX_MTU 256
#define ATT_DEFAULT_L2CAP_MTU 48
#define ATT_DEFAULT_LE_MTU 23
diff --git a/attrib/gatt-service.c b/attrib/gatt-service.c
index d8f7b37..a9de98c 100644
--- a/attrib/gatt-service.c
+++ b/attrib/gatt-service.c
@@ -31,9 +31,10 @@
#include <bluetooth/sdp.h>
#include <adapter.h>

+#include "gattrib.h"
#include "att.h"
+#include "gatt.h"
#include "att-database.h"
-#include "gattrib.h"
#include "attrib-server.h"
#include "gatt-service.h"
#include "log.h"
diff --git a/attrib/gatt.h b/attrib/gatt.h
index 1732270..53be000 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -21,8 +21,37 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+
#include <bluetooth/sdp.h>

+/* GATT Profile Attribute types */
+#define GATT_PRIM_SVC_UUID 0x2800
+#define GATT_SND_SVC_UUID 0x2801
+#define GATT_INCLUDE_UUID 0x2802
+#define GATT_CHARAC_UUID 0x2803
+
+/* GATT Characteristic Types */
+#define GATT_CHARAC_DEVICE_NAME 0x2A00
+#define GATT_CHARAC_APPEARANCE 0x2A01
+#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02
+#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
+#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
+#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
+
+/* GATT Characteristic Descriptors */
+#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
+#define GATT_CHARAC_USER_DESC_UUID 0x2901
+#define GATT_CLIENT_CHARAC_CFG_UUID 0x2902
+#define GATT_SERVER_CHARAC_CFG_UUID 0x2903
+#define GATT_CHARAC_FMT_UUID 0x2904
+#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
+#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
+#define GATT_REPORT_REFERENCE 0x2908
+
+/* Client Characteristic Configuration bit field */
+#define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001
+#define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002
+
typedef void (*gatt_cb_t) (GSList *l, guint8 status, gpointer user_data);

struct gatt_primary {
diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c
index 482bc2d..cd2c481 100644
--- a/plugins/gatt-example.c
+++ b/plugins/gatt-example.c
@@ -37,6 +37,7 @@
#include "gattrib.h"
#include "gatt-service.h"
#include "att.h"
+#include "gatt.h"
#include "att-database.h"
#include "attrib-server.h"

diff --git a/proximity/immalert.c b/proximity/immalert.c
index 4aa973f..1540b61 100644
--- a/proximity/immalert.c
+++ b/proximity/immalert.c
@@ -32,9 +32,10 @@
#include <gdbus.h>

#include "log.h"
+#include "gattrib.h"
#include "att.h"
+#include "gatt.h"
#include "att-database.h"
-#include "gattrib.h"
#include "gatt-service.h"
#include "attrib-server.h"
#include "device.h"
diff --git a/proximity/linkloss.c b/proximity/linkloss.c
index 239eba9..14403cb 100644
--- a/proximity/linkloss.c
+++ b/proximity/linkloss.c
@@ -32,9 +32,10 @@
#include <gdbus.h>

#include "log.h"
-#include "att.h"
#include "att-database.h"
#include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
#include "gatt-service.h"
#include "attrib-server.h"
#include "device.h"
diff --git a/proximity/reporter.c b/proximity/reporter.c
index cb30da5..6d63f25 100644
--- a/proximity/reporter.c
+++ b/proximity/reporter.c
@@ -40,9 +40,10 @@
#include "error.h"
#include "device.h"
#include "hcid.h"
+#include "gattrib.h"
#include "att.h"
+#include "gatt.h"
#include "att-database.h"
-#include "gattrib.h"
#include "attrib-server.h"
#include "reporter.h"
#include "linkloss.h"
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 21b1501..9a211d9 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -45,9 +45,10 @@
#include "adapter.h"
#include "device.h"
#include "manager.h"
+#include "gattrib.h"
#include "att.h"
+#include "gatt.h"
#include "att-database.h"
-#include "gattrib.h"
#include "storage.h"

#include "attrib-server.h"
diff --git a/time/server.c b/time/server.c
index 58d0bcc..13a7bbe 100644
--- a/time/server.c
+++ b/time/server.c
@@ -32,9 +32,10 @@
#include <bluetooth/uuid.h>
#include <adapter.h>

+#include "gattrib.h"
#include "att.h"
+#include "gatt.h"
#include "att-database.h"
-#include "gattrib.h"
#include "attrib-server.h"
#include "gatt-service.h"
#include "log.h"
--
1.7.7.6


2012-04-26 19:45:43

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 13/15] GATT: Rename Characteristic Configuration constants

From: Claudio Takahasi <[email protected]>

This patch renames the constants related to Client Characteristic
Configuration bit field to use a proper name since it is related to
GATT instead of ATT.
---
attrib/att.h | 4 ++--
thermometer/thermometer.c | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/attrib/att.h b/attrib/att.h
index a74eb5a..ba11da7 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -108,8 +108,8 @@
#define ATT_CHAR_PROPER_EXT_PROPER 0x80

/* Client Characteristic Configuration bit field */
-#define ATT_CLIENT_CHAR_CONF_NOTIFICATION 0x0001
-#define ATT_CLIENT_CHAR_CONF_INDICATION 0x0002
+#define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001
+#define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002

#define ATT_MAX_MTU 256
#define ATT_DEFAULT_L2CAP_MTU 48
diff --git a/thermometer/thermometer.c b/thermometer/thermometer.c
index 92c0225..b2d41cd 100644
--- a/thermometer/thermometer.c
+++ b/thermometer/thermometer.c
@@ -363,7 +363,7 @@ static void process_thermometer_desc(struct descriptor *desc)
if (g_slist_length(ch->t->fwatchers) == 0)
return;

- val = ATT_CLIENT_CHAR_CONF_INDICATION;
+ val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
msg = g_strdup("Enable Temperature Measurement "
"indication");
} else if (g_strcmp0(ch->attr.uuid,
@@ -371,12 +371,12 @@ static void process_thermometer_desc(struct descriptor *desc)
if (g_slist_length(ch->t->iwatchers) == 0)
return;

- val = ATT_CLIENT_CHAR_CONF_NOTIFICATION;
+ val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
msg = g_strdup("Enable Intermediate Temperature "
"notification");
} else if (g_strcmp0(ch->attr.uuid,
MEASUREMENT_INTERVAL_UUID) == 0) {
- val = ATT_CLIENT_CHAR_CONF_INDICATION;
+ val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
msg = g_strdup("Enable Measurement Interval "
"indication");
} else
--
1.7.7.6


2012-04-26 19:45:42

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 12/15] HoG: Add read Report Reference descriptor

From: Claudio Takahasi <[email protected]>

This patch adds the GATT operation to read the value of the Report
Reference descriptor of the Report characteristic.
---
input/hog_device.c | 27 +++++++++++++++++++++++----
1 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index 6a7cda2..99de25c 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -120,9 +120,27 @@ static void write_ccc(uint16_t handle, gpointer user_data)
report_ccc_written_cb, hogdev);
}

+static void report_reference_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ if (status != 0) {
+ error("Read Report Reference descriptor failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (plen != 3) {
+ error("Malformed ATT read response");
+ return;
+ }
+
+ DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]);
+}
+
static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
+ struct hog_device *hogdev = user_data;
struct att_data_list *list;
uint8_t format;
int i;
@@ -148,10 +166,11 @@ static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
handle = att_get_u16(value);
uuid16 = att_get_u16(&value[2]);

- if (uuid16 != GATT_CLIENT_CHARAC_CFG_UUID)
- continue;
-
- write_ccc(handle, user_data);
+ if (uuid16 == GATT_CLIENT_CHARAC_CFG_UUID)
+ write_ccc(handle, user_data);
+ else if (uuid16 == GATT_REPORT_REFERENCE)
+ gatt_read_char(hogdev->attrib, handle, 0,
+ report_reference_cb, hogdev);
}

done:
--
1.7.7.6


2012-04-26 19:45:41

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 11/15] GATT: Add Report Reference Descriptor declaration

From: Claudio Takahasi <[email protected]>

This patch adds the Report Reference Descriptor assigned number
declaration defined by the Bluetooth SIG.
---
attrib/att.h | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/attrib/att.h b/attrib/att.h
index 1e128a7..a74eb5a 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -44,6 +44,7 @@
#define GATT_CHARAC_FMT_UUID 0x2904
#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
+#define GATT_REPORT_REFERENCE 0x2908

/* Attribute Protocol Opcodes */
#define ATT_OP_ERROR 0x01
--
1.7.7.6


2012-04-26 19:45:39

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 09/15] HoG: HID I/O driver

UHID is HID I/O driver that makes possible to implement HID I/O drivers in
user-space. It works similar to the uinput but it is initialized with a HID
descriptor and deals with raw HID reports.

This commit uses UHID to create a HID device for the remote HoG device and
to tranfers HID reports to HID subsystem.
---
acinclude.m4 | 9 +++++++-
configure.ac | 2 +
input/hog_device.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++-
input/main.c | 2 +
input/manager.c | 2 +
5 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 8656379..5069878 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -168,6 +168,13 @@ AC_DEFUN([AC_PATH_OUI], [
AC_DEFINE_UNQUOTED(OUIFILE, ["$ac_with_ouifile"], [Define the OUI file path])
])

+AC_DEFUN([AC_PATH_UHID], [
+ AC_CHECK_HEADERS(linux/uhid.h,
+ uhid_found=yes,
+ uhid_found=no
+ )
+])
+
AC_DEFUN([AC_ARG_BLUEZ], [
debug_enable=no
optimization_enable=yes
@@ -392,5 +399,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(DBUSOOBPLUGIN, test "${dbusoob_enable}" = "yes")
AM_CONDITIONAL(WIIMOTEPLUGIN, test "${wiimote_enable}" = "yes")
AM_CONDITIONAL(GATTMODULES, test "${gatt_enable}" = "yes")
- AM_CONDITIONAL(HOGPLUGIN, test "${gatt_enable}" = "yes" && test "${input_enable}" = "yes")
+ AM_CONDITIONAL(HOGPLUGIN, test "${gatt_enable}" = "yes" && test "${input_enable}" = "yes" && test "${uhid_found}" = "yes")
])
diff --git a/configure.ac b/configure.ac
index f298909..689f189 100644
--- a/configure.ac
+++ b/configure.ac
@@ -39,6 +39,7 @@ AC_CHECK_HEADER([sys/inotify.h],
[AC_DEFINE([HAVE_SYS_INOTIFY_H], 1,
[Define to 1 if you have <sys/inotify.h>.])],
[AC_MSG_ERROR(inotify headers are required and missing)])
+
AC_PATH_DBUS
AC_PATH_GLIB
AC_PATH_ALSA
@@ -49,6 +50,7 @@ AC_PATH_SNDFILE
AC_PATH_OUI
AC_PATH_READLINE
AC_PATH_CHECK
+AC_PATH_UHID

AC_ARG_BLUEZ

diff --git a/input/hog_device.c b/input/hog_device.c
index 923ecf7..45c13b2 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -29,6 +29,10 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/uhid.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/uuid.h>
@@ -49,6 +53,11 @@

#define HOG_REPORT_MAP_UUID 0x2A4B
#define HOG_REPORT_UUID 0x2A4D
+#define UHID_DEVICE_FILE "/dev/uhid"
+
+#ifndef MIN
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif

struct report {
struct gatt_char *decl;
@@ -62,13 +71,17 @@ struct hog_device {
guint report_cb_id;
struct gatt_primary *hog_primary;
GSList *reports;
+ int uhid_fd;
};

static GSList *devices = NULL;

static void report_value_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
+ struct hog_device *hogdev = user_data;
+ struct uhid_event ev;
uint16_t handle;
+ uint16_t report_size = len - 3;

if (len < 3) { /* 1-byte opcode + 2-byte handle */
error("Malformed ATT notification");
@@ -76,7 +89,14 @@ static void report_value_cb(const uint8_t *pdu, uint16_t len, gpointer user_data
}

handle = att_get_u16(&pdu[1]);
- DBG("Report notification on handle 0x%04x", handle);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_INPUT;
+ ev.u.input.size = MIN(report_size, UHID_DATA_MAX);
+ memcpy(ev.u.input.data, &pdu[3], MIN(report_size, UHID_DATA_MAX));
+
+ if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
+ error("UHID write failed: %s", strerror(errno));
}

static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
@@ -155,6 +175,8 @@ static void discover_descriptor(GAttrib *attrib, struct gatt_char *chr,
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
+ struct hog_device *hogdev = user_data;
+ struct uhid_event ev;
uint8_t value[ATT_MAX_MTU];
int vlen, i;

@@ -175,6 +197,22 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
else
DBG("\t %02x %02x", value[i], value[i + 1]);
}
+
+ /* create UHID device */
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_CREATE;
+ /* TODO: get info from DIS */
+ strcpy((char *)ev.u.create.name, "bluez-hog-device");
+ ev.u.create.vendor = 0xBEBA;
+ ev.u.create.product = 0xCAFE;
+ ev.u.create.version = 0;
+ ev.u.create.country = 0;
+ ev.u.create.bus = BUS_USB; /* BUS_BLUETOOTH doesn't work here */
+ ev.u.create.rd_data = value;
+ ev.u.create.rd_size = vlen;
+
+ if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
+ error("Failed to create UHID device: %s", strerror(errno));
}

static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
@@ -227,6 +265,13 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
gatt_discover_char(hogdev->attrib, prim->range.start, prim->range.end,
NULL, char_discovered_cb, hogdev);

+ if (hogdev->uhid_fd > 0)
+ return;
+
+ hogdev->uhid_fd = open(UHID_DEVICE_FILE, O_RDWR | O_CLOEXEC);
+ if (hogdev->uhid_fd < 0)
+ error("Failed to open UHID device: %s", strerror(errno));
+
hogdev->report_cb_id = g_attrib_register(hogdev->attrib,
ATT_OP_HANDLE_NOTIFY, report_value_cb,
hogdev, NULL);
@@ -235,6 +280,15 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
static void attio_disconnected_cb(gpointer user_data)
{
struct hog_device *hogdev = user_data;
+ struct uhid_event ev;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_DESTROY;
+ if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
+ error("Failed to destroy UHID device: %s", strerror(errno));
+
+ close(hogdev->uhid_fd);
+ hogdev->uhid_fd = -1;

g_attrib_unregister(hogdev->attrib, hogdev->report_cb_id);
hogdev->report_cb_id = 0;
diff --git a/input/main.c b/input/main.c
index 2aac3db..cea83d8 100644
--- a/input/main.c
+++ b/input/main.c
@@ -85,6 +85,7 @@ static void input_exit(void)
BLUETOOTH_PLUGIN_DEFINE(input, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
input_init, input_exit)

+#ifdef HAVE_LINUX_UHID_H
static int hog_init(void)
{
return hog_manager_init();
@@ -97,3 +98,4 @@ static void hog_exit(void)

BLUETOOTH_PLUGIN_DEFINE(hog, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
hog_init, hog_exit)
+#endif
diff --git a/input/manager.c b/input/manager.c
index 3707e88..8692712 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -196,6 +196,7 @@ void input_manager_exit(void)
connection = NULL;
}

+#ifdef HAVE_LINUX_UHID_H
static int hog_device_probe(struct btd_device *device, GSList *uuids)
{
const char *path = device_get_path(device);
@@ -230,3 +231,4 @@ void hog_manager_exit(void)
{
btd_unregister_device_driver(&hog_driver);
}
+#endif
--
1.7.7.6


2012-04-26 19:45:40

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 10/15] HoG: Use real values for vendor and product IDs

From: Claudio Takahasi <[email protected]>

This patch replaces the hard-code values for vendor and product IDs
by the values obtained from the device core functions. Vendor and
product IDs are read from the remote's Device Information Service.
---
input/hog_device.c | 17 ++++++++++++-----
1 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index 45c13b2..6a7cda2 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -178,6 +178,7 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
struct hog_device *hogdev = user_data;
struct uhid_event ev;
uint8_t value[ATT_MAX_MTU];
+ uint16_t vendor_src, vendor, product, version;
int vlen, i;

if (status != 0) {
@@ -198,15 +199,21 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
DBG("\t %02x %02x", value[i], value[i + 1]);
}

+ vendor_src = btd_device_get_vendor_src(hogdev->device);
+ vendor = btd_device_get_vendor(hogdev->device);
+ product = btd_device_get_product(hogdev->device);
+ version = btd_device_get_version(hogdev->device);
+ DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, "
+ "version=0x%X", vendor_src, vendor, product, version);
+
/* create UHID device */
memset(&ev, 0, sizeof(ev));
ev.type = UHID_CREATE;
- /* TODO: get info from DIS */
strcpy((char *)ev.u.create.name, "bluez-hog-device");
- ev.u.create.vendor = 0xBEBA;
- ev.u.create.product = 0xCAFE;
- ev.u.create.version = 0;
- ev.u.create.country = 0;
+ ev.u.create.vendor = vendor;
+ ev.u.create.product = product;
+ ev.u.create.version = version;
+ ev.u.create.country = 0; /* get this info from the right place */
ev.u.create.bus = BUS_USB; /* BUS_BLUETOOTH doesn't work here */
ev.u.create.rd_data = value;
ev.u.create.rd_size = vlen;
--
1.7.7.6


2012-04-26 19:45:38

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 08/15] HoG: add report notification handler

---
input/hog_device.c | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index 28e7cad..923ecf7 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -59,12 +59,26 @@ struct hog_device {
struct btd_device *device;
GAttrib *attrib;
guint attioid;
+ guint report_cb_id;
struct gatt_primary *hog_primary;
GSList *reports;
};

static GSList *devices = NULL;

+static void report_value_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+ uint16_t handle;
+
+ if (len < 3) { /* 1-byte opcode + 2-byte handle */
+ error("Malformed ATT notification");
+ return;
+ }
+
+ handle = att_get_u16(&pdu[1]);
+ DBG("Report notification on handle 0x%04x", handle);
+}
+
static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
@@ -212,12 +226,19 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)

gatt_discover_char(hogdev->attrib, prim->range.start, prim->range.end,
NULL, char_discovered_cb, hogdev);
+
+ hogdev->report_cb_id = g_attrib_register(hogdev->attrib,
+ ATT_OP_HANDLE_NOTIFY, report_value_cb,
+ hogdev, NULL);
}

static void attio_disconnected_cb(gpointer user_data)
{
struct hog_device *hogdev = user_data;

+ g_attrib_unregister(hogdev->attrib, hogdev->report_cb_id);
+ hogdev->report_cb_id = 0;
+
g_attrib_unref(hogdev->attrib);
hogdev->attrib = NULL;
}
--
1.7.7.6


2012-04-26 19:45:37

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 07/15] HoG: enable "Report" characteristic notification

---
input/hog_device.c | 30 +++++++++++++++++++++++++++---
1 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index c28d337..28e7cad 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -65,10 +65,30 @@ struct hog_device {

static GSList *devices = NULL;

+static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ if (status != 0) {
+ error("Write report characteristic descriptor failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ DBG("Report characteristic descriptor written: notification enabled");
+}
+
+static void write_ccc(uint16_t handle, gpointer user_data)
+{
+ struct hog_device *hogdev = user_data;
+ uint8_t value[] = { 0x01, 0x00 };
+
+ gatt_write_char(hogdev->attrib, handle, value, sizeof(value),
+ report_ccc_written_cb, hogdev);
+}
+
static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
- struct report *report = user_data;
struct att_data_list *list;
uint8_t format;
int i;
@@ -87,13 +107,17 @@ static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
goto done;

for (i = 0; i < list->num; i++) {
- uint16_t uuid16;
+ uint16_t uuid16, handle;
uint8_t *value;

value = list->data[i];
+ handle = att_get_u16(value);
uuid16 = att_get_u16(&value[2]);

- DBG("%s descriptor: 0x%04x", report->decl->uuid, uuid16);
+ if (uuid16 != GATT_CLIENT_CHARAC_CFG_UUID)
+ continue;
+
+ write_ccc(handle, user_data);
}

done:
--
1.7.7.6


2012-04-26 19:45:36

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 06/15] HoG: discover the "Report Map" characteristic

This characteristic contains the HID descriptor.
---
input/hog_device.c | 46 +++++++++++++++++++++++++++++++++++++---------
1 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index 5a81f41..c28d337 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -47,6 +47,7 @@
#include "attio.h"
#include "gatt.h"

+#define HOG_REPORT_MAP_UUID 0x2A4B
#define HOG_REPORT_UUID 0x2A4D

struct report {
@@ -113,10 +114,35 @@ static void discover_descriptor(GAttrib *attrib, struct gatt_char *chr,
gatt_find_info(attrib, start, end, discover_descriptor_cb, user_data);
}

+static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ uint8_t value[ATT_MAX_MTU];
+ int vlen, i;
+
+ if (status != 0) {
+ error("Report Map read failed: %s", att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_read_resp(pdu, plen, value, &vlen)) {
+ error("ATT protocol error");
+ return;
+ }
+
+ DBG("Report MAP:");
+ for (i = 0; i < vlen; i += 2) {
+ if (i + 1 == vlen)
+ DBG("\t %02x", value[i]);
+ else
+ DBG("\t %02x %02x", value[i], value[i + 1]);
+ }
+}
+
static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
{
struct hog_device *hogdev = user_data;
- bt_uuid_t report_uuid;
+ bt_uuid_t report_uuid, report_map_uuid;
struct report *report;
GSList *l;

@@ -127,6 +153,7 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
}

bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
+ bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);

for (l = chars; l; l = g_slist_next(l)) {
struct gatt_char *chr, *next;
@@ -140,14 +167,15 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)

bt_string_to_uuid(&uuid, chr->uuid);

- if (bt_uuid_cmp(&uuid, &report_uuid) != 0)
- continue;
-
- report = g_new0(struct report, 1);
- report->decl = g_memdup(chr, sizeof(*chr));
- hogdev->reports = g_slist_append(hogdev->reports, report);
-
- discover_descriptor(hogdev->attrib, chr, next, hogdev);
+ if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
+ report = g_new0(struct report, 1);
+ report->decl = g_memdup(chr, sizeof(*chr));
+ hogdev->reports = g_slist_append(hogdev->reports,
+ report);
+ discover_descriptor(hogdev->attrib, chr, next, hogdev);
+ } else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0)
+ gatt_read_char(hogdev->attrib, chr->value_handle, 0,
+ report_map_read_cb, hogdev);
}
}

--
1.7.7.6


2012-04-26 19:45:35

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 05/15] HoG: discover descriptors for all characteristics

From: Claudio Takahasi <[email protected]>

"Report" characteristic has "Report Reference Characteristic" descriptor and
"Client Characteristic Configuration" descriptor.
---
input/hog_device.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 55 insertions(+), 1 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index 791550a..5a81f41 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -64,6 +64,55 @@ struct hog_device {

static GSList *devices = NULL;

+static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
+ guint16 len, gpointer user_data)
+{
+ struct report *report = user_data;
+ struct att_data_list *list;
+ uint8_t format;
+ int i;
+
+ if (status != 0) {
+ error("Discover all characteristic descriptors failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ list = dec_find_info_resp(pdu, len, &format);
+ if (list == NULL)
+ return;
+
+ if (format != 0x01)
+ goto done;
+
+ for (i = 0; i < list->num; i++) {
+ uint16_t uuid16;
+ uint8_t *value;
+
+ value = list->data[i];
+ uuid16 = att_get_u16(&value[2]);
+
+ DBG("%s descriptor: 0x%04x", report->decl->uuid, uuid16);
+ }
+
+done:
+ att_data_list_free(list);
+}
+
+static void discover_descriptor(GAttrib *attrib, struct gatt_char *chr,
+ struct gatt_char *next, gpointer user_data)
+{
+ uint16_t start, end;
+
+ start = chr->value_handle + 1;
+ end = (next ? next->handle - 1 : 0xffff);
+
+ if (start >= end)
+ return;
+
+ gatt_find_info(attrib, start, end, discover_descriptor_cb, user_data);
+}
+
static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
{
struct hog_device *hogdev = user_data;
@@ -80,9 +129,12 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);

for (l = chars; l; l = g_slist_next(l)) {
- struct gatt_char *chr = l->data;
+ struct gatt_char *chr, *next;
bt_uuid_t uuid;

+ chr = l->data;
+ next = l->next ? l->next->data : NULL;
+
DBG("0x%04x UUID: %s properties: %02x",
chr->handle, chr->uuid, chr->properties);

@@ -94,6 +146,8 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
report = g_new0(struct report, 1);
report->decl = g_memdup(chr, sizeof(*chr));
hogdev->reports = g_slist_append(hogdev->reports, report);
+
+ discover_descriptor(hogdev->attrib, chr, next, hogdev);
}
}

--
1.7.7.6


2012-04-26 19:45:34

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 04/15] HoG: discover all characteristics declaration

HID service supports multiple report characteristic. Each report
characteristic has a reference descriptor containing ID and type.
---
input/hog_device.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index 6ce05a9..791550a 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -47,21 +47,65 @@
#include "attio.h"
#include "gatt.h"

+#define HOG_REPORT_UUID 0x2A4D
+
+struct report {
+ struct gatt_char *decl;
+};
+
struct hog_device {
char *path;
struct btd_device *device;
GAttrib *attrib;
guint attioid;
struct gatt_primary *hog_primary;
+ GSList *reports;
};

static GSList *devices = NULL;

+static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
+{
+ struct hog_device *hogdev = user_data;
+ bt_uuid_t report_uuid;
+ struct report *report;
+ GSList *l;
+
+ if (status != 0) {
+ const char *str = att_ecode2str(status);
+ DBG("Discover all characteristics failed: %s", str);
+ return;
+ }
+
+ bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
+
+ for (l = chars; l; l = g_slist_next(l)) {
+ struct gatt_char *chr = l->data;
+ bt_uuid_t uuid;
+
+ DBG("0x%04x UUID: %s properties: %02x",
+ chr->handle, chr->uuid, chr->properties);
+
+ bt_string_to_uuid(&uuid, chr->uuid);
+
+ if (bt_uuid_cmp(&uuid, &report_uuid) != 0)
+ continue;
+
+ report = g_new0(struct report, 1);
+ report->decl = g_memdup(chr, sizeof(*chr));
+ hogdev->reports = g_slist_append(hogdev->reports, report);
+ }
+}
+
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
{
struct hog_device *hogdev = user_data;
+ struct gatt_primary *prim = hogdev->hog_primary;

hogdev->attrib = g_attrib_ref(attrib);
+
+ gatt_discover_char(hogdev->attrib, prim->range.start, prim->range.end,
+ NULL, char_discovered_cb, hogdev);
}

static void attio_disconnected_cb(gpointer user_data)
@@ -148,9 +192,17 @@ int hog_device_register(struct btd_device *device, const char *path)
return 0;
}

+static void report_free(void *data)
+{
+ struct report *report = data;
+ g_free(report->decl);
+ g_free(report);
+}
+
static void hog_device_free(struct hog_device *hogdev)
{
btd_device_unref(hogdev->device);
+ g_slist_free_full(hogdev->reports, report_free);
g_free(hogdev->path);
g_free(hogdev->hog_primary);
g_free(hogdev);
--
1.7.7.6


2012-04-26 19:45:33

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 03/15] HoG: load primary service handle

---
input/hog_device.c | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/input/hog_device.c b/input/hog_device.c
index 687dc95..6ce05a9 100644
--- a/input/hog_device.c
+++ b/input/hog_device.c
@@ -31,6 +31,7 @@
#include <unistd.h>

#include <bluetooth/bluetooth.h>
+#include <bluetooth/uuid.h>

#include <glib.h>

@@ -41,14 +42,17 @@

#include "hog_device.h"

+#include "att.h"
#include "gattrib.h"
#include "attio.h"
+#include "gatt.h"

struct hog_device {
char *path;
struct btd_device *device;
GAttrib *attrib;
guint attioid;
+ struct gatt_primary *hog_primary;
};

static GSList *devices = NULL;
@@ -95,18 +99,44 @@ static struct hog_device *hog_device_new(struct btd_device *device,
return hogdev;
}

+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 struct gatt_primary *load_hog_primary(struct btd_device *device)
+{
+ GSList *primaries, *l;
+
+ primaries = btd_device_get_primaries(device);
+
+ l = g_slist_find_custom(primaries, HOG_UUID, primary_uuid_cmp);
+
+ return (l ? l->data : NULL);
+}
+
int hog_device_register(struct btd_device *device, const char *path)
{
struct hog_device *hogdev;
+ struct gatt_primary *prim;

hogdev = find_device_by_path(devices, path);
if (hogdev)
return -EALREADY;

+ prim = load_hog_primary(device);
+ if (!prim)
+ return -EINVAL;
+
hogdev = hog_device_new(device, path);
if (!hogdev)
return -ENOMEM;

+ hogdev->hog_primary = g_memdup(prim, sizeof(*prim));
+
hogdev->attioid = btd_device_add_attio_callback(device,
attio_connected_cb,
attio_disconnected_cb,
@@ -122,6 +152,7 @@ static void hog_device_free(struct hog_device *hogdev)
{
btd_device_unref(hogdev->device);
g_free(hogdev->path);
+ g_free(hogdev->hog_primary);
g_free(hogdev);
}

--
1.7.7.6


2012-04-26 19:45:32

by Joao Paulo Rechi Vita

[permalink] [raw]
Subject: [BlueZ 02/15] HoG: register ATTIO callbacks

This way the LE connection is kept up. Also set device to autoconnect.
---
Makefile.am | 2 +-
input/hog_device.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++
input/hog_device.h | 3 +
input/manager.c | 4 +-
4 files changed, 148 insertions(+), 2 deletions(-)
create mode 100644 input/hog_device.c

diff --git a/Makefile.am b/Makefile.am
index 6e152f4..50777dc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -185,7 +185,7 @@ endif

if HOGPLUGIN
builtin_modules += hog
-builtin_sources += input/hog_device.h
+builtin_sources += input/hog_device.h input/hog_device.c
endif

if SERIALPLUGIN
diff --git a/input/hog_device.c b/input/hog_device.c
new file mode 100644
index 0000000..687dc95
--- /dev/null
+++ b/input/hog_device.c
@@ -0,0 +1,141 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ * 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 <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+#include "../src/adapter.h"
+#include "../src/device.h"
+
+#include "hog_device.h"
+
+#include "gattrib.h"
+#include "attio.h"
+
+struct hog_device {
+ char *path;
+ struct btd_device *device;
+ GAttrib *attrib;
+ guint attioid;
+};
+
+static GSList *devices = NULL;
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+ struct hog_device *hogdev = user_data;
+
+ hogdev->attrib = g_attrib_ref(attrib);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+ struct hog_device *hogdev = user_data;
+
+ g_attrib_unref(hogdev->attrib);
+ hogdev->attrib = NULL;
+}
+
+static struct hog_device *find_device_by_path(GSList *list, const char *path)
+{
+ for (; list; list = list->next) {
+ struct hog_device *hogdev = list->data;
+
+ if (!strcmp(hogdev->path, path))
+ return hogdev;
+ }
+
+ return NULL;
+}
+
+static struct hog_device *hog_device_new(struct btd_device *device,
+ const char *path)
+{
+ struct hog_device *hogdev;
+
+ hogdev = g_new0(struct hog_device, 1);
+ if (!hogdev)
+ return NULL;
+
+ hogdev->path = g_strdup(path);
+ hogdev->device = btd_device_ref(device);
+
+ return hogdev;
+}
+
+int hog_device_register(struct btd_device *device, const char *path)
+{
+ struct hog_device *hogdev;
+
+ hogdev = find_device_by_path(devices, path);
+ if (hogdev)
+ return -EALREADY;
+
+ hogdev = hog_device_new(device, path);
+ if (!hogdev)
+ return -ENOMEM;
+
+ hogdev->attioid = btd_device_add_attio_callback(device,
+ attio_connected_cb,
+ attio_disconnected_cb,
+ hogdev);
+ device_set_auto_connect(device, TRUE);
+
+ devices = g_slist_append(devices, hogdev);
+
+ return 0;
+}
+
+static void hog_device_free(struct hog_device *hogdev)
+{
+ btd_device_unref(hogdev->device);
+ g_free(hogdev->path);
+ g_free(hogdev);
+}
+
+int hog_device_unregister(const char *path)
+{
+ struct hog_device *hogdev;
+
+ hogdev = find_device_by_path(devices, path);
+ if (hogdev == NULL)
+ return -EINVAL;
+
+ btd_device_remove_attio_callback(hogdev->device, hogdev->attioid);
+ devices = g_slist_remove(devices, hogdev);
+ hog_device_free(hogdev);
+
+ return 0;
+}
diff --git a/input/hog_device.h b/input/hog_device.h
index a0158ea..ce6a79e 100644
--- a/input/hog_device.h
+++ b/input/hog_device.h
@@ -23,3 +23,6 @@
*/

#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
+
+int hog_device_register(struct btd_device *device, const char *path);
+int hog_device_unregister(const char *path);
diff --git a/input/manager.c b/input/manager.c
index e1d1f81..3707e88 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -202,7 +202,7 @@ static int hog_device_probe(struct btd_device *device, GSList *uuids)

DBG("path %s", path);

- return 0;
+ return hog_device_register(device, path);
}

static void hog_device_remove(struct btd_device *device)
@@ -210,6 +210,8 @@ static void hog_device_remove(struct btd_device *device)
const gchar *path = device_get_path(device);

DBG("path %s", path);
+
+ hog_device_unregister(path);
}

static struct btd_device_driver hog_driver = {
--
1.7.7.6