mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 06:23:02 +02:00
Bluetooth: Add support for Shorter Connection Interval (SCI) feature
Add HCI command, event and feature bit definitions for the Bluetooth 6.2 Shorter Connection Interval feature: Commands: - HCI_OP_LE_CONN_RATE (0x20a1) - Connection Rate Request - HCI_OP_LE_SET_DEF_RATE (0x20a2) - Set Default Rate Parameters - HCI_OP_LE_READ_CONN_INTERVAL (0x20a3) - Read Min Supported Connection Interval Events: - HCI_EVT_LE_CONN_RATE_CHANGE (0x37) - Connection Rate Change Feature bits: - HCI_LE_SCI - Shorter Connection Intervals - HCI_LE_SCI_HOST - Shorter Connection Intervals (Host Support) During controller init, when SCI is supported: - Set Shorter Connection Intervals (Host Support) feature via LE Set Host Feature - Read Minimum Supported Connection Interval - Set Default Rate Parameters The Connection Rate Change event handler updates the connection interval, latency and supervision timeout on the hci_conn. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
39bbe7b738
commit
2f8784cfe8
|
|
@ -653,6 +653,8 @@ enum {
|
||||||
#define HCI_LE_LL_EXT_FEATURE 0x80
|
#define HCI_LE_LL_EXT_FEATURE 0x80
|
||||||
#define HCI_LE_CS 0x40
|
#define HCI_LE_CS 0x40
|
||||||
#define HCI_LE_CS_HOST 0x80
|
#define HCI_LE_CS_HOST 0x80
|
||||||
|
#define HCI_LE_SCI 0x01 /* byte 9 - Shorter Connection Intervals */
|
||||||
|
#define HCI_LE_SCI_HOST 0x02 /* byte 9 - Shorter Connection Intervals (Host) */
|
||||||
|
|
||||||
/* Connection modes */
|
/* Connection modes */
|
||||||
#define HCI_CM_ACTIVE 0x0000
|
#define HCI_CM_ACTIVE 0x0000
|
||||||
|
|
@ -2489,6 +2491,46 @@ struct hci_cp_le_set_host_feature_v2 {
|
||||||
__u8 bit_value;
|
__u8 bit_value;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_LE_CONN_RATE 0x20a1
|
||||||
|
struct hci_cp_le_conn_rate {
|
||||||
|
__le16 handle;
|
||||||
|
__le16 interval_min;
|
||||||
|
__le16 interval_max;
|
||||||
|
__le16 subrate_min;
|
||||||
|
__le16 subrate_max;
|
||||||
|
__le16 max_latency;
|
||||||
|
__le16 cont_num;
|
||||||
|
__le16 supv_timeout;
|
||||||
|
__le16 min_ce_len;
|
||||||
|
__le16 max_ce_len;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_LE_SET_DEF_RATE 0x20a2
|
||||||
|
struct hci_cp_le_set_def_rate {
|
||||||
|
__le16 interval_min;
|
||||||
|
__le16 interval_max;
|
||||||
|
__le16 subrate_min;
|
||||||
|
__le16 subrate_max;
|
||||||
|
__le16 max_latency;
|
||||||
|
__le16 cont_num;
|
||||||
|
__le16 supv_timeout;
|
||||||
|
__le16 min_ce_len;
|
||||||
|
__le16 max_ce_len;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_OP_LE_READ_CONN_INTERVAL 0x20a3
|
||||||
|
struct hci_le_conn_interval_group {
|
||||||
|
__le16 min;
|
||||||
|
__le16 max;
|
||||||
|
__le16 stride;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct hci_rp_le_read_conn_interval {
|
||||||
|
__u8 status;
|
||||||
|
__u8 num_grps;
|
||||||
|
struct hci_le_conn_interval_group grps[];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/* ---- HCI Events ---- */
|
/* ---- HCI Events ---- */
|
||||||
struct hci_ev_status {
|
struct hci_ev_status {
|
||||||
__u8 status;
|
__u8 status;
|
||||||
|
|
@ -3303,6 +3345,17 @@ struct hci_evt_le_cs_test_end_complete {
|
||||||
__u8 status;
|
__u8 status;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_EVT_LE_CONN_RATE_CHANGE 0x37
|
||||||
|
struct hci_evt_le_conn_rate_change {
|
||||||
|
__u8 status;
|
||||||
|
__le16 handle;
|
||||||
|
__le16 interval;
|
||||||
|
__le16 subrate;
|
||||||
|
__le16 latency;
|
||||||
|
__le16 cont_number;
|
||||||
|
__le16 supv_timeout;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define HCI_EV_VENDOR 0xff
|
#define HCI_EV_VENDOR 0xff
|
||||||
|
|
||||||
/* Internal events generated by Bluetooth stack */
|
/* Internal events generated by Bluetooth stack */
|
||||||
|
|
|
||||||
|
|
@ -416,6 +416,7 @@ struct hci_dev {
|
||||||
__u16 le_conn_max_interval;
|
__u16 le_conn_max_interval;
|
||||||
__u16 le_conn_latency;
|
__u16 le_conn_latency;
|
||||||
__u16 le_supv_timeout;
|
__u16 le_supv_timeout;
|
||||||
|
__u16 le_min_rate_interval;
|
||||||
__u16 le_def_tx_len;
|
__u16 le_def_tx_len;
|
||||||
__u16 le_def_tx_time;
|
__u16 le_def_tx_time;
|
||||||
__u16 le_max_tx_len;
|
__u16 le_max_tx_len;
|
||||||
|
|
@ -720,6 +721,11 @@ struct hci_conn {
|
||||||
__u16 le_conn_interval;
|
__u16 le_conn_interval;
|
||||||
__u16 le_conn_latency;
|
__u16 le_conn_latency;
|
||||||
__u16 le_supv_timeout;
|
__u16 le_supv_timeout;
|
||||||
|
__u16 le_rate_interval;
|
||||||
|
__u16 le_subrate;
|
||||||
|
__u16 le_rate_latency;
|
||||||
|
__u16 le_cont_num;
|
||||||
|
__u16 le_rate_supv_timeout;
|
||||||
__u8 le_adv_data[HCI_MAX_EXT_AD_LENGTH];
|
__u8 le_adv_data[HCI_MAX_EXT_AD_LENGTH];
|
||||||
__u8 le_adv_data_len;
|
__u8 le_adv_data_len;
|
||||||
__u8 le_per_adv_data[HCI_MAX_PER_AD_TOT_LEN];
|
__u8 le_per_adv_data[HCI_MAX_PER_AD_TOT_LEN];
|
||||||
|
|
@ -2079,6 +2085,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
||||||
#define le_cs_host_capable(dev) \
|
#define le_cs_host_capable(dev) \
|
||||||
((dev)->le_features[5] & HCI_LE_CS_HOST)
|
((dev)->le_features[5] & HCI_LE_CS_HOST)
|
||||||
|
|
||||||
|
#define le_sci_capable(dev) \
|
||||||
|
((dev)->le_features[9] & HCI_LE_SCI)
|
||||||
|
|
||||||
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
|
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
|
||||||
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))
|
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1241,6 +1241,39 @@ static u8 hci_cc_le_read_local_features(struct hci_dev *hdev, void *data,
|
||||||
return rp->status;
|
return rp->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 hci_cc_le_read_conn_interval(struct hci_dev *hdev, void *data,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hci_rp_le_read_conn_interval *rp = data;
|
||||||
|
u16 min_interval = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
|
||||||
|
|
||||||
|
if (rp->status)
|
||||||
|
return rp->status;
|
||||||
|
|
||||||
|
if (skb->len < flex_array_size(rp, grps, rp->num_grps)) {
|
||||||
|
bt_dev_err(hdev, "Invalid response length for 0x%4.4x",
|
||||||
|
HCI_OP_LE_READ_CONN_INTERVAL);
|
||||||
|
return HCI_ERROR_UNSPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the smallest minimum supported connection interval reported by
|
||||||
|
* the controller so the default rate parameters can be clamped to it.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < rp->num_grps; i++) {
|
||||||
|
u16 min = le16_to_cpu(rp->grps[i].min);
|
||||||
|
|
||||||
|
if (!min_interval || min < min_interval)
|
||||||
|
min_interval = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdev->le_min_rate_interval = min_interval;
|
||||||
|
|
||||||
|
return rp->status;
|
||||||
|
}
|
||||||
|
|
||||||
static u8 hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, void *data,
|
static u8 hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, void *data,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
|
@ -4153,6 +4186,9 @@ static const struct hci_cc {
|
||||||
sizeof(struct hci_rp_le_read_buffer_size)),
|
sizeof(struct hci_rp_le_read_buffer_size)),
|
||||||
HCI_CC(HCI_OP_LE_READ_LOCAL_FEATURES, hci_cc_le_read_local_features,
|
HCI_CC(HCI_OP_LE_READ_LOCAL_FEATURES, hci_cc_le_read_local_features,
|
||||||
sizeof(struct hci_rp_le_read_local_features)),
|
sizeof(struct hci_rp_le_read_local_features)),
|
||||||
|
HCI_CC_VL(HCI_OP_LE_READ_CONN_INTERVAL, hci_cc_le_read_conn_interval,
|
||||||
|
sizeof(struct hci_rp_le_read_conn_interval),
|
||||||
|
HCI_MAX_EVENT_SIZE),
|
||||||
HCI_CC(HCI_OP_LE_READ_ADV_TX_POWER, hci_cc_le_read_adv_tx_power,
|
HCI_CC(HCI_OP_LE_READ_ADV_TX_POWER, hci_cc_le_read_adv_tx_power,
|
||||||
sizeof(struct hci_rp_le_read_adv_tx_power)),
|
sizeof(struct hci_rp_le_read_adv_tx_power)),
|
||||||
HCI_CC(HCI_OP_USER_CONFIRM_REPLY, hci_cc_user_confirm_reply,
|
HCI_CC(HCI_OP_USER_CONFIRM_REPLY, hci_cc_user_confirm_reply,
|
||||||
|
|
@ -7363,6 +7399,31 @@ static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev,
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hci_le_conn_rate_change_evt(struct hci_dev *hdev, void *data,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hci_evt_le_conn_rate_change *ev = data;
|
||||||
|
struct hci_conn *conn;
|
||||||
|
|
||||||
|
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||||
|
|
||||||
|
if (ev->status)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
||||||
|
if (conn) {
|
||||||
|
conn->le_rate_interval = le16_to_cpu(ev->interval);
|
||||||
|
conn->le_subrate = le16_to_cpu(ev->subrate);
|
||||||
|
conn->le_rate_latency = le16_to_cpu(ev->latency);
|
||||||
|
conn->le_cont_num = le16_to_cpu(ev->cont_number);
|
||||||
|
conn->le_rate_supv_timeout = le16_to_cpu(ev->supv_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
|
}
|
||||||
|
|
||||||
#define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \
|
#define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \
|
||||||
[_op] = { \
|
[_op] = { \
|
||||||
.func = _func, \
|
.func = _func, \
|
||||||
|
|
@ -7474,6 +7535,9 @@ static const struct hci_le_ev {
|
||||||
sizeof(struct
|
sizeof(struct
|
||||||
hci_evt_le_read_all_remote_features_complete),
|
hci_evt_le_read_all_remote_features_complete),
|
||||||
HCI_MAX_EVENT_SIZE),
|
HCI_MAX_EVENT_SIZE),
|
||||||
|
/* [0x37 = HCI_EVT_LE_CONN_RATE_CHANGE] */
|
||||||
|
HCI_LE_EV(HCI_EVT_LE_CONN_RATE_CHANGE, hci_le_conn_rate_change_evt,
|
||||||
|
sizeof(struct hci_evt_le_conn_rate_change)),
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
|
static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
|
||||||
|
|
|
||||||
|
|
@ -4541,6 +4541,10 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
|
||||||
events[6] |= 0x02; /* LE CS Subevent Result Continue event */
|
events[6] |= 0x02; /* LE CS Subevent Result Continue event */
|
||||||
events[6] |= 0x04; /* LE CS Test End Complete event */
|
events[6] |= 0x04; /* LE CS Test End Complete event */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (le_sci_capable(hdev))
|
||||||
|
events[6] |= 0x40; /* LE Connection Rate Change event */
|
||||||
|
|
||||||
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK,
|
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK,
|
||||||
sizeof(events), events, HCI_CMD_TIMEOUT);
|
sizeof(events), events, HCI_CMD_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
@ -4709,12 +4713,59 @@ static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u16 bit, u8 value)
|
||||||
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hci_le_read_conn_interval_sync(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
if (!le_sci_capable(hdev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_CONN_INTERVAL,
|
||||||
|
0, NULL, HCI_CMD_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hci_le_set_def_rate_sync(struct hci_dev *hdev)
|
||||||
|
{
|
||||||
|
struct hci_cp_le_set_def_rate cp;
|
||||||
|
u16 interval_min = 0x000a; /* 1.25 ms */
|
||||||
|
u16 interval_max = 0x0078; /* 15 ms */
|
||||||
|
|
||||||
|
if (!le_sci_capable(hdev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Clamp the interval range to the controller's minimum supported
|
||||||
|
* connection interval (read via HCI_OP_LE_READ_CONN_INTERVAL) so the
|
||||||
|
* default rate parameters are not rejected. The maximum is raised as
|
||||||
|
* well if needed to keep interval_min <= interval_max.
|
||||||
|
*/
|
||||||
|
if (hdev->le_min_rate_interval > interval_min) {
|
||||||
|
interval_min = hdev->le_min_rate_interval;
|
||||||
|
if (interval_min > interval_max)
|
||||||
|
interval_max = interval_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&cp, 0, sizeof(cp));
|
||||||
|
|
||||||
|
/* Use the HIDS 1.2 recommended Full Range mode values as the default
|
||||||
|
* rate parameters (see HOGP v1.2 spec). Connection intervals are in
|
||||||
|
* units of 0.125 ms and the supervision timeout is in units of 10 ms.
|
||||||
|
*/
|
||||||
|
cp.interval_min = cpu_to_le16(interval_min);
|
||||||
|
cp.interval_max = cpu_to_le16(interval_max);
|
||||||
|
cp.subrate_min = cpu_to_le16(0x0001);
|
||||||
|
cp.subrate_max = cpu_to_le16(0x0004);
|
||||||
|
cp.max_latency = cpu_to_le16(0x0000);
|
||||||
|
cp.cont_num = cpu_to_le16(0x0001);
|
||||||
|
cp.supv_timeout = cpu_to_le16(0x000c); /* 120 ms */
|
||||||
|
|
||||||
|
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_DEF_RATE,
|
||||||
|
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set Host Features, each feature needs to be sent separately since
|
/* 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.
|
* 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)
|
static int hci_le_set_host_features_sync(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
int err;
|
int err = 0;
|
||||||
|
|
||||||
if (cis_capable(hdev)) {
|
if (cis_capable(hdev)) {
|
||||||
/* Connected Isochronous Channels (Host Support) */
|
/* Connected Isochronous Channels (Host Support) */
|
||||||
|
|
@ -4725,9 +4776,16 @@ static int hci_le_set_host_features_sync(struct hci_dev *hdev)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (le_cs_capable(hdev))
|
if (le_cs_capable(hdev)) {
|
||||||
/* Channel Sounding (Host Support) */
|
/* Channel Sounding (Host Support) */
|
||||||
err = hci_le_set_host_feature_sync(hdev, 47, 0x01);
|
err = hci_le_set_host_feature_sync(hdev, 47, 0x01);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (le_sci_capable(hdev))
|
||||||
|
/* Shorter Connection Intervals (Host Support) */
|
||||||
|
err = hci_le_set_host_feature_sync(hdev, 73, 0x01);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -4760,6 +4818,10 @@ static const struct hci_init_stage le_init3[] = {
|
||||||
HCI_INIT(hci_set_le_support_sync),
|
HCI_INIT(hci_set_le_support_sync),
|
||||||
/* HCI_OP_LE_SET_HOST_FEATURE */
|
/* HCI_OP_LE_SET_HOST_FEATURE */
|
||||||
HCI_INIT(hci_le_set_host_features_sync),
|
HCI_INIT(hci_le_set_host_features_sync),
|
||||||
|
/* HCI_OP_LE_READ_CONN_INTERVAL */
|
||||||
|
HCI_INIT(hci_le_read_conn_interval_sync),
|
||||||
|
/* HCI_OP_LE_SET_DEF_RATE */
|
||||||
|
HCI_INIT(hci_le_set_def_rate_sync),
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user