/*******************************************************************************
**
** Function         nfc_hal_prm_spd_reset_ntf
**
** Description      Received RESET NTF from NFCC, indicating it has completed
**                  reset after patch download.
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_prm_spd_reset_ntf (UINT8 reset_reason, UINT8 reset_type)
{
    /* Check if we were expecting a RESET NTF */
    if (nfc_hal_cb.prm.state == NFC_HAL_PRM_ST_SPD_AUTH_DONE)
    {
        HAL_TRACE_DEBUG2 ("Received RESET NTF after patch download (reset_reason=%i, reset_type=%i)", reset_reason, reset_type);

        /* Stop waiting for RESET NTF */
        nfc_hal_main_stop_quick_timer (&nfc_hal_cb.prm.timer);

        {
            /* Continue with patch download */
            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 ("Received RESET NTF after pre-I2C patch download. Proceeding with patch download...");

        /* Stop waiting for RESET NTF */
        nfc_hal_main_stop_quick_timer (&nfc_hal_cb.prm.timer);
        nfc_hal_prm_spd_handle_next_patch_start ();
    }
    else
    {
        HAL_TRACE_ERROR2 ("Received unexpected RESET NTF (reset_reason=%i, reset_type=%i)", reset_reason, reset_type);
    }
}
/*******************************************************************************
**
** 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_shutting_down_nfcc
**
** Description      This function initializes Broadcom specific control blocks for
**                  NCI transport
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_dm_shutting_down_nfcc (void)
{
    HAL_TRACE_DEBUG0 ("nfc_hal_dm_shutting_down_nfcc ()");

    nfc_hal_cb.dev_cb.initializing_state = NFC_HAL_INIT_STATE_CLOSING;

    /* reset low power mode variables */
    if (  (nfc_hal_cb.dev_cb.power_mode  == NFC_HAL_POWER_MODE_FULL)
        &&(nfc_hal_cb.dev_cb.snooze_mode != NFC_HAL_LP_SNOOZE_MODE_NONE)  )
    {
        nfc_hal_dm_set_nfc_wake (NFC_HAL_ASSERT_NFC_WAKE);
    }

    nfc_hal_cb.ncit_cb.nci_wait_rsp = NFC_HAL_WAIT_RSP_NONE;

    nfc_hal_cb.dev_cb.power_mode  = NFC_HAL_POWER_MODE_FULL;
    nfc_hal_cb.dev_cb.snooze_mode = NFC_HAL_LP_SNOOZE_MODE_NONE;

    /* Stop all timers */
    nfc_hal_main_stop_quick_timer (&nfc_hal_cb.ncit_cb.nci_wait_rsp_timer);
    nfc_hal_main_stop_quick_timer (&nfc_hal_cb.dev_cb.lp_timer);
    nfc_hal_main_stop_quick_timer (&nfc_hal_cb.prm.timer);
#if (defined(NFC_HAL_HCI_INCLUDED) && (NFC_HAL_HCI_INCLUDED == TRUE))
    nfc_hal_cb.hci_cb.hcp_conn_id = 0;
    nfc_hal_main_stop_quick_timer (&nfc_hal_cb.hci_cb.hci_timer);
