All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ v2 1/4] lib/uuid: Add VCS UUIDs
@ 2022-09-15  9:54 Sathish Narasimman
  2022-09-15  9:54 ` [PATCH BlueZ v2 2/4] shared/vcp: Add initial code for handling VCP Sathish Narasimman
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Sathish Narasimman @ 2022-09-15  9:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This adds Volume Control Service UUIDs which will be used by
Volume Control Profile.
---
 lib/uuid.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index cb9294be8c6e..f667a74b9b73 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -164,6 +164,13 @@ extern "C" {
 #define ASE_SOURCE_UUID					0x2bc5
 #define ASE_CP_UUID					0x2bc6
 
+#define VCS_UUID					0x1844
+#define VOL_OFFSET_CS_UUID				0x1845
+#define AUDIO_INPUT_CS_UUID				0x1843
+#define VOL_STATE_CHRC_UUID				0x2B7D
+#define VOL_CP_CHRC_UUID				0x2B7E
+#define VOL_FLAG_CHRC_UUID				0x2B7F
+
 typedef struct {
 	enum {
 		BT_UUID_UNSPEC = 0,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH BlueZ v2 2/4] shared/vcp: Add initial code for handling VCP
  2022-09-15  9:54 [PATCH BlueZ v2 1/4] lib/uuid: Add VCS UUIDs Sathish Narasimman
@ 2022-09-15  9:54 ` Sathish Narasimman
  2022-09-15  9:54 ` [PATCH BlueZ v2 3/4] profiles: Add initial code for vcp plugin Sathish Narasimman
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Sathish Narasimman @ 2022-09-15  9:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This adds initial code for Volume Control Profile.
---
 Makefile.am      |    1 +
 src/shared/vcp.c | 1041 ++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/vcp.h |   58 +++
 3 files changed, 1100 insertions(+)
 create mode 100644 src/shared/vcp.c
 create mode 100644 src/shared/vcp.h

diff --git a/Makefile.am b/Makefile.am
index 960bf21bc726..27715c73d76f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -231,6 +231,7 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
 			src/shared/gap.h src/shared/gap.c \
 			src/shared/log.h src/shared/log.c \
 			src/shared/bap.h src/shared/bap.c src/shared/ascs.h \
+			src/shared/vcp.c src/shared/vcp.h \
 			src/shared/lc3.h src/shared/tty.h
 
 if READLINE
diff --git a/src/shared/vcp.c b/src/shared/vcp.c
new file mode 100644
index 000000000000..2d718cfff174
--- /dev/null
+++ b/src/shared/vcp.c
@@ -0,0 +1,1041 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2022  Intel Corporation. All rights reserved.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+
+#include "src/shared/queue.h"
+#include "src/shared/util.h"
+#include "src/shared/timeout.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/vcp.h"
+#include "src/log.h"
+
+#define VCP_STEP_SIZE 1
+
+/* Apllication Error Code */
+#define BT_ATT_ERROR_INVALID_CHANGE_COUNTER	0x80
+#define BT_ATT_ERROR_OPCODE_NOT_SUPPORTED	0x81
+
+struct bt_vcp_db {
+	struct gatt_db *db;
+	struct bt_vcs *vcs;
+};
+
+typedef void (*vcp_func_t)(struct bt_vcp *vcp, bool success, uint8_t att_ecode,
+					const uint8_t *value, uint16_t length,
+					void *user_data);
+
+struct bt_vcp_pending {
+	unsigned int id;
+	struct bt_vcp *vcp;
+	vcp_func_t func;
+	void *user_data;
+};
+
+struct bt_vcs_param {
+	uint8_t	op;
+	uint8_t	change_counter;
+} __packed;
+
+struct bt_vcs_ab_vol {
+	uint8_t	change_counter;
+	uint8_t	vol_set;
+} __packed;
+
+struct bt_vcp_cb {
+	unsigned int id;
+	bt_vcp_func_t attached;
+	bt_vcp_func_t detached;
+	void *user_data;
+};
+
+typedef void (*vcp_notify_t)(struct bt_vcp *vcp, uint16_t value_handle,
+				const uint8_t *value, uint16_t length,
+				void *user_data);
+
+struct bt_vcp_notify {
+	unsigned int id;
+	struct bt_vcp *vcp;
+	vcp_notify_t func;
+	void *user_data;
+};
+
+struct bt_vcp {
+	int ref_count;
+	struct bt_vcp_db *ldb;
+	struct bt_vcp_db *rdb;
+	struct bt_gatt_client *client;
+	struct bt_att *att;
+	unsigned int vstate_id;
+	unsigned int vflag_id;
+
+	struct queue *pending;
+
+	void *debug_data;
+	void *user_data;
+};
+
+#define RESET_VOLUME_SETTING 0x00
+#define USERSET_VOLUME_SETTING 0x01
+
+/* Contains local bt_vcp_db */
+struct vol_state {
+	uint8_t	vol_set;
+	uint8_t	mute;
+	uint8_t counter;
+} __packed;
+
+struct bt_vcs {
+	struct bt_vcp_db *vdb;
+	struct vol_state *vstate;
+	uint8_t vol_flag;
+	struct gatt_db_attribute *service;
+	struct gatt_db_attribute *vs;
+	struct gatt_db_attribute *vs_ccc;
+	struct gatt_db_attribute *vol_cp;
+	struct gatt_db_attribute *vf;
+	struct gatt_db_attribute *vf_ccc;
+};
+
+static struct queue *vcp_db;
+static struct queue *vcp_cbs;
+static struct queue *sessions;
+
+static void *iov_pull_mem(struct iovec *iov, size_t len)
+{
+	void *data = iov->iov_base;
+
+	if (iov->iov_len < len)
+		return NULL;
+
+	iov->iov_base += len;
+	iov->iov_len -= len;
+
+	return data;
+}
+
+static struct bt_vcs *vcp_get_vcs(struct bt_vcp *vcp)
+{
+	if (!vcp)
+		return NULL;
+
+	if (vcp->rdb->vcs)
+		return vcp->rdb->vcs;
+
+	vcp->rdb->vcs = new0(struct bt_vcs, 1);
+	vcp->rdb->vcs->vdb = vcp->rdb;
+
+	return vcp->rdb->vcs;
+}
+
+static void vcp_detached(void *data, void *user_data)
+{
+	struct bt_vcp_cb *cb = data;
+	struct bt_vcp *vcp = user_data;
+
+	cb->detached(vcp, cb->user_data);
+}
+
+void bt_vcp_detach(struct bt_vcp *vcp)
+{
+	if (!queue_remove(sessions, vcp))
+		return;
+
+	bt_gatt_client_unref(vcp->client);
+	vcp->client = NULL;
+
+	queue_foreach(vcp_cbs, vcp_detached, vcp);
+}
+
+static void vcp_db_free(void *data)
+{
+	struct bt_vcp_db *vdb = data;
+
+	if (!vdb)
+		return;
+
+	gatt_db_unref(vdb->db);
+
+	free(vdb->vcs);
+	free(vdb);
+}
+
+static void vcp_free(void *data)
+{
+	struct bt_vcp *vcp = data;
+
+	bt_vcp_detach(vcp);
+
+	vcp_db_free(vcp->rdb);
+
+	queue_destroy(vcp->pending, NULL);
+
+	free(vcp);
+}
+bool bt_vcp_set_user_data(struct bt_vcp *vcp, void *user_data)
+{
+	if (!vcp)
+		return false;
+
+	vcp->user_data = user_data;
+
+	return true;
+}
+
+static bool vcp_db_match(const void *data, const void *match_data)
+{
+	const struct bt_vcp_db *vdb = data;
+	const struct gatt_db *db = match_data;
+
+	return (vdb->db == db);
+}
+
+struct bt_att *bt_vcp_get_att(struct bt_vcp *vcp)
+{
+	if (!vcp)
+		return NULL;
+
+	if (vcp->att)
+		return vcp->att;
+
+	return bt_gatt_client_get_att(vcp->client);
+}
+
+struct bt_vcp *bt_vcp_ref(struct bt_vcp *vcp)
+{
+	if (!vcp)
+		return NULL;
+
+	__sync_fetch_and_add(&vcp->ref_count, 1);
+
+	return vcp;
+}
+
+void bt_vcp_unref(struct bt_vcp *vcp)
+{
+	if (!vcp)
+		return;
+
+	if (__sync_sub_and_fetch(&vcp->ref_count, 1))
+		return;
+
+	vcp_free(vcp);
+}
+
+static void vcp_disconnected(int err, void *user_data)
+{
+	struct bt_vcp *vcp = user_data;
+
+	DBG("vcp %p disconnected err %d", vcp, err);
+
+	bt_vcp_detach(vcp);
+}
+
+static struct bt_vcp *vcp_get_session(struct bt_att *att, struct gatt_db *db)
+{
+	const struct queue_entry *entry;
+	struct bt_vcp *vcp;
+
+	for (entry = queue_get_entries(sessions); entry; entry = entry->next) {
+		struct bt_vcp *vcp = entry->data;
+
+		if (att == bt_vcp_get_att(vcp))
+			return vcp;
+	}
+
+	vcp = bt_vcp_new(db, NULL);
+	vcp->att = att;
+
+	bt_att_register_disconnect(att, vcp_disconnected, vcp, NULL);
+
+	bt_vcp_attach(vcp, NULL);
+
+	return vcp;
+
+}
+
+static uint8_t vcs_rel_vol_down(struct bt_vcs *vcs, struct bt_vcp *vcp,
+				struct iovec *iov)
+{
+	struct bt_vcp_db *vdb;
+	struct vol_state *vstate;
+	uint8_t	*change_counter;
+
+	DBG("");
+
+	vdb = vcp->ldb;
+	if (!vdb && !vdb->vcs)
+		DBG("error: vcp database not available!!!!");
+
+	vstate = vdb->vcs->vstate;
+	if (!vstate)
+		DBG("error: vstate not availalbe!!!!");
+
+	change_counter = iov_pull_mem(iov, sizeof(*change_counter));
+
+	if (*change_counter != vstate->counter) {
+		DBG("Change Counter Mismatch Volume not decremented!");
+		return BT_ATT_ERROR_INVALID_CHANGE_COUNTER;
+	}
+
+	vstate->vol_set = MAX((vstate->vol_set - VCP_STEP_SIZE), 0);
+	vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+
+	gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
+				 sizeof(struct vol_state),
+				 bt_vcp_get_att(vcp));
+	return 0;
+}
+
+static uint8_t vcs_rel_vol_up(struct bt_vcs *vcs, struct bt_vcp *vcp,
+				struct iovec *iov)
+{
+	struct bt_vcp_db *vdb;
+	struct vol_state *vstate;
+	uint8_t	*change_counter;
+
+	DBG("");
+
+	vdb = vcp->ldb;
+	if (!vdb && !vdb->vcs)
+		DBG("error: vcp database not available!!!!");
+
+	vstate = vdb->vcs->vstate;
+	if (!vstate)
+		DBG("error: vstate not availalbe!!!!");
+
+	change_counter = iov_pull_mem(iov, sizeof(*change_counter));
+
+	if (*change_counter != vstate->counter) {
+		DBG("Change Counter Mismatch Volume not decremented!");
+		return BT_ATT_ERROR_INVALID_CHANGE_COUNTER;
+	}
+
+	vstate->vol_set = MIN((vstate->vol_set + VCP_STEP_SIZE), 255);
+	vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+
+	gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
+				 sizeof(struct vol_state),
+				 bt_vcp_get_att(vcp));
+	return 0;
+}
+
+static uint8_t vcs_unmute_rel_vol_down(struct bt_vcs *vcs, struct bt_vcp *vcp,
+				struct iovec *iov)
+{
+	struct bt_vcp_db *vdb;
+	struct vol_state *vstate;
+	uint8_t	*change_counter;
+
+	DBG("");
+
+	vdb = vcp->ldb;
+	if (!vdb && !vdb->vcs)
+		DBG("error: vcp database not available!!!!");
+
+	vstate = vdb->vcs->vstate;
+	if (!vstate)
+		DBG("error: vstate not availalbe!!!!");
+
+	change_counter = iov_pull_mem(iov, sizeof(*change_counter));
+
+	if (*change_counter != vstate->counter) {
+		DBG("Change Counter Mismatch Volume not decremented!");
+		return BT_ATT_ERROR_INVALID_CHANGE_COUNTER;
+	}
+
+	vstate->mute = 0x00;
+	vstate->vol_set = MAX((vstate->vol_set - VCP_STEP_SIZE), 0);
+	vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+
+	gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
+				 sizeof(struct vol_state),
+				 bt_vcp_get_att(vcp));
+	return 0;
+}
+
+static uint8_t vcs_unmute_rel_vol_up(struct bt_vcs *vcs, struct bt_vcp *vcp,
+				struct iovec *iov)
+{
+	struct bt_vcp_db *vdb;
+	struct vol_state *vstate;
+	uint8_t	*change_counter;
+
+	DBG("");
+
+	vdb = vcp->ldb;
+	if (!vdb && !vdb->vcs)
+		DBG("error: vcp database not available!!!!");
+
+	vstate = vdb->vcs->vstate;
+	if (!vstate)
+		DBG("error: vstate not availalbe!!!!");
+
+	change_counter = iov_pull_mem(iov, sizeof(*change_counter));
+
+	if (*change_counter != vstate->counter) {
+		DBG("Change Counter Mismatch Volume not decremented!");
+		return BT_ATT_ERROR_INVALID_CHANGE_COUNTER;
+	}
+
+	vstate->mute = 0x00;
+	vstate->vol_set = MIN((vstate->vol_set + VCP_STEP_SIZE), 255);
+	vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+
+	gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
+				 sizeof(struct vol_state),
+				 bt_vcp_get_att(vcp));
+	return 0;
+}
+
+static uint8_t vcs_set_absolute_vol(struct bt_vcs *vcs, struct bt_vcp *vcp,
+				struct iovec *iov)
+{
+	struct bt_vcp_db *vdb;
+	struct vol_state *vstate;
+	struct bt_vcs_ab_vol *req;
+
+	DBG("");
+
+	vdb = vcp->ldb;
+	if (!vdb && !vdb->vcs)
+		DBG("error: vcp database not available!!!!");
+
+	vstate = vdb->vcs->vstate;
+	if (!vstate)
+		DBG("error: vstate not availalbe!!!!");
+
+	req = iov_pull_mem(iov, sizeof(*req));
+
+	if (req->change_counter != vstate->counter) {
+		DBG("Change Counter Mismatch Volume not decremented!");
+		return BT_ATT_ERROR_INVALID_CHANGE_COUNTER;
+	}
+
+	vstate->vol_set = req->vol_set;
+	vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+
+	gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
+				 sizeof(struct vol_state),
+				 bt_vcp_get_att(vcp));
+	return 0;
+}
+
+static uint8_t vcs_unmute(struct bt_vcs *vcs, struct bt_vcp *vcp,
+				struct iovec *iov)
+{
+	struct bt_vcp_db *vdb;
+	struct vol_state *vstate;
+	uint8_t	*change_counter;
+
+	DBG("");
+
+	vdb = vcp->ldb;
+	if (!vdb && !vdb->vcs)
+		DBG("error: vcp database not available!!!!");
+
+	vstate = vdb->vcs->vstate;
+	if (!vstate)
+		DBG("error: vstate not availalbe!!!!");
+
+	change_counter = iov_pull_mem(iov, sizeof(*change_counter));
+
+	if (*change_counter != vstate->counter) {
+		DBG("Change Counter Mismatch Volume not decremented!");
+		return BT_ATT_ERROR_INVALID_CHANGE_COUNTER;
+	}
+
+	vstate->mute = 0x00;
+	vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+
+	gatt_db_attribute_notify(vdb->vcs->vs, (void *)vstate,
+				 sizeof(struct vol_state),
+				 bt_vcp_get_att(vcp));
+	return 0;
+}
+
+static uint8_t vcs_mute(struct bt_vcs *vcs, struct bt_vcp *vcp,
+				struct iovec *iov)
+{
+	struct bt_vcp_db *vdb;
+	struct vol_state *vstate;
+	uint8_t	*change_counter;
+
+	DBG("");
+
+	vdb = vcp->ldb;
+	if (!vdb && !vdb->vcs)
+		DBG("error: vcp database not available!!!!");
+
+	vstate = vdb->vcs->vstate;
+	if (!vstate)
+		DBG("error: vstate not availalbe!!!!");
+
+	change_counter = iov_pull_mem(iov, sizeof(*change_counter));
+
+	if (*change_counter != vstate->counter) {
+		DBG("Change Counter Mismatch Volume not decremented!");
+		return BT_ATT_ERROR_INVALID_CHANGE_COUNTER;
+	}
+
+	vstate->mute = 0x01;
+	vstate->counter = -~vstate->counter; /*Increment Change Counter*/
+
+	return 0;
+}
+
+
+#define	BT_VCS_REL_VOL_DOWN		0x00
+#define	BT_VCS_REL_VOL_UP		0x01
+#define	BT_VCS_UNMUTE_REL_VOL_DOWN	0x02
+#define	BT_VCS_UNMUTE_REL_VOL_UP	0x03
+#define	BT_VCS_SET_ABSOLUTE_VOL		0x04
+#define	BT_VCS_UNMUTE			0x05
+#define	BT_VCS_MUTE			0x06
+
+#define VCS_OP(_str, _op, _size, _func) \
+	{ \
+		.str = _str, \
+		.op = _op, \
+		.size = _size, \
+		.func = _func, \
+	}
+
+struct vcs_op_handler {
+	const char *str;
+	uint8_t	op;
+	size_t	size;
+	uint8_t	(*func)(struct bt_vcs *vcs, struct bt_vcp *vcp,
+			struct iovec *iov);
+} vcp_handlers[] = {
+	VCS_OP("Relative Volume Down", BT_VCS_REL_VOL_DOWN,
+		sizeof(uint8_t), vcs_rel_vol_down),
+	VCS_OP("Relative Volume Up", BT_VCS_REL_VOL_UP,
+		sizeof(uint8_t), vcs_rel_vol_up),
+	VCS_OP("Unmute - Relative Volume Down", BT_VCS_UNMUTE_REL_VOL_DOWN,
+		sizeof(uint8_t), vcs_unmute_rel_vol_down),
+	VCS_OP("Unmute - Relative Volume Up", BT_VCS_UNMUTE_REL_VOL_UP,
+		sizeof(uint8_t), vcs_unmute_rel_vol_up),
+	VCS_OP("Set Absolute Volume", BT_VCS_SET_ABSOLUTE_VOL,
+		sizeof(struct bt_vcs_ab_vol), vcs_set_absolute_vol),
+	VCS_OP("UnMute", BT_VCS_UNMUTE,
+		sizeof(uint8_t), vcs_unmute),
+	VCS_OP("Mute", BT_VCS_MUTE,
+		sizeof(uint8_t), vcs_mute),
+	{}
+};
+
+static void vcs_cp_write(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				const uint8_t *value, size_t len,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	struct bt_vcs *vcs = user_data;
+	struct bt_vcp *vcp = vcp_get_session(att, vcs->vdb->db);
+	struct iovec iov = {
+		.iov_base = (void *) value,
+		.iov_len = len,
+	};
+	uint8_t	*vcp_op;
+	struct vcs_op_handler *handler;
+	uint8_t ret = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+
+	DBG("");
+	if (offset) {
+		DBG("invalid offset %d", offset);
+		ret = BT_ATT_ERROR_INVALID_OFFSET;
+		goto respond;
+	}
+
+	if (len < sizeof(*vcp_op)) {
+		DBG("invalid len %ld < %ld sizeof(*param)", len,
+							sizeof(*vcp_op));
+		ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+		goto respond;
+	}
+
+	vcp_op = iov_pull_mem(&iov, sizeof(*vcp_op));
+
+	DBG("vcp_op: %x", *vcp_op);
+
+	for (handler = vcp_handlers; handler && handler->str; handler++) {
+		if (handler->op != *vcp_op)
+			continue;
+
+		if (iov.iov_len < handler->size) {
+			DBG("invalid len %ld < %ld handler->size", len,
+			    handler->size);
+			ret = BT_ATT_ERROR_OPCODE_NOT_SUPPORTED;
+			goto respond;
+		}
+
+		break;
+	}
+
+	if (handler && handler->str) {
+		DBG("%s", handler->str);
+
+		ret = handler->func(vcs, vcp, &iov);
+	} else {
+		DBG("Unknown opcode 0x%02x", *vcp_op);
+		ret = BT_ATT_ERROR_OPCODE_NOT_SUPPORTED;
+	}
+
+respond:
+	gatt_db_attribute_write_result(attrib, id, ret);
+}
+
+static void vcs_state_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	struct bt_vcs *vcs = user_data;
+	struct iovec iov;
+
+	DBG("");
+
+	iov.iov_base = vcs->vstate;
+	iov.iov_len = sizeof(*vcs->vstate);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void vcs_flag_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	struct bt_vcs *vcs = user_data;
+	struct iovec iov;
+
+	DBG("vf: %x", vcs->vol_flag);
+
+	iov.iov_base = &vcs->vol_flag;
+	iov.iov_len = sizeof(vcs->vol_flag);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static struct bt_vcs *vcs_new(struct gatt_db *db)
+{
+	struct bt_vcs *vcs;
+	struct vol_state *vstate;
+	bt_uuid_t uuid;
+
+	if (!db)
+		return NULL;
+
+	vcs = new0(struct bt_vcs, 1);
+
+	vstate = new0(struct vol_state, 1);
+
+	vcs->vstate = vstate;
+	vcs->vol_flag = USERSET_VOLUME_SETTING;
+
+	/* Populate DB with VCS attributes */
+	bt_uuid16_create(&uuid, VCS_UUID);
+	vcs->service = gatt_db_add_service(db, &uuid, true, 9);
+
+	bt_uuid16_create(&uuid, VOL_STATE_CHRC_UUID);
+	vcs->vs = gatt_db_service_add_characteristic(vcs->service,
+					&uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ |
+					BT_GATT_CHRC_PROP_NOTIFY,
+					vcs_state_read, NULL,
+					vcs);
+
+	vcs->vs_ccc = gatt_db_service_add_ccc(vcs->service,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+
+	bt_uuid16_create(&uuid, VOL_CP_CHRC_UUID);
+	vcs->vol_cp = gatt_db_service_add_characteristic(vcs->service,
+					&uuid,
+					BT_ATT_PERM_WRITE,
+					BT_GATT_CHRC_PROP_WRITE,
+					NULL, vcs_cp_write,
+					vcs);
+
+	bt_uuid16_create(&uuid, VOL_FLAG_CHRC_UUID);
+	vcs->vf = gatt_db_service_add_characteristic(vcs->service,
+					&uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ |
+					BT_GATT_CHRC_PROP_NOTIFY,
+					vcs_flag_read, NULL,
+					vcs);
+
+	vcs->vf_ccc = gatt_db_service_add_ccc(vcs->service,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+
+
+	gatt_db_service_set_active(vcs->service, true);
+
+	return vcs;
+}
+
+static struct bt_vcp_db *vcp_db_new(struct gatt_db *db)
+{
+	struct bt_vcp_db *vdb;
+
+	if (!db)
+		return NULL;
+
+	vdb = new0(struct bt_vcp_db, 1);
+	vdb->db = gatt_db_ref(db);
+
+	if (!vcp_db)
+		vcp_db = queue_new();
+
+	vdb->vcs = vcs_new(db);
+	vdb->vcs->vdb = vdb;
+
+	queue_push_tail(vcp_db, vdb);
+
+	return vdb;
+}
+
+static struct bt_vcp_db *vcp_get_db(struct gatt_db *db)
+{
+	struct bt_vcp_db *vdb;
+
+	vdb = queue_find(vcp_db, vcp_db_match, db);
+	if (vdb)
+		return vdb;
+
+	return vcp_db_new(db);
+}
+
+void bt_vcp_add_db(struct gatt_db *db)
+{
+	vcp_db_new(db);
+}
+
+unsigned int bt_vcp_register(bt_vcp_func_t attached, bt_vcp_func_t detached,
+							void *user_data)
+{
+	struct bt_vcp_cb *cb;
+	static unsigned int id;
+
+	if (!attached && !detached)
+		return 0;
+
+	if (!vcp_cbs)
+		vcp_cbs = queue_new();
+
+	cb = new0(struct bt_vcp_cb, 1);
+	cb->id = ++id ? id : ++id;
+	cb->attached = attached;
+	cb->detached = detached;
+	cb->user_data = user_data;
+
+	queue_push_tail(vcp_cbs, cb);
+
+	return cb->id;
+}
+
+static bool match_id(const void *data, const void *match_data)
+{
+	const struct bt_vcp_cb *cb = data;
+	unsigned int id = PTR_TO_UINT(match_data);
+
+	return (cb->id == id);
+}
+
+bool bt_vcp_unregister(unsigned int id)
+{
+	struct bt_vcp_cb *cb;
+
+	cb = queue_remove_if(vcp_cbs, match_id, UINT_TO_PTR(id));
+	if (!cb)
+		return false;
+
+	free(cb);
+
+	return true;
+}
+
+struct bt_vcp *bt_vcp_new(struct gatt_db *ldb, struct gatt_db *rdb)
+{
+	struct bt_vcp *vcp;
+	struct bt_vcp_db *vdb;
+
+	if (!ldb)
+		return NULL;
+
+	vdb = vcp_get_db(ldb);
+	if (!vdb)
+		return NULL;
+
+	vcp = new0(struct bt_vcp, 1);
+	vcp->ldb = vdb;
+	vcp->pending = queue_new();
+
+	if (!rdb)
+		goto done;
+
+	vdb = new0(struct bt_vcp_db, 1);
+	vdb->db = gatt_db_ref(rdb);
+
+	vcp->rdb = vdb;
+
+done:
+	bt_vcp_ref(vcp);
+
+	return vcp;
+}
+
+static void vcp_vstate_register(uint16_t att_ecode, void *user_data)
+{
+	DBG("");
+	if (att_ecode)
+		DBG("ASE register failed: 0x%04x", att_ecode);
+}
+
+static void vcp_vflag_register(uint16_t att_ecode, void *user_data)
+{
+	DBG("");
+	if (att_ecode)
+		DBG("ASE register failed: 0x%04x", att_ecode);
+}
+
+static void vcp_vstate_notify(uint16_t value_handle, const uint8_t *value,
+				uint16_t length, void *user_data)
+{
+	struct vol_state vstate;
+
+	memcpy(&vstate, value, sizeof(struct vol_state));
+
+	DBG("Vol Settings 0x%x", vstate.vol_set);
+	DBG("Mute Status 0x%x", vstate.mute);
+	DBG("Vol Counter 0x%x", vstate.counter);
+}
+
+static void vcp_vflag_notify(uint16_t value_handle, const uint8_t *value,
+				uint16_t length, void *user_data)
+{
+	uint8_t vflag;
+
+	memcpy(&vflag, value, sizeof(vflag));
+
+	DBG("Vol Flag 0x%x", vflag);
+}
+
+static void read_vol_flag(struct bt_vcp *vcp, bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	uint8_t *vol_flag;
+	struct iovec iov = {
+		.iov_base = (void *) value,
+		.iov_len = length,
+	};
+
+	if (!success) {
+		DBG("Unable to read VCP Vol State: error 0x%02x", att_ecode);
+		return;
+	}
+
+	vol_flag = iov_pull_mem(&iov, sizeof(*vol_flag));
+	if (!vol_flag) {
+		DBG("Unable to get Vol State");
+		return;
+	}
+
+	DBG("Vol Flag:%x", *vol_flag);
+}
+
+static void read_vol_state(struct bt_vcp *vcp, bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct vol_state *vs;
+	struct iovec iov = {
+		.iov_base = (void *) value,
+		.iov_len = length,
+	};
+
+	if (!success) {
+		DBG("Unable to read VCP Vol State: error 0x%02x", att_ecode);
+		return;
+	}
+
+	vs = iov_pull_mem(&iov, sizeof(*vs));
+	if (!vs) {
+		DBG("Unable to get Vol State");
+		return;
+	}
+
+	DBG("Vol Set:%x", vs->vol_set);
+	DBG("Vol Mute:%x", vs->mute);
+	DBG("Vol Counter:%x", vs->counter);
+
+}
+
+static void vcp_pending_destroy(void *data)
+{
+	struct bt_vcp_pending *pending = data;
+	struct bt_vcp *vcp = pending->vcp;
+
+	if (queue_remove_if(vcp->pending, NULL, pending))
+		free(pending);
+}
+
+static void vcp_pending_complete(bool success, uint8_t att_ecode,
+				const uint8_t *value, uint16_t length,
+				void *user_data)
+{
+	struct bt_vcp_pending *pending = user_data;
+
+	if (pending->func)
+		pending->func(pending->vcp, success, att_ecode, value, length,
+						pending->user_data);
+}
+
+static void vcp_read_value(struct bt_vcp *vcp, uint16_t value_handle,
+				vcp_func_t func, void *user_data)
+{
+	struct bt_vcp_pending *pending;
+
+	pending = new0(struct bt_vcp_pending, 1);
+	pending->vcp = vcp;
+	pending->func = func;
+	pending->user_data = user_data;
+
+	pending->id = bt_gatt_client_read_value(vcp->client, value_handle,
+						vcp_pending_complete, pending,
+						vcp_pending_destroy);
+	if (!pending->id) {
+		DBG("Unable to send Read request");
+		free(pending);
+		return;
+	}
+
+	queue_push_tail(vcp->pending, pending);
+}
+
+static void foreach_vcs_char(struct gatt_db_attribute *attr, void *user_data)
+{
+	struct bt_vcp *vcp = user_data;
+	uint16_t value_handle;
+	bt_uuid_t uuid, uuid_vstate, uuid_cp, uuid_vflag;
+	struct bt_vcs *vcs;
+
+	DBG("");
+	if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle,
+						NULL, NULL, &uuid))
+		return;
+
+	bt_uuid16_create(&uuid_vstate, VOL_STATE_CHRC_UUID);
+	bt_uuid16_create(&uuid_cp, VOL_CP_CHRC_UUID);
+	bt_uuid16_create(&uuid_vflag, VOL_FLAG_CHRC_UUID);
+
+	if (!bt_uuid_cmp(&uuid, &uuid_vstate)) {
+		DBG("VCS Volume state found: handle 0x%04x", value_handle);
+
+		vcs = vcp_get_vcs(vcp);
+		if (!vcs || vcs->vs)
+			return;
+
+		vcs->vs = attr;
+
+		vcp_read_value(vcp, value_handle, read_vol_state, vcp);
+		vcp->vstate_id = bt_gatt_client_register_notify(vcp->client,
+						value_handle,
+						vcp_vstate_register,
+						vcp_vstate_notify, vcp, NULL);
+
+		return;
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_cp)) {
+		DBG("VCS Volume CP found: handle 0x%04x", value_handle);
+
+		vcs = vcp_get_vcs(vcp);
+		if (!vcs || vcs->vol_cp)
+			return;
+
+		vcs->vol_cp = attr;
+
+		return;
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_vflag)) {
+		DBG("VCS Vol Flaf found: handle 0x%04x", value_handle);
+
+		vcs = vcp_get_vcs(vcp);
+		if (!vcs || vcs->vf)
+			return;
+
+		vcs->vf = attr;
+
+		vcp_read_value(vcp, value_handle, read_vol_flag, vcp);
+		vcp->vflag_id = bt_gatt_client_register_notify(vcp->client,
+						value_handle,
+						vcp_vflag_register,
+						vcp_vflag_notify, vcp, NULL);
+	}
+
+}
+
+static void foreach_vcs_service(struct gatt_db_attribute *attr,
+						void *user_data)
+{
+	struct bt_vcp *vcp = user_data;
+	struct bt_vcs *vcs = vcp_get_vcs(vcp);
+
+	DBG("");
+	vcs->service = attr;
+
+	gatt_db_service_set_claimed(attr, true);
+
+	gatt_db_service_foreach_char(attr, foreach_vcs_char, vcp);
+}
+
+bool bt_vcp_attach(struct bt_vcp *vcp, struct bt_gatt_client *client)
+{
+	bt_uuid_t uuid;
+
+	if (!sessions)
+		sessions = queue_new();
+
+	queue_push_tail(sessions, vcp);
+
+	if (!client)
+		return true;
+
+	if (vcp->client)
+		return false;
+
+	vcp->client = bt_gatt_client_clone(client);
+	if (!vcp->client)
+		return false;
+
+	bt_uuid16_create(&uuid, VCS_UUID);
+	gatt_db_foreach_service(vcp->ldb->db, &uuid, foreach_vcs_service, vcp);
+
+	return true;
+}
+
diff --git a/src/shared/vcp.h b/src/shared/vcp.h
new file mode 100644
index 000000000000..456ad8041162
--- /dev/null
+++ b/src/shared/vcp.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ */
+
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include "src/shared/io.h"
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+#define BT_VCP_RENDERER			0x01
+#define	BT_VCP_CONTROLLER		0x02
+
+#define BT_VCP_RELATIVE_VOL_DOWN	0x00
+#define BT_VCP_RELATIVE_VOL_UP		0x01
+#define BT_VCP_UNMUTE_RELATIVE_VOL_DOWN	0x02
+#define BT_VCP_UNMUTE_RELATIVE_VOL_UP	0x03
+#define BT_VCP_SET_ABOSULTE_VOL		0x04
+#define BT_VCP_UNMUTE			0x05
+#define BT_VCP_MUTE			0x06
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+struct bt_vcp;
+
+typedef void (*bt_vcp_func_t)(struct bt_vcp *vcp, void *user_data);
+
+struct bt_vcp *bt_vcp_ref(struct bt_vcp *vcp);
+void bt_vcp_unref(struct bt_vcp *vcp);
+
+void bt_vcp_add_db(struct gatt_db *db);
+
+bool bt_vcp_attach(struct bt_vcp *vcp, struct bt_gatt_client *client);
+void bt_vcp_detach(struct bt_vcp *vcp);
+
+struct bt_att *bt_vcp_get_att(struct bt_vcp *vcp);
+
+bool bt_vcp_set_user_data(struct bt_vcp *vcp, void *user_data);
+
+/* Session related function */
+unsigned int bt_vcp_register(bt_vcp_func_t added, bt_vcp_func_t removed,
+							void *user_data);
+bool bt_vcp_unregister(unsigned int id);
+struct bt_vcp *bt_vcp_new(struct gatt_db *ldb, struct gatt_db *rdb);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH BlueZ v2 3/4] profiles: Add initial code for vcp plugin
  2022-09-15  9:54 [PATCH BlueZ v2 1/4] lib/uuid: Add VCS UUIDs Sathish Narasimman
  2022-09-15  9:54 ` [PATCH BlueZ v2 2/4] shared/vcp: Add initial code for handling VCP Sathish Narasimman
