123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- // 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_OR_NULL(skb)) {
- if (!skb)
- skb = ERR_PTR(-EIO);
- 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_OR_NULL(skb)) {
- if (!skb)
- skb = ERR_PTR(-EIO);
- 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_OR_NULL(skb)) {
- if (!skb)
- skb = ERR_PTR(-EIO);
- 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);
- }
|