Marcel Holtmann | f67743f | 2021-04-06 21:55:52 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * Copyright (C) 2021 Intel Corporation |
| 4 | */ |
| 5 | |
| 6 | #include <net/bluetooth/bluetooth.h> |
| 7 | #include <net/bluetooth/hci_core.h> |
| 8 | |
| 9 | #include "aosp.h" |
| 10 | |
Joseph Hwang | 749a6c5 | 2021-11-02 15:19:28 +0800 | [diff] [blame] | 11 | /* Command complete parameters of LE_Get_Vendor_Capabilities_Command |
| 12 | * The parameters grow over time. The base version that declares the |
| 13 | * version_supported field is v0.95. Refer to |
| 14 | * https://cs.android.com/android/platform/superproject/+/master:system/ |
| 15 | * bt/gd/hci/controller.cc;l=452?q=le_get_vendor_capabilities_handler |
| 16 | */ |
| 17 | struct aosp_rp_le_get_vendor_capa { |
| 18 | /* v0.95: 15 octets */ |
| 19 | __u8 status; |
| 20 | __u8 max_advt_instances; |
| 21 | __u8 offloaded_resolution_of_private_address; |
| 22 | __le16 total_scan_results_storage; |
| 23 | __u8 max_irk_list_sz; |
| 24 | __u8 filtering_support; |
| 25 | __u8 max_filter; |
| 26 | __u8 activity_energy_info_support; |
| 27 | __le16 version_supported; |
| 28 | __le16 total_num_of_advt_tracked; |
| 29 | __u8 extended_scan_support; |
| 30 | __u8 debug_logging_supported; |
| 31 | /* v0.96: 16 octets */ |
| 32 | __u8 le_address_generation_offloading_support; |
| 33 | /* v0.98: 21 octets */ |
| 34 | __le32 a2dp_source_offload_capability_mask; |
| 35 | __u8 bluetooth_quality_report_support; |
| 36 | /* v1.00: 25 octets */ |
| 37 | __le32 dynamic_audio_buffer_support; |
| 38 | } __packed; |
| 39 | |
| 40 | #define VENDOR_CAPA_BASE_SIZE 15 |
| 41 | #define VENDOR_CAPA_0_98_SIZE 21 |
| 42 | |
Marcel Holtmann | f67743f | 2021-04-06 21:55:52 +0200 | [diff] [blame] | 43 | void aosp_do_open(struct hci_dev *hdev) |
| 44 | { |
| 45 | struct sk_buff *skb; |
Joseph Hwang | 749a6c5 | 2021-11-02 15:19:28 +0800 | [diff] [blame] | 46 | struct aosp_rp_le_get_vendor_capa *rp; |
| 47 | u16 version_supported; |
Marcel Holtmann | f67743f | 2021-04-06 21:55:52 +0200 | [diff] [blame] | 48 | |
| 49 | if (!hdev->aosp_capable) |
| 50 | return; |
| 51 | |
| 52 | bt_dev_dbg(hdev, "Initialize AOSP extension"); |
| 53 | |
| 54 | /* LE Get Vendor Capabilities Command */ |
| 55 | skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL, |
| 56 | HCI_CMD_TIMEOUT); |
Joseph Hwang | 749a6c5 | 2021-11-02 15:19:28 +0800 | [diff] [blame] | 57 | if (IS_ERR(skb)) { |
| 58 | bt_dev_err(hdev, "AOSP get vendor capabilities (%ld)", |
| 59 | PTR_ERR(skb)); |
Marcel Holtmann | f67743f | 2021-04-06 21:55:52 +0200 | [diff] [blame] | 60 | return; |
Joseph Hwang | 749a6c5 | 2021-11-02 15:19:28 +0800 | [diff] [blame] | 61 | } |
Marcel Holtmann | f67743f | 2021-04-06 21:55:52 +0200 | [diff] [blame] | 62 | |
Joseph Hwang | 749a6c5 | 2021-11-02 15:19:28 +0800 | [diff] [blame] | 63 | /* A basic length check */ |
| 64 | if (skb->len < VENDOR_CAPA_BASE_SIZE) |
| 65 | goto length_error; |
| 66 | |
| 67 | rp = (struct aosp_rp_le_get_vendor_capa *)skb->data; |
| 68 | |
| 69 | version_supported = le16_to_cpu(rp->version_supported); |
| 70 | /* AOSP displays the verion number like v0.98, v1.00, etc. */ |
| 71 | bt_dev_info(hdev, "AOSP extensions version v%u.%02u", |
| 72 | version_supported >> 8, version_supported & 0xff); |
| 73 | |
| 74 | /* Do not support very old versions. */ |
| 75 | if (version_supported < 95) { |
| 76 | bt_dev_warn(hdev, "AOSP capabilities version %u too old", |
| 77 | version_supported); |
| 78 | goto done; |
| 79 | } |
| 80 | |
| 81 | if (version_supported < 98) { |
| 82 | bt_dev_warn(hdev, "AOSP quality report is not supported"); |
| 83 | goto done; |
| 84 | } |
| 85 | |
| 86 | if (skb->len < VENDOR_CAPA_0_98_SIZE) |
| 87 | goto length_error; |
| 88 | |
| 89 | /* The bluetooth_quality_report_support is defined at version |
| 90 | * v0.98. Refer to |
| 91 | * https://cs.android.com/android/platform/superproject/+/ |
| 92 | * master:system/bt/gd/hci/controller.cc;l=477 |
| 93 | */ |
| 94 | if (rp->bluetooth_quality_report_support) { |
| 95 | hdev->aosp_quality_report = true; |
| 96 | bt_dev_info(hdev, "AOSP quality report is supported"); |
| 97 | } |
| 98 | |
| 99 | goto done; |
| 100 | |
| 101 | length_error: |
| 102 | bt_dev_err(hdev, "AOSP capabilities length %d too short", skb->len); |
| 103 | |
| 104 | done: |
Marcel Holtmann | f67743f | 2021-04-06 21:55:52 +0200 | [diff] [blame] | 105 | kfree_skb(skb); |
| 106 | } |
| 107 | |
| 108 | void aosp_do_close(struct hci_dev *hdev) |
| 109 | { |
| 110 | if (!hdev->aosp_capable) |
| 111 | return; |
| 112 | |
| 113 | bt_dev_dbg(hdev, "Cleanup of AOSP extension"); |
| 114 | } |
Joseph Hwang | 258f56d | 2021-11-02 15:19:29 +0800 | [diff] [blame] | 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 | } |