1 驱动部分

 这部分主要根据驱动源码的初始化部分进行分析

1.1 mtk_leds_drv

  路径:/kernel-4.14/drivers/misc/mediatek/leds/mtk_leds_drv.c

mt65xx_leds_probe→ *cust_led_list = mt_get_cust_led_list → get_cust_led_dtsi //根据leds_name数组以及设备树初始化struct cust_mt65xx_led数组把地址返回给cust_led_list,mode,data参数都在mt_get_cust_led_list进行赋值→ g_leds_data //根据cut_led_list初始化g_leds_data→ led_classdev_register(&pdev->dev, &g_leds_data[i]→cdev)  → device_create_with_groups //sys/calss/leds下注册leds_name目录以及注册attrs 文件节点→ list_add_tail(&led_cdev->node, &leds_list); //添加到led_list,led_cdev是 g_leds_data[i]→cdev→ led_init_core //初始化led_cdev的set_brightness_work 回调函数:set_brightness_work//以及初始化led_cdev的set_brightness_work, 回调函数:led_timer_function//私有数据设置为led_cdev→ led_trigger_set_default(led_cdev)//在led_cdev->default_trigger不为空的情况下遍历trigger_list拿到trigger//使用led_cdev->default_trigger与trigger->name属性进行匹配并设置//匹配成功后调用led_trigger_set设置启动对应trigger//led_cdev->trigger,本驱动中default_trigger为空直接返回主要的结构体参数初始化如下:leds_name初始化
char *leds_name[TYPE_TOTAL] = {"red","green","blue","jogball-backlight","keyboard-backlight","button-backlight","lcd-backlight",};cust_led_list 初始化:
struct cust_mt65xx_led {.name→  leds_name[i].mode→  “led_mode”//设备树中定义.data → “data”
.config_data.clock_source //”pwm_config”的0~4bit分别初始化
config_data.div
config_data.low_duration
config_data.High_duration
config_data.pmic_pad
}
/*当mode是以下的参数结构体中的data会被重新赋值关系如下
mode:MT65XX_LED_MODE_CUST_LCM ,data: mtkfb_set_backlight_level
mode: MT65XX_LED_MODE_CUST_BLS_PWM, data: disp_bls_set_backligh */g_leds_data 初始化:
struct mt65xx_led_data {                                                  .cdev {.brightness_set = mt65xx_led_set.blink_set = mt65xx_blink_set.name = cust_led_list[i].name.set_brightness_work.blink_timer} struct cust_mt65xx_led cust → cust_led_list struct work_struct work → mt_mt65xx_led_workint level;int delay_on;int delay_off;}

1.2 led-class

路径:/kernel-4.14/drivers/leds/led-class.c

leds_init→ leds_class = class_create(THIS_MODULE, "leds")  //创建类→ leds_class->pm = &leds_class_dev_pm_ops; //初始化 pm→  leds_class->dev_groups = led_groups;
/* 初始化dev_groups,mtk_leds_drv驱动 调用led_classdev_register注册attrs文件节点时使用该参数,led-class主要是创建leds类以及提供attrs操作集合 */

1.3 led-trigger

路径:/kernel-4.14/drivers/leds/trigger/./ledtrig-timer.c

这里主要分析 timer这个trigger,这个模块主要实现led的闪烁功能

led_trigger_register(&timer_led_trigger) //注册led_trigger→ list_add_tail(&trig->next_trig, &trigger_list); //添加到链表trigger_list→ list_for_each_entry(led_cdev, &leds_list, node) → if (!led_cdev->trigger && led_cdev->default_trigger &&!strcmp(led_cdev->default_trigger, trig->name)) //遍历leds_list,led_cedv的trigger,default_trigger与trig->name作匹配→ led_trigger_set(led_cdev, trig); //对 led_cdev->trigger进行设置/* mtk_leds_drv.c 驱动中g_leds_data[i]→cdev.default_trigger为空所以此处 led_trigger_set函数并未对其操作 ledtrig-timer 主要就是向trigger_list链表里面添加timer_led_trigger */主要结构体参数:static struct led_trigger timer_led_trigger {.name → “timer”.activate → timer_trig_activate.deactivate  →  timer_trig_deactivate.next_trig  → trigger_list
}

 框架图

1.4 操作流程

这部分主要集中分析设置背光以及设置闪烁的操作进行分析

1.4.1 设置背光

