162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2021 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 762306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "aosp.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* Command complete parameters of LE_Get_Vendor_Capabilities_Command 1262306a36Sopenharmony_ci * The parameters grow over time. The base version that declares the 1362306a36Sopenharmony_ci * version_supported field is v0.95. Refer to 1462306a36Sopenharmony_ci * https://cs.android.com/android/platform/superproject/+/master:system/ 1562306a36Sopenharmony_ci * bt/gd/hci/controller.cc;l=452?q=le_get_vendor_capabilities_handler 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_cistruct aosp_rp_le_get_vendor_capa { 1862306a36Sopenharmony_ci /* v0.95: 15 octets */ 1962306a36Sopenharmony_ci __u8 status; 2062306a36Sopenharmony_ci __u8 max_advt_instances; 2162306a36Sopenharmony_ci __u8 offloaded_resolution_of_private_address; 2262306a36Sopenharmony_ci __le16 total_scan_results_storage; 2362306a36Sopenharmony_ci __u8 max_irk_list_sz; 2462306a36Sopenharmony_ci __u8 filtering_support; 2562306a36Sopenharmony_ci __u8 max_filter; 2662306a36Sopenharmony_ci __u8 activity_energy_info_support; 2762306a36Sopenharmony_ci __le16 version_supported; 2862306a36Sopenharmony_ci __le16 total_num_of_advt_tracked; 2962306a36Sopenharmony_ci __u8 extended_scan_support; 3062306a36Sopenharmony_ci __u8 debug_logging_supported; 3162306a36Sopenharmony_ci /* v0.96: 16 octets */ 3262306a36Sopenharmony_ci __u8 le_address_generation_offloading_support; 3362306a36Sopenharmony_ci /* v0.98: 21 octets */ 3462306a36Sopenharmony_ci __le32 a2dp_source_offload_capability_mask; 3562306a36Sopenharmony_ci __u8 bluetooth_quality_report_support; 3662306a36Sopenharmony_ci /* v1.00: 25 octets */ 3762306a36Sopenharmony_ci __le32 dynamic_audio_buffer_support; 3862306a36Sopenharmony_ci} __packed; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define VENDOR_CAPA_BASE_SIZE 15 4162306a36Sopenharmony_ci#define VENDOR_CAPA_0_98_SIZE 21 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_civoid aosp_do_open(struct hci_dev *hdev) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct sk_buff *skb; 4662306a36Sopenharmony_ci struct aosp_rp_le_get_vendor_capa *rp; 4762306a36Sopenharmony_ci u16 version_supported; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (!hdev->aosp_capable) 5062306a36Sopenharmony_ci return; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci bt_dev_dbg(hdev, "Initialize AOSP extension"); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* LE Get Vendor Capabilities Command */ 5562306a36Sopenharmony_ci skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL, 5662306a36Sopenharmony_ci HCI_CMD_TIMEOUT); 5762306a36Sopenharmony_ci if (IS_ERR_OR_NULL(skb)) { 5862306a36Sopenharmony_ci if (!skb) 5962306a36Sopenharmony_ci skb = ERR_PTR(-EIO); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci bt_dev_err(hdev, "AOSP get vendor capabilities (%ld)", 6262306a36Sopenharmony_ci PTR_ERR(skb)); 6362306a36Sopenharmony_ci return; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* A basic length check */ 6762306a36Sopenharmony_ci if (skb->len < VENDOR_CAPA_BASE_SIZE) 6862306a36Sopenharmony_ci goto length_error; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci rp = (struct aosp_rp_le_get_vendor_capa *)skb->data; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci version_supported = le16_to_cpu(rp->version_supported); 7362306a36Sopenharmony_ci /* AOSP displays the verion number like v0.98, v1.00, etc. */ 7462306a36Sopenharmony_ci bt_dev_info(hdev, "AOSP extensions version v%u.%02u", 7562306a36Sopenharmony_ci version_supported >> 8, version_supported & 0xff); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Do not support very old versions. */ 7862306a36Sopenharmony_ci if (version_supported < 95) { 7962306a36Sopenharmony_ci bt_dev_warn(hdev, "AOSP capabilities version %u too old", 8062306a36Sopenharmony_ci version_supported); 8162306a36Sopenharmony_ci goto done; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (version_supported < 98) { 8562306a36Sopenharmony_ci bt_dev_warn(hdev, "AOSP quality report is not supported"); 8662306a36Sopenharmony_ci goto done; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (skb->len < VENDOR_CAPA_0_98_SIZE) 9062306a36Sopenharmony_ci goto length_error; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* The bluetooth_quality_report_support is defined at version 9362306a36Sopenharmony_ci * v0.98. Refer to 9462306a36Sopenharmony_ci * https://cs.android.com/android/platform/superproject/+/ 9562306a36Sopenharmony_ci * master:system/bt/gd/hci/controller.cc;l=477 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci if (rp->bluetooth_quality_report_support) { 9862306a36Sopenharmony_ci hdev->aosp_quality_report = true; 9962306a36Sopenharmony_ci bt_dev_info(hdev, "AOSP quality report is supported"); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci goto done; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cilength_error: 10562306a36Sopenharmony_ci bt_dev_err(hdev, "AOSP capabilities length %d too short", skb->len); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cidone: 10862306a36Sopenharmony_ci kfree_skb(skb); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_civoid aosp_do_close(struct hci_dev *hdev) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci if (!hdev->aosp_capable) 11462306a36Sopenharmony_ci return; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci bt_dev_dbg(hdev, "Cleanup of AOSP extension"); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* BQR command */ 12062306a36Sopenharmony_ci#define BQR_OPCODE hci_opcode_pack(0x3f, 0x015e) 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* BQR report action */ 12362306a36Sopenharmony_ci#define REPORT_ACTION_ADD 0x00 12462306a36Sopenharmony_ci#define REPORT_ACTION_DELETE 0x01 12562306a36Sopenharmony_ci#define REPORT_ACTION_CLEAR 0x02 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* BQR event masks */ 12862306a36Sopenharmony_ci#define QUALITY_MONITORING BIT(0) 12962306a36Sopenharmony_ci#define APPRAOCHING_LSTO BIT(1) 13062306a36Sopenharmony_ci#define A2DP_AUDIO_CHOPPY BIT(2) 13162306a36Sopenharmony_ci#define SCO_VOICE_CHOPPY BIT(3) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define DEFAULT_BQR_EVENT_MASK (QUALITY_MONITORING | APPRAOCHING_LSTO | \ 13462306a36Sopenharmony_ci A2DP_AUDIO_CHOPPY | SCO_VOICE_CHOPPY) 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* Reporting at milliseconds so as not to stress the controller too much. 13762306a36Sopenharmony_ci * Range: 0 ~ 65535 ms 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci#define DEFALUT_REPORT_INTERVAL_MS 5000 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistruct aosp_bqr_cp { 14262306a36Sopenharmony_ci __u8 report_action; 14362306a36Sopenharmony_ci __u32 event_mask; 14462306a36Sopenharmony_ci __u16 min_report_interval; 14562306a36Sopenharmony_ci} __packed; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int enable_quality_report(struct hci_dev *hdev) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct sk_buff *skb; 15062306a36Sopenharmony_ci struct aosp_bqr_cp cp; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci cp.report_action = REPORT_ACTION_ADD; 15362306a36Sopenharmony_ci cp.event_mask = DEFAULT_BQR_EVENT_MASK; 15462306a36Sopenharmony_ci cp.min_report_interval = DEFALUT_REPORT_INTERVAL_MS; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp, 15762306a36Sopenharmony_ci HCI_CMD_TIMEOUT); 15862306a36Sopenharmony_ci if (IS_ERR_OR_NULL(skb)) { 15962306a36Sopenharmony_ci if (!skb) 16062306a36Sopenharmony_ci skb = ERR_PTR(-EIO); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci bt_dev_err(hdev, "Enabling Android BQR failed (%ld)", 16362306a36Sopenharmony_ci PTR_ERR(skb)); 16462306a36Sopenharmony_ci return PTR_ERR(skb); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci kfree_skb(skb); 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int disable_quality_report(struct hci_dev *hdev) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct sk_buff *skb; 17462306a36Sopenharmony_ci struct aosp_bqr_cp cp = { 0 }; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci cp.report_action = REPORT_ACTION_CLEAR; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp, 17962306a36Sopenharmony_ci HCI_CMD_TIMEOUT); 18062306a36Sopenharmony_ci if (IS_ERR_OR_NULL(skb)) { 18162306a36Sopenharmony_ci if (!skb) 18262306a36Sopenharmony_ci skb = ERR_PTR(-EIO); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci bt_dev_err(hdev, "Disabling Android BQR failed (%ld)", 18562306a36Sopenharmony_ci PTR_ERR(skb)); 18662306a36Sopenharmony_ci return PTR_ERR(skb); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci kfree_skb(skb); 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cibool aosp_has_quality_report(struct hci_dev *hdev) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci return hdev->aosp_quality_report; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciint aosp_set_quality_report(struct hci_dev *hdev, bool enable) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci if (!aosp_has_quality_report(hdev)) 20162306a36Sopenharmony_ci return -EOPNOTSUPP; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci bt_dev_dbg(hdev, "quality report enable %d", enable); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Enable or disable the quality report feature. */ 20662306a36Sopenharmony_ci if (enable) 20762306a36Sopenharmony_ci return enable_quality_report(hdev); 20862306a36Sopenharmony_ci else 20962306a36Sopenharmony_ci return disable_quality_report(hdev); 21062306a36Sopenharmony_ci} 211