All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ayush Garg <ayush.garg@samsung.com>
To: linux-bluetooth@vger.kernel.org
Cc: anupam.r@samsung.com, nitin.j@samsung.com
Subject: [PATCH BlueZ 4/8] device: Add support for get/set PHY property
Date: Thu, 22 Jul 2021 11:19:47 +0530	[thread overview]
Message-ID: <20210722054951.8291-5-ayush.garg@samsung.com> (raw)
In-Reply-To: <20210722054951.8291-1-ayush.garg@samsung.com>

This change introduces a new device property
which will enable user to get PHYs of the current
LE Connection.
It will also allow to set preferred PHYs for
a particular LE connection.

Reviewed-by: Anupam Roy <anupam.r@samsung.com>
---
 lib/bluetooth.h |   9 ++
 src/adapter.c   |   8 ++
 src/adapter.h   |   1 +
 src/device.c    | 220 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 238 insertions(+)

diff --git a/lib/bluetooth.h b/lib/bluetooth.h
index 9ab033ec4..a6afaa753 100644
--- a/lib/bluetooth.h
+++ b/lib/bluetooth.h
@@ -127,6 +127,15 @@ struct bt_voice {
 #define BT_PHY_LE_2M_RX		0x00001000
 #define BT_PHY_LE_CODED_TX	0x00002000
 #define BT_PHY_LE_CODED_RX	0x00004000
+#define BT_PHY_LE_CODED_S2	0x00008000
+#define BT_PHY_LE_CODED_S8	0x00010000
+
+#define BT_PHY_LE_MASK (BT_PHY_LE_1M_TX | BT_PHY_LE_1M_RX | \
+				BT_PHY_LE_2M_TX | BT_PHY_LE_2M_RX | \
+				BT_PHY_LE_CODED_TX | BT_PHY_LE_CODED_RX)
+
+#define BT_PHY_LE_CODED_MASK (BT_PHY_LE_CODED_TX | \
+				BT_PHY_LE_CODED_RX)
 
 #define BT_MODE			15
 
diff --git a/src/adapter.c b/src/adapter.c
index 3861ade8a..5de92a570 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -6661,6 +6661,14 @@ const char *adapter_get_path(struct btd_adapter *adapter)
 	return adapter->path;
 }
 
