1f67743f9SMarcel Holtmann // SPDX-License-Identifier: GPL-2.0-only
2f67743f9SMarcel Holtmann /*
3f67743f9SMarcel Holtmann * Copyright (C) 2021 Intel Corporation
4f67743f9SMarcel Holtmann */
5f67743f9SMarcel Holtmann
6f67743f9SMarcel Holtmann #include <net/bluetooth/bluetooth.h>
7f67743f9SMarcel Holtmann #include <net/bluetooth/hci_core.h>
8f67743f9SMarcel Holtmann
9f67743f9SMarcel Holtmann #include "aosp.h"
10f67743f9SMarcel Holtmann
11749a6c59SJoseph Hwang /* Command complete parameters of LE_Get_Vendor_Capabilities_Command
12749a6c59SJoseph Hwang * The parameters grow over time. The base version that declares the
13749a6c59SJoseph Hwang * version_supported field is v0.95. Refer to
14749a6c59SJoseph Hwang * https://cs.android.com/android/platform/superproject/+/master:system/
15749a6c59SJoseph Hwang * bt/gd/hci/controller.cc;l=452?q=le_get_vendor_capabilities_handler
16749a6c59SJoseph Hwang */
17749a6c59SJoseph Hwang struct aosp_rp_le_get_vendor_capa {
18749a6c59SJoseph Hwang /* v0.95: 15 octets */
19749a6c59SJoseph Hwang __u8 status;
20749a6c59SJoseph Hwang __u8 max_advt_instances;
21749a6c59SJoseph Hwang __u8 offloaded_resolution_of_private_address;
22749a6c59SJoseph Hwang __le16 total_scan_results_storage;
23749a6c59SJoseph Hwang __u8 max_irk_list_sz;
24749a6c59SJoseph Hwang __u8 filtering_support;
25749a6c59SJoseph Hwang __u8 max_filter;
26749a6c59SJoseph Hwang __u8 activity_energy_info_support;
27749a6c59SJoseph Hwang __le16 version_supported;
28749a6c59SJoseph Hwang __le16 total_num_of_advt_tracked;
29749a6c59SJoseph Hwang __u8 extended_scan_support;
30749a6c59SJoseph Hwang __u8 debug_logging_supported;
31749a6c59SJoseph Hwang /* v0.96: 16 octets */
32749a6c59SJoseph Hwang __u8 le_address_generation_offloading_support;
33749a6c59SJoseph Hwang /* v0.98: 21 octets */
34749a6c59SJoseph Hwang __le32 a2dp_source_offload_capability_mask;
35749a6c59SJoseph Hwang __u8 bluetooth_quality_report_support;
36749a6c59SJoseph Hwang /* v1.00: 25 octets */
37749a6c59SJoseph Hwang __le32 dynamic_audio_buffer_support;
38749a6c59SJoseph Hwang } __packed;
39749a6c59SJoseph Hwang
40749a6c59SJoseph Hwang #define VENDOR_CAPA_BASE_SIZE 15
41749a6c59SJoseph Hwang #define VENDOR_CAPA_0_98_SIZE 21
42749a6c59SJoseph Hwang
aosp_do_open(struct hci_dev * hdev)43f67743f9SMarcel Holtmann void aosp_do_open(struct hci_dev *hdev)
44f67743f9SMarcel Holtmann {
45f67743f9SMarcel Holtmann struct sk_buff *skb;
46749a6c59SJoseph Hwang struct aosp_rp_le_get_vendor_capa *rp;
47749a6c59SJoseph Hwang u16 version_supported;
48f67743f9SMarcel Holtmann
49f67743f9SMarcel Holtmann if (!hdev->aosp_capable)
50f67743f9SMarcel Holtmann return;
51f67743f9SMarcel Holtmann
52f67743f9SMarcel Holtmann bt_dev_dbg(hdev, "Initialize AOSP extension");
53f67743f9SMarcel Holtmann
54f67743f9SMarcel Holtmann /* LE Get Vendor Capabilities Command */
55f67743f9SMarcel Holtmann skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL,
56f67743f9SMarcel Holtmann HCI_CMD_TIMEOUT);
57*ce78e557SSoenke Huster if (IS_ERR_OR_NULL(skb)) {
58*ce78e557SSoenke Huster if (!skb)
59*ce78e557SSoenke Huster skb = ERR_PTR(-EIO);
60*ce78e557SSoenke Huster
61749a6c59SJoseph Hwang bt_dev_err(hdev, "AOSP get vendor capabilities (%ld)",
62749a6c59SJoseph Hwang PTR_ERR(skb));
63f67743f9SMarcel Holtmann return;
64749a6c59SJoseph Hwang }
65f67743f9SMarcel Holtmann
66749a6c59SJoseph Hwang /* A basic length check */
67749a6c59SJoseph Hwang if (skb->len < VENDOR_CAPA_BASE_SIZE)
68749a6c59SJoseph Hwang goto length_error;
69749a6c59SJoseph Hwang
70749a6c59SJoseph Hwang rp = (struct aosp_rp_le_get_vendor_capa *)skb->data;
71749a6c59SJoseph Hwang
72749a6c59SJoseph Hwang version_supported = le16_to_cpu(rp->version_supported);
73749a6c59SJoseph Hwang /* AOSP displays the verion number like v0.98, v1.00, etc. */
74749a6c59SJoseph Hwang bt_dev_info(hdev, "AOSP extensions version v%u.%02u",
75749a6c59SJoseph Hwang version_supported >> 8, version_supported & 0xff);
76749a6c59SJoseph Hwang
77749a6c59SJoseph Hwang /* Do not support very old versions. */
78749a6c59SJoseph Hwang if (version_supported < 95) {
79749a6c59SJoseph Hwang bt_dev_warn(hdev, "AOSP capabilities version %u too old",
80749a6c59SJoseph Hwang version_supported);
81749a6c59SJoseph Hwang goto done;
82749a6c59SJoseph Hwang }
83749a6c59SJoseph Hwang
84749a6c59SJoseph Hwang if (version_supported < 98) {
85749a6c59SJoseph Hwang bt_dev_warn(hdev, "AOSP quality report is not supported");
86749a6c59SJoseph Hwang goto done;
87749a6c59SJoseph Hwang }
88749a6c59SJoseph Hwang
89749a6c59SJoseph Hwang if (skb->len < VENDOR_CAPA_0_98_SIZE)
90749a6c59SJoseph Hwang goto length_error;
91749a6c59SJoseph Hwang
92749a6c59SJoseph Hwang /* The bluetooth_quality_report_support is defined at version
93749a6c59SJoseph Hwang * v0.98. Refer to
94749a6c59SJoseph Hwang * https://cs.android.com/android/platform/superproject/+/
95749a6c59SJoseph Hwang * master:system/bt/gd/hci/controller.cc;l=477
96749a6c59SJoseph Hwang */
97749a6c59SJoseph Hwang if (rp->bluetooth_quality_report_support) {
98749a6c59SJoseph Hwang hdev->aosp_quality_report = true;
99749a6c59SJoseph Hwang bt_dev_info(hdev, "AOSP quality report is supported");
100749a6c59SJoseph Hwang }
101749a6c59SJoseph Hwang
102749a6c59SJoseph Hwang goto done;
103749a6c59SJoseph Hwang
104749a6c59SJoseph Hwang length_error:
105749a6c59SJoseph Hwang bt_dev_err(hdev, "AOSP capabilities length %d too short", skb->len);
106749a6c59SJoseph Hwang
107749a6c59SJoseph Hwang done:
108f67743f9SMarcel Holtmann kfree_skb(skb);
109f67743f9SMarcel Holtmann }
110f67743f9SMarcel Holtmann
aosp_do_close(struct hci_dev * hdev)111f67743f9SMarcel Holtmann void aosp_do_close(struct hci_dev *hdev)
112f67743f9SMarcel Holtmann {
113f67743f9SMarcel Holtmann if (!hdev->aosp_capable)
114f67743f9SMarcel Holtmann return;
115f67743f9SMarcel Holtmann
116f67743f9SMarcel Holtmann bt_dev_dbg(hdev, "Cleanup of AOSP extension");
117f67743f9SMarcel Holtmann }
118258f56d1SJoseph Hwang
119258f56d1SJoseph Hwang /* BQR command */
120258f56d1SJoseph Hwang #define BQR_OPCODE hci_opcode_pack(0x3f, 0x015e)
121258f56d1SJoseph Hwang
122258f56d1SJoseph Hwang /* BQR report action */
123258f56d1SJoseph Hwang #define REPORT_ACTION_ADD 0x00
124258f56d1SJoseph Hwang #define REPORT_ACTION_DELETE 0x01
125258f56d1SJoseph Hwang #define REPORT_ACTION_CLEAR 0x02
126258f56d1SJoseph Hwang
127258f56d1SJoseph Hwang /* BQR event masks */
128258f56d1SJoseph Hwang #define QUALITY_MONITORING BIT(0)
129258f56d1SJoseph Hwang #define APPRAOCHING_LSTO BIT(1)
130258f56d1SJoseph Hwang #define A2DP_AUDIO_CHOPPY BIT(2)
131258f56d1SJoseph Hwang #define SCO_VOICE_CHOPPY BIT(3)
132258f56d1SJoseph Hwang
133258f56d1SJoseph Hwang #define DEFAULT_BQR_EVENT_MASK (QUALITY_MONITORING | APPRAOCHING_LSTO | \
134258f56d1SJoseph Hwang A2DP_AUDIO_CHOPPY | SCO_VOICE_CHOPPY)
135258f56d1SJoseph Hwang
136258f56d1SJoseph Hwang /* Reporting at milliseconds so as not to stress the controller too much.
137258f56d1SJoseph Hwang * Range: 0 ~ 65535 ms
138258f56d1SJoseph Hwang */
139258f56d1SJoseph Hwang #define DEFALUT_REPORT_INTERVAL_MS 5000
140258f56d1SJoseph Hwang
141258f56d1SJoseph Hwang struct aosp_bqr_cp {
142258f56d1SJoseph Hwang __u8 report_action;
143258f56d1SJoseph Hwang __u32 event_mask;
144258f56d1SJoseph Hwang __u16 min_report_interval;
145258f56d1SJoseph Hwang } __packed;
146258f56d1SJoseph Hwang
enable_quality_report(struct hci_dev * hdev)147258f56d1SJoseph Hwang static int enable_quality_report(struct hci_dev *hdev)
148258f56d1SJoseph Hwang {
149258f56d1SJoseph Hwang struct sk_buff *skb;
150258f56d1SJoseph Hwang struct aosp_bqr_cp cp;
151258f56d1SJoseph Hwang
152258f56d1SJoseph Hwang cp.report_action = REPORT_ACTION_ADD;
153258f56d1SJoseph Hwang cp.event_mask = DEFAULT_BQR_EVENT_MASK;
154258f56d1SJoseph Hwang cp.min_report_interval = DEFALUT_REPORT_INTERVAL_MS;
155258f56d1SJoseph Hwang
156258f56d1SJoseph Hwang skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp,
157258f56d1SJoseph Hwang HCI_CMD_TIMEOUT);
158*ce78e557SSoenke Huster if (IS_ERR_OR_NULL(skb)) {
159*ce78e557SSoenke Huster if (!skb)
160*ce78e557SSoenke Huster skb = ERR_PTR(-EIO);
161*ce78e557SSoenke Huster
162258f56d1SJoseph Hwang bt_dev_err(hdev, "Enabling Android BQR failed (%ld)",
163258f56d1SJoseph Hwang PTR_ERR(skb));
164258f56d1SJoseph Hwang return PTR_ERR(skb);
165258f56d1SJoseph Hwang }
166258f56d1SJoseph Hwang
167258f56d1SJoseph Hwang kfree_skb(skb);
168258f56d1SJoseph Hwang return 0;
169258f56d1SJoseph Hwang }
170258f56d1SJoseph Hwang
disable_quality_report(struct hci_dev * hdev)171258f56d1SJoseph Hwang static int disable_quality_report(struct hci_dev *hdev)
172258f56d1SJoseph Hwang {
173258f56d1SJoseph Hwang struct sk_buff *skb;
174258f56d1SJoseph Hwang struct aosp_bqr_cp cp = { 0 };
175258f56d1SJoseph Hwang
176258f56d1SJoseph Hwang cp.report_action = REPORT_ACTION_CLEAR;
177258f56d1SJoseph Hwang
178258f56d1SJoseph Hwang skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp,
179258f56d1SJoseph Hwang HCI_CMD_TIMEOUT);
180*ce78e557SSoenke Huster if (IS_ERR_OR_NULL(skb)) {
181*ce78e557SSoenke Huster if (!skb)
182*ce78e557SSoenke Huster skb = ERR_PTR(-EIO);
183*ce78e557SSoenke Huster
184258f56d1SJoseph Hwang bt_dev_err(hdev, "Disabling Android BQR failed (%ld)",
185258f56d1SJoseph Hwang PTR_ERR(skb));
186258f56d1SJoseph Hwang return PTR_ERR(skb);
187258f56d1SJoseph Hwang }
188258f56d1SJoseph Hwang
189258f56d1SJoseph Hwang kfree_skb(skb);
190258f56d1SJoseph Hwang return 0;
191258f56d1SJoseph Hwang }
192258f56d1SJoseph Hwang
aosp_has_quality_report(struct hci_dev * hdev)193258f56d1SJoseph Hwang bool aosp_has_quality_report(struct hci_dev *hdev)
194258f56d1SJoseph Hwang {
195258f56d1SJoseph Hwang return hdev->aosp_quality_report;
196258f56d1SJoseph Hwang }
197258f56d1SJoseph Hwang
aosp_set_quality_report(struct hci_dev * hdev,bool enable)198258f56d1SJoseph Hwang int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
199258f56d1SJoseph Hwang {
200258f56d1SJoseph Hwang if (!aosp_has_quality_report(hdev))
201258f56d1SJoseph Hwang return -EOPNOTSUPP;
202258f56d1SJoseph Hwang
203258f56d1SJoseph Hwang bt_dev_dbg(hdev, "quality report enable %d", enable);
204258f56d1SJoseph Hwang
205258f56d1SJoseph Hwang /* Enable or disable the quality report feature. */
206258f56d1SJoseph Hwang if (enable)
207258f56d1SJoseph Hwang return enable_quality_report(hdev);
208258f56d1SJoseph Hwang else
209258f56d1SJoseph Hwang return disable_quality_report(hdev);
210258f56d1SJoseph Hwang }
211