Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 4/8]  android: Add initial skeleton for AVRCP in the HAL
From: Luiz Augusto von Dentz @ 2014-01-23 16:39 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390495198-28400-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/Android.mk      |  1 +
 android/Makefile.am     |  1 +
 android/hal-avrcp.c     | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
 android/hal-bluetooth.c |  3 ++
 android/hal.h           |  2 ++
 5 files changed, 94 insertions(+)
 create mode 100644 android/hal-avrcp.c

diff --git a/android/Android.mk b/android/Android.mk
index 45ceeb2..1e1b60c 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -96,6 +96,7 @@ LOCAL_SRC_FILES := \
 	bluez/android/hal-hidhost.c \
 	bluez/android/hal-pan.c \
 	bluez/android/hal-a2dp.c \
+	bluez/android/hal-avrcp.c \
 	bluez/android/hal-utils.c \
 
 LOCAL_C_INCLUDES += \
diff --git a/android/Makefile.am b/android/Makefile.am
index 47e7551..9e96d55 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -50,6 +50,7 @@ android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \
 					android/hal-hidhost.c \
 					android/hal-pan.c \
 					android/hal-a2dp.c \
+					android/hal-avrcp.c \
 					android/hardware/bluetooth.h \
 					android/hardware/bt_av.h \
 					android/hardware/bt_gatt.h \
diff --git a/android/hal-avrcp.c b/android/hal-avrcp.c
new file mode 100644
index 0000000..01d233b
--- /dev/null
+++ b/android/hal-avrcp.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "hal-log.h"
+#include "hal.h"
+#include "hal-msg.h"
+#include "hal-ipc.h"
+
+static const btrc_callbacks_t *cbs = NULL;
+
+static bool interface_ready(void)
+{
+	return cbs != NULL;
+}
+
+static bt_status_t init(btrc_callbacks_t *callbacks)
+{
+	struct hal_cmd_register_module cmd;
+	int ret;
+
+	DBG("");
+
+	if (interface_ready())
+		return BT_STATUS_DONE;
+
+	cbs = callbacks;
+
+	cmd.service_id = HAL_SERVICE_ID_AVRCP;
+
+	ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+					sizeof(cmd), &cmd, 0, NULL, NULL);
+
+	if (ret != BT_STATUS_SUCCESS) {
+		cbs = NULL;
+		hal_ipc_unregister(HAL_SERVICE_ID_AVRCP);
+	}
+
+	return ret;
+}
+
+static void cleanup()
+{
+	struct hal_cmd_unregister_module cmd;
+
+	DBG("");
+
+	if (!interface_ready())
+		return;
+
+	cbs = NULL;
+
+	cmd.service_id = HAL_SERVICE_ID_AVRCP;
+
+	hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+					sizeof(cmd), &cmd, 0, NULL, NULL);
+
+	hal_ipc_unregister(HAL_SERVICE_ID_AVRCP);
+}
+
+static btrc_interface_t iface = {
+	.size = sizeof(iface),
+	.init = init,
+	.cleanup = cleanup
+};
+
+btrc_interface_t *bt_get_avrcp_interface()
+{
+	return &iface;
+}
diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c
index 4f0e7b7..0dac158 100644
--- a/android/hal-bluetooth.c
+++ b/android/hal-bluetooth.c
@@ -762,6 +762,9 @@ static const void *get_profile_interface(const char *profile_id)
 	if (!strcmp(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
 		return bt_get_a2dp_interface();
 
+	if (!strcmp(profile_id, BT_PROFILE_AV_RC_ID))
+		return bt_get_avrcp_interface();
+
 	return NULL;
 }
 
diff --git a/android/hal.h b/android/hal.h
index b475411..1ff4fbd 100644
--- a/android/hal.h
+++ b/android/hal.h
@@ -20,11 +20,13 @@
 #include <hardware/bt_hh.h>
 #include <hardware/bt_pan.h>
 #include <hardware/bt_av.h>
+#include <hardware/bt_rc.h>
 
 btsock_interface_t *bt_get_sock_interface(void);
 bthh_interface_t *bt_get_hidhost_interface(void);
 btpan_interface_t *bt_get_pan_interface(void);
 btav_interface_t *bt_get_a2dp_interface(void);
+btrc_interface_t *bt_get_avrcp_interface(void);
 
 void bt_thread_associate(void);
 void bt_thread_disassociate(void);
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 3/8] android: Add initial skeleton for AVRCP in the daemon
From: Luiz Augusto von Dentz @ 2014-01-23 16:39 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390495198-28400-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 android/Android.mk                          |  1 +
 android/Makefile.am                         |  1 +
 plugins/external-dummy.c => android/avrcp.c | 32 ++++++++++++++++++++++-------
 android/{hidhost.h => avrcp.h}              |  6 +++---
 android/main.c                              | 11 ++++++++++
 5 files changed, 41 insertions(+), 10 deletions(-)
 copy plugins/external-dummy.c => android/avrcp.c (62%)
 copy android/{hidhost.h => avrcp.h} (84%)

diff --git a/android/Android.mk b/android/Android.mk
index b43119e..45ceeb2 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -29,6 +29,7 @@ LOCAL_SRC_FILES := \
 	bluez/android/avdtp.c \
 	bluez/android/a2dp.c \
 	bluez/android/avctp.c \
+	bluez/android/avrcp.c \
 	bluez/android/pan.c \
 	bluez/src/log.c \
 	bluez/src/shared/mgmt.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 41694ee..47e7551 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -34,6 +34,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.h android/avrcp.c \
 				android/socket.h android/socket.c \
 				android/pan.h android/pan.c \
 				btio/btio.h btio/btio.c \
diff --git a/plugins/external-dummy.c b/android/avrcp.c
similarity index 62%
copy from plugins/external-dummy.c
copy to android/avrcp.c
index ff31290..707506b 100644
--- a/plugins/external-dummy.c
+++ b/android/avrcp.c
@@ -2,6 +2,9 @@
  *
  *  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
@@ -22,20 +25,35 @@
 #include <config.h>
 #endif
 
-#include "plugin.h"
+#include <stdbool.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
 #include "log.h"
+#include "avrcp.h"
+#include "hal-msg.h"
+#include "ipc.h"
+
+static bdaddr_t adapter_addr;
+
+static const struct ipc_handler cmd_handlers[] = {
+};
 
-static int dummy_init(void)
+bool bt_avrcp_register(const bdaddr_t *addr)
 {
 	DBG("");
 
-	return 0;
+	bacpy(&adapter_addr, addr);
+
+	ipc_register(HAL_SERVICE_ID_AVRCP, cmd_handlers,
+						G_N_ELEMENTS(cmd_handlers));
+
+	return true;
 }
 
-static void dummy_exit(void)
+void bt_avrcp_unregister(void)
 {
 	DBG("");
-}
 
-BLUETOOTH_PLUGIN_DEFINE(external_dummy, VERSION,
-		BLUETOOTH_PLUGIN_PRIORITY_LOW, dummy_init, dummy_exit)
+	ipc_unregister(HAL_SERVICE_ID_AVRCP);
+}
diff --git a/android/hidhost.h b/android/avrcp.h
similarity index 84%
copy from android/hidhost.h
copy to android/avrcp.h
index ea14446..6fe7fbf 100644
--- a/android/hidhost.h
+++ b/android/avrcp.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2014  Intel Corporation. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -21,5 +21,5 @@
  *
  */
 
-bool bt_hid_register(const bdaddr_t *addr);
-void bt_hid_unregister(void);
+bool bt_avrcp_register(const bdaddr_t *addr);
+void bt_avrcp_unregister(void);
diff --git a/android/main.c b/android/main.c
index 8983a84..c353c4a 100644
--- a/android/main.c
+++ b/android/main.c
@@ -55,6 +55,7 @@
 #include "ipc.h"
 #include "a2dp.h"
 #include "pan.h"
+#include "avrcp.h"
 
 #define STARTUP_GRACE_SECONDS 5
 #define SHUTDOWN_GRACE_SECONDS 10
@@ -107,6 +108,13 @@ static void service_register(const void *buf, uint16_t len)
 		}
 
 		break;
+	case HAL_SERVICE_ID_AVRCP:
+		if (!bt_avrcp_register(&adapter_bdaddr)) {
+			status = HAL_STATUS_FAILED;
+			goto failed;
+		}
+
+		break;
 	default:
 		DBG("service %u not supported", m->service_id);
 		status = HAL_STATUS_FAILED;
@@ -149,6 +157,9 @@ static void service_unregister(const void *buf, uint16_t len)
 	case HAL_SERVICE_ID_PAN:
 		bt_pan_unregister();
 		break;
+	case HAL_SERVICE_ID_AVRCP:
+		bt_avrcp_unregister();
+		break;
 	default:
 		/* This would indicate bug in HAL, as unregister should not be
 		 * called in init failed */
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 2/8] android/AVCTP: Strip dependencies
From: Luiz Augusto von Dentz @ 2014-01-23 16:39 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390495198-28400-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This strips AVCTP code of any dependency of core and btio to make it
transport agnostic.
---
 android/Android.mk  |   1 +
 android/Makefile.am |   1 +
 android/avctp.c     | 793 ++++++++--------------------------------------------
 android/avctp.h     |  40 +--
 4 files changed, 134 insertions(+), 701 deletions(-)

diff --git a/android/Android.mk b/android/Android.mk
index 43e6036..b43119e 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -28,6 +28,7 @@ LOCAL_SRC_FILES := \
 	bluez/android/audio-ipc.c \
 	bluez/android/avdtp.c \
 	bluez/android/a2dp.c \
+	bluez/android/avctp.c \
 	bluez/android/pan.c \
 	bluez/src/log.c \
 	bluez/src/shared/mgmt.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 910beb5..41694ee 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -33,6 +33,7 @@ android_bluetoothd_SOURCES = android/main.c \
 				android/audio-ipc.h android/audio-ipc.c \
 				android/avdtp.h android/avdtp.c \
 				android/a2dp.h android/a2dp.c \
+				android/avctp.h android/avctp.c \
 				android/socket.h android/socket.c \
 				android/pan.h android/pan.c \
 				btio/btio.h btio/btio.c \
diff --git a/android/avctp.c b/android/avctp.c
index 6669ddc..a31dcc6 100644
--- a/android/avctp.c
+++ b/android/avctp.c
@@ -34,27 +34,20 @@
 #include <unistd.h>
 #include <assert.h>
 #include <signal.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <netinet/in.h>
 
-#include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
-#include <bluetooth/l2cap.h>
 
 #include <glib.h>
-#include <btio/btio.h>
-
-#include "lib/uuid.h"
-#include "src/adapter.h"
-#include "src/device.h"
 
 #include "log.h"
 #include "error.h"
 #include "uinput.h"
 #include "avctp.h"