+uint32_t adapter_get_supported_phys(struct btd_adapter *adapter)
+{
+	if (!adapter)
+		return 0;
+
+	return adapter->supported_phys;
+}
+
 const bdaddr_t *btd_adapter_get_address(struct btd_adapter *adapter)
 {
 	return &adapter->bdaddr;
diff --git a/src/adapter.h b/src/adapter.h
index 60b5e3bcc..21046ceaa 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -87,6 +87,7 @@ struct btd_device *btd_adapter_find_device_by_path(struct btd_adapter *adapter,
 						   const char *path);
 
 const char *adapter_get_path(struct btd_adapter *adapter);
+uint32_t adapter_get_supported_phys(struct btd_adapter *adapter);
 const bdaddr_t *btd_adapter_get_address(struct btd_adapter *adapter);
 uint8_t btd_adapter_get_address_type(struct btd_adapter *adapter);
 const char *btd_adapter_get_storage_dir(struct btd_adapter *adapter);
diff --git a/src/device.c b/src/device.c
index b29aa195d..6f74989c7 100644
--- a/src/device.c
+++ b/src/device.c
@@ -272,6 +272,9 @@ struct btd_device {
 
 	GIOChannel	*att_io;
 	guint		store_id;
+
+	uint32_t phys;
+	bool pending_phys;
 };
 
 static const uint16_t uuid_list[] = {
@@ -1470,6 +1473,212 @@ static gboolean dev_property_wake_allowed_exist(
 	return device_get_wake_support(device);
 }
 
+static struct phys_config {
+	uint32_t flag;
+	const char *name;
+} phys_str[] = {
+	{ BT_PHY_LE_1M_TX, "LE1MTX" },
+	{ BT_PHY_LE_1M_RX, "LE1MRX" },
+	{ BT_PHY_LE_2M_TX, "LE2MTX" },
+	{ BT_PHY_LE_2M_RX, "LE2MRX" },
+	{ BT_PHY_LE_CODED_TX, "LECODEDTX" },
+	{ BT_PHY_LE_CODED_RX, "LECODEDRX" },
+	{ BT_PHY_LE_CODED_S2, "LECODEDS2" },
+	{ BT_PHY_LE_CODED_S8, "LECODEDS8" }
+};
+
+static void append_phys_str(DBusMessageIter *array, uint32_t phys)
+{
+	unsigned int i;
+
+	for (i = 0; i < NELEM(phys_str); i++) {
+		if (phys & phys_str[i].flag)
+			dbus_message_iter_append_basic(array, DBUS_TYPE_STRING,
+						&phys_str[i].name);
+	}
+}
+
+static bool parse_phys_str(DBusMessageIter *array, uint32_t *phys)
+{
+	const char *str;
+	unsigned int i;
+
+	*phys = 0;
+
+	do {
+		if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_STRING)
+			return false;
+
+		dbus_message_iter_get_basic(array, &str);
+
+		for (i = 0; i < NELEM(phys_str); i++) {
+			if (!strcmp(str, phys_str[i].name)) {
+				*phys |= phys_str[i].flag;
+				break;
+			}
+		}
+
+		if (i == NELEM(phys_str))
+			return false;
+	} while (dbus_message_iter_next(array));
+
+	return true;
+}
+
+static void device_set_phy(struct btd_device *device, uint32_t phys)
+{
+	if (!device)
+		return;
+
+	DBG("Device PHYs %u", phys);
+
+	device->phys = phys;
+
+	g_dbus_emit_property_changed(dbus_conn, device->path,
+					DEVICE_INTERFACE, "Phy");
+
+}
+
+static int set_preferred_phy(struct btd_device *device, uint32_t phys)
+{
+	GIOChannel *io;
+	GError *gerr = NULL;
+	uint32_t supported_phys = 0;
+	int ret;
+
+	if (!device || !phys) {
+		error("Invalid arguments in method call");
+		return -EINVAL;
+	}
+
+	if (!device->le) {
+		error("Operation is not supported");
+		return -ENOTSUP;
+	}
+
+	if (!device->le_state.connected || !device->attrib) {
+		error("Device Not Connected");
+		return -ENOTCONN;
+	}
+
+	io = g_attrib_get_channel(device->attrib);
+
+	if (!io) {
+		error("Device Not Connected");
+		return -ENOTCONN;
+	}
+
+	supported_phys = adapter_get_supported_phys(device->adapter) &
+					BT_PHY_LE_MASK;
+
+	if (supported_phys & BT_PHY_LE_CODED_MASK) {
+		supported_phys |= BT_PHY_LE_CODED_S2;
+		supported_phys |= BT_PHY_LE_CODED_S8;
+	}
+
+	if (phys & ~supported_phys) {
+		error("Supplied phy(s) are not supported");
+		return -EINVAL;
+	}
+
+	if (device->pending_phys) {
+		error("Operation already in progress");
+		return -EINPROGRESS;
+	}
+
+	device->pending_phys = true;
+
+	if (device->phys == phys) {
+		device->pending_phys = false;
+		return 0;
+	}
+
+	bt_io_set(io, &gerr, BT_IO_OPT_PHY, phys, BT_IO_OPT_INVALID);
+
+	if (gerr) {
+		error("bt_io_set: %s", gerr->message);
+		device->pending_phys = false;
+		ret = gerr->code;
+		g_error_free(gerr);
+		return ret;
+	}
+
+	return 0;
+}
+
+static gboolean dev_property_get_phy(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct btd_device *device = data;
+	DBusMessageIter array;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
+
+	append_phys_str(&array, device->phys);
+
+	dbus_message_iter_close_container(iter, &array);
+
+	return TRUE;
+}
+
+static void dev_property_set_phy(const GDBusPropertyTable *property,
+					DBusMessageIter *value,
+					GDBusPendingPropertySet id, void *data)
+{
+	struct btd_device *device = data;
+	DBusMessageIter array;
+	uint32_t phys;
+	int ret;
+
+	if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_ARRAY) {
+		ret = -EINVAL;
+		goto failed;
+	}
+
+	dbus_message_iter_recurse(value, &array);
+
+	if (!parse_phys_str(&array, &phys)) {
+		ret = -EINVAL;
+		goto failed;
+	}
+
+	ret = set_preferred_phy(device, phys);
+
+	if (ret >= 0) {
+		g_dbus_pending_property_success(id);
+		return;
+	}
+
+failed:
+	switch (-ret) {
+	case EINVAL:
+		g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
+		break;
+	case ENOTSUP:
+		g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".NotSupported",
+					"Operation is not supported");
+		break;
+	case ENOTCONN:
+		g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".NotConnected",
+					"Device Not Connected");
+		break;
+	case EINPROGRESS:
+		g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InProgress",
+					"Operation already in progress");
+		break;
+	default:
+		g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+							strerror(-ret));
+		break;
+	}
+
+}
+
 static bool disconnect_all(gpointer user_data)
 {
 	struct btd_device *device = user_data;
@@ -2950,6 +3159,7 @@ static const GDBusPropertyTable device_properties[] = {
 	{ "WakeAllowed", "b", dev_property_get_wake_allowed,
 				dev_property_set_wake_allowed,
 				dev_property_wake_allowed_exist },
+	{ "Phy", "as", dev_property_get_phy, dev_property_set_phy },
 	{ }
 };
 
@@ -3017,6 +3227,12 @@ void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type)
 	state->connected = false;
 	device->general_connect = FALSE;
 