echo 255 > /sys/class/leds/xxx/brightness  //设置背光亮度→ brightness_store→ struct led_classdev *led_cdev = dev_get_drvdata(dev)//从dev->driver_date获取struct led_classdev→  led_set_brightness(led_cdev, state)→ led_set_brightness_nosleep(led_cdev, brightness)→ led_set_brightness_nopm(led_cdev, led_cdev->brightness)→ __led_set_brightness(led_cdev, value)→  led_cdev→brightness_set(led_cdev, value)/* mtk_leds_drv在对g_leds_data初始化时 struct led_classdev cdev 的
brightness_set = mt65xx_led_set*/
即: led_cdev→brightness_set→ mt65xx_led_set → mt_mt65xx_led_set   //背光mode:MT65XX_LED_MODE_CUST_BLS_PWM→ mt_mt65xx_led_set_cust //依据mode: MT65XX_LED_MODE_CUST_BLS_PWM  → ((cust_brightness_set) (cust->data)) (level, bl_div_hal) //data参数在调用get_cust_led_dtsi()函数时依据mode进行初始化即调用:disp_bls_set_backlight :设置背光

1.4.2 设置闪烁


echo timer > ./sys/calss/leds/xxx/trigger //启动定时器触发器→ led_trigger_store→ struct led_classdev *led_cdev = dev_get_drvdata(dev)//从dev->driver_date获取struct led_classdev→ list_for_each_entry(trig, &trigger_list, next_trig)/*遍历 trigger_list 使用 ”timer ”  与 led_trigger的name 元素进行配对,与timer_led_trigger 进行匹配 */→ led_trigger_set(led_cdev, trig) → trig→activate(led_cdev)  //调用触发器的 activate timer_led_trigger                                                                .activate: timer_trig_activatestatic void timer_trig_activate(struct led_classdev *led_cdev)→ device_create_file(led_cdev->dev, &dev_attr_delay_on)→ device_create_file(led_cdev->dev, &dev_attr_delay_off)/* 创建delay_on以及delay_off文件节点分别用于设置led_cdev->blink_delay_on 以及 led_cdev->blink_delay_off用于实现开和关的延时时间 */→ led_blink_set(led_cdev, &led_cdev→blink_delay_on,&led_cdev→blink_delay_off);led_blink_set()→ led_blink_setup(led_cdev, delay_on, delay_off)→ if(..... && !led_cdev→blink_set(led_cdev, delay_on, delay_off))  /*调用led_cdev→blink_set 进行设置 此处直接返回-1调用led_set_software_blinkmtk_leds_drv初始化阶段blink_set为 mt65xx_blink_set*/ → led_set_software_blink→ mod_timer(&led_cdev->blink_timer, jiffies + 1) //启动定时器//mtk65xx_leds_probe阶段的led_init_core函数对blink_timer进行了初始化,//回调函:led_timer_functionvoid led_timer_function(unsigned long data)//实现闪烁功能→ if (!brightness)    //根据当前数值进行反向赋值以及设置延迟时间  brightness = led_cdev->blink_brightness;delay = led_cdev->blink_delay_on;→ elsebrightness = LED_OFF;delay = led_cdev->blink_delay_off;→ led_set_brightness_nosleep(led_cdev, brightness); //设置亮灭→ mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay))//再次启动定时器进入下一轮反向操作/* mt65xx_blink_set:
led_data->delay_on 以及led_data->delay_off
其中都不为0或者其中之一不为0会根据mode值经进行设置,当都为0时
直接返回-1,目前支持的mode值为:MT65XX_LED_MODE_PWM以及MT65XX_LED_MODE_PMIC */

操作流程图

2 hal 层

这层主要对驱动生成的 /sys/class/leds/目录下的文件进行封装一些操作接口

2.1 lights.c

路径: vendor/mediatek/proprietary/hardware/liblights/lights.c

主要结构体
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,}static struct hw_module_methods_t lights_module_methods = {.open =  open_lights,};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);  //定义函数指针→ if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))→ set_light = set_light_backlight; ......→ else if (0 == strcmp(LIGHT_ID_BATTERY, name))→ set_light = set_light_battery;//根据传入参数name的不同对 set_light进行不同的赋值→ dev->set_light = set_light→ *device = (struct hw_device_t*)dev;

name 与 set_Light回调函数赋值的对应关系:

name ID 回调函数
“backlight” LIGHT_ID_BACKLIGHT  set_light_backlight
“keyboard” LIGHT_ID_KEYBOARD set_light_keyboard
“buttons" LIGHT_ID_BUTTONS  set_light_buttons
“battery”: LIGHT_ID_BATTERY set_light_battery
“notification” LIGHT_ID_NOTIFICATIONS set_light_notifications
“attention” LIGHT_ID_ATTENTION  set_light_attention
     