-#include "avrcp.h"
 
 /* AV/C Panel 1.23, page 76:
  * command with the pressed value is valid for two seconds
@@ -115,20 +108,6 @@ struct avc_header {
 #error "Unknown byte order"
 #endif
 
-struct avctp_state_callback {
-	avctp_state_cb cb;
-	struct btd_device *dev;
-	unsigned int id;
-	void *user_data;
-};
-
-struct avctp_server {
-	struct btd_adapter *adapter;
-	GIOChannel *control_io;
-	GIOChannel *browsing_io;
-	GSList *sessions;
-};
-
 struct avctp_control_req {
 	struct avctp_pending_req *p;
 	uint8_t code;
@@ -157,7 +136,7 @@ struct avctp_pending_req {
 	int err;
 	avctp_process_cb process;
 	void *data;
-	GDestroyNotify destroy;
+	avctp_destroy_cb_t destroy;
 };
 
 struct avctp_channel {
@@ -173,7 +152,7 @@ struct avctp_channel {
 	GQueue *queue;
 	GSList *processed;
 	guint process_id;
-	GDestroyNotify destroy;
+	avctp_destroy_cb_t destroy;
 };
 
 struct key_pressed {
@@ -182,14 +161,8 @@ struct key_pressed {
 };
 
 struct avctp {
-	struct avctp_server *server;
-	struct btd_device *device;
-
-	avctp_state_t state;
-
 	int uinput;
 
-	guint auth_id;
 	unsigned int passthrough_id;
 	unsigned int unit_id;
 	unsigned int subunit_id;
@@ -201,7 +174,7 @@ struct avctp {
 
 	uint8_t key_quirks[256];
 	struct key_pressed key;
-	bool initiator;
+	uint16_t version;
 };
 
 struct avctp_passthrough_handler {
@@ -221,7 +194,7 @@ struct avctp_browsing_pdu_handler {
 	avctp_browsing_pdu_cb cb;
 	void *user_data;
 	unsigned int id;
-	GDestroyNotify destroy;
+	avctp_destroy_cb_t destroy;
 };
 
 static struct {
@@ -259,10 +232,6 @@ static struct {
 	{ NULL }
 };
 
-static GSList *callbacks = NULL;
-static GSList *servers = NULL;
-
-static void auth_cb(DBusError *derr, void *user_data);
 static gboolean process_queue(gpointer user_data);
 static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
 					uint8_t subunit, uint8_t *operands,
@@ -488,83 +457,6 @@ static void avctp_channel_destroy(struct avctp_channel *chan)
 	g_free(chan);
 }
 
-static void avctp_disconnected(struct avctp *session)
-{
-	struct avctp_server *server;
-
-	if (!session)
-		return;
-
-	if (session->browsing)
-		avctp_channel_destroy(session->browsing);
-
-	if (session->control)
-		avctp_channel_destroy(session->control);
-
-	if (session->auth_id != 0) {
-		btd_cancel_authorization(session->auth_id);
-		session->auth_id = 0;
-	}
-
-	if (session->key.timer > 0)
-		g_source_remove(session->key.timer);
-
-	if (session->uinput >= 0) {
-		char address[18];
-
-		ba2str(device_get_address(session->device), address);
-		DBG("AVCTP: closing uinput for %s", address);
-
-		ioctl(session->uinput, UI_DEV_DESTROY);
-		close(session->uinput);
-		session->uinput = -1;
-	}
-
-	server = session->server;
-	server->sessions = g_slist_remove(server->sessions, session);
-	btd_device_unref(session->device);
-	g_free(session);
-}
-
-static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
-{
-	GSList *l;
-	avctp_state_t old_state = session->state;
-
-	session->state = new_state;
-
-	for (l = callbacks; l != NULL; l = l->next) {
-		struct avctp_state_callback *cb = l->data;
-
-		if (cb->dev && cb->dev != session->device)
-			continue;
-
-		cb->cb(session->device, old_state, new_state, cb->user_data);
-	}
-
-	switch (new_state) {
-	case AVCTP_STATE_DISCONNECTED:
-		DBG("AVCTP Disconnected");
-		avctp_disconnected(session);
-		break;
-	case AVCTP_STATE_CONNECTING:
-		DBG("AVCTP Connecting");
-		break;
-	case AVCTP_STATE_CONNECTED:
-		DBG("AVCTP Connected");
-		break;
-	case AVCTP_STATE_BROWSING_CONNECTING:
-		DBG("AVCTP Browsing Connecting");
-		break;
-	case AVCTP_STATE_BROWSING_CONNECTED:
-		DBG("AVCTP Browsing Connected");
-		break;
-	default:
-		error("Invalid AVCTP state %d", new_state);
-		return;
-	}
-}
-
 static int avctp_send(struct avctp_channel *control, uint8_t transaction,
 				uint8_t cr, uint8_t code,
 				uint8_t subunit, uint8_t opcode,
@@ -874,7 +766,8 @@ static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
 	handler = g_slist_nth_data(browsing->handlers, 0);
 	if (handler == NULL) {
 		DBG("handler not found");
-		packet_size += avrcp_browsing_general_reject(operands);
+		/* FIXME: Add general reject */
+		/* packet_size += avrcp_browsing_general_reject(operands); */
 		goto send;
 	}
 
@@ -893,7 +786,6 @@ send:
 
 failed:
 	DBG("AVCTP Browsing: disconnected");
-	avctp_set_state(session, AVCTP_STATE_CONNECTED);
 
 	if (session->browsing) {
 		avctp_channel_destroy(session->browsing);
@@ -966,7 +858,9 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
 	handler = find_handler(control->handlers, avc->opcode);
 	if (!handler) {
 		DBG("handler not found for 0x%02x", avc->opcode);
-		packet_size += avrcp_handle_vendor_reject(&code, operands);
+		/* FIXME:
+		 * packet_size += avrcp_handle_vendor_reject(&code, operands);
+		 */
 		avc->code = code;
 		goto done;
 	}
@@ -990,11 +884,11 @@ done:
 
 failed:
 	DBG("AVCTP session %p got disconnected", session);
-	avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+	avctp_shutdown(session);
 	return FALSE;
 }
 
-static int uinput_create(char *name)
+static int uinput_create(const char *name)
 {
 	struct uinput_dev dev;
 	int fd, err, i;
@@ -1049,11 +943,9 @@ static int uinput_create(char *name)
 	return fd;
 }
 
-static void init_uinput(struct avctp *session)
+int avctp_init_uinput(struct avctp *session, const char *name,
+							const char *address)
 {
-	char address[18], name[248 + 1];
-
-	device_get_name(session->device, name, sizeof(name));
 	if (g_str_equal(name, "Nokia CK-20W")) {
 		session->key_quirks[AVC_FORWARD] |= QUIRK_NO_RELEASE;
 		session->key_quirks[AVC_BACKWARD] |= QUIRK_NO_RELEASE;
@@ -1061,24 +953,28 @@ static void init_uinput(struct avctp *session)
 		session->key_quirks[AVC_PAUSE] |= QUIRK_NO_RELEASE;
 	}
 
-	ba2str(device_get_address(session->device), address);
 	session->uinput = uinput_create(address);
-	if (session->uinput < 0)
-		error("AVRCP: failed to init uinput for %s", address);
-	else
-		DBG("AVRCP: uinput initialized for %s", address);
+	if (session->uinput < 0) {
+		error("AVCTP: failed to init uinput for %s", address);
+		return session->uinput;
+	}
+
+	return 0;
 }
 
-static struct avctp_channel *avctp_channel_create(struct avctp *session,
-							GIOChannel *io,
-							GDestroyNotify destroy)
+static struct avctp_channel *avctp_channel_create(struct avctp *session, int fd,
+						size_t imtu, size_t omtu,
+						avctp_destroy_cb_t destroy)
 {
 	struct avctp_channel *chan;
 
 	chan = g_new0(struct avctp_channel, 1);
 	chan->session = session;
-	chan->io = g_io_channel_ref(io);
+	chan->io = g_io_channel_unix_new(fd);
 	chan->queue = g_queue_new();
+	chan->imtu = imtu;
+	chan->omtu = omtu;
+	chan->buffer = g_malloc0(MAX(imtu, omtu));
 	chan->destroy = destroy;
 
 	return chan;
@@ -1103,381 +999,10 @@ static void avctp_destroy_browsing(void *data)
 	chan->handlers = NULL;
 }
 
