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();
blink
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
- MTK LIGHT 代码分析
- mtk battery_common代码分析
- MTK UART驱动代码分析
- MTK I2C驱动代码分析
- MTK UART驱动代码分析
- MTK light sensor驱动
- MTK穿戴设备开发代码分析
- MTK平台 UART驱动代码分析
- mtk android 4.4 audio framework 代码分析(未完成)
- MTK手机皮套驱动实现驱动代码分析
- mtk android 4.4 audio framework 代码分析(未完成)
- Android5.0 MTk Camera HAL层代码分析
- MTK手机短信漏洞代码
- mtk 基站定位代码
- MTK代码全集
- MTK android代码架构
- MTK resgen编译分析
- MTK 通话记录分析
- java.lang.UnsupportedClassVersionError: Unsupported major.minor version 51.0的错误
- hibernate项目环境步骤
- jQuery.extend()与 jQuery.fn.extend()比较
- c++异常处理机制 (try—throw—catch的使用)
- sql语句中较为重要的查询逻辑
- MTK LIGHT 代码分析
- 使用Java编写并运行Spark应用程序
- HDU 1850解题报告
- libpcap 使用 any interface的bug:SIOCGIFHWADDR: No such device
- Service的远程调用
- ruby日常
- 关于java.lang.NoSuchMethodError: android.view.View.setBackground
- 四大湖问题(枚举法)
- Oracle 11g R2 64bit 安装(Oracle linux 7实践,帮助新手安装oracle)