这里主要分析  LIGHT_ID_BACKLIGHT:set_light_backlight设置背光的接口函数

2.1.1 LIGHT_ID_BACKLIGHT:set_light_backlight

set_light_backlight(struct light_device_t* dev, struct light_state_t const* state)→ write_int(LCD_FILE, brightness); //write_int 通过标准的文件io:write()操作写入背光值//LCD_FILE :"/sys/class/leds/lcd-backlight/brightness"

2.1.2 LIGHT_ID_BATTERY:set_light_battery

set_light_battery(struct light_device_t* dev,struct light_state_t const* state)→ set_speaker_light_locked(dev, state)//调用该接口实现三色灯的亮灭以及闪烁static int set_speaker_light_locked(__attribute__((__unused__)) struct light_device_t* dev,   struct light_state_t const* state)
{→ switch (state->flashMode)  //根据flashMode 对onMS以及offMS两个闪烁亮灭时长进行赋值case LIGHT_FLASH_TIMED:onMS = state->flashOnMS;offMS = state->flashOffMS;.....→ colorRGB = state->color;.....
//解析state→color参数获取三色灯的配置情况 Color: 0xFF FF FF FF: Alpha  R   G  B→ red = (colorRGB >> 16) & 0xFF;→ green = (colorRGB >> 8) & 0xFF;→ blue = colorRGB & 0xFF;.....   → if (red) {blink_green(0, 0, 0);blink_blue(0, 0, 0);blink_red(red, onMS, offMS);  }
//根据rgb对应的参数是否为true调用blink_xxx(xxx, onMS, offMS)设置亮灭以及闪烁
…...
}blink_red(int level, int onMS, int offMS)的内部具体操作如下:
{→ nowStatus 参数 0: off , 1: blink(配置闪烁), 2常亮→ if (preStatus == nowStatus) //状态相同时直接返回return -1;→ nowStatus == 0  //RED_LED_FILE: "/sys/class/leds/red/brightness"    → write_int(RED_LED_FILE, 0) //进行灭灯操作        → nowStatus == 1 → write_str(RED_TRIGGER_FILE, "timer"); //往/sys/class/leds/red/trigger 写入 "timer" 启动tiemr触发器的activate操作→ while (((access(RED_DELAY_OFF_FILE, F_OK) == -1) || (access(RED_DELAY_OFF_FILE, R_OK|W_OK) == -1))→ led_wait_delay(5)//等待 delay_off以及delay_on文件的生成→ write_int(RED_DELAY_OFF_FILE, offMS) //设置delay_off的时长→ write_int(RED_DELAY_ON_FILE, onMS) //设置delay_on的时长→ nowStatus其他状态下→ write_str(RED_TRIGGER_FILE, "none");//关掉所有触发器→ write_int(RED_LED_FILE, 255); //亮灯操作
}

3 hidl 层

路径 /vendor/mediatek/proprietary/hardware/liblights/2.0/default

3.1 Light.cpp

Light.cpp:对hal :vendor/mediatek/proprietary/hardware/liblights/lights.c文件提供的一些接口进一步封装

3.1.1 hal中hw_module_t的获取

