/**
 * @brief Junks consecutive logical sectors.
 *
 * @param[in]      FPDConfig_p   Flash device configuration of BDM
 * @param[in]      Position      Logical sector number.
 * @param[in]      NrOfSectors   Number of sectors to junk.
 * @param[in, out] FirstBad_p    Not used for eMMC.
 * @return         E_SUCCESS     Logical sectors was successfully junked.
 *
 * @return ErrorCode_e Forwards the response from CABS module.
 */
ErrorCode_e Do_BDM_EMMC_Junk(FPD_Config_t *const FPDConfig_p, uint32 Position, uint32 NrOfSectors, uint32 *FirstBad_p)
{
    ErrorCode_e ReturnValue = E_GENERAL_FATAL_ERROR;
    t_mmc_error MMC_Error;

    IDENTIFIER_NOT_USED(FirstBad_p);

    // Jedec 84-A44 : Size < 2GB => byte addressing
    if (!FPDConfig_p->HC_Card) {
        Position *= MMC_ADDRESS_MODE_FACTOR;
    }

    MMC_Error = MMC_Erase(1, Position, Position + NrOfSectors, FPDConfig_p->DeviceId);
    VERIFY(MMC_OK == MMC_Error, E_BDM_JUNK_FAILED);

    ReturnValue = E_SUCCESS;
ErrorExit:
    return ReturnValue;
}
/***************************************************************************//**
* @brief Reads bits from OTP memory.
*
* Reads all requested Length bits from OTP.
*
* @param[in]      Session   Command session.
* @param[in]      OTP_id    NOT used.
* @param[in]      Start     NOT used.
* @param[in]      Length    Number of bits to read.
*
* @return         E_INVALID_INPUT_PARAMETERS if input parameters are invalid.
*                 E_ALLOCATE_FAILED if memory allocation failed.
*                 E_READING_OTP_FAILED if reading from OTP failed.
*                 E_SUCCESS if reading was successful.
*
*******************************************************************************/
ErrorCode_e Do_OTP_ReadBitsImpl(uint16 Session, const uint32 OTP_id,
                                const uint32 Start, const uint32 Length)
{
    ErrorCode_e ReturnValue = E_GENERAL_FATAL_ERROR;
    CommandData_t CmmData   = {0};
    void *Data_p            = NULL;
    IDENTIFIER_NOT_USED(OTP_id);

    CmmData.CommandNr = COMMAND_OTP_READBITS;
    CmmData.ApplicationNr = GROUP_OTP;
    CmmData.SessionNr = Session;
    CmmData.Type = COMMAND_TYPE;

    VERIFY((Start & START_BIT_MASK) == Start, E_INVALID_INPUT_PARAMETERS);

    CmmData.Payload.Size = sizeof(uint32) + sizeof(uint32);
    CmmData.Payload.Data_p = (uint8 *)malloc(CmmData.Payload.Size);
    ASSERT(NULL != CmmData.Payload.Data_p);

    Data_p = CmmData.Payload.Data_p;
    put_uint32_le((void **)&Data_p, Start);
    put_uint32_le((void **)&Data_p, Length);

    C_(printf("otp_applications_functions.c (%d): Do_OTP_ReadBitsImpl: OTP_AREA_SIZE = %d \n", __LINE__, OTP_AREA_SIZE);)
/**
 * @brief Reads data from EMMC block device manager
 *
 * @param[in]     FPDConfig_p Flash device configuration of BDM
 * @param[in]     Pos         EMMC sector where reading should start.
 * @param[in]     Length      Number of sectors to read.
 * @param[in,out] FirstBad_p  Not used for eMMC.
 * @param[out]    Data_p      Output buffer.
 *
 * @return ErrorCode_e Forwards the response from EMMC module.
 *
 * @remark This function should be called only from BDM module.
 */
ErrorCode_e Do_BDM_EMMC_Read(FPD_Config_t *const FPDConfig_p, uint32 Pos, uint32 Length, uint32 *FirstBad_p, uint8 *Data_p)
{
    ErrorCode_e     ReturnValue = E_GENERAL_FATAL_ERROR;
    t_mmc_error     MMC_Error;
    void *TmpData_p = Data_p;

    IDENTIFIER_NOT_USED(FirstBad_p);

    // MMC interface requires uint32* for data, Data_p must be 32-bit aligned
    IS_ALIGNED((uint32)Data_p);

    // Jedec 84-A44 : Size < 2GB => byte addressing
    if (!FPDConfig_p->HC_Card) {
        Pos *= MMC_ADDRESS_MODE_FACTOR;
    }

    // Typecast on Data_p OK, alignment checked above
    MMC_Error = MMC_ReadBlocks(1, Pos, (uint32 *)TmpData_p, FPDConfig_p->PageSize, Length, FPDConfig_p->DeviceId);
    VERIFY(MMC_OK == MMC_Error, E_BDM_READ_FAILED);

    ReturnValue = E_SUCCESS;
ErrorExit:
    return ReturnValue;
}
void sigchld_handler(int sig) {
  IDENTIFIER_NOT_USED(sig);
  while(waitpid(-1, NULL, WNOHANG) > 0);
}
/*----------------------------------------------------------------------------
 * PEC_SA_Register
 *
 * SA_Handle1 = SA
 * SA_Handle2 = State (optional)
 * SA_Handle3 = ARC4 State (optional)
 */
PEC_Status_t
PEC_SA_Register(
        DMABuf_Handle_t SA_Handle1,
        DMABuf_Handle_t SA_Handle2,
        DMABuf_Handle_t SA_Handle3)
{
    IDENTIFIER_NOT_USED(&SA_Handle1 > &SA_Handle2);
    IDENTIFIER_NOT_USED(&SA_Handle2 > &SA_Handle3);

    LOG_INFO(
        "PEC_SA_Register: "
        "SA_Handle1,2,3 = %p, %p, %p\n",
        SA_Handle1.p,
        SA_Handle2.p,
        SA_Handle3.p);

    // reset the previous handles
    Adapter_DHM_Work.SA_Handle = Adapter_DMABuf_NullHandle;
    Adapter_DHM_Work.SA_State_Handle = Adapter_DMABuf_NullHandle;
    Adapter_DHM_Work.SA_ARC4State_Handle = Adapter_DMABuf_NullHandle;

    if (!Adapter_DMABuf_IsValidHandle(SA_Handle1))
        return PEC_ERROR_BAD_HANDLE;

    // accepted as the SA Handle
    Adapter_DHM_Work.SA_Handle = SA_Handle1;

    if (Adapter_DMABuf_IsValidHandle(SA_Handle2))
    {
        // make sure it is not identical to SA_Handle1
        if (Adapter_DMABuf_IsSameHandle(&SA_Handle1, &SA_Handle2))
            return PEC_ERROR_BAD_HANDLE;

        // State record is of variable size, but depends on the SA format
        // SA_Rev1: 10 words = 40 bytes
        // SA_Rev2: 22 words = 88 bytes
        // DynSA: 4, 18 or 22 bytes = 16, 72 or 88 bytes
        // verify the buffer is large enough
        // by checking it here, we can assume the fixed size in Packet_Put
        {
            HWPAL_DMAResource_Handle_t DMAHandle;
            HWPAL_DMAResource_Record_t * DMARec_p;

            DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(SA_Handle2);
            DMARec_p = HWPAL_DMAResource_Handle2RecordPtr(DMAHandle);
            if (DMARec_p == NULL)
            {
                LOG_WARN(
                    "PEC_Register_SA: "
                    "Address look-up for SA_Handle2 failed\n");

                return PEC_ERROR_BAD_HANDLE;
            }

            if (DMARec_p->host.BufferSize < 16)
            {
                LOG_CRIT(
                    "PEC_Register_SA: "
                 "Rejecting SA_Handle2 for State Record because size %d < 16\n",
                    DMARec_p->host.BufferSize);

                return PEC_ERROR_BAD_HANDLE;
            }
        }

        // accepted as the SA State Record buffer
        Adapter_DHM_Work.SA_State_Handle = SA_Handle2;
    }

    if (Adapter_DMABuf_IsValidHandle(SA_Handle3))
    {
        // make sure it is not identical to SA_Handle1 or SA_Handle2
        if (Adapter_DMABuf_IsSameHandle(&SA_Handle1, &SA_Handle3) ||
            Adapter_DMABuf_IsSameHandle(&SA_Handle2, &SA_Handle3))
        {
            return PEC_ERROR_BAD_HANDLE;
        }

        // ARC4 State record is fixed size 256 bytes
        // verify the buffer is large enough
        // by checking it here, we can assume the fixed size in Packet_Put
        {
            HWPAL_DMAResource_Handle_t DMAHandle;
            HWPAL_DMAResource_Record_t * DMARec_p;

            DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(SA_Handle3);
            DMARec_p = HWPAL_DMAResource_Handle2RecordPtr(DMAHandle);
            if (DMARec_p == NULL)
            {
                LOG_WARN(
                    "PEC_Register_SA: "
                    "Address look-up for SA_Handle3 failed\n");

                return PEC_ERROR_BAD_HANDLE;
            }

            if (DMARec_p->host.BufferSize < 256)
            {
                LOG_CRIT(
                    "PEC_Register_SA: "
                 "Rejecting SA_Handle3 for ARC4 State because size %d < 256\n",
                    DMARec_p->host.BufferSize);

                return PEC_ERROR_BAD_HANDLE;
            }
        }

        // accept it as the SA ARC4 State buffer
        Adapter_DHM_Work.SA_ARC4State_Handle = SA_Handle3;
    }

    // this call is not required, so we fake it is OK
    return PEC_STATUS_OK;
}
/*----------------------------------------------------------------------------
 * Adapter_EIP93_SetMode_ARM
 *
 * Return Value
 *     true  Success
 *     false Failed
 */
bool
Adapter_EIP93_SetMode_ARM(
        const bool fEnableDynamicSA)
{
#ifndef ADAPTER_EIP93_PE_MODE_ARM
    IDENTIFIER_NOT_USED(fEnableDynamicSA);
    return false;
#else
    EIP93_ARM_Settings_t Settings = {0};
    EIP93_ARM_RingMemory_t RingMemory = {0};
    EIP93_Status_t res93;

    if (Adapter_EIP93_Mode != ADAPTER_EIP93_MODE_IDLE)
    {
        LOG_CRIT("Adapter_EIP93_SetMode_ARM: Not possible in mode %d\n",
            Adapter_EIP93_Mode);
        return false;
    }

/**** allocate memory for the ring ****/

    ZEROINIT(RingMemory);
    // bytes to words conversion from ADAPTER_EIP93_RINGSIZE_BYTES
    RingMemory.RingSizeInWords = Adapter_EIP93_RingProps.Size >> 2;

    {
        DMABuf_Status_t dmares;
        DMABuf_HostAddress_t HostAddr;

        dmares = DMABuf_Alloc(
                        Adapter_EIP93_RingProps,
                        &HostAddr,
                        &Adapter_EIP93_CmdRing_Handle);

        if (dmares != DMABUF_STATUS_OK)
        {
            LOG_CRIT(
                "Adapter_EIP93_Init: "
                "DMABuf_Alloc (Command Ring) returned %d\n",
                dmares);

            return false;
        }

        LOG_INFO(
            "Adapter_EIP93_Init: "
            "CmdRing_Handle=%p\n",
            Adapter_EIP93_CmdRing_Handle.p);

        Adapter_GetEIP93PhysAddr(
                Adapter_EIP93_CmdRing_Handle,
                &RingMemory.CommandRingHandle,
                &RingMemory.CommandRingAddr);

        if (RingMemory.CommandRingAddr.Addr == 0)
        {
            LOG_CRIT(
                "Adapter_EIP93_Init: "
                "Failed to get command ring physical address\n");

            // free the command ring memory
            DMABuf_Release(Adapter_EIP93_CmdRing_Handle);

            return false;       // ## RETURN ##
        }
    }

#ifndef ADAPTER_EIP93_SEPARATE_RINGS
    // not separate rings
    RingMemory.fSeparateRings = false;
#else
    // separat rings
    RingMemory.fSeparateRings = true;

    {
        DMABuf_Status_t dmares;
        DMABuf_HostAddress_t HostAddr;

        dmares = DMABuf_Alloc(
                        Adapter_EIP93_RingProps,
                        &HostAddr,
                        &Adapter_EIP93_ResRing_Handle);

        if (dmares != DMABUF_STATUS_OK)
        {
            LOG_CRIT(
                    "Adapter_EIP93_Init: "
                    "DMABuf_Alloc (Result Ring) returned %d\n",
                    dmares);

            // free the command ring memory
            DMABuf_Release(Adapter_EIP93_CmdRing_Handle);

            return false;
        }

        LOG_INFO(
            "Adapter_EIP93_Init: "
            "ResRing_Handle=%p\n",
            Adapter_EIP93_ResRing_Handle.p);

        Adapter_GetEIP93PhysAddr(
                Adapter_EIP93_ResRing_Handle,
                &RingMemory.ResultRingHandle,
                &RingMemory.ResultRingAddr);
 
        if (RingMemory.ResultRingAddr.Addr == 0)
        {
            LOG_CRIT(
                "Adapter_EIP93_Init: "
                "Failed to get result ring physical address\n");

            // free the ring memories
            DMABuf_Release(Adapter_EIP93_CmdRing_Handle);
            DMABuf_Release(Adapter_EIP93_ResRing_Handle);

            return false;
        }
    }
#endif /* ADAPTER_EIP93_SEPARATE_RINGS */

    // create the engine settings block
    Settings.nPEInputThreshold = ADAPTER_EIP93_DMATHRESHOLD_INPUT;
    Settings.nPEOutputThreshold = ADAPTER_EIP93_DMATHRESHOLD_OUTPUT;
    Settings.nDescriptorDoneCount = ADAPTER_EIP93_DESCRIPTORDONECOUNT;
    Settings.nDescriptorDoneTimeout = ADAPTER_EIP93_DESCRIPTORDONETIMEOUT;
    Settings.nDescriptorPendingCount= ADAPTER_EIP93_DESCRIPTORPENDINGCOUNT;
    Settings.nDescriptorSize = 8 ;
//    Settings.nRingPollDivisor = ADAPTER_EIP93_RINGPOLLDIVISOR;

    Adapter_EIP93_MaxDescriptorsInRing =
            RingMemory.RingSizeInWords /
            EIP93_ARM_DESCRIPTOR_SIZE();

    res93 = EIP93_ARM_Activate(
                &Adapter_EIP93_IOArea,
                &Settings,
                &RingMemory);

    if (res93 != EIP93_STATUS_OK)
    {
        LOG_CRIT(
            "Adapter_EIP93_Init: "
            "EIP93_ARM_Activate returned %d\n",
            res93);

        // free the ring memory blocks
        DMABuf_Release(Adapter_EIP93_CmdRing_Handle);
#ifdef ADAPTER_EIP93_SEPARATE_RINGS
        DMABuf_Release(Adapter_EIP93_ResRing_Handle);
#endif
        return false;
    }

    Adapter_EIP93_Mode = ADAPTER_EIP93_MODE_ARM;

    LOG_INFO("Adapter: Successfully initialized EIP93v2 in ARM mode\n");

    return true;
#endif /* ADAPTER_EIP93_PE_MODE_ARM */
}