@ 2022-09-15  9:54 ` Sathish Narasimman
  2022-09-15  9:54 ` [PATCH BlueZ v2 4/4] monitor/att: Add decoding support for Volume Control Serice Sathish Narasimman
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Sathish Narasimman @ 2022-09-15  9:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This adds initial code for vcp plugin which handles Volume Control
Profile and Volume Control Service.
---
 Makefile.plugins     |   5 +
 configure.ac         |   4 +
 profiles/audio/vcp.c | 312 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 321 insertions(+)
 create mode 100644 profiles/audio/vcp.c

diff --git a/Makefile.plugins b/Makefile.plugins
index 213ed99edf2d..a3654980f86d 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -121,3 +121,8 @@ if BAP
 builtin_modules += bap
 builtin_sources += profiles/audio/bap.c
 endif
+
+if VCP
+builtin_modules += vcp
+builtin_sources += profiles/audio/vcp.c
+endif
diff --git a/configure.ac b/configure.ac
index 1f76915b4349..79645e6917cc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,6 +199,10 @@ AC_ARG_ENABLE(bap, AS_HELP_STRING([--disable-bap],
 		[disable BAP profile]), [enable_bap=${enableval}])
 AM_CONDITIONAL(BAP, test "${enable_bap}" != "no")
 
