Android Camera序列11(MTK )

Android Camera序列11(MTK )---Flashlight HAL-Kernel


一、HAL层

1.1、HAL层闪光灯调用具体函数执行流程

1.1.1、Hal3AIf::getInstance的实现

打开相机APK时调用的初始化函数

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/aaa_hal_if.cpp

Hal3AIf::getInstance(MINT32 const i4SensorOpenIndex, E_FlowControl_Type eType, MINT32 i4SubsampleCount)
{
    CAM_LOGD("[%s] sensoridx(%d)", __FUNCTION__, i4SensorOpenIndex);
    switch (eType)
    {
    case Hal3AIf::E_FlowControl_Type_SMVR:
        return Hal3AFlowCtrl_SMVR::getInstance(i4SensorOpenIndex, i4SubsampleCount);
    case Hal3AIf::E_FlowControl_Type_NORMAL:
        return Hal3AFlowCtrl::getInstance(i4SensorOpenIndex);
    default:
        return NULL;
    }
}

1.1.2、Hal3AFlowCtrl::getInstance的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp

Hal3AIf*
Hal3AFlowCtrl::
getInstance(MINT32 i4SensorOpenIndex)
{
    IHalSensorList* const pHalSensorList = MAKE_HalSensorList();
    if (!pHalSensorList) return NULL;

    MINT32 i4SensorDev = pHalSensorList->querySensorDevIdx(i4SensorOpenIndex);

    switch (i4SensorDev)
    {
        case SENSOR_DEV_MAIN:
        {
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
        case SENSOR_DEV_SUB:
        {
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_SUB);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
        case SENSOR_DEV_MAIN_2:
        {
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN_2);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
        case SENSOR_DEV_SUB_2:
        {
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_SUB_2);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
        case SENSOR_DEV_MAIN_3:
        {
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN_3);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
    default:
        CAM_LOGE("Unsupport sensor device ID: %d\n", i4SensorDev);
        AEE_ASSERT_3A_HAL("Unsupport sensor device.");
        return MNULL;
    }
}

1.1.3、Hal3AFlowCtrl::init的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp

MRESULT
Hal3AFlowCtrl::
init(MINT32 i4SensorOpenIndex) //can be called only once by RAW or YUV, no user count
{
    MY_LOGD("[%s] +", __FUNCTION__);

    m_fgLogEn = ::property_get_int32("vendor.debug.camera.log", 0);
    if ( m_fgLogEn == 0 ) {
        m_fgLogEn = ::property_get_int32("vendor.debug.camera.log.hal3a", 0);
    }
    m_u4FrmIdFreeze = ::property_get_int32("vendor.debug.3a.freeze", 0);
    m_bRRZDump = 0;
    m_fgDebugLogWEn = DebugUtil::getDebugLevel(DBG_3A);

    IHalSensorList*const pHalSensorList = MAKE_HalSensorList();
    if (!pHalSensorList) return 0;

#if (CAM3_3ATESTLVL <= CAM3_3AUT)
    I3AWrapper::E_TYPE_T eType = I3AWrapper::E_TYPE_DFT;
#else
    MINT32 eSensorType = pHalSensorList->queryType(i4SensorOpenIndex);
    I3AWrapper::E_TYPE_T eType = I3AWrapper::E_TYPE_RAW;
    switch (eSensorType)
    {
    case NSSensorType::eRAW:
        eType = I3AWrapper::E_TYPE_RAW;
        break;
    case NSSensorType::eYUV:
        eType = I3AWrapper::E_TYPE_YUV;
        break;
    default:
        eType = I3AWrapper::E_TYPE_DFT;
        break;
    }
#endif

    m_i4SensorOpenIdx = i4SensorOpenIndex;

    // create 3A wrapper
    if (m_p3AWrap == NULL)
    {
        m_p3AWrap = I3AWrapper::getInstance(eType, i4SensorOpenIndex);
        if (m_p3AWrap)
        {
            MY_LOGD_IF(m_fgLogEn, "[%s] m_p3AWrapper(%p) created OK", __FUNCTION__, m_p3AWrap);
        }
        else
        {
            CAM_LOGE("m_p3AWrapper created fail!");
            AEE_ASSERT_3A_HAL("m_p3AWrapper created fail!");
        }
    }

    // create Vsync event
    //IEventIrq::ConfigParam IrqConfig(i4SensorDev, i4SensorOpenIndex, 5000, IEventIrq::E_Event_Vsync);
    //m_pEventIrq = IEventIrq::createInstance(IrqConfig, "VSIrq");

    m_SttBufQEnable = property_get_int32("vendor.debug.camera.SttBufQ.enable", 0);
    if (m_SttBufQEnable) {
        ISttBufQ::createSingleton(m_i4SensorDev, LOG_TAG);
    }

    // create statistic control
#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
    if (m_p3ASttCtrl == NULL  && eType == I3AWrapper::E_TYPE_RAW)
    {
        m_p3ASttCtrl = Hal3ASttCtrl::createInstance(m_i4SensorDev, i4SensorOpenIndex);
        if (m_p3ASttCtrl)
        {
            MY_LOGD_IF(m_fgLogEn, "[%s] m_p3ASttCtrl(%p) created OK", __FUNCTION__, m_p3ASttCtrl);
        }
        else
        {
            CAM_LOGE("m_p3ASttCtrl created fail!");
            AEE_ASSERT_3A_HAL("m_p3ASttCtrl created fail!");
        }
    }
#endif

    // create AA thread
    if (m_pThread == NULL)
    {
    	/* 闪光灯的相关操作在这个线程中实现 */
        m_pThread = IThread3A::createInstance(this);
        if (m_pThread)
        {
            MY_LOGD_IF(m_fgLogEn, "[%s] m_pThread(%p) created OK", __FUNCTION__, m_pThread);
        }
        else
        {
            CAM_LOGE("m_pThread created fail!");
            AEE_ASSERT_3A_HAL("m_pThread created fail!");
        }
    }

    // ResultPool - Get result pool object
    if(m_pResultPoolObj == NULL)
        m_pResultPoolObj = IResultPool::getInstance(m_i4SensorDev);
    if(m_pResultPoolObj == NULL)
        CAM_LOGE("ResultPool getInstance fail");

    MY_LOGD("[%s] - eType(%d), sensor(%d), sensorIdx(%d)", __FUNCTION__, eType, m_i4SensorDev, i4SensorOpenIndex);
    return S_3A_OK;
}

1.1.4、IThread3A::createInstance的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

IThread3A*
IThread3A::createInstance(Hal3AIf* pHal3A)
{
    return Thread3AImp::createInstance(pHal3A);
}

1.1.5、Thread3AImp::createInstance的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

IThread3A*
Thread3AImp::
createInstance(Hal3AIf* pHal3A)
{
    //static Thread3AImp singleton(pHal3A);
    //singleton.createThread();   // user count protected
    //return &singleton;
    Thread3AImp* pThd3A = new Thread3AImp(pHal3A);
    //if (pThd3A)
        //pThd3A->createThread();
    return pThd3A;
}

1.1.6、Thread3AImp::Thread3AImp的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

Thread3AImp::
Thread3AImp(Hal3AIf* pHal3A)
    : mpHal3A(pHal3A)
    , mu4LogEn(MFALSE)
    , mbListenUpdate(MFALSE)
    , mbSetFromP1(MFALSE)
    , mLock()
{
    MY_LOGD("[%s] Enter (%d)", __FUNCTION__, pHal3A->getSensorDev());
    createThread();
}

1.1.7、Thread3AImp::createThread的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

MVOID
Thread3AImp::createThread()
{
    //Mutex::Autolock lock(mLock);  // Nelson : mutual exclusive by atomic_flag

    GET_PROP("vendor.debug.3a.log", 0, mu4LogEn);
    mu4DebugLogWEn = DebugUtil::getDebugLevel(DBG_3A);

    if (!thread_alive.test_and_set())
    {
        MY_LOGD("[%s] +", __FUNCTION__);
        sem_init(&mSem, 0, 0);
        //pthread_create(&mThread, NULL, onThreadLoop, this);
        create3Athread = thread(onThreadLoop, this);
        MY_LOGD("[%s] -", __FUNCTION__);
    }
}

在打开相机APK后,会通过 Thread3AImp::createThread() 函数创建并执行了线程 create3Athread ,它最终会调用 Thread3AImp::onThreadLoop() 方法

1.1.8、Thread3AImp::onThreadLoop的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

MVOID*
Thread3AImp::onThreadLoop(MVOID *arg)
{
    MY_LOGD("+");

    CmdQ_T rCmd(ECmd_Update, ParamIspProfile_T());
    Thread3AImp *_this = reinterpret_cast<Thread3AImp*>(arg);
//    AaaTimer ccTimer;
    MBOOL bGetCmd;
    MBOOL fgLogEn = (_this->mu4LogEn & EN_LOG_3A_THREAD) ? MTRUE : MFALSE;
    MUINT32 cmdQSize = 0;

    // (1) change thread setting
    _this->changeThreadSetting();

    // (2) thread-in-loop
    while (_this->getCommand(rCmd, bGetCmd, MFALSE)) /* 从 getCommand() 中获取rCmd的值 */
    {
        //MY_LOGD_IF(1, "rCmd(%d)+", rCmd);
        //
        DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 0);
        switch (rCmd.eCmd)
        {
            case ECmd_Update:
                if (!_this->mbListenUpdate)
                {
                    MY_LOGD("[%s] Exit 3A thread", __FUNCTION__);
                    break;
                }
                MY_LOGD_IF(fgLogEn, "rCmd(%d)+", rCmd.eCmd);
                DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 1);

                /* 在这函数里不断通过 post_commnad 发送 ECmd_Update 命令 */
                if (!_this->mpHal3A->doUpdateCmd(&rCmd.rParamIspProfile))//on3aprocfinish
                {
                    char strErr[512] = {'\0'};
                    sprintf(strErr, "ECmd_Update failed #(%d)", rCmd.rParamIspProfile.i4MagicNum);
                    CAM_LOGE("%s", strErr);
                    AEE_ASSERT_3A_HAL(strErr);
                }

                if (!_this->mbSetFromP1) //only check before first set from MW
                {
                    if (rCmd.rParamIspProfile.iValidateOpt != ParamIspProfile_T::EParamValidate_None)
                    {
                        MY_LOGD("[%s] First command from P1",__FUNCTION__);
                        _this->mbSetFromP1 = MTRUE;
                    }
                }
                DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 2);

                _this->mpHal3A->on3AProcSet(_this->mbSetFromP1);//vsync callback

                DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 3);
                {
                    Mutex::Autolock autoLock(_this->mModuleMtx);
                    cmdQSize = _this->mCmdQ.size();
                }
                if (cmdQSize)
                {
                    MY_LOGD_IF(fgLogEn, "[%s] Cmd from P1", __FUNCTION__);
                }
                else
                {
                    if (_this->mbSetFromP1)
                    {
                        _this->mpHal3A->doUpdateCmdDummy();
                        MY_LOGD_IF(fgLogEn, "[%s] Dummy cmd from 3A Thread", __FUNCTION__);
                    }
                }

                MY_LOGD_IF(fgLogEn, "rCmd(%d), magic#(%d)-", rCmd.eCmd, rCmd.rParamIspProfile.i4MagicNum);
            break;

            default:
                AAA_TRACE_HAL(Thread3A_CmdDefault);
                MY_LOGD_IF(fgLogEn, "rCmd(%d)+", rCmd.eCmd);
                //
                DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 4);
                if ( ! _this->mpHal3A->postCommand(rCmd.eCmd, &rCmd.rParamIspProfile))
                {
                    CAM_LOGE("Cmd(%d) failed", rCmd.eCmd);
                    AEE_ASSERT_3A_HAL("onThreadLoop postCommand fail(2).");
                }
                //
                if (rCmd.eCmd != ECmd_PrecaptureStart && rCmd.eCmd != ECmd_PrecaptureEnd)
                {
                    ::sem_post(&_this->mSem);
                }
                MY_LOGD_IF(fgLogEn, "rCmd(%d), magic#(%d)-", rCmd.eCmd, rCmd.rParamIspProfile.i4MagicNum);
                AAA_TRACE_END_HAL;
            break;
        }
        DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", -1);
        //

    }

    MY_LOGD("-");

    return NULL;
}