-static void avctp_connect_browsing_cb(GIOChannel *chan, GError *err,
-							gpointer data)
-{
-	struct avctp *session = data;
-	struct avctp_channel *browsing = session->browsing;
-	char address[18];
-	uint16_t imtu, omtu;
-	GError *gerr = NULL;
-
-	if (err) {
-		error("Browsing: %s", err->message);
-		goto fail;
-	}
-
-	bt_io_get(chan, &gerr,
-			BT_IO_OPT_DEST, &address,
-			BT_IO_OPT_IMTU, &imtu,
-			BT_IO_OPT_OMTU, &omtu,
-			BT_IO_OPT_INVALID);
-	if (gerr) {
-		error("%s", gerr->message);
-		g_io_channel_shutdown(chan, TRUE, NULL);
-		g_io_channel_unref(chan);
-		g_error_free(gerr);
-		goto fail;
-	}
-
-	DBG("AVCTP Browsing: connected to %s", address);
-
-	if (browsing == NULL) {
-		browsing = avctp_channel_create(session, chan,
-						avctp_destroy_browsing);
-		session->browsing = browsing;
-	}
-
-	browsing->imtu = imtu;
-	browsing->omtu = omtu;
-	browsing->buffer = g_malloc0(MAX(imtu, omtu));
-	browsing->watch = g_io_add_watch(session->browsing->io,
-				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-				(GIOFunc) session_browsing_cb, session);
-
-	avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTED);
-
-	/* Process any request that was pending the connection to complete */
-	if (browsing->process_id == 0 && !g_queue_is_empty(browsing->queue))
-		browsing->process_id = g_idle_add(process_queue, browsing);
-
-	return;
-
-fail:
-	avctp_set_state(session, AVCTP_STATE_CONNECTED);
-
-	if (session->browsing) {
-		avctp_channel_destroy(session->browsing);
-		session->browsing = NULL;
-	}
-}
-
-static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
-{
-	struct avctp *session = data;
-	char address[18];
-	uint16_t imtu, omtu;
-	GError *gerr = NULL;
-
-	if (err) {
-		avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-		error("%s", err->message);
-		return;
-	}
-
-	bt_io_get(chan, &gerr,
-			BT_IO_OPT_DEST, &address,
-			BT_IO_OPT_IMTU, &imtu,
-			BT_IO_OPT_IMTU, &omtu,
-			BT_IO_OPT_INVALID);
-	if (gerr) {
-		avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-		error("%s", gerr->message);
-		g_error_free(gerr);
-		return;
-	}
-
-	DBG("AVCTP: connected to %s", address);
-
-	if (session->control == NULL)
-		session->control = avctp_channel_create(session, chan, NULL);
-
-	session->control->imtu = imtu;
-	session->control->omtu = omtu;
-	session->control->buffer = g_malloc0(MAX(imtu, omtu));
-	session->control->watch = g_io_add_watch(session->control->io,
-				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-				(GIOFunc) session_cb, session);
-
-	session->passthrough_id = avctp_register_pdu_handler(session,
-						AVC_OP_PASSTHROUGH,
-						handle_panel_passthrough,
-						NULL);
-	session->unit_id = avctp_register_pdu_handler(session,
-						AVC_OP_UNITINFO,
-						handle_unit_info,
-						NULL);
-	session->subunit_id = avctp_register_pdu_handler(session,
-						AVC_OP_SUBUNITINFO,
-						handle_subunit_info,
-						NULL);
-
-	init_uinput(session);
-
-	avctp_set_state(session, AVCTP_STATE_CONNECTED);
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
-	struct avctp *session = user_data;
-	GError *err = NULL;
-
-	session->auth_id = 0;
-
-	if (session->control->watch > 0) {
-		g_source_remove(session->control->watch);
-		session->control->watch = 0;
-	}
-
-	if (derr && dbus_error_is_set(derr)) {
-		error("Access denied: %s", derr->message);
-		avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-		return;
-	}
-
-	if (!bt_io_accept(session->control->io, avctp_connect_cb, session,
-								NULL, &err)) {
-		error("bt_io_accept: %s", err->message);
-		g_error_free(err);
-		avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-	}
-}
-
-static struct avctp_server *find_server(GSList *list, struct btd_adapter *a)
-{
-	for (; list; list = list->next) {
-		struct avctp_server *server = list->data;
-
-		if (server->adapter == a)
-			return server;
-	}
-
-	return NULL;
-}
-
-static struct avctp *find_session(GSList *list, struct btd_device *device)
-{
-	for (; list != NULL; list = g_slist_next(list)) {
-		struct avctp *s = list->data;
-
-		if (s->device == device)
-			return s;
-	}
-
-	return NULL;
-}
-
-static struct avctp *avctp_get_internal(struct btd_device *device)
-{
-	struct avctp_server *server;
-	struct avctp *session;
-
-	server = find_server(servers, device_get_adapter(device));
-	if (server == NULL)
-		return NULL;
-
-	session = find_session(server->sessions, device);
-	if (session)
-		return session;
-
-	session = g_new0(struct avctp, 1);
-
-	session->server = server;
-	session->device = btd_device_ref(device);
-	session->state = AVCTP_STATE_DISCONNECTED;
-	session->uinput = -1;
-
-	server->sessions = g_slist_append(server->sessions, session);
-
-	return session;
-}
-
-static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
-						struct btd_device *dev)
-{
-	const bdaddr_t *src;
-	const bdaddr_t *dst;
-
-	if (session->control != NULL) {
-		error("Control: Refusing unexpected connect");
-		g_io_channel_shutdown(chan, TRUE, NULL);
-		return;
-	}
-
-	avctp_set_state(session, AVCTP_STATE_CONNECTING);
-	session->control = avctp_channel_create(session, chan, NULL);
-
-	src = btd_adapter_get_address(device_get_adapter(dev));
-	dst = device_get_address(dev);
-
-	session->auth_id = btd_request_authorization(src, dst,
-							AVRCP_REMOTE_UUID,
-							auth_cb, session);
-	if (session->auth_id == 0)
-		goto drop;
-
-	session->control->watch = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
-						G_IO_NVAL, session_cb, session);
-	return;
-
-drop:
-	avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-}
-
-static void avctp_browsing_confirm(struct avctp *session, GIOChannel *chan,
-						struct btd_device *dev)
-{
-	GError *err = NULL;
-
-	if (session->control == NULL || session->browsing != NULL) {
-		error("Browsing: Refusing unexpected connect");
-		g_io_channel_shutdown(chan, TRUE, NULL);
-		return;
-	}
-
-	if (bt_io_accept(chan, avctp_connect_browsing_cb, session, NULL,
-								&err)) {
-		avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING);
-		return;
-	}
-
-	error("Browsing: %s", err->message);
-	g_error_free(err);
-
-	return;
-}
-
-static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
-{
-	struct avctp *session;
-	char address[18];
-	bdaddr_t src, dst;
-	GError *err = NULL;
-	uint16_t psm;
-	struct btd_device *device;
-
-	bt_io_get(chan, &err,
-			BT_IO_OPT_SOURCE_BDADDR, &src,
-			BT_IO_OPT_DEST_BDADDR, &dst,
-			BT_IO_OPT_DEST, address,
-			BT_IO_OPT_PSM, &psm,
-			BT_IO_OPT_INVALID);
-	if (err) {
-		error("%s", err->message);
-		g_error_free(err);
-		g_io_channel_shutdown(chan, TRUE, NULL);
-		return;
-	}
-
-	DBG("AVCTP: incoming connect from %s", address);
-
-	device = btd_adapter_find_device(adapter_find(&src), &dst);
-	if (!device)
-		return;
-
-	session = avctp_get_internal(device);
-	if (session == NULL)
-		return;
-
-	if (btd_device_get_service(device, AVRCP_REMOTE_UUID) == NULL)
-		btd_device_add_uuid(device, AVRCP_REMOTE_UUID);
-
-	if (btd_device_get_service(device, AVRCP_TARGET_UUID) == NULL)
-		btd_device_add_uuid(device, AVRCP_TARGET_UUID);
-
-	switch (psm) {
-	case AVCTP_CONTROL_PSM:
-		avctp_control_confirm(session, chan, device);
-		break;
-	case AVCTP_BROWSING_PSM:
-		avctp_browsing_confirm(session, chan, device);
-		break;
-	}
-
-	return;
-}
-
-static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master,
-						uint8_t mode, uint16_t psm)
-{
-	GError *err = NULL;
-	GIOChannel *io;
-
-	io = bt_io_listen(NULL, avctp_confirm_cb, NULL,
-				NULL, &err,
-				BT_IO_OPT_SOURCE_BDADDR, src,
-				BT_IO_OPT_PSM, psm,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_MASTER, master,
-				BT_IO_OPT_MODE, mode,
-				BT_IO_OPT_INVALID);
-	if (!io) {
-		error("%s", err->message);
-		g_error_free(err);
-	}
-
-	return io;
-}
-
-int avctp_register(struct btd_adapter *adapter, gboolean master)
-{
-	struct avctp_server *server;
-	const bdaddr_t *src = btd_adapter_get_address(adapter);
-
-	server = g_new0(struct avctp_server, 1);
-
-	server->control_io = avctp_server_socket(src, master, L2CAP_MODE_BASIC,
-							AVCTP_CONTROL_PSM);
-	if (!server->control_io) {
-		g_free(server);
-		return -1;
-	}
-	server->browsing_io = avctp_server_socket(src, master, L2CAP_MODE_ERTM,
-							AVCTP_BROWSING_PSM);
-	if (!server->browsing_io) {
-		if (server->control_io) {
-			g_io_channel_shutdown(server->control_io, TRUE, NULL);
-			g_io_channel_unref(server->control_io);
-			server->control_io = NULL;
-		}
-		g_free(server);
-		return -1;
-	}
-
-	server->adapter = btd_adapter_ref(adapter);
-
-	servers = g_slist_append(servers, server);
-
-	return 0;
-}
-
-void avctp_unregister(struct btd_adapter *adapter)
-{
-	struct avctp_server *server;
-
-	server = find_server(servers, adapter);
-	if (!server)
-		return;
-
-	while (server->sessions)
-		avctp_disconnected(server->sessions->data);
-
-	servers = g_slist_remove(servers, server);
-
-	g_io_channel_shutdown(server->browsing_io, TRUE, NULL);
-	g_io_channel_unref(server->browsing_io);
-	server->browsing_io = NULL;
-
-	g_io_channel_shutdown(server->control_io, TRUE, NULL);
-	g_io_channel_unref(server->control_io);
-	btd_adapter_unref(server->adapter);
-	g_free(server);
-}
-
 static struct avctp_pending_req *pending_create(struct avctp_channel *chan,
 						avctp_process_cb process,
 						void *data,
-						GDestroyNotify destroy)
+						avctp_destroy_cb_t destroy)
 {
 	struct avctp_pending_req *p;
 	GSList *l, *tmp;
@@ -1732,39 +1257,6 @@ int avctp_send_vendordep_req(struct avctp *session, uint8_t code,
 						func, user_data);
 }
 
