2021-04-06 22:55:52 +03:00
// 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"
2021-11-02 10:19:28 +03:00
/* 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
2021-04-06 22:55:52 +03:00
void aosp_do_open ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
2021-11-02 10:19:28 +03:00
struct aosp_rp_le_get_vendor_capa * rp ;
u16 version_supported ;
2021-04-06 22:55:52 +03:00
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 ) ;
2022-07-22 14:53:07 +03:00
if ( IS_ERR_OR_NULL ( skb ) ) {
if ( ! skb )
skb = ERR_PTR ( - EIO ) ;
2021-11-02 10:19:28 +03:00
bt_dev_err ( hdev , " AOSP get vendor capabilities (%ld) " ,
PTR_ERR ( skb ) ) ;
2021-04-06 22:55:52 +03:00
return ;
2021-11-02 10:19:28 +03:00
}
/* 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 ) ;
2021-04-06 22:55:52 +03:00
2021-11-02 10:19:28 +03:00
done :
2021-04-06 22:55:52 +03:00
kfree_skb ( skb ) ;
}
void aosp_do_close ( struct hci_dev * hdev )
{
if ( ! hdev - > aosp_capable )
return ;
bt_dev_dbg ( hdev , " Cleanup of AOSP extension " ) ;
}
2021-11-02 10:19:29 +03:00
/* 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 ) ;
2022-07-22 14:53:07 +03:00
if ( IS_ERR_OR_NULL ( skb ) ) {
if ( ! skb )
skb = ERR_PTR ( - EIO ) ;
2021-11-02 10:19:29 +03:00
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 ) ;
2022-07-22 14:53:07 +03:00
if ( IS_ERR_OR_NULL ( skb ) ) {
if ( ! skb )
skb = ERR_PTR ( - EIO ) ;
2021-11-02 10:19:29 +03:00
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 ) ;
}