由 onThreadLoop 这个函数名就可以知道,在这个线程内会不断的进行循环操作,直到退出相机APK。具体的循环操作是在 while (_this->getCommand(rCmd, bGetCmd, MFALSE)) 中实现的。由上述代码可知,当从 _this->getCommand() 中获取的 rCmd.eCmd 等于 ECmd_Update 时,会一直处于拍照前的预览状态,并不断的调用 if (!_this->mpHal3A->doUpdateCmd(&rCmd.rParamIspProfile)) 刷新预览界面,而当发生其他操作,比如开始拍照,则会调用 default 下的 if ( ! _this->mpHal3A->postCommand(rCmd.eCmd, &rCmd.rParamIspProfile)) 将 ECmd_Update 切换成其他的状态。

1.1.9、Thread3AImp::getCommand的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

MBOOL
Thread3AImp::getCommand(IThread3A::CmdQ_T &rCmd, MBOOL &bGetCmd, MBOOL en_timeout)
{
    //returning MFALSE means break onThreadLoop
    MBOOL fgLogEn = (mu4LogEn & EN_LOG_3A_THREAD) ? MTRUE : MFALSE;
    MY_LOGD_IF(fgLogEn, "[%s] +", __FUNCTION__);
    Mutex::Autolock autoLock(mModuleMtx);
    MY_LOGD_IF(fgLogEn, "[%s] mCmdQ.size()=%d, en_timeout(%d)", __FUNCTION__, (MINT32)mCmdQ.size(), en_timeout);

    if (mCmdQ.size() == 0)
    {
        if (en_timeout)
        {
            MY_LOGD_IF(fgLogEn, "[%s] mCmdQCond.waitRelative +", __FUNCTION__);
            mCmdQCond.waitRelative(mModuleMtx, (long long int)27000000);
            MY_LOGD_IF(fgLogEn, "[%s] mCmdQCond.waitRelative -", __FUNCTION__);
        }
        else
        {
            MY_LOGD_IF(fgLogEn, "[%s] mCmdQCond.wait +", __FUNCTION__);
            mCmdQCond.wait(mModuleMtx);
            MY_LOGD_IF(fgLogEn, "[%s] mCmdQCond.wait -", __FUNCTION__);
        }
    }
    if (mCmdQ.size() == 0) //this is only for en_timeout == 1 & timeout case
    {
        MY_LOGD_IF(fgLogEn, "[%s] mCmdQ.size() = %d after mCmdQCond.wait/waitRelative\n", __FUNCTION__, (MINT32)mCmdQ.size());
        bGetCmd = MFALSE; // timeout, no command received
        return MTRUE;
    }
    bGetCmd = MTRUE;
    // two cases: 1. en_timeout == 1, but get command in time
    //                 2. en_timeout == 0, finally get command

    rCmd = *mCmdQ.begin();
    MY_LOGD_IF(fgLogEn, "CmdQ-size(%d), todo(%d, %d)", (MINT32)mCmdQ.size(), rCmd.eCmd, rCmd.rParamIspProfile.i4MagicNum);

    mCmdQ.erase(mCmdQ.begin());

    return rCmd.eCmd != ECmd_Uninit;
}

相机APK所处状态的更新最终是由 *rCmd = mCmdQ.begin(); 获取的,然后通过 return rCmd.eCmd != ECmd_Uninit; 输出返回值。当相机APK退出的时候,rCmd.eCmd 的值为10,此时等于 ECmd_Uninit ,所以 rCmd.eCmd != ECmd_Uninit 为 false,此时跳出 while (_this->getCommand(rCmd, bGetCmd, MFALSE)) 循环。

1.1.10、Hal3AFlowCtrl::doUpdateCmd的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp

MBOOL
Hal3AFlowCtrl::
doUpdateCmd(const ParamIspProfile_T* pParam)
{
    MINT32 i4MagicNum = pParam->i4MagicNum;
    if (m_pThread->isEnd() || m_fgPreStop)
    {
        MY_LOGD("[%s] Stop updating #(%d)", __FUNCTION__, i4MagicNum);
        return MTRUE;
    }
    //call notifyResult4TG API
    if(m_bTgIntAEEn)
    {
        // ResultPool - Get History
        MINT32 rHistoryReqMagic[HistorySize] = {0,0,0};
        m_pResultPoolObj->getHistory(rHistoryReqMagic);
        MY_LOGD_IF(m_fgLogEn, "[%s] History (Req0, Req1, Req2) = (#%d, #%d, #%d)", __FUNCTION__, rHistoryReqMagic[0], rHistoryReqMagic[1], rHistoryReqMagic[2]);

        //call notifyResult4TG API
        MY_LOGD_IF(m_fgLogEn, "[%s] notifyResult4TG Previous Req (#%d) New Req (#%d) bTgIntAEEn(%d)",__FUNCTION__, rHistoryReqMagic[1], i4MagicNum, m_bTgIntAEEn);
        if(rHistoryReqMagic[1] != 0)
            notifyResult4TG(rHistoryReqMagic[1]);
    }

    AAA_TRACE_D("3A_Update #(%d)", i4MagicNum);
    /* 这里发送的命令会更新状态 */
    MBOOL fgRet = postCommand(ECmd_Update, pParam);
    AAA_TRACE_END_D;

    if (!fgRet)
    {
        CAM_LOGE("ECmd_Update failed");
        return MFALSE;
    }

    if(m_fgPreStop)
    {
        MY_LOGD("[%s] Stop wait vsirq #(%d)", __FUNCTION__, i4MagicNum);
        return MTRUE;
    }
    IEventIrq::Duration duration;
    MY_LOGD_IF(m_fgLogEn, "[%s] start waitVSirq.", __FUNCTION__);
    AAA_TRACE_D("3A_WaitVSync #(%d)", i4MagicNum);
    AAA_TRACE_DRV(WaitVSync);
    m_pEventIrq->wait(duration);
#if (CAM3_3A_ISP_30_EN)
    // Apply 3A ISP info at the time after Vsync (isp 3.0 only)
    m_p3AWrap->set3AISPInfo();
#endif
    //
    AAA_TRACE_END_DRV;
    AAA_TRACE_END_D;

    return MTRUE;
}

当进入相机APK,但还没有开始拍照时,会不断调用 doUpdateCmd() 函数更新相机闪光灯的状态,即不断的执行 MBOOL fgRet = postCommand(ECmd_Update, pParam); 这条代码直到退出相机APK。

打开闪光灯

1.1.11、Hal3AFlowCtrl::postCommand的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp

MBOOL
Hal3AFlowCtrl::
postCommand(ECmd_T const eCmd, const ParamIspProfile_T* pParam)
{
    MY_LOGD_IF(m_fgLogEn, "[%s] enter(%d)", __FUNCTION__, eCmd);
    MINT32 i4MagicNum = 0;
    MINT32 i4MagicNumCur = 0;
    MBOOL bMainFlash = MFALSE;
    MBOOL bPre = MFALSE;
    ParamIspProfile_T rParamIspProf = *pParam;
    m_rCapParam.u4CapType = E_CAPTURE_NORMAL;
    if (eCmd == ECmd_CameraPreviewStart) /* 刚打开相机APK以及拍完照后条件会成立,但只会调用一次 */
    {
        MY_LOGD("[%s] Clear ResultPool", __FUNCTION__);
        // ResultPool - preview start to clear ResultPool
        m_pResultPoolObj->clearAllResultPool();
        m_rParam.i8ExposureTime = 0;

        if (m_pEventIrq == NULL)
        {
            IEventIrq::ConfigParam IrqConfig(m_i4SensorDev, m_i4SensorOpenIdx, 5000000, IEventIrq::E_Event_Vsync);
            IrqConfig.i4TgInfo = m_i4TgInfo;
            m_pEventIrq = IEventIrq::createInstance(IrqConfig, "VSIrq");
        }
#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
    if(m_p3ASttCtrl)
        m_p3ASttCtrl->startStt();
#endif
        m_p3AWrap->start();
    }

    if (eCmd == ECmd_Update)
    {
        MY_LOGD("[%s] m_rParam.u4AeMode(%d), m_rParam.i8ExposureTime(%lld), iValidateOpt(%d)", __FUNCTION__, (MINT32)m_rParam.u4AeMode, (long long)m_rParam.i8ExposureTime, rParamIspProf.iValidateOpt);
        /* rParamIspProf.iValidateOpt 的值默认是1,但需要开启闪光灯时会切换成0 */
        if (rParamIspProf.iValidateOpt != ParamIspProfile_T::EParamValidate_None)
        {
            i4MagicNum = rParamIspProf.i4MagicNum;
            i4MagicNumCur = rParamIspProf.i4MagicNumCur;
            bMainFlash = m_p3AWrap->chkMainFlashOnCond();
            bPre = m_p3AWrap->chkPreFlashOnCond();
            rParamIspProf.bMainFlash = bMainFlash;
            MY_LOGD_IF(m_fgLogEn, "[%s] (bMainFlash,bPre):(%d,%d)", __FUNCTION__, bMainFlash,bPre);

            if ((bMainFlash||bPre) && i4MagicNum != 0)
            {
                m_u4FlashOnIdx = i4MagicNum;
                m_fgFlashOn = 1;
            }
            if (bMainFlash) /* bMainFlash 需要为 true */
            {
                /* 这里开启闪光灯 */
                m_p3AWrap->setFlashLightOnOff(1, 1);
                m_i4MainFlashOnIdx = i4MagicNum;
                m_fgInternalFlashOn = MFALSE;
            }
            if (bPre) {
                m_p3AWrap->setFlashLightOnOff(1, 0);
                m_fgInternalFlashOn = MFALSE;
            }
            m_p3AWrap->postCommand(eCmd, &rParamIspProf);

            if (m_p3AWrap->chkCapFlash())
            {
                m_rCapParam.u4CapType = E_CAPTURE_HIGH_QUALITY_CAPTURE;
            }
            MY_LOGD_IF(m_fgLogEn, "[%s][HQC] inform p1 capture type (%d)", __FUNCTION__, m_rCapParam.u4CapType);

            i4MagicNumCur = m_p3AWrap->queryMagicNumber();

            MY_LOGD_IF(m_fgLogEn, "[%s] (Req, Stt) = (#%d, #%d)", __FUNCTION__, i4MagicNum, i4MagicNumCur);

            // ResultPool - must update u4MagicNumCur to resultPool i4StatiticMagic
            MBOOL ret = m_pResultPoolObj->updateResultCFG(i4MagicNum, i4MagicNumCur); //update ReqResult i4StatiticMagic of CFG
            if(!ret)
                MY_LOGE("[%s] update MagicNumCur to resultPool i4StatiticMagic fail", __FUNCTION__);
            // i4StatiticMagic for high quality
            AAA_TRACE_HAL(on3AProcFinish);
            on3AProcFinish(i4MagicNum, i4MagicNumCur);
            AAA_TRACE_END_HAL;
        }else {
            if (m_rParam.u4AeMode == 0 && m_rParam.i8ExposureTime >= 400000000)
            {
                m_p3AWrap->postCommand(eCmd, &rParamIspProf);
            }
            else
            {
                // dummy frame  need to enqueueHwBuf
                Hal3ASttCtrl* p3ASttCtrl = Hal3ASttCtrl::getInstance(m_i4SensorDev);
                // enque AAO
                IBufMgr* pAAOBufMgr = p3ASttCtrl->getBufMgr(BUF_AAO);
                if(pAAOBufMgr) pAAOBufMgr->enqueueHwBuf();
            }
        }
        IspTuningBufCtrl::getInstance(m_i4SensorDev)->clearP1Buffer();
    }
    else
    {
        m_p3AWrap->postCommand(eCmd, &rParamIspProf);
    }

    /* 拍照结束或者退出相机APK时,会调用 */
    if (eCmd == ECmd_CameraPreviewEnd)
    {
        MY_LOGD("[%s] reset bMainFlash", __FUNCTION__);
        m_u4FlashOnIdx = -1;

#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
    if(m_p3ASttCtrl)
        m_p3ASttCtrl->stopStt();
#endif

        m_p3AWrap->stop();

#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
    if(m_p3ASttCtrl)
        m_p3ASttCtrl->uninitStt();
#endif

        if (m_pEventIrq)
        {
            m_pEventIrq->destroyInstance("VSIrq");
            m_pEventIrq = NULL;
        }
        m_fgPreStop = MFALSE;
    }

    return MTRUE;
}