light_device_t* getLightDevice(const char* name)→ hw_get_module (LIGHTS_HARDWARE_MODULE_ID, &hwModule); //获取hw_module_t→ hwModule->methods->open(hwModule, name,reinterpret_cast<hw_device_t**>     (&lightDevice))
/* 调用lights_module_methods中的open_lights函数 ,open_lights函数中的(struct hw_device_t*)dev初始化完后赋值给了lightDevice,通过参数name传入methods->open最终让open_lights函数对set_light的回调对象进行初始化 */getLightDevice的调用:
ILight* HIDL_FETCH_ILight(const char* /* name */) 
{→ for(auto const &pair : kLogicalLights) {  Type type = pair.firstconst char* name = pair.second; //name 参数被赋值 LIGHT_ID_xxxxlight_device_t* light = getLightDevice(name);  //通过for循环调用 getLightDevice对所有类型的设备进行初始化if (light != nullptr) {lights[type] = light;  //初始化的light保存在lights数组中}……………return new Light(std::move(lights));}
}Light::Light(std::map<Type, light_device_t*> &&lights): mLights(std::move(lights)) {}  // 根据lights对mLights

通过for循环 调用getLightDevice(name)函数返回值light_device_t*保存在mLights中,通过不同的type索引号即可拿到对应的light_device_t结构体参数进一步通过结构体参数调用 set_Light回调函数, type索引号对应参数name(LIGHT_ID_xxx)通过getLightDevice函数对应对应的set_Light

type与LIGHT_ID_XXX的对应关系根据kLogicalLights参数的定义 如下表

Type ID(name)
Type::BACKLIGHT LIGHT_ID_BACKLIGHT
Type::KEYBOARD LIGHT_ID_KEYBOARD
Type::BUTTONS LIGHT_ID_BUTTONS
Type::BATTERY LIGHT_ID_BATTERY
Type::NOTIFICATIONS LIGHT_ID_NOTIFICATIONS
Type::ATTENTION LIGHT_ID_ATTENTION
Type::BLUETOOTH LIGHT_ID_BLUETOOTH
Type::WIFI LIGHT_ID_WIFI

3.1.2 hidl 设置灯光的接口

Return<Status> Light::setLight(Type type, const LightState& state)→ auto it = mLights.find(type);  //根据Type定位 mLights→ light_device_t* hwLight = it→second; //通过 mLights获取light_device_t→ light_state_t legacyState { //参数进行初始化.color = state.color,.flashMode = static_cast<int>(state.flashMode),.flashOnMS = state.flashOnMs,.flashOffMS = state.flashOffMs,.brightnessMode = static_cast<int>(state.brightnessMode),};→ hwLight->set_light(hwLight, &legacyState) //通过set_light回调
/*
整个setLight 流程根据Type::XXX 调用对应的 LIGHT_ID_xxx的 set_light回调函数例:Type type参数: Type::BATTERY→  定位  mLights→  mLight 找到 hwLight →  通过 hwLight->set_light 调用到对应LIGHT_ID_BATTERY的set_light回调函数→  LIGHT_ID_BATTERY的set_light回调函数即hal层的 set_light_battery
*/

4. jni 层

路径frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp

jni层主要是对package android.hardware.light@2.0 提供的接口进一步封装

tatic const JNINativeMethod method_table[] = {{ "setLight_native", "(IIIIII)V", (void*)setLight_native },}; //这里主要提供的接口是setLight_native,所以主要对此进行分析static void setLight_native( JNIEnv* /* env */, jobject /* clazz */,  jint light, jint colorARGB,jint flashMode, jint onMS, jint offMS, jint brightnessMode)
{→ Type type = static_cast<Type>(light);  //类型转换为Type→ LightState state = constructState( colorARGB, flashMode, onMS, offMS, brightnessMode);
//根据 colorARGB, flashMode, onMS, offMS, brightnessMode这一系列参数对state的元素进行赋值→ sp<ILight> hal = Ilight::getService()//获取light-hal-2-0 Service用于后续调用其提供的接口→ Return<Status> ret = hal->setLight(type, state) ; //调用hidl层对接的接口
}

5 java层

路径:framework//base/services/core/java/com/android/server/lights

设置led 灯显示:setColor(int color)→  setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0)
设置led闪烁:setFlashing(int color, int mode, int onMS, int offMS)→ setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER)private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode)→ setLight_native(mId, color, mode, onMS, offMS, brightnessMode); //调用jni的接口,mId会在JNI层转化为Type类型/* setLight_native第一个参数mId即 hidl层用于定位set_light回调函数的typemId 与type对应关系通过以下步骤完成 */1.public LightsService(Context context)→ for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++)→ mLights[i] = new LightImpl(context, i)  //通过for循环 new LightImpl对象 ,LIGHT_ID_xxx与mLights[i]的i对应2.private LightImpl(Context context, int id) → mId = id 
/* LightImpl会对class LightImpl的元素的mId元素进行初始化即  LightImpl  mLights[i]的索引i 与 mLights[i] .mId对应所以操作流程是先获取对应的 mLights[i]对象再通过 setLightLocked方法设置亮度或者闪烁 */获取 mLights对象的方法:
public Light getLight(int id)→ if (0 <= id && id < LIGHT_ID_COUNT)→ return mLights[id]/* 以BatteryService.java中这部分操作为例:BatteryService.java中
updateLightsLocked()会根据电量的情况调用mBatteryLight.setFlashing以及mBatteryLight.setColor设置三色灯 */
mBatteryLight操作流程如下:
1  BatteryService初始化阶段获取LIGHT_ID_BATTERY的mLights对象
public BatteryService(Context context)→ mLed = new Led(context, getLocalService(LightsManager.class))  public Led(Context context, LightsManager lights)→  mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
//获取id: LIGHT_ID_BATTERY的 mLights[i]对象
2 updateLightsLocked()中调用setColor以及setFlashing

