Skip to content

Commit

Permalink
rtw88: coex: Add C2H/H2C handshake with BT mailbox for asking HID Info
Browse files Browse the repository at this point in the history
In order to recognize the gaming controller HID, make a C2H/H2C/Mailbox
handshake to collect all the connected information from BT.

Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220215004855.4098-6-pkshih@realtek.com
  • Loading branch information
Ching-Te Ku authored and Kalle Valo committed Feb 21, 2022
1 parent 0c496a7 commit fc3c66d
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 11 deletions.
150 changes: 139 additions & 11 deletions drivers/net/wireless/realtek/rtw88/coex.c
Original file line number Diff line number Diff line change
Expand Up @@ -2375,6 +2375,7 @@ static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex_stat *coex_stat = &coex->stat;
u8 table_case, tdma_case;

if (coex->under_5g)
Expand All @@ -2383,7 +2384,6 @@ static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);

rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);

if (efuse->share_ant) {
/* Shared-Ant */
Expand All @@ -2395,6 +2395,16 @@ static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
tdma_case = 100;
}

if (coex_stat->bt_game_hid_exist) {
coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[6]);
else
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[5]);
} else {
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
}

rtw_coex_table(rtwdev, false, table_case);
rtw_coex_tdma(rtwdev, false, tdma_case);
}
Expand Down Expand Up @@ -3249,20 +3259,138 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
coex_stat->bt_a2dp_bitpool = 0;

coex_stat->bt_a2dp_sink = ((coex_stat->bt_info_hb3 & BIT(7)) == BIT(7));
if (chip->wl_mimo_ps_support && !coex_stat->bt_inq_page) {
if ((coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION) &&
(coex_stat->hi_pri_tx + coex_stat->hi_pri_rx >
COEX_BT_GAMEHID_CNT) && !coex_stat->bt_slave) {
coex_stat->bt_game_hid_exist = true;
rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], BT game controller exisit!!\n");

rtw_coex_update_bt_link_info(rtwdev);
rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
}

#define COEX_BT_HIDINFO_MTK 0x46
static const u8 coex_bt_hidinfo_ps[] = {0x57, 0x69, 0x72};
static const u8 coex_bt_hidinfo_xb[] = {0x58, 0x62, 0x6f};

void rtw_coex_bt_hid_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_hid *hidinfo;
struct rtw_coex_hid_info_a *hida;
struct rtw_coex_hid_handle_list *hl, *bhl;
u8 sub_id = buf[2], gamehid_cnt = 0, handle, i;
bool cur_game_hid_exist, complete;

if (!chip->wl_mimo_ps_support &&
(sub_id == COEX_BT_HIDINFO_LIST || sub_id == COEX_BT_HIDINFO_A))
return;

rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], HID info notify, sub_id = 0x%x\n", sub_id);

switch (sub_id) {
case COEX_BT_HIDINFO_LIST:
hl = &coex_stat->hid_handle_list;
bhl = (struct rtw_coex_hid_handle_list *)buf;
if (!memcmp(hl, bhl, sizeof(*hl)))
return;
coex_stat->hid_handle_list = *bhl;
memset(&coex_stat->hid_info, 0, sizeof(coex_stat->hid_info));
for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
hidinfo = &coex_stat->hid_info[i];
if (hl->handle[i] != COEX_BT_HIDINFO_NOTCON &&
hl->handle[i] != 0)
hidinfo->hid_handle = hl->handle[i];
}
break;
case COEX_BT_HIDINFO_A:
hida = (struct rtw_coex_hid_info_a *)buf;
handle = hida->handle;
for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
hidinfo = &coex_stat->hid_info[i];
if (hidinfo->hid_handle == handle) {
hidinfo->hid_vendor = hida->vendor;
memcpy(hidinfo->hid_name, hida->name,
sizeof(hidinfo->hid_name));
hidinfo->hid_info_completed = true;
break;
}
}
break;
}
for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
hidinfo = &coex_stat->hid_info[i];
complete = hidinfo->hid_info_completed;
handle = hidinfo->hid_handle;
if (!complete || handle == COEX_BT_HIDINFO_NOTCON ||
handle == 0 || handle >= COEX_BT_BLE_HANDLE_THRS) {
hidinfo->is_game_hid = false;
continue;
}