想要调用到 **m_p3AWrap->setFlashLightOnOff(1, 1); ** 开启闪光灯,需要 bMainFlash 变量为 true , 而 bMainFlash 是通过 bMainFlash = m_p3AWrap->chkMainFlashOnCond(); 这条代码进行赋值的。chkMainFlashOnCond() 在文件 Hal3ARawImp.cpp 中定义,具体代码如下:

1.1.12、Hal3ARawImp::chkPreFlashOnCond的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/isp_30/wrapper/Hal3ARawImp.cpp

MBOOL
Hal3ARawImp::
chkPreFlashOnCond() const
{
    // Torch
    FlashPolicy_T rFlashPolicy;
    rFlashPolicy.bIsFlashOnCapture = isFlashOnCapture();
    rFlashPolicy.bIsFlashCharging = (FlashMgr::getInstance(m_i4SensorDev)->getFlashState() == MTK_FLASH_STATE_CHARGING);
    FlashHal::getInstance(m_i4SensorDev)->hasHw(rFlashPolicy.i4HWSuppportFlash);

    CAM_LOGD_IF(m_3ALogEnable, "[%s] bIsFlashOnCapture(%d), bIsFlashCharging(%d), i4HWSuppportFlash(%d)", __FUNCTION__,
        rFlashPolicy.bIsFlashOnCapture,
        rFlashPolicy.bIsFlashCharging,
        rFlashPolicy.i4HWSuppportFlash);
    return HAL3A_POLICY_TORCH_ONOFF(m_i4SensorDev, m_rParam, rFlashPolicy);
}
MBOOL
Hal3ARawImp::
chkMainFlashOnCond() const
{
    // Main Flash
    FlashPolicy_T rFlashPolicy;
    rFlashPolicy.bIsFlashOnCapture = isFlashOnCapture();
    rFlashPolicy.bIsFlashCharging = (FlashMgr::getInstance(m_i4SensorDev)->getFlashState() == MTK_FLASH_STATE_CHARGING);
    FlashHal::getInstance(m_i4SensorDev)->hasHw(rFlashPolicy.i4HWSuppportFlash);

    CAM_LOGD_IF(m_3ALogEnable, "[%s] bIsFlashOnCapture(%d), bIsFlashCharging(%d), i4HWSuppportFlash(%d)", __FUNCTION__,
        rFlashPolicy.bIsFlashOnCapture,
        rFlashPolicy.bIsFlashCharging,
        rFlashPolicy.i4HWSuppportFlash);
    return HAL3A_POLICY_MAIN_FLASH_ONOFF(m_i4SensorDev, m_rParam, rFlashPolicy);
}

Hal3ARawImp::chkMainFlashOnCond() 和 Hal3ARawImp::chkPreFlashOnCond() 函数会不断的被调用直到退出相机APK。同理,关闭闪光灯实际也会调用到这两个函数,相应的条件成立后才会调用 m_p3AWrap->setFlashLightOnOff(0, 1); 关闭闪光灯。

关闭闪光灯

1.1.13、Hal3AFlowCtrl::notifyP1Done的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp

MVOID
Hal3AFlowCtrl::
notifyP1Done(MINT32 i4MagicNum, MVOID* /*pvArg*/)
{
    MBOOL bMainFlash = m_p3AWrap->chkMainFlashOnCond();
    MBOOL bPre = m_p3AWrap->chkPreFlashOnCond();
    MBOOL bMagicNum = (i4MagicNum >= (MINT32)m_u4FlashOnIdx);

    MY_LOGD_IF(m_fgLogEn, "[%s] i4MagicNum(%d), m_u4FlashOnIdx(%d), bMagicNum(%d), bMainFlash(%d), bPre(%d), m_fgFlashOn(%d)", __FUNCTION__, i4MagicNum, m_u4FlashOnIdx, bMagicNum, bMainFlash, bPre, m_fgFlashOn);
    if ( bMagicNum && !bMainFlash && !bPre && m_fgFlashOn)
    {
        /* 这里关闭闪光灯 */
        m_p3AWrap->setFlashLightOnOff(0, 1); // don't care main or pre
        m_u4FlashOnIdx = -1;
        m_fgFlashOn = 0;
    }

    if (bMagicNum && m_i4MainFlashOnIdx != -1)
    {
        m_i4MainFlashOnIdx = -1;
    }

    MBOOL isNeedTurnOnPreFlash = m_p3AWrap->isNeedTurnOnPreFlash();
    MY_LOGD_IF(m_fgLogEn,"[%s] isNeedTurnOnPreFlash(%d)", __FUNCTION__, isNeedTurnOnPreFlash);
    if(m_fgInternalFlashOn != isNeedTurnOnPreFlash)
    {
        m_fgInternalFlashOn = isNeedTurnOnPreFlash;
        MY_LOG("[%s] setPreFlashOnOff(%d)", __FUNCTION__, m_fgInternalFlashOn);
        m_p3AWrap->setPreFlashOnOff(isNeedTurnOnPreFlash);
    }

    if ((m_u4FrmIdFreeze != 0) && (static_cast<MUINT32>(i4MagicNum) == m_u4FrmIdFreeze))
    {
        MY_LOGD("[%s]+ one-shot dump @%d", __FUNCTION__, i4MagicNum);
        m_p3AWrap->dumpP1Params(i4MagicNum);
        ::property_set("vendor.debug.rrz.dump", 0);
        m_u4FrmIdFreeze = 0;
        MY_LOGD("[%s]- one-shot dump @%d", __FUNCTION__, i4MagicNum);
    }
}

控制闪光灯开启和关闭的方法

1.1.14、Hal3ARawImp::setFlashLightOnOff的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/isp_30/wrapper/Hal3ARawImp.cpp

MBOOL
Hal3ARawImp::
setFlashLightOnOff(MBOOL bOnOff, MBOOL bMainPre)
{
#if CAM3_FLASH_FEATURE_EN
    CAM_LOGD_IF(m_3ALogEnable, "[%s] bOnOff(%d) + ", __FUNCTION__, bOnOff);
    if (m_bIsFlashOpened == bOnOff)
    {
        CAM_LOGD("[%s] flashlight unchanged, bOnOff(%d)", __FUNCTION__, bOnOff);
    }
    else if (!bOnOff)
    {
        //modified to update strobe state after capture for ae manager
        IAeMgr::getInstance().setStrobeMode(m_i4SensorDev, MFALSE);
        IAwbMgr::getInstance().setStrobeMode(m_i4SensorDev, AWB_STROBE_MODE_OFF);

        if (bMainPre)
            FlashHal::getInstance(m_i4SensorDev)->setOnOff(MFALSE, FLASH_HAL_SCENARIO_MAIN_FLASH);
        else
            FlashHal::getInstance(m_i4SensorDev)->setOnOff(MFALSE, FLASH_HAL_SCENARIO_VIDEO_TORCH);
    }
    else //flash on
    {
        if (bMainPre){
            FlashHal::getInstance(m_i4SensorDev)->setOnOff(MTRUE, FLASH_HAL_SCENARIO_MAIN_FLASH);
            IAwbMgr::getInstance().SetMainFlashInfo(m_i4SensorDev, MTRUE);
            }

        else{
            FlashHal::getInstance(m_i4SensorDev)->setOnOff(MTRUE, FLASH_HAL_SCENARIO_VIDEO_TORCH);
            IAwbMgr::getInstance().setStrobeMode(m_i4SensorDev, AWB_STROBE_MODE_ON);
            }

    }
    if(m_bIsFlashOpened != bOnOff)
    {
        CAM_LOGD("[%s] flashlight is changed (%d->%d), and assign bOnOff to m_bIsFlashOpened", __FUNCTION__, m_bIsFlashOpened, bOnOff);
        m_bIsFlashOpened = bOnOff;
        handleBadPicture(m_rParam.i4MagicNum);
    }
    CAM_LOGD_IF(m_3ALogEnable, "[%s] - ", __FUNCTION__);
#endif
    return MTRUE;
}

