blob: 1033327dc0a8d92d553963be50380cb9a5392600 [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2012-2014 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* Vendor-specific handler for HCI events
*
******************************************************************************/
#include "gki.h"
#include "nfc_hal_api.h"
#include "nfc_hal_int.h"
#include "nfc_hal_target.h"
#if (NFC_HAL_HCI_INCLUDED == TRUE)
#include "nfc_hal_nv_ci.h"
#include "nfc_hal_nv_co.h"
#include <string.h>
#ifndef NFC_HAL_HCI_NV_READ_TIMEOUT
#define NFC_HAL_HCI_NV_READ_TIMEOUT 1000
#endif
#ifndef NFC_HAL_HCI_NFCC_RSP_TIMEOUT
#define NFC_HAL_HCI_NFCC_RSP_TIMEOUT 3000
#endif
#define NFC_HAL_HCI_NETWK_CMD_TYPE_A_CE_PIPE_INFO_OFFSET 0x0C
#define NFC_HAL_HCI_NETWK_CMD_TYPE_B_CE_PIPE_INFO_OFFSET 0x32
#define NFC_HAL_HCI_NETWK_CMD_TYPE_BP_CE_PIPE_INFO_OFFSET 0x7F
#define NFC_HAL_HCI_NETWK_CMD_TYPE_F_CE_PIPE_INFO_OFFSET 0xB4
#define NFC_HAL_HCI_PIPE_VALID_MASK 0x80
#define NFC_HAL_HCI_FIRST_BOOT_SESSION_ID_0_VAL 0xFF
#define NFC_HAL_HCI_NEXT_BOOT_SESSION_ID_0_VAL 0xFE
/* Version string for BCM20791B3 */
const uint8_t NFC_HAL_DM_BCM20791B3_STR[] = "20791B3";
#define NFC_HAL_DM_BCM20791B3_STR_LEN (sizeof(NFC_HAL_DM_BCM20791B3_STR) - 1)
/* Version string for BCM20791B4 */
const uint8_t NFC_HAL_DM_BCM20791B4_STR[] = "20791B4";
#define NFC_HAL_DM_BCM20791B4_STR_LEN (sizeof(NFC_HAL_DM_BCM20791B4_STR) - 1)
/* Version string for BCM43341B0 */
const uint8_t NFC_HAL_DM_BCM43341B0_STR[] = "43341B0";
#define NFC_HAL_DM_BCM43341B0_STR_LEN (sizeof(NFC_HAL_DM_BCM43341B0_STR) - 1)
extern tNFC_HAL_CFG* p_nfc_hal_cfg;
/****************************************************************************
** Internal function prototypes
****************************************************************************/
static void nfc_hal_hci_set_next_hci_netwk_config(uint8_t block);
static void nfc_hal_hci_remove_dyn_pipe_to_uicc1(void);
static void nfc_hal_hci_handle_nv_read(uint8_t block, tHAL_NFC_STATUS status,
uint16_t size);
static void nfc_hal_hci_init_complete(tHAL_NFC_STATUS status);
static void nfc_hal_hci_vsc_cback(tNFC_HAL_NCI_EVT event, uint16_t data_len,
uint8_t* p_data);
/*******************************************************************************
**
** Function nfc_hal_hci_evt_hdlr
**
** Description Processing event for NFA HCI
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_evt_hdlr(tNFC_HAL_HCI_EVENT_DATA* p_evt_data) {
HAL_TRACE_DEBUG0("nfc_hal_hci_evt_hdlr ()");
switch (p_evt_data->hdr.event) {
case NFC_HAL_HCI_RSP_NV_READ_EVT:
if ((nfc_hal_cb.hci_cb.p_hci_netwk_info_buf &&
(p_evt_data->nv_read.block == HC_F3_NV_BLOCK ||
p_evt_data->nv_read.block == HC_F4_NV_BLOCK ||
p_evt_data->nv_read.block == HC_F5_NV_BLOCK)) ||
(nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf &&
p_evt_data->nv_read.block == HC_F2_NV_BLOCK)) {
nfc_hal_hci_handle_nv_read(p_evt_data->nv_read.block,
p_evt_data->nv_read.status,
p_evt_data->nv_read.size);
} else {
/* Invalid block or no buffer, Ignore */
HAL_TRACE_ERROR1(
"nfc_hal_hci_evt_hdlr: No buffer for handling read NV block: "
"0x%02x",
p_evt_data->nv_read.block);
}
break;
case NFC_HAL_HCI_RSP_NV_WRITE_EVT:
/* NV Ram write completed - nothing to do... */
break;
default:
break;
}
}
/*******************************************************************************
**
** Function nfc_hal_hci_enable
**
** Description Program nv data on to controller
**
** Returns void
**
*******************************************************************************/
void nfc_hal_hci_enable(void) {
uint8_t* p_hci_netwk_cmd;
HAL_TRACE_DEBUG0("nfc_hal_hci_enable ()");
if (nfc_hal_cb.nvm_cb.nvm_type == NCI_SPD_NVM_TYPE_NONE) {
HAL_TRACE_DEBUG1(
"nfc_hal_hci_enable (): No HCI NETWK CMD to send for NVM Type: 0x%02x",
nfc_hal_cb.nvm_cb.nvm_type);
nfc_hal_hci_init_complete(HAL_NFC_STATUS_OK);
return;
}
if (nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf) {
p_hci_netwk_cmd = (uint8_t*)(nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf -
NCI_MSG_HDR_SIZE);
GKI_freebuf(p_hci_netwk_cmd);
nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf = NULL;
}
if (nfc_hal_cb.hci_cb.p_hci_netwk_info_buf) {
p_hci_netwk_cmd =
(uint8_t*)(nfc_hal_cb.hci_cb.p_hci_netwk_info_buf - NCI_MSG_HDR_SIZE);
GKI_freebuf(p_hci_netwk_cmd);
nfc_hal_cb.hci_cb.p_hci_netwk_info_buf = NULL;
}
if ((p_nfc_hal_cfg->nfc_hal_hci_uicc_support & HAL_NFC_HCI_UICC0_HOST) ||
((p_nfc_hal_cfg->nfc_hal_hci_uicc_support & HAL_NFC_HCI_UICC1_HOST) &&
((!nfc_hal_cb.hci_cb.hci_fw_workaround) ||
(nfc_hal_cb.nvm_cb.nvm_type == NCI_SPD_NVM_TYPE_EEPROM))) ||
(p_nfc_hal_cfg->nfc_hal_hci_uicc_support & HAL_NFC_HCI_UICC2_HOST)) {
p_hci_netwk_cmd =
(uint8_t*)GKI_getbuf(NCI_MSG_HDR_SIZE + NFC_HAL_HCI_NETWK_INFO_SIZE);
if (p_hci_netwk_cmd == NULL) {
HAL_TRACE_ERROR0(
"nfc_hal_hci_enable: unable to allocate buffer for reading hci "
"network info from nvram");
nfc_hal_hci_init_complete(HAL_NFC_STATUS_FAILED);
} else {
nfc_hal_cb.hci_cb.p_hci_netwk_info_buf =
(uint8_t*)(p_hci_netwk_cmd + NCI_MSG_HDR_SIZE);
nfc_hal_cb.hci_cb.hci_netwk_config_block = 0;
if (p_nfc_hal_cfg->nfc_hal_hci_uicc_support & HAL_NFC_HCI_UICC0_HOST) {
memset(nfc_hal_cb.hci_cb.p_hci_netwk_info_buf, 0,
NFC_HAL_HCI_NETWK_INFO_SIZE);
nfc_hal_nv_co_read((uint8_t*)nfc_hal_cb.hci_cb.p_hci_netwk_info_buf,
NFC_HAL_HCI_NETWK_INFO_SIZE, HC_F3_NV_BLOCK);
nfc_hal_main_start_quick_timer(&nfc_hal_cb.hci_cb.hci_timer,
NFC_HAL_HCI_VSC_TIMEOUT_EVT,
NFC_HAL_HCI_NV_READ_TIMEOUT);
} else {
HAL_TRACE_DEBUG1(
"nfc_hal_hci_enable (): Skip send F3 HCI NETWK CMD for UICC Mask: "
"0x%02x",
p_nfc_hal_cfg->nfc_hal_hci_uicc_support);
nfc_hal_hci_set_next_hci_netwk_config(HC_F3_NV_BLOCK);
}
}
} else {
HAL_TRACE_DEBUG2(
"nfc_hal_hci_enable (): No HCI NETWK CMD to send for UICC Mask: 0x%02x "
"& NVM Type: 0x%02x",
p_nfc_hal_cfg->nfc_hal_hci_uicc_support, nfc_hal_cb.nvm_cb.nvm_type);
nfc_hal_hci_set_next_hci_netwk_config(HC_F2_NV_BLOCK);
}
}
/*******************************************************************************
**
** Function nfc_hal_hci_handle_build_info
**
** Description handle build info evt
**
** Returns void
**
*******************************************************************************/
void nfc_hal_hci_handle_build_info(uint8_t chipverlen, uint8_t* p_chipverstr) {
HAL_TRACE_DEBUG0("nfc_hal_hci_handle_build_info ()");
if ((chipverlen == NFC_HAL_DM_BCM20791B3_STR_LEN) &&
(memcmp(NFC_HAL_DM_BCM20791B3_STR, p_chipverstr,
NFC_HAL_DM_BCM20791B3_STR_LEN) == 0)) {
/* BCM2079B3 FW - eSE restarted for patch download */
nfc_hal_cb.hci_cb.hci_fw_workaround = true;
nfc_hal_cb.hci_cb.hci_fw_validate_netwk_cmd = true;
} else if (((chipverlen == NFC_HAL_DM_BCM20791B4_STR_LEN) &&
(memcmp(NFC_HAL_DM_BCM20791B4_STR, p_chipverstr,
NFC_HAL_DM_BCM20791B4_STR_LEN) == 0)) ||
((chipverlen == NFC_HAL_DM_BCM43341B0_STR_LEN) &&
(memcmp(NFC_HAL_DM_BCM43341B0_STR, p_chipverstr,
NFC_HAL_DM_BCM43341B0_STR_LEN) == 0))) {
/* BCM43341B0/BCM2079B4 FW - eSE restarted for patch download */
nfc_hal_cb.hci_cb.hci_fw_workaround = true;
nfc_hal_cb.hci_cb.hci_fw_validate_netwk_cmd = false;
} else {
/* BCM2079B5 FW - eSE not be restarted for patch download from UICC */
nfc_hal_cb.hci_cb.hci_fw_workaround = false;
nfc_hal_cb.hci_cb.hci_fw_validate_netwk_cmd = false;
}
}
/*******************************************************************************
**
** Function nfc_hal_hci_handle_hci_netwk_info
**
** Description Handler function for HCI Network Notification
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_handle_hci_netwk_info(uint8_t* p_data) {
uint8_t* p = p_data;
uint16_t data_len;
uint8_t target_handle = 0;
uint8_t hci_netwk_cmd[1 + NFC_HAL_HCI_SESSION_ID_LEN];
uint8_t block = 0;
HAL_TRACE_DEBUG0("nfc_hal_hci_handle_hci_netwk_info ()");
/* skip NCI header byte0 (MT,GID), byte1 (OID) */
p += 2;
STREAM_TO_UINT8(data_len, p);
target_handle = *(uint8_t*)p;
if (target_handle == NFC_HAL_HCI_DH_TARGET_HANDLE) {
/* Correct the session id assigned by DH */
*(p + 1) = nfc_hal_cb.hci_cb.dh_session_id[0];
nfc_hal_nv_co_write(p, data_len, HC_F2_NV_BLOCK);
return;
}
if (target_handle == NFC_HAL_HCI_UICC0_TARGET_HANDLE) {
block = HC_F3_NV_BLOCK;
} else if (target_handle == NFC_HAL_HCI_UICC1_TARGET_HANDLE) {
block = HC_F4_NV_BLOCK;
} else if (target_handle == NFC_HAL_HCI_UICC2_TARGET_HANDLE) {
block = HC_F5_NV_BLOCK;
} else {
HAL_TRACE_DEBUG1(
"nfc_hal_hci_handle_hci_netwk_info(): Invalid Target handle: 0x%02x",
target_handle);
return;
}
if ((!nfc_hal_cb.hci_cb.hci_fw_validate_netwk_cmd) ||
(p[NFC_HAL_HCI_NETWK_CMD_TYPE_A_CE_PIPE_INFO_OFFSET] &
NFC_HAL_HCI_PIPE_VALID_MASK) ||
(p[NFC_HAL_HCI_NETWK_CMD_TYPE_B_CE_PIPE_INFO_OFFSET] &
NFC_HAL_HCI_PIPE_VALID_MASK) ||
(p[NFC_HAL_HCI_NETWK_CMD_TYPE_BP_CE_PIPE_INFO_OFFSET] &
NFC_HAL_HCI_PIPE_VALID_MASK) ||
(p[NFC_HAL_HCI_NETWK_CMD_TYPE_F_CE_PIPE_INFO_OFFSET] &
NFC_HAL_HCI_PIPE_VALID_MASK)) {
/* HCI Network notification received for UICC0/UICC1/UICC2, Update nv data
*/
nfc_hal_nv_co_write(p, data_len, block);
} else {
HAL_TRACE_DEBUG1(
"nfc_hal_hci_handle_hci_netwk_info(): Type A Card Emulation invalid, "
"Reset nv file: 0x%02x",
p[NFC_HAL_HCI_NETWK_CMD_TYPE_A_CE_PIPE_INFO_OFFSET]);
hci_netwk_cmd[0] = target_handle;
memset(&hci_netwk_cmd[1], 0xFF, NFC_HAL_HCI_SESSION_ID_LEN);
nfc_hal_nv_co_write(hci_netwk_cmd, 1, block);
}
}
/*******************************************************************************
**
** Function nfc_hal_hci_fake_adm_notify_all_pipe_cleared_to_dh
**
** Description Fake ADM_NOTIFY_ALL_PIPE_CLEARED cmd to nfc task
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_fake_adm_notify_all_pipe_cleared_to_dh(void) {
NFC_HDR* p_msg;
uint8_t *p, *ps;
HAL_TRACE_DEBUG1(
"nfc_hal_hci_fake_adm_notify_all_pipe_cleared_to_dh (): Fake "
"ADM_NOTIFY_ALL_PIPE_CLEARED (0x%02x) from HAL",
NFC_HAL_HCI_HOST_ID_UICC1);
/* Start of new message. Allocate a buffer for message */
p_msg = (NFC_HDR*)GKI_getpoolbuf(NFC_HAL_NCI_POOL_ID);
if (p_msg != NULL) {
/* Initialize NFC_HDR */
p_msg->len = NCI_DATA_HDR_SIZE + 0x03;
p_msg->event = 0;
p_msg->offset = 0;
p_msg->layer_specific = 0;
p = (uint8_t*)(p_msg + 1) + p_msg->offset;
ps = p;
NCI_DATA_BLD_HDR(p, nfc_hal_cb.hci_cb.hcp_conn_id, 0x03);
/* HCP header with ADMIN pipe id and chaining bit set */
*p++ = ((1 << 0x07) | (NFC_HAL_HCI_ADMIN_PIPE & 0x7F));
/* HCP Message header with Command type instruction and
* ADM_NOTIFY_ALL_PIPE_CLEARED command */
*p++ = ((NFC_HAL_HCI_COMMAND_TYPE << 6) |
(NFC_HAL_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED & 0x3F));
/* HCP Data with UICC1 host id */
*p = NFC_HAL_HCI_HOST_ID_UICC1;
#ifdef DISP_NCI
DISP_NCI(ps, (uint16_t)p_msg->len, true);
#endif
nfc_hal_send_nci_msg_to_nfc_task(p_msg);
} else {
HAL_TRACE_ERROR0(
"Unable to allocate buffer for faking ADM_NOTIFY_ALL_PIPE_CLEARED cmd "
"from HAL to stack");
}
}
/*******************************************************************************
**
** Function nfc_hal_hci_handle_hcp_pkt_to_hc
**
** Description Handle HCP Packet from NFC task to Host Controller
**
** Returns FALSE to send the packet to host controller
** TRUE to drop the packet and fake credit ntf for hcp
*connection
**
*******************************************************************************/
bool nfc_hal_hci_handle_hcp_pkt_to_hc(uint8_t* p_data) {
uint8_t chaining_bit;
uint8_t pipe;
uint8_t type;
uint8_t inst;
uint8_t index;
HAL_TRACE_DEBUG0("nfc_hal_hci_handle_hcp_pkt_to_hc ()");
chaining_bit = ((*p_data) >> 0x07) & 0x01;
pipe = (*p_data++) & 0x7F;
if ((chaining_bit) && (pipe == NFC_HAL_HCI_ADMIN_PIPE)) {
type = ((*p_data) >> 0x06) & 0x03;
if (type == NFC_HAL_HCI_COMMAND_TYPE) {
inst = (*p_data++ & 0x3F);
if (inst == NFC_HAL_HCI_ANY_GET_PARAMETER) {
index = *(p_data++);
if (index == NFC_HAL_HCI_SESSION_IDENTITY_INDEX) {
/* Set flag to modify session id[0] on response
* from host controller to set session id cmd
*/
nfc_hal_cb.hci_cb.update_session_id = true;
}
} else if (inst == NFC_HAL_HCI_ANY_SET_PARAMETER) {
index = *(p_data++);
if (index == NFC_HAL_HCI_WHITELIST_INDEX) {
if ((nfc_hal_cb.hci_cb.hci_fw_workaround) &&
(nfc_hal_cb.nvm_cb.nvm_type == NCI_SPD_NVM_TYPE_UICC)) {
/* Set flag to fake ADM_NOTIFY_ALL_PIPE_CLEARED cmd to nfc task
* after
* response from host controller to set whitelist cmd
*/
nfc_hal_cb.hci_cb.clear_all_pipes_to_uicc1 = true;
}
} else if (index == NFC_HAL_HCI_SESSION_IDENTITY_INDEX) {
nfc_hal_cb.hci_cb.dh_session_id[0] = *p_data;
if (p_nfc_hal_cfg->nfc_hal_first_boot)
*p_data = NFC_HAL_HCI_FIRST_BOOT_SESSION_ID_0_VAL;
else
*p_data = NFC_HAL_HCI_NEXT_BOOT_SESSION_ID_0_VAL;
}
}
} else if (type == NFC_HAL_HCI_RESPONSE_TYPE) {
if ((nfc_hal_cb.hci_cb.hci_fw_workaround) &&
(nfc_hal_cb.nvm_cb.nvm_type == NCI_SPD_NVM_TYPE_UICC) &&
(nfc_hal_cb.hci_cb.clear_all_pipes_to_uicc1)) {
/* Got response to the fake ADM_NOTIFY_ALL_PIPE_CLEARED cmd sent by HAL
* to nfc task */
nfc_hal_cb.hci_cb.clear_all_pipes_to_uicc1 = false;
/* return TRUE to drop this hcp without forwarding to host controller */
return true;
}
}
}
return false;
}
/*******************************************************************************
**
** Function nfc_hal_hci_handle_hcp_pkt_from_hc
**
** Description Handle HCP Packet from Host controller to Terminal Host
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_handle_hcp_pkt_from_hc(uint8_t* p_data) {
uint8_t chaining_bit;
uint8_t pipe;
uint8_t type;
uint8_t inst;
uint8_t hci_netwk_cmd[1 + NFC_HAL_HCI_SESSION_ID_LEN];
uint8_t source_host;
uint8_t block = 0;
HAL_TRACE_DEBUG0("nfc_hal_hci_handle_hcp_pkt_from_hc ()");
chaining_bit = ((*p_data) >> 0x07) & 0x01;
pipe = (*p_data++) & 0x7F;
if ((chaining_bit) && (pipe == NFC_HAL_HCI_ADMIN_PIPE)) {
type = ((*p_data) >> 0x06) & 0x03;
if (type == NFC_HAL_HCI_COMMAND_TYPE) {
if (!nfc_hal_cb.hci_cb.hci_fw_workaround) return;
inst = (*p_data++ & 0x3F);
if (inst == NFC_HAL_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED) {
STREAM_TO_UINT8(source_host, p_data);
HAL_TRACE_DEBUG1(
"nfc_hal_hci_handle_hcp_pkt_from_hc (): Received "
"ADM_NOTIFY_ALL_PIPE_CLEARED command for UICC: 0x%02x",
source_host);
if (source_host == NFC_HAL_HCI_HOST_ID_UICC0) {
block = HC_F3_NV_BLOCK;
hci_netwk_cmd[0] = NFC_HAL_HCI_UICC0_TARGET_HANDLE;
} else if (source_host == NFC_HAL_HCI_HOST_ID_UICC1) {
block = HC_F4_NV_BLOCK;
hci_netwk_cmd[0] = NFC_HAL_HCI_UICC1_TARGET_HANDLE;
} else if (source_host == NFC_HAL_HCI_HOST_ID_UICC2) {
block = HC_F5_NV_BLOCK;
hci_netwk_cmd[0] = NFC_HAL_HCI_UICC2_TARGET_HANDLE;
}
if (source_host >= NFC_HAL_HCI_HOST_ID_UICC0) {
/* Reset Session ID */
memset(&hci_netwk_cmd[1], 0xFF, NFC_HAL_HCI_SESSION_ID_LEN);
nfc_hal_nv_co_write(hci_netwk_cmd, 1, block);
HAL_TRACE_DEBUG1(
"nfc_hal_hci_handle_hcp_pkt_from_hc (): Sent command to reset nv "
"file for block: 0x%02x",
block);
}
}
} else if (type == NFC_HAL_HCI_RESPONSE_TYPE) {
if (nfc_hal_cb.hci_cb.update_session_id) {
nfc_hal_cb.hci_cb.update_session_id = false;
inst = (*p_data++ & 0x3F);
if (inst == NFC_HAL_HCI_ANY_OK) {
/* Correct the session id assigned by DH */
*p_data = nfc_hal_cb.hci_cb.dh_session_id[0];
}
} else if (nfc_hal_cb.hci_cb.clear_all_pipes_to_uicc1) {
/* NVM Type is UICC and got response from host controller
* to Set whitelist command. Now fake ADM_NOTIFY_ALL_PIPE_CLEARED cmd to
* NFC Task and then forward the whitelist cmd response
*/
nfc_hal_hci_fake_adm_notify_all_pipe_cleared_to_dh();
}
}
}
}
/*******************************************************************************
**
** Function nfc_hal_hci_handle_nv_read
**
** Description handler function for nv read complete event
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_handle_nv_read(uint8_t block, tHAL_NFC_STATUS status,
uint16_t size) {
uint8_t* p;
uint8_t* p_hci_netwk_info = NULL;
HAL_TRACE_DEBUG3(
"nfc_hal_hci_handle_nv_read (): Block: [0x%02x], Status: [0x%02x], Size: "
"[0x%04x]",
block, status, size);
/* Stop timer as NVDATA Read Completed */
nfc_hal_main_stop_quick_timer(&nfc_hal_cb.hci_cb.hci_timer);
switch (block) {
case HC_F3_NV_BLOCK:
case HC_F4_NV_BLOCK:
case HC_F5_NV_BLOCK:
if ((status != HAL_NFC_STATUS_OK) ||
(size > NFC_HAL_HCI_NETWK_INFO_SIZE) ||
(size < NFC_HAL_HCI_MIN_NETWK_INFO_SIZE) ||
((nfc_hal_cb.hci_cb.hci_fw_workaround) && (block == HC_F4_NV_BLOCK) &&
(nfc_hal_cb.nvm_cb.nvm_type == NCI_SPD_NVM_TYPE_UICC))) {
HAL_TRACE_DEBUG1(
"nfc_hal_hci_handle_nv_read: Invalid data from nv memory, Set "
"DEFAULT Configuration for block:0x%02x",
block);
memset(nfc_hal_cb.hci_cb.p_hci_netwk_info_buf, 0,
NFC_HAL_HCI_NETWK_INFO_SIZE);
if (block == HC_F3_NV_BLOCK)
nfc_hal_cb.hci_cb.p_hci_netwk_info_buf[0] =
NFC_HAL_HCI_UICC0_TARGET_HANDLE;
else if (block == HC_F4_NV_BLOCK)
nfc_hal_cb.hci_cb.p_hci_netwk_info_buf[0] =
NFC_HAL_HCI_UICC1_TARGET_HANDLE;
else
nfc_hal_cb.hci_cb.p_hci_netwk_info_buf[0] =
NFC_HAL_HCI_UICC2_TARGET_HANDLE;
memset(&nfc_hal_cb.hci_cb.p_hci_netwk_info_buf[1], 0xFF,
NFC_HAL_HCI_SESSION_ID_LEN);
size = NFC_HAL_HCI_NETWK_INFO_SIZE;
}
p_hci_netwk_info =
(uint8_t*)nfc_hal_cb.hci_cb.p_hci_netwk_info_buf - NCI_MSG_HDR_SIZE;
break;
case HC_F2_NV_BLOCK:
nfc_hal_cb.hci_cb.dh_session_id[0] =
nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf[1];
if (p_nfc_hal_cfg->nfc_hal_first_boot)
nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf[1] =
NFC_HAL_HCI_FIRST_BOOT_SESSION_ID_0_VAL;
else
nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf[1] =
NFC_HAL_HCI_NEXT_BOOT_SESSION_ID_0_VAL;
if ((status != HAL_NFC_STATUS_OK) ||
(size > NFC_HAL_HCI_DH_NETWK_INFO_SIZE) ||
(size < NFC_HAL_HCI_MIN_DH_NETWK_INFO_SIZE)) {
HAL_TRACE_DEBUG1(
"nfc_hal_hci_handle_nv_read: Invalid data from nv memory, Set "
"DEFAULT Configuration for block:0x%02x",
block);
nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf[0] =
NFC_HAL_HCI_DH_TARGET_HANDLE;
nfc_hal_cb.hci_cb.dh_session_id[0] = 0xFF;
memset(&nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf[2], 0xFF,
(NFC_HAL_HCI_SESSION_ID_LEN - 1));
memset((nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf +
NFC_HAL_HCI_SESSION_ID_LEN + 1),
0, (NFC_HAL_HCI_DH_NETWK_INFO_SIZE - NFC_HAL_HCI_SESSION_ID_LEN -
1));
size = NFC_HAL_HCI_DH_NETWK_INFO_SIZE;
p_hci_netwk_info = (uint8_t*)nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf -
NCI_MSG_HDR_SIZE;
} else {
if ((nfc_hal_cb.hci_cb.hci_fw_workaround) &&
(nfc_hal_cb.nvm_cb.nvm_type == NCI_SPD_NVM_TYPE_UICC)) {
/* if NVM Type is UICC, then UICC1 will find session id mismatch when
* activated for patch download,
* and will remove pipes connected to DH even before DH is enabled, So
* DH will update NFCC
* control block by removing all dynamic pipes connected to UICC1 */
nfc_hal_hci_remove_dyn_pipe_to_uicc1();
size = NFC_HAL_HCI_DH_NETWK_INFO_SIZE;
}
p_hci_netwk_info =
(uint8_t*)(nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf -
NCI_MSG_HDR_SIZE);
}
break;
default:
return;
}
p = p_hci_netwk_info;
/* Send HCI Network ntf command using nv data */
NCI_MSG_BLD_HDR0(p, NCI_MT_CMD, NCI_GID_PROP);
NCI_MSG_BLD_HDR1(p, NCI_MSG_HCI_NETWK);
UINT8_TO_STREAM(p, (uint8_t)size);
nfc_hal_dm_send_nci_cmd(p_hci_netwk_info, (uint16_t)(NCI_MSG_HDR_SIZE + size),
nfc_hal_hci_vsc_cback);
nfc_hal_cb.hci_cb.hci_netwk_config_block = block;
}
/*******************************************************************************
**
** Function nfc_hal_hci_remove_dyn_pipe_to_uicc1
**
** Description Prepare hci network command read from nv file removing
** all pipes connected to UICC1
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_remove_dyn_pipe_to_uicc1(void) {
uint8_t *p, *np;
uint8_t num_dyn_pipes = 0, new_num_dyn_pipes = 0;
uint8_t xx;
uint8_t source_host, dest_host, pipe_id;
HAL_TRACE_DEBUG0("nfc_hal_hci_remove_dyn_pipe_to_uicc1 ()");
p = (uint8_t*)(nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf +
NFC_HAL_HCI_MIN_DH_NETWK_INFO_SIZE);
np = p;
num_dyn_pipes = *(p - 1);
for (xx = 0; xx < num_dyn_pipes; xx++, p += NFC_HAL_HCI_PIPE_INFO_SIZE) {
source_host = *(uint8_t*)(p);
dest_host = *(uint8_t*)(p + 1);
pipe_id = *(uint8_t*)(p + 4);
if ((source_host != NFC_HAL_HCI_HOST_ID_UICC1) &&
(dest_host != NFC_HAL_HCI_HOST_ID_UICC1)) {
memcpy(np, p, NFC_HAL_HCI_PIPE_INFO_SIZE);
np += NFC_HAL_HCI_PIPE_INFO_SIZE;
new_num_dyn_pipes++;
}
}
memset((uint8_t*)(np), 0,
NFC_HAL_HCI_PIPE_INFO_SIZE * (20 - new_num_dyn_pipes));
/* Update number of pipes after removing pipes connected to UICC1 */
p = (uint8_t*)(nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf +
NFC_HAL_HCI_MIN_DH_NETWK_INFO_SIZE);
*(p - 1) = new_num_dyn_pipes;
}
/*******************************************************************************
**
** Function nfc_hal_hci_init_complete
**
** Description Notify VSC initialization is complete
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_init_complete(tHAL_NFC_STATUS status) {
uint8_t* p_hci_netwk_cmd;
HAL_TRACE_DEBUG1("nfc_hal_hci_init_complete (): Status: [0x%02x]", status);
if (nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf) {
p_hci_netwk_cmd = (uint8_t*)(nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf -
NCI_MSG_HDR_SIZE);
GKI_freebuf(p_hci_netwk_cmd);
nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf = NULL;
}
if (nfc_hal_cb.hci_cb.p_hci_netwk_info_buf) {
p_hci_netwk_cmd =
(uint8_t*)(nfc_hal_cb.hci_cb.p_hci_netwk_info_buf - NCI_MSG_HDR_SIZE);
GKI_freebuf(p_hci_netwk_cmd);
nfc_hal_cb.hci_cb.p_hci_netwk_info_buf = NULL;
}
NFC_HAL_SET_INIT_STATE(NFC_HAL_INIT_STATE_IDLE);
nfc_hal_cb.p_stack_cback(HAL_NFC_POST_INIT_CPLT_EVT, status);
}
/*******************************************************************************
**
** Function nfc_hal_hci_set_next_hci_netwk_config
**
** Description set next hci network configuration
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_set_next_hci_netwk_config(uint8_t block) {
uint8_t* p_hci_netwk_cmd;
HAL_TRACE_DEBUG1("nfc_hal_hci_set_next_hci_netwk_config (): Block: [0x%02x]",
block);
switch (block) {
case HC_F3_NV_BLOCK:
if ((p_nfc_hal_cfg->nfc_hal_hci_uicc_support & HAL_NFC_HCI_UICC1_HOST) &&
(nfc_hal_cb.hci_cb.p_hci_netwk_info_buf) &&
((!nfc_hal_cb.hci_cb.hci_fw_workaround) ||
(nfc_hal_cb.nvm_cb.nvm_type == NCI_SPD_NVM_TYPE_EEPROM))) {
/* Send command to read nvram data for 0xF4 */
memset(nfc_hal_cb.hci_cb.p_hci_netwk_info_buf, 0,
NFC_HAL_HCI_NETWK_INFO_SIZE);
nfc_hal_nv_co_read((uint8_t*)nfc_hal_cb.hci_cb.p_hci_netwk_info_buf,
NFC_HAL_HCI_NETWK_INFO_SIZE, HC_F4_NV_BLOCK);
nfc_hal_main_start_quick_timer(&nfc_hal_cb.hci_cb.hci_timer,
NFC_HAL_HCI_VSC_TIMEOUT_EVT,
NFC_HAL_HCI_NV_READ_TIMEOUT);
break;
}
HAL_TRACE_DEBUG2(
"nfc_hal_hci_set_next_hci_netwk_config (): Skip send F4 HCI NETWK "
"CMD for UICC Mask: 0x%02x & NVM Type: 0x%02x",
p_nfc_hal_cfg->nfc_hal_hci_uicc_support, nfc_hal_cb.nvm_cb.nvm_type);
case HC_F4_NV_BLOCK:
if ((p_nfc_hal_cfg->nfc_hal_hci_uicc_support & HAL_NFC_HCI_UICC2_HOST) &&
(nfc_hal_cb.hci_cb.p_hci_netwk_info_buf)) {
/* Send command to read nvram data for 0xF5 */
memset(nfc_hal_cb.hci_cb.p_hci_netwk_info_buf, 0,
NFC_HAL_HCI_NETWK_INFO_SIZE);
nfc_hal_nv_co_read((uint8_t*)nfc_hal_cb.hci_cb.p_hci_netwk_info_buf,
NFC_HAL_HCI_NETWK_INFO_SIZE, HC_F5_NV_BLOCK);
nfc_hal_main_start_quick_timer(&nfc_hal_cb.hci_cb.hci_timer,
NFC_HAL_HCI_VSC_TIMEOUT_EVT,
NFC_HAL_HCI_NV_READ_TIMEOUT);
break;
}
HAL_TRACE_DEBUG2(
"nfc_hal_hci_set_next_hci_netwk_config (): Skip send F5 HCI NETWK "
"CMD for UICC Mask: 0x%02x & NVM Type: 0x%02x",
p_nfc_hal_cfg->nfc_hal_hci_uicc_support, nfc_hal_cb.nvm_cb.nvm_type);
case HC_F5_NV_BLOCK:
p_hci_netwk_cmd = (uint8_t*)GKI_getbuf(NCI_MSG_HDR_SIZE +
NFC_HAL_HCI_DH_NETWK_INFO_SIZE);
if (p_hci_netwk_cmd == NULL) {
HAL_TRACE_ERROR0(
"nfc_hal_hci_set_next_hci_netwk_config: unable to allocate buffer "
"for reading hci network info from nvram");
nfc_hal_hci_init_complete(HAL_NFC_STATUS_FAILED);
} else {
nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf =
(uint8_t*)(p_hci_netwk_cmd + NCI_MSG_HDR_SIZE);
/* Send command to read nvram data for 0xF2 */
memset(nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf, 0,
NFC_HAL_HCI_DH_NETWK_INFO_SIZE);
nfc_hal_nv_co_read((uint8_t*)nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf,
NFC_HAL_HCI_DH_NETWK_INFO_SIZE, HC_F2_NV_BLOCK);
nfc_hal_main_start_quick_timer(&nfc_hal_cb.hci_cb.hci_timer,
NFC_HAL_HCI_VSC_TIMEOUT_EVT,
NFC_HAL_HCI_NV_READ_TIMEOUT);
}
break;
case HC_F2_NV_BLOCK:
nfc_hal_hci_init_complete(HAL_NFC_STATUS_OK);
break;
default:
HAL_TRACE_ERROR1(
"nfc_hal_hci_set_next_hci_netwk_config: unable to allocate buffer to "
"send VSC 0x%02x",
block);
/* Brcm initialization failed */
nfc_hal_hci_init_complete(HAL_NFC_STATUS_FAILED);
break;
}
}
/*******************************************************************************
**
** Function nfc_hal_hci_vsc_cback
**
** Description process VS callback event from stack
**
** Returns none
**
*******************************************************************************/
static void nfc_hal_hci_vsc_cback(tNFC_HAL_NCI_EVT event, uint16_t data_len,
uint8_t* p_data) {
uint8_t* p_ret = NULL;
uint8_t status;
p_ret = p_data + NCI_MSG_HDR_SIZE;
status = *p_ret;
HAL_TRACE_DEBUG3(
"nfc_hal_hci_vsc_cback (): Event: [0x%02x], Data length: [0x%04x], "
"Status: [0x%02x]",
event, data_len, status);
if (event != NFC_VS_HCI_NETWK_RSP) return;
if (status != HAL_NFC_STATUS_OK) {
nfc_hal_hci_init_complete(HAL_NFC_STATUS_FAILED);
return;
}
switch (nfc_hal_cb.hci_cb.hci_netwk_config_block) {
case HC_F3_NV_BLOCK:
case HC_F4_NV_BLOCK:
case HC_F5_NV_BLOCK:
case HC_F2_NV_BLOCK:
nfc_hal_hci_set_next_hci_netwk_config(
nfc_hal_cb.hci_cb.hci_netwk_config_block);
break;
default:
/* Ignore the event */
break;
}
}
/*******************************************************************************
**
** Function nfc_hal_nci_cmd_timeout_cback
**
** Description callback function for timeout
**
** Returns void
**
*******************************************************************************/
void nfc_hal_hci_timeout_cback(void* p_tle) {
TIMER_LIST_ENT* p_tlent = (TIMER_LIST_ENT*)p_tle;
HAL_TRACE_DEBUG0("nfc_hal_hci_timeout_cback ()");
if (p_tlent->event == NFC_HAL_HCI_VSC_TIMEOUT_EVT) {
HAL_TRACE_ERROR0(
"nfc_hal_hci_timeout_cback: Timeout - NFC HAL HCI BRCM Initialization "
"Failed!");
nfc_hal_hci_init_complete(HAL_NFC_STATUS_FAILED);
}
}
#endif