+	/* Reset PHYs if LE connection is disconnected */
+	if (bdaddr_type != BDADDR_BREDR) {
+		device->pending_phys = false;
+		device_set_phy(device, 0);
+	}
+
 	device_set_svc_refreshed(device, false);
 
 	if (device->disconn_timer > 0) {
@@ -5305,10 +5521,12 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
 	struct btd_gatt_database *database;
 	const bdaddr_t *dst;
 	char dstaddr[18];
+	uint32_t phys;
 
 	bt_io_get(io, &gerr, BT_IO_OPT_SEC_LEVEL, &sec_level,
 						BT_IO_OPT_IMTU, &mtu,
 						BT_IO_OPT_CID, &cid,
+						BT_IO_OPT_PHY, &phys,
 						BT_IO_OPT_INVALID);
 
 	if (gerr) {
@@ -5358,6 +5576,8 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
 	dev->attrib = attrib;
 	dev->att = g_attrib_get_att(attrib);
 
+	device_set_phy(dev, phys);
+
 	bt_att_ref(dev->att);
 
 	bt_att_set_debug(dev->att, BT_ATT_DEBUG, gatt_debug, NULL, NULL);
-- 
2.17.1


  parent reply	other threads:[~2021-07-22  6:01 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20210722055008epcas5p28da6985b690d3bbc564a5957c1b209f4@epcas5p2.samsung.com>
2021-07-22  5:49 ` [PATCH BlueZ 0/8] Support for connection specific LE PHY configuration Ayush Garg
     [not found]   ` <CGME20210722055009epcas5p25e4997aa7e53cb2a6e3780fdb7301785@epcas5p2.samsung.com>
2021-07-22  5:49     ` [PATCH BlueZ 1/8] doc/device-api: Add Phy property Ayush Garg
2021-07-22 17:33       ` Luiz Augusto von Dentz
     [not found]   ` <CGME20210722055010epcas5p45a16ff704c37d108a9df0d6c0a1942a8@epcas5p4.samsung.com>
2021-07-22  5:49     ` [PATCH BlueZ 2/8] doc/mgmt-api: Add support for LE PHY Update Complete event Ayush Garg
2021-07-22 14:45       ` Marcel Holtmann
     [not found]   ` <CGME20210722055011epcas5p15299bfe8f8b8dd58e1354364071608e3@epcas5p1.samsung.com>
2021-07-22  5:49     ` [PATCH BlueZ 3/8] btio: Add BT_IO_PHY option to set le phy options Ayush Garg
     [not found]   ` <CGME20210722055012epcas5p1bb92b3e31233da03906c4f562b22b4fc@epcas5p1.samsung.com>
2021-07-22  5:49     ` Ayush Garg [this message]
     [not found]   ` <CGME20210722055013epcas5p350d88f402bbe4c55f1f868dbb2decbaf@epcas5p3.samsung.com>
2021-07-22  5:49     ` [PATCH BlueZ 5/8] adapter: Add support for LE PHY Update Complete event Ayush Garg
     [not found]   ` <CGME20210722055015epcas5p4db389aa15f16f1577a74ba5ce446919b@epcas5p4.samsung.com>
2021-07-22  5:49     ` [PATCH BlueZ 6/8] client: Add support for LE get/set device PHY in bluetoothctl Ayush Garg
     [not found]   ` <CGME20210722055016epcas5p267b70f0da3b5c1991d29ca47d685ab6d@epcas5p2.samsung.com>
2021-07-22  5:49     ` [PATCH BlueZ 7/8] device: Save device PHY in storage and read it at init Ayush Garg
     [not found]   ` <CGME20210722055017epcas5p4da91b311c34a5fb869148b369338ed07@epcas5p4.samsung.com>
2021-07-22  5:49     ` [PATCH BlueZ 8/8] monitor: Add support for LE PHY Update event Ayush Garg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210722054951.8291-5-ayush.garg@samsung.com \
    --to=ayush.garg@samsung.com \
    --cc=anupam.r@samsung.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=nitin.j@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.