/*******************************************************************************
**
** Function         nfc_hal_main_userial_cback
**
** Description      USERIAL callback for NCI transport
**
** Returns          nothing
**
*******************************************************************************/
static void nfc_hal_main_userial_cback (tUSERIAL_PORT port, tUSERIAL_EVT evt, tUSERIAL_EVT_DATA *p_data)
{
    if (evt == USERIAL_RX_READY_EVT)
    {
        /* Notify transport task of serial port event */
        GKI_send_event (NFC_HAL_TASK, NFC_HAL_TASK_EVT_DATA_RDY);
    }
    else if (evt == USERIAL_TX_DONE_EVT)
    {
        /* Serial driver has finshed sending data from USERIAL_Write */
        /* Currently, no action is needed for this event */
    }
    else if (evt == USERIAL_ERR_EVT)
    {
        HAL_TRACE_ERROR0 ("nfc_hal_main_userial_cback: USERIAL_ERR_EVT. Notifying NFC_TASK of transport error");
        if (nfc_hal_cb.ncit_cb.nci_wait_rsp != NFC_HAL_WAIT_RSP_NONE)
        {
            nfc_hal_main_stop_quick_timer (&nfc_hal_cb.ncit_cb.nci_wait_rsp_timer);
            nfc_hal_nci_cmd_timeout_cback ((void *)&nfc_hal_cb.ncit_cb.nci_wait_rsp_timer);
        }
        else
        {
            nfc_hal_main_send_error (HAL_NFC_STATUS_ERR_TRANSPORT);
        }
    }
    else if (evt == USERIAL_WAKEUP_EVT)
    {
        HAL_TRACE_DEBUG1 ("nfc_hal_main_userial_cback: USERIAL_WAKEUP_EVT: %d", p_data->sigs);
    }
    else
    {
        HAL_TRACE_DEBUG1 ("nfc_hal_main_userial_cback: unhandled userial evt: %i", evt);
    }
}
/*******************************************************************************
**
** Function         nfc_hal_dm_send_startup_vsc
**
** Description      Send VS command before NFA start-up
**
** Returns          None
**
*******************************************************************************/
void nfc_hal_dm_send_startup_vsc (void)
{
    UINT8  *p, *p_end;
    UINT16 len;

    HAL_TRACE_DEBUG0 ("nfc_hal_dm_send_startup_vsc ()");

    /* VSC must have NCI header at least */
    if (nfc_hal_cb.dev_cb.next_startup_vsc + NCI_MSG_HDR_SIZE - 1 <= *p_nfc_hal_dm_start_up_vsc_cfg)
    {
        p     = p_nfc_hal_dm_start_up_vsc_cfg + nfc_hal_cb.dev_cb.next_startup_vsc;
        len   = *(p + 2);
        p_end = p + NCI_MSG_HDR_SIZE - 1 + len;

        if (p_end <= p_nfc_hal_dm_start_up_vsc_cfg + *p_nfc_hal_dm_start_up_vsc_cfg)
        {
            /* move to next VSC */
            nfc_hal_cb.dev_cb.next_startup_vsc += NCI_MSG_HDR_SIZE + len;

            /* if this is last VSC */
            if (p_end == p_nfc_hal_dm_start_up_vsc_cfg + *p_nfc_hal_dm_start_up_vsc_cfg)
                nfc_hal_cb.dev_cb.next_dm_config = NFC_HAL_DM_CONFIG_NONE;

            nfc_hal_dm_send_nci_cmd (p, (UINT16)(NCI_MSG_HDR_SIZE + len), nfc_hal_dm_config_nfcc_cback);
            return;
        }
    }

    HAL_TRACE_ERROR0 ("nfc_hal_dm_send_startup_vsc (): Bad start-up VSC");

    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_FAILED);
}
/*******************************************************************************
**
** Function         nfc_hal_dm_send_bt_cmd
**
** Description      Send BT message to NFCC while initializing BRCM NFCC
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_dm_send_bt_cmd (const UINT8 *p_data, UINT16 len, tNFC_HAL_BTVSC_CPLT_CBACK *p_cback)
{
    NFC_HDR *p_buf;

    HAL_TRACE_DEBUG1 ("nfc_hal_dm_send_bt_cmd (): nci_wait_rsp = 0x%x", nfc_hal_cb.ncit_cb.nci_wait_rsp);

    if (nfc_hal_cb.ncit_cb.nci_wait_rsp != NFC_HAL_WAIT_RSP_NONE)
    {
        HAL_TRACE_ERROR0 ("nfc_hal_dm_send_bt_cmd(): no command window");
        return;
    }

    if ((p_buf = (NFC_HDR *) GKI_getpoolbuf (NFC_HAL_NCI_POOL_ID)) != NULL)
    {
        nfc_hal_cb.ncit_cb.nci_wait_rsp = NFC_HAL_WAIT_RSP_PROP;

        p_buf->offset = NFC_HAL_NCI_MSG_OFFSET_SIZE;
        p_buf->len    = len;

        memcpy ((UINT8*) (p_buf + 1) + p_buf->offset, p_data, len);

        /* save the callback for NCI VSCs)  */
        nfc_hal_cb.ncit_cb.p_vsc_cback = (void *)p_cback;

        nfc_hal_cb.ncit_cb.p_pend_cmd = p_buf;
        if (nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_IDLE)
        {
            NFC_HAL_SET_INIT_STATE(NFC_HAL_INIT_STATE_W4_CONTROL_DONE);
            nfc_hal_cb.p_stack_cback (HAL_NFC_REQUEST_CONTROL_EVT, HAL_NFC_STATUS_OK);
            return;
        }

        nfc_hal_dm_send_pend_cmd();
    }
}
/*******************************************************************************
**
** Function         nfc_hal_dm_send_bt_cmd
**
** Description      Send BT message to NFCC while initializing BRCM NFCC
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_dm_send_bt_cmd (const UINT8 *p_data, UINT16 len, tNFC_HAL_BTVSC_CPLT_CBACK *p_cback)
{
    NFC_HDR *p_buf;
    char buff[300];
    char tmp[4];
    buff[0] = 0;
    int i;

    HAL_TRACE_DEBUG1 ("nfc_hal_dm_send_bt_cmd (): nci_wait_rsp = 0x%x", nfc_hal_cb.ncit_cb.nci_wait_rsp);

    for (i = 0; i < len; i++)
    {
        sprintf (tmp, "%02x ", p_data[i]);
        strcat(buff, tmp);
    }
    HAL_TRACE_DEBUG2 ("nfc_hal_dm_send_bt_cmd (): HCI Write (%d bytes): %s", len, buff);

    if (nfc_hal_cb.ncit_cb.nci_wait_rsp != NFC_HAL_WAIT_RSP_NONE)
    {
        HAL_TRACE_ERROR0 ("nfc_hal_dm_send_bt_cmd(): no command window");
        return;
    }

    if ((p_buf = (NFC_HDR *) GKI_getpoolbuf (NFC_HAL_NCI_POOL_ID)) != NULL)
    {
        nfc_hal_cb.ncit_cb.nci_wait_rsp = NFC_HAL_WAIT_RSP_PROP;

        p_buf->offset = NFC_HAL_NCI_MSG_OFFSET_SIZE;
        p_buf->len    = len;

        memcpy ((UINT8*) (p_buf + 1) + p_buf->offset, p_data, len);

        /* save the callback for NCI VSCs)  */
        nfc_hal_cb.ncit_cb.p_vsc_cback = (void *)p_cback;

        nfc_hal_cb.ncit_cb.p_pend_cmd = p_buf;
        if (nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_IDLE)
        {
            NFC_HAL_SET_INIT_STATE(NFC_HAL_INIT_STATE_W4_CONTROL_DONE);
            nfc_hal_cb.p_stack_cback (HAL_NFC_REQUEST_CONTROL_EVT, HAL_NFC_STATUS_OK);
            return;
        }

        nfc_hal_dm_send_pend_cmd();
    }
}
/*******************************************************************************
**
** Function         nfc_hal_dm_send_nci_cmd
**
** Description      Send NCI command to NFCC while initializing BRCM NFCC
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_dm_send_nci_cmd (const UINT8 *p_data, UINT16 len, tNFC_HAL_NCI_CBACK *p_cback)
{
    NFC_HDR *p_buf;
    UINT8  *ps;

    HAL_TRACE_DEBUG1 ("nfc_hal_dm_send_nci_cmd (): nci_wait_rsp = 0x%x", nfc_hal_cb.ncit_cb.nci_wait_rsp);

    if (nfc_hal_cb.ncit_cb.nci_wait_rsp != NFC_HAL_WAIT_RSP_NONE)
    {
        HAL_TRACE_ERROR0 ("nfc_hal_dm_send_nci_cmd(): no command window");
        return;
    }

    if ((p_buf = (NFC_HDR *)GKI_getpoolbuf (NFC_HAL_NCI_POOL_ID)) != NULL)
    {
        nfc_hal_cb.ncit_cb.nci_wait_rsp = NFC_HAL_WAIT_RSP_VSC;

        p_buf->offset = NFC_HAL_NCI_MSG_OFFSET_SIZE;
        p_buf->event  = NFC_HAL_EVT_TO_NFC_NCI;
        p_buf->len    = len;

        memcpy ((UINT8*) (p_buf + 1) + p_buf->offset, p_data, len);

        /* Keep a copy of the command and send to NCI transport */

        /* save the message header to double check the response */
        ps   = (UINT8 *)(p_buf + 1) + p_buf->offset;
        memcpy(nfc_hal_cb.ncit_cb.last_hdr, ps, NFC_HAL_SAVED_HDR_SIZE);
        memcpy(nfc_hal_cb.ncit_cb.last_cmd, ps + NCI_MSG_HDR_SIZE, NFC_HAL_SAVED_CMD_SIZE);

        /* save the callback for NCI VSCs */
        nfc_hal_cb.ncit_cb.p_vsc_cback = (void *)p_cback;

        nfc_hal_nci_send_cmd (p_buf);

        /* start NFC command-timeout timer */
        nfc_hal_main_start_quick_timer (&nfc_hal_cb.ncit_cb.nci_wait_rsp_timer, (UINT16)(NFC_HAL_TTYPE_NCI_WAIT_RSP),
                                        ((UINT32) NFC_HAL_CMD_TOUT) * QUICK_TIMER_TICKS_PER_SEC / 1000);
    }
}
/*******************************************************************************
**
** Function         nfc_hal_prm_process_timeout
**
** Description      Process timer expireation for patch download
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_prm_process_timeout (void *p_tle)
{
    NFC_HAL_PRM_STATE ("nfc_hal_prm_process_timeout");

    if (nfc_hal_cb.prm.state == NFC_HAL_PRM_ST_SPD_AUTH_DONE)
    {
        if (!(nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_BCM20791B3))
        {
            /* Timeout waiting for RESET NTF after signature sent */
            HAL_TRACE_ERROR0 ("Timeout waiting for RESET NTF after patch download");
            nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_EVT);
        }
        else
        {
            nfc_hal_prm_nfcc_ready_to_continue ();
        }
    }
    else if (nfc_hal_cb.prm.state == NFC_HAL_PRM_ST_SPD_GET_PATCH_HEADER)
    {
        HAL_TRACE_DEBUG0 ("Delay after PreI2C patch download...proceeding to download firmware patch");
        nfc_hal_prm_spd_handle_next_patch_start ();
    }
    else if (nfc_hal_cb.prm.state == NFC_HAL_PRM_ST_W4_GET_VERSION)
    {
        HAL_TRACE_DEBUG0 ("get patch version timeout???");
        nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_COMPLETE_EVT);
    }
    else
    {
        HAL_TRACE_ERROR1 ("Patch download: command timeout (state=%i)", nfc_hal_cb.prm.state);

        nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_EVT);
    }

    NFC_HAL_PRM_STATE ("nfc_hal_prm_process_timeout");
}
/*******************************************************************************
**
** Function         nfc_hal_send_credit_ntf_for_cid
**
** Description      This function is called to send credit ntf
**                  for the specified connection id to nfc task
**
** Returns          void
**
*******************************************************************************/
static void nfc_hal_send_credit_ntf_for_cid (UINT8 cid)
{
    NFC_HDR  *p_msg;
    UINT8    *p, *ps;

    /* Start of new message. Allocate a buffer for message */
    if ((p_msg = (NFC_HDR *) GKI_getpoolbuf (NFC_HAL_NCI_POOL_ID)) != 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 *) (p_msg + 1) + p_msg->offset;
        ps = p;
        NCI_MSG_BLD_HDR0(p, NCI_MT_NTF, NCI_GID_CORE);
        NCI_MSG_BLD_HDR1(p, NCI_MSG_CORE_CONN_CREDITS);
        UINT8_TO_STREAM (p, 0x03);

        /* Number of credit entries */
        *p++ = 0x01;
        /* Connection id of the credit ntf */
        *p++ = cid;
        /* Number of credits */
        *p = 0x01;
#ifdef DISP_NCI
        DISP_NCI (ps, (UINT16) p_msg->len, TRUE);
#endif
        nfc_hal_send_nci_msg_to_nfc_task (p_msg);
    }
    else
    {
        HAL_TRACE_ERROR0 ("Unable to allocate buffer for Sending credit ntf to stack");
    }
}
/*******************************************************************************
**
** Function         HAL_NfcPrmDownloadStart
**
** Description      Initiate patch download
**
** Input Params
**                  format_type     patch format type
**                                  (NFC_HAL_PRM_FORMAT_BIN, NFC_HAL_PRM_FORMAT_HCD, or
**                                   NFC_HAL_PRM_FORMAT_NCD)
**
**                  dest_address    destination adderess (needed for BIN format only)
**
**                  p_patchram_buf  pointer to patchram buffer. If NULL,
**                                  then app must call HAL_NfcPrmDownloadContinue when
**                                  NFC_HAL_PRM_CONTINUE_EVT is received, to send the next
**                                  segment of patchram
**
**                  patchram_len    size of p_patchram_buf (if non-NULL)
**
**                  patchram_delay  The delay after each patch.
**                                  If the given value is less than the size of the patchram,
**                                  the size of patchram is used instead.
**
**                  p_cback         callback for download status
**
**
** Returns          TRUE if successful, otherwise FALSE
**
**
*******************************************************************************/
BOOLEAN HAL_NfcPrmDownloadStart (tNFC_HAL_PRM_FORMAT format_type,
                                 UINT32              dest_address,
                                 UINT8               *p_patchram_buf,
                                 UINT32              patchram_len,
                                 UINT32              patchram_delay,
                                 tNFC_HAL_PRM_CBACK  *p_cback)
{
    HAL_TRACE_API0 ("HAL_NfcPrmDownloadStart ()");

    memset (&nfc_hal_cb.prm, 0, sizeof (tNFC_HAL_PRM_CB));

    if (p_patchram_buf)
    {
        nfc_hal_cb.prm.p_cur_patch_data = p_patchram_buf;
        nfc_hal_cb.prm.cur_patch_offset = 0;
        nfc_hal_cb.prm.cur_patch_len_remaining = (UINT16) patchram_len;
        nfc_hal_cb.prm.flags |= NFC_HAL_PRM_FLAGS_USE_PATCHRAM_BUF;

        if (patchram_len == 0)
            return FALSE;
    }

    nfc_hal_cb.prm.p_cback          = p_cback;
    nfc_hal_cb.prm.dest_ram         = dest_address;
    nfc_hal_cb.prm.format           = format_type;
    nfc_hal_cb.prm.patchram_delay   = patchram_delay;

    nfc_hal_cb.prm.timer.p_cback = nfc_hal_prm_process_timeout;

    if (format_type == NFC_HAL_PRM_FORMAT_NCD)
    {
        /* Store patch buffer pointer and length */
        nfc_hal_cb.prm.p_spd_patch             = p_patchram_buf;
        nfc_hal_cb.prm.spd_patch_len_remaining = (UINT16)patchram_len;
        nfc_hal_cb.prm.spd_patch_offset        = 0;

        /* If patch download is required, but no NVM is available, then abort */
        if ((p_nfc_hal_cfg->nfc_hal_prm_nvm_required) && (nfc_hal_cb.nvm_cb.flags & NFC_HAL_NVM_FLAGS_NO_NVM))
        {
            HAL_TRACE_ERROR0 ("This platform requires NVM and the NVM is not available - Abort");
            nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_NO_NVM_EVT);
            return FALSE;
        }

        /* Compare patch version in NVM with version in patchfile */
        nfc_hal_cb.prm.state = NFC_HAL_PRM_ST_SPD_COMPARE_VERSION;
        if (nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_USE_PATCHRAM_BUF)
        {
            /* If patchfile is in a buffer, get patch version from buffer */
            nfc_hal_prm_spd_check_version ();
        }
        else
        {
            /* If patchfile is not in a buffer, then request patchfile header from adaptation layer. */
            (nfc_hal_cb.prm.p_cback) (NFC_HAL_PRM_SPD_GET_PATCHFILE_HDR_EVT);
        }
    }
    else
    {
        HAL_TRACE_ERROR0 ("Unexpected patch format.");
        return FALSE;
    }

    return TRUE;
}
/*******************************************************************************
**
** Function         nfc_hal_prm_spd_send_next_segment
**
** Description      Send next patch segment (for secure patch download)
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_prm_spd_send_next_segment (void)
{
    UINT8   *p_src;
    UINT16  len, offset = nfc_hal_cb.prm.cur_patch_offset;
    UINT8   hcit, oid, hdr0, type;
    UINT8   chipverlen;
    UINT8   chipverstr[NCI_SPD_HEADER_CHIPVER_LEN];
    UINT8   patch_hdr_size = NCI_MSG_HDR_SIZE + 1; /* 1 is for HCIT */

    /* Validate that segment is at least big enought to have NCI_MSG_HDR_SIZE + 1 (hcit) */
    if (nfc_hal_cb.prm.cur_patch_len_remaining < patch_hdr_size)
    {
        HAL_TRACE_ERROR0 ("Unexpected end of patch.");
        nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_INVALID_PATCH_EVT);
        return;
    }

    /* Parse NCI command header */
    p_src = (UINT8*) (nfc_hal_cb.prm.p_cur_patch_data + offset);
    STREAM_TO_UINT8 (hcit, p_src);
    STREAM_TO_UINT8 (hdr0, p_src);
    STREAM_TO_UINT8 (oid,  p_src);
    STREAM_TO_UINT8 (len,  p_src);
    STREAM_TO_UINT8 (type, p_src);


    /* Update number of bytes comsumed */
    nfc_hal_cb.prm.cur_patch_offset += (len + patch_hdr_size);
    nfc_hal_cb.prm.cur_patch_len_remaining -=  (len + patch_hdr_size);

    /* Check if sending signature byte */
    if (  (oid == NCI_MSG_SECURE_PATCH_DOWNLOAD )
        &&(type == NCI_SPD_TYPE_SIGNATURE)  )
    {
        nfc_hal_cb.prm.flags |= NFC_HAL_PRM_FLAGS_SIGNATURE_SENT;
    }
    /* Check for header */
    else if (  (oid == NCI_MSG_SECURE_PATCH_DOWNLOAD )
             &&(type == NCI_SPD_TYPE_HEADER)  )
    {
        /* Check if patch is for BCM20791B3 */
        p_src += NCI_SPD_HEADER_OFFSET_CHIPVERLEN;
        STREAM_TO_UINT8 (chipverlen, p_src);
        if (memcmp (nfc_hal_cb.nvm_cb.chip_ver, p_src, chipverlen) != 0)
        {
            HAL_TRACE_ERROR0 ("Unexpected chip ver.");
            nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_INVALID_PATCH_EVT);
            return;
        }
        STREAM_TO_ARRAY (chipverstr, p_src, NCI_SPD_HEADER_CHIPVER_LEN);

        if (memcmp (NFC_HAL_PRM_BCM20791B3_STR, chipverstr, NFC_HAL_PRM_BCM20791B3_STR_LEN) == 0)
        {
            /* Patch is for BCM2079B3 - do not wait for RESET_NTF after patch download */
            nfc_hal_cb.prm.flags |= NFC_HAL_PRM_FLAGS_BCM20791B3;
        }
        else
        {
            /* Patch is for BCM2079B4 or newer - wait for RESET_NTF after patch download */
            nfc_hal_cb.prm.flags &= ~NFC_HAL_PRM_FLAGS_BCM20791B3;
        }
    }

    /* Send the command (not including HCIT here) */
    nfc_hal_dm_send_nci_cmd ((UINT8*) (nfc_hal_cb.prm.p_cur_patch_data + offset + 1), (UINT8) (len + NCI_MSG_HDR_SIZE),
                             nfc_hal_prm_nci_command_complete_cback);
}
/*******************************************************************************
**
** Function         nfc_hal_prm_nci_command_complete_cback
**
** Description      Callback for NCI vendor specific command complete
**                  (for secure patch download)
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_prm_nci_command_complete_cback (tNFC_HAL_NCI_EVT event, UINT16 data_len, UINT8 *p_data)
{
    UINT8 status, u8;
    UINT8 *p;
    UINT32 post_signature_delay;

    NFC_HAL_PRM_STATE ("nfc_hal_prm_nci_command_complete_cback");

    /* Stop the command-timeout timer */
    nfc_hal_main_stop_quick_timer (&nfc_hal_cb.prm.timer);

    /* Skip over NCI header */
    p = p_data + NCI_MSG_HDR_SIZE;

    /* Handle SECURE_PATCH_DOWNLOAD Rsp */
    if (event == NFC_VS_SEC_PATCH_DOWNLOAD_EVT)
    {
        /* Status and error code */
        STREAM_TO_UINT8 (status, p);
        STREAM_TO_UINT8 (u8, p);

        if (status != NCI_STATUS_OK)
        {
#if (NFC_HAL_TRACE_VERBOSE == TRUE)
            HAL_TRACE_ERROR2 ("Patch download failed, reason code=0x%X (%s)", status, nfc_hal_prm_spd_status_str (status));
#else
            HAL_TRACE_ERROR1 ("Patch download failed, reason code=0x%X", status);
#endif

            /* Notify application */
            nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_INVALID_PATCH_EVT);
            return;
        }

        /* If last segment (SIGNATURE) sent */
        if (nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_SIGNATURE_SENT)
        {
            /* Wait for authentication complete (SECURE_PATCH_DOWNLOAD NTF), including time to commit to NVM (for BCM43341B0) */
            int auth_delay = NFC_HAL_PRM_SPD_TOUT;
            if (!(nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_BCM20791B3))
            {
                /* XXX maco only wait 30 seconds for B4+ revisions to avoid watchdog timeouts */
                auth_delay = NFC_HAL_PRM_COMMIT_DELAY;
            }
            nfc_hal_cb.prm.state = NFC_HAL_PRM_ST_SPD_AUTHENTICATING;
            nfc_hal_main_start_quick_timer (&nfc_hal_cb.prm.timer, 0x00,
                                            (auth_delay * QUICK_TIMER_TICKS_PER_SEC) / 1000);
            return;
        }
        /* Download next segment */
        else if (nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_USE_PATCHRAM_BUF)
        {
            /* If patch is in a buffer, get next patch from buffer */
            nfc_hal_prm_spd_send_next_segment ();
        }
        else
        {
            /* Notify adaptation layer to get next patch segment (via HAL_NfcPrmDownloadContinue) */
            (nfc_hal_cb.prm.p_cback) (NFC_HAL_PRM_CONTINUE_EVT);
        }
    }
    /* Handle SECURE_PATCH_DOWNLOAD NTF */
    else if (event == NFC_VS_SEC_PATCH_AUTH_EVT)
    {
        HAL_TRACE_DEBUG1 ("prm flags:0x%x.", nfc_hal_cb.prm.flags);
        /* Status and error code */
        STREAM_TO_UINT8 (status, p);
        STREAM_TO_UINT8 (u8, p);

        /* Sanity check - should only get this NTF while in AUTHENTICATING stage */
        if (nfc_hal_cb.prm.state == NFC_HAL_PRM_ST_SPD_AUTHENTICATING)
        {
            if (status != NCI_STATUS_OK)
            {
                HAL_TRACE_ERROR0 ("Patch authentication failed");
                nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_BAD_SIGNATURE_EVT);
                return;
            }

#if (defined (NFC_HAL_PRE_I2C_PATCH_INCLUDED) && (NFC_HAL_PRE_I2C_PATCH_INCLUDED == TRUE))
            if (nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_I2C_FIX_REQUIRED)
            {
                HAL_TRACE_DEBUG1 ("PreI2C patch downloaded...waiting %i ms for NFCC to reboot.", nfc_hal_cb.prm_i2c.prei2c_delay);

                /* Restore pointers to patchfile */
                nfc_hal_cb.prm.flags &= ~NFC_HAL_PRM_FLAGS_I2C_FIX_REQUIRED;
                nfc_hal_cb.prm.p_cur_patch_data = nfc_hal_cb.prm.p_spd_patch;
                nfc_hal_cb.prm.cur_patch_offset = nfc_hal_cb.prm.spd_patch_offset;
                nfc_hal_cb.prm.cur_patch_len_remaining = nfc_hal_cb.prm.spd_patch_len_remaining;

                /* Resume normal patch download */
                nfc_hal_cb.prm.state = NFC_HAL_PRM_ST_SPD_GET_PATCH_HEADER;
                nfc_hal_cb.prm.flags &= ~NFC_HAL_PRM_FLAGS_SIGNATURE_SENT;

                /* Post PreI2C delay */
                nfc_hal_main_start_quick_timer (&nfc_hal_cb.prm.timer, 0x00, (nfc_hal_cb.prm_i2c.prei2c_delay * QUICK_TIMER_TICKS_PER_SEC) / 1000);

                return;
            }
#endif  /* NFC_HAL_PRE_I2C_PATCH_INCLUDED */


            /* Wait for NFCC to save the patch to NVM */
            if (!(nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_BCM20791B3))
            {
                /* 20791B4 or newer - wait for RESET_NTF; including time to commit to NVM (for BCM20791B4+) */
                post_signature_delay = NFC_HAL_PRM_COMMIT_DELAY;
                HAL_TRACE_DEBUG1 ("Patch downloaded and authenticated. Waiting %i ms for RESET NTF...", post_signature_delay);

            }
            else if (nfc_hal_cb.nvm_cb.flags & NFC_HAL_NVM_FLAGS_NO_NVM)
            {
                /* No NVM. Wait for NFCC to restart */
                post_signature_delay = NFC_HAL_PRM_END_DELAY;
                HAL_TRACE_DEBUG1 ("Patch downloaded and authenticated. Waiting %i ms for NFCC to restart...", post_signature_delay);
            }
            else
            {
                /* Wait for NFCC to save the patch to NVM (need about 1 ms per byte) */
                post_signature_delay = nfc_hal_cb.prm.spd_patch_desc[nfc_hal_cb.prm.spd_cur_patch_idx].len;
                if (post_signature_delay < nfc_hal_cb.prm.patchram_delay)
                    post_signature_delay = nfc_hal_cb.prm.patchram_delay;
                HAL_TRACE_DEBUG1 ("Patch downloaded and authenticated. Waiting %i ms for NVM update to complete...", post_signature_delay);
            }

            nfc_hal_cb.prm.state = NFC_HAL_PRM_ST_SPD_AUTH_DONE;

            nfc_hal_main_start_quick_timer (&nfc_hal_cb.prm.timer, 0x00,
                                            (post_signature_delay * QUICK_TIMER_TICKS_PER_SEC) / 1000);
        }
        else
        {
            HAL_TRACE_ERROR0 ("Got unexpected SECURE_PATCH_DOWNLOAD NTF");
            nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_EVT);
        }
    }
    /* Handle NCI_MSG_GET_PATCH_VERSION RSP */
    else if (event == NFC_VS_GET_PATCH_VERSION_EVT)
    {
        nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_COMPLETE_EVT);
    }
    else
    {
        /* Invalid response from NFCC during patch download */
        HAL_TRACE_ERROR1 ("Invalid response from NFCC during patch download (opcode=0x%02X)", event);
        nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_INVALID_PATCH_EVT);
    }

    NFC_HAL_PRM_STATE ("prm_nci_command_complete_cback");
}
/*******************************************************************************
**
** Function         nfc_hal_prm_spd_check_version
**
** Description      Check patchfile version with current downloaded version
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_prm_spd_check_version (void)
{
    UINT8 *p, *p_start, i;
    UINT32 nvm_patch_present_mask = 0;
    UINT32 patchfile_patch_present_mask;
    UINT16 patchfile_project_id = 0;
    UINT16 patchfile_ver_major = 0;
    UINT16 patchfile_ver_minor = 0;
    UINT16 patchfile_patchsize;

    UINT8  return_code = NFC_HAL_PRM_COMPLETE_EVT;

    /* Initialize patchfile offset pointers */
    p = p_start = NULL;
    patchfile_patchsize = 0;

    /* the good patches in NVM */
    if (nfc_hal_cb.nvm_cb.lpm_size && !(nfc_hal_cb.nvm_cb.flags & (NFC_HAL_NVM_FLAGS_LPM_BAD)))
        nvm_patch_present_mask  |= (1 << NFC_HAL_PRM_SPD_POWER_MODE_LPM);

    if (nfc_hal_cb.nvm_cb.fpm_size && !(nfc_hal_cb.nvm_cb.flags & (NFC_HAL_NVM_FLAGS_FPM_BAD)))
        nvm_patch_present_mask  |= (1 << NFC_HAL_PRM_SPD_POWER_MODE_FPM);

    /* Get patchfile version */
    if (nfc_hal_cb.prm.cur_patch_len_remaining >= NFC_HAL_PRM_NCD_PATCHFILE_HDR_LEN)
    {
        /* Parse patchfile header */
        p       = (UINT8 *) nfc_hal_cb.prm.p_cur_patch_data;
        p_start = p;
        STREAM_TO_UINT16 (patchfile_project_id, p);
        STREAM_TO_UINT16 (patchfile_ver_major, p);
        STREAM_TO_UINT16 (patchfile_ver_minor, p);

        /* RFU */
        p++;

        /* Check how many patches are in the patch file */
        STREAM_TO_UINT8 (nfc_hal_cb.prm.spd_patch_count, p);

        if (nfc_hal_cb.prm.spd_patch_count > NFC_HAL_PRM_MAX_PATCH_COUNT)
        {
            HAL_TRACE_ERROR2 ("Unsupported patchfile (number of patches (%i) exceeds maximum (%i)",
                               nfc_hal_cb.prm.spd_patch_count, NFC_HAL_PRM_MAX_PATCH_COUNT);
        }

        /* Mask of patches that are present in the patchfile */
        patchfile_patch_present_mask = 0;

        /* Get lengths for each patch */
        for (i = 0; i < nfc_hal_cb.prm.spd_patch_count; i++)
        {
            /* Get power mode for this patch */
            STREAM_TO_UINT8 (nfc_hal_cb.prm.spd_patch_desc[i].power_mode, p);

            /* Update mask of power-modes present in the patchfile */
            patchfile_patch_present_mask |= ((UINT32) 1 << nfc_hal_cb.prm.spd_patch_desc[i].power_mode);

            /* Get length of patch */
            STREAM_TO_UINT16 (nfc_hal_cb.prm.spd_patch_desc[i].len, p);

            /* Add total size of patches */
            patchfile_patchsize += nfc_hal_cb.prm.spd_patch_desc[i].len;

            /* 5 byte RFU */
            p += 5;
        }

        /* Adjust offset to after the patch file header */
        nfc_hal_cb.prm.cur_patch_offset += (UINT16) (p - p_start);              /* Bytes of patchfile transmitted/processed so far */
        nfc_hal_cb.prm.cur_patch_len_remaining -= (UINT16) (p - p_start);       /* Adjust size of patchfile                        */


        HAL_TRACE_DEBUG4 ("NVM Patch info: flags=0x%04x,   Ver=%i.%i, PatchMask=0x%08x",
            nfc_hal_cb.nvm_cb.flags, nfc_hal_cb.nvm_cb.ver_major, nfc_hal_cb.nvm_cb.ver_minor, nvm_patch_present_mask );
        HAL_TRACE_DEBUG6 ("Patchfile info: ProjID=0x%04x,  Ver=%i.%i, Num patches=%i, PatchMask=0x%08x, PatchSize=%i",
                           patchfile_project_id, patchfile_ver_major, patchfile_ver_minor,
                           nfc_hal_cb.prm.spd_patch_count, patchfile_patch_present_mask, patchfile_patchsize);

        /*********************************************************************
        * Version check of patchfile against NVM
        ********************************************************************
        /* Download the patchfile if no patches in NVM */
        if ((nfc_hal_cb.nvm_cb.project_id == 0) || !(nfc_hal_cb.nvm_cb.flags & NFC_HAL_NVM_FLAGS_PATCH_PRESENT))
        {
            /* No patch in NVM, need to download all */
            nfc_hal_cb.prm.spd_patch_needed_mask = patchfile_patch_present_mask;

            HAL_TRACE_DEBUG2 ("No previous patch detected. Downloading patch %i.%i",
                              patchfile_ver_major, patchfile_ver_minor);
        }
        /* Skip download if project ID of patchfile does not match NVM */
        else if (nfc_hal_cb.nvm_cb.project_id != patchfile_project_id)
        {
            /* Project IDs mismatch */
            HAL_TRACE_DEBUG2 ("Patch download skipped: Mismatched Project ID (NVM ProjId: 0x%04x, Patchfile ProjId: 0x%04x)",
                              nfc_hal_cb.nvm_cb.project_id, patchfile_project_id);

            return_code = NFC_HAL_PRM_ABORT_INVALID_PATCH_EVT;
        }
        /* Skip download if version of patchfile is equal to version in NVM */
        /*                  and patches of the power modes are the same as the good patches in NVM */
        else if (  (nfc_hal_cb.nvm_cb.ver_major == patchfile_ver_major)
                 &&(nfc_hal_cb.nvm_cb.ver_minor == patchfile_ver_minor)
                 &&((nvm_patch_present_mask | patchfile_patch_present_mask) == nvm_patch_present_mask)  ) /* if the NVM patch include all the patched in file */
        {
            HAL_TRACE_DEBUG2 ("Patch download skipped. NVM patch (version %i.%i) is the same than the patchfile ",
                              nfc_hal_cb.nvm_cb.ver_major, nfc_hal_cb.nvm_cb.ver_minor);

            return_code = NFC_HAL_PRM_COMPLETE_EVT;
        }
        /* Remaining cases: Download all patches in the patchfile */
        else
        {
            nfc_hal_cb.prm.spd_patch_needed_mask = patchfile_patch_present_mask;

            HAL_TRACE_DEBUG4 ("Downloading patch version: %i.%i (previous version in NVM: %i.%i)...",
                              patchfile_ver_major, patchfile_ver_minor,
                              nfc_hal_cb.nvm_cb.ver_major, nfc_hal_cb.nvm_cb.ver_minor);
        }

    }
    else
    {
        /* Invalid patch file header */
        HAL_TRACE_ERROR0 ("Invalid patch file header.");

        return_code = NFC_HAL_PRM_ABORT_INVALID_PATCH_EVT;
    }

    /* If we need to download anything, get the first patch to download */
    if (nfc_hal_cb.prm.spd_patch_needed_mask)
    {
        HAL_TRACE_ERROR4 ("Downloading patch version: %i.%i (previous version in NVM: %i.%i)...",
                            patchfile_ver_major, patchfile_ver_minor,
                            nfc_hal_cb.nvm_cb.ver_major, nfc_hal_cb.nvm_cb.ver_minor);
#if (defined (NFC_HAL_PRE_I2C_PATCH_INCLUDED) && (NFC_HAL_PRE_I2C_PATCH_INCLUDED == TRUE))
        /* Check if I2C patch is needed: if                                     */
        /*      - I2C patch file was provided using HAL_NfcPrmSetI2cPatch, and        */
        /*      -   current patch in NVM has ProjectID=0, or                    */
        /*          FPM is not present or corrupted, or                         */
        /*          or patchfile is major-ver 76+                               */
        /*          or patchfile is not for B3 (always download for B4 onward)  */
        if (  (nfc_hal_cb.prm_i2c.p_patch)
            &&(  (nfc_hal_cb.nvm_cb.project_id == 0)
               ||(nfc_hal_cb.nvm_cb.fpm_size == 0)
               ||(nfc_hal_cb.nvm_cb.flags & NFC_HAL_NVM_FLAGS_FPM_BAD)
               ||(patchfile_ver_major >= 76)
               ||(!(nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_BCM20791B3)) ))
        {
            HAL_TRACE_DEBUG0 ("I2C patch fix required.");
            nfc_hal_cb.prm.flags |= NFC_HAL_PRM_FLAGS_I2C_FIX_REQUIRED;

            /* Download i2c fix first */
            nfc_hal_prm_spd_download_i2c_fix ();
            return;
        }
#endif  /* NFC_HAL_PRE_I2C_PATCH_INCLUDED */

        /* Download first segment */
        nfc_hal_cb.prm.state = NFC_HAL_PRM_ST_SPD_GET_PATCH_HEADER;
        if (!(nfc_hal_cb.prm.flags & NFC_HAL_PRM_FLAGS_USE_PATCHRAM_BUF))
        {
            /* Notify adaptation layer to call HAL_NfcPrmDownloadContinue with the next patch segment */
            (nfc_hal_cb.prm.p_cback) (NFC_HAL_PRM_SPD_GET_NEXT_PATCH);
        }
        else
        {
            nfc_hal_prm_spd_handle_next_patch_start ();
        }
    }
    else
    {
        static BOOLEAN firstTime = TRUE;
        if (firstTime)
        {
            HAL_TRACE_ERROR2 ("NVM patch version is %d.%d",
                              nfc_hal_cb.nvm_cb.ver_major, nfc_hal_cb.nvm_cb.ver_minor);
            firstTime = FALSE;
        }
        /* Download complete */
        nfc_hal_prm_spd_handle_download_complete (return_code);
    }
}
/*******************************************************************************
**
** Function         nfc_hal_prm_spd_download_i2c_fix
**
** Description      Start downloading patch for i2c fix
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_prm_spd_download_i2c_fix (void)
{
    UINT8 *p, *p_start;
    UINT16 patchfile_project_id;
    UINT16 patchfile_ver_major;
    UINT16 patchfile_ver_minor;
    UINT16 patchfile_patchsize;
    UINT8 u8;

    HAL_TRACE_DEBUG0 ("Downloading I2C fix...");

    /* Save pointer and offset of patchfile, so we can resume after downloading the i2c fix */
    nfc_hal_cb.prm.spd_patch_offset = nfc_hal_cb.prm.cur_patch_offset;
    nfc_hal_cb.prm.spd_patch_len_remaining = nfc_hal_cb.prm.cur_patch_len_remaining;

    /* Initialize pointers for downloading i2c fix */
    nfc_hal_cb.prm.p_cur_patch_data = nfc_hal_cb.prm_i2c.p_patch;
    nfc_hal_cb.prm.cur_patch_offset = 0;
    nfc_hal_cb.prm.cur_patch_len_remaining = nfc_hal_cb.prm_i2c.len;

    /* Parse the i2c patchfile */
    if (nfc_hal_cb.prm.cur_patch_len_remaining >= NFC_HAL_PRM_NCD_PATCHFILE_HDR_LEN)
    {
        /* Parse patchfile header */
        p = (UINT8 *) nfc_hal_cb.prm.p_cur_patch_data;
        p_start = p;
        STREAM_TO_UINT16 (patchfile_project_id, p);
        STREAM_TO_UINT16 (patchfile_ver_major, p);
        STREAM_TO_UINT16 (patchfile_ver_minor, p);

        /* RFU */
        p++;

        /* Check how many patches are in the patch file */
        STREAM_TO_UINT8 (u8, p);

        /* Should only be one patch */
        if (u8 > 1)
        {
            HAL_TRACE_ERROR1 ("Invalid i2c fix: invalid number of patches (%i)", u8);
            nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_INVALID_PATCH_EVT);
            return;
        }


        /* Get info about the i2c patch*/
        STREAM_TO_UINT8 (u8, p);                     /* power mode (not needed for i2c patch)    */
        STREAM_TO_UINT16 (patchfile_patchsize, p);   /* size of patch                            */

        /* 5 byte RFU */
        p += 5;

        /* Adjust length to exclude patchfiloe header */
        nfc_hal_cb.prm.cur_patch_len_remaining -= (UINT16) (p - p_start);       /* Adjust size of patchfile                        */
        nfc_hal_cb.prm.cur_patch_offset += (UINT16) (p - p_start);              /* Bytes of patchfile transmitted/processed so far */

        /* Begin sending patch to the NFCC */
        nfc_hal_prm_spd_send_next_segment ();
    }
    else
    {
        /* ERROR: Bad length for patchfile */
        HAL_TRACE_ERROR0 ("Invalid i2c fix: unexpected end of patch");
        nfc_hal_prm_spd_handle_download_complete (NFC_HAL_PRM_ABORT_INVALID_PATCH_EVT);
    }
}
/*******************************************************************************
**
** Function         nfc_hal_main_send_message
**
** Description      This function is calledto send an NCI message.
**
** Returns          void
**
*******************************************************************************/
static void nfc_hal_main_send_message (NFC_HDR *p_msg)
{
#if (defined(NFC_HAL_HCI_INCLUDED) && (NFC_HAL_HCI_INCLUDED == TRUE))
    UINT8   cid, pbf;
    UINT16  data_len;
#endif
    UINT8   *ps, *pp;
    UINT16  len = p_msg->len;
#ifdef DISP_NCI
    UINT8   delta;
#endif

    HAL_TRACE_DEBUG1 ("nfc_hal_main_send_message() ls:0x%x", p_msg->layer_specific);
    if (  (p_msg->layer_specific == NFC_HAL_WAIT_RSP_CMD)
        ||(p_msg->layer_specific == NFC_HAL_WAIT_RSP_VSC)  )
    {
        nfc_hal_nci_send_cmd (p_msg);
    }
    else
    {
        /* NFC task has fragmented the data packet to the appropriate size
         * and data credit is available; just send it */

        /* add NCI packet type in front of message */
        nfc_hal_nci_add_nfc_pkt_type (p_msg);

        /* send this packet to transport */
        ps = (UINT8 *) (p_msg + 1) + p_msg->offset;
        pp = ps + 1;
#ifdef DISP_NCI
        delta = p_msg->len - len;
        DISP_NCI (ps + delta, (UINT16) (p_msg->len - delta), FALSE);
#endif

#if (defined(NFC_HAL_HCI_INCLUDED) && (NFC_HAL_HCI_INCLUDED == TRUE))
        if (nfc_hal_cb.hci_cb.hcp_conn_id)
        {
            NCI_DATA_PRS_HDR(pp, pbf, cid, data_len);
            if (cid == nfc_hal_cb.hci_cb.hcp_conn_id)
            {
                if (nfc_hal_hci_handle_hcp_pkt_to_hc (pp))
                {
                    HAL_TRACE_DEBUG0 ("nfc_hal_main_send_message() - Drop rsp to Fake cmd, Fake credit ntf");
                    GKI_freebuf (p_msg);
                    nfc_hal_send_credit_ntf_for_cid (cid);
                    return;
                }
            }

        }
#endif

        /* check low power mode state */
        if (nfc_hal_dm_power_mode_execute (NFC_HAL_LP_TX_DATA_EVT))
        {
            USERIAL_Write (USERIAL_NFC_PORT, ps, p_msg->len);
        }
        else
        {
            HAL_TRACE_ERROR0 ("nfc_hal_main_send_message(): drop data in low power mode");
        }
        GKI_freebuf (p_msg);
    }
}
/*******************************************************************************
**
** Function         nfc_hal_dm_set_config
**
** Description      Send NCI config items to NFCC
**
** Returns          tHAL_NFC_STATUS
**
*******************************************************************************/
tHAL_NFC_STATUS nfc_hal_dm_set_config (UINT8 tlv_size,
                                       UINT8 *p_param_tlvs,
                                       tNFC_HAL_NCI_CBACK *p_cback)
{
    UINT8  *p_buff, *p;
    UINT8  num_param = 0, param_len, rem_len, *p_tlv;
    UINT16 cmd_len = NCI_MSG_HDR_SIZE + tlv_size + 1;
    tHAL_NFC_STATUS status = HAL_NFC_STATUS_FAILED;

    if ((tlv_size == 0)||(p_param_tlvs == NULL))
    {
        return status;
    }

    if ((p_buff = (UINT8 *) GKI_getbuf ((UINT16)(NCI_MSG_HDR_SIZE + tlv_size))) != NULL)
    {
        p = p_buff;

        NCI_MSG_BLD_HDR0 (p, NCI_MT_CMD, NCI_GID_CORE);
        NCI_MSG_BLD_HDR1 (p, NCI_MSG_CORE_SET_CONFIG);
        UINT8_TO_STREAM  (p, (UINT8) (tlv_size + 1));

        rem_len = tlv_size;
        p_tlv   = p_param_tlvs;
        while (rem_len > 1)
        {
            num_param++;                /* number of params */

            p_tlv ++;                   /* param type   */
            param_len = *p_tlv++;       /* param length */

            rem_len -= 2;               /* param type and length */
            if (rem_len >= param_len)
            {
                rem_len -= param_len;
                p_tlv   += param_len;   /* next param_type */

                if (rem_len == 0)
                {
                    status = HAL_NFC_STATUS_OK;
                    break;
                }
            }
            else
            {
                /* error found */
                break;
            }
        }

        if (status == HAL_NFC_STATUS_OK)
        {
            UINT8_TO_STREAM (p, num_param);
            ARRAY_TO_STREAM (p, p_param_tlvs, tlv_size);

            nfc_hal_dm_send_nci_cmd (p_buff, cmd_len, p_cback);
        }
        else
        {
            HAL_TRACE_ERROR0 ("nfc_hal_dm_set_config ():Bad TLV");
        }

        GKI_freebuf (p_buff);
    }

    return status;
}