summaryrefslogtreecommitdiff
path: root/net/bluetooth/hci_sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/hci_sync.c')
-rw-r--r--net/bluetooth/hci_sync.c125
1 files changed, 113 insertions, 12 deletions
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index cbc3a75d7326..f04a90bce4a9 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -2948,8 +2948,8 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
if (conn) {
struct bt_iso_qos *qos = &conn->iso_qos;
- if (qos->bcast.in.phy & BT_ISO_PHY_1M ||
- qos->bcast.in.phy & BT_ISO_PHY_2M) {
+ if (qos->bcast.in.phys & BT_ISO_PHY_1M ||
+ qos->bcast.in.phys & BT_ISO_PHY_2M) {
cp->scanning_phys |= LE_SCAN_PHY_1M;
hci_le_scan_phy_params(phy, type,
interval,
@@ -2958,7 +2958,7 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
phy++;
}
- if (qos->bcast.in.phy & BT_ISO_PHY_CODED) {
+ if (qos->bcast.in.phys & BT_ISO_PHY_CODED) {
cp->scanning_phys |= LE_SCAN_PHY_CODED;
hci_le_scan_phy_params(phy, type,
interval * 3,
@@ -4428,6 +4428,17 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
events[4] |= 0x02; /* LE BIG Info Advertising Report */
}
+ if (le_cs_capable(hdev)) {
+ /* Channel Sounding events */
+ events[5] |= 0x08; /* LE CS Read Remote Supported Cap Complete event */
+ events[5] |= 0x10; /* LE CS Read Remote FAE Table Complete event */
+ events[5] |= 0x20; /* LE CS Security Enable Complete event */
+ events[5] |= 0x40; /* LE CS Config Complete event */
+ events[5] |= 0x80; /* LE CS Procedure Enable Complete event */
+ events[6] |= 0x01; /* LE CS Subevent Result event */
+ events[6] |= 0x02; /* LE CS Subevent Result Continue event */
+ events[6] |= 0x04; /* LE CS Test End Complete event */
+ }
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK,
sizeof(events), events, HCI_CMD_TIMEOUT);
}
@@ -4560,23 +4571,43 @@ static int hci_set_le_support_sync(struct hci_dev *hdev)
}
/* LE Set Host Feature */
-static int hci_le_set_host_feature_sync(struct hci_dev *hdev)
+static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u8 bit, u8 value)
{
struct hci_cp_le_set_host_feature cp;
- if (!iso_capable(hdev))
- return 0;
-
memset(&cp, 0, sizeof(cp));
/* Connected Isochronous Channels (Host Support) */
- cp.bit_number = 32;
- cp.bit_value = iso_enabled(hdev) ? 0x01 : 0x00;
+ cp.bit_number = bit;
+ cp.bit_value = value;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_HOST_FEATURE,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
+/* Set Host Features, each feature needs to be sent separately since
+ * HCI_OP_LE_SET_HOST_FEATURE doesn't support setting all of them at once.
+ */
+static int hci_le_set_host_features_sync(struct hci_dev *hdev)
+{
+ int err;
+
+ if (iso_capable(hdev)) {
+ /* Connected Isochronous Channels (Host Support) */
+ err = hci_le_set_host_feature_sync(hdev, 32,
+ (iso_enabled(hdev) ? 0x01 :
+ 0x00));
+ if (err)
+ return err;
+ }
+
+ if (le_cs_capable(hdev))
+ /* Channel Sounding (Host Support) */
+ err = hci_le_set_host_feature_sync(hdev, 47, 0x01);
+
+ return err;
+}
+
/* LE Controller init stage 3 command sequence */
static const struct hci_init_stage le_init3[] = {
/* HCI_OP_LE_SET_EVENT_MASK */
@@ -4604,7 +4635,7 @@ static const struct hci_init_stage le_init3[] = {
/* HCI_OP_WRITE_LE_HOST_SUPPORTED */
HCI_INIT(hci_set_le_support_sync),
/* HCI_OP_LE_SET_HOST_FEATURE */
- HCI_INIT(hci_le_set_host_feature_sync),
+ HCI_INIT(hci_le_set_host_features_sync),
{}
};
@@ -6897,8 +6928,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
conn->attempt++;
- conn->link_policy = hdev->link_policy;
-
memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
@@ -7419,3 +7448,75 @@ int hci_le_read_remote_features(struct hci_conn *conn)
return err;
}
+
+static void pkt_type_changed(struct hci_dev *hdev, void *data, int err)
+{
+ struct hci_cp_change_conn_ptype *cp = data;
+
+ bt_dev_dbg(hdev, "err %d", err);
+
+ kfree(cp);
+}
+
+static int hci_change_conn_ptype_sync(struct hci_dev *hdev, void *data)
+{
+ struct hci_cp_change_conn_ptype *cp = data;
+
+ return __hci_cmd_sync_status_sk(hdev, HCI_OP_CHANGE_CONN_PTYPE,
+ sizeof(*cp), cp,
+ HCI_EV_PKT_TYPE_CHANGE,
+ HCI_CMD_TIMEOUT, NULL);
+}
+
+int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type)
+{
+ struct hci_dev *hdev = conn->hdev;
+ struct hci_cp_change_conn_ptype *cp;
+
+ cp = kmalloc(sizeof(*cp), GFP_KERNEL);
+ if (!cp)
+ return -ENOMEM;
+
+ cp->handle = cpu_to_le16(conn->handle);
+ cp->pkt_type = cpu_to_le16(pkt_type);
+
+ return hci_cmd_sync_queue_once(hdev, hci_change_conn_ptype_sync, cp,
+ pkt_type_changed);
+}
+
+static void le_phy_update_complete(struct hci_dev *hdev, void *data, int err)
+{
+ struct hci_cp_le_set_phy *cp = data;
+
+ bt_dev_dbg(hdev, "err %d", err);
+
+ kfree(cp);
+}
+
+static int hci_le_set_phy_sync(struct hci_dev *hdev, void *data)
+{
+ struct hci_cp_le_set_phy *cp = data;
+
+ return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_SET_PHY,
+ sizeof(*cp), cp,
+ HCI_EV_LE_PHY_UPDATE_COMPLETE,
+ HCI_CMD_TIMEOUT, NULL);
+}
+
+int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys)
+{
+ struct hci_dev *hdev = conn->hdev;
+ struct hci_cp_le_set_phy *cp;
+
+ cp = kmalloc(sizeof(*cp), GFP_KERNEL);
+ if (!cp)
+ return -ENOMEM;
+
+ memset(cp, 0, sizeof(*cp));
+ cp->handle = cpu_to_le16(conn->handle);
+ cp->tx_phys = tx_phys;
+ cp->rx_phys = rx_phys;
+
+ return hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp,
+ le_phy_update_complete);
+}