MTK LIGHT 代码分析

来源:互联网 发布:电商运营数据报表 编辑:程序博客网 时间:2024/04/27 20:01

MTK LIGHT 代码分析

项目上需要做些客制化的东西,需要用到light 一块的东西,好久以前看过,但是没有记录下来,这次重新看看,然后记录下来。

lightservice start

private void startCoreServices() {    // Manages LEDs and display backlight.    mSystemServiceManager.startService(LightsService.class);

应用中怎么用

get service

    final LightsManager lights = getLocalService(LightsManager.class);    mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);    返回一个 lightmanager, 只有一个方法。    public abstract class LightsManager {    public static final int LIGHT_ID_BACKLIGHT = 0;    public static final int LIGHT_ID_KEYBOARD = 1;    public static final int LIGHT_ID_BUTTONS = 2;    public static final int LIGHT_ID_BATTERY = 3;    public static final int LIGHT_ID_NOTIFICATIONS = 4;    public static final int LIGHT_ID_ATTENTION = 5;    public static final int LIGHT_ID_BLUETOOTH = 6;    public static final int LIGHT_ID_WIFI = 7;    public static final int LIGHT_ID_COUNT = 8;    public abstract Light getLight(int id);    }

关掉

    mNotificationLight.turnOff();
    NotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,ledOnMS, ledOffMS);

setFlashing 从service 到 HAL分析

LightsManager getLight 实现

private final LightsManager mService = new LightsManager() {    @Override    public com.android.server.lights.Light getLight(int id) {        if (id < LIGHT_ID_COUNT) {            return mLights[id];        } else {            return null;        }    }};final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];  LightsService 成员变量

setFlashing在 LightImpl 中实现 ###

private final class LightImpl extends Light {public void setFlashing(int color, int mode, int onMS, int offMS) {        synchronized (this) {            setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);        }    }

————》