if (hidinfo->hid_vendor == COEX_BT_HIDINFO_MTK) {
if ((memcmp(hidinfo->hid_name,
coex_bt_hidinfo_ps,
COEX_BT_HIDINFO_NAME)) == 0)
hidinfo->is_game_hid = true;
else if ((memcmp(hidinfo->hid_name,
coex_bt_hidinfo_xb,
COEX_BT_HIDINFO_NAME)) == 0)
hidinfo->is_game_hid = true;
else
hidinfo->is_game_hid = false;
} else {
coex_stat->bt_game_hid_exist = false;
hidinfo->is_game_hid = false;
}
if (hidinfo->is_game_hid)
gamehid_cnt++;
}

rtw_coex_update_bt_link_info(rtwdev);
rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
if (gamehid_cnt > 0)
cur_game_hid_exist = true;
else
cur_game_hid_exist = false;

if (cur_game_hid_exist != coex_stat->bt_game_hid_exist) {
coex_stat->bt_game_hid_exist = cur_game_hid_exist;
rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], HID info changed!bt_game_hid_exist = %d!\n",
coex_stat->bt_game_hid_exist);
rtw_coex_run_coex(rtwdev, COEX_RSN_BTSTATUS);
}
}

void rtw_coex_query_bt_hid_list(struct rtw_dev *rtwdev)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_hid *hidinfo;
u8 i, handle;
bool complete;

if (!chip->wl_mimo_ps_support || coex_stat->wl_under_ips ||
(coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl))
return;

if (!coex_stat->bt_hid_exist &&
!((coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION) &&
(coex_stat->hi_pri_tx + coex_stat->hi_pri_rx >
COEX_BT_GAMEHID_CNT)))
return;

rtw_fw_coex_query_hid_info(rtwdev, COEX_BT_HIDINFO_LIST, 0);

for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
hidinfo = &coex_stat->hid_info[i];
complete = hidinfo->hid_info_completed;
handle = hidinfo->hid_handle;
if (handle == 0 || handle == COEX_BT_HIDINFO_NOTCON ||
handle >= COEX_BT_BLE_HANDLE_THRS || complete)
continue;

rtw_fw_coex_query_hid_info(rtwdev,
COEX_BT_HIDINFO_A,
handle);
}
}

void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/realtek/rtw88/coex.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,12 @@ void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_bt_hid_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type);
void rtw_coex_wl_status_check(struct rtw_dev *rtwdev);
void rtw_coex_query_bt_hid_list(struct rtw_dev *rtwdev);
void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m);

static inline bool rtw_coex_disabled(struct rtw_dev *rtwdev)
Expand Down
15 changes: 15 additions & 0 deletions drivers/net/wireless/realtek/rtw88/fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
case C2H_BT_INFO:
rtw_coex_bt_info_notify(rtwdev, c2h->payload, len);
break;
case C2H_BT_HID_INFO:
rtw_coex_bt_hid_info_notify(rtwdev, c2h->payload, len);
break;
case C2H_WLAN_INFO:
rtw_coex_wl_fwdbginfo_notify(rtwdev, c2h->payload, len);
break;
Expand Down Expand Up @@ -538,6 +541,18 @@ void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev,
rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
}

void rtw_fw_coex_query_hid_info(struct rtw_dev *rtwdev, u8 sub_id, u8 data)
{
u8 h2c_pkt[H2C_PKT_SIZE] = {0};

SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_QUERY_BT_HID_INFO);

SET_COEX_QUERY_HID_INFO_SUBID(h2c_pkt, sub_id);
SET_COEX_QUERY_HID_INFO_DATA1(h2c_pkt, data);

rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
}