1.1.15、FlashHal::setOnOff的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/flash_mgr/flash_hal.cpp

int FlashHal::setOnOff(int enable, FLASH_HAL_SCENARIO_ENUM scenario)
{
    logI("setOnOff(): type(%d), enable(%d), scenario(%d).", mStrobeTypeId, enable, scenario);

    /* verify arguments */
    if (verifyScenario(scenario)) {
        logE("setOnOff(): invalid arguments.");
        return -1;
    }

    if (!isAvailable()) {
        logI("setOnOff(): sensorDev(%d) not available.", mSensorDev);
        return -1;
    }

    if (scenario == FLASH_HAL_SCENARIO_MAIN_FLASH) {
        /* get timeout */
        int currentTime = getMs();
        if (enable) {
            mFlashHalTimeInfo.mfStartTime = currentTime;
            mFlashHalTimeInfo.mfIsTimeout = 0;
            mFlashHalTimeInfo.mfTimeout = mFlashHalInfo[FLASH_HAL_SCENARIO_MAIN_FLASH].timeout;
            if (mStrobeCtNum > 1)
                mFlashHalTimeInfo.mfTimeoutLt = mFlashHalInfo[FLASH_HAL_SCENARIO_MAIN_FLASH].timeoutLt;

        } else {
            mFlashHalTimeInfo.mfEndTime = currentTime;

            int flashOnPeriod = mFlashHalTimeInfo.mfEndTime - mFlashHalTimeInfo.mfStartTime;
            if (flashOnPeriod > mFlashHalTimeInfo.mfTimeout &&
                    mFlashHalTimeInfo.mfTimeout)
                mFlashHalTimeInfo.mfIsTimeout = 1;
            if (mStrobeCtNum > 1)
                if (flashOnPeriod > mFlashHalTimeInfo.mfTimeoutLt &&
                        mFlashHalTimeInfo.mfTimeoutLt)
                    mFlashHalTimeInfo.mfIsTimeout = 1;
        }
    }

    /* set flash info to ISP */ // TODO: moveout
    if (scenario != FLASH_HAL_SCENARIO_TORCH) {
        FLASH_INFO_T finfo;
        finfo.flashMode = FLASHLIGHT_FORCE_OFF; // TODO: not use
        finfo.isFlash = enable;
        //IspTuningMgr::getInstance().setFlashInfo(mSensorDev, finfo);
    }

    if (enable)
        return setFlashOn(mFlashHalInfo[scenario]);
    else
        return setFlashOff();
}

开启闪光灯

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/flash_mgr/flash_hal.cpp

int FlashHal::setFlashOn(FlashHalInfo info)
{
    Mutex::Autolock lock(mLock);

    logI("setFlashOn(): duty(%d), timeout(%d), lt duty(%d), lt timeout(%d).",
            info.duty, info.timeout, info.dutyLt, info.timeoutLt);

    int isLow = 0;
    isLowPower(&isLow);
    if (isLow) {
        logI("setFlashOn(): is low power.");
        return 0;
    }

    /* set duty */
    int dutyCur;
    int dutyCurLt;
    {
        mpStrobe->getDuty(&dutyCur);
        if (dutyCur != info.duty)
            mpStrobe->setDuty(info.duty);
    }
    if (mStrobeCtNum > 1) {
        mpStrobe2->getDuty(&dutyCurLt);
        if (dutyCurLt != info.dutyLt)
            mpStrobe2->setDuty(info.dutyLt);
    }

    /* set on/off */
    int bOn;
    {
        mpStrobe->isOn(&bOn);
        if (info.duty < 0) {
            /* 实际调用的是 StrobeDrvFlashlight::setOnOff */
            mpStrobe->setOnOff(0); 
        } else {
            mpStrobe->setTimeOutTime(info.timeout);
            mpStrobe->setOnOff(1);
        }
    }
    if (mStrobeCtNum > 1) {
        mpStrobe2->isOn(&bOn);
        if (info.dutyLt < 0) {
            mpStrobe2->setOnOff(0);
        } else {
            mpStrobe2->setTimeOutTime(info.timeoutLt);
            mpStrobe2->setOnOff(1);
        }
    }

    return 0;
}

关闭闪光灯

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/flash_mgr/flash_hal.cpp

int FlashHal::setFlashOff()
{
    Mutex::Autolock lock(mLock);

    logI("setFlashOff().");

    mpStrobe->setOnOff(0); /* 实际调用的是 StrobeDrvFlashlight::setOnOff */
    if (mStrobeCtNum > 1)
        mpStrobe2->setOnOff(0);

    mpStrobe->getHwFault(&mDriverFault);
    return 0;
}

StrobeDrvFlashlight 继承于类 StrobeDrv , StrobeDrvFlashlight::setOnOff 是对 StrobeDrv 中虚函数 setOnOff 的覆写。

1.1.16、StrobeDrvFlashlight::setOnOff 的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/strobe/strobe_drv_flashlight.cpp

int StrobeDrvFlashlight::setOnOff(int enable)
{
    int ret = 0;

    /* verify arguments */
    if (verifyTypeCt(mTypeId, mCtId)) {
        logE("setOnOff(): error type/ct(%d,%d).", mTypeId, mCtId);
        return -1;
    }
    if (enable != MTRUE && enable != MFALSE && enable != 2) {
        logE("setOnOff(): error enable(%d).", enable);
        return -1;
    }

    logI("setOnOff(): enable(%d).", enable);

    /* get strobe fops handler */
    StrobeDrvFlashlightFops *pStrobeDrvFlashlightFops = StrobeDrvFlashlightFops::getInstance();

    if (enable == MTRUE) {
        /* record time at turning on */
        if (mIsOn == MFALSE)
            mOnTime = getMs();

        /* get pre-on time from driver */
        int needPreOnTime = 0;
        getPreOnTimeMsDuty(mDuty, &needPreOnTime);
        needPreOnTime = min(needPreOnTime, MAX_NEED_PRE_ON_TIME);

        /* sleep for pre-on */
        if (needPreOnTime > 0) {
            if (mPreOnTime == -1) {
                setPreOn();
                logI("setOnOff(): needs pre-on time(%d ms).", needPreOnTime);
                sleepMs(needPreOnTime);
            } else {
                long int curTime = getMs();
                int sleepTimeMs = needPreOnTime - (curTime - mPreOnTime);
                sleepTimeMs = min(sleepTimeMs, needPreOnTime);
                if (sleepTimeMs > 0) {
                    logI("setOnOff(): still needs pre-on time(%d ms).", sleepTimeMs);
                    sleepMs(sleepTimeMs);
                }
            }
        }

        /* enable strobe */
        ret = pStrobeDrvFlashlightFops->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, MTRUE);
        logI("setOnOff(): on time(%ld).", mOnTime);

    } else if (enable == MFALSE) {
        if (mIsOn == MTRUE) {
            mOffTime = getMs();
            if (mTimeOutTime && (mOffTime - mOnTime > mTimeOutTime))
                logI("setOnOff(): timeout.");
        }

        /* clear set pre-on time */
        mPreOnTime = -1;

        /* disable strobe */
        ret = pStrobeDrvFlashlightFops->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, MFALSE);
        logI("setOnOff(): off time(%ld).", mOffTime);
    }
    else if (enable == 2) {

        /* enable strobe */
        ret = pStrobeDrvFlashlightFops->sendCommand(FLASH_IOC_SET_ONOFF, mTypeId, mCtId, 2);
        logI("setOnOff(): on time(%ld).", mOnTime);
    }

    if (!ret)
        mIsOn = enable;
    else
        logE("setOnOff(): failed to ioctl.");

    return ret;
}

1.1.17、StrobeDrvFlashlightFops::sendCommand的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/strobe/strobe_drv_flashlight_fops.cpp

int StrobeDrvFlashlightFops::sendCommand(int cmd, int typeId, int ctId, int arg)
{
    Mutex::Autolock lock(mLock);

    if (mStrobeHandle < 0) {
        logD("sendCommandRet(): failed with no strobe handler.");
        return -1;
    }

    /* setup arguments */
    struct flashlight_user_arg strobeArg;
    strobeArg.type_id = typeId;
    strobeArg.ct_id = ctId;
    strobeArg.arg = arg;

    /* send ioctl */
    int ret = ioctl(mStrobeHandle, cmd, &strobeArg); /* 调用kernel中的ioctl */

    logD("Send command: type/ct(%d,%d), cmd(%d).", typeId, ctId, cmd);

    return ret;
}