-unsigned int avctp_add_state_cb(struct btd_device *dev, avctp_state_cb cb,
-							void *user_data)
-{
-	struct avctp_state_callback *state_cb;
-	static unsigned int id = 0;
-
-	state_cb = g_new(struct avctp_state_callback, 1);
-	state_cb->cb = cb;
-	state_cb->dev = dev;
-	state_cb->id = ++id;
-	state_cb->user_data = user_data;
-
-	callbacks = g_slist_append(callbacks, state_cb);
-
-	return state_cb->id;
-}
-
-gboolean avctp_remove_state_cb(unsigned int id)
-{
-	GSList *l;
-
-	for (l = callbacks; l != NULL; l = l->next) {
-		struct avctp_state_callback *cb = l->data;
-		if (cb && cb->id == id) {
-			callbacks = g_slist_remove(callbacks, cb);
-			g_free(cb);
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
 unsigned int avctp_register_passthrough_handler(struct avctp *session,
 						avctp_passthrough_cb cb,
 						void *user_data)
@@ -1786,29 +1278,18 @@ unsigned int avctp_register_passthrough_handler(struct avctp *session,
 	return handler->id;
 }
 
-bool avctp_unregister_passthrough_handler(unsigned int id)
+bool avctp_unregister_passthrough_handler(struct avctp *session,
+							unsigned int id)
 {
-	GSList *l;
-
-	for (l = servers; l; l = l->next) {
-		struct avctp_server *server = l->data;
-		GSList *s;
+	if (session->handler == NULL)
+		return false;
 
-		for (s = server->sessions; s; s = s->next) {
-			struct avctp *session = s->data;
-
-			if (session->handler == NULL)
-				continue;
-
-			if (session->handler->id == id) {
-				g_free(session->handler);
-				session->handler = NULL;
-				return true;
-			}
-		}
-	}
+	if (session->handler->id != id)
+		return false;
 
-	return false;
+	g_free(session->handler);
+	session->handler = NULL;
+	return true;
 }
 
 unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
@@ -1840,7 +1321,7 @@ unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
 unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
 						avctp_browsing_pdu_cb cb,
 						void *user_data,
-						GDestroyNotify destroy)
+						avctp_destroy_cb_t destroy)
 {
 	struct avctp_channel *browsing = session->browsing;
 	struct avctp_browsing_pdu_handler *handler;
@@ -1863,165 +1344,129 @@ unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
 	return handler->id;
 }
 
-gboolean avctp_unregister_pdu_handler(unsigned int id)
+bool avctp_unregister_pdu_handler(struct avctp *session, unsigned int id)
 {
+	struct avctp_channel *control = session->control;
 	GSList *l;
 
-	for (l = servers; l; l = l->next) {
-		struct avctp_server *server = l->data;
-		GSList *s;
-
-		for (s = server->sessions; s; s = s->next) {
-			struct avctp *session = s->data;
-			struct avctp_channel *control = session->control;
-			GSList *h;
+	if (!control)
+		return false;
 
-			if (control == NULL)
-				continue;
+	for (l = control->handlers; l; l = g_slist_next(l)) {
+		struct avctp_pdu_handler *handler = l->data;
 
-			for (h = control->handlers; h; h = h->next) {
-				struct avctp_pdu_handler *handler = h->data;
-
-				if (handler->id != id)
-					continue;
+		if (handler->id != id)
+			continue;
 
-				control->handlers = g_slist_remove(
-							control->handlers,
-							handler);
-				g_free(handler);
-				return TRUE;
-			}
-		}
+		control->handlers = g_slist_remove(control->handlers, handler);
+		g_free(handler);
+		return true;
 	}
 
-	return FALSE;
+	return false;
 }
 
-gboolean avctp_unregister_browsing_pdu_handler(unsigned int id)
+bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
+							unsigned int id)
 {
+	struct avctp_channel *browsing = session->browsing;
 	GSList *l;
 
-	for (l = servers; l; l = l->next) {
-		struct avctp_server *server = l->data;
-		GSList *s;
-
-		for (s = server->sessions; s; s = s->next) {
-			struct avctp *session = s->data;
-			struct avctp_channel *browsing = session->browsing;
-			GSList *h;
-
-			if (browsing == NULL)
-				continue;
+	if (browsing == NULL)
+		return false;
 
-			for (h = browsing->handlers; h; h = h->next) {
-				struct avctp_browsing_pdu_handler *handler =
-								h->data;
+	for (l = browsing->handlers; l; l = g_slist_next(l)) {
+		struct avctp_browsing_pdu_handler *handler = l->data;
 
-				if (handler->id != id)
-					continue;
+		if (handler->id != id)
+			continue;
 
-				browsing->handlers = g_slist_remove(
-							browsing->handlers,
-							handler);
-				g_free(handler);
-				return TRUE;
-			}
-		}
+		browsing->handlers = g_slist_remove(browsing->handlers,
+								handler);
+		g_free(handler);
+		return true;
 	}
 
-	return FALSE;
+	return false;
 }
 
-struct avctp *avctp_connect(struct btd_device *device)
+struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
 {
 	struct avctp *session;
-	GError *err = NULL;
-	GIOChannel *io;
-	const bdaddr_t *src;
-
-	session = avctp_get_internal(device);
-	if (!session)
-		return NULL;
-
-	if (session->state > AVCTP_STATE_DISCONNECTED)
-		return session;
-
-	avctp_set_state(session, AVCTP_STATE_CONNECTING);
+	struct avctp_channel *control;
+	GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
 
-	src = btd_adapter_get_address(session->server->adapter);
+	session = g_new0(struct avctp, 1);
+	session->version = version;
 
-	io = bt_io_connect(avctp_connect_cb, session, NULL, &err,
-				BT_IO_OPT_SOURCE_BDADDR, src,
-				BT_IO_OPT_DEST_BDADDR,
-				device_get_address(session->device),
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
-				BT_IO_OPT_INVALID);
-	if (err) {
-		avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-		error("%s", err->message);
-		g_error_free(err);
+	control = avctp_channel_create(session, fd, imtu, omtu, NULL);
+	if (!control) {
+		g_free(session);
 		return NULL;
 	}
 
-	session->control = avctp_channel_create(session, io, NULL);
-	session->initiator = true;
-	g_io_channel_unref(io);
+	session->passthrough_id = avctp_register_pdu_handler(session,
+						AVC_OP_PASSTHROUGH,
+						handle_panel_passthrough,
+						NULL);
+	session->unit_id = avctp_register_pdu_handler(session,
+						AVC_OP_UNITINFO,
+						handle_unit_info,
+						NULL);
+	session->subunit_id = avctp_register_pdu_handler(session,
+						AVC_OP_SUBUNITINFO,
+						handle_subunit_info,
+						NULL);
+
+	session->control = control;
+	control->watch = g_io_add_watch(session->control->io, cond,
+						(GIOFunc) session_cb, session);
 
 	return session;
 }
 
-int avctp_connect_browsing(struct avctp *session)
+int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu,
+								size_t omtu)
 {
-	const bdaddr_t *src;
-	GError *err = NULL;
-	GIOChannel *io;
-
-	if (session->state != AVCTP_STATE_CONNECTED)
-		return -ENOTCONN;
-
-	if (session->browsing != NULL)
-		return 0;
+	struct avctp_channel *browsing;
+	GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
 
-	avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING);
-
-	src = btd_adapter_get_address(session->server->adapter);
-
-	io = bt_io_connect(avctp_connect_browsing_cb, session, NULL, &err,
-				BT_IO_OPT_SOURCE_BDADDR, src,
-				BT_IO_OPT_DEST_BDADDR,
-				device_get_address(session->device),
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_PSM, AVCTP_BROWSING_PSM,
-				BT_IO_OPT_MODE, L2CAP_MODE_ERTM,
-				BT_IO_OPT_INVALID);
-	if (err) {
-		error("%s", err->message);
-		g_error_free(err);
-		return -EIO;
-	}
+	if (session->browsing)
+		return -EISCONN;
 
-	session->browsing = avctp_channel_create(session, io,
+	browsing = avctp_channel_create(session, fd, imtu, omtu,
 						avctp_destroy_browsing);
-	g_io_channel_unref(io);
+	if (!browsing)
+		return -EINVAL;
+
+	session->browsing = browsing;
+	browsing->watch = g_io_add_watch(session->browsing->io, cond,
+					(GIOFunc) session_browsing_cb, session);
 
 	return 0;
 }
 
-void avctp_disconnect(struct avctp *session)
+void avctp_shutdown(struct avctp *session)
 {
-	if (session->state == AVCTP_STATE_DISCONNECTED)
+	if (!session)
 		return;
 
-	avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-}
+	if (session->browsing)
+		avctp_channel_destroy(session->browsing);
 
-struct avctp *avctp_get(struct btd_device *device)
-{
-	return avctp_get_internal(device);
-}
+	if (session->control)
+		avctp_channel_destroy(session->control);
 
-bool avctp_is_initiator(struct avctp *session)
-{
-	return session->initiator;
+	if (session->key.timer > 0)
+		g_source_remove(session->key.timer);
+
+	if (session->uinput >= 0) {
+		DBG("AVCTP: closing uinput");
+
+		ioctl(session->uinput, UI_DEV_DESTROY);
+		close(session->uinput);
+		session->uinput = -1;
+	}
+
+	g_free(session);
 }
diff --git a/android/avctp.h b/android/avctp.h
index f9c665e..99aaf95 100644
--- a/android/avctp.h
+++ b/android/avctp.h
@@ -82,19 +82,6 @@
 
 struct avctp;
 
-typedef enum {
-	AVCTP_STATE_DISCONNECTED = 0,
-	AVCTP_STATE_CONNECTING,
-	AVCTP_STATE_CONNECTED,
-	AVCTP_STATE_BROWSING_CONNECTING,
-	AVCTP_STATE_BROWSING_CONNECTED
-} avctp_state_t;
-
-typedef void (*avctp_state_cb) (struct btd_device *dev,
-				avctp_state_t old_state,
-				avctp_state_t new_state,
-				void *user_data);
-
 typedef bool (*avctp_passthrough_cb) (struct avctp *session,
 					uint8_t op, bool pressed,
 					void *user_data);
@@ -113,34 +100,33 @@ typedef size_t (*avctp_browsing_pdu_cb) (struct avctp *session,
 					uint8_t *operands, size_t operand_count,
 					void *user_data);
 
-unsigned int avctp_add_state_cb(struct btd_device *dev, avctp_state_cb cb,
-							void *user_data);
-gboolean avctp_remove_state_cb(unsigned int id);
+typedef void (*avctp_destroy_cb_t) (void *user_data);
 
-int avctp_register(struct btd_adapter *adapter, gboolean master);
-void avctp_unregister(struct btd_adapter *adapter);
+struct avctp *avctp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
+int avctp_init_uinput(struct avctp *session, const char *name,
+							const char *address);
+int avctp_connect_browsing(struct avctp *session, int fd, size_t imtu,
+								size_t omtu);
 
-struct avctp *avctp_connect(struct btd_device *device);
-struct avctp *avctp_get(struct btd_device *device);
-bool avctp_is_initiator(struct avctp *session);
-int avctp_connect_browsing(struct avctp *session);
-void avctp_disconnect(struct avctp *session);
+void avctp_shutdown(struct avctp *session);
 
 unsigned int avctp_register_passthrough_handler(struct avctp *session,
 						avctp_passthrough_cb cb,
 						void *user_data);
-bool avctp_unregister_passthrough_handler(unsigned int id);
+bool avctp_unregister_passthrough_handler(struct avctp *session,
+							unsigned int id);
 
 unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
 						avctp_control_pdu_cb cb,
 						void *user_data);
-gboolean avctp_unregister_pdu_handler(unsigned int id);
+bool avctp_unregister_pdu_handler(struct avctp *session, unsigned int id);
 
 unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
 						avctp_browsing_pdu_cb cb,
 						void *user_data,
-						GDestroyNotify destroy);
-gboolean avctp_unregister_browsing_pdu_handler(unsigned int id);
+						avctp_destroy_cb_t destroy);
+bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
+							unsigned int id);
 
 int avctp_send_passthrough(struct avctp *session, uint8_t op);
 int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH BlueZ 1/8] android: Add copy of current AVCTP implemention
From: Luiz Augusto von Dentz @ 2014-01-23 16:39 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

These files are not added to any makefile on purpose because they still
have external dependencies.
---
 {profiles/audio => android}/avctp.c | 0
 {profiles/audio => android}/avctp.h | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 copy {profiles/audio => android}/avctp.c (100%)
 copy {profiles/audio => android}/avctp.h (100%)

diff --git a/profiles/audio/avctp.c b/android/avctp.c
similarity index 100%
copy from profiles/audio/avctp.c
copy to android/avctp.c
diff --git a/profiles/audio/avctp.h b/android/avctp.h
similarity index 100%
copy from profiles/audio/avctp.h
copy to android/avctp.h
-- 
1.8.4.2


^ permalink raw reply

* [PATCH] android/audio: Fix for loading audio lib
From: Lukasz Rymanowski @ 2014-01-23 16:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: szymon.janc, Lukasz Rymanowski

Issue visible when haltest loads audio.a2dp.default.so

> HAL E: load:
> module=/home/rymanluk/devel/kitkat/external/bluetooth/bluez/android/.libs/audio.a2dp.default.so
/home/rymanluk/devel/kitkat/external/bluetooth/bluez/android/.libs/audio.a2dp.default.so:
undefined symbol: clock_gettime
hw_get_module_by_class returned -22

---
 android/Makefile.am | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/Makefile.am b/android/Makefile.am
index e9d9db1..f85de20 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -152,7 +152,7 @@ android_audio_a2dp_default_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
 android_audio_a2dp_default_la_LIBADD = @SBC_LIBS@
 
 android_audio_a2dp_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
-					-no-undefined -pthread
+					-no-undefined -pthread -lrt
 
 endif
 
-- 
1.8.4


^ permalink raw reply related

* [PATCH 2/2] android/hal-audio: Do not allocate memory if fd < 0
From: Andrei Emeltchenko @ 2014-01-23 15:43 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390491807-11095-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Fixes memory leak when returning bad fd we still allocate memory which
is not freed in the caller function audio_open_output_stream().
---
 android/hal-audio.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 2fbb956..9bbb53d 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -705,8 +705,7 @@ static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu, int *fd,
 
 	result = audio_ipc_cmd(AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
 				sizeof(cmd), &cmd, &rsp_len, rsp, fd);
-
-	if (result == AUDIO_STATUS_SUCCESS) {
+	if (result == AUDIO_STATUS_SUCCESS && *fd >= 0) {
 		size_t buf_len = sizeof(struct audio_preset) +
 					rsp->preset[0].len;
 		*mtu = rsp->mtu;
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 1/2] android/hal-audio: Check calloc return value
From: Andrei Emeltchenko @ 2014-01-23 15:43 UTC (permalink / raw)
  To: linux-bluetooth

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

calloc() might return NULL and is usually checked for NULL in BlueZ.
---
 android/hal-audio.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 4326ccd..2fbb956 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -320,6 +320,8 @@ static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
 	}
 
 	sbc_data = calloc(sizeof(struct sbc_data), 1);
+	if (!sbc_data)
+		return AUDIO_STATUS_FAILED;
 
 	memcpy(&sbc_data->sbc, preset->data, preset->len);
 
-- 
1.8.3.2


^ permalink raw reply related

* Re: [PATCH SBC 1/2] sbc: Add sbc_reinit_a2dp
From: Luiz Augusto von Dentz @ 2014-01-23 15:32 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org
In-Reply-To: <1390479624-5858-1-git-send-email-luiz.dentz@gmail.com>

Hi,

On Thu, Jan 23, 2014 at 2:20 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This adds sbc_reinit_a2dp that can be used to reconfigure a previous
> initialized sbc_t with new A2DP configuration.
> ---
>  sbc/sbc.c | 49 +++++++++++++++++++++++++++++++++++--------------
>  sbc/sbc.h |  2 ++
>  2 files changed, 37 insertions(+), 14 deletions(-)
>
> diff --git a/sbc/sbc.c b/sbc/sbc.c
> index 51bca55..534027e 100644
> --- a/sbc/sbc.c
> +++ b/sbc/sbc.c
> @@ -1087,19 +1087,14 @@ SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags)
>         return 0;
>  }
>
> -SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
> +static int sbc_set_a2dp(sbc_t *sbc, unsigned long flags,
>                                         const void *conf, size_t conf_len)
>  {
>         const struct a2dp_sbc *a2dp;
> -       int err;
>
>         if (conf_len != sizeof(*a2dp))
>                 return -EINVAL;
>
> -       err = sbc_init(sbc, flags);
> -       if (err < 0)
> -               return err;
> -
>         a2dp = conf;
>
>         switch (a2dp->frequency) {
> @@ -1116,7 +1111,7 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
>                 sbc->frequency = SBC_FREQ_48000;
>                 break;
>         default:
> -               goto failed;
> +               return -EINVAL;
>         }
>
>         switch (a2dp->channel_mode) {
> @@ -1133,7 +1128,7 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
>                 sbc->mode = SBC_MODE_JOINT_STEREO;
>                 break;
>         default:
> -               goto failed;
> +               return -EINVAL;
>         }
>
>         switch (a2dp->allocation_method) {
> @@ -1144,7 +1139,7 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
>                 sbc->allocation = SBC_AM_LOUDNESS;
>                 break;
>         default:
> -               goto failed;
> +               return -EINVAL;
>         }
>
>         switch (a2dp->subbands) {
> @@ -1155,7 +1150,7 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
>                 sbc->subbands = SBC_SB_8;
>                 break;
>         default:
> -               goto failed;
> +               return -EINVAL;
>         }
>
>         switch (a2dp->block_length) {
> @@ -1172,14 +1167,40 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
>                 sbc->blocks = SBC_BLK_16;
>                 break;
>         default:
> -               goto failed;
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
> +                                       const void *conf, size_t conf_len)
> +{
> +       int err;
> +
> +       err = sbc_init(sbc, flags);
> +       if (err < 0)
> +               return err;
> +
> +       err = sbc_set_a2dp(sbc, flags, conf, conf_len);
> +       if (err < 0) {
> +               sbc_finish(sbc);
> +               return err;
>         }
>
>         return 0;
> +}
> +
> +int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
> +                                       const void *conf, size_t conf_len)
> +{
> +       int err;
> +
> +       err = sbc_reinit(sbc, flags);
> +       if (err < 0)
> +               return err;
>
> -failed:
> -       sbc_finish(sbc);
> -       return -EINVAL;
> +       return sbc_set_a2dp(sbc, flags, conf, conf_len);
>  }
>
>  SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
> diff --git a/sbc/sbc.h b/sbc/sbc.h
> index a542845..d6f123e 100644
> --- a/sbc/sbc.h
> +++ b/sbc/sbc.h
> @@ -87,6 +87,8 @@ int sbc_reinit(sbc_t *sbc, unsigned long flags);
>  int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
>  int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
>                                         const void *conf, size_t conf_len);
> +int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
> +                                       const void *conf, size_t conf_len);
>
>  ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
>
> --
> 1.8.4.2

