summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/aosp.c
blob: 432ae3aac9e31d60375f60f81a604f8fed3c944c (plain)
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
// 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(skb)) {
		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(skb)) {
		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(skb)) {
		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);
}