mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
Bluetooth: aosp: Support AOSP Bluetooth Quality Report
This patch adds the support of the AOSP Bluetooth Quality Report (BQR) events. Multiple vendors have supported the AOSP Bluetooth Quality Report. When a Bluetooth controller supports the capability, it can enable the aosp capability through hci_set_aosp_capable. Then hci_core will set up the hdev->aosp_set_quality_report callback through aosp_do_open if the controller responds to support the quality report capability. Note that Intel also supports a distinct telemetry quality report specification. Intel sets up the hdev->set_quality_report callback in the btusb driver module. Reviewed-by: Miao-chen Chou <mcchou@chromium.org> Signed-off-by: Joseph Hwang <josephsih@chromium.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
749a6c5942
commit
258f56d11b
@ -112,3 +112,90 @@ void aosp_do_close(struct hci_dev *hdev)
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -8,9 +8,22 @@
|
||||
void aosp_do_open(struct hci_dev *hdev);
|
||||
void aosp_do_close(struct hci_dev *hdev);
|
||||
|
||||
bool aosp_has_quality_report(struct hci_dev *hdev);
|
||||
int aosp_set_quality_report(struct hci_dev *hdev, bool enable);
|
||||
|
||||
#else
|
||||
|
||||
static inline void aosp_do_open(struct hci_dev *hdev) {}
|
||||
static inline void aosp_do_close(struct hci_dev *hdev) {}
|
||||
|
||||
static inline bool aosp_has_quality_report(struct hci_dev *hdev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "mgmt_config.h"
|
||||
#include "msft.h"
|
||||
#include "eir.h"
|
||||
#include "aosp.h"
|
||||
|
||||
#define MGMT_VERSION 1
|
||||
#define MGMT_REVISION 21
|
||||
@ -3934,7 +3935,8 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (hdev && hdev->set_quality_report) {
|
||||
if (hdev && (aosp_has_quality_report(hdev) ||
|
||||
hdev->set_quality_report)) {
|
||||
if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT))
|
||||
flags = BIT(0);
|
||||
else
|
||||
@ -4198,7 +4200,7 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
|
||||
val = !!cp->param[0];
|
||||
changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT));
|
||||
|
||||
if (!hdev->set_quality_report) {
|
||||
if (!aosp_has_quality_report(hdev) && !hdev->set_quality_report) {
|
||||
err = mgmt_cmd_status(sk, hdev->id,
|
||||
MGMT_OP_SET_EXP_FEATURE,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
@ -4206,13 +4208,18 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
err = hdev->set_quality_report(hdev, val);
|
||||
if (hdev->set_quality_report)
|
||||
err = hdev->set_quality_report(hdev, val);
|
||||
else
|
||||
err = aosp_set_quality_report(hdev, val);
|
||||
|
||||
if (err) {
|
||||
err = mgmt_cmd_status(sk, hdev->id,
|
||||
MGMT_OP_SET_EXP_FEATURE,
|
||||
MGMT_STATUS_FAILED);
|
||||
goto unlock_quality_report;
|
||||
}
|
||||
|
||||
if (val)
|
||||
hci_dev_set_flag(hdev, HCI_QUALITY_REPORT);
|
||||
else
|
||||
@ -4224,8 +4231,8 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
|
||||
memcpy(rp.uuid, quality_report_uuid, 16);
|
||||
rp.flags = cpu_to_le32(val ? BIT(0) : 0);
|
||||
hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
|
||||
err = mgmt_cmd_complete(sk, hdev->id,
|
||||
MGMT_OP_SET_EXP_FEATURE, 0,
|
||||
|
||||
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_EXP_FEATURE, 0,
|
||||
&rp, sizeof(rp));
|
||||
|
||||
if (changed)
|
||||
|
Loading…
Reference in New Issue
Block a user