Pushed.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH] android/a2dp: Free device outside of notify function
From: Andrei Emeltchenko @ 2014-01-23 15:26 UTC (permalink / raw)
  To: linux-bluetooth

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

device_free() was used inside notify_state() function based on parameter
which makes it complex to follow. Change logic so that notify_state()
only notifies and the other code makes device_free().
---
 android/a2dp.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 572e0d1..d043c04 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -189,11 +189,6 @@ static void bt_a2dp_notify_state(struct a2dp_device *dev, uint8_t state)
 
 	ipc_send_notif(HAL_SERVICE_ID_A2DP, HAL_EV_A2DP_CONN_STATE, sizeof(ev),
 									&ev);
-
-	if (state != HAL_A2DP_STATE_DISCONNECTED)
-		return;
-
-	a2dp_device_free(dev);
 }
 
 static void bt_audio_notify_state(struct a2dp_setup *setup, uint8_t state)
@@ -221,6 +216,7 @@ static void disconnect_cb(void *user_data)
 	struct a2dp_device *dev = user_data;
 
 	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+	a2dp_device_free(dev);
 }
 
 static int sbc_check_config(void *caps, uint8_t caps_len, void *conf,
@@ -460,6 +456,7 @@ static gboolean idle_timeout(gpointer user_data)
 
 	error("avdtp_discover: %s", strerror(-err));
 	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+	a2dp_device_free(dev);
 
 	return FALSE;
 }
@@ -474,6 +471,7 @@ static void signaling_connect_cb(GIOChannel *chan, GError *err,
 
 	if (err) {
 		bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+		a2dp_device_free(dev);
 		error("%s", err->message);
 		return;
 	}
@@ -519,6 +517,7 @@ static void signaling_connect_cb(GIOChannel *chan, GError *err,
 
 failed:
 	bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+	a2dp_device_free(dev);
 }
 
 static void bt_a2dp_connect(const void *buf, uint16_t len)
@@ -581,6 +580,7 @@ static void bt_a2dp_disconnect(const void *buf, uint16_t len)
 
 	if (dev->io) {
 		bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED);
+		a2dp_device_free(dev);
 		goto failed;
 	}
 
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH] android/hal-audio: Workaround AudioFlinger issues
From: Andrzej Kaczmarek @ 2014-01-23 15:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Audio HAL code calculates accurate input stream buffer size which
allows to fill media packets with as much data as possible. However,
in most cases calculated buffer size does not work well with Android
audio code which causes glitches when playing simultaneously to
different audio output (like notification) or crashes mediaserver
when disconnecting with headset.

This patch changes input buffer size to fixed magic value 20*512 which
is used in Bluedroid Audio HAL. Such change requires that we need to
drop assumption that each input buffer can be used to fill exactly one
media packet and need to use it to fill multiple media packets. To
avoid buffering in Audio HAL, we allow that last media packet can be
filled in non-optimal way, i.e. has less data that can fit.
---
 android/hal-audio.c | 86 ++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 56 insertions(+), 30 deletions(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 4326ccd..f4a4ee1 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -413,6 +413,42 @@ static void sbc_resume(void *codec_data)
 	sbc_data->frames_sent = 0;
 }
 
+static void write_media_packet(int fd, struct sbc_data *sbc_data,
+				struct media_packet *mp, size_t data_len)
+{
+	struct timespec cur;
+	struct timespec diff;
+	unsigned expected_frames;
+	int ret;
+
+	ret = write(fd, mp, sizeof(*mp) + data_len);
+	if (ret < 0) {
+		int err = errno;
+		DBG("error writing data: %d (%s)", err,
+						strerror(err));
+	}
+
+	sbc_data->frames_sent += mp->payload.frame_count;
+
+	clock_gettime(CLOCK_MONOTONIC, &cur);
+	timespec_diff(&cur, &sbc_data->start, &diff);
+	expected_frames = (diff.tv_sec * 1000000 + diff.tv_nsec / 1000) /
+						sbc_data->frame_duration;
+
+	/* AudioFlinger does not seem to provide any *working*
+	 * API to provide data in some interval and will just
+	 * send another buffer as soon as we process current
+	 * one. To prevent overflowing L2CAP socket, we need to
+	 * introduce some artificial delay here base on how many
+	 * audio frames were sent so far, i.e. if we're not
+	 * lagging behind audio stream, we can sleep for
+	 * duration of single media packet.
+	 */
+	if (sbc_data->frames_sent >= expected_frames)
+		usleep(sbc_data->frame_duration *
+				mp->payload.frame_count);
+}
+
 static ssize_t sbc_write_data(void *codec_data, const void *buffer,
 				size_t bytes, int fd)
 {
@@ -421,9 +457,6 @@ static ssize_t sbc_write_data(void *codec_data, const void *buffer,
 	size_t encoded = 0;
 	struct media_packet *mp = (struct media_packet *) sbc_data->out_buf;
 	size_t free_space = sbc_data->out_buf_size - sizeof(*mp);
-	struct timespec cur;
-	struct timespec diff;
-	unsigned expected_frames;
 	int ret;
 
 	mp->hdr.v = 2;
@@ -450,39 +483,28 @@ static ssize_t sbc_write_data(void *codec_data, const void *buffer,
 		consumed += ret;
 		encoded += written;
 		free_space -= written;
-	}
 
-	ret = write(fd, mp, sizeof(*mp) + encoded);
-	if (ret < 0) {
-		int err = errno;
-		DBG("error writing data: %d (%s)", err, strerror(err));
+		/* write data if we either filled media packed or encoded all
+		 * input data
+		 */
+		if (mp->payload.frame_count == sbc_data->frames_per_packet ||
+				bytes == consumed) {
+			write_media_packet(fd, sbc_data, mp, encoded);
+
+			encoded = 0;
+			free_space = sbc_data->out_buf_size - sizeof(*mp);
+			mp->payload.frame_count = 0;
+		}
 	}
 
-	if (consumed != bytes || free_space != 0) {
-		/* we should encode all input data and fill output buffer
+	if (consumed != bytes) {
+		/* we should encode all input data
 		 * if we did not, something went wrong but we can't really
 		 * handle this so this is just sanity check
 		 */
 		DBG("some data were not encoded");
 	}
 
-	sbc_data->frames_sent += mp->payload.frame_count;
-
-	clock_gettime(CLOCK_MONOTONIC, &cur);
-	timespec_diff(&cur, &sbc_data->start, &diff);
-	expected_frames = (diff.tv_sec * 1000000 + diff.tv_nsec / 1000) /
-				sbc_data->frame_duration;
-
-	/* AudioFlinger does not seem to provide any *working* API to provide
-	 * data in some interval and will just send another buffer as soon as
-	 * we process current one. To prevent overflowing L2CAP socket, we need
-	 * to introduce some artificial delay here base on how many audio frames
-	 * were sent so far, i.e. if we're not lagging behind audio stream, we
-	 * can sleep for duration of single media packet.
-	 */
-	if (sbc_data->frames_sent >= expected_frames)
-		usleep(sbc_data->frame_duration * mp->payload.frame_count);
-
 	/* we always assume that all data was processed and sent */
 	return bytes;
 }
@@ -853,11 +875,15 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
 
 static size_t out_get_buffer_size(const struct audio_stream *stream)
 {
-	struct a2dp_stream_out *out = (struct a2dp_stream_out *) stream;
-
 	DBG("");
 
-	return out->ep->codec->get_buffer_size(out->ep->codec_data);
+	/* We should return proper buffer size calculated by codec (so each
+	 * input buffer is encoded into single media packed) but this does not
+	 * work well with AudioFlinger and causes problems. For this reason we
+	 * use magic value here and out_write code takes care of splitting
+	 * input buffer into multiple media packets.
+	 */
+	return 20 * 512;
 }
 
 static uint32_t out_get_channels(const struct audio_stream *stream)
-- 
1.8.5.2


^ permalink raw reply related

* [PATCH v2 2/2] android/hal-audio: Don't try to unregister endpoints on handler exit
From: Szymon Janc @ 2014-01-23 15:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390490548-19697-1-git-send-email-szymon.janc@tieto.com>

audio_sk is already closed at this point so just cleanup any leftovers
in enpoints states.
---
 android/hal-audio.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 52f8894..6104183 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -1378,7 +1378,8 @@ static void *ipc_handler(void *data)
 		}
 	}
 