二、KERNEL层

2.1、flash驱动加载流程

2.1.1、flashlight_init的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-core.c

module_init(flashlight_init);

static int __init flashlight_init(void)
{
	int ret;

	pr_debug("Init start\n");

    ...... /* 省略部分代码 */

	ret = platform_driver_register(&flashlight_platform_driver);
	if (ret) {
		pr_err("Failed to register platform driver\n");
		return ret;
	}

#ifdef CONFIG_MTK_FLASHLIGHT_PT
	register_low_battery_notify(
			&pt_low_vol_callback, LOW_BATTERY_PRIO_FLASHLIGHT);
	register_battery_percent_notify(
			&pt_low_bat_callback, BATTERY_PERCENT_PRIO_FLASHLIGHT);
	register_battery_oc_notify(
			&pt_oc_callback, BATTERY_OC_PRIO_FLASHLIGHT);
#endif

	pr_debug("Init done\n");

	return 0;
}

2.1.2、flashlight_platform_driver结构体的实现

#ifdef CONFIG_OF
static const struct of_device_id flashlight_of_match[] = {
	{.compatible = "mediatek,flashlight_core"},
	{},
};
MODULE_DEVICE_TABLE(of, flashlight_of_match);
#else
    ..... /* 省略部分代码 */
#endif

static struct platform_driver flashlight_platform_driver = {
	.probe = flashlight_probe,
	.remove = flashlight_remove,
	.shutdown = flashlight_shutdown,
	.driver = {
		   .name = FLASHLIGHT_DEVNAME,
		   .owner = THIS_MODULE,
#ifdef CONFIG_OF
		   .of_match_table = flashlight_of_match, /* "mediatek,flashlight_core" */
#endif
	},
};

./kernel-4.4/arch/arm/boot/dts/mt6739.dts

flashlight_core: flashlight_core {
        compatible = "mediatek,flashlight_core";
};

2.1.3、flashlight_probe的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-core.c

static int flashlight_probe(struct platform_device *dev)
{
	pr_debug("Probe start\n");

	/* allocate char device number */
	alloc_chrdev_region(&flashlight_devno, 0, 1, FLASHLIGHT_DEVNAME);

	pr_debug("Allocate major number and minor number: (%d, %d)\n",
			MAJOR(flashlight_devno),
			MINOR(flashlight_devno));

	/* allocate char device */
	flashlight_cdev = cdev_alloc();

	flashlight_cdev->ops = &flashlight_fops;
	flashlight_cdev->owner = THIS_MODULE;

	/* add char device to the system */
	cdev_add(flashlight_cdev, flashlight_devno, 1);


	/* create class */
	flashlight_class = class_create(THIS_MODULE, FLASHLIGHT_CORE);

	/* create device */
	flashlight_device = device_create(flashlight_class, NULL, flashlight_devno,
														NULL, FLASHLIGHT_DEVNAME);

	/* create device file */
	device_create_file(flashlight_device, &dev_attr_flashlight_strobe);
        
	device_create_file(flashlight_device, &dev_attr_flashlight_pt);
        
	device_create_file(flashlight_device, &dev_attr_flashlight_charger);
        
	device_create_file(flashlight_device, &dev_attr_flashlight_capability);
    
	device_create_file(flashlight_device, &dev_attr_flashlight_current);
    
	device_create_file(flashlight_device, &dev_attr_flashlight_fault);
    
	device_create_file(flashlight_device, &dev_attr_flashlight_sw_disable);

	/* init flashlight */
	fl_init();

	pr_debug("Probe done\n");

	return 0;

    ...... /* 省略部分代码 */
}

2.1.4、flashlight_led191_init的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

module_init(flashlight_led191_init);

static int __init flashlight_led191_init(void)
{
	int ret;

	PK_DBG("Init start.\n");

#ifndef CONFIG_OF
	...... /* 省略部分代码 */
#endif

	ret = platform_driver_register(&led191_platform_driver);
	if (ret) {
		PK_ERR("Failed to register platform driver\n");
		return ret;
	}

	PK_DBG("Init done.\n");

	return 0;
}
/* define device tree */
#ifndef LED191_DTNAME
#define LED191_DTNAME "mediatek,flashlights_led191"
#endif

#ifdef CONFIG_OF
static const struct of_device_id led191_gpio_of_match[] = {
	{.compatible = LED191_DTNAME},
	{},
};
MODULE_DEVICE_TABLE(of, led191_gpio_of_match);
#else
    ...... /* 省略部分代码 */
#endif

static struct platform_driver led191_platform_driver = {
	.probe = led191_probe,
	.remove = led191_remove,
	.driver = {
		.name = LED191_NAME,
		.owner = THIS_MODULE,
#ifdef CONFIG_OF
		.of_match_table = led191_gpio_of_match, /* "mediatek,flashlights_led191" */
#endif
	},
};

./kernel-4.4/arch/arm/boot/dts/x006_k39tv1_bsp_1g.dtsi

flashlights_led191: flashlights_led191 {
        compatible = "mediatek,flashlights_led191";
        decouple = <0>;
        channel@1 {
                type = <0>;
                ct = <0>;
                part = <0>;
        };
};

2.1.5、led191_probe的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

static int led191_probe(struct platform_device *pdev)
{
	struct led191_platform_data *pdata = dev_get_platdata(&pdev->dev);
	int err;
	int i;

	PK_DBG("Probe start.\n");
	/* init pinctrl */
	if (led191_pinctrl_init(pdev)) {
		PK_DBG("Failed to init pinctrl.\n");
		err = -EFAULT;
		goto err;
	}

	/* init platform data */
	if (!pdata) {
		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
		if (!pdata) {
			err = -ENOMEM;
			goto err;
		}
		pdev->dev.platform_data = pdata;
		err = led191_parse_dt(&pdev->dev, pdata);
		if (err)
			goto err;
	}

	/* init work queue */
	INIT_WORK(&led191_work, led191_work_disable);

	/* init timer */
	hrtimer_init(&led191_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	led191_timer.function = led191_timer_func;
	led191_timeout_ms = 100;

    /* 为了降低功耗,led191芯片的初始化放到了“set_driver”中实现。这里直接return 0 */
	/* init chip hw */
	led191_chip_init();

	/* clear usage count */
	use_count = 0;

	/* register flashlight device */
	if (pdata->channel_num) {
		for (i = 0; i < pdata->channel_num; i++)
			if (flashlight_dev_register_by_device_id(&pdata->dev_id[i], &led191_ops)) {
				err = -EFAULT;
				goto err;
			}
	} else {
		if (flashlight_dev_register(LED191_NAME, &led191_ops)) {
			err = -EFAULT;
			goto err;
		}
	}

	PK_DBG("Probe done.\n");

	return 0;
err:
	return err;
}

2.1.6、led191_pinctrl_init的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

static int led191_pinctrl_init(struct platform_device *pdev)
{
	int ret = 0;

	/* get pinctrl */
	led191_pinctrl = devm_pinctrl_get(&pdev->dev);
	if (IS_ERR(led191_pinctrl)) {
		PK_ERR("Failed to get flashlight pinctrl.\n");
		ret = PTR_ERR(led191_pinctrl);
	}

	/*  Flashlight pin initialization */
	led191_hw_ch0_high = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH0_HIGH);
	if (IS_ERR(led191_hw_ch0_high)) {
		PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH0_HIGH);
		ret = PTR_ERR(led191_hw_ch0_high);
	}
	led191_hw_ch0_low = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH0_LOW);
	if (IS_ERR(led191_hw_ch0_low)) {
		PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH0_LOW);
		ret = PTR_ERR(led191_hw_ch0_low);
	}

	if (flashlight_device_num == 2)	{
		led191_hw_ch1_high = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH1_HIGH);
		if (IS_ERR(led191_hw_ch1_high)) {
			PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH1_HIGH);
			ret = PTR_ERR(led191_hw_ch1_high);
		}
		led191_hw_ch1_low = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH1_LOW);
		if (IS_ERR(led191_hw_ch1_low)) {
			PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH1_LOW);
			ret = PTR_ERR(led191_hw_ch1_low);
		}
	}

	// sgm3785 flash ic,
	#if defined(USING_SGM3785_FLASH)
	/*  sgm3785 flash ENM pin initialization */
	led191_hw_ch01_high = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH01_HIGH);
	if (IS_ERR(led191_hw_ch01_high)) {
		PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH01_HIGH);
		ret = PTR_ERR(led191_hw_ch01_high);
	}
	led191_hw_ch01_low = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH01_LOW);
	if (IS_ERR(led191_hw_ch01_low)) {
		PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH01_LOW);
		ret = PTR_ERR(led191_hw_ch01_low);
	}
	led191_hw_ch01_pwm = pinctrl_lookup_state(led191_pinctrl, LED191_PINCTRL_STATE_HW_CH01_PWM);
	if (IS_ERR(led191_hw_ch01_pwm)) {
		PK_ERR("Failed to init (%s)\n", LED191_PINCTRL_STATE_HW_CH01_PWM);
		ret = PTR_ERR(led191_hw_ch01_pwm);
	}

	// init state, ENF = 0 && ENM = 0
	if (!IS_ERR(led191_hw_ch0_low)) {
		ret = pinctrl_select_state(led191_pinctrl, led191_hw_ch0_low);// ENF = 0
	}
	if (!IS_ERR(led191_hw_ch01_low)) {
		ret = pinctrl_select_state(led191_pinctrl, led191_hw_ch01_low);// ENM = 0
	}
	
	pwm_setting.pwm_no = 3;
	pwm_setting.mode = PWM_MODE_OLD;
	pwm_setting.clk_div = CLK_DIV1;
	pwm_setting.clk_src = PWM_CLK_OLD_MODE_32K;
	pwm_setting.pmic_pad = 0;
	pwm_setting.PWM_MODE_OLD_REGS.IDLE_VALUE = 0;
	pwm_setting.PWM_MODE_OLD_REGS.GUARD_VALUE = 0;
	pwm_setting.PWM_MODE_OLD_REGS.GDURATION = 0;
	pwm_setting.PWM_MODE_OLD_REGS.WAVE_NUM = 0;
	pwm_setting.PWM_MODE_OLD_REGS.DATA_WIDTH = 7;	/* 7 level */
	pwm_setting.PWM_MODE_OLD_REGS.THRESH = 0; // level to set.
	#endif
	// end +++

	return ret;
}

