blob: 1504c94262cb967408cba54c84181512f27c658c [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2012 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_nv_ci.h"
#include "nfc_hal_nv_co.h"
#include <string.h>
#include "nfc_hal_nv_co.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
static void nfc_hal_hci_set_next_hci_netwk_config (UINT8 block);
static void nfc_hal_hci_handle_nv_read (UINT8 block, tHAL_NFC_STATUS status, UINT16 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 data_len, UINT8 *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)
{
switch (p_evt_data->hdr.event)
{
case NFC_HAL_HCI_RSP_NV_READ_EVT:
nfc_hal_hci_handle_nv_read (p_evt_data->nv_read.block, p_evt_data->nv_read.status, p_evt_data->nv_read.size);
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 *p_hci_netwk_cmd;
if (nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf)
{
p_hci_netwk_cmd = (UINT8 *) (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 *) (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_hci_netwk_cmd = (UINT8 *) GKI_getbuf (NCI_MSG_HDR_SIZE + NFC_HAL_HCI_NETWK_INFO_SIZE)) == NULL)
{
NCI_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 *) (p_hci_netwk_cmd + NCI_MSG_HDR_SIZE);
nfc_hal_cb.hci_cb.hci_netwk_config_block = 0;
memset (nfc_hal_cb.hci_cb.p_hci_netwk_info_buf, 0, NFC_HAL_HCI_NETWK_INFO_SIZE);
nfc_hal_nv_co_read ((UINT8 *) 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);
}
}
/*******************************************************************************
**
** 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 *p_data)
{
UINT8 *p = p_data;
UINT16 data_len;
UINT8 target_handle;
UINT8 hci_netwk_cmd[1 + NFC_HAL_HCI_SESSION_ID_LEN];
NCI_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 *) p;
if (target_handle == NFC_HAL_HCI_DH_TARGET_HANDLE)
nfc_hal_nv_co_write (p, data_len,HC_DH_NV_BLOCK);
else if (target_handle == NFC_HAL_HCI_UICC0_TARGET_HANDLE)
{
if (p[12] & 0x80)
{
/* HCI Network notification received for UICC 0, Update nv data */
nfc_hal_nv_co_write (p, data_len,HC_F3_NV_BLOCK);
}
else
{
NCI_TRACE_DEBUG1 ("nfc_hal_hci_handle_hci_netwk_info(): Type A Card Emulation invalid, Reset nv file: 0x%02x", p[15]);
hci_netwk_cmd[0] = NFC_HAL_HCI_UICC0_TARGET_HANDLE;
memset (&hci_netwk_cmd[1], 0xFF, NFC_HAL_HCI_SESSION_ID_LEN);
nfc_hal_nv_co_write (hci_netwk_cmd, 1, HC_F3_NV_BLOCK);
}
}
else if (target_handle == NFC_HAL_HCI_UICC1_TARGET_HANDLE)
{
if (p[12] & 0x80)
{
/* HCI Network notification received for UICC 1, Update nv data */
nfc_hal_nv_co_write (p, data_len,HC_F4_NV_BLOCK);
}
else
{
NCI_TRACE_DEBUG1 ("nfc_hal_hci_handle_hci_netwk_info(): Type A Card Emulation invalid, Reset nv file: 0x%02x", p[15]);
hci_netwk_cmd[0] = NFC_HAL_HCI_UICC1_TARGET_HANDLE;
/* Reset Session ID */
memset (&hci_netwk_cmd[1], 0xFF, NFC_HAL_HCI_SESSION_ID_LEN);
nfc_hal_nv_co_write (hci_netwk_cmd, 1, HC_F4_NV_BLOCK);
}
}
}
/*******************************************************************************
**
** Function nfc_hal_hci_handle_hcp_pkt
**
** Description Handle HCP Packet
**
** Returns None
**
*******************************************************************************/
void nfc_hal_hci_handle_hcp_pkt (UINT8 *p_data)
{
UINT8 chaining_bit;
UINT8 pipe;
UINT8 type;
UINT8 inst;
UINT8 hci_netwk_cmd[1 + NFC_HAL_HCI_SESSION_ID_LEN];
UINT8 source_host;
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_ADM_NOTIFY_ALL_PIPE_CLEARED)
{
STREAM_TO_UINT8 (source_host, p_data);
NCI_TRACE_DEBUG1 ("nfc_hal_hci_handle_hcp_pkt(): Received Clear All pipe command for UICC: 0x%02x", source_host);
if (source_host == NFC_HAL_HCI_HOST_ID_UICC0)
{
hci_netwk_cmd[0] = NFC_HAL_HCI_UICC0_TARGET_HANDLE;
/* Reset Session ID */
memset (&hci_netwk_cmd[1], 0xFF, NFC_HAL_HCI_SESSION_ID_LEN);
nfc_hal_nv_co_write (hci_netwk_cmd, 1, HC_F3_NV_BLOCK);
NCI_TRACE_DEBUG1 ("nfc_hal_hci_handle_hcp_pkt(): Sent command to reset nv file for block: 0x%02x", HC_F3_NV_BLOCK);
}
else if (source_host == NFC_HAL_HCI_HOST_ID_UICC1)
{
hci_netwk_cmd[0] = NFC_HAL_HCI_UICC1_TARGET_HANDLE;
/* Reset Session ID */
memset (&hci_netwk_cmd[1], 0xFF, NFC_HAL_HCI_SESSION_ID_LEN);
nfc_hal_nv_co_write (hci_netwk_cmd, 1, HC_F4_NV_BLOCK);
NCI_TRACE_DEBUG1 ("nfc_hal_hci_handle_hcp_pkt(): Sent command to reset nv file for block: 0x%02x", HC_F4_NV_BLOCK);
}
}
}
}
}
/*******************************************************************************
**
** 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 block, tHAL_NFC_STATUS status, UINT16 size)
{
NFC_HDR *p_data = NULL;
UINT8 *p;
UINT8 *p_hci_netwk_info = NULL;
/* 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:
if ( (status != HAL_NFC_STATUS_OK)
||(size > NFC_HAL_HCI_NETWK_INFO_SIZE) )
{
NCI_TRACE_DEBUG0 ("nfc_hal_hci_handle_nv_read: Invalid data from nv memory, Set DEFAULT Configuration!");
memset (nfc_hal_cb.hci_cb.p_hci_netwk_info_buf, 0, NFC_HAL_HCI_NETWK_INFO_SIZE);
nfc_hal_cb.hci_cb.p_hci_netwk_info_buf[0] = (block == HC_F3_NV_BLOCK) ? NFC_HAL_HCI_UICC0_TARGET_HANDLE : NFC_HAL_HCI_UICC1_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 *) nfc_hal_cb.hci_cb.p_hci_netwk_info_buf - NCI_MSG_HDR_SIZE;
break;
case HC_DH_NV_BLOCK:
if ( (status == HAL_NFC_STATUS_OK)
&&(size <= NFC_HAL_HCI_DH_NETWK_INFO_SIZE) )
{
p_hci_netwk_info = (UINT8 *) (nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf - NCI_MSG_HDR_SIZE);
}
else
{
NCI_TRACE_ERROR0 ("nfc_hal_hci_handle_nv_read: Invalid data from nv memory, Skip DH Configuration!");
}
break;
default:
return;
}
if (p_hci_netwk_info)
{
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) size);
nfc_hal_dm_send_nci_cmd (p_hci_netwk_info, (UINT16) (NCI_MSG_HDR_SIZE + size), nfc_hal_hci_vsc_cback);
nfc_hal_cb.hci_cb.hci_netwk_config_block = block;
}
else
{
/* Set next HCI Network configuration */
nfc_hal_hci_set_next_hci_netwk_config (block);
}
}
/*******************************************************************************
**
** 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 *p_hci_netwk_cmd;
if (nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf)
{
p_hci_netwk_cmd = (UINT8 *) (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 *) (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, HAL_NFC_STATUS_OK);
}
/*******************************************************************************
**
** 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 block)
{
UINT8 *p_hci_netwk_cmd;
switch (block)
{
case HC_F3_NV_BLOCK:
/* 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 *) 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;
case HC_F4_NV_BLOCK:
if ((p_hci_netwk_cmd = (UINT8 *) GKI_getbuf (NCI_MSG_HDR_SIZE + NFC_HAL_HCI_DH_NETWK_INFO_SIZE)) == NULL)
{
NCI_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 *) (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 *) nfc_hal_cb.hci_cb.p_hci_netwk_dh_info_buf, NFC_HAL_HCI_DH_NETWK_INFO_SIZE, HC_DH_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_DH_NV_BLOCK:
nfc_hal_hci_init_complete (HAL_NFC_STATUS_OK);
break;
default:
NCI_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 data_len, UINT8 *p_data)
{
UINT8 *p_ret = NULL;
UINT8 status;
p_ret = p_data + NCI_MSG_HDR_SIZE;
status = *p_ret;
if (event != NFC_VS_HCI_NETWK_RSP)
return;
if (status != HAL_NFC_STATUS_OK)
nfc_hal_hci_init_complete (HAL_NFC_STATUS_FAILED);
switch (nfc_hal_cb.hci_cb.hci_netwk_config_block)
{
case HC_F3_NV_BLOCK:
case HC_F4_NV_BLOCK:
case HC_DH_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;
NCI_TRACE_DEBUG0 ("nfc_hal_hci_timeout_cback ()");
if (p_tlent->event == NFC_HAL_HCI_VSC_TIMEOUT_EVT)
{
NCI_TRACE_ERROR0 ("nfc_hal_hci_timeout_cback: Timeout - NFC HAL HCI BRCM Initialization Failed!");
nfc_hal_hci_init_complete (HAL_NFC_STATUS_FAILED);
}
}