-	unregister_endpoints();
+	/* audio_sk is closed at this point, just cleanup endpoints states */
+	memset(audio_endpoints, 0, sizeof(audio_endpoints));
 
 	info("Closing Audio IPC thread");
 	return NULL;
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH v2 1/2] android/hal-audio: Simplify and fix locking
From: Szymon Janc @ 2014-01-23 15:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This fix various issues with locking like missing unlock on
audio_ipc_cmd() return or accesing audio_sk without holding lock.
close_thread is removed to simplify code and shutdown on listen_sk is
used to indicate that that handler thread should stop.
---
v2: fix missing unregister_endpoints() on audio_close

 android/hal-audio.c | 70 +++++++++++++++++++++++++++++------------------------
 1 file changed, 38 insertions(+), 32 deletions(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 4326ccd..52f8894 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -44,10 +44,8 @@ static const uint8_t a2dp_src_uuid[] = {
 
 static int listen_sk = -1;
 static int audio_sk = -1;
-static bool close_thread = false;
 
 static pthread_t ipc_th = 0;
-static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -487,14 +485,6 @@ static ssize_t sbc_write_data(void *codec_data, const void *buffer,
 	return bytes;
 }
 
-static void audio_ipc_cleanup(void)
-{
-	if (audio_sk >= 0) {
-		shutdown(audio_sk, SHUT_RDWR);
-		audio_sk = -1;
-	}
-}
-
 static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 			void *param, size_t *rsp_len, void *rsp, int *fd)
 {
@@ -506,6 +496,8 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 	struct hal_status s;
 	size_t s_len = sizeof(s);
 
+	pthread_mutex_lock(&sk_mutex);
+
 	if (audio_sk < 0) {
 		error("audio: Invalid cmd socket passed to audio_ipc_cmd");
 		goto failed;
@@ -533,12 +525,9 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 	msg.msg_iov = iv;
 	msg.msg_iovlen = 2;
 
-	pthread_mutex_lock(&sk_mutex);
-
 	ret = sendmsg(audio_sk, &msg, 0);
 	if (ret < 0) {
 		error("audio: Sending command failed:%s", strerror(errno));
-		pthread_mutex_unlock(&sk_mutex);
 		goto failed;
 	}
 
@@ -570,12 +559,9 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 	if (ret < 0) {
 		error("audio: Receiving command response failed:%s",
 							strerror(errno));
-		pthread_mutex_unlock(&sk_mutex);
 		goto failed;
 	}
 
-	pthread_mutex_unlock(&sk_mutex);
-
 	if (ret < (ssize_t) sizeof(cmd)) {
 		error("audio: Too small response received(%zd bytes)", ret);
 		goto failed;
@@ -611,9 +597,13 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 			goto failed;
 		}
 
+		pthread_mutex_unlock(&sk_mutex);
+
 		return s->code;
 	}
 
+	pthread_mutex_unlock(&sk_mutex);
+
 	/* Receive auxiliary data in msg */
 	if (fd) {
 		struct cmsghdr *cmsg;
@@ -638,7 +628,8 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 failed:
 	/* Some serious issue happen on IPC - recover */
 	shutdown(audio_sk, SHUT_RDWR);
-	audio_sk = -1;
+	pthread_mutex_unlock(&sk_mutex);
+
 	return AUDIO_STATUS_FAILED;
 }
 
@@ -1311,10 +1302,10 @@ static int audio_close(hw_device_t *device)
 
 	DBG("");
 
-	pthread_mutex_lock(&close_mutex);
-	audio_ipc_cleanup();
-	close_thread = true;
-	pthread_mutex_unlock(&close_mutex);
+	unregister_endpoints();
+
+	shutdown(listen_sk, SHUT_RDWR);
+	shutdown(audio_sk, SHUT_RDWR);
 
 	pthread_join(ipc_th, NULL);
 
@@ -1329,19 +1320,31 @@ static void *ipc_handler(void *data)
 {
 	bool done = false;
 	struct pollfd pfd;
+	int sk;
 
 	DBG("");
 
 	while (!done) {
 		DBG("Waiting for connection ...");
-		audio_sk = accept(listen_sk, NULL, NULL);
-		if (audio_sk < 0) {
+
+		sk = accept(listen_sk, NULL, NULL);
+		if (sk < 0) {
 			int err = errno;
-			error("audio: Failed to accept socket: %d (%s)", err,
-								strerror(err));
-			continue;
+
+			if (err == EINTR)
+				continue;
+
+			if (err != ECONNABORTED && err != EINVAL)
+				error("audio: Failed to accept socket: %d (%s)",
+							err, strerror(err));
+
+			break;
 		}
 
+		pthread_mutex_lock(&sk_mutex);
+		audio_sk = sk;
+		pthread_mutex_unlock(&sk_mutex);
+
 		DBG("Audio IPC: Connected");
 
 		if (register_endpoints() != AUDIO_STATUS_SUCCESS) {
@@ -1349,7 +1352,12 @@ static void *ipc_handler(void *data)
 
 			unregister_endpoints();
 
+			pthread_mutex_lock(&sk_mutex);
 			shutdown(audio_sk, SHUT_RDWR);
+			close(audio_sk);
+			audio_sk = -1;
+			pthread_mutex_unlock(&sk_mutex);
+
 			continue;
 		}
 
@@ -1362,14 +1370,12 @@ static void *ipc_handler(void *data)
 
 		if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
 			info("Audio HAL: Socket closed");
+
+			pthread_mutex_lock(&sk_mutex);
+			close(audio_sk);
 			audio_sk = -1;
+			pthread_mutex_unlock(&sk_mutex);
 		}
-
-		/*Check if audio_dev is closed */
-		pthread_mutex_lock(&close_mutex);
-		done = close_thread;
-		close_thread = false;
-		pthread_mutex_unlock(&close_mutex);
 	}
 
 	unregister_endpoints();
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 2/2] android/hal-audio: Don't try to unregister endpoints on handler exit
From: Szymon Janc @ 2014-01-23 14:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1390486886-12350-1-git-send-email-szymon.janc@tieto.com>

audio_sk is already closed at this point so just cleanup any leftovers
in enpoints states.
---
 android/hal-audio.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 11b0767..0128622 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -1376,7 +1376,8 @@ static void *ipc_handler(void *data)
 		}
 	}
 
-	unregister_endpoints();
+	/* audio_sk is closed at this point, just cleanup endpoints states */
+	memset(audio_endpoints, 0, sizeof(audio_endpoints));
 
 	info("Closing Audio IPC thread");
 	return NULL;
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 1/2] android/hal-audio: Simplify and fix locking
From: Szymon Janc @ 2014-01-23 14:21 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This fix various issues with locking like missing unlock on
audio_ipc_cmd() return or accesing audio_sk without holding lock.
close_thread is removed to simplify code and shutdown on listen_sk is
used to indicate that that handler thread should stop.
---
 android/hal-audio.c | 68 ++++++++++++++++++++++++++++-------------------------
 1 file changed, 36 insertions(+), 32 deletions(-)

diff --git a/android/hal-audio.c b/android/hal-audio.c
index 4326ccd..11b0767 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -44,10 +44,8 @@ static const uint8_t a2dp_src_uuid[] = {
 
 static int listen_sk = -1;
 static int audio_sk = -1;
-static bool close_thread = false;
 
 static pthread_t ipc_th = 0;
-static pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t sk_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -487,14 +485,6 @@ static ssize_t sbc_write_data(void *codec_data, const void *buffer,
 	return bytes;
 }
 
-static void audio_ipc_cleanup(void)
-{
-	if (audio_sk >= 0) {
-		shutdown(audio_sk, SHUT_RDWR);
-		audio_sk = -1;
-	}
-}
-
 static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 			void *param, size_t *rsp_len, void *rsp, int *fd)
 {
@@ -506,6 +496,8 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 	struct hal_status s;
 	size_t s_len = sizeof(s);
 
+	pthread_mutex_lock(&sk_mutex);
+
 	if (audio_sk < 0) {
 		error("audio: Invalid cmd socket passed to audio_ipc_cmd");
 		goto failed;
@@ -533,12 +525,9 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 	msg.msg_iov = iv;
 	msg.msg_iovlen = 2;
 
-	pthread_mutex_lock(&sk_mutex);
-
 	ret = sendmsg(audio_sk, &msg, 0);
 	if (ret < 0) {
 		error("audio: Sending command failed:%s", strerror(errno));
-		pthread_mutex_unlock(&sk_mutex);
 		goto failed;
 	}
 
@@ -570,12 +559,9 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 	if (ret < 0) {
 		error("audio: Receiving command response failed:%s",
 							strerror(errno));
-		pthread_mutex_unlock(&sk_mutex);
 		goto failed;
 	}
 
-	pthread_mutex_unlock(&sk_mutex);
-
 	if (ret < (ssize_t) sizeof(cmd)) {
 		error("audio: Too small response received(%zd bytes)", ret);
 		goto failed;
@@ -611,9 +597,13 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 			goto failed;
 		}
 
+		pthread_mutex_unlock(&sk_mutex);
+
 		return s->code;
 	}
 
+	pthread_mutex_unlock(&sk_mutex);
+
 	/* Receive auxiliary data in msg */
 	if (fd) {
 		struct cmsghdr *cmsg;
@@ -638,7 +628,8 @@ static int audio_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len,
 failed:
 	/* Some serious issue happen on IPC - recover */
 	shutdown(audio_sk, SHUT_RDWR);
-	audio_sk = -1;
+	pthread_mutex_unlock(&sk_mutex);
+
 	return AUDIO_STATUS_FAILED;
 }
 
@@ -1311,10 +1302,8 @@ static int audio_close(hw_device_t *device)
 
 	DBG("");
 
-	pthread_mutex_lock(&close_mutex);
-	audio_ipc_cleanup();
-	close_thread = true;
-	pthread_mutex_unlock(&close_mutex);
+	shutdown(listen_sk, SHUT_RDWR);
+	shutdown(audio_sk, SHUT_RDWR);
 
 	pthread_join(ipc_th, NULL);
 
@@ -1329,19 +1318,31 @@ static void *ipc_handler(void *data)
 {
 	bool done = false;
 	struct pollfd pfd;
+	int sk;
 
 	DBG("");
 
 	while (!done) {
 		DBG("Waiting for connection ...");
-		audio_sk = accept(listen_sk, NULL, NULL);
-		if (audio_sk < 0) {
+
+		sk = accept(listen_sk, NULL, NULL);
+		if (sk < 0) {
 			int err = errno;
-			error("audio: Failed to accept socket: %d (%s)", err,
-								strerror(err));
-			continue;
+
+			if (err == EINTR)
+				continue;
+
+			if (err != ECONNABORTED && err != EINVAL)
+				error("audio: Failed to accept socket: %d (%s)",
+							err, strerror(err));
+
+			break;
 		}
 
+		pthread_mutex_lock(&sk_mutex);
+		audio_sk = sk;
+		pthread_mutex_unlock(&sk_mutex);
+
 		DBG("Audio IPC: Connected");
 
 		if (register_endpoints() != AUDIO_STATUS_SUCCESS) {
@@ -1349,7 +1350,12 @@ static void *ipc_handler(void *data)
 
 			unregister_endpoints();
 
+			pthread_mutex_lock(&sk_mutex);
 			shutdown(audio_sk, SHUT_RDWR);
+			close(audio_sk);
+			audio_sk = -1;
+			pthread_mutex_unlock(&sk_mutex);
+
 			continue;
 		}
 
@@ -1362,14 +1368,12 @@ static void *ipc_handler(void *data)
 
 		if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
 			info("Audio HAL: Socket closed");
+
+			pthread_mutex_lock(&sk_mutex);
+			close(audio_sk);
 			audio_sk = -1;
+			pthread_mutex_unlock(&sk_mutex);
 		}
-
-		/*Check if audio_dev is closed */
-		pthread_mutex_lock(&close_mutex);
-		done = close_thread;
-		close_thread = false;
-		pthread_mutex_unlock(&close_mutex);
 	}
 
 	unregister_endpoints();
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 3/3] android/pan: Fix bnep interface name
From: Ravi kumar Veeramally @ 2014-01-23 13:39 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1390484367-6332-1-git-send-email-ravikumar.veeramally@linux.intel.com>

Android uses bt-pan static interface in PAN profile. In server role
it uses as bridge name. But current implementaion passes interface
names like bnep0, bnep1... Android Java layer unaware of this name
and unable to allocate IP address after profile connection setup.
---
 android/pan.c                 | 45 ++++++++++++++++++++++++++++++++++---------
 profiles/network/bnep.c       |  8 +++++---
 profiles/network/bnep.h       |  3 ++-
 profiles/network/connection.c |  5 +++--
 profiles/network/server.c     |  4 ++++
 5 files changed, 50 insertions(+), 15 deletions(-)

diff --git a/android/pan.c b/android/pan.c
index 67b62f2..8c545c0 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -51,7 +51,9 @@
 
 #define SVC_HINT_NETWORKING 0x02
 
-#define BNEP_BRIDGE "bnep"
+#define BNEP_BRIDGE "bt-pan"
+#define BNEP_PANU_INTERFACE "bt-pan"
+#define BNEP_NAP_INTERFACE "bt-pan%d"
 #define FORWARD_DELAY_PATH "/sys/class/net/"BNEP_BRIDGE"/bridge/forward_delay"
 
 static bdaddr_t adapter_addr;
@@ -71,11 +73,16 @@ struct pan_device {
 static struct {
 	uint32_t	record_id;
 	GIOChannel	*io;
+	bool		bridge;
 } nap_dev = {
 	.record_id = 0,
 	.io = NULL,
+	.bridge = false,
 };
 
+static int nap_create_bridge(void);
+static int nap_remove_bridge(void);
+
 static int device_cmp(gconstpointer s, gconstpointer user_data)
 {
 	const struct pan_device *dev = s;
@@ -102,8 +109,10 @@ static void pan_device_free(struct pan_device *dev)
 	devices = g_slist_remove(devices, dev);
 	g_free(dev);
 
-	if (g_slist_length(devices) == 0)
+	if (g_slist_length(devices) == 0) {
 		local_role = HAL_PAN_ROLE_NONE;
+		nap_remove_bridge();
+	}
 }
 
 static void bt_pan_notify_conn_state(struct pan_device *dev, uint8_t state)
@@ -140,7 +149,11 @@ static void bt_pan_notify_ctrl_state(struct pan_device *dev, uint8_t state)
 	ev.local_role = local_role;
 	ev.status = HAL_STATUS_SUCCESS;
 	memset(ev.name, 0, sizeof(ev.name));
-	memcpy(ev.name, dev->iface, sizeof(dev->iface));
+
+	if (local_role == HAL_PAN_ROLE_NAP)
+		memcpy(ev.name, BNEP_BRIDGE, sizeof(BNEP_BRIDGE));
+	else
+		memcpy(ev.name, dev->iface, sizeof(dev->iface));
 
 	ipc_send_notif(HAL_SERVICE_ID_PAN, HAL_EV_PAN_CTRL_STATE, sizeof(ev),
 									&ev);
@@ -194,7 +207,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
 
 	sk = g_io_channel_unix_get_fd(dev->io);
 
-	dev->session = bnep_new(sk, l_role, r_role);
+	dev->session = bnep_new(sk, l_role, r_role, BNEP_PANU_INTERFACE);
 	if (!dev->session)
 		goto fail;
 
@@ -380,6 +393,9 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
 		goto failed;
 	}
 
+	if (nap_create_bridge() < 0)
+		goto failed;
+
 	if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
 							&dev->dst) < 0) {
 		error("server_connadd failed");
@@ -448,6 +464,9 @@ static void nap_confirm_cb(GIOChannel *chan, gpointer data)
 	local_role = HAL_PAN_ROLE_NAP;
 	dev->role = HAL_PAN_ROLE_PANU;
 
+	memset(dev->iface, 0, 16);
+	strcpy(dev->iface, BNEP_NAP_INTERFACE);
+
 	dev->io = g_io_channel_ref(chan);
 	g_io_channel_set_close_on_unref(dev->io, TRUE);
 
@@ -488,6 +507,9 @@ static int nap_create_bridge(void)
 
 	DBG("%s", BNEP_BRIDGE);
 
+	if (nap_dev.bridge == true)
+		return 0;
+
 	sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
 	if (sk < 0)
 		return -EOPNOTSUPP;
@@ -506,6 +528,11 @@ static int nap_create_bridge(void)
 
 	close(sk);
 
+	if (err == 0)
+		nap_dev.bridge = true;
+	else
+		nap_dev.bridge = false;
+
 	return err;
 }
 