MTK Android Led框架分析相关推荐

  1. Android DRM框架分析

    Android DRM框架分析 1. DRM框架 2.DRM架构 3.DRM插件 4. 实现 5.DRM插件详情 6.MediaDrm 7.MediaCrypto 8.参考链接 1. DRM框架 An ...

  2. Android WIFI框架分析(1)

    趁做Android WIFI驱动移植,对Android WIFI框架做了深刻的分析,并做此文档共同学习. 对上层WIFI的应用,基本流程为:(1)WIFI初始化  (2)Wifi启动      (3) ...

  3. Android灯光系统框架分析

    首先别人的APP要能直接访问到你写的硬件或者不经过任何修改的APP能直接使用你的驱动,就需要使用系统自带的JNI,所以我们需要写出符合系统自带JNI文件的HAL文件和驱动程序,下面具体分析一个这个HA ...

  4. android输入法框架分析,Android与iOS输入法开发框架比较谈

    对于任何一个使用手机的人,有一样工具是不可能缺少的,它既不是微信之类的社交工具,也不是支付宝之类的金融工具(事实上这两个都越界了),而是输入法这样的输入工具.更重要的是,输入法还是一种特权工具,因为它 ...

  5. Android Framework框架分析

    转自:微点阅读  https://www.weidianyuedu.com/content/2617738210126.html Android framework analysis (partI z ...

  6. Android RIL框架分析

    1.RIL框架 RIL,Radio Interface Layer.本层为一个协议转换层,提供Android Telephony与无线通信设备之间的抽象层. Android RIL位于Telephon ...

  7. android输入法框架分析,Android输入法架构.ppt

    Android输入法架构 Android输入法架构 裴润升 oppo开发三部 输入法 为系统中其他模块提供输入功能的模块 1 硬键盘 2 软键盘 3 手写 4 语音输入 问题: 输入法和应用分属不同的 ...

  8. android nfc框架分析,Android NFC架构分析

    原创:木头月亮 来自:http://blog.csdn.net/mutouyueliang/archive/2011/03/08/6232028.aspx Android中对NFC的实现代码分布在如下 ...

  9. Android以太网框架情景分析之启动简介

            Android以太网框架情景分析之启动简介 Android网络框架分析系列文章目录: Android P适配以太网功能开发指南 Android以太网框架情景分析之启动简介 Androi ...

最新文章

  1. 马莉 - 人神共愤的处女座
  2. 解决Tomcat v8.0 Server at localhost failed to start.
  3. Silverlight编程模型
  4. 豆瓣9.2!为什么这款剧最能打动大家?真相都在数据里!
  5. Coolpad Y1刷机方法
  6. HTTP权威指南-概述
  7. WinAPI: GetNextWindow - 获取指定窗口Z上或Z下的窗口的句柄
  8. BT1120,模拟视频输入输出格式
  9. 《LeetCode刷题C/C++版答案》pdf出炉,白瞟党乐坏了
  10. Java爬虫学习——实例:获取起点中文网站小说并保存成txt文件
  11. 通过apizza生成python接口测试代码
  12. 解决Chrome浏览器主页被hao123、360和2345篡改简单有效方法
  13. 【项目管理/PMP/PMBOK第六版/新考纲】项目资源管理/权力理论/管理方格理论/领导生命周期理论/激励理论/马斯洛需求层次理论/赫兹伯格的双因素理论/X理论和Y理论/弗鲁姆的期望理论
  14. 猫哥教你写爬虫 047--scrapy框架
  15. 如何从Docker容器内部获取Docker主机的IP地址
  16. 点击地图获取经纬度(基于腾旭地图api)
  17. html5行高有什么用,css行高line-height的一些深入理解及应用
  18. 试用期、加班时间、加班补偿——职场常见知识《劳动法》
  19. case zhen语句_case when zhen else (Sql 2005)
  20. SQL Server提高事务复制效率优化(二)快照初始化优化

热门文章

  1. python永久删除文件_Python彻底删除文件夹及其子文件方式
  2. Xilinx ZCU106开发详解(Xilinx Zynq UltraScale+ MPSoC)
  3. 浪漫的星空,表白的弹窗,python制作
  4. 关于安装mathtype后找不到电脑预装office2016安装路径的问题
  5. android 实现Sqlite的增删改查及系统的登录注册功能
  6. .[转] 全国主体功能区规划图
  7. vmware win7虚拟机运行异常卡顿问题解决
  8. 深入理解Spring----PostConstruct和PreDestroy
  9. Android面试经验一:
  10. html的网页制作需要哪些知识,网页制作之HTML基础知识