2.1.7、led191_parse_dt的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

static int led191_parse_dt(struct device *dev,
		struct led191_platform_data *pdata)
{
	struct device_node *np, *cnp;
	u32 decouple = 0;
	int i = 0;

	if (!dev || !dev->of_node || !pdata)
		return -ENODEV;

	np = dev->of_node;

	pdata->channel_num = of_get_child_count(np);
	if (!pdata->channel_num) {
		PK_LOG("Parse no dt, node.\n");
		return 0;
	}
	PK_LOG("Channel number(%d).\n", pdata->channel_num);

	if (of_property_read_u32(np, "decouple", &decouple))
		PK_LOG("Parse no dt, decouple.\n");

	pdata->dev_id = devm_kzalloc(dev,
			pdata->channel_num * sizeof(struct flashlight_device_id),
			GFP_KERNEL);
	if (!pdata->dev_id)
		return -ENOMEM;

	for_each_child_of_node(np, cnp) {
		if (of_property_read_u32(cnp, "type", &pdata->dev_id[i].type))
			goto err_node_put;
		if (of_property_read_u32(cnp, "ct", &pdata->dev_id[i].ct))
			goto err_node_put;
		if (of_property_read_u32(cnp, "part", &pdata->dev_id[i].part))
			goto err_node_put;
		snprintf(pdata->dev_id[i].name, FLASHLIGHT_NAME_SIZE, LED191_NAME);
		pdata->dev_id[i].channel = i;
		pdata->dev_id[i].decouple = decouple;

		PK_LOG("Parse dt (type,ct,part,name,channel,decouple)=(%d,%d,%d,%s,%d,%d).\n",
				pdata->dev_id[i].type, pdata->dev_id[i].ct,
				pdata->dev_id[i].part, pdata->dev_id[i].name,
				pdata->dev_id[i].channel, pdata->dev_id[i].decouple);
		i++;
	}

	return 0;

err_node_put:
	of_node_put(cnp);
	return -EINVAL;
}

2.1.8、flashlight_dev_register_by_device_id的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-core.c

/*
 * Register devices
 *
 * Please DO NOT register flashlight device driver,
 * until success to probe hardware.
 */
int flashlight_dev_register_by_device_id(
		struct flashlight_device_id *dev_id,
		struct flashlight_operations *dev_ops)
{
	struct flashlight_dev *fdev;

	if (!dev_id || !dev_ops)
		return -EINVAL;

	if (flashlight_verify_index(dev_id->type, dev_id->ct, dev_id->part)) {
		pr_err("Failed to register device (%d,%d,%d)\n",
				dev_id->type, dev_id->ct, dev_id->part);
		return -EINVAL;
	}

	pr_info("Register device (%d,%d,%d)\n",
			dev_id->type, dev_id->ct, dev_id->part);

	mutex_lock(&fl_mutex);
	fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
	if (!fdev) {
		mutex_unlock(&fl_mutex);
		return -ENOMEM;
	}
	fdev->ops = dev_ops;
	fdev->dev_id = *dev_id;
	fdev->low_pt_level = -1;
	fdev->charger_status = FLASHLIGHT_CHARGER_READY;
	list_add_tail(&fdev->node, &flashlight_list);
	mutex_unlock(&fl_mutex);

	return 0;
}
EXPORT_SYMBOL(flashlight_dev_register_by_device_id);

2.1.9、led191_ops结构体的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

static struct flashlight_operations led191_ops = {
    /*************************************************************
     * 为了降低功耗,led191芯片的 open 和 release 都放到了“set_driver”
     * 中实现。这里直接return 0 
     *************************************************************/
	led191_open, 
	led191_release, 
    
	led191_ioctl,
	led191_strobe_store,
	led191_set_driver
};

2.1.10、led191_ioctl的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

/*****************************************************************************
 * Flashlight operations
 *****************************************************************************/
static int led191_ioctl(unsigned int cmd, unsigned long arg)
{
	struct flashlight_dev_arg *fl_arg;
	int channel;
	ktime_t ktime;

	fl_arg = (struct flashlight_dev_arg *)arg;
	channel = fl_arg->channel;
	g_flash_channel_idx = channel;

	switch (cmd) {
	case FLASH_IOC_SET_TIME_OUT_TIME_MS:
		PK_DBG("FLASH_IOC_SET_TIME_OUT_TIME_MS(%d): %d\n",
				channel, (int)fl_arg->arg);
		led191_timeout_ms = fl_arg->arg;
		break;

	case FLASH_IOC_SET_DUTY:
		PK_DBG("FLASH_IOC_SET_DUTY(%d): %d\n",
				channel, (int)fl_arg->arg);
		led191_set_level(fl_arg->arg);
		break;

	case FLASH_IOC_SET_ONOFF:
		PK_DBG("FLASH_IOC_SET_ONOFF(%d): %d\n",
				channel, (int)fl_arg->arg);
		if (fl_arg->arg == 1) {
			if (led191_timeout_ms) {
				ktime = ktime_set(led191_timeout_ms / 1000,
						(led191_timeout_ms % 1000) * 1000000);
				hrtimer_start(&led191_timer, ktime, HRTIMER_MODE_REL);
			}
			led191_enable(channel);
		} else {
			led191_disable(channel);
			hrtimer_cancel(&led191_timer);
		}
		break;
	default:
		PK_LOG("No such command and arg(%d): (%d, %d)\n",
				channel, _IOC_NR(cmd), (int)fl_arg->arg);
		return -ENOTTY;
	}

	return 0;
}

2.1.11、led191_enable和led191_disable的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

