* [PATCH 1/4] android/avrcp: Decouple AVRCP logic from btio
From: Andrei Emeltchenko @ 2014-02-06 16:06 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
The patch makes AVRCP to be channel-agnostic so that it might be used in
unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
channel stuff got to avrcp.
---
android/Android.mk | 1 +
android/Makefile.am | 1 +
android/avrcp-lib.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++
android/avrcp-lib.h | 34 +++++++++++++++++++++++
android/avrcp.c | 60 ++++++----------------------------------
5 files changed, 125 insertions(+), 51 deletions(-)
create mode 100644 android/avrcp-lib.c
create mode 100644 android/avrcp-lib.h
diff --git a/android/Android.mk b/android/Android.mk
index 20105e6..9b10cfe 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \
bluez/android/avdtp.c \
bluez/android/a2dp.c \
bluez/android/avctp.c \
+ bluez/android/avrcp-lib.c \
bluez/android/avrcp.c \
bluez/android/pan.c \
bluez/android/handsfree.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 5baa8db..3032940 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -36,6 +36,7 @@ android_bluetoothd_SOURCES = android/main.c \
android/avdtp.h android/avdtp.c \
android/a2dp.h android/a2dp.c \
android/avctp.h android/avctp.c \
+ android/avrcp-lib.h android/avrcp-lib.c \
android/avrcp.h android/avrcp.c \
android/socket.h android/socket.c \
android/pan.h android/pan.c \
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
new file mode 100644
index 0000000..6dcc8ac
--- /dev/null
+++ b/android/avrcp-lib.c
@@ -0,0 +1,80 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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 <stdbool.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/log.h"
+
+#include "avctp.h"
+#include "avrcp-lib.h"
+
+static GSList *devices = NULL;
+
+void avrcp_device_remove(struct avrcp_device *dev)
+{
+ devices = g_slist_remove(devices, dev);
+ avrcp_device_free(dev);
+}
+
+void avrcp_free_all(void)
+{
+ g_slist_free_full(devices, avrcp_device_free);
+ devices = NULL;
+}
+
+struct avrcp_device *avrcp_device_new(const bdaddr_t *dst)
+{
+ struct avrcp_device *dev;
+
+ dev = g_new0(struct avrcp_device, 1);
+ bacpy(&dev->dst, dst);
+ devices = g_slist_prepend(devices, dev);
+
+ return dev;
+}
+
+static int device_cmp(gconstpointer s, gconstpointer user_data)
+{
+ const struct avrcp_device *dev = s;
+ const bdaddr_t *dst = user_data;
+
+ return bacmp(&dev->dst, dst);
+}
+
+struct avrcp_device *avrcp_find(const bdaddr_t *dst)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(devices, dst, device_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
new file mode 100644
index 0000000..bf6872e
--- /dev/null
+++ b/android/avrcp-lib.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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
+ *
+ */
+
+struct avrcp_device {
+ bdaddr_t dst;
+ struct avctp *session;
+ GIOChannel *io;
+};
+
+struct avrcp_device *avrcp_device_new(const bdaddr_t *dst);
+void avrcp_device_free(void *data);
+void avrcp_device_remove(struct avrcp_device *dev);
+void avrcp_free_all(void);
+struct avrcp_device *avrcp_find(const bdaddr_t *dst);
diff --git a/android/avrcp.c b/android/avrcp.c
index 7ee5a8a..22f0a04 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -38,6 +38,7 @@
#include "hal-msg.h"
#include "ipc.h"
#include "avctp.h"
+#include "avrcp-lib.h"
#define L2CAP_PSM_AVCTP 0x17
@@ -48,15 +49,8 @@
static bdaddr_t adapter_addr;
static uint32_t record_id = 0;
-static GSList *devices = NULL;
static GIOChannel *server = NULL;
-struct avrcp_device {
- bdaddr_t dst;
- struct avctp *session;
- GIOChannel *io;
-};
-
static const struct ipc_handler cmd_handlers[] = {
};
@@ -128,7 +122,7 @@ static sdp_record_t *avrcp_record(void)
return record;
}
-static void avrcp_device_free(void *data)
+void avrcp_device_free(void *data)
{
struct avrcp_device *dev = data;
@@ -143,31 +137,6 @@ static void avrcp_device_free(void *data)
g_free(dev);
}
-static void avrcp_device_remove(struct avrcp_device *dev)
-{
- devices = g_slist_remove(devices, dev);
- avrcp_device_free(dev);
-}
-
-static struct avrcp_device *avrcp_device_new(const bdaddr_t *dst)
-{
- struct avrcp_device *dev;
-
- dev = g_new0(struct avrcp_device, 1);
- bacpy(&dev->dst, dst);
- devices = g_slist_prepend(devices, dev);
-
- return dev;
-}
-
-static int device_cmp(gconstpointer s, gconstpointer user_data)
-{
- const struct avrcp_device *dev = s;
- const bdaddr_t *dst = user_data;
-
- return bacmp(&dev->dst, dst);
-}
-
static void disconnect_cb(void *data)
{
struct avrcp_device *dev = data;
@@ -186,7 +155,6 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
char address[18];
uint16_t imtu, omtu;
GError *gerr = NULL;
- GSList *l;
int fd;
if (err) {
@@ -209,13 +177,9 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
ba2str(&dst, address);
- l = g_slist_find_custom(devices, &dst, device_cmp);
- if (l) {
- dev = l->data;
- if (dev->session) {
- error("Unexpected connection");
- return;
- }
+ if (avrcp_find(&dst)) {
+ error("Unexpected connection");
+ return;
} else {
DBG("Incoming connection from %s", address);
dev = avrcp_device_new(&dst);
@@ -293,8 +257,7 @@ void bt_avrcp_unregister(void)
{
DBG("");
- g_slist_free_full(devices, avrcp_device_free);
- devices = NULL;
+ avrcp_free_all();
ipc_unregister(HAL_SERVICE_ID_AVRCP);
@@ -331,12 +294,10 @@ void bt_avrcp_connect(const bdaddr_t *dst)
{
struct avrcp_device *dev;
char addr[18];
- GSList *l;
DBG("");
- l = g_slist_find_custom(devices, dst, device_cmp);
- if (l)
+ if (avrcp_find(dst))
return;
dev = avrcp_device_new(dst);
@@ -352,16 +313,13 @@ void bt_avrcp_connect(const bdaddr_t *dst)
void bt_avrcp_disconnect(const bdaddr_t *dst)
{
struct avrcp_device *dev;
- GSList *l;
DBG("");
- l = g_slist_find_custom(devices, dst, device_cmp);
- if (!l)
+ dev = avrcp_find(dst);
+ if (!dev)
return;
- dev = l->data;
-
if (dev->session) {
avctp_shutdown(dev->session);
return;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/4] unit/avrcp: First unit test for AVRCP profile
From: Andrei Emeltchenko @ 2014-02-06 16:06 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1391702774-18972-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test TP/MPS/BV-01-C [SetAddressedPlayer – CT] verifies
SetAddressedPlayer command.
---
Makefile.am | 9 ++
unit/test-avrcp.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 340 insertions(+)
create mode 100644 unit/test-avrcp.c
diff --git a/Makefile.am b/Makefile.am
index 1a44a9f..67b7167 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -281,6 +281,15 @@ unit_test_avctp_SOURCES = unit/test-avctp.c \
android/avctp.c android/avctp.h
unit_test_avctp_LDADD = @GLIB_LIBS@
+unit_tests += unit/test-avrcp
+
+unit_test_avrcp_SOURCES = unit/test-avrcp.c \
+ src/shared/util.h src/shared/util.c \
+ src/log.h src/log.c \
+ android/avctp.c android/avctp.h \
+ android/avrcp-lib.c android/avrcp-lib.h
+unit_test_avrcp_LDADD = @GLIB_LIBS@ lib/libbluetooth-internal.la
+
unit_tests += unit/test-gdbus-client
unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
new file mode 100644
index 0000000..7efdaea
--- /dev/null
+++ b/unit/test-avrcp.c
@@ -0,0 +1,331 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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 <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "src/log.h"
+#include "lib/bluetooth.h"
+
+#include "android/avctp.h"
+#include "android/avrcp-lib.h"
+
+#define IEEEID_BTSIG 0x001958
+
+struct test_pdu {
+ bool valid;
+ bool fragmented;
+ const uint8_t *data;
+ size_t size;
+};
+
+struct test_data {
+ char *test_name;
+ struct test_pdu *pdu_list;
+};
+
+struct context {
+ GMainLoop *main_loop;
+ struct avrcp_device *dev;
+ guint source;
+ guint process;
+ int fd;
+ unsigned int pdu_offset;
+ const struct test_data *data;
+};
+
+#define data(args...) ((const unsigned char[]) { args })
+
+#define raw_pdu(args...) \
+ { \
+ .valid = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define frg_pdu(args...) \
+ { \
+ .valid = true, \
+ .fragmented = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define define_test(name, function, args...) \
+ do { \
+ const struct test_pdu pdus[] = { \
+ args, { } \
+ }; \
+ static struct test_data data; \
+ data.test_name = g_strdup(name); \
+ data.pdu_list = g_malloc(sizeof(pdus)); \
+ memcpy(data.pdu_list, pdus, sizeof(pdus)); \
+ g_test_add_data_func(name, &data, function); \
+ } while (0)
+
+static void test_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ g_print("%s%s\n", prefix, str);
+}
+
+static void test_free(gconstpointer user_data)
+{
+ const struct test_data *data = user_data;
+
+ g_free(data->test_name);
+ g_free(data->pdu_list);
+}
+
+static gboolean context_quit(gpointer user_data)
+{
+ struct context *context = user_data;
+
+ if (context->process > 0)
+ g_source_remove(context->process);
+
+ g_main_loop_quit(context->main_loop);
+
+ return FALSE;
+}
+
+static gboolean send_pdu(gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ ssize_t len;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ len = write(context->fd, pdu->data, pdu->size);
+
+ if (g_test_verbose())
+ util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ if (pdu->fragmented)
+ return send_pdu(user_data);
+
+ context->process = 0;
+ return FALSE;
+}
+
+static void context_process(struct context *context)
+{
+ if (!context->data->pdu_list[context->pdu_offset].valid) {
+ context_quit(context);
+ return;
+ }
+
+ context->process = g_idle_add(send_pdu, context);
+}
+
+static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ unsigned char buf[512];
+ ssize_t len;
+ int fd;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ context->source = 0;
+ g_print("%s: cond %x\n", __func__, cond);
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ len = read(fd, buf, sizeof(buf));
+
+ g_assert(len > 0);
+
+ if (g_test_verbose())
+ util_hexdump('>', buf, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+ if (!pdu->fragmented)
+ context_process(context);
+
+ return TRUE;
+}
+
+static struct context *create_context(uint16_t version, gconstpointer data)
+{
+ struct context *context = g_new0(struct context, 1);
+ GIOChannel *channel;
+ int err, sv[2];
+ bdaddr_t dst = {};
+
+ context->main_loop = g_main_loop_new(NULL, FALSE);
+ g_assert(context->main_loop);
+
+ err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+ g_assert(err == 0);
+
+ context->dev = avrcp_device_new(&dst);
+ context->dev->session = avctp_new(sv[0], 672, 672, version);
+ g_assert(context->dev->session != NULL);
+
+ channel = g_io_channel_unix_new(sv[1]);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ context->source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ test_handler, context);
+ g_assert(context->source > 0);
+
+ g_io_channel_unref(channel);
+
+ context->fd = sv[1];
+ context->data = data;
+
+ return context;
+}
+
+static void execute_context(struct context *context)
+{
+ g_main_loop_run(context->main_loop);
+
+ if (context->source > 0)
+ g_source_remove(context->source);
+
+ avrcp_device_free(context->dev);
+
+ g_main_loop_unref(context->main_loop);
+
+ test_free(context->data);
+ g_free(context);
+}
+
+#define AVRCP_SET_ADDRESSED_PLAYER 0x60
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avrcp_header {
+ uint8_t company_id[3];
+ uint8_t pdu_id;
+ uint8_t packet_type:2;
+ uint8_t rsvd:6;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avrcp_header {
+ uint8_t company_id[3];
+ uint8_t pdu_id;
+ uint8_t rsvd:6;
+ uint8_t packet_type:2;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#else
+#error "Unknown byte order"
+#endif
+
+static void set_company_id(uint8_t cid[3], const uint32_t cid_in)
+{
+ cid[0] = cid_in >> 16;
+ cid[1] = cid_in >> 8;
+ cid[2] = cid_in;
+}
+
+static int avrcp_set_addr_player(struct context *context)
+{
+ uint8_t buf[AVRCP_HEADER_LENGTH + 2];
+ struct avrcp_header *pdu = (void *) buf;
+ struct avctp *session = context->dev->session;
+
+ memset(buf, 0, sizeof(buf));
+
+ set_company_id(pdu->company_id, IEEEID_BTSIG);
+
+ pdu->pdu_id = AVRCP_SET_ADDRESSED_PLAYER;
+ pdu->params[0] = 0xab;
+ pdu->params[1] = 0xcd;
+ pdu->params_len = htons(2);
+
+ return avctp_send_vendordep_req(session, AVC_CTYPE_CONTROL,
+ AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+ NULL, NULL);
+}
+
+static void test_client(gconstpointer data)
+{
+ struct context *context = create_context(0x0100, data);
+ int ret = 0;
+
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-01-C"))
+ ret = avrcp_set_addr_player(context);
+
+ DBG("ret = %d", ret);
+
+ g_assert(!ret);
+
+ execute_context(context);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ if (g_test_verbose())
+ __btd_log_init("*", 0);
+
+ /* Media Player Selection Commands and Notifications tests */
+
+ define_test("/TP/MPS/BV-01-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48, 0x00,
+ 0x00, 0x19, 0x58, 0x60, 0x00, 0x00,
+ 0x02, 0xab, 0xcd));
+
+ return g_test_run();
+}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/4] unit/avrcp: Add support for browsing AVCTP channel
From: Andrei Emeltchenko @ 2014-02-06 16:06 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1391702774-18972-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
unit/test-avrcp.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 92 insertions(+), 4 deletions(-)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 7efdaea..58e4c15 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -47,6 +47,7 @@
struct test_pdu {
bool valid;
bool fragmented;
+ bool browse;
const uint8_t *data;
size_t size;
};
@@ -60,8 +61,10 @@ struct context {
GMainLoop *main_loop;
struct avrcp_device *dev;
guint source;
+ guint browse_source;
guint process;
int fd;
+ int browse_fd;
unsigned int pdu_offset;
const struct test_data *data;
};
@@ -75,6 +78,14 @@ struct context {
.size = sizeof(data(args)), \
}
+#define brs_pdu(args...) \
+ { \
+ .valid = true, \
+ .browse = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
#define frg_pdu(args...) \
{ \
.valid = true, \
@@ -130,7 +141,10 @@ static gboolean send_pdu(gpointer user_data)
pdu = &context->data->pdu_list[context->pdu_offset++];
- len = write(context->fd, pdu->data, pdu->size);
+ if (pdu->browse)
+ len = write(context->browse_fd, pdu->data, pdu->size);
+ else
+ len = write(context->fd, pdu->data, pdu->size);
if (g_test_verbose())
util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
@@ -163,6 +177,8 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
ssize_t len;
int fd;
+ DBG("");
+
pdu = &context->data->pdu_list[context->pdu_offset++];
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -190,23 +206,68 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
return TRUE;
}
+static gboolean browse_test_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ unsigned char buf[512];
+ ssize_t len;
+ int fd;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ context->browse_source = 0;
+ g_print("%s: cond %x\n", __func__, cond);
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ len = read(fd, buf, sizeof(buf));
+
+ g_assert(len > 0);
+
+ if (g_test_verbose())
+ util_hexdump('>', buf, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+ if (!pdu->fragmented)
+ context_process(context);
+
+ return TRUE;
+}
+
static struct context *create_context(uint16_t version, gconstpointer data)
{
struct context *context = g_new0(struct context, 1);
+ struct avctp *session;
GIOChannel *channel;
int err, sv[2];
bdaddr_t dst = {};
+ int ret;
+
+ DBG("");
context->main_loop = g_main_loop_new(NULL, FALSE);
g_assert(context->main_loop);
+ /* Control channel setup */
+
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
- g_assert(err == 0);
+ g_assert(!err);
context->dev = avrcp_device_new(&dst);
- context->dev->session = avctp_new(sv[0], 672, 672, version);
- g_assert(context->dev->session != NULL);
+ g_assert(context->dev);
+ session = avctp_new(sv[0], 672, 672, version);
+ g_assert(session);
+
+ context->dev->session = session;
channel = g_io_channel_unix_new(sv[1]);
g_io_channel_set_close_on_unref(channel, TRUE);
@@ -221,6 +282,30 @@ static struct context *create_context(uint16_t version, gconstpointer data)
g_io_channel_unref(channel);
context->fd = sv[1];
+
+ /* Browsing channel setup */
+
+ err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+ g_assert(!err);
+
+ ret = avctp_connect_browsing(session, sv[0], 672, 672);
+ g_assert(!ret);
+
+ channel = g_io_channel_unix_new(sv[1]);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ context->browse_source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ browse_test_handler, context);
+ g_assert(context->browse_source > 0);
+
+ g_io_channel_unref(channel);
+
+ context->browse_fd = sv[1];
+
context->data = data;
return context;
@@ -233,6 +318,9 @@ static void execute_context(struct context *context)
if (context->source > 0)
g_source_remove(context->source);
+ if (context->browse_source > 0)
+ g_source_remove(context->browse_source);
+
avrcp_device_free(context->dev);
g_main_loop_unref(context->main_loop);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 4/4] unit/avrcp: Add TP/MPS/BV-03-C test case
From: Andrei Emeltchenko @ 2014-02-06 16:06 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1391702774-18972-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the Set Browsed Player command issued by the
AVRCP controller.
---
unit/test-avrcp.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 58e4c15..211ea36 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -330,6 +330,7 @@ static void execute_context(struct context *context)
}
#define AVRCP_SET_ADDRESSED_PLAYER 0x60
+#define AVRCP_SET_BROWSED_PLAYER 0x70
#if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -359,6 +360,13 @@ struct avrcp_header {
#error "Unknown byte order"
#endif
+struct avrcp_browsing_header {
+ uint8_t pdu_id;
+ uint16_t param_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
static void set_company_id(uint8_t cid[3], const uint32_t cid_in)
{
cid[0] = cid_in >> 16;
@@ -386,6 +394,35 @@ static int avrcp_set_addr_player(struct context *context)
NULL, NULL);
}
+static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
+ uint8_t *operands,
+ size_t operand_count,
+ void *user_data)
+{
+ DBG("");
+
+ return FALSE;
+}
+
+static int avrcp_set_browsed_player(struct context *context)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 2];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+ struct avctp *session = context->dev->session;
+
+ DBG("");
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_SET_BROWSED_PLAYER;
+ pdu->params[0] = 0xab;
+ pdu->params[1] = 0xcd;
+ pdu->param_len = htons(2);
+
+ return avctp_send_browsing_req(session, buf, sizeof(buf),
+ avrcp_set_browsed_player_rsp, session);
+}
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(0x0100, data);
@@ -394,6 +431,9 @@ static void test_client(gconstpointer data)
if (g_str_equal(context->data->test_name, "/TP/MPS/BV-01-C"))
ret = avrcp_set_addr_player(context);
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-03-C"))
+ ret = avrcp_set_browsed_player(context);
+
DBG("ret = %d", ret);
g_assert(!ret);
@@ -415,5 +455,8 @@ int main(int argc, char *argv[])
0x00, 0x19, 0x58, 0x60, 0x00, 0x00,
0x02, 0xab, 0xcd));
+ define_test("/TP/MPS/BV-03-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x70, 0x00, 0x02,
+ 0xab, 0xcd));
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* Re: LE Connection Update Disallowed
From: Sandy Chapman @ 2014-02-06 16:21 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: BlueZ development
In-Reply-To: <CAJdJm_MScMpFNekv-9E3eFneNmLsgdurKb-R3kMTP66Gy40yaQ@mail.gmail.com>
Hi Anderson,
On Wed, Feb 5, 2014 at 11:23 AM, Anderson Lizardo
<anderson.lizardo@openbossa.org> wrote:
> HI Sandy,
>
> On Wed, Feb 5, 2014 at 10:51 AM, Sandy Chapman <schapman@lixar.com> wrote:
>>>> How do I initiate a Connection Update from the peripheral?
>>>
>>> I never tried this procedure myself, but my guess it that you are
>>> using the incorrect mechanism on the slave role. Take a look at the
>>> "Connection Parameters Update Request" on Vol 3, Part A, Section 4.20.
>>> I believe this is the correct way to request from the slave (from what
>>> I understand while reading the Linux kernel implementation of the
>>> master side).
>>>
>>> Note that when Linux is the master, this command is issued
>>> automatically by the kernel when requested by the slave.
>>
>> I've taken a look at that section and it appears that this is what is
>> used to trigger the Connection Update. It states that the command
>> shall only be issued from the slave to the master. I can confirm that
>> my device is in the slave role using 'hcitool con'.
>
> I think you didn't notice that the section I mentioned is about a
> L2CAP signalling packet, not an HCI command (which in this case is to
> be used on the master side). I suggest you read a bit more on the
> L2CAP section to understand how these signalling packets work. Then
> you can try building such packet with "hcitool cmd" (unless there is
> some support for it on the current kernel, which I didn't check)
>
Yes, you right, I missed that part. I've built out what my packet
should look like, but I'm having troubles sending it to the
controller. I really am stuck on issuing this packet. It appears that
I need to send an HCI ACL Data Packet which holds a Signalling
Command. This signalling command then holds the connection parameter
update request as it's payload. It looks like 'hcitool cmd' can't send
ACL packets though as the command requires an OGF and OCF which are
part of the HCI Command Packet, not the HCI ACL Data Packet. From what
I can tell, the best chance I'd have is to send it via the l2test tool
over L2CAP, but attempting to use le_public address type doesn't work
(which I believe will send the message over CID 0x0005 - the fixed LE
channel). It fails on getsockopt/setsockopt for the SOL_BLUETOOTH
type. From what I can tell, it requires a kernel with CoC (not sure
what it means or if I have it). I'm really hoping I'm not going to
have to compile the bluetooth kernel module myself to send this
connection update packet.
>>> You may want to take a look at the "GAP Peripheral Preferred
>>> Connection Parameters" characteristic (see Vol 3, Part C, Section
>>> 12.3). If iPhones reads this characteristic and honours the
>>> parameters, it may help.
>>
>> Unfortunately, it appears Apple explicitly ignores this parameter
>> (section 3.6 in this document
>> https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf).
>
> This is unfortunate. It would be the easiest way to pass custom
> connection parameters IMHO.
>
>> I believe that 'hcitool lecup' is exactly supposed to initiate this
>> process. I've also tried to use 'hcitool cmd' to issue direct commands
>> to the controller (using Vol 3, Part A, Section 4.20 as a guide), but
>> I am having no luck. It's stating that the command is disallowed (not
>> that the parameters are invalid), so I'm guessing there's something
>> else wrong. Since this is directly communicating with the controller,
>> where would the problem be? In the kernel, itself? Could it be a
>> problem with the Broadcom chipset in my MacBook?
>
> "hcitool lecup" is just a helper, it uses the same mechanism that
> "hcitool cmd" uses (and both are just "raw" interfaces to the
> Bluetooth controller). If you are getting an "Invalid Parameters" on
> any of them, is either because you built the packet incorrectly on
> "hcitool cmd" or given invalid values as per the spec.
>
> By the way, I suggest using "btmon" instead of "hcidump", as the
> former has nicer output and is more up-to-date (although I'm not sure
> it supports parsing "LE Connection Update" parameters).
>
You're right btmon is much nicer and does support recognition of the
LE commands.
> Best Regards,
> --
> Anderson Lizardo
> http://www.indt.org/?lang=en
> INdT - Manaus - Brazil
I know what I'm doing might not be typical, but I really appreciate
your help. If there's any direction you could point me in, I'd be
really thankful. I don't really know what to try next.
Thanks again,
Sandy
--
^ permalink raw reply
* Re: [RFC v8 06/10] Bluetooth: Introduce LE auto connection infrastructure
From: Andre Guedes @ 2014-02-06 17:34 UTC (permalink / raw)
To: Vinicius Costa Gomes; +Cc: linux-bluetooth
In-Reply-To: <20140206160209.GA26623@molly>
Hi Vinicius,
On Thu, 2014-02-06 at 14:02 -0200, Vinicius Costa Gomes wrote:
> Hi Andre,
>
> On 19:23 Wed 05 Feb, Andre Guedes wrote:
> > This patch introduces the LE auto connection infrastructure which
> > will be used to implement the LE auto connection options.
> >
> > In summary, the auto connection mechanism works as follows: Once the
> > first pending LE connection is created, the background scanning is
> > started. When the target device is found in range, the kernel
> > autonomously starts the connection attempt. If connection is
> > established successfully, that pending LE connection is deleted and
> > the background is stopped.
> >
> > To achieve that, this patch introduces the hci_update_background_scan()
> > which controls the background scanning state. This function starts or
> > stops the background scanning based on the hdev->pend_le_conns list. If
> > there is no pending LE connection, the background scanning is stopped.
> > Otherwise, we start the background scanning.
> >
> > Then, every time a pending LE connection is added we call hci_update_
> > background_scan() so the background scanning is started (in case it is
> > not already running). Likewise, every time a pending LE connection is
> > deleted we call hci_update_background_scan() so the background scanning
> > is stopped (in case this was the last pending LE connection) or it is
> > started again (in case we have more pending LE connections). Finally,
> > we also call hci_update_background_scan() in hci_le_conn_failed() so
> > the background scan is restarted in case the connection establishment
> > fails. This way the background scanning keeps running until all pending
> > LE connection are established.
> >
> > Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> > ---
>
> [snip]
>
> > static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > {
> > u8 num_reports = skb->data[0];
> > void *ptr = &skb->data[1];
> > s8 rssi;
> >
> > + hci_dev_lock(hdev);
> > +
> > while (num_reports--) {
> > struct hci_ev_le_advertising_info *ev = ptr;
> >
> > + check_pending_le_conn(hdev, &ev->bdaddr, ev->bdaddr_type);
> > +
>
> Shouldn't the event type be checked to see if it is a connectable event?
Sure. I'm fixing it.
Thanks,
Andre
^ permalink raw reply
* [RFC v8 06/10] Bluetooth: Introduce LE auto connection infrastructure
From: Andre Guedes @ 2014-02-06 17:35 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20140206160209.GA26623@molly>
This patch introduces the LE auto connection infrastructure which
will be used to implement the LE auto connection options.
In summary, the auto connection mechanism works as follows: Once the
first pending LE connection is created, the background scanning is
started. When the target device is found in range, the kernel
autonomously starts the connection attempt. If connection is
established successfully, that pending LE connection is deleted and
the background is stopped.
To achieve that, this patch introduces the hci_update_background_scan()
which controls the background scanning state. This function starts or
stops the background scanning based on the hdev->pend_le_conns list. If
there is no pending LE connection, the background scanning is stopped.
Otherwise, we start the background scanning.
Then, every time a pending LE connection is added we call hci_update_
background_scan() so the background scanning is started (in case it is
not already running). Likewise, every time a pending LE connection is
deleted we call hci_update_background_scan() so the background scanning
is stopped (in case this was the last pending LE connection) or it is
started again (in case we have more pending LE connections). Finally,
we also call hci_update_background_scan() in hci_le_conn_failed() so
the background scan is restarted in case the connection establishment
fails. This way the background scanning keeps running until all pending
LE connection are established.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 2 +
net/bluetooth/hci_conn.c | 5 +++
net/bluetooth/hci_core.c | 83 +++++++++++++++++++++++++++++++++++++++-
net/bluetooth/hci_event.c | 44 +++++++++++++++++++++
4 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7b9c4ed..3c8dc0f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -778,6 +778,8 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
void hci_pend_le_conns_clear(struct hci_dev *hdev);
+void hci_update_background_scan(struct hci_dev *hdev);
+
int hci_uuids_clear(struct hci_dev *hdev);
int hci_link_keys_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 70f4226..f3ca73f 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -527,6 +527,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
hci_proto_connect_cfm(conn, status);
hci_conn_del(conn);
+
+ /* Since we may have temporarily stopped the background scanning in
+ * favor of connection establishment, we should restart it.
+ */
+ hci_update_background_scan(hdev);
}
static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0f670bc..ff85205 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3021,7 +3021,7 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
if (entry)
- return;
+ goto done;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
@@ -3035,6 +3035,9 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
list_add(&entry->list, &hdev->pend_le_conns);
BT_DBG("addr %pMR (type %u)", addr, addr_type);
+
+done:
+ hci_update_background_scan(hdev);
}
/* This function requires the caller holds hdev->lock */
@@ -3044,12 +3047,15 @@ void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
if (!entry)
- return;
+ goto done;
list_del(&entry->list);
kfree(entry);
BT_DBG("addr %pMR (type %u)", addr, addr_type);
+
+done:
+ hci_update_background_scan(hdev);
}
/* This function requires the caller holds hdev->lock */
@@ -4597,3 +4603,76 @@ void hci_stop_le_scan_req(struct hci_request *req)
cp.enable = LE_SCAN_DISABLE;
hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
}
+
+static void update_background_scan_complete(struct hci_dev *hdev, u8 status)
+{
+ if (status)
+ BT_DBG("HCI request failed to update background scanning: "
+ "status 0x%2.2x", status);
+}
+
+/* This function controls the background scanning based on hdev->pend_le_conns
+ * list. If there are pending LE connection we start the background scanning,
+ * otherwise we stop it.
+ *
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_update_background_scan(struct hci_dev *hdev)
+{
+ struct hci_cp_le_set_scan_param param_cp;
+ struct hci_cp_le_set_scan_enable enable_cp;
+ struct hci_request req;
+ struct hci_conn *conn;
+ int err;
+
+ hci_req_init(&req, hdev);
+
+ if (list_empty(&hdev->pend_le_conns)) {
+ /* If there is no pending LE connections, we should stop
+ * the background scanning.
+ */
+
+ /* If controller is not scanning we are done. */
+ if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return;
+
+ hci_stop_le_scan_req(&req);
+
+ BT_DBG("%s stopping background scanning", hdev->name);
+ } else {
+ /* If there is at least one pending LE connection, we should
+ * keep the background scan running.
+ */
+
+ /* If controller is already scanning we are done. */
+ if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return;
+
+ /* If controller is connecting, we should not start scanning
+ * since some controllers are not able to scan and connect at
+ * the same time.
+ */
+ conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+ if (conn)
+ return;
+
+ memset(¶m_cp, 0, sizeof(param_cp));
+ param_cp.type = LE_SCAN_PASSIVE;
+ param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
+ param_cp.window = cpu_to_le16(hdev->le_scan_window);
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
+ ¶m_cp);
+
+ memset(&enable_cp, 0, sizeof(enable_cp));
+ enable_cp.enable = LE_SCAN_ENABLE;
+ enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+ &enable_cp);
+
+ BT_DBG("%s starting background scanning", hdev->name);
+ }
+
+ err = hci_req_run(&req, update_background_scan_complete);
+ if (err)
+ BT_ERR("Failed to run HCI request: err %d", err);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index df58cde..5796c06 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3620,25 +3620,69 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_proto_connect_cfm(conn, ev->status);
+ hci_pend_le_conn_del(hdev, &ev->bdaddr, ev->bdaddr_type);
+
unlock:
hci_dev_unlock(hdev);
}
+/* This function requires the caller holds hdev->lock */
+static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
+ u8 addr_type)
+{
+ struct hci_conn *conn;
+ u8 bdaddr_type;
+
+ if (!hci_pend_le_conn_lookup(hdev, addr, addr_type))
+ return;
+
+ if (addr_type == ADDR_LE_DEV_PUBLIC)
+ bdaddr_type = BDADDR_LE_PUBLIC;
+ else
+ bdaddr_type = BDADDR_LE_RANDOM;
+
+ conn = hci_connect(hdev, LE_LINK, addr, bdaddr_type, BT_SECURITY_LOW,
+ HCI_AT_NO_BONDING);
+ if (!IS_ERR(conn))
+ return;
+
+ switch (PTR_ERR(conn)) {
+ case -EBUSY:
+ /* If hci_connect() returns -EBUSY it means there is already
+ * an LE connection attempt going on. Since controllers don't
+ * support more than one connection attempt at the time, we
+ * don't consider this an error case.
+ */
+ break;
+ default:
+ BT_DBG("Failed to connect: err %ld", PTR_ERR(conn));
+ }
+}
+
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
u8 num_reports = skb->data[0];
void *ptr = &skb->data[1];
s8 rssi;
+ hci_dev_lock(hdev);
+
while (num_reports--) {
struct hci_ev_le_advertising_info *ev = ptr;
+ if (ev->evt_type == LE_ADV_IND ||
+ ev->evt_type == LE_ADV_DIRECT_IND)
+ check_pending_le_conn(hdev, &ev->bdaddr,
+ ev->bdaddr_type);
+
rssi = ev->data[ev->length];
mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
NULL, rssi, 0, 1, ev->data, ev->length);
ptr += sizeof(*ev) + ev->length + 1;
}
+
+ hci_dev_unlock(hdev);
}
static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
--
1.8.5.3
^ permalink raw reply related
* [PATCH 1/6] android/a2dp: Close AVDTP gracefully
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
When closing AVDTP we should wait for for CLOSE request to complete
(so stream go to idle state) before disconnecting signalling socket.
In case CLOSE is rejected, we simply abort stream.
---
android/a2dp.c | 4 +++-
android/avdtp.c | 21 +++++++++++++++++----
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 8cff535..8d6e7bf 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1166,8 +1166,10 @@ static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
DBG("");
- if (err)
+ if (err) {
+ avdtp_abort(session, stream);
return;
+ }
setup_remove_by_id(endpoint->id);
}
diff --git a/android/avdtp.c b/android/avdtp.c
index e26d6ec..b9d1992 100644
--- a/android/avdtp.c
+++ b/android/avdtp.c
@@ -398,6 +398,8 @@ struct avdtp {
struct pending_req *req;
GSList *disconnect;
+
+ bool shutdown;
};
static GSList *lseps = NULL;
@@ -913,6 +915,11 @@ static void avdtp_sep_set_state(struct avdtp *session,
session->streams = g_slist_remove(session->streams, stream);
stream_free(stream);
}
+
+ if (session->io && session->shutdown && session->streams == NULL) {
+ int sock = g_io_channel_unix_get_fd(session->io);
+ shutdown(sock, SHUT_RDWR);
+ }
}
static void finalize_discovery(struct avdtp *session, int err)
@@ -2141,7 +2148,7 @@ gboolean avdtp_remove_disconnect_cb(struct avdtp *session, unsigned int id)
void avdtp_shutdown(struct avdtp *session)
{
GSList *l;
- int sock;
+ bool closing = false;
if (!session->io)
return;
@@ -2149,12 +2156,18 @@ void avdtp_shutdown(struct avdtp *session)
for (l = session->streams; l; l = g_slist_next(l)) {
struct avdtp_stream *stream = l->data;
- avdtp_close(session, stream, TRUE);
+ if (avdtp_close(session, stream, TRUE) == 0)
+ closing = true;
}
- sock = g_io_channel_unix_get_fd(session->io);
+ if (closing) {
+ /* defer shutdown until all streams closed */
+ session->shutdown = true;
+ } else {
+ int sock = g_io_channel_unix_get_fd(session->io);
- shutdown(sock, SHUT_RDWR);
+ shutdown(sock, SHUT_RDWR);
+ }
}
static void queue_request(struct avdtp *session, struct pending_req *req,
--
1.8.5.3
^ permalink raw reply related
* [PATCH 2/6] android/a2dp: Notify audio state on SEP close
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
---
android/a2dp.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 8d6e7bf..8eabfeb 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -990,6 +990,8 @@ static gboolean sep_close_ind(struct avdtp *session,
return FALSE;
}
+ bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+
setup_remove(setup);
return TRUE;
@@ -1163,6 +1165,7 @@ static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
void *user_data)
{
struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
DBG("");
@@ -1171,7 +1174,16 @@ static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
return;
}
- setup_remove_by_id(endpoint->id);
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for %u endpoint",
+ endpoint->id);
+ return;
+ }
+
+ bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+
+ setup_remove(setup);
}
static void sep_abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
--
1.8.5.3
^ permalink raw reply related
* [PATCH 3/6] android/hal-audio: Ignore write call when closing
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
We should not try to neither auto-resume nor write when state is set to
NONE as this is case when we're being closed and it's ok do ignore
write request.
---
android/hal-audio.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/android/hal-audio.c b/android/hal-audio.c
index efdf823..766327b 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -831,6 +831,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *) stream;
+ /* just return in case we're closing */
+ if (out->audio_state == AUDIO_A2DP_STATE_NONE)
+ return -1;
+
/* We can auto-start only from standby */
if (out->audio_state == AUDIO_A2DP_STATE_STANDBY) {
DBG("stream in standby, auto-start");
--
1.8.5.3
^ permalink raw reply related
* [PATCH 4/6] android/hal-audio: Write SBC parameters to logcat
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
---
android/hal-audio.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/android/hal-audio.c b/android/hal-audio.c
index 766327b..9312659 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -289,6 +289,78 @@ static int sbc_get_presets(struct audio_preset *preset, size_t *len)
return i;
}
+static int sbc_freq2int(uint8_t freq)
+{
+ switch (freq) {
+ case SBC_SAMPLING_FREQ_16000:
+ return 16000;
+ case SBC_SAMPLING_FREQ_32000:
+ return 32000;
+ case SBC_SAMPLING_FREQ_44100:
+ return 44100;
+ case SBC_SAMPLING_FREQ_48000:
+ return 48000;
+ default:
+ return 0;
+ }
+}
+
+static const char *sbc_mode2str(uint8_t mode)
+{
+ switch (mode) {
+ case SBC_CHANNEL_MODE_MONO:
+ return "Mono";
+ case SBC_CHANNEL_MODE_DUAL_CHANNEL:
+ return "DualChannel";
+ case SBC_CHANNEL_MODE_STEREO:
+ return "Stereo";
+ case SBC_CHANNEL_MODE_JOINT_STEREO:
+ return "JointStereo";
+ default:
+ return "(unknown)";
+ }
+}
+
+static int sbc_blocks2int(uint8_t blocks)
+{
+ switch (blocks) {
+ case SBC_BLOCK_LENGTH_4:
+ return 4;
+ case SBC_BLOCK_LENGTH_8:
+ return 8;
+ case SBC_BLOCK_LENGTH_12:
+ return 12;
+ case SBC_BLOCK_LENGTH_16:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+static int sbc_subbands2int(uint8_t subbands)
+{
+ switch (subbands) {
+ case SBC_SUBBANDS_4:
+ return 4;
+ case SBC_SUBBANDS_8:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+static const char *sbc_allocation2str(uint8_t allocation)
+{
+ switch (allocation) {
+ case SBC_ALLOCATION_SNR:
+ return "SNR";
+ case SBC_ALLOCATION_LOUDNESS:
+ return "Loudness";
+ default:
+ return "(unknown)";
+ }
+}
+
static void sbc_init_encoder(struct sbc_data *sbc_data)
{
a2dp_sbc_t *in = &sbc_data->sbc;
@@ -298,6 +370,15 @@ static void sbc_init_encoder(struct sbc_data *sbc_data)
out->endian = SBC_LE;
out->bitpool = in->max_bitpool;
+
+ DBG("frequency=%d channel_mode=%s block_length=%d subbands=%d "
+ "allocation=%s bitpool=%d-%d",
+ sbc_freq2int(in->frequency),
+ sbc_mode2str(in->channel_mode),
+ sbc_blocks2int(in->block_length),
+ sbc_subbands2int(in->subbands),
+ sbc_allocation2str(in->allocation_method),
+ in->min_bitpool, in->max_bitpool);
}
static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
--
1.8.5.3
^ permalink raw reply related
* [PATCH 5/6] android/a2dp: Disconnect headset on IPC failure
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
In case audio IPC is suddenly disconnected (most likely due to crash of
mediaserver process) we should disconnect headset since it is no longer
associated with valid setup and cannot be used properly.
---
android/a2dp.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 8eabfeb..f67a593 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1515,6 +1515,7 @@ static gboolean audio_retry_register(void *data)
static void audio_disconnected(void *data)
{
+ GSList *l;
bool restart;
DBG("");
@@ -1526,6 +1527,12 @@ static void audio_disconnected(void *data)
bt_audio_unregister();
+ for (l = devices; l; l = g_slist_next(l)) {
+ struct a2dp_device *dev = l->data;
+
+ avdtp_shutdown(dev->session);
+ }
+
if (!restart)
return;
--
1.8.5.3
^ permalink raw reply related
* [PATCH 6/6] android/a2dp: Fix audio deregistration
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
Unregistering a SEP can trigger abort_cfm callback if some device is
connected thus we should free setups list before all endpoints are
unregistered to avoid error in abort_cfm due to non-existing setup.
---
android/a2dp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index f67a593..7a2f3cf 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1483,12 +1483,12 @@ static void bt_audio_unregister(void)
if (audio_retry_id > 0)
g_source_remove(audio_retry_id);
- g_slist_free_full(setups, setup_free);
- setups = NULL;
-
g_slist_free_full(endpoints, unregister_endpoint);
endpoints = NULL;
+ g_slist_free_full(setups, setup_free);
+ setups = NULL;
+
audio_ipc_cleanup();
}
--
1.8.5.3
^ permalink raw reply related
* FW: How to install bluez in Linux mint
From: Eric Shields @ 2014-02-06 22:21 UTC (permalink / raw)
To: linux-bluetooth
Sorry about that. No idea you didn't accept html. Below is the original
message in plain text, as is the rest of this email. I would NEVER be so
mean as to even attempt to send a virus or junk through your system. I just
need help, that's all. I shouldn't have used Gmail. Isn't configured for
plain text.
Thank you,
Eric Shields
Sent with Microsoft Outlook 2003
________________________________________
From: Eric Shields [mailto:skyvaleden0120@gmail.com]
Sent: Thursday, February 06, 2014 4:18 PM
To: linux-bluetooth@vger.kernel.org
Subject: How to install bluez in Linux mint
Hello, I am new to Linux but familiar with Android so I was wondering if any
help can be lent (so I can configure my Bluetooth adapter to be recognized
as a network adapter)? Please get back to me whenever possible.
Eric Shields
Sent via my Galaxy S Relay
via Gmail App
^ permalink raw reply
* RE: possible bug in blueZ 5.8 gatt tool or library
From: Caleb Reinhold @ 2014-02-06 22:48 UTC (permalink / raw)
To: 'Anderson Lizardo'; +Cc: 'BlueZ development'
In-Reply-To: <CAJdJm_PEQEmCz1owo8MZ+29R-O5u8qm8x85WgeuKy9U1x74zGw@mail.gmail.com>
Hi Anderson,
Thanks for your advice. Connecting to the device on low security and then
switching to medium does allow gatttool to receive and confirm the
indication.
Our interest in gatttool is mainly as a demonstration of BlueZ's GATT API.
Our own GATT client application borrows heavily from gatttool and adds
features such as support for multiple simultaneous connections.
It seemed that calling g_attrib_register() in the connection callback might
be causing the client to start listening for indications and notifications
too late, but registering right after the gatt_connect() call doesn't seem
to help. Nor does placing a watch on the GIOChannel inside bt_io_connect(),
so registering earlier doesn't appear to be the right approach. Do you know
why we keep missing this initial indication on medium security, and how we
might fix this issue?
Thanks for your time,
Tom Harada
-----Original Message-----
From: Anderson Lizardo [mailto:anderson.lizardo@openbossa.org]
Sent: Tuesday, February 04, 2014 6:06 PM
To: Caleb Reinhold
Cc: BlueZ development
Subject: Re: possible bug in blueZ 5.8 gatt tool or library
Hi Caleb,
On Tue, Feb 4, 2014 at 5:12 PM, Caleb Reinhold
<creinhold@lampreynetworks.com> wrote:
> We are working with the 5.8 version of the library, kernel version
> 3.12.9, bluetoothctl, and gatttool when we encountered a possible error.
> We expected on the reconnection of two bonded devices, one of which
> had stored measurements, that data would transfer. When running gatt
> tool in medium security the first measurement to be indicated was lost.
First of all, gatttool is a developer tool, and it is far from being a
compliant GATT endpoint (e.g. it does not report to requests, which is
mandatory by the spec). With moderate effort though, the missing features
can be added.
> However upon attempting to reconnect to the simulated agent device
> with medium security two unexpected behaviors occurred. First, and
> more immediately apparent was that the simulated agent did not receive
> a confirmation of the indication. A slightly closer look using the
> hcidump, trying to find what had happened, showed that the indication
> had arrived at the hci layer but was not received at events_handler.
Are you using gatttool in interactive mode (i.e. the -I option) ? If yes,
try first connecting to the device with "connect" followed by setting the
security level to medium with "sec-level medium". This will imitate the
behavior of the BlueZ daemon when connecting to LE devices. Also be sure to
use the "--listen" option so the confirmation is sent by gatttool.
Let us know if it works :)
> While the indication
> is sent very swiftly upon the reconnection of the devices we
> understand this to be the manner in which low energy devices are
> supposed to behave given stored measurements and a bonded device.
You are correct that this is the expected behavior. But gatttool is far from
perfect. Did you try implementing a BlueZ plugin?
Best Regards,
--
Anderson Lizardo
http://www.indt.org/?lang=en
INdT - Manaus - Brazil
--
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
^ permalink raw reply
* BISECTED Re: 3.14-mw regression: circular locking dependency (&tty->legacy_mutex){+.+.+.}, at: [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
From: Sander Eikelenboom @ 2014-02-07 0:37 UTC (permalink / raw)
To: Marcel Holtmann, gianluca
Cc: Greg Kroah-Hartman, linux-wireless, linux-bluetooth, linux-serial
In-Reply-To: <378824645.20140126114721@eikelenboom.it>
Hi Marcel / Gianluca,
Bisection points to this commit:
4a2fb3ecc7467c775b154813861f25a0ddc11aa0 is the first bad commit
commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0
Author: Gianluca Anzolin <gianluca@sottospazio.it>
Date: Mon Jan 6 21:23:52 2014 +0100
Bluetooth: Always wait for a connection on RFCOMM open()
This patch fixes two regressions introduced with the recent rfcomm tty
rework.
The current code uses the carrier_raised() method to wait for the
bluetooth connection when a process opens the tty.
However processes may open the port with the O_NONBLOCK flag or set the
CLOCAL termios flag: in these cases the open() syscall returns
immediately without waiting for the bluetooth connection to
complete.
This behaviour confuses userspace which expects an established bluetooth
connection.
The patch restores the old behaviour by waiting for the connection in
rfcomm_dev_activate() and removes carrier_raised() from the tty_port ops.
As a side effect the new code also fixes the case in which the rfcomm
tty device is created with the flag RFCOMM_REUSE_DLC: the old code
didn't call device_move() and ModemManager skipped the detection
probe. Now device_move() is always called inside rfcomm_dev_activate().
Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
Reported-by: Andrey Vihrov <andrey.vihrov@gmail.com>
Reported-by: Beson Chow <blc+bluez@mail.vanade.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
BTW perhaps time to update your tree ?
Bisection took me back to 3.12 like areas .. the risk of bisection failing of other unrelated bugs seems to increase that way
Sunday, January 26, 2014, 11:47:21 AM, you wrote:
> Hi,
> I have got a regression with a 3.14-mw kernel (last commit is 4ba9920e5e9c0e16b5ed24292d45322907bb9035)
> when a script is started that reads from serial over bluetooth, that wasn't in the 3.13 release kernel:
> Jan 26 11:36:10 serveerstertje kernel: [ 72.892926]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.900249] ======================================================
> Jan 26 11:36:10 serveerstertje kernel: [ 72.907697] [ INFO: possible circular locking dependency detected ]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.915214] 3.13.0-20140125-mw-pcireset+ #1 Not tainted
> Jan 26 11:36:10 serveerstertje kernel: [ 72.922307] -------------------------------------------------------
> Jan 26 11:36:10 serveerstertje kernel: [ 72.928315] zabbix_slimmeme/5909 is trying to acquire lock:
> Jan 26 11:36:10 serveerstertje kernel: [ 72.934323] (&tty->legacy_mutex){+.+.+.}, at: [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 72.940434]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.940434] but task is already holding lock:
> Jan 26 11:36:10 serveerstertje kernel: [ 72.952263] (&port->mutex){+.+.+.}, at: [<ffffffff81518aa7>] tty_port_open+0x67/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 72.958292]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.958292] which lock already depends on the new lock.
> Jan 26 11:36:10 serveerstertje kernel: [ 72.958292]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.976267]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.976267] the existing dependency chain (in reverse order) is:
> Jan 26 11:36:10 serveerstertje kernel: [ 72.988276]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.988276] -> #1 (&port->mutex){+.+.+.}:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.000386] [<ffffffff81102dfd>] lock_acquire+0xcd/0x110
> Jan 26 11:36:10 serveerstertje kernel: [ 73.006526] [<ffffffff81ad3f97>] mutex_lock_nested+0x47/0x560
> Jan 26 11:36:10 serveerstertje kernel: [ 73.012612] [<ffffffff81518aa7>] tty_port_open+0x67/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.018637] [<ffffffff81aa4356>] rfcomm_tty_open+0x26/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.024674] [<ffffffff8150fcea>] tty_open+0x16a/0x5c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.030748] [<ffffffff811b4013>] chrdev_open+0xa3/0x1c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.036833] [<ffffffff811ad686>] do_dentry_open.isra.16+0x246/0x2f0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.043001] [<ffffffff811ad81d>] finish_open+0x1d/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.049106] [<ffffffff811befae>] do_last+0x7ce/0xdf0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.055191] [<ffffffff811bf68d>] path_openat+0xbd/0x6b0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.061211] [<ffffffff811c004e>] do_filp_open+0x3e/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.067177] [<ffffffff811aeaec>] do_sys_open+0x13c/0x230
> Jan 26 11:36:10 serveerstertje kernel: [ 73.073141] [<ffffffff811aebfd>] SyS_open+0x1d/0x20
> Jan 26 11:36:10 serveerstertje kernel: [ 73.079047] [<ffffffff81ad6f39>] system_call_fastpath+0x16/0x1b
> Jan 26 11:36:10 serveerstertje kernel: [ 73.084962]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.084962] -> #0 (&tty->legacy_mutex){+.+.+.}:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.096600] [<ffffffff8110230b>] __lock_acquire+0x1d4b/0x2220
> Jan 26 11:36:10 serveerstertje kernel: [ 73.102559] [<ffffffff81102dfd>] lock_acquire+0xcd/0x110
> Jan 26 11:36:10 serveerstertje kernel: [ 73.108475] [<ffffffff81ad3f97>] mutex_lock_nested+0x47/0x560
> Jan 26 11:36:10 serveerstertje kernel: [ 73.114419] [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.120354] [<ffffffff81ad63ab>] tty_lock+0xb/0x10
> Jan 26 11:36:10 serveerstertje kernel: [ 73.126258] [<ffffffff81aa4677>] rfcomm_dev_activate+0xb7/0x250
> Jan 26 11:36:10 serveerstertje kernel: [ 73.132222] [<ffffffff81518ad7>] tty_port_open+0x97/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.138195] [<ffffffff81aa4356>] rfcomm_tty_open+0x26/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.144207] [<ffffffff8150fcea>] tty_open+0x16a/0x5c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.150164] [<ffffffff811b4013>] chrdev_open+0xa3/0x1c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.156127] [<ffffffff811ad686>] do_dentry_open.isra.16+0x246/0x2f0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.162070] [<ffffffff811ad81d>] finish_open+0x1d/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.167933] [<ffffffff811befae>] do_last+0x7ce/0xdf0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.173787] [<ffffffff811bf68d>] path_openat+0xbd/0x6b0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.179600] [<ffffffff811c004e>] do_filp_open+0x3e/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.185302] [<ffffffff811aeaec>] do_sys_open+0x13c/0x230
> Jan 26 11:36:10 serveerstertje kernel: [ 73.190880] [<ffffffff811aebfd>] SyS_open+0x1d/0x20
> Jan 26 11:36:10 serveerstertje kernel: [ 73.196247] [<ffffffff81ad6f39>] system_call_fastpath+0x16/0x1b
> Jan 26 11:36:10 serveerstertje kernel: [ 73.201486]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.201486] other info that might help us debug this:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.201486]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.216718] Possible unsafe locking scenario:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.216718]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.226933] CPU0 CPU1
> Jan 26 11:36:10 serveerstertje kernel: [ 73.231978] ---- ----
> Jan 26 11:36:10 serveerstertje kernel: [ 73.237001] lock(&port->mutex);
> Jan 26 11:36:10 serveerstertje kernel: [ 73.241994] lock(&tty->legacy_mutex);
> Jan 26 11:36:10 serveerstertje kernel: [ 73.247043] lock(&port->mutex);
> Jan 26 11:36:10 serveerstertje kernel: [ 73.251999] lock(&tty->legacy_mutex);
> Jan 26 11:36:10 serveerstertje kernel: [ 73.256902]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.256902] *** DEADLOCK ***
> Jan 26 11:36:10 serveerstertje kernel: [ 73.256902]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.270890] 1 lock held by zabbix_slimmeme/5909:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.275398] #0: (&port->mutex){+.+.+.}, at: [<ffffffff81518aa7>] tty_port_open+0x67/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.280124]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.280124] stack backtrace:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.289130] CPU: 5 PID: 5909 Comm: zabbix_slimmeme Not tainted 3.13.0-20140125-mw-pcireset+ #1
> Jan 26 11:36:10 serveerstertje kernel: [ 73.293860] Hardware name: MSI MS-7640/890FXA-GD70 (MS-7640) , BIOS V1.8B1 09/13/2010
> Jan 26 11:36:10 serveerstertje kernel: [ 73.298625] ffffffff826e2b70 ffff88005858f818 ffffffff81acbcfa ffff880057c72300
> Jan 26 11:36:10 serveerstertje kernel: [ 73.303571] ffffffff826e2b70 ffff88005858f868 ffffffff81ac7011 ffff880057c72300
> Jan 26 11:36:10 serveerstertje kernel: [ 73.308511] ffff880057c72300 ffff88005858f868 ffff880057c72ac0 0000000000000000
> Jan 26 11:36:10 serveerstertje kernel: [ 73.313325] Call Trace:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.318092] [<ffffffff81acbcfa>] dump_stack+0x46/0x58
> Jan 26 11:36:10 serveerstertje kernel: [ 73.322900] [<ffffffff81ac7011>] print_circular_bug+0x2f6/0x32a
> Jan 26 11:36:10 serveerstertje kernel: [ 73.327723] [<ffffffff8110230b>] __lock_acquire+0x1d4b/0x2220
> Jan 26 11:36:10 serveerstertje kernel: [ 73.332545] [<ffffffff810fedbd>] ? trace_hardirqs_on+0xd/0x10
> Jan 26 11:36:10 serveerstertje kernel: [ 73.337414] [<ffffffff810e6141>] ? finish_task_switch+0x41/0xf0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.342279] [<ffffffff81ad0244>] ? sleep_on_timeout+0x4/0x20
> Jan 26 11:36:10 serveerstertje kernel: [ 73.347128] [<ffffffff81102dfd>] lock_acquire+0xcd/0x110
> Jan 26 11:36:10 serveerstertje kernel: [ 73.351950] [<ffffffff81ad6344>] ? tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.356792] [<ffffffff81ad3f97>] mutex_lock_nested+0x47/0x560
> Jan 26 11:36:10 serveerstertje kernel: [ 73.361599] [<ffffffff81ad6344>] ? tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.366363] [<ffffffff810fec6b>] ? trace_hardirqs_on_caller+0xfb/0x240
> Jan 26 11:36:10 serveerstertje kernel: [ 73.371200] [<ffffffff810fedbd>] ? trace_hardirqs_on+0xd/0x10
> Jan 26 11:36:10 serveerstertje kernel: [ 73.376030] [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.380842] [<ffffffff81ad63ab>] tty_lock+0xb/0x10
> Jan 26 11:36:10 serveerstertje kernel: [ 73.385616] [<ffffffff81aa4677>] rfcomm_dev_activate+0xb7/0x250
> Jan 26 11:36:10 serveerstertje kernel: [ 73.390398] [<ffffffff81ad4287>] ? mutex_lock_nested+0x337/0x560
> Jan 26 11:36:10 serveerstertje kernel: [ 73.395154] [<ffffffff810f90f0>] ? __init_waitqueue_head+0x60/0x60
> Jan 26 11:36:10 serveerstertje kernel: [ 73.399861] [<ffffffff81518ad7>] tty_port_open+0x97/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.404552] [<ffffffff81aa4356>] rfcomm_tty_open+0x26/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.409263] [<ffffffff8150fcea>] tty_open+0x16a/0x5c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.413954] [<ffffffff811b4013>] chrdev_open+0xa3/0x1c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.418657] [<ffffffff81457bfd>] ? lockref_get+0x1d/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.423379] [<ffffffff811b3f70>] ? cdev_put+0x30/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.428056] [<ffffffff811ad686>] do_dentry_open.isra.16+0x246/0x2f0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.432768] [<ffffffff811ad81d>] finish_open+0x1d/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.437464] [<ffffffff811befae>] do_last+0x7ce/0xdf0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.442166] [<ffffffff811baff3>] ? inode_permission+0x13/0x50
> Jan 26 11:36:10 serveerstertje kernel: [ 73.446861] [<ffffffff811bb5ce>] ? link_path_walk+0x21e/0x880
> Jan 26 11:36:10 serveerstertje kernel: [ 73.451533] [<ffffffff810fec6b>] ? trace_hardirqs_on_caller+0xfb/0x240
> Jan 26 11:36:10 serveerstertje kernel: [ 73.456280] [<ffffffff811bf68d>] path_openat+0xbd/0x6b0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.461029] [<ffffffff8104cb03>] ? __do_page_fault+0x103/0x4e0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.465782] [<ffffffff81102e1d>] ? lock_acquire+0xed/0x110
> Jan 26 11:36:10 serveerstertje kernel: [ 73.470553] [<ffffffff811c004e>] do_filp_open+0x3e/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.475321] [<ffffffff811cda31>] ? __alloc_fd+0xd1/0x120
> Jan 26 11:36:10 serveerstertje kernel: [ 73.480064] [<ffffffff811aeaec>] do_sys_open+0x13c/0x230
> Jan 26 11:36:10 serveerstertje kernel: [ 73.484743] [<ffffffff810fec6b>] ? trace_hardirqs_on_caller+0xfb/0x240
> Jan 26 11:36:10 serveerstertje kernel: [ 73.489470] [<ffffffff811aebfd>] SyS_open+0x1d/0x20
> Jan 26 11:36:10 serveerstertje kernel: [ 73.494191] [<ffffffff81ad6f39>] system_call_fastpath+0x16/0x1b
--
Best regards,
Sander mailto:linux@eikelenboom.it
^ permalink raw reply
* Re: possible bug in blueZ 5.8 gatt tool or library
From: Anderson Lizardo @ 2014-02-07 0:55 UTC (permalink / raw)
To: Caleb Reinhold; +Cc: BlueZ development
In-Reply-To: <000001cf238d$a774e310$f65ea930$@lampreynetworks.com>
Hi,
On Thu, Feb 6, 2014 at 6:48 PM, Caleb Reinhold
<creinhold@lampreynetworks.com> wrote:
> It seemed that calling g_attrib_register() in the connection callback might
> be causing the client to start listening for indications and notifications
> too late, but registering right after the gatt_connect() call doesn't seem
> to help. Nor does placing a watch on the GIOChannel inside bt_io_connect(),
> so registering earlier doesn't appear to be the right approach. Do you know
> why we keep missing this initial indication on medium security, and how we
> might fix this issue?
If I remember correctly, the issue is in the kernel: if connect() is
called when security level is medium, the socket only gets POLLOUT
once SMP pairing finishes, and any ATT PDU received during that time
is lost.
Note that it's almost certain that your device is sending the
indication without requiring encryption. Otherwise, it would have sent
a Security Request (which triggers a Pairing Request from the Linux
side) and wait for the encryption to be enabled before sending the
indication. If that was the case, the kernel would deliver the ATT PDU
to gatttool after encryption is enabled and it would work as expected.
PS: Please, as common netiquette, avoid top-posting (i.e. answer
before the original message) and quote only the text that gives
context to your answer.
Best Regards,
--
Anderson Lizardo
http://www.indt.org/?lang=en
INdT - Manaus - Brazil
^ permalink raw reply
* Re: BISECTED Re: 3.14-mw regression: circular locking dependency (&tty->legacy_mutex){+.+.+.}, at: [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
From: Gianluca Anzolin @ 2014-02-07 6:55 UTC (permalink / raw)
To: Sander Eikelenboom
Cc: Marcel Holtmann, Greg Kroah-Hartman, linux-wireless,
linux-bluetooth, linux-serial
In-Reply-To: <754206689.20140207013750@eikelenboom.it>
Hi Sander,
On Fri, Feb 07, 2014 at 01:37:50AM +0100, Sander Eikelenboom wrote:
> Hi Marcel / Gianluca,
>
> Bisection points to this commit:
>
> 4a2fb3ecc7467c775b154813861f25a0ddc11aa0 is the first bad commit
> commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0
> Author: Gianluca Anzolin <gianluca@sottospazio.it>
> Date: Mon Jan 6 21:23:52 2014 +0100
Thank you for you report. I'm aware of this bug, no need to investigate
further.
This and other bugs are being tackled by Peter Hurley, who knows the tty
code way better than me.
You just have to wait for his patches, I think they will come shortly.
Thank you,
Gianluca
^ permalink raw reply
* Re: [PATCH 1/6] android/a2dp: Close AVDTP gracefully
From: Luiz Augusto von Dentz @ 2014-02-07 9:18 UTC (permalink / raw)
To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
Hi Andrzej,
On Thu, Feb 6, 2014 at 7:54 PM, Andrzej Kaczmarek
<andrzej.kaczmarek@tieto.com> wrote:
> When closing AVDTP we should wait for for CLOSE request to complete
> (so stream go to idle state) before disconnecting signalling socket.
> In case CLOSE is rejected, we simply abort stream.
> ---
> android/a2dp.c | 4 +++-
> android/avdtp.c | 21 +++++++++++++++++----
> 2 files changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index 8cff535..8d6e7bf 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -1166,8 +1166,10 @@ static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
>
> DBG("");
>
> - if (err)
> + if (err) {
> + avdtp_abort(session, stream);
> return;
> + }
>
> setup_remove_by_id(endpoint->id);
> }
> diff --git a/android/avdtp.c b/android/avdtp.c
> index e26d6ec..b9d1992 100644
> --- a/android/avdtp.c
> +++ b/android/avdtp.c
> @@ -398,6 +398,8 @@ struct avdtp {
> struct pending_req *req;
>
> GSList *disconnect;
> +
> + bool shutdown;
> };
>
> static GSList *lseps = NULL;
> @@ -913,6 +915,11 @@ static void avdtp_sep_set_state(struct avdtp *session,
> session->streams = g_slist_remove(session->streams, stream);
> stream_free(stream);
> }
> +
> + if (session->io && session->shutdown && session->streams == NULL) {
> + int sock = g_io_channel_unix_get_fd(session->io);
> + shutdown(sock, SHUT_RDWR);
> + }
> }
>
> static void finalize_discovery(struct avdtp *session, int err)
> @@ -2141,7 +2148,7 @@ gboolean avdtp_remove_disconnect_cb(struct avdtp *session, unsigned int id)
> void avdtp_shutdown(struct avdtp *session)
> {
> GSList *l;
> - int sock;
> + bool closing = false;
>
> if (!session->io)
> return;
> @@ -2149,12 +2156,18 @@ void avdtp_shutdown(struct avdtp *session)
> for (l = session->streams; l; l = g_slist_next(l)) {
> struct avdtp_stream *stream = l->data;
>
> - avdtp_close(session, stream, TRUE);
> + if (avdtp_close(session, stream, TRUE) == 0)
> + closing = true;
You could assign true directly to session->shutdown and return, also
it is probably a good idea to check if the flag is already set and if
it does call avdtp_abort, in fact I think we should call avdtp_abort
not avdtp_close anyway since we are shutting it down there is no point
of given the remote even a chance to reject.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v3 0/8] Android PAN fixes
From: Luiz Augusto von Dentz @ 2014-02-07 9:37 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1391700522-9036-1-git-send-email-szymon.janc@tieto.com>
Hi Szymon,
On Thu, Feb 6, 2014 at 5:28 PM, Szymon Janc <szymon.janc@tieto.com> wrote:
> V3:
> - fixed not bringing bridge if down
> - add forward_delay with ioctl patch
> - other minor bugfixes
>
> V2:
> This is based on patch from Ravi (sent 23.01.2013). Changes include
> patch split and some bugfixes.
>
> Ravi kumar Veeramally (1):
> android/pan: Fix bnep interface name
>
> Szymon Janc (7):
> profiles/network: Use interface name passed to bnep_connadd
> profiles/network: Allow to pass interface name to bnep_new
> android/pan: Move functions up to avoid forward declarations
> android/pan: Fix unregistering NAP bridge
> android/pan: Use ioctl instead of sysfs for setting forward delay
> android/pan: Pass error in nap_remove_bridge
> android/pan: Bring bridge interface down before removing it
>
> android/pan.c | 205 ++++++++++++++++++++++++++----------------
> profiles/network/bnep.c | 10 ++-
> profiles/network/bnep.h | 3 +-
> profiles/network/connection.c | 6 +-
> profiles/network/server.c | 4 +
> 5 files changed, 146 insertions(+), 82 deletions(-)
>
> --
> 1.8.3.2
Applied, thanks.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH 5/6] android/a2dp: Disconnect headset on IPC failure
From: Luiz Augusto von Dentz @ 2014-02-07 9:45 UTC (permalink / raw)
To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1391709250-8047-5-git-send-email-andrzej.kaczmarek@tieto.com>
Hi Andrzej,
On Thu, Feb 6, 2014 at 7:54 PM, Andrzej Kaczmarek
<andrzej.kaczmarek@tieto.com> wrote:
> In case audio IPC is suddenly disconnected (most likely due to crash of
> mediaserver process) we should disconnect headset since it is no longer
> associated with valid setup and cannot be used properly.
> ---
> android/a2dp.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index 8eabfeb..f67a593 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -1515,6 +1515,7 @@ static gboolean audio_retry_register(void *data)
>
> static void audio_disconnected(void *data)
> {
> + GSList *l;
> bool restart;
>
> DBG("");
> @@ -1526,6 +1527,12 @@ static void audio_disconnected(void *data)
>
> bt_audio_unregister();
>
> + for (l = devices; l; l = g_slist_next(l)) {
> + struct a2dp_device *dev = l->data;
> +
> + avdtp_shutdown(dev->session);
> + }
> +
> if (!restart)
> return;
If we are unregistering the endpoints properly this should not happen,
perhaps what is wrong is avdtp_unregister_sep is not aborting existing
streams properly. Btw we should probably add a unit test if this is
happening in practice because otherwise the remote won't notice.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH 5/6] android/a2dp: Disconnect headset on IPC failure
From: Luiz Augusto von Dentz @ 2014-02-07 9:58 UTC (permalink / raw)
To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CABBYNZKZGX54FnUPEZWM_4A+5otRHk+wyA-xhppfD8FeZckMjg@mail.gmail.com>
Hi Andrzej,
On Fri, Feb 7, 2014 at 11:45 AM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Hi Andrzej,
>
> On Thu, Feb 6, 2014 at 7:54 PM, Andrzej Kaczmarek
> <andrzej.kaczmarek@tieto.com> wrote:
>> In case audio IPC is suddenly disconnected (most likely due to crash of
>> mediaserver process) we should disconnect headset since it is no longer
>> associated with valid setup and cannot be used properly.
>> ---
>> android/a2dp.c | 7 +++++++
>> 1 file changed, 7 insertions(+)
>>
>> diff --git a/android/a2dp.c b/android/a2dp.c
>> index 8eabfeb..f67a593 100644
>> --- a/android/a2dp.c
>> +++ b/android/a2dp.c
>> @@ -1515,6 +1515,7 @@ static gboolean audio_retry_register(void *data)
>>
>> static void audio_disconnected(void *data)
>> {
>> + GSList *l;
>> bool restart;
>>
>> DBG("");
>> @@ -1526,6 +1527,12 @@ static void audio_disconnected(void *data)
>>
>> bt_audio_unregister();
>>
>> + for (l = devices; l; l = g_slist_next(l)) {
>> + struct a2dp_device *dev = l->data;
>> +
>> + avdtp_shutdown(dev->session);
>> + }
>> +
>> if (!restart)
>> return;
>
> If we are unregistering the endpoints properly this should not happen,
> perhaps what is wrong is avdtp_unregister_sep is not aborting existing
> streams properly. Btw we should probably add a unit test if this is
> happening in practice because otherwise the remote won't notice.
I checked the code and actually this should not be a problem since we
drop the stream transport connection it should indicate a unclean
abort as it should be, in the past we had many times this happening
with PA crashing and it seems the headsets react properly to the
stream transport dropping unexpectedly, we can still do abort though.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCHv2 1/2] android/haltest: Close file in case of error
From: Szymon Janc @ 2014-02-07 10:05 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1391696563-7478-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Thursday 06 of February 2014 16:22:42 Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> ---
> android/client/if-audio.c | 13 ++++++++++---
> 1 file changed, 10 insertions(+), 3 deletions(-)
>
> diff --git a/android/client/if-audio.c b/android/client/if-audio.c
> index 66f8364..3b34c95 100644
> --- a/android/client/if-audio.c
> +++ b/android/client/if-audio.c
> @@ -258,19 +258,26 @@ static void play_p(int argc, const char **argv)
>
> if (buffer_size == 0) {
> haltest_error("Invalid buffer size. Was stream_out opened?\n");
> - return;
> + goto fail;
> }
>
> pthread_mutex_lock(&state_mutex);
> if (current_state != STATE_STOPPED) {
> haltest_error("Already playing or stream suspended!\n");
> pthread_mutex_unlock(&state_mutex);
> - return;
> + goto fail;
> }
> pthread_mutex_unlock(&state_mutex);
>
> - if (pthread_create(&play_thread, NULL, playback_thread, in) != 0)
> + if (pthread_create(&play_thread, NULL, playback_thread, in) != 0) {
> haltest_error("Cannot create playback thread!\n");
> + goto fail;
> + }
> +
> + return;
> +fail:
> + if (in)
> + fclose(in);
> }
>
> static void stop_p(int argc, const char **argv)
>
This patch is now upstream, thanks.
--
Best regards,
Szymon Janc
^ permalink raw reply
* [RFC 0/2] Add hci_smd driver
From: Lukasz Rymanowski @ 2014-02-07 11:35 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
Hello,
This is a try (long shoot) to upstream hci shared memory driver (hci_smd)
which is used on Qualcomm platforms and BT chips.
To make it build with upstream tree I had to introduce some simple SMD API.
The idea here is that since SMD channel is represented by platform device
(as it is done in mach-msm),
then platfrom_data contains smd_data which contains API for that channel.
Writing this SMD API I was inspired with MSM-SMD and since I'm not an expert
in this area I'm asking for comments here.
Maybe instead of SMD API I made, I should expose functions like smd_open(), smd_write()
etc. something similar how sdio does, and just deliver to upstream dummy device
implementing this SMD API?
Other options I was considering is to implement module inside mach-msm which
would handle registering SMD BT Channels and when it is done, it would register
new platform device like "smd-bt". Then I could move smd.h to some bluetooth includes
(althought don't now where at the moment) and hci_smd would register driver for "smd-bt"
In this case I would also could rid of one static variable I have now in hci_smd
Comments on those options are welcome.
Anyway, Hci_smd is based on one of the older version of this driver found in msm kernel
branch, so there are no wakelocks as in new version and also workqueues are used
instead of takslet.
Since SMD expose two channels, one for CMD/EVENT and one for ACL Data I decide to
do separate worqueues for this. This is to make sure that ACL data never blocks EVENT
packages
Lukasz Rymanowski (2):
Add basic API for shared memory driver
bluetooth: Add initial support for BT chip over SMD
drivers/bluetooth/Kconfig | 9 +
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/hci_smd.c | 461 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/smd.h | 68 +++++++
include/net/bluetooth/hci.h | 1 +
5 files changed, 540 insertions(+)
create mode 100644 drivers/bluetooth/hci_smd.c
create mode 100644 include/linux/smd.h
--
1.8.4
^ permalink raw reply
* [RFC 1/2] Add basic API for shared memory driver
From: Lukasz Rymanowski @ 2014-02-07 11:35 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1391772937-12802-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds simple API to shared memory driver based on msm-smd.h
This is required in order to add support for support Qualcomm BT chips
via SMD
Signed-off-by: Lukasz Rymanowski <lukasz.rymanowski@tieto.com>
---
include/linux/smd.h | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
create mode 100644 include/linux/smd.h
diff --git a/include/linux/smd.h b/include/linux/smd.h
new file mode 100644
index 0000000..58de0d4
--- /dev/null
+++ b/include/linux/smd.h
@@ -0,0 +1,69 @@
+/*
+* smd.h - API for Shared Memory Driver
+*
+* Copyright (c) 2014 Intel Corporation
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*/
+
+#ifndef _SMD_H_
+#define _SMD_H_
+
+#include <linux/platform_device.h>
+
+/**
+* Events from smd device.
+*/
+#define SMD_EVENT_DATA 1
+#define SMD_EVENT_OPEN 2
+#define SMD_EVENT_CLOSE 3
+
+struct smd_channel;
+struct smd_notify_data;
+struct smd_data;
+
+/**
+* struct smd_ops - specific operation for smd channel
+*
+* @open: Open SMD channel. It should return zero once device is opened.
+* On open there is need to pass notification cb which is used
+* for notifications form SMD device.
+* @close Close SMD channel
+* @write: Write data to SMD channel. It should return number of written
+* bytes or negative value in case of error.
+* @read: Read data from SMD channel.It should return number of written
+* bytes or negative value in case of error.
+*@read_avail: Returns number of bytes ready to be read. This should be called
+* before read in order to allocate enought skb
+*
+*/
+struct smd_ops {
+ int (*open)(struct smd_data *s,
+ void (*notify)(struct platform_device *pdev,
+ unsigned int event));
+ int (*close)(struct smd_data *s);
+ int (*write)(struct smd_data *s, const void *data, int len);
+ int (*read)(struct smd_data *s, void *buf, int len);
+ int (*read_avail)(struct smd_data *s);
+};
+/**
+* struct smd_data - smd device data for shared memory channel
+*
+* @pdev: Platform device for given smd channel.
+* @ops: SMD specific operations for this smd channel.
+* @ch: SMD channel which is used by SMD device. Should not be
+* used by the driver
+* @notifier: SMD notifier data. Shall not be used by driver.
+*
+* smd_data are initialized by the platform and are available for driver
+* in platform_data.
+*/
+struct smd_data {
+ struct platform_device *pdev;
+ struct smd_ops ops;
+ struct smd_channel *ch;
+ struct smd_notify_data *notify_data;
+};
+#endif
--
1.8.4
^ 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