Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2021 Intel Corporation */ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include "aosp.h" /* Command complete parameters of LE_Get_Vendor_Capabilities_Command * The parameters grow over time. The base version that declares the * version_supported field is v0.95. Refer to * https://cs.android.com/android/platform/superproject/+/master:system/ * bt/gd/hci/controller.cc;l=452?q=le_get_vendor_capabilities_handler */ struct aosp_rp_le_get_vendor_capa { /* v0.95: 15 octets */ __u8 status; __u8 max_advt_instances; __u8 offloaded_resolution_of_private_address; __le16 total_scan_results_storage; __u8 max_irk_list_sz; __u8 filtering_support; __u8 max_filter; __u8 activity_energy_info_support; __le16 version_supported; __le16 total_num_of_advt_tracked; __u8 extended_scan_support; __u8 debug_logging_supported; /* v0.96: 16 octets */ __u8 le_address_generation_offloading_support; /* v0.98: 21 octets */ __le32 a2dp_source_offload_capability_mask; __u8 bluetooth_quality_report_support; /* v1.00: 25 octets */ __le32 dynamic_audio_buffer_support; } __packed; #define VENDOR_CAPA_BASE_SIZE 15 #define VENDOR_CAPA_0_98_SIZE 21 void aosp_do_open(struct hci_dev *hdev) { struct sk_buff *skb; struct aosp_rp_le_get_vendor_capa *rp; u16 version_supported; if (!hdev->aosp_capable) return; bt_dev_dbg(hdev, "Initialize AOSP extension"); /* LE Get Vendor Capabilities Command */ skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL, HCI_CMD_TIMEOUT); if (IS_ERR_OR_NULL(skb)) { if (!skb) skb = ERR_PTR(-EIO); bt_dev_err(hdev, "AOSP get vendor capabilities (%ld)", PTR_ERR(skb)); return; } /* A basic length check */ if (skb->len < VENDOR_CAPA_BASE_SIZE) goto length_error; rp = (struct aosp_rp_le_get_vendor_capa *)skb->data; version_supported = le16_to_cpu(rp->version_supported); /* AOSP displays the verion number like v0.98, v1.00, etc. */ bt_dev_info(hdev, "AOSP extensions version v%u.%02u", version_supported >> 8, version_supported & 0xff); /* Do not support very old versions. */ if (version_supported < 95) { bt_dev_warn(hdev, "AOSP capabilities version %u too old", version_supported); goto done; } if (version_supported < 98) { bt_dev_warn(hdev, "AOSP quality report is not supported"); goto done; } if (skb->len < VENDOR_CAPA_0_98_SIZE) goto length_error; /* The bluetooth_quality_report_support is defined at version * v0.98. Refer to * https://cs.android.com/android/platform/superproject/+/ * master:system/bt/gd/hci/controller.cc;l=477 */ if (rp->bluetooth_quality_report_support) { hdev->aosp_quality_report = true; bt_dev_info(hdev, "AOSP quality report is supported"); } goto done; length_error: bt_dev_err(hdev, "AOSP capabilities length %d too short", skb->len); done: kfree_skb(skb); } void aosp_do_close(struct hci_dev *hdev) { if (!hdev->aosp_capable) return; bt_dev_dbg(hdev, "Cleanup of AOSP extension"); } /* BQR command */ #define BQR_OPCODE hci_opcode_pack(0x3f, 0x015e) /* BQR report action */ #define REPORT_ACTION_ADD 0x00 #define REPORT_ACTION_DELETE 0x01 #define REPORT_ACTION_CLEAR 0x02 /* BQR event masks */ #define QUALITY_MONITORING BIT(0) #define APPRAOCHING_LSTO BIT(1) #define A2DP_AUDIO_CHOPPY BIT(2) #define SCO_VOICE_CHOPPY BIT(3) #define DEFAULT_BQR_EVENT_MASK (QUALITY_MONITORING | APPRAOCHING_LSTO | \ A2DP_AUDIO_CHOPPY | SCO_VOICE_CHOPPY) /* Reporting at milliseconds so as not to stress the controller too much. * Range: 0 ~ 65535 ms */ #define DEFALUT_REPORT_INTERVAL_MS 5000 struct aosp_bqr_cp { __u8 report_action; __u32 event_mask; __u16 min_report_interval; } __packed; static int enable_quality_report(struct hci_dev *hdev) { struct sk_buff *skb; struct aosp_bqr_cp cp; cp.report_action = REPORT_ACTION_ADD; cp.event_mask = DEFAULT_BQR_EVENT_MASK; cp.min_report_interval = DEFALUT_REPORT_INTERVAL_MS; skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp, HCI_CMD_TIMEOUT); if (IS_ERR_OR_NULL(skb)) { if (!skb) skb = ERR_PTR(-EIO); bt_dev_err(hdev, "Enabling Android BQR failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); } kfree_skb(skb); return 0; } static int disable_quality_report(struct hci_dev *hdev) { struct sk_buff *skb; struct aosp_bqr_cp cp = { 0 }; cp.report_action = REPORT_ACTION_CLEAR; skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp, HCI_CMD_TIMEOUT); if (IS_ERR_OR_NULL(skb)) { if (!skb) skb = ERR_PTR(-EIO); bt_dev_err(hdev, "Disabling Android BQR failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); } kfree_skb(skb); return 0; } bool aosp_has_quality_report(struct hci_dev *hdev) { return hdev->aosp_quality_report; } int aosp_set_quality_report(struct hci_dev *hdev, bool enable) { if (!aosp_has_quality_report(hdev)) return -EOPNOTSUPP; bt_dev_dbg(hdev, "quality report enable %d", enable); /* Enable or disable the quality report feature. */ if (enable) return enable_quality_report(hdev); else return disable_quality_report(hdev); } |