Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: aosp: Support AOSP Bluetooth Quality Report

This patch adds the support of the AOSP Bluetooth Quality Report
(BQR) events.

Multiple vendors have supported the AOSP Bluetooth Quality Report.
When a Bluetooth controller supports the capability, it can enable
the aosp capability through hci_set_aosp_capable. Then hci_core will
set up the hdev->aosp_set_quality_report callback through aosp_do_open
if the controller responds to support the quality report capability.

Note that Intel also supports a distinct telemetry quality report
specification. Intel sets up the hdev->set_quality_report callback
in the btusb driver module.

Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
Signed-off-by: Joseph Hwang <josephsih@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Joseph Hwang and committed by
Marcel Holtmann
258f56d1 749a6c59

+112 -5
+87
net/bluetooth/aosp.c
··· 112 112 113 113 bt_dev_dbg(hdev, "Cleanup of AOSP extension"); 114 114 } 115 + 116 + /* BQR command */ 117 + #define BQR_OPCODE hci_opcode_pack(0x3f, 0x015e) 118 + 119 + /* BQR report action */ 120 + #define REPORT_ACTION_ADD 0x00 121 + #define REPORT_ACTION_DELETE 0x01 122 + #define REPORT_ACTION_CLEAR 0x02 123 + 124 + /* BQR event masks */ 125 + #define QUALITY_MONITORING BIT(0) 126 + #define APPRAOCHING_LSTO BIT(1) 127 + #define A2DP_AUDIO_CHOPPY BIT(2) 128 + #define SCO_VOICE_CHOPPY BIT(3) 129 + 130 + #define DEFAULT_BQR_EVENT_MASK (QUALITY_MONITORING | APPRAOCHING_LSTO | \ 131 + A2DP_AUDIO_CHOPPY | SCO_VOICE_CHOPPY) 132 + 133 + /* Reporting at milliseconds so as not to stress the controller too much. 134 + * Range: 0 ~ 65535 ms 135 + */ 136 + #define DEFALUT_REPORT_INTERVAL_MS 5000 137 + 138 + struct aosp_bqr_cp { 139 + __u8 report_action; 140 + __u32 event_mask; 141 + __u16 min_report_interval; 142 + } __packed; 143 + 144 + static int enable_quality_report(struct hci_dev *hdev) 145 + { 146 + struct sk_buff *skb; 147 + struct aosp_bqr_cp cp; 148 + 149 + cp.report_action = REPORT_ACTION_ADD; 150 + cp.event_mask = DEFAULT_BQR_EVENT_MASK; 151 + cp.min_report_interval = DEFALUT_REPORT_INTERVAL_MS; 152 + 153 + skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp, 154 + HCI_CMD_TIMEOUT); 155 + if (IS_ERR(skb)) { 156 + bt_dev_err(hdev, "Enabling Android BQR failed (%ld)", 157 + PTR_ERR(skb)); 158 + return PTR_ERR(skb); 159 + } 160 + 161 + kfree_skb(skb); 162 + return 0; 163 + } 164 + 165 + static int disable_quality_report(struct hci_dev *hdev) 166 + { 167 + struct sk_buff *skb; 168 + struct aosp_bqr_cp cp = { 0 }; 169 + 170 + cp.report_action = REPORT_ACTION_CLEAR; 171 + 172 + skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp, 173 + HCI_CMD_TIMEOUT); 174 + if (IS_ERR(skb)) { 175 + bt_dev_err(hdev, "Disabling Android BQR failed (%ld)", 176 + PTR_ERR(skb)); 177 + return PTR_ERR(skb); 178 + } 179 + 180 + kfree_skb(skb); 181 + return 0; 182 + } 183 + 184 + bool aosp_has_quality_report(struct hci_dev *hdev) 185 + { 186 + return hdev->aosp_quality_report; 187 + } 188 + 189 + int aosp_set_quality_report(struct hci_dev *hdev, bool enable) 190 + { 191 + if (!aosp_has_quality_report(hdev)) 192 + return -EOPNOTSUPP; 193 + 194 + bt_dev_dbg(hdev, "quality report enable %d", enable); 195 + 196 + /* Enable or disable the quality report feature. */ 197 + if (enable) 198 + return enable_quality_report(hdev); 199 + else 200 + return disable_quality_report(hdev); 201 + }
+13
net/bluetooth/aosp.h
··· 8 8 void aosp_do_open(struct hci_dev *hdev); 9 9 void aosp_do_close(struct hci_dev *hdev); 10 10 11 + bool aosp_has_quality_report(struct hci_dev *hdev); 12 + int aosp_set_quality_report(struct hci_dev *hdev, bool enable); 13 + 11 14 #else 12 15 13 16 static inline void aosp_do_open(struct hci_dev *hdev) {} 14 17 static inline void aosp_do_close(struct hci_dev *hdev) {} 18 + 19 + static inline bool aosp_has_quality_report(struct hci_dev *hdev) 20 + { 21 + return false; 22 + } 23 + 24 + static inline int aosp_set_quality_report(struct hci_dev *hdev, bool enable) 25 + { 26 + return -EOPNOTSUPP; 27 + } 15 28 16 29 #endif
+12 -5
net/bluetooth/mgmt.c
··· 39 39 #include "mgmt_config.h" 40 40 #include "msft.h" 41 41 #include "eir.h" 42 + #include "aosp.h" 42 43 43 44 #define MGMT_VERSION 1 44 45 #define MGMT_REVISION 21 ··· 3935 3934 idx++; 3936 3935 } 3937 3936 3938 - if (hdev && hdev->set_quality_report) { 3937 + if (hdev && (aosp_has_quality_report(hdev) || 3938 + hdev->set_quality_report)) { 3939 3939 if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT)) 3940 3940 flags = BIT(0); 3941 3941 else ··· 4200 4198 val = !!cp->param[0]; 4201 4199 changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT)); 4202 4200 4203 - if (!hdev->set_quality_report) { 4201 + if (!aosp_has_quality_report(hdev) && !hdev->set_quality_report) { 4204 4202 err = mgmt_cmd_status(sk, hdev->id, 4205 4203 MGMT_OP_SET_EXP_FEATURE, 4206 4204 MGMT_STATUS_NOT_SUPPORTED); ··· 4208 4206 } 4209 4207 4210 4208 if (changed) { 4211 - err = hdev->set_quality_report(hdev, val); 4209 + if (hdev->set_quality_report) 4210 + err = hdev->set_quality_report(hdev, val); 4211 + else 4212 + err = aosp_set_quality_report(hdev, val); 4213 + 4212 4214 if (err) { 4213 4215 err = mgmt_cmd_status(sk, hdev->id, 4214 4216 MGMT_OP_SET_EXP_FEATURE, 4215 4217 MGMT_STATUS_FAILED); 4216 4218 goto unlock_quality_report; 4217 4219 } 4220 + 4218 4221 if (val) 4219 4222 hci_dev_set_flag(hdev, HCI_QUALITY_REPORT); 4220 4223 else ··· 4231 4224 memcpy(rp.uuid, quality_report_uuid, 16); 4232 4225 rp.flags = cpu_to_le32(val ? BIT(0) : 0); 4233 4226 hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); 4234 - err = mgmt_cmd_complete(sk, hdev->id, 4235 - MGMT_OP_SET_EXP_FEATURE, 0, 4227 + 4228 + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_EXP_FEATURE, 0, 4236 4229 &rp, sizeof(rp)); 4237 4230 4238 4231 if (changed)