@@ -515,6 +542,11 @@ static int nap_remove_bridge(void)
 
 	DBG("%s", BNEP_BRIDGE);
 
+	if (nap_dev.bridge == false)
+		return 0;
+
+	nap_dev.bridge = false;
+
 	sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
 	if (sk < 0)
 		return -EOPNOTSUPP;
@@ -544,14 +576,9 @@ static void destroy_nap_device(void)
 static int register_nap_server(void)
 {
 	GError *gerr = NULL;
-	int err;
 
 	DBG("");
 
-	err = nap_create_bridge();
-	if (err < 0)
-		return err;
-
 	nap_dev.io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
 					BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
 					BT_IO_OPT_PSM, BNEP_PSM,
diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index 2a74016..aed9260 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -173,9 +173,8 @@ static int bnep_connadd(int sk, uint16_t role, char *dev)
 {
 	struct bnep_connadd_req req;
 
-	memset(dev, 0, 16);
 	memset(&req, 0, sizeof(req));
-	strcpy(req.device, "bnep%d");
+	strcpy(req.device, dev);
 	req.sock = sk;
 	req.role = role;
 	if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
@@ -384,7 +383,8 @@ static gboolean bnep_conn_req_to(gpointer user_data)
 	return FALSE;
 }
 
-struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role)
+struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role,
+								char *iface)
 {
 	struct bnep *session;
 	int dup_fd;
@@ -397,6 +397,8 @@ struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role)
 	session->io = g_io_channel_unix_new(dup_fd);
 	session->src = local_role;
 	session->dst = remote_role;
+	memset(session->iface, 0, 16);
+	strcpy(session->iface, iface);
 
 	g_io_channel_set_close_on_unref(session->io, TRUE);
 	session->watch = g_io_add_watch(session->io,
diff --git a/profiles/network/bnep.h b/profiles/network/bnep.h
index 87cdacf..bc43d4f 100644
--- a/profiles/network/bnep.h
+++ b/profiles/network/bnep.h
@@ -30,7 +30,8 @@ uint16_t bnep_service_id(const char *svc);
 const char *bnep_uuid(uint16_t id);
 const char *bnep_name(uint16_t id);
 
-struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role);
+struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role,
+								char *iface);
 void bnep_free(struct bnep *session);
 
 typedef void (*bnep_connect_cb) (char *iface, int err, void *data);
diff --git a/profiles/network/connection.c b/profiles/network/connection.c
index c66987d..d01d178 100644
--- a/profiles/network/connection.c
+++ b/profiles/network/connection.c
@@ -51,6 +51,7 @@
 #include "connection.h"
 
 #define NETWORK_PEER_INTERFACE "org.bluez.Network1"
+#define BNEP_INTERFACE	"bnep%d"
 
 typedef enum {
 	CONNECTED,
@@ -128,7 +129,7 @@ static void bnep_disconn_cb(gpointer data)
 
 	nc->state = DISCONNECTED;
 	memset(nc->dev, 0, sizeof(nc->dev));
-	strcpy(nc->dev, "bnep%d");
+	strcpy(nc->dev, BNEP_INTERFACE);
 
 	bnep_free(nc->session);
 	nc->session = NULL;
@@ -243,7 +244,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
 	}
 
 	sk = g_io_channel_unix_get_fd(nc->io);
-	nc->session = bnep_new(sk, BNEP_SVC_PANU, nc->id);
+	nc->session = bnep_new(sk, BNEP_SVC_PANU, nc->id, BNEP_INTERFACE);
 	if (!nc->session)
 		goto failed;
 
diff --git a/profiles/network/server.c b/profiles/network/server.c
index 7cb5a1e..755db0d 100644
--- a/profiles/network/server.c
+++ b/profiles/network/server.c
@@ -53,6 +53,7 @@
 
 #define NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer1"
 #define SETUP_TIMEOUT		1
+#define BNEP_INTERFACE	"bnep%d"
 
 /* Pending Authorization */
 struct network_session {
@@ -348,6 +349,9 @@ static gboolean bnep_setup(GIOChannel *chan,
 		goto reply;
 	}
 
+	memset(na->setup->dev, 0, 16);
+	strcpy(na->setup->dev, BNEP_INTERFACE);
+
 	if (bnep_server_add(sk, dst_role, ns->bridge, na->setup->dev,
 							&na->setup->dst) < 0)
 		goto reply;
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 2/3] android/pan: Handle error case properly in NAP registration
From: Ravi kumar Veeramally @ 2014-01-23 13:39 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1390484367-6332-1-git-send-email-ravikumar.veeramally@linux.intel.com>

---
 android/pan.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/android/pan.c b/android/pan.c
index 67c7556..67b62f2 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -471,8 +471,10 @@ static int set_forward_delay(void)
 	int fd, ret;
 
 	fd = open(FORWARD_DELAY_PATH, O_RDWR);
-	if (fd < 0)
+	if (fd < 0) {
+		error("open forward delay path : %s", strerror(errno));
 		return -errno;
+	}
 
 	ret = write(fd, "0", sizeof("0"));
 	close(fd);
@@ -728,7 +730,7 @@ bool bt_pan_register(const bdaddr_t *addr)
 	}
 
 	err = bnep_init();
-	if (err) {
+	if (err < 0) {
 		error("bnep init failed");
 		bt_adapter_remove_record(rec->handle);
 		return false;
@@ -736,6 +738,7 @@ bool bt_pan_register(const bdaddr_t *addr)
 
 	err = register_nap_server();
 	if (err < 0) {
+		error("Failed to register NAP");
 		bt_adapter_remove_record(rec->handle);
 		bnep_cleanup();
 		return false;
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 1/3] android/pan: Fix control state change callback parameters order
From: Ravi kumar Veeramally @ 2014-01-23 13:39 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ravi kumar Veeramally

Callback declared in bt_pan.h is
'typedef void (*btpan_control_state_callback)
(btpan_control_state_t state, bt_status_t error, int local_role,
const char* ifname);

But PanService.Java defined it wrong way.
private void onControlStateChanged(int local_role, int state,
int error, String ifname).
First and third parameters are misplaced, so sending data according
to PanService.Java, discard this fix if issue fixed in PanService.Java.
---
 android/hal-pan.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/android/hal-pan.c b/android/hal-pan.c
index 8c0f8d8..a596ffd 100644
--- a/android/hal-pan.c
+++ b/android/hal-pan.c
@@ -45,9 +45,18 @@ static void handle_ctrl_state(void *buf, uint16_t len)
 {
 	struct hal_ev_pan_ctrl_state *ev = buf;
 
+	/* FIXME: Callback declared in bt_pan.h is 'typedef void
+	 * (*btpan_control_state_callback)(btpan_control_state_t state,
+	 * bt_status_t error, int local_role, const char* ifname);
+	 * But PanService.Java defined it wrong way.
+	 * private void onControlStateChanged(int local_role, int state,
+	 * int error, String ifname).
+	 * First and third parameters are misplaced, so sending data according
+	 * to PanService.Java, fix this if issue fixed in PanService.Java.
+	 */
 	if (cbs->control_state_cb)
-		cbs->control_state_cb(ev->state, ev->status,
-					ev->local_role, (char *)ev->name);
+		cbs->control_state_cb(ev->local_role, ev->state, ev->status,
+							(char *)ev->name);
 }
 
 /* handlers will be called from notification thread context,
-- 
1.8.3.2


^ permalink raw reply related

* Re: [PATCH] btproxy: Fix resource leak
From: Johan Hedberg @ 2014-01-23 13:24 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1390468048-8526-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Thu, Jan 23, 2014, Andrei Emeltchenko wrote:
> Close file descriptors before leaving.
> ---
>  tools/btproxy.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)

Applied. Thanks.

Johan

^ permalink raw reply

* [PATCH 2/2] Bluetooth: Switch ATT channels to use L2CAP_CHAN_FIXED_CID
From: johan.hedberg @ 2014-01-23 13:22 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390483368-21321-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

ATT channels are not connection oriented so having them use
L2CAP_CHAN_CONN_ORIENTED is quite confusing. Instead, use the new
L2CAP_CHAN_FIXED_CID type and ensure that the MTU and CID values get
properly set.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 21 +++++++++------------
 net/bluetooth/l2cap_sock.c |  6 ++++++
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 84714541b48c..c5c47667bfe0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -498,18 +498,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
 	switch (chan->chan_type) {
 	case L2CAP_CHAN_CONN_ORIENTED:
-		if (conn->hcon->type == LE_LINK) {
-			if (chan->dcid == L2CAP_CID_ATT) {
-				chan->omtu = L2CAP_DEFAULT_MTU;
-				chan->scid = L2CAP_CID_ATT;
-			} else {
-				chan->scid = l2cap_alloc_cid(conn);
-			}
-		} else {
-			/* Alloc CID for connection-oriented socket */
-			chan->scid = l2cap_alloc_cid(conn);
+		/* Alloc CID for connection-oriented socket */
+		chan->scid = l2cap_alloc_cid(conn);
+		if (conn->hcon->type == ACL_LINK)
 			chan->omtu = L2CAP_DEFAULT_MTU;
-		}
 		break;
 
 	case L2CAP_CHAN_CONN_LESS:
@@ -7025,7 +7017,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 		goto done;
 	}
 