+AC_ARG_ENABLE(vcp, AS_HELP_STRING([--disable-vcp],
+		[disable VCP profile]), [enable_vcp=${enableval}])
+AM_CONDITIONAL(VCP, test "${enable_vcp}" != "no")
+
 AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools],
 		[disable Bluetooth tools]), [enable_tools=${enableval}])
 AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no")
diff --git a/profiles/audio/vcp.c b/profiles/audio/vcp.c
new file mode 100644
index 000000000000..34950d4070f2
--- /dev/null
+++ b/profiles/audio/vcp.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2022  Intel Corporation. All rights reserved.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "gdbus/gdbus.h"
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "src/dbus-common.h"
+#include "src/shared/util.h"
+#include "src/shared/att.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/vcp.h"
+
+#include "btio/btio.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/gatt-database.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+#include "src/log.h"
+#include "src/error.h"
+
+#define VCS_UUID_STR "00001844-0000-1000-8000-00805f9b34fb"
+#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
+
+struct vcp_data {
+	struct btd_device *device;
+	struct btd_service *service;
+	struct bt_vcp *vcp;
+};
+
+static struct queue *sessions;
+
+static int vcp_disconnect(struct btd_service *service)
+{
+	DBG("");
+	return 0;
+}
+
+static struct vcp_data *vcp_data_new(struct btd_device *device)
+{
+	struct vcp_data *data;
+
+	data = new0(struct vcp_data, 1);
+	data->device = device;
+
+	return data;
+}
+
+static void vcp_data_add(struct vcp_data *data)
+{
+	DBG("data %p", data);
+
+	if (queue_find(sessions, NULL, data)) {
+		error("data %p already added", data);
+		return;
+	}
+
+	if (!sessions)
+		sessions = queue_new();
+
+	queue_push_tail(sessions, data);
+
+	if (data->service)
+		btd_service_set_user_data(data->service, data);
+}
+
+static bool match_data(const void *data, const void *match_data)
+{
+	const struct vcp_data *vdata = data;
+	const struct bt_vcp *vcp = match_data;
+
+	return vdata->vcp == vcp;
+}
+
+static void vcp_data_free(struct vcp_data *data)
+{
+	if (data->service) {
+		btd_service_set_user_data(data->service, NULL);
+		bt_vcp_set_user_data(data->vcp, NULL);
+	}
+
+	bt_vcp_unref(data->vcp);
+	free(data);
+}
+
+static void vcp_data_remove(struct vcp_data *data)
+{
+	DBG("data %p", data);
+
+	if (!queue_remove(sessions, data))
+		return;
+
+	vcp_data_free(data);
+
+	if (queue_isempty(sessions)) {
+		queue_destroy(sessions, NULL);
+		sessions = NULL;
+	}
+}
+
+static void vcp_detached(struct bt_vcp *vcp, void *user_data)
+{
+	struct vcp_data *data;
+
+	DBG("%p", vcp);
+
+	data = queue_find(sessions, match_data, vcp);
+	if (!data) {
+		error("Unable to find vcp session");
+		return;
+	}
+
+	vcp_data_remove(data);
+}
+
+static void vcp_attached(struct bt_vcp *vcp, void *user_data)
+{
+	struct vcp_data *data;
+	struct bt_att *att;
+	struct btd_device *device;
+
+	DBG("%p", vcp);
+
+	data = queue_find(sessions, match_data, vcp);
+	if (data)
+		return;
+
+	att = bt_vcp_get_att(vcp);
+	if (!att)
+		return;
+
+	device = btd_adapter_find_device_by_fd(bt_att_get_fd(att));
+	if (!device) {
+		error("Unable to find device");
+		return;
+	}
+
+	data = vcp_data_new(device);
+	data->vcp = vcp;
+
+	vcp_data_add(data);
+
+}
+
+static int vcp_probe(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct btd_adapter *adapter = device_get_adapter(device);
+	struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+	struct vcp_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	/* Ignore, if we were probed for this device already */
+	if (data) {
+		error("Profile probed twice for the same device!");
+		return -EINVAL;
+	}
+
+	data = vcp_data_new(device);
+	data->service = service;
+
+	data->vcp = bt_vcp_new(btd_gatt_database_get_db(database),
+					btd_device_get_gatt_db(device));
+	if (!data->vcp) {
+		error("Unable to create VCP instance");
+		free(data);
+		return -EINVAL;
+	}
+
+	vcp_data_add(data);
+
+	bt_vcp_set_user_data(data->vcp, service);
+
+	return 0;
+}
+
+static void vcp_remove(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct vcp_data *data;
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	data = btd_service_get_user_data(service);
+	if (!data) {
+		error("VCP service not handled by profile");
+		return;
+	}
+
+	vcp_data_remove(data);
+}
+
+static int vcp_accept(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct bt_gatt_client *client = btd_device_get_gatt_client(device);
+	struct vcp_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	if (!data) {
+		error("VCP service not handled by profile");
+		return -EINVAL;
+	}
+
+	if (!bt_vcp_attach(data->vcp, client)) {
+		error("VCP unable to attach");
+		return -EINVAL;
+	}
+
+	btd_service_connecting_complete(service, 0);
+
+	return 0;
+}
+
+static int vcp_server_probe(struct btd_profile *p,
+				  struct btd_adapter *adapter)
+{
+	struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+
+	DBG("VCP path %s", adapter_get_path(adapter));
+
+	bt_vcp_add_db(btd_gatt_database_get_db(database));
+
+	return 0;
+}
+
+static void vcp_server_remove(struct btd_profile *p,
+					struct btd_adapter *adapter)
+{
+	DBG("VCP remove Adapter");
+}
+
+static struct btd_profile vcp_profile = {
+	.name		= "vcp",
+	.priority	= BTD_PROFILE_PRIORITY_MEDIUM,
+	.remote_uuid	= VCS_UUID_STR,
+
+	.device_probe	= vcp_probe,
+	.device_remove	= vcp_remove,
+
+	.accept		= vcp_accept,
+	.disconnect	= vcp_disconnect,
+
+	.adapter_probe = vcp_server_probe,
+	.adapter_remove = vcp_server_remove,
+};
+
+static unsigned int vcp_id = 0;
+
+static int vcp_init(void)
+{
+	if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) {
+		warn("D-Bus experimental not enabled");
+		return -ENOTSUP;
+	}
+
+	btd_profile_register(&vcp_profile);
+	vcp_id = bt_vcp_register(vcp_attached, vcp_detached, NULL);
+
+	return 0;
+}
+
+static void vcp_exit(void)
+{
+	if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
+		btd_profile_unregister(&vcp_profile);
+		bt_vcp_unregister(vcp_id);
+	}
+}
+
+BLUETOOTH_PLUGIN_DEFINE(vcp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+							vcp_init, vcp_exit)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH BlueZ v2 4/4] monitor/att: Add decoding support for Volume Control Serice
  2022-09-15  9:54 [PATCH BlueZ v2 1/4] lib/uuid: Add VCS UUIDs Sathish Narasimman
  2022-09-15  9:54 ` [PATCH BlueZ v2 2/4] shared/vcp: Add initial code for handling VCP Sathish Narasimman
  2022-09-15  9:54 ` [PATCH BlueZ v2 3/4] profiles: Add initial code for vcp plugin Sathish Narasimman