/* flashlight enable function */
static int led191_enable(int channel)
{
	int pin = LED191_PINCTRL_PIN_HWEN;

	PK_LOG("g_flash_duty = %d, channel:%d\n", g_flash_duty, channel);
	led191_pinctrl_set(channel, 1);
	return 0;
		
	if (g_flash_duty == 1) {
		led191_pinctrl_set(pin, 1);
	} else {
		led191_pinctrl_set(pin, 1);
		led191_pinctrl_set(pin, 0);
	}
	led191_pinctrl_set(pin, 1);

	return 0;
}

/* flashlight disable function */
static int led191_disable(int channel)
{
	int pin = 0, state = 0;
	PK_LOG("no use pin:%d, channel:%d, state:%d\n", pin, channel, state);
	return led191_pinctrl_set(channel, state);
}

2.1.12、led191_pinctrl_set的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

static int led191_pinctrl_set(int pin, int state)
{
	int ret = 0;
	struct pinctrl_state *led191_hw_chx_low = led191_hw_ch0_low;
	struct pinctrl_state *led191_hw_chx_high = led191_hw_ch0_high;

	struct pinctrl_state *led191_hw_chx1_low = led191_hw_ch1_low;
	struct pinctrl_state *led191_hw_chx1_high = led191_hw_ch1_high;

#if defined(USING_SGM3785_FLASH)
	struct pinctrl_state *led191_hw_chx_enm_low = led191_hw_ch01_low;
	struct pinctrl_state *led191_hw_chx_enm_high = led191_hw_ch01_high;
	struct pinctrl_state *led191_hw_chx_pwm = led191_hw_ch01_pwm;
#endif


	if (IS_ERR(led191_pinctrl)) {
		PK_ERR("pinctrl is not available\n");
		return -1;
	}

	PK_DBG("g_flash_channel_idx = %d\n", g_flash_channel_idx);
	if (pin == 0) {
		led191_hw_chx_low = led191_hw_ch0_low;
		led191_hw_chx_high = led191_hw_ch0_high;

	#if defined(USING_SGM3785_FLASH)
		led191_hw_chx_enm_low = led191_hw_ch01_low;
		led191_hw_chx_enm_high = led191_hw_ch01_high;
		led191_hw_chx_pwm = led191_hw_ch01_pwm;
	#endif

	} else if (pin == 1 && (flashlight_device_num == 2)) {
		led191_hw_chx1_low = led191_hw_ch1_low;
		led191_hw_chx1_high = led191_hw_ch1_high;
	} else {
		PK_DBG("please check g_flash_channel_idx!!!\n");
	}

	switch (pin) {
	case LED191_PINCTRL_PIN_HWEN:
		PK_DBG("LED191_PINCTRL_PIN_HWEN\n");

#if defined(USING_SGM3785_FLASH)
		if (state == LED191_PINCTRL_PINSTATE_HIGH) { // enable
			if (led191_is_flash(g_flash_duty)) { // Flash
				PK_LOG("goto flash mode on\n");
				// 1. enter Active Mode, ENF = 0 && ENM = PWM && PWM high time <= 2.5ms
				if (!IS_ERR(led191_hw_chx_low)) {
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_low);
				}
				
				// ENM PWM config
				// a. config GPIO28 to PWM mode
				if (!IS_ERR(led191_hw_chx_pwm)) {
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_pwm);
				}
				// b. set PWM
				pwm_setting.PWM_MODE_OLD_REGS.THRESH = g_flash_duty;
				ret = pwm_set_spec_config(&pwm_setting);
				PK_LOG("set PWM return value:%d\n", ret);
				udelay(400);// delay 400us

				// 2. enter Flash Mode, ENF = 1 && ENM = PWM
				if (!IS_ERR(led191_hw_chx_high)) {
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_high);
				}
			} else { // Torch
				PK_LOG("goto torch mode on\n");
				// 1. enter Movie/Torch Mode, ENF = 0 && ENM = 1 && time >= 5ms
				if (!IS_ERR(led191_hw_chx_low)) {
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_low);
				}
				if (!IS_ERR(led191_hw_chx_enm_high)) {
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_enm_high);
				}
				mdelay(5);// delay 5ms
			}
		} else { // disable
			PK_LOG("exit Flash/Torch[Movie] mode, transit to Shutdown Mode\n");
			// 1. exit flash Mode or Torch[Movie] mode, ENF = 0 && ENM = 0 && time >= 5ms
			if (!IS_ERR(led191_hw_chx_low)) {
				ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_low);
			}
			if (!IS_ERR(led191_hw_chx_enm_low)) {
				ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_enm_low);
			}
			mdelay(5);// delay 5ms
		}
#else
		if (state == LED191_PINCTRL_PINSTATE_LOW && !IS_ERR(led191_hw_chx_low))
			ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_low);
		else if (state == LED191_PINCTRL_PINSTATE_HIGH && !IS_ERR(led191_hw_chx_high))
			ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx_high);
		else
			PK_ERR("set err, pin(%d) state(%d)\n", pin, state);
#endif
		break;
	
	case LED191_PINCTRL_PIN_HWEN1:
		PK_DBG("LED191_PINCTRL_PIN_HWEN1\n");
		if (flashlight_device_num == 2) {
			#if defined(CONFIG_P32A_PROJECT) || defined(CONFIG_P33A_PROJECT) || defined(CONFIG_A95C_PROJECT) || defined(CONFIG_H33E_PROJECT)// flash control level is inverse
				if (state == LED191_PINCTRL_PINSTATE_LOW && !IS_ERR(led191_hw_chx1_high))
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx1_high);
				else if (state == LED191_PINCTRL_PINSTATE_HIGH && !IS_ERR(led191_hw_chx1_low))
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx1_low);
				else
					PK_ERR("set err, pin(%d) state(%d)\n", pin, state);
			#else
				if (state == LED191_PINCTRL_PINSTATE_LOW && !IS_ERR(led191_hw_chx1_low))
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx1_low);
				else if (state == LED191_PINCTRL_PINSTATE_HIGH && !IS_ERR(led191_hw_chx1_high))
					ret = pinctrl_select_state(led191_pinctrl, led191_hw_chx1_high);
				else
					PK_ERR("set err, pin(%d) state(%d)\n", pin, state);
			#endif
		}
		break;
	// end +++
	default:
		PK_ERR("set err, pin(%d) state(%d)\n", pin, state);
		break;
	}
	PK_DBG("pin(%d) state(%d), ret:%d\n", pin, state, ret);

	return ret;
}

2.1.13、led191_strobe_store的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

static ssize_t led191_strobe_store(struct flashlight_arg arg)
{
	led191_set_driver(1);
	led191_set_level(arg.level);
	led191_timeout_ms = 0;
	g_flash_channel_idx = arg.channel;// optimise the channel id
	if (arg.level < 0) // optimise
		led191_disable(arg.channel);
	else
		led191_enable(arg.channel);
	msleep(arg.dur);
	led191_disable(arg.channel);
	led191_set_driver(0);

	return 0;
}

2.1.14、led191_set_driver的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

static int led191_set_driver(int set)
{
	int ret = 0;

	/* set chip and usage count */
	mutex_lock(&led191_mutex);
	if (set) {
		if (!use_count)
			ret = led191_init();
		use_count++;
		PK_DBG("Set driver: %d\n", use_count);
	} else {
		use_count--;
		if (!use_count)
			ret = led191_uninit();
		if (use_count < 0)
			use_count = 0;
		PK_DBG("Unset driver: %d\n", use_count);
	}
	mutex_unlock(&led191_mutex);

	return ret;
}

2.1.15、led191_init的实现

./kernel-4.4/drivers/misc/mediatek/flashlight/flashlight-led191.c

/* flashlight init */
static int led191_init(void)
{
	int pin = 0, state = 0;
	
	PK_LOG("g_flash_channel_idx:%d\n", g_flash_channel_idx);
	g_flash_duty = -1; // init flash duty
	if (g_flash_channel_idx == -1) {
		led191_pinctrl_set(LED191_PINCTRL_PIN_HWEN, LED191_PINCTRL_PINSTATE_LOW);
		led191_pinctrl_set(LED191_PINCTRL_PIN_HWEN1, LED191_PINCTRL_PINSTATE_LOW);
		return 0;
	}
	
	return led191_pinctrl_set(pin, state);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值