void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data)
{
u8 h2c_pkt[H2C_PKT_SIZE] = {0};
Expand Down
9 changes: 9 additions & 0 deletions drivers/net/wireless/realtek/rtw88/fw.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ enum rtw_c2h_cmd_id {
C2H_CCX_TX_RPT = 0x03,
C2H_BT_INFO = 0x09,
C2H_BT_MP_INFO = 0x0b,
C2H_BT_HID_INFO = 0x45,
C2H_RA_RPT = 0x0c,
C2H_HW_FEATURE_REPORT = 0x19,
C2H_WLAN_INFO = 0x27,
Expand Down Expand Up @@ -529,6 +530,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define H2C_CMD_QUERY_BT_MP_INFO 0x67
#define H2C_CMD_BT_WIFI_CONTROL 0x69
#define H2C_CMD_WIFI_CALIBRATION 0x6d
#define H2C_CMD_QUERY_BT_HID_INFO 0x73

#define H2C_CMD_KEEP_ALIVE 0x03
#define H2C_CMD_DISCONNECT_DECISION 0x04
Expand Down Expand Up @@ -681,6 +683,11 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define SET_BT_WIFI_CONTROL_DATA5(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16))

#define SET_COEX_QUERY_HID_INFO_SUBID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_COEX_QUERY_HID_INFO_DATA1(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))

#define SET_KEEP_ALIVE_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_KEEP_ALIVE_ADOPT(h2c_pkt, value) \
Expand Down Expand Up @@ -780,6 +787,8 @@ void rtw_fw_force_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl);
void rtw_fw_bt_ignore_wlan_action(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev,
u8 para1, u8 para2, u8 para3, u8 para4, u8 para5);
void rtw_fw_coex_query_hid_info(struct rtw_dev *rtwdev, u8 sub_id, u8 data);

void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data);
void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/realtek/rtw88/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ static void rtw_watch_dog_work(struct work_struct *work)
clear_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);

rtw_coex_wl_status_check(rtwdev);
rtw_coex_query_bt_hid_list(rtwdev);

if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags))
rtw_coex_wl_status_change_notify(rtwdev, 0);
Expand Down
40 changes: 40 additions & 0 deletions drivers/net/wireless/realtek/rtw88/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,42 @@ struct rtw_coex_dm {
#define COEX_BTINFO_LENGTH_MAX 10
#define COEX_BTINFO_LENGTH 7

#define COEX_BT_HIDINFO_LIST 0x0
#define COEX_BT_HIDINFO_A 0x1
#define COEX_BT_HIDINFO_NAME 3

#define COEX_BT_HIDINFO_LENGTH 6
#define COEX_BT_HIDINFO_HANDLE_NUM 4
#define COEX_BT_HIDINFO_C2H_HANDLE 0
#define COEX_BT_HIDINFO_C2H_VENDOR 1
#define COEX_BT_BLE_HANDLE_THRS 0x10
#define COEX_BT_HIDINFO_NOTCON 0xff

struct rtw_coex_hid {
u8 hid_handle;
u8 hid_vendor;
u8 hid_name[COEX_BT_HIDINFO_NAME];
bool hid_info_completed;
bool is_game_hid;
};

struct rtw_coex_hid_handle_list {
u8 cmd_id;
u8 len;
u8 subid;
u8 handle_cnt;
u8 handle[COEX_BT_HIDINFO_HANDLE_NUM];
} __packed;

struct rtw_coex_hid_info_a {
u8 cmd_id;
u8 len;
u8 subid;
u8 handle;
u8 vendor;
u8 name[COEX_BT_HIDINFO_NAME];
} __packed;

struct rtw_coex_stat {
bool bt_disabled;
bool bt_disabled_pre;
Expand Down Expand Up @@ -1386,6 +1422,7 @@ struct rtw_coex_stat {
bool bt_418_hid_exist;
bool bt_ble_hid_exist;
bool bt_game_hid_exist;
bool bt_hid_handle_cnt;
bool bt_mailbox_reply;

bool wl_under_lps;
Expand Down Expand Up @@ -1464,6 +1501,9 @@ struct rtw_coex_stat {

u32 darfrc;
u32 darfrch;

struct rtw_coex_hid hid_info[COEX_BT_HIDINFO_HANDLE_NUM];
struct rtw_coex_hid_handle_list hid_handle_list;
};

struct rtw_coex {
Expand Down

0 comments on commit fc3c66d

Please sign in to comment.