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 | |
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 | |
43 | void aosp_do_open(struct hci_dev *hdev) |
44 | { |
45 | struct sk_buff *skb; |
46 | struct aosp_rp_le_get_vendor_capa *rp; |
47 | u16 version_supported; |
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), plen: 0, NULL, |
56 | HCI_CMD_TIMEOUT); |
57 | if (IS_ERR_OR_NULL(ptr: skb)) { |
58 | if (!skb) |
59 | skb = ERR_PTR(error: -EIO); |
60 | |
61 | bt_dev_err(hdev, "AOSP get vendor capabilities (%ld)" , |
62 | PTR_ERR(skb)); |
63 | return; |
64 | } |
65 | |
66 | /* A basic length check */ |
67 | if (skb->len < VENDOR_CAPA_BASE_SIZE) |
68 | goto length_error; |
69 | |
70 | rp = (struct aosp_rp_le_get_vendor_capa *)skb->data; |
71 | |
72 | version_supported = le16_to_cpu(rp->version_supported); |
73 | /* AOSP displays the verion number like v0.98, v1.00, etc. */ |
74 | bt_dev_info(hdev, "AOSP extensions version v%u.%02u" , |
75 | version_supported >> 8, version_supported & 0xff); |
76 | |
77 | /* Do not support very old versions. */ |
78 | if (version_supported < 95) { |
79 | bt_dev_warn(hdev, "AOSP capabilities version %u too old" , |
80 | version_supported); |
81 | goto done; |
82 | } |
83 | |
84 | if (version_supported < 98) { |
85 | bt_dev_warn(hdev, "AOSP quality report is not supported" ); |
86 | goto done; |
87 | } |
88 | |
89 | if (skb->len < VENDOR_CAPA_0_98_SIZE) |
90 | goto length_error; |
91 | |
92 | /* The bluetooth_quality_report_support is defined at version |
93 | * v0.98. Refer to |
94 | * https://cs.android.com/android/platform/superproject/+/ |
95 | * master:system/bt/gd/hci/controller.cc;l=477 |
96 | */ |
97 | if (rp->bluetooth_quality_report_support) { |
98 | hdev->aosp_quality_report = true; |
99 | bt_dev_info(hdev, "AOSP quality report is supported" ); |
100 | } |
101 | |
102 | goto done; |
103 | |
104 | length_error: |
105 | bt_dev_err(hdev, "AOSP capabilities length %d too short" , skb->len); |
106 | |
107 | done: |
108 | kfree_skb(skb); |
109 | } |
110 | |
111 | void aosp_do_close(struct hci_dev *hdev) |
112 | { |
113 | if (!hdev->aosp_capable) |
114 | return; |
115 | |
116 | bt_dev_dbg(hdev, "Cleanup of AOSP extension" ); |
117 | } |
118 | |
119 | /* BQR command */ |
120 | #define BQR_OPCODE hci_opcode_pack(0x3f, 0x015e) |
121 | |
122 | /* BQR report action */ |
123 | #define REPORT_ACTION_ADD 0x00 |
124 | #define REPORT_ACTION_DELETE 0x01 |
125 | #define REPORT_ACTION_CLEAR 0x02 |
126 | |
127 | /* BQR event masks */ |
128 | #define QUALITY_MONITORING BIT(0) |
129 | #define APPRAOCHING_LSTO BIT(1) |
130 | #define A2DP_AUDIO_CHOPPY BIT(2) |
131 | #define SCO_VOICE_CHOPPY BIT(3) |
132 | |
133 | #define DEFAULT_BQR_EVENT_MASK (QUALITY_MONITORING | APPRAOCHING_LSTO | \ |
134 | A2DP_AUDIO_CHOPPY | SCO_VOICE_CHOPPY) |
135 | |
136 | /* Reporting at milliseconds so as not to stress the controller too much. |
137 | * Range: 0 ~ 65535 ms |
138 | */ |
139 | #define DEFALUT_REPORT_INTERVAL_MS 5000 |
140 | |
141 | struct aosp_bqr_cp { |
142 | __u8 report_action; |
143 | __u32 event_mask; |
144 | __u16 min_report_interval; |
145 | } __packed; |
146 | |
147 | static int enable_quality_report(struct hci_dev *hdev) |
148 | { |
149 | struct sk_buff *skb; |
150 | struct aosp_bqr_cp cp; |
151 | |
152 | cp.report_action = REPORT_ACTION_ADD; |
153 | cp.event_mask = DEFAULT_BQR_EVENT_MASK; |
154 | cp.min_report_interval = DEFALUT_REPORT_INTERVAL_MS; |
155 | |
156 | skb = __hci_cmd_sync(hdev, BQR_OPCODE, plen: sizeof(cp), param: &cp, |
157 | HCI_CMD_TIMEOUT); |
158 | if (IS_ERR_OR_NULL(ptr: skb)) { |
159 | if (!skb) |
160 | skb = ERR_PTR(error: -EIO); |
161 | |
162 | bt_dev_err(hdev, "Enabling Android BQR failed (%ld)" , |
163 | PTR_ERR(skb)); |
164 | return PTR_ERR(ptr: skb); |
165 | } |
166 | |
167 | kfree_skb(skb); |
168 | return 0; |
169 | } |
170 | |
171 | static int disable_quality_report(struct hci_dev *hdev) |
172 | { |
173 | struct sk_buff *skb; |
174 | struct aosp_bqr_cp cp = { 0 }; |
175 | |
176 | cp.report_action = REPORT_ACTION_CLEAR; |
177 | |
178 | skb = __hci_cmd_sync(hdev, BQR_OPCODE, plen: sizeof(cp), param: &cp, |
179 | HCI_CMD_TIMEOUT); |
180 | if (IS_ERR_OR_NULL(ptr: skb)) { |
181 | if (!skb) |
182 | skb = ERR_PTR(error: -EIO); |
183 | |
184 | bt_dev_err(hdev, "Disabling Android BQR failed (%ld)" , |
185 | PTR_ERR(skb)); |
186 | return PTR_ERR(ptr: skb); |
187 | } |
188 | |
189 | kfree_skb(skb); |
190 | return 0; |
191 | } |
192 | |
193 | bool aosp_has_quality_report(struct hci_dev *hdev) |
194 | { |
195 | return hdev->aosp_quality_report; |
196 | } |
197 | |
198 | int aosp_set_quality_report(struct hci_dev *hdev, bool enable) |
199 | { |
200 | if (!aosp_has_quality_report(hdev)) |
201 | return -EOPNOTSUPP; |
202 | |
203 | bt_dev_dbg(hdev, "quality report enable %d" , enable); |
204 | |
205 | /* Enable or disable the quality report feature. */ |
206 | if (enable) |
207 | return enable_quality_report(hdev); |
208 | else |
209 | return disable_quality_report(hdev); |
210 | } |
211 | |