#endif
    nfc_hal_main_stop_quick_timer (&nfc_hal_cb.timer);
}
/*******************************************************************************
**
** 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_dm_init
**
** Description      This function initializes Broadcom specific control blocks for
**                  NCI transport
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_dm_init (void)
{
    HAL_TRACE_DEBUG0 ("nfc_hal_dm_init ()");

    nfc_hal_cb.dev_cb.lp_timer.p_cback = nci_brcm_lp_timeout_cback;

    nfc_hal_cb.ncit_cb.nci_wait_rsp_timer.p_cback = nfc_hal_nci_cmd_timeout_cback;

    nfc_hal_cb.hci_cb.hci_timer.p_cback = nfc_hal_hci_timeout_cback;

    nfc_hal_cb.pre_discover_done        = FALSE;

    nfc_post_reset_cb.spd_nvm_detection_cur_count = 0;
    nfc_post_reset_cb.spd_skip_on_power_cycle     = FALSE;

}
/*******************************************************************************
**
** Function         nfc_hal_dm_init
**
** Description      This function initializes Broadcom specific control blocks for
**                  NCI transport
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_dm_init (void)
{
    HAL_TRACE_DEBUG0 ("nfc_hal_dm_init ()");

    nfc_hal_cb.dev_cb.lp_timer.p_cback = nci_brcm_lp_timeout_cback;

    nfc_hal_cb.ncit_cb.nci_wait_rsp_timer.p_cback = nfc_hal_nci_cmd_timeout_cback;

#if (defined(NFC_HAL_HCI_INCLUDED) && (NFC_HAL_HCI_INCLUDED == TRUE))
    nfc_hal_cb.hci_cb.hci_timer.p_cback = nfc_hal_hci_timeout_cback;
#endif

    nfc_hal_cb.pre_discover_done        = FALSE;

    nfc_post_reset_cb.spd_nvm_detection_cur_count = 0;
    nfc_post_reset_cb.spd_skip_on_power_cycle     = FALSE;

}
/*******************************************************************************
**
** Function         nfc_hal_dm_pre_init_nfcc
**
** Description      This function initializes Broadcom specific control blocks for
**                  NCI transport
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_dm_pre_init_nfcc (void)
{
    HAL_TRACE_DEBUG0 ("nfc_hal_dm_pre_init_nfcc ()");

    /* if it was waiting for core reset notification after raising REG_PU */
    if (nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_W4_NFCC_ENABLE)
    {
        nfc_hal_dm_send_get_build_info_cmd ();
    }
    /* if it was waiting for core reset notification after setting Xtal */
    else if (nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_POST_XTAL_SET)
    {
        {
            /* Core reset ntf after xtal setting indicating NFCC loaded patch from NVM */
            NFC_HAL_SET_INIT_STATE (NFC_HAL_INIT_STATE_W4_PATCH_INFO);

            nfc_hal_dm_send_nci_cmd (nfc_hal_dm_get_patch_version_cmd, NCI_MSG_HDR_SIZE, NULL);
        }
    }
}
/*******************************************************************************
**
** Function         nfc_hal_prm_nfcc_ready_to_continue
**
** Description      Continue to download patch or notify application completition
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_prm_nfcc_ready_to_continue (void)
{
    UINT8 get_patch_version_cmd [NCI_MSG_HDR_SIZE] =
    {
        NCI_MTS_CMD|NCI_GID_PROP,
        NCI_MSG_GET_PATCH_VERSION,
        0x00
    };

    /* Clear the bit for the patch we just downloaded */
    nfc_hal_cb.prm.spd_patch_needed_mask &= ~ ((UINT32) 1 << nfc_hal_cb.prm.spd_patch_desc[nfc_hal_cb.prm.spd_cur_patch_idx].power_mode);

    /* Check if another patch to download */
    nfc_hal_cb.prm.spd_cur_patch_idx++;
    if ((nfc_hal_cb.prm.spd_patch_needed_mask) && (nfc_hal_cb.prm.spd_cur_patch_idx < nfc_hal_cb.prm.spd_patch_count))
    {
        nfc_hal_cb.prm.state = NFC_HAL_PRM_ST_SPD_GET_PATCH_HEADER;
        nfc_hal_cb.prm.flags &= ~NFC_HAL_PRM_FLAGS_SIGNATURE_SENT;

        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_handle_next_patch_start ();
        }
        else
        {
            /* Notify adaptation layer to get next patch header (via HAL_NfcPrmDownloadContinue) */
            (nfc_hal_cb.prm.p_cback) (NFC_HAL_PRM_SPD_GET_NEXT_PATCH);
        }

    }
    else
    {
        /* Done downloading */
        HAL_TRACE_DEBUG0 ("Patch downloaded and authenticated. Get new patch version.");
        /* add get patch info again to verify the effective FW version */
        nfc_hal_dm_send_nci_cmd (get_patch_version_cmd, NCI_MSG_HDR_SIZE, nfc_hal_prm_nci_command_complete_cback);
        nfc_hal_cb.prm.state = NFC_HAL_PRM_ST_W4_GET_VERSION;
    }
}
/*******************************************************************************
**
** Function         nfc_hal_main_timeout_cback
**
** Description      callback function for timeout
**
** Returns          void
**
*******************************************************************************/
static void nfc_hal_main_timeout_cback (void *p_tle)
{
    TIMER_LIST_ENT  *p_tlent = (TIMER_LIST_ENT *) p_tle;

    HAL_TRACE_DEBUG0 ("nfc_hal_main_timeout_cback ()");

    switch (p_tlent->event)
    {
    case NFC_HAL_TTYPE_POWER_CYCLE:
        nfc_hal_main_open_transport ();
        break;

    case NFC_HAL_TTYPE_NFCC_ENABLE:
        /* NFCC should have enabled now, notify transport openned */
        nfc_hal_dm_pre_init_nfcc ();
        break;

    default:
        HAL_TRACE_DEBUG1 ("nfc_hal_main_timeout_cback: unhandled timer event (0x%04x)", p_tlent->event);
        break;
    }
}
/*******************************************************************************
**
** 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_task
**
** Description      NFC HAL NCI transport event processing task
**
** Returns          0
**
*******************************************************************************/
UINT32 nfc_hal_main_task (UINT32 param)
{
    UINT16   event;
    UINT8    byte;
    UINT8    num_interfaces;
    UINT8    *p;
    NFC_HDR  *p_msg;
    BOOLEAN  free_msg;

    HAL_TRACE_DEBUG0 ("NFC_HAL_TASK started");

    /* Main loop */
    while (TRUE)
    {
        event = GKI_wait (0xFFFF, 0);

        /* Handle NFC_HAL_TASK_EVT_INITIALIZE (for initializing NCI transport) */
        if (event & NFC_HAL_TASK_EVT_INITIALIZE)
        {
            HAL_TRACE_DEBUG0 ("NFC_HAL_TASK got NFC_HAL_TASK_EVT_INITIALIZE signal. Opening NFC transport...");

            nfc_hal_main_open_transport ();
        }

        /* Check for terminate event */
        if (event & NFC_HAL_TASK_EVT_TERMINATE)
        {
            HAL_TRACE_DEBUG0 ("NFC_HAL_TASK got NFC_HAL_TASK_EVT_TERMINATE");
            nfc_hal_main_handle_terminate ();

            /* Close uart */
            USERIAL_Close (USERIAL_NFC_PORT);

            if (nfc_hal_cb.p_stack_cback)
            {
                nfc_hal_cb.p_stack_cback (HAL_NFC_CLOSE_CPLT_EVT, HAL_NFC_STATUS_OK);
                nfc_hal_cb.p_stack_cback = NULL;
            }
            continue;
        }

        /* Check for power cycle event */
        if (event & NFC_HAL_TASK_EVT_POWER_CYCLE)
        {
            HAL_TRACE_DEBUG0 ("NFC_HAL_TASK got NFC_HAL_TASK_EVT_POWER_CYCLE");
            nfc_hal_main_handle_terminate ();

            /* Close uart */
            USERIAL_Close (USERIAL_NFC_PORT);

            /* power cycle timeout */
            nfc_hal_main_start_quick_timer (&nfc_hal_cb.timer, NFC_HAL_TTYPE_POWER_CYCLE,
                                            (NFC_HAL_POWER_CYCLE_DELAY*QUICK_TIMER_TICKS_PER_SEC)/1000);
            continue;
        }

        /* NCI message ready to be sent to NFCC */
        if (event & NFC_HAL_TASK_EVT_MBOX)
        {
            while ((p_msg = (NFC_HDR *) GKI_read_mbox (NFC_HAL_TASK_MBOX)) != NULL)
            {
                free_msg = TRUE;
                switch (p_msg->event & NFC_EVT_MASK)
                {
                case NFC_HAL_EVT_TO_NFC_NCI:
                    nfc_hal_main_send_message (p_msg);
                    /* do not free buffer. NCI VS code may keep it for processing later */
                    free_msg = FALSE;
                    break;

                case NFC_HAL_EVT_POST_CORE_RESET:
                    NFC_HAL_SET_INIT_STATE (NFC_HAL_INIT_STATE_W4_POST_INIT_DONE);

                    /* set NCI Control packet size from CORE_INIT_RSP */
                    p = (UINT8 *) (p_msg + 1) + p_msg->offset + NCI_MSG_HDR_SIZE;
                    p += 5;
                    STREAM_TO_UINT8 (num_interfaces, p);
                    p += (num_interfaces + 3);
                    nfc_hal_cb.ncit_cb.nci_ctrl_size = *p;

                    /* start post initialization */
                    nfc_hal_cb.dev_cb.next_dm_config = NFC_HAL_DM_CONFIG_LPTD;
                    nfc_hal_cb.dev_cb.next_startup_vsc = 1;

                    nfc_hal_dm_config_nfcc ();
                    break;

                case NFC_HAL_EVT_TO_START_QUICK_TIMER:
                    GKI_start_timer (NFC_HAL_QUICK_TIMER_ID, ((GKI_SECS_TO_TICKS (1) / QUICK_TIMER_TICKS_PER_SEC)), TRUE);
                    break;

                case NFC_HAL_EVT_HCI:
                    nfc_hal_hci_evt_hdlr ((tNFC_HAL_HCI_EVENT_DATA *) p_msg);
                    break;

                case NFC_HAL_EVT_PRE_DISCOVER:
                    NFC_HAL_SET_INIT_STATE(NFC_HAL_INIT_STATE_W4_PREDISCOVER_DONE);
                    nfa_hal_send_pre_discover_cfg ();
                    break;

                case NFC_HAL_EVT_CONTROL_GRANTED:
                    nfc_hal_dm_send_pend_cmd ();
                    break;

                default:
                    break;
                }

                if (free_msg)
                    GKI_freebuf (p_msg);
            }
        }

        /* Data waiting to be read from serial port */
        if (event & NFC_HAL_TASK_EVT_DATA_RDY)
        {
            while (TRUE)
            {
                /* Read one byte to see if there is anything waiting to be read */
                if (USERIAL_Read (USERIAL_NFC_PORT, &byte, 1) == 0)
                {
                    break;
                }

                if (nfc_hal_nci_receive_msg (byte))
                {
                    /* complete of receiving NCI message */
                    nfc_hal_nci_assemble_nci_msg ();
                    if (nfc_hal_cb.ncit_cb.p_rcv_msg)
                    {
                        if (nfc_hal_nci_preproc_rx_nci_msg (nfc_hal_cb.ncit_cb.p_rcv_msg))
                        {
                            /* Send NCI message to the stack */
                            nfc_hal_send_nci_msg_to_nfc_task (nfc_hal_cb.ncit_cb.p_rcv_msg);
                        }
                        else
                        {
                            if (nfc_hal_cb.ncit_cb.p_rcv_msg)
                                GKI_freebuf(nfc_hal_cb.ncit_cb.p_rcv_msg);
                        }
                        nfc_hal_cb.ncit_cb.p_rcv_msg = NULL;
                    }
                }
            } /* while (TRUE) */
        }

        /* Process quick timer tick */
        if (event & NFC_HAL_QUICK_TIMER_EVT_MASK)
        {
            nfc_hal_main_process_quick_timer_evt ();
        }
    }

    HAL_TRACE_DEBUG0 ("nfc_hal_main_task terminated");

    GKI_exit_task (GKI_get_taskid ());
    return 0;
}
/*******************************************************************************
**
** 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_proc_msg_during_init
**
** Description      Process NCI message while initializing NFCC
**
** Returns          void
**
*******************************************************************************/
void nfc_hal_dm_proc_msg_during_init (NFC_HDR *p_msg)
{
    UINT8 *p;
    UINT8 reset_reason, reset_type;
    UINT8 mt, pbf, gid, op_code;
    UINT8 *p_old, old_gid, old_oid, old_mt;
    UINT8 u8;
    tNFC_HAL_NCI_CBACK *p_cback = NULL;
    UINT8   chipverlen;
    UINT8   chipverstr[NCI_SPD_HEADER_CHIPVER_LEN];
    UINT32  hw_id = 0;

    HAL_TRACE_DEBUG1 ("nfc_hal_dm_proc_msg_during_init(): init state:%d", nfc_hal_cb.dev_cb.initializing_state);

    p = (UINT8 *) (p_msg + 1) + p_msg->offset;

    NCI_MSG_PRS_HDR0 (p, mt, pbf, gid);
    NCI_MSG_PRS_HDR1 (p, op_code);

    /* check if waiting for this response */
    if (  (nfc_hal_cb.ncit_cb.nci_wait_rsp == NFC_HAL_WAIT_RSP_CMD)
        ||(nfc_hal_cb.ncit_cb.nci_wait_rsp == NFC_HAL_WAIT_RSP_VSC)  )
    {
        if (mt == NCI_MT_RSP)
        {
            p_old = nfc_hal_cb.ncit_cb.last_hdr;
            NCI_MSG_PRS_HDR0 (p_old, old_mt, pbf, old_gid);
            old_oid = ((*p_old) & NCI_OID_MASK);
            /* make sure this is the RSP we are waiting for before updating the command window */
            if ((old_gid == gid) && (old_oid == op_code))
            {
                nfc_hal_cb.ncit_cb.nci_wait_rsp = NFC_HAL_WAIT_RSP_NONE;
                p_cback = (tNFC_HAL_NCI_CBACK *)nfc_hal_cb.ncit_cb.p_vsc_cback;
                nfc_hal_cb.ncit_cb.p_vsc_cback  = NULL;
                nfc_hal_main_stop_quick_timer (&nfc_hal_cb.ncit_cb.nci_wait_rsp_timer);
            }
        }
    }

    if (gid == NCI_GID_CORE)
    {
        if (op_code == NCI_MSG_CORE_RESET)
        {
            if (mt == NCI_MT_NTF)
            {
                if (  (nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_W4_NFCC_ENABLE)
                    ||(nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_POST_XTAL_SET)  )
                {
                    /*
                    ** Core reset ntf in the following cases;
                    ** 1) after power up (raising REG_PU)
                    ** 2) after setting xtal index
                    ** Start pre-initializing NFCC
                    */
                    nfc_hal_main_stop_quick_timer (&nfc_hal_cb.timer);
                    nfc_hal_dm_pre_init_nfcc ();
                }
                else
                {
                    /* Core reset ntf after post-patch download, Call reset notification callback */
                    p++;                                /* Skip over param len */
                    STREAM_TO_UINT8 (reset_reason, p);
                    STREAM_TO_UINT8 (reset_type, p);
                    nfc_hal_prm_spd_reset_ntf (reset_reason, reset_type);
                }
            }
        }
        else if (p_cback)
        {
            (*p_cback) ((tNFC_HAL_NCI_EVT) (op_code),
                        p_msg->len,
                        (UINT8 *) (p_msg + 1) + p_msg->offset);
        }
    }
    else if (gid == NCI_GID_PROP) /* this is for download patch */
    {
        if (mt == NCI_MT_NTF)
            op_code |= NCI_NTF_BIT;
        else
            op_code |= NCI_RSP_BIT;

        if (nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_W4_XTAL_SET)
        {
            if (op_code == (NCI_RSP_BIT|NCI_MSG_GET_XTAL_INDEX_FROM_DH))
            {
                /* start timer in case that NFCC doesn't send RESET NTF after loading patch from NVM */
                NFC_HAL_SET_INIT_STATE (NFC_HAL_INIT_STATE_POST_XTAL_SET);

                nfc_hal_main_start_quick_timer (&nfc_hal_cb.timer, NFC_HAL_TTYPE_NFCC_ENABLE,
                                                ((p_nfc_hal_cfg->nfc_hal_post_xtal_timeout)*QUICK_TIMER_TICKS_PER_SEC)/1000);
            }
        }
        else if (  (op_code == NFC_VS_GET_BUILD_INFO_EVT)
                 &&(nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_W4_BUILD_INFO)  )
        {
            p += NCI_BUILD_INFO_OFFSET_HWID;

            STREAM_TO_UINT32 (hw_id, p);
            nfc_hal_cb.dev_cb.brcm_hw_id = nfc_hal_dm_adjust_hw_id (hw_id);
            HAL_TRACE_DEBUG2 ("brcm_hw_id: 0x%x -> 0x%x", hw_id, nfc_hal_cb.dev_cb.brcm_hw_id);

            STREAM_TO_UINT8 (chipverlen, p);
            memset (chipverstr, 0, NCI_SPD_HEADER_CHIPVER_LEN);

            STREAM_TO_ARRAY (chipverstr, p, chipverlen);

            nfc_hal_hci_handle_build_info (chipverlen, chipverstr);
            nfc_hal_cb.pre_set_mem_idx = 0;
            if (!nfc_hal_dm_check_pre_set_mem())
            {
                /* pre-set mem started */
                return;
            }
            nfc_hal_dm_check_xtal();
        }
        else if (  (op_code == NFC_VS_GET_PATCH_VERSION_EVT)
                 &&(nfc_hal_cb.dev_cb.initializing_state == NFC_HAL_INIT_STATE_W4_PATCH_INFO)  )
        {
            /* Store NVM info to control block */

            /* Skip over rsp len */
            p++;

            /* Get project id */
            STREAM_TO_UINT16 (nfc_hal_cb.nvm_cb.project_id, p);

            /* RFU */
            p++;

            /* Get chip version string */
            STREAM_TO_UINT8 (u8, p);
            if (u8 > NFC_HAL_PRM_MAX_CHIP_VER_LEN)
                u8 = NFC_HAL_PRM_MAX_CHIP_VER_LEN;
            memcpy (nfc_hal_cb.nvm_cb.chip_ver, p, u8);
            p += NCI_PATCH_INFO_VERSION_LEN;

            /* Get major/minor version */
            STREAM_TO_UINT16 (nfc_hal_cb.nvm_cb.ver_major, p);
            STREAM_TO_UINT16 (nfc_hal_cb.nvm_cb.ver_minor, p);

            /* Skip over max_size and patch_max_size */
            p += 4;

            /* Get current lpm patch size */
            STREAM_TO_UINT16 (nfc_hal_cb.nvm_cb.lpm_size, p);
            STREAM_TO_UINT16 (nfc_hal_cb.nvm_cb.fpm_size, p);

            /* clear all flags which may be set during previous initialization */
            nfc_hal_cb.nvm_cb.flags = 0;

            /* Set patch present flag */
            if ((nfc_hal_cb.nvm_cb.fpm_size) || (nfc_hal_cb.nvm_cb.lpm_size))
                nfc_hal_cb.nvm_cb.flags |= NFC_HAL_NVM_FLAGS_PATCH_PRESENT;

            /* LPMPatchCodeHasBadCRC (if not bad crc, then indicate LPM patch is present in nvm) */
            STREAM_TO_UINT8 (u8, p);
            if (u8)
            {
                /* LPM patch in NVM fails CRC check */
                nfc_hal_cb.nvm_cb.flags |= NFC_HAL_NVM_FLAGS_LPM_BAD;
            }


            /* FPMPatchCodeHasBadCRC (if not bad crc, then indicate LPM patch is present in nvm) */
            STREAM_TO_UINT8 (u8, p);
            if (u8)
            {
                /* FPM patch in NVM fails CRC check */
                nfc_hal_cb.nvm_cb.flags |= NFC_HAL_NVM_FLAGS_FPM_BAD;
            }

            /* Check if downloading patch to RAM only (no NVM) */
            STREAM_TO_UINT8 (nfc_hal_cb.nvm_cb.nvm_type, p);
            if (nfc_hal_cb.nvm_cb.nvm_type == NCI_SPD_NVM_TYPE_NONE)
            {
                nfc_hal_cb.nvm_cb.flags |= NFC_HAL_NVM_FLAGS_NO_NVM;
            }

            /* let platform update baudrate or download patch */
            NFC_HAL_SET_INIT_STATE (NFC_HAL_INIT_STATE_W4_APP_COMPLETE);
            nfc_hal_post_reset_init (nfc_hal_cb.dev_cb.brcm_hw_id, nfc_hal_cb.nvm_cb.nvm_type);
        }
        else if (p_cback)
        {
            (*p_cback) ((tNFC_HAL_NCI_EVT) (op_code),
                        p_msg->len,
                        (UINT8 *) (p_msg + 1) + p_msg->offset);
        }
        else if (op_code == NFC_VS_SEC_PATCH_AUTH_EVT)
        {
            HAL_TRACE_DEBUG0 ("signature!!");
            nfc_hal_prm_nci_command_complete_cback ((tNFC_HAL_NCI_EVT) (op_code),
                                                    p_msg->len,
                                                    (UINT8 *) (p_msg + 1) + p_msg->offset);
        }
    }
}
/*******************************************************************************
**
** Function         nci_brcm_lp_timeout_cback
**
** Description      callback function for low power timeout
**
** Returns          void
**
*******************************************************************************/
static void nci_brcm_lp_timeout_cback (void *p_tle)
{
    HAL_TRACE_DEBUG0 ("nci_brcm_lp_timeout_cback ()");

    nfc_hal_dm_power_mode_execute (NFC_HAL_LP_TIMEOUT_EVT);
}