-	if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
+	if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !psm) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	if (chan->chan_type == L2CAP_CHAN_FIXED_CID && !cid) {
 		err = -EINVAL;
 		goto done;
 	}
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 4aa6704f0b33..45064d130308 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -101,6 +101,12 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 	if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
 		return -EINVAL;
 
+	if (la.l2_cid) {
+		/* Update type from the default CONN_ORIENTED */
+		chan->chan_type = L2CAP_CHAN_FIXED_CID;
+		chan->omtu = L2CAP_DEFAULT_MTU;
+	}
+
 	if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
 		if (!enable_lecoc && la.l2_psm)
 			return -EINVAL;
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH 1/2] Bluetooth: Rename L2CAP_CHAN_CONN_FIX_A2MP to L2CAP_CHAN_FIXED_CID
From: johan.hedberg @ 2014-01-23 13:22 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

There's no reason why A2DP should need or deserve its on channel type.
Instead we should be able to group all fixed CID users under a single
channel type and reuse as much code as possible for them. Where CID
specific exceptions are needed the chan-scid value can be used.

This patch renames the current A2DP channel type to a generic one and
thereby paves the way to allow converting ATT and SMP (and any future
fixed channel protocols) to use the new channel type.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/l2cap.h |  2 +-
 net/bluetooth/a2mp.c          |  8 ++++++--
 net/bluetooth/l2cap_core.c    | 15 ++++++---------
 3 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 85cf40acc47e..eeb02f414255 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -651,7 +651,7 @@ struct l2cap_user {
 #define L2CAP_CHAN_RAW			1
 #define L2CAP_CHAN_CONN_LESS		2
 #define L2CAP_CHAN_CONN_ORIENTED	3
-#define L2CAP_CHAN_CONN_FIX_A2MP	4
+#define L2CAP_CHAN_FIXED_CID		4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index efcd108822c4..677b970cede6 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -235,7 +235,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 			BT_DBG("chan %p state %s", chan,
 			       state_to_string(chan->state));
 
-			if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
+			if (chan->scid == L2CAP_CID_A2MP)
 				continue;
 
 			l2cap_chan_lock(chan);
@@ -726,7 +726,11 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
 
 	BT_DBG("chan %p", chan);
 
-	chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
+	chan->chan_type = L2CAP_CHAN_FIXED_CID;
+	chan->scid = L2CAP_CID_A2MP;
+	chan->dcid = L2CAP_CID_A2MP;
+	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
 	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 
 	chan->ops = &a2mp_chan_ops;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 138394ad3e51..84714541b48c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -519,11 +519,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 		chan->omtu = L2CAP_DEFAULT_MTU;
 		break;
 
-	case L2CAP_CHAN_CONN_FIX_A2MP:
-		chan->scid = L2CAP_CID_A2MP;
-		chan->dcid = L2CAP_CID_A2MP;
-		chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
-		chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	case L2CAP_CHAN_FIXED_CID:
+		/* Caller will set CID and CID specific MTU values */
 		break;
 
 	default:
@@ -571,7 +568,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
 		chan->conn = NULL;
 
-		if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
+		if (chan->scid != L2CAP_CID_A2MP)
 			hci_conn_drop(conn->hcon);
 
 		if (mgr && mgr->bredr_chan == chan)
@@ -1310,7 +1307,7 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err)
 		__clear_ack_timer(chan);
 	}
 
-	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+	if (chan->scid == L2CAP_CID_A2MP) {
 		l2cap_state_change(chan, BT_DISCONN);
 		return;
 	}
@@ -1508,7 +1505,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
 		l2cap_chan_lock(chan);
 
-		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+		if (chan->scid == L2CAP_CID_A2MP) {
 			l2cap_chan_unlock(chan);
 			continue;
 		}
@@ -7245,7 +7242,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 		BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
 		       state_to_string(chan->state));
 
-		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+		if (chan->scid == L2CAP_CID_A2MP) {
 			l2cap_chan_unlock(chan);
 			continue;
 		}
-- 
1.8.5.3


^ permalink raw reply related

* [PATCH SBC 2/2] sbc: Add sbc_reinit_a2dp to sbc.sym
From: Luiz Augusto von Dentz @ 2014-01-23 12:20 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390479624-5858-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 sbc/sbc.sym | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sbc/sbc.sym b/sbc/sbc.sym
index 0c23a05..0642a0b 100644
--- a/sbc/sbc.sym
+++ b/sbc/sbc.sym
@@ -22,4 +22,5 @@ global:
 SBC_1.2 {
 global:
 	sbc_init_a2dp;
+	sbc_reinit_a2dp;
 } SBC_1.1;
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH SBC 1/2] sbc: Add sbc_reinit_a2dp
From: Luiz Augusto von Dentz @ 2014-01-23 12:20 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds sbc_reinit_a2dp that can be used to reconfigure a previous
initialized sbc_t with new A2DP configuration.
---
 sbc/sbc.c | 49 +++++++++++++++++++++++++++++++++++--------------
 sbc/sbc.h |  2 ++
 2 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/sbc/sbc.c b/sbc/sbc.c
index 51bca55..534027e 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -1087,19 +1087,14 @@ SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags)
 	return 0;
 }
 
-SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+static int sbc_set_a2dp(sbc_t *sbc, unsigned long flags,
 					const void *conf, size_t conf_len)
 {
 	const struct a2dp_sbc *a2dp;
-	int err;
 
 	if (conf_len != sizeof(*a2dp))
 		return -EINVAL;
 
-	err = sbc_init(sbc, flags);
-	if (err < 0)
-		return err;
-
 	a2dp = conf;
 
 	switch (a2dp->frequency) {
@@ -1116,7 +1111,7 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
 		sbc->frequency = SBC_FREQ_48000;
 		break;
 	default:
-		goto failed;
+		return -EINVAL;
 	}
 
 	switch (a2dp->channel_mode) {
@@ -1133,7 +1128,7 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
 		sbc->mode = SBC_MODE_JOINT_STEREO;
 		break;
 	default:
-		goto failed;
+		return -EINVAL;
 	}
 
 	switch (a2dp->allocation_method) {
@@ -1144,7 +1139,7 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
 		sbc->allocation = SBC_AM_LOUDNESS;
 		break;
 	default:
-		goto failed;
+		return -EINVAL;
 	}
 
 	switch (a2dp->subbands) {
@@ -1155,7 +1150,7 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
 		sbc->subbands = SBC_SB_8;
 		break;
 	default:
-		goto failed;
+		return -EINVAL;
 	}
 
 	switch (a2dp->block_length) {
@@ -1172,14 +1167,40 @@ SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
 		sbc->blocks = SBC_BLK_16;
 		break;
 	default:
-		goto failed;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+					const void *conf, size_t conf_len)
+{
+	int err;
+
+	err = sbc_init(sbc, flags);
+	if (err < 0)
+		return err;
+
+	err = sbc_set_a2dp(sbc, flags, conf, conf_len);
+	if (err < 0) {
+		sbc_finish(sbc);
+		return err;
 	}
 
 	return 0;
+}
+
+int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
+					const void *conf, size_t conf_len)
+{
+	int err;
+
+	err = sbc_reinit(sbc, flags);
+	if (err < 0)
+		return err;
 
-failed:
-	sbc_finish(sbc);
-	return -EINVAL;
+	return sbc_set_a2dp(sbc, flags, conf, conf_len);
 }
 
 SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
diff --git a/sbc/sbc.h b/sbc/sbc.h
index a542845..d6f123e 100644
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -87,6 +87,8 @@ int sbc_reinit(sbc_t *sbc, unsigned long flags);
 int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
 int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
 					const void *conf, size_t conf_len);
+int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
+					const void *conf, size_t conf_len);
 
 ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
 
-- 
1.8.4.2


^ permalink raw reply related

* Re: [PATCH v3 00/10] android: Add SBC encoding
From: Luiz Augusto von Dentz @ 2014-01-23  9:43 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1390386893-8212-1-git-send-email-andrzej.kaczmarek@tieto.com>

Hi Andrzej,

On Wed, Jan 22, 2014 at 12:34 PM, Andrzej Kaczmarek
<andrzej.kaczmarek@tieto.com> wrote:
> Hi,
>
> v1 -> v2
> - fixed comments
> - added dependency to libsbc shared library on Android
>
> v2 -> v3
> - added comment explaining why we need to sleep in out_write
> - updated to new SBC API
> - libsbc shared library is now built from our Android.mk
> - implemented proper get_latency callback
>
>
>
> Andrzej Kaczmarek (10):
>   android: Add MTU data to Open Stream Audio IPC
>   android: Build Audio HAL with SBC
>   android/hal-audio: Rename sbc_init to avoid collision with libsbc
>   android/hal-audio: Initialize SBC encoder
>   android/hal-audio: Calculate SBC stream parameters
>   android/hal-audio: Add resume to codec callbacks
>   android/hal-audio: Return proper buffer size to AudioFlinger
>   android/hal-audio: Read fd from Output Stream response
>   android/hal-audio: Add proper SBC encoding
>   android/hal-audio: Return proper latency for stream
>
>  android/Android.mk  |  37 ++++++-
>  android/Makefile.am |   2 +
>  android/a2dp.c      |   8 +-
>  android/audio-msg.h |   1 +
>  android/hal-audio.c | 301 +++++++++++++++++++++++++++++++++++++++++++++++++---
>  configure.ac        |   7 ++
>  6 files changed, 338 insertions(+), 18 deletions(-)
>
> --
> 1.8.5.2

Pushed, thanks.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH] btproxy: Fix resource leak
From: Andrei Emeltchenko @ 2014-01-23  9:07 UTC (permalink / raw)
  To: linux-bluetooth

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

Close file descriptors before leaving.
---
 tools/btproxy.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tools/btproxy.c b/tools/btproxy.c
index be81bae..3503148 100644
--- a/tools/btproxy.c
+++ b/tools/btproxy.c
@@ -680,8 +680,11 @@ int main(int argc, char *argv[])
 			return EXIT_FAILURE;
 		}
 
-		if (!setup_proxy(host_fd, false, dev_fd, true))
+		if (!setup_proxy(host_fd, false, dev_fd, true)) {
+			close(dev_fd);
+			close(host_fd);
 			return EXIT_FAILURE;
+		}
 	} else {
 		int server_fd;
 
-- 
1.8.3.2


^ permalink raw reply related

* Re: [PATCH] 6lowpan: add a license to 6lowpan_iphc module
From: David Miller @ 2014-01-23  5:59 UTC (permalink / raw)
  To: ydroneaud
  Cc: alex.bluesman.smirnov, dbaryshkov, marcel, gustavo, johan.hedberg,
	linux-zigbee-devel, linux-bluetooth, netdev, linux-kernel,
	jukka.rissanen, alex.aring
In-Reply-To: <1390418724-9804-1-git-send-email-ydroneaud@opteya.com>

From: Yann Droneaud <ydroneaud@opteya.com>
Date: Wed, 22 Jan 2014 20:25:24 +0100

> Since commit 8df8c56a5abc, 6lowpan_iphc is a module of its own.
> 
> Unfortunately, it lacks some infrastructure to behave like a
> good kernel citizen:
> 
>   kernel: 6lowpan_iphc: module license 'unspecified' taints kernel.
>   kernel: Disabling lock debugging due to kernel taint
> 
> This patch adds the basic MODULE_LICENSE(); with GPL license:
> the code was copied from net/ieee802154/6lowpan.c which is GPL
> and the module exports symbol with EXPORT_SYMBOL_GPL();.
> 
> Cc: Jukka Rissanen <jukka.rissanen@linux.intel.com>
> Cc: Alexander Aring <alex.aring@gmail.com>
> Cc: Marcel Holtmann <marcel@holtmann.org>
> Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>

Applied.

^ permalink raw reply


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