private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {        if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {            if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"                    + Integer.toHexString(color));            mColor = color;            mMode = mode;            mOnMS = onMS;            mOffMS = offMS;            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", " + color + ")");            try {                setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);            } finally {                Trace.traceEnd(Trace.TRACE_TAG_POWER);            }        }    }

————》

 native 端 setLight_native, 在文件 com_android_server_lights_LightsService.cpp (35_smt\frameworks\base\services\core\jni) 中static void setLight_native(JNIEnv *env, jobject clazz, jlong ptr,    jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode){    Devices* devices = (Devices*)ptr;    light_state_t state;    if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {        return ;    }    memset(&state, 0, sizeof(light_state_t));    state.color = colorARGB;    state.flashMode = flashMode;    state.flashOnMS = onMS;    state.flashOffMS = offMS;    state.brightnessMode = brightnessMode;    {        ALOGD_IF_SLOW(50, "Excessive delay setting light");        **devices->lights[light]->set_light(devices->lights[light], &state);**    }}

————–》

Lights.c (35_smt\vendor\mediatek\proprietary\hardware\liblights)static int open_lights(const struct hw_module_t* module, char const* name,    struct hw_device_t** device){    int (*set_light)(struct light_device_t* dev,            struct light_state_t const* state);     // 根据NAME 来分辨操作,  #define LIGHT_ID_BACKLIGHT          "backlight" 在light.h 中定义。    if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {        set_light = set_light_backlight;    }     else if (0 == strcmp(LIGHT_ID_KEYBOARD, name)) {        set_light = set_light_keyboard;    }    else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {        set_light = set_light_buttons;    }    else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {        set_light = set_light_battery;    }    else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {        set_light = set_light_notifications;    }    else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) {        set_light = set_light_attention;    }    else {        return -EINVAL;    }    pthread_once(&g_init, init_globals);    struct light_device_t *dev = malloc(sizeof(struct light_device_t));    memset(dev, 0, sizeof(*dev));    dev->common.tag = HARDWARE_DEVICE_TAG;    dev->common.version = 0;    dev->common.module = (struct hw_module_t*)module;    dev->common.close = (int (*)(struct hw_device_t*))close_lights;    dev->set_light = set_light;    *device = (struct hw_device_t*)dev;    return 0;}static struct hw_module_methods_t lights_module_methods = {    .open =  open_lights,};/* * The lights Module */struct hw_module_t HAL_MODULE_INFO_SYM = {    .tag = HARDWARE_MODULE_TAG,    //.version_major = 1,    //.version_minor = 0,    .id = LIGHTS_HARDWARE_MODULE_ID,    .name = "MTK lights Module",    .author = "MediaTek",    .methods = &lights_module_methods,};

————》
我们的是LIGHT_ID_NOTIFICATIONS,接下来我们来看 set_light_notifications

static int set_light_notifications(struct light_device_t* dev,        struct light_state_t const* state){    pthread_mutex_lock(&g_lock);    g_notification = *state;    ALOGV("set_light_notifications g_trackball=%d color=0x%08x",            g_trackball, state->color);    if (g_haveTrackballLight) {        handle_trackball_light_locked(dev);    }    handle_speaker_battery_locked(dev);    pthread_mutex_unlock(&g_lock);    return 0;}static void handle_speaker_battery_locked(struct light_device_t* dev){    if (is_lit(&g_battery)) {        set_speaker_light_locked(dev, &g_battery);    } else {        set_speaker_light_locked(dev, &g_battery); /*Turkey workaround: notification and Low battery case, IPO bootup, NLED cannot blink*/ 处理低电压下情况        set_speaker_light_locked(dev, &g_notification);    }}

我们的是LIGHT_ID_NOTIFICATIONS 会比较复杂,如果是 LIGHT_ID_KEYBOARD ,则非常简单:

static int set_light_keyboard(struct light_device_t* dev,        struct light_state_t const* state){    int err = 0;    int on = is_lit(state);    pthread_mutex_lock(&g_lock);    err = write_int(KEYBOARD_FILE, on?255:0);    pthread_mutex_unlock(&g_lock);    return err;}

直接写sys file, 然后就到kernel中去了。

——-》 对于notification light, 不管低电的特殊情况,我们来关注 set_speaker_light_locked(dev, &g_notification);

static int set_speaker_light_locked(struct light_device_t* dev,        struct light_state_t const* state){    int len;    int alpha, red, green, blue;    int onMS, offMS;    unsigned int colorRGB;    switch (state->flashMode) {        case LIGHT_FLASH_TIMED:            onMS = state->flashOnMS;            offMS = state->flashOffMS;            break;        case LIGHT_FLASH_NONE:        default:            onMS = 0;            offMS = 0;            break;    }    colorRGB = state->color;#ifdef LIGHTS_DBG_ON    ALOGD("set_led_state colorRGB=%08X, onMS=%d, offMS=%d\n",            colorRGB, onMS, offMS);#endif    alpha = (colorRGB >> 24) & 0xFF;    if (alpha) {        red = (colorRGB >> 16) & 0xFF;        green = (colorRGB >> 8) & 0xFF;        blue = colorRGB & 0xFF;    } else { // alpha = 0 means turn the LED off        red = green = blue = 0;    }    if (red) {        blink_green(0, 0, 0);        blink_blue(0, 0, 0);        blink_red(red, onMS, offMS);    }    else if (green) {        blink_red(0, 0, 0);        blink_blue(0, 0, 0);        blink_green(green, onMS, offMS);    }    else if (blue) {        blink_red(0, 0, 0);        blink_green(0, 0, 0);        blink_blue(blue, onMS, offMS);    }    else {        blink_red(0, 0, 0);        blink_green(0, 0, 0);        blink_blue(0, 0, 0);    }    return 0;}

————》 接下来我们抽一个来看

static intblink_blue(int level, int onMS, int offMS){    static int preStatus = 0; // 0: off, 1: blink, 2: no blink    int nowStatus;    int i = 0;    if (level == 0)        nowStatus = 0;    else if (onMS && offMS)        nowStatus = 1;    else        nowStatus = 2;    if (preStatus == nowStatus)        return -1;#ifdef LIGHTS_DBG_ON    ALOGD("blink_blue, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);#endif    if (nowStatus == 0) {            write_int(BLUE_LED_FILE, 0);    }    else if (nowStatus == 1) {//          write_int(BLUE_LED_FILE, level); // default full brightness        write_str(BLUE_TRIGGER_FILE, "timer");  //  先写此 /sys/class/leds/blue/trigger  sys文件路径        while (((access(BLUE_DELAY_OFF_FILE, F_OK) == -1) || (access(BLUE_DELAY_OFF_FILE, R_OK|W_OK) == -1)) && i<10) {            ALOGD("BLUE_DELAY_OFF_FILE doesn't exist or cannot write!!\n");            led_wait_delay(5);//sleep 5ms for wait kernel LED class create led delay_off/delay_on node of fs            i++;        }        write_int(BLUE_DELAY_OFF_FILE, offMS);    "/sys/class/leds/blue/delay_off";        write_int(BLUE_DELAY_ON_FILE, onMS);   /sys/class/leds/blue/delay_on    }    else {        write_str(BLUE_TRIGGER_FILE, "none");        write_int(BLUE_LED_FILE, 255); // default full brightness    }    preStatus = nowStatus;    return 0;}

kernel light 分析

probe 分析

Leds_drv.c (35_smt\kernel-3.10\drivers\misc\mediatek\leds)static int __init mt65xx_leds_probe(struct platform_device *pdev){    int i;    int ret, rc;    struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list();     ****************************************************************************************************************    static struct cust_mt65xx_led cust_led_list[MT65XX_LED_TYPE_TOTAL] = {        {"red",               MT65XX_LED_MODE_NONE, -1,{0}},        {"green",             MT65XX_LED_MODE_NONE, -1,{0}},        {"blue",              MT65XX_LED_MODE_NONE, -1,{0}},        {"jogball-backlight", MT65XX_LED_MODE_NONE, -1,{0}},        {"keyboard-backlight",MT65XX_LED_MODE_NONE, -1,{0}},        {"button-backlight",  MT65XX_LED_MODE_NONE, -1,{0}},        {"lcd-backlight",     MT65XX_LED_MODE_CUST_BLS_PWM, (long)disp_bls_set_backlight,{0}},    };    ****************************************************************************************************************    LEDS_DRV_DEBUG("[LED]%s\n", __func__);    get_div_array();    for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++) {          if (cust_led_list[i].mode == MT65XX_LED_MODE_NONE) {            g_leds_data[i] = NULL;            continue;        }        g_leds_data[i] = kzalloc(sizeof(struct mt65xx_led_data), GFP_KERNEL);        if (!g_leds_data[i]) {            ret = -ENOMEM;            goto err;        }        g_leds_data[i]->cust.mode = cust_led_list[i].mode;        g_leds_data[i]->cust.data = cust_led_list[i].data;        g_leds_data[i]->cust.name = cust_led_list[i].name;        g_leds_data[i]->cdev.name = cust_led_list[i].name;        g_leds_data[i]->cust.config_data = cust_led_list[i].config_data;    /* bei add */        g_leds_data[i]->cdev.brightness_set = mt65xx_led_set;   // 所有的操作都在这3个函数中,后面来详细分析。        g_leds_data[i]->cdev.blink_set = mt65xx_blink_set;        INIT_WORK(&g_leds_data[i]->work, mt_mt65xx_led_work);        ret = led_classdev_register(&pdev->dev, &g_leds_data[i]->cdev);        if (strcmp(g_leds_data[i]->cdev.name, "lcd-backlight") == 0) {            rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_duty);            if (rc) {                LEDS_DRV_DEBUG("[LED]device_create_file duty fail!\n");            }            rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_div);            if (rc) {                LEDS_DRV_DEBUG("[LED]device_create_file duty fail!\n");            }            rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_frequency);            if (rc) {                LEDS_DRV_DEBUG("[LED]device_create_file duty fail!\n");            }            rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_pwm_register);            if (rc) {                LEDS_DRV_DEBUG("[LED]device_create_file duty fail!\n");            }            bl_setting = &g_leds_data[i]->cust;        }        if (ret)            goto err;    }#ifdef CONTROL_BL_TEMPERATURE    last_level = 0;    limit = 255;    limit_flag = 0;    current_level = 0;    LEDS_DRV_DEBUG        ("[LED]led probe last_level = %d, limit = %d, limit_flag = %d, current_level = %d\n",         last_level, limit, limit_flag, current_level);#endif    return 0; err:    if (i) {        for (i = i - 1; i >= 0; i--) {            if (!g_leds_data[i])                continue;            led_classdev_unregister(&g_leds_data[i]->cdev);            cancel_work_sync(&g_leds_data[i]->work);            kfree(g_leds_data[i]);            g_leds_data[i] = NULL;        }    }    return ret;}

——–》 下面来详细分析上面3个函数,先看mt65xx_led_set

static void mt65xx_led_set(struct led_classdev *led_cdev, enum led_brightness level){    struct mt65xx_led_data *led_data = container_of(led_cdev, struct mt65xx_led_data, cdev);    if (strcmp(led_data->cust.name, "lcd-backlight") == 0) { 如果是背光,做些特殊处理#ifdef CONTROL_BL_TEMPERATURE        mutex_lock(&bl_level_limit_mutex);        current_level = level;        /* LEDS_DRV_DEBUG("brightness_set_cust:current_level=%d\n", current_level); */        if (0 == limit_flag) {            last_level = level;            /* LEDS_DRV_DEBUG("brightness_set_cust:last_level=%d\n", last_level); */        } else {            if (limit < current_level) {                level = limit;                LEDS_DRV_DEBUG("backlight_set_cust: control level=%d\n", level);            }        }        mutex_unlock(&bl_level_limit_mutex);#endif    }    mt_mt65xx_led_set(led_cdev, level);  }

———》mt_mt65xx_led_set

void mt_mt65xx_led_set(struct led_classdev *led_cdev, enum led_brightness level){    struct mt65xx_led_data *led_data =        container_of(led_cdev, struct mt65xx_led_data, cdev);    //unsigned long flags;    //spin_lock_irqsave(&leds_lock, flags);#ifdef CONFIG_MTK_AAL_SUPPORT       if(led_data->level != level)    {        led_data->level = level;        if(strcmp(led_data->cust.name,"lcd-backlight") != 0)        {            LEDS_DEBUG("[LED]Set NLED directly %d at time %lu\n",led_data->level,jiffies);            schedule_work(&led_data->work);                     }        else        {            LEDS_DEBUG("[LED]Set Backlight directly %d at time %lu\n",led_data->level,jiffies);            //mt_mt65xx_led_set_cust(&led_data->cust, led_data->level);             disp_aal_notify_backlight_changed( (((1 << MT_LED_INTERNAL_LEVEL_BIT_CNT) - 1)*level + 127)/255 );        }    }#else                           // do something only when level is changed    if(led_data->level != level)    {        led_data->level = level;        if(strcmp(led_data->cust.name,"lcd-backlight") != 0)  非背光,直接到 在工作队列中处理,WORK        {            LEDS_DEBUG("[LED]Set NLED directly %d at time %lu\n",led_data->level,jiffies);                schedule_work(&led_data->work);        }        else        {                LEDS_DEBUG("[LED]Set Backlight directly %d at time %lu\n",led_data->level,jiffies);            if(MT65XX_LED_MODE_CUST_BLS_PWM == led_data->cust.mode)  背光,直接设置。 背光相应快。            {                mt_mt65xx_led_set_cust(&led_data->cust, ((((1 << MT_LED_INTERNAL_LEVEL_BIT_CNT) - 1)*level + 127)/255));            }            else            {                mt_mt65xx_led_set_cust(&led_data->cust, led_data->level);           }    }    }    //spin_unlock_irqrestore(&leds_lock, flags);#endif//    if(0!=aee_kernel_Powerkey_is_press())//      aee_kernel_wdt_kick_Powkey_api("mt_mt65xx_led_set",WDT_SETBY_Backlight); }

—–》调用WORK,会直接到WORK函数中处理,即mt_mt65xx_led_work

void mt_mt65xx_led_work(struct work_struct *work){    struct mt65xx_led_data *led_data =        container_of(work, struct mt65xx_led_data, work);    LEDS_DEBUG("[LED]%s:%d\n", led_data->cust.name, led_data->level);    mutex_lock(&leds_mutex);    mt_mt65xx_led_set_cust(&led_data->cust, led_data->level);    mutex_unlock(&leds_mutex);;}可以看出 实际上还是调用的 mt_mt65xx_led_set_cust处理,上面背光的特殊处理确实只是为了速度更快写而已。

———-》

int mt_mt65xx_led_set_cust(struct cust_mt65xx_led *cust, int level){        switch (cust->mode) {  根据不同的模式来操作        case MT65XX_LED_MODE_PWM:            if(strcmp(cust->name,"lcd-backlight") == 0)            {                bl_brightness_hal = level;                if(level == 0)                {                    mt_pwm_disable(cust->data, cust->config_data.pmic_pad);                }else                {                    if (BacklightLevelSupport == BACKLIGHT_LEVEL_PWM_256_SUPPORT)                        level = brightness_mapping(tmp_level);                    else                        level = brightness_mapto64(tmp_level);                      mt_backlight_set_pwm(cust->data, level, bl_div_hal,&cust->config_data);                }                bl_duty_hal = level;                }else            {                if(level == 0)                {                    led_tmp_setting.nled_mode = NLED_OFF;                    mt_led_set_pwm(cust->data,&led_tmp_setting);                    mt_pwm_disable(cust->data, cust->config_data.pmic_pad);                }else                {                    led_tmp_setting.nled_mode = NLED_ON;                    mt_led_set_pwm(cust->data,&led_tmp_setting);                }            }            return 1;        case MT65XX_LED_MODE_GPIO:  用函数指针去做相应的操作            LEDS_DEBUG("brightness_set_cust:go GPIO mode!!!!!\n");            return ((cust_set_brightness)(cust->data))(level);        case MT65XX_LED_MODE_PMIC:            //for button baclight used SINK channel, when set button ISINK, don't do disable other ISINK channel            if((strcmp(cust->name,"button-backlight") == 0)) {                if(button_flag==false) {                    switch (cust->data) {                        case MT65XX_LED_PMIC_NLED_ISINK0:                            button_flag_isink0 = 1;                            break;                        case MT65XX_LED_PMIC_NLED_ISINK1:                            button_flag_isink1 = 1;                            break;                        case MT65XX_LED_PMIC_NLED_ISINK2:                            button_flag_isink2 = 1;                            break;                        case MT65XX_LED_PMIC_NLED_ISINK3:                            button_flag_isink3 = 1;                            break;                        default:                            break;                    }                    button_flag=true;                }            }                               return mt_brightness_set_pmic(cust->data, level, bl_div_hal);  PMIC的        case MT65XX_LED_MODE_CUST_LCM:        if (strcmp(cust->name, "lcd-backlight") == 0) {                bl_brightness_hal = level;            }            LEDS_DEBUG("brightness_set_cust:backlight control by LCM\n");            return ((cust_brightness_set)(cust->data))(level, bl_div_hal);  可以自定义背光的        case MT65XX_LED_MODE_CUST_BLS_PWM:  实际上背光用的是 这个: MT65XX_LED_MODE_CUST_BLS_PWM        if (strcmp(cust->name, "lcd-backlight") == 0) {                bl_brightness_hal = level;            }            return ((cust_set_brightness)(cust->data))(level);        case MT65XX_LED_MODE_NONE:        default:            break;    }}

————-》 mt65xx_blink_set 分析

static int mt65xx_blink_set(struct led_classdev *led_cdev,            unsigned long *delay_on, unsigned long *delay_off){    if (mt_mt65xx_blink_set(led_cdev, delay_on, delay_off)) {        return -1;    } else {        return 0;    }}

———-》

int  mt_mt65xx_blink_set(struct led_classdev *led_cdev,             unsigned long *delay_on,             unsigned long *delay_off){    struct mt65xx_led_data *led_data =        container_of(led_cdev, struct mt65xx_led_data, cdev);    static int got_wake_lock = 0;    struct nled_setting nled_tmp_setting = {0,0,0};    // only allow software blink when delay_on or delay_off changed    if (*delay_on != led_data->delay_on || *delay_off != led_data->delay_off) {        led_data->delay_on = *delay_on;        led_data->delay_off = *delay_off;        if (led_data->delay_on && led_data->delay_off) { // enable blink            led_data->level = 255; // when enable blink  then to set the level  (255)            //AP PWM all support OLD mode             if(led_data->cust.mode == MT65XX_LED_MODE_PWM)            {                nled_tmp_setting.nled_mode = NLED_BLINK;                nled_tmp_setting.blink_off_time = led_data->delay_off;                nled_tmp_setting.blink_on_time = led_data->delay_on;                mt_led_set_pwm(led_data->cust.data,&nled_tmp_setting);  PWM硬件模块能有此模式,配置好后不需要CPU参与。                return 0;            }            else if((led_data->cust.mode == MT65XX_LED_MODE_PMIC) && (led_data->cust.data == MT65XX_LED_PMIC_NLED_ISINK0                || led_data->cust.data == MT65XX_LED_PMIC_NLED_ISINK1 || led_data->cust.data == MT65XX_LED_PMIC_NLED_ISINK2                 || led_data->cust.data == MT65XX_LED_PMIC_NLED_ISINK3))            {                nled_tmp_setting.nled_mode = NLED_BLINK;                nled_tmp_setting.blink_off_time = led_data->delay_off;                nled_tmp_setting.blink_on_time = led_data->delay_on;                mt_led_blink_pmic(led_data->cust.data, &nled_tmp_setting);                return 0;            }                           else if (!got_wake_lock) {  没有实现,需要CPU参与的,需要获取锁,实际上GPIO BLINK可以在这里实现。                wake_lock(&leds_suspend_lock);                got_wake_lock = 1;            }        }        else if (!led_data->delay_on && !led_data->delay_off) { // disable blink            //AP PWM all support OLD mode             if(led_data->cust.mode == MT65XX_LED_MODE_PWM)            {                nled_tmp_setting.nled_mode = NLED_OFF;                mt_led_set_pwm(led_data->cust.data,&nled_tmp_setting);                return 0;            }            else if((led_data->cust.mode == MT65XX_LED_MODE_PMIC) && (led_data->cust.data == MT65XX_LED_PMIC_NLED_ISINK0                || led_data->cust.data == MT65XX_LED_PMIC_NLED_ISINK1 || led_data->cust.data == MT65XX_LED_PMIC_NLED_ISINK2                 || led_data->cust.data == MT65XX_LED_PMIC_NLED_ISINK3))            {                mt_brightness_set_pmic(led_data->cust.data, 0, 0);                return 0;            }                   else if (got_wake_lock) {                wake_unlock(&leds_suspend_lock);                got_wake_lock = 0;            }        }        return -1;    }    // delay_on and delay_off are not changed    return 0;}
0 0
原创粉丝点击