@ 2022-09-15  9:54 ` Sathish Narasimman
  2022-09-15 20:59   ` Luiz Augusto von Dentz
  2022-09-15 11:36 ` [BlueZ,v2,1/4] lib/uuid: Add VCS UUIDs bluez.test.bot
  2022-09-15 21:20 ` [PATCH BlueZ v2 1/4] " patchwork-bot+bluetooth
  4 siblings, 1 reply; 9+ messages in thread
From: Sathish Narasimman @ 2022-09-15  9:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This adds decoding support for VCS attributes

> ACL Data RX: Handle 3585 flags 0x02 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x0017 Type: Volume State (0x2b7d)
< ACL Data TX: Handle 3585 flags 0x00 dlen 8
      ATT: Read Response (0x0b) len 3
        Value: 000000
        Handle: 0x0017 Type: Volume State (0x2b7d)
            Volume Setting: 0
            Not Muted: 0
            Change Counter: 0
> HCI Event: Number of Completed Packets (0x13) plen 5
        Num handles: 1
        Handle: 3585 Address: 49:71:FC:C0:66:C6 (Resolvable)
        Count: 1
> ACL Data RX: Handle 3585 flags 0x02 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x001c Type: Volume Flags (0x2b7f)
< ACL Data TX: Handle 3585 flags 0x00 dlen 6
      ATT: Read Response (0x0b) len 1
        Value: 01
        Handle: 0x001c Type: Volume Flags (0x2b7f)
            Volume Falg: 1
---
 monitor/att.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)

diff --git a/monitor/att.c b/monitor/att.c
index b7470f7a2ff4..3c1ff2e2aaa0 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -1590,6 +1590,162 @@ static void pac_context_notify(const struct l2cap_frame *frame)
 	print_pac_context(frame);
 }
 
+static void print_vcs_state(const struct l2cap_frame *frame)
+{
+	uint8_t vol_set, mute, chng_ctr;
+
+	if (!l2cap_frame_get_u8((void *)frame, &vol_set)) {
+		print_text(COLOR_ERROR, "Volume Settings: invalid size");
+		goto done;
+	}
+	print_field("    Volume Setting: %u", vol_set);
+
+	if (!l2cap_frame_get_u8((void *)frame, &mute)) {
+		print_text(COLOR_ERROR, "Mute Filed: invalid size");
+		goto done;
+	}
+
+	switch (mute) {
+	case 0x00:
+		print_field("    Not Muted: %u", mute);
+		break;
+	case 0x01:
+		print_field("    Muted: %u", mute);
+		break;
+	default:
+		print_field("    Unknown Mute Value: %u", mute);
+		break;
+	}
+
+	if (!l2cap_frame_get_u8((void *)frame, &chng_ctr)) {
+		print_text(COLOR_ERROR, "Change Counter: invalid size");
+		goto done;
+	}
+	print_field("    Change Counter: %u", chng_ctr);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void vol_state_read(const struct l2cap_frame *frame)
+{
+	print_vcs_state(frame);
+}
+
+static void vol_state_notify(const struct l2cap_frame *frame)
+{
+	print_vcs_state(frame);
+}
+
+static bool vcs_config_cmd(const struct l2cap_frame *frame)
+{
+	if (!l2cap_frame_print_u8((void *)frame, "    Change Counter"))
+		return false;
+
+	return true;
+}
+
+static bool vcs_absolute_cmd(const struct l2cap_frame *frame)
+{
+	if (!l2cap_frame_print_u8((void *)frame, "    Change Counter"))
+		return false;
+
+	if (!l2cap_frame_print_u8((void *)frame, "    Volume Setting"))
+		return false;
+
+	return true;
+}
+
+#define ASE_CMD(_op, _desc, _func) \
+[_op] = { \
+	.desc = _desc, \
+	.func = _func, \
+}
+
+struct vcs_cmd {
+	const char *desc;
+	bool (*func)(const struct l2cap_frame *frame);
+} vcs_cmd_table[] = {
+	/* Opcode = 0x00 (Relative Volume Down) */
+	ASE_CMD(0x00, "Relative Volume Down", vcs_config_cmd),
+	/* Opcode = 0x01 (Relative Volume Up) */
+	ASE_CMD(0x01, "Relative Volume Up", vcs_config_cmd),
+	/* Opcode = 0x02 (Unmute/Relative Volume Down) */
+	ASE_CMD(0x02, "Unmute/Relative Volume Down", vcs_config_cmd),
+	/* Opcode = 0x03 (Unmute/Relative Volume Up) */
+	ASE_CMD(0x03, "Unmute/Relative Volume Up", vcs_config_cmd),
+	/* Opcode = 0x04 (Set Absolute Volume) */
+	ASE_CMD(0x04, "Set Absolute Volume", vcs_absolute_cmd),
+	/* Opcode = 0x05 (Unmute) */
+	ASE_CMD(0x05, "Unmute", vcs_config_cmd),
+	/* Opcode = 0x06 (Mute) */
+	ASE_CMD(0x06, "Mute", vcs_config_cmd),
+};
+
+static struct vcs_cmd *vcs_get_cmd(uint8_t op)
+{
+	if (op > ARRAY_SIZE(vcs_cmd_table))
+		return NULL;
+
+	return &vcs_cmd_table[op];
+}
+
+static void print_vcs_cmd(const struct l2cap_frame *frame)
+{
+	uint8_t op;
+	struct vcs_cmd *cmd;
+
+	if (!l2cap_frame_get_u8((void *)frame, &op)) {
+		print_text(COLOR_ERROR, "opcode: invalid size");
+		goto done;
+	}
+
+	cmd = vcs_get_cmd(op);
+	if (!cmd) {
+		print_field("    Opcode: Reserved (0x%2.2x)", op);
+		goto done;
+	}
+
+	print_field("    Opcode: %s (0x%2.2x)", cmd->desc, op);
+	if (!cmd->func(frame))
+		print_field("    Unknown Opcode");
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void vol_cp_write(const struct l2cap_frame *frame)
+{
+	print_vcs_cmd(frame);
+}
+
+static void print_vcs_flag(const struct l2cap_frame *frame)
+{
+	uint8_t vol_flag;
+
+	if (!l2cap_frame_get_u8((void *)frame, &vol_flag)) {
+		print_text(COLOR_ERROR, "Volume Flag: invalid size");
+		goto done;
+	}
+	print_field("    Volume Falg: %u", vol_flag);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void vol_flag_read(const struct l2cap_frame *frame)
+{
+	print_vcs_flag(frame);
+}
+
+static void vol_flag_notify(const struct l2cap_frame *frame)
+{
+	print_vcs_flag(frame);
+}
+
 #define GATT_HANDLER(_uuid, _read, _write, _notify) \
 { \
 	.uuid = { \
@@ -1617,6 +1773,9 @@ struct gatt_handler {
 	GATT_HANDLER(0x2bcc, pac_loc_read, NULL, pac_loc_notify),
 	GATT_HANDLER(0x2bcd, pac_context_read, NULL, pac_context_notify),
 	GATT_HANDLER(0x2bce, pac_context_read, NULL, pac_context_notify),
+	GATT_HANDLER(0x2b7d, vol_state_read, NULL, vol_state_notify),
+	GATT_HANDLER(0x2b7e, NULL, vol_cp_write, NULL),
+	GATT_HANDLER(0x2b7f, vol_flag_read, NULL, vol_flag_notify),
 };
 
 static struct gatt_handler *get_handler(struct gatt_db_attribute *attr)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* RE: [BlueZ,v2,1/4] lib/uuid: Add VCS UUIDs
  2022-09-15  9:54 [PATCH BlueZ v2 1/4] lib/uuid: Add VCS UUIDs Sathish Narasimman
                   ` (2 preceding siblings ...)
  2022-09-15  9:54 ` [PATCH BlueZ v2 4/4] monitor/att: Add decoding support for Volume Control Serice Sathish Narasimman
@ 2022-09-15 11:36 ` bluez.test.bot
  2022-09-15 21:00   ` Luiz Augusto von Dentz
  2022-09-15 21:20 ` [PATCH BlueZ v2 1/4] " patchwork-bot+bluetooth
  4 siblings, 1 reply; 9+ messages in thread
From: bluez.test.bot @ 2022-09-15 11:36 UTC (permalink / raw)
  To: linux-bluetooth, sathish.narasimman

[-- Attachment #1: Type: text/plain, Size: 6174 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=677268

---Test result---

Test Summary:
CheckPatch                    FAIL      4.02 seconds
GitLint                       PASS      1.89 seconds
Prep - Setup ELL              PASS      33.60 seconds
Build - Prep                  PASS      0.77 seconds
Build - Configure             PASS      10.44 seconds
Build - Make                  PASS      1169.04 seconds
Make Check                    PASS      12.60 seconds
Make Check w/Valgrind         PASS      356.41 seconds
Make Distcheck                PASS      304.10 seconds
Build w/ext ELL - Configure   PASS      11.04 seconds
Build w/ext ELL - Make        PASS      108.76 seconds
Incremental Build w/ patches  PASS      511.45 seconds
Scan Build                    WARNING   1239.48 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script with rule in .checkpatch.conf
Output:
[BlueZ,v2,2/4] shared/vcp: Add initial code for handling VCP
WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
#1154: FILE: src/shared/vcp.h:16:
+#define __packed __attribute__((packed))

/github/workspace/src/12977204.patch total: 0 errors, 1 warnings, 1106 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/12977204.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.

[BlueZ,v2,3/4] profiles: Add initial code for vcp plugin
ERROR:INITIALISED_STATIC: do not initialise statics to 0
#395: FILE: profiles/audio/vcp.c:288:
+static unsigned int vcp_id = 0;

/github/workspace/src/12977206.patch total: 1 errors, 0 warnings, 330 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/12977206.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: Scan Build - WARNING
Desc: Run Scan Build with patches
Output:
*****************************************************************************
The bugs reported by the scan-build may or may not be caused by your patches.
Please check the list and fix the bugs if they are caused by your patch.
*****************************************************************************
src/shared/vcp.c:285:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
        if (!vdb && !vdb->vcs)
                     ^~~~~~~~
src/shared/vcp.c:294:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
        if (*change_counter != vstate->counter) {
                               ^~~~~~~~~~~~~~~
src/shared/vcp.c:318:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
        if (!vdb && !vdb->vcs)
                     ^~~~~~~~
src/shared/vcp.c:327:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
        if (*change_counter != vstate->counter) {
                               ^~~~~~~~~~~~~~~
src/shared/vcp.c:351:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
        if (!vdb && !vdb->vcs)
                     ^~~~~~~~
src/shared/vcp.c:360:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
        if (*change_counter != vstate->counter) {
                               ^~~~~~~~~~~~~~~
src/shared/vcp.c:385:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
        if (!vdb && !vdb->vcs)
                     ^~~~~~~~
src/shared/vcp.c:394:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
        if (*change_counter != vstate->counter) {
                               ^~~~~~~~~~~~~~~
src/shared/vcp.c:419:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
        if (!vdb && !vdb->vcs)
                     ^~~~~~~~
src/shared/vcp.c:428:29: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
        if (req->change_counter != vstate->counter) {
                                   ^~~~~~~~~~~~~~~
src/shared/vcp.c:452:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
        if (!vdb && !vdb->vcs)
                     ^~~~~~~~
src/shared/vcp.c:461:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
        if (*change_counter != vstate->counter) {
                               ^~~~~~~~~~~~~~~
src/shared/vcp.c:485:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
        if (!vdb && !vdb->vcs)
                     ^~~~~~~~
src/shared/vcp.c:494:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
        if (*change_counter != vstate->counter) {
                               ^~~~~~~~~~~~~~~
14 warnings generated.




---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH BlueZ v2 4/4] monitor/att: Add decoding support for Volume Control Serice
  2022-09-15  9:54 ` [PATCH BlueZ v2 4/4] monitor/att: Add decoding support for Volume Control Serice Sathish Narasimman
@ 2022-09-15 20:59   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2022-09-15 20:59 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hi Sathish,

On Thu, Sep 15, 2022 at 3:11 AM Sathish Narasimman
<sathish.narasimman@intel.com> wrote:
>
> This adds decoding support for VCS attributes
>
> > ACL Data RX: Handle 3585 flags 0x02 dlen 7
>       ATT: Read Request (0x0a) len 2
>         Handle: 0x0017 Type: Volume State (0x2b7d)
> < ACL Data TX: Handle 3585 flags 0x00 dlen 8
>       ATT: Read Response (0x0b) len 3
>         Value: 000000
>         Handle: 0x0017 Type: Volume State (0x2b7d)
>             Volume Setting: 0
>             Not Muted: 0
>             Change Counter: 0
> > HCI Event: Number of Completed Packets (0x13) plen 5
>         Num handles: 1
>         Handle: 3585 Address: 49:71:FC:C0:66:C6 (Resolvable)
>         Count: 1
> > ACL Data RX: Handle 3585 flags 0x02 dlen 7
>       ATT: Read Request (0x0a) len 2
>         Handle: 0x001c Type: Volume Flags (0x2b7f)
> < ACL Data TX: Handle 3585 flags 0x00 dlen 6
>       ATT: Read Response (0x0b) len 1
>         Value: 01
>         Handle: 0x001c Type: Volume Flags (0x2b7f)
>             Volume Falg: 1
> ---
>  monitor/att.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 159 insertions(+)
>
> diff --git a/monitor/att.c b/monitor/att.c
> index b7470f7a2ff4..3c1ff2e2aaa0 100644
> --- a/monitor/att.c
> +++ b/monitor/att.c
> @@ -1590,6 +1590,162 @@ static void pac_context_notify(const struct l2cap_frame *frame)
>         print_pac_context(frame);
>  }
>
> +static void print_vcs_state(const struct l2cap_frame *frame)
> +{
> +       uint8_t vol_set, mute, chng_ctr;
> +
> +       if (!l2cap_frame_get_u8((void *)frame, &vol_set)) {
> +               print_text(COLOR_ERROR, "Volume Settings: invalid size");
> +               goto done;
> +       }
> +       print_field("    Volume Setting: %u", vol_set);
> +
> +       if (!l2cap_frame_get_u8((void *)frame, &mute)) {
> +               print_text(COLOR_ERROR, "Mute Filed: invalid size");
> +               goto done;
> +       }
> +
> +       switch (mute) {
> +       case 0x00:
> +               print_field("    Not Muted: %u", mute);
> +               break;
> +       case 0x01:
> +               print_field("    Muted: %u", mute);
> +               break;
> +       default:
> +               print_field("    Unknown Mute Value: %u", mute);
> +               break;
> +       }
> +
> +       if (!l2cap_frame_get_u8((void *)frame, &chng_ctr)) {
> +               print_text(COLOR_ERROR, "Change Counter: invalid size");
> +               goto done;
> +       }
> +       print_field("    Change Counter: %u", chng_ctr);
> +
> +done:
> +       if (frame->size)
> +               print_hex_field("  Data", frame->data, frame->size);
> +}
> +
> +static void vol_state_read(const struct l2cap_frame *frame)
> +{
> +       print_vcs_state(frame);
> +}
> +
> +static void vol_state_notify(const struct l2cap_frame *frame)
> +{
> +       print_vcs_state(frame);
> +}
> +
> +static bool vcs_config_cmd(const struct l2cap_frame *frame)
> +{
> +       if (!l2cap_frame_print_u8((void *)frame, "    Change Counter"))
> +               return false;
> +
> +       return true;
> +}
> +
> +static bool vcs_absolute_cmd(const struct l2cap_frame *frame)
> +{
> +       if (!l2cap_frame_print_u8((void *)frame, "    Change Counter"))
> +               return false;
> +
> +       if (!l2cap_frame_print_u8((void *)frame, "    Volume Setting"))
> +               return false;
> +
> +       return true;
> +}
> +
> +#define ASE_CMD(_op, _desc, _func) \
> +[_op] = { \
> +       .desc = _desc, \
> +       .func = _func, \
> +}

Well those are not really ASE commands so Id probably reword that to
be VCS_CMD instead.

> +struct vcs_cmd {
> +       const char *desc;
> +       bool (*func)(const struct l2cap_frame *frame);
> +} vcs_cmd_table[] = {
> +       /* Opcode = 0x00 (Relative Volume Down) */
> +       ASE_CMD(0x00, "Relative Volume Down", vcs_config_cmd),
> +       /* Opcode = 0x01 (Relative Volume Up) */
> +       ASE_CMD(0x01, "Relative Volume Up", vcs_config_cmd),
> +       /* Opcode = 0x02 (Unmute/Relative Volume Down) */
> +       ASE_CMD(0x02, "Unmute/Relative Volume Down", vcs_config_cmd),
> +       /* Opcode = 0x03 (Unmute/Relative Volume Up) */
> +       ASE_CMD(0x03, "Unmute/Relative Volume Up", vcs_config_cmd),
> +       /* Opcode = 0x04 (Set Absolute Volume) */
> +       ASE_CMD(0x04, "Set Absolute Volume", vcs_absolute_cmd),
> +       /* Opcode = 0x05 (Unmute) */
> +       ASE_CMD(0x05, "Unmute", vcs_config_cmd),
> +       /* Opcode = 0x06 (Mute) */
> +       ASE_CMD(0x06, "Mute", vcs_config_cmd),
> +};
> +
> +static struct vcs_cmd *vcs_get_cmd(uint8_t op)
> +{
> +       if (op > ARRAY_SIZE(vcs_cmd_table))
> +               return NULL;
> +
> +       return &vcs_cmd_table[op];
> +}
> +
> +static void print_vcs_cmd(const struct l2cap_frame *frame)
> +{
> +       uint8_t op;
> +       struct vcs_cmd *cmd;
> +
> +       if (!l2cap_frame_get_u8((void *)frame, &op)) {
> +               print_text(COLOR_ERROR, "opcode: invalid size");
> +               goto done;
> +       }
> +
> +       cmd = vcs_get_cmd(op);
> +       if (!cmd) {
> +               print_field("    Opcode: Reserved (0x%2.2x)", op);
> +               goto done;
> +       }
> +
> +       print_field("    Opcode: %s (0x%2.2x)", cmd->desc, op);
> +       if (!cmd->func(frame))
> +               print_field("    Unknown Opcode");
> +
> +done:
> +       if (frame->size)
> +               print_hex_field("  Data", frame->data, frame->size);
> +}
> +
> +static void vol_cp_write(const struct l2cap_frame *frame)
> +{
> +       print_vcs_cmd(frame);
> +}
> +
> +static void print_vcs_flag(const struct l2cap_frame *frame)
> +{
> +       uint8_t vol_flag;
> +
> +       if (!l2cap_frame_get_u8((void *)frame, &vol_flag)) {
> +               print_text(COLOR_ERROR, "Volume Flag: invalid size");
> +               goto done;
> +       }
> +       print_field("    Volume Falg: %u", vol_flag);
> +
> +done:
> +       if (frame->size)
> +               print_hex_field("  Data", frame->data, frame->size);
> +}
> +
> +static void vol_flag_read(const struct l2cap_frame *frame)
> +{
> +       print_vcs_flag(frame);
> +}
> +
> +static void vol_flag_notify(const struct l2cap_frame *frame)
> +{
> +       print_vcs_flag(frame);
> +}
> +
>  #define GATT_HANDLER(_uuid, _read, _write, _notify) \
>  { \
>         .uuid = { \
> @@ -1617,6 +1773,9 @@ struct gatt_handler {
>         GATT_HANDLER(0x2bcc, pac_loc_read, NULL, pac_loc_notify),
>         GATT_HANDLER(0x2bcd, pac_context_read, NULL, pac_context_notify),
>         GATT_HANDLER(0x2bce, pac_context_read, NULL, pac_context_notify),
> +       GATT_HANDLER(0x2b7d, vol_state_read, NULL, vol_state_notify),
> +       GATT_HANDLER(0x2b7e, NULL, vol_cp_write, NULL),
> +       GATT_HANDLER(0x2b7f, vol_flag_read, NULL, vol_flag_notify),
>  };
>
>  static struct gatt_handler *get_handler(struct gatt_db_attribute *attr)
> --
> 2.25.1
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [BlueZ,v2,1/4] lib/uuid: Add VCS UUIDs
  2022-09-15 11:36 ` [BlueZ,v2,1/4] lib/uuid: Add VCS UUIDs bluez.test.bot
@ 2022-09-15 21:00   ` Luiz Augusto von Dentz
  2022-09-16  5:02     ` Sathish Narasimman
  0 siblings, 1 reply; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2022-09-15 21:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: sathish.narasimman

Hi Sathish,

On Thu, Sep 15, 2022 at 4:41 AM <bluez.test.bot@gmail.com> wrote:
>
> This is automated email and please do not reply to this email!
>
> Dear submitter,
>
> Thank you for submitting the patches to the linux bluetooth mailing list.
> This is a CI test results with your patch series:
> PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=677268
>
> ---Test result---
>
> Test Summary:
> CheckPatch                    FAIL      4.02 seconds
> GitLint                       PASS      1.89 seconds
> Prep - Setup ELL              PASS      33.60 seconds
> Build - Prep                  PASS      0.77 seconds
> Build - Configure             PASS      10.44 seconds
> Build - Make                  PASS      1169.04 seconds
> Make Check                    PASS      12.60 seconds
> Make Check w/Valgrind         PASS      356.41 seconds
> Make Distcheck                PASS      304.10 seconds
> Build w/ext ELL - Configure   PASS      11.04 seconds
> Build w/ext ELL - Make        PASS      108.76 seconds
> Incremental Build w/ patches  PASS      511.45 seconds
> Scan Build                    WARNING   1239.48 seconds
>
> Details
> ##############################
> Test: CheckPatch - FAIL
> Desc: Run checkpatch.pl script with rule in .checkpatch.conf
> Output:
> [BlueZ,v2,2/4] shared/vcp: Add initial code for handling VCP
> WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
> #1154: FILE: src/shared/vcp.h:16:
> +#define __packed __attribute__((packed))
>
> /github/workspace/src/12977204.patch total: 0 errors, 1 warnings, 1106 lines checked
>
> NOTE: For some of the reported defects, checkpatch may be able to
>       mechanically convert to the typical style using --fix or --fix-inplace.
>
> /github/workspace/src/12977204.patch has style problems, please review.
>
> NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
>
> NOTE: If any of the errors are false positives, please report
>       them to the maintainer, see CHECKPATCH in MAINTAINERS.
>
> [BlueZ,v2,3/4] profiles: Add initial code for vcp plugin
> ERROR:INITIALISED_STATIC: do not initialise statics to 0
> #395: FILE: profiles/audio/vcp.c:288:
> +static unsigned int vcp_id = 0;
>
> /github/workspace/src/12977206.patch total: 1 errors, 0 warnings, 330 lines checked
>
> NOTE: For some of the reported defects, checkpatch may be able to
>       mechanically convert to the typical style using --fix or --fix-inplace.
>
> /github/workspace/src/12977206.patch has style problems, please review.
>
> NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
>
> NOTE: If any of the errors are false positives, please report
>       them to the maintainer, see CHECKPATCH in MAINTAINERS.
>
>
> ##############################
> Test: Scan Build - WARNING
> Desc: Run Scan Build with patches
> Output:
> *****************************************************************************
> The bugs reported by the scan-build may or may not be caused by your patches.
> Please check the list and fix the bugs if they are caused by your patch.
> *****************************************************************************
> src/shared/vcp.c:285:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
>         if (!vdb && !vdb->vcs)
>                      ^~~~~~~~
> src/shared/vcp.c:294:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
>         if (*change_counter != vstate->counter) {
>                                ^~~~~~~~~~~~~~~
> src/shared/vcp.c:318:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
>         if (!vdb && !vdb->vcs)
>                      ^~~~~~~~
> src/shared/vcp.c:327:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
>         if (*change_counter != vstate->counter) {
>                                ^~~~~~~~~~~~~~~
> src/shared/vcp.c:351:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
>         if (!vdb && !vdb->vcs)
>                      ^~~~~~~~
> src/shared/vcp.c:360:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
>         if (*change_counter != vstate->counter) {
>                                ^~~~~~~~~~~~~~~
> src/shared/vcp.c:385:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
>         if (!vdb && !vdb->vcs)
>                      ^~~~~~~~
> src/shared/vcp.c:394:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
>         if (*change_counter != vstate->counter) {
>                                ^~~~~~~~~~~~~~~
> src/shared/vcp.c:419:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
>         if (!vdb && !vdb->vcs)
>                      ^~~~~~~~
> src/shared/vcp.c:428:29: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
>         if (req->change_counter != vstate->counter) {
>                                    ^~~~~~~~~~~~~~~
> src/shared/vcp.c:452:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
>         if (!vdb && !vdb->vcs)
>                      ^~~~~~~~
> src/shared/vcp.c:461:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
>         if (*change_counter != vstate->counter) {
>                                ^~~~~~~~~~~~~~~
> src/shared/vcp.c:485:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
>         if (!vdb && !vdb->vcs)
>                      ^~~~~~~~
> src/shared/vcp.c:494:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
>         if (*change_counter != vstate->counter) {
>                                ^~~~~~~~~~~~~~~
> 14 warnings generated.

Lets have these warnings fixed so vstate needs to be checked.

>
>
>
> ---
> Regards,
> Linux Bluetooth
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH BlueZ v2 1/4] lib/uuid: Add VCS UUIDs
  2022-09-15  9:54 [PATCH BlueZ v2 1/4] lib/uuid: Add VCS UUIDs Sathish Narasimman
                   ` (3 preceding siblings ...)
  2022-09-15 11:36 ` [BlueZ,v2,1/4] lib/uuid: Add VCS UUIDs bluez.test.bot
@ 2022-09-15 21:20 ` patchwork-bot+bluetooth
  4 siblings, 0 replies; 9+ messages in thread
From: patchwork-bot+bluetooth @ 2022-09-15 21:20 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Thu, 15 Sep 2022 15:24:09 +0530 you wrote:
> This adds Volume Control Service UUIDs which will be used by
> Volume Control Profile.
> ---
>  lib/uuid.h | 7 +++++++
>  1 file changed, 7 insertions(+)

Here is the summary with links:
  - [BlueZ,v2,1/4] lib/uuid: Add VCS UUIDs
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=af1bfbb470c0
  - [BlueZ,v2,2/4] shared/vcp: Add initial code for handling VCP
    (no matching commit)
  - [BlueZ,v2,3/4] profiles: Add initial code for vcp plugin
    (no matching commit)
  - [BlueZ,v2,4/4] monitor/att: Add decoding support for Volume Control Serice
    (no matching commit)

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [BlueZ,v2,1/4] lib/uuid: Add VCS UUIDs
  2022-09-15 21:00   ` Luiz Augusto von Dentz
@ 2022-09-16  5:02     ` Sathish Narasimman
  0 siblings, 0 replies; 9+ messages in thread
From: Sathish Narasimman @ 2022-09-16  5:02 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth, sathish.narasimman

Hi Luiz

On Fri, Sep 16, 2022 at 2:37 AM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> Hi Sathish,
>
> On Thu, Sep 15, 2022 at 4:41 AM <bluez.test.bot@gmail.com> wrote:
> >
> > This is automated email and please do not reply to this email!
> >
> > Dear submitter,
> >
> > Thank you for submitting the patches to the linux bluetooth mailing list.
> > This is a CI test results with your patch series:
> > PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=677268
> >
> > ---Test result---
> >
> > Test Summary:
> > CheckPatch                    FAIL      4.02 seconds
> > GitLint                       PASS      1.89 seconds
> > Prep - Setup ELL              PASS      33.60 seconds
> > Build - Prep                  PASS      0.77 seconds
> > Build - Configure             PASS      10.44 seconds
> > Build - Make                  PASS      1169.04 seconds
> > Make Check                    PASS      12.60 seconds
> > Make Check w/Valgrind         PASS      356.41 seconds
> > Make Distcheck                PASS      304.10 seconds
> > Build w/ext ELL - Configure   PASS      11.04 seconds
> > Build w/ext ELL - Make        PASS      108.76 seconds
> > Incremental Build w/ patches  PASS      511.45 seconds
> > Scan Build                    WARNING   1239.48 seconds
> >
> > Details
> > ##############################
> > Test: CheckPatch - FAIL
> > Desc: Run checkpatch.pl script with rule in .checkpatch.conf
> > Output:
> > [BlueZ,v2,2/4] shared/vcp: Add initial code for handling VCP
> > WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
> > #1154: FILE: src/shared/vcp.h:16:
> > +#define __packed __attribute__((packed))
> >
> > /github/workspace/src/12977204.patch total: 0 errors, 1 warnings, 1106 lines checked
> >
> > NOTE: For some of the reported defects, checkpatch may be able to
> >       mechanically convert to the typical style using --fix or --fix-inplace.
> >
> > /github/workspace/src/12977204.patch has style problems, please review.
> >
> > NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
> >
> > NOTE: If any of the errors are false positives, please report
> >       them to the maintainer, see CHECKPATCH in MAINTAINERS.
> >
> > [BlueZ,v2,3/4] profiles: Add initial code for vcp plugin
> > ERROR:INITIALISED_STATIC: do not initialise statics to 0
> > #395: FILE: profiles/audio/vcp.c:288:
> > +static unsigned int vcp_id = 0;
> >
> > /github/workspace/src/12977206.patch total: 1 errors, 0 warnings, 330 lines checked
> >
> > NOTE: For some of the reported defects, checkpatch may be able to
> >       mechanically convert to the typical style using --fix or --fix-inplace.
> >
> > /github/workspace/src/12977206.patch has style problems, please review.
> >
> > NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
> >
> > NOTE: If any of the errors are false positives, please report
> >       them to the maintainer, see CHECKPATCH in MAINTAINERS.
> >
> >
> > ##############################
> > Test: Scan Build - WARNING
> > Desc: Run Scan Build with patches
> > Output:
> > *****************************************************************************
> > The bugs reported by the scan-build may or may not be caused by your patches.
> > Please check the list and fix the bugs if they are caused by your patch.
> > *****************************************************************************
> > src/shared/vcp.c:285:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
> >         if (!vdb && !vdb->vcs)
> >                      ^~~~~~~~
> > src/shared/vcp.c:294:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
> >         if (*change_counter != vstate->counter) {
> >                                ^~~~~~~~~~~~~~~
> > src/shared/vcp.c:318:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
> >         if (!vdb && !vdb->vcs)
> >                      ^~~~~~~~
> > src/shared/vcp.c:327:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
> >         if (*change_counter != vstate->counter) {
> >                                ^~~~~~~~~~~~~~~
> > src/shared/vcp.c:351:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
> >         if (!vdb && !vdb->vcs)
> >                      ^~~~~~~~
> > src/shared/vcp.c:360:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
> >         if (*change_counter != vstate->counter) {
> >                                ^~~~~~~~~~~~~~~
> > src/shared/vcp.c:385:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
> >         if (!vdb && !vdb->vcs)
> >                      ^~~~~~~~
> > src/shared/vcp.c:394:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
> >         if (*change_counter != vstate->counter) {
> >                                ^~~~~~~~~~~~~~~
> > src/shared/vcp.c:419:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
> >         if (!vdb && !vdb->vcs)
> >                      ^~~~~~~~
> > src/shared/vcp.c:428:29: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
> >         if (req->change_counter != vstate->counter) {
> >                                    ^~~~~~~~~~~~~~~
> > src/shared/vcp.c:452:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
> >         if (!vdb && !vdb->vcs)
> >                      ^~~~~~~~
> > src/shared/vcp.c:461:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
> >         if (*change_counter != vstate->counter) {
> >                                ^~~~~~~~~~~~~~~
> > src/shared/vcp.c:485:15: warning: Access to field 'vcs' results in a dereference of a null pointer (loaded from variable 'vdb')
> >         if (!vdb && !vdb->vcs)
> >                      ^~~~~~~~
> > src/shared/vcp.c:494:25: warning: Access to field 'counter' results in a dereference of a null pointer (loaded from variable 'vstate')
> >         if (*change_counter != vstate->counter) {
> >                                ^~~~~~~~~~~~~~~
> > 14 warnings generated.
>
> Lets have these warnings fixed so vstate needs to be checked.
Thanks for the review. Will Update for sure.
Is there a way I can run Checkpatch.pl locally?
>
> >
> >
> >
> > ---
> > Regards,
> > Linux Bluetooth
> >
>
>
> --
> Luiz Augusto von Dentz

Sathish N

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-09-16  5:02 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-15  9:54 [PATCH BlueZ v2 1/4] lib/uuid: Add VCS UUIDs Sathish Narasimman
2022-09-15  9:54 ` [PATCH BlueZ v2 2/4] shared/vcp: Add initial code for handling VCP Sathish Narasimman
2022-09-15  9:54 ` [PATCH BlueZ v2 3/4] profiles: Add initial code for vcp plugin Sathish Narasimman
2022-09-15  9:54 ` [PATCH BlueZ v2 4/4] monitor/att: Add decoding support for Volume Control Serice Sathish Narasimman
2022-09-15 20:59   ` Luiz Augusto von Dentz
2022-09-15 11:36 ` [BlueZ,v2,1/4] lib/uuid: Add VCS UUIDs bluez.test.bot
2022-09-15 21:00   ` Luiz Augusto von Dentz
2022-09-16  5:02     ` Sathish Narasimman
2022-09-15 21:20 ` [PATCH BlueZ v2 1/4] " patchwork-bot+bluetooth

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.