分类: Linux驱动 Android系统 287人阅读评论(0)收藏 举报

目录(?)[+]

  1. Android的Setting
  2. Android的背光JNI层
  3. Android的背光HAL层
  4. Linux的背光内核层
  5. Linux的背光驱动层
  6. 总结

其实Android的底层就是Linux,所以其驱动本质就是Linux驱动,但是这些Linux驱动是服务上层Android的,所以需遵循上Android的一些接口规范。所以涉及到的Android驱动都应应密切关注上层传递的接口。本文介绍的LCD背光驱动就是从上层一直往下层展现,但是笔者毕竟不是专注于Android上层,碍于知识不充裕,所以对上层的东西介绍得相对简单。

1.Android的Setting

Android的设置里面管理了Andoird系统的所有设置,其中当然包括了屏幕亮度设置。Setting的源码目录在:mydroid/packages/apps/Settings/src/com/android/settings
亮度设置的java源文件在:mydroid/packages/apps/Settings/src/com/android/settings/BrightnessPreference.java
打开这个文件看到:[java] view plain copy print ?
  1. publicclassBrightnessPreferenceextendsSeekBarDialogPreferenceimplements
  2. SeekBar.OnSeekBarChangeListener,CheckBox.OnCheckedChangeListener{
  3. privateSeekBarmSeekBar;
  4. privateCheckBoxmCheckBox;
  5. privateintmOldBrightness;
  6. privateintmOldAutomatic;
  7. privatebooleanmAutomaticAvailable;
  8. privatebooleanmRestoredOldState;
  9. //Backlightrangeisfrom0-255.Needtomakesurethatuser
  10. //doesn'tsetthebacklightto0andgetstuck
  11. privateintmScreenBrightnessDim=
  12. ...
public class BrightnessPreference extends SeekBarDialogPreference implements        SeekBar.OnSeekBarChangeListener, CheckBox.OnCheckedChangeListener {    private SeekBar mSeekBar;    private CheckBox mCheckBox;    private int mOldBrightness;    private int mOldAutomatic;    private boolean mAutomaticAvailable;    private boolean mRestoredOldState;    // Backlight range is from 0 - 255. Need to make sure that user    // doesn't set the backlight to 0 and get stuck    private int mScreenBrightnessDim =...
Android的最上层已经将背光亮度量化为了[0,255]个等级,并且提示注意不要设置为0,所以在进行最低层的背光驱动编写时,可以合理按这个范围部署背光的亮度。

2.Android的背光JNI层

背光的JNI层源码在:mydroid/frameworks/base/services/jni/com_android_server_LightsService.cpp
这一层就是调用HAL层的方法,为上一层实现一个设置亮度接口。

3.Android的背光HAL层

Java App和JNI一般是google维护的,所以源码位置相对固定,HAL有产品商开发维护的,所以位置是不固定的,看产品上喜好,笔者使用的TI OMAP4平台,背光的HAL层代码就在:mydroid/device/ti/xxx_product/liblights/light.c
先浏览欣赏一下light.c先[cpp] view plain copy print ?
  1. /*
  2. *Copyright(C)2008TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. #defineLOG_TAG"lights"
  17. #include<cutils/log.h>
  18. #include<stdint.h>
  19. #include<string.h>
  20. #include<unistd.h>
  21. #include<errno.h>
  22. #include<fcntl.h>
  23. #include<pthread.h>
  24. #include<sys/ioctl.h>
  25. #include<sys/types.h>
  26. #include<hardware/lights.h>
  27. /******************************************************************************/
  28. staticpthread_once_tg_init=PTHREAD_ONCE_INIT;
  29. staticpthread_mutex_tg_lock=PTHREAD_MUTEX_INITIALIZER;
  30. charconst*constLCD_FILE
  31. ="/sys/class/leds/lcd-backlight/brightness";
  32. charconst*constKEYBOARD_FILE
  33. ="/sys/class/leds/keyboard-backlight/brightness";
  34. charconst*constCHARGING_LED_FILE
  35. ="/sys/class/leds/battery-led/brightness";
  36. /*RGBfiledescriptors*/
  37. charconst*constRED_LED_FILE
  38. ="/sys/class/leds/red/brightness";
  39. charconst*constRED_DELAY_ON_FILE
  40. ="/sys/class/leds/red/delay_on";
  41. charconst*constRED_DELAY_OFF_FILE
  42. ="/sys/class/leds/red/delay_off";
  43. charconst*constGREEN_LED_FILE
  44. ="/sys/class/leds/green/brightness";
  45. charconst*constGREEN_DELAY_ON_FILE
  46. ="/sys/class/leds/green/delay_on";
  47. charconst*constGREEN_DELAY_OFF_FILE
  48. ="/sys/class/leds/green/delay_off";
  49. charconst*constBLUE_LED_FILE
  50. ="/sys/class/leds/blue/brightness";
  51. charconst*constBLUE_DELAY_ON_FILE
  52. ="/sys/class/leds/blue/delay_on";
  53. charconst*constBLUE_DELAY_OFF_FILE
  54. ="/sys/class/leds/blue/delay_off";
  55. ...
/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#define LOG_TAG "lights"#include <cutils/log.h>#include <stdint.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <pthread.h>#include <sys/ioctl.h>#include <sys/types.h>#include <hardware/lights.h>/******************************************************************************/static pthread_once_t g_init = PTHREAD_ONCE_INIT;static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;char const*const LCD_FILE        = "/sys/class/leds/lcd-backlight/brightness";char const*const KEYBOARD_FILE        = "/sys/class/leds/keyboard-backlight/brightness";char const*const CHARGING_LED_FILE        = "/sys/class/leds/battery-led/brightness";/*RGB file descriptors */char const*const RED_LED_FILE        = "/sys/class/leds/red/brightness";char const*const RED_DELAY_ON_FILE        = "/sys/class/leds/red/delay_on";char const*const RED_DELAY_OFF_FILE        = "/sys/class/leds/red/delay_off";char const*const GREEN_LED_FILE        = "/sys/class/leds/green/brightness";char const*const GREEN_DELAY_ON_FILE        = "/sys/class/leds/green/delay_on";char const*const GREEN_DELAY_OFF_FILE        = "/sys/class/leds/green/delay_off";char const*const BLUE_LED_FILE        = "/sys/class/leds/blue/brightness";char const*const BLUE_DELAY_ON_FILE        = "/sys/class/leds/blue/delay_on";char const*const BLUE_DELAY_OFF_FILE        = "/sys/class/leds/blue/delay_off";...
[cpp] view plain copy print ?
  1. staticint
  2. set_light_backlight(structlight_device_t*dev,
  3. structlight_state_tconst*state)
  4. {
  5. interr=0;
  6. intbrightness=rgb_to_brightness(state);
  7. pthread_mutex_lock(&g_lock);
  8. err=write_int(LCD_FILE,brightness);
  9. pthread_mutex_unlock(&g_lock);
  10. returnerr;
  11. }
static intset_light_backlight(struct light_device_t* dev,        struct light_state_t const* state){    int err = 0;    int brightness = rgb_to_brightness(state);    pthread_mutex_lock(&g_lock);    err = write_int(LCD_FILE, brightness);    pthread_mutex_unlock(&g_lock);    return err;}
这里关注一下LCD背光的sys文件节点:"/sys/class/leds/lcd-backlight/brightness"疑问1:这个sys接口是谁约定的呢?疑问2:可不可以改这个接口呢?疑问3:为什么这里还有其他led的很多sys文件节点呢:先解释疑问3,因为一个Android设备,不只是有LCD背光的LED,还有可以有其他很多LED(当然也可以没有),所以这里一并实现了这些LED的HAL,产品商可以沿用这些HAL。先来试验一把:启动Android设备,在Setting里更改亮度,然后在串口命令行中或“adb shell"中运行命令cat /sys/class/leds/lcd-backlight/brightness,会发现Setting的更改后可以通过cat 显示Setting的更改。所以更加确认了这个"/sys/class/leds/lcd-backlight/brightness"接口是正确的。因为HAL层是和Linux Kernel交互的,所以这里如果能cat实现读取亮度等级,那么在Linux kernel层就一定实现了sysfs接口。

4.Linux的背光内核层

背光的内核层源码在:driver/leds/led-class.c这一层由内核开发者去维护,不用我们操心。看看它的init函数[cpp] view plain copy print ?
  1. staticint__initleds_init(void)
  2. {
  3. leds_class=class_create(THIS_MODULE,"leds");
  4. if(IS_ERR(leds_class))
  5. returnPTR_ERR(leds_class);
  6. leds_class->suspend=led_suspend;
  7. leds_class->resume=led_resume;
  8. leds_class->dev_attrs=led_class_attrs;
  9. return0;
  10. }
static int __init leds_init(void){leds_class = class_create(THIS_MODULE, "leds");if (IS_ERR(leds_class))return PTR_ERR(leds_class);leds_class->suspend = led_suspend;leds_class->resume = led_resume;leds_class->dev_attrs = led_class_attrs;return 0;}
好明显,正是由于它创建了sys class,名字为”leds“,所以上面的背光sys文件节点"/sys/class/leds/”就有了来由,那么剩下的“../lcd-backlight/brightness"又是怎么来的呢?看看一个注册led设备类的函数.[cpp] view plain copy print ?
  1. /**
  2. *led_classdev_register-registeranewobjectofled_classdevclass.
  3. *@parent:Thedevicetoregister.
  4. *@led_cdev:theled_classdevstructureforthisdevice.
  5. */
  6. intled_classdev_register(structdevice*parent,structled_classdev*led_cdev)
  7. {
  8. led_cdev->dev=device_create(leds_class,parent,0,led_cdev,
  9. "%s",led_cdev->name);
  10. if(IS_ERR(led_cdev->dev))
  11. returnPTR_ERR(led_cdev->dev);
  12. #ifdefCONFIG_LEDS_TRIGGERS
  13. init_rwsem(&led_cdev->trigger_lock);
  14. ...
/** * led_classdev_register - register a new object of led_classdev class. * @parent: The device to register. * @led_cdev: the led_classdev structure for this device. */int led_classdev_register(struct device *parent, struct led_classdev *led_cdev){led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,      "%s", led_cdev->name);if (IS_ERR(led_cdev->dev))return PTR_ERR(led_cdev->dev);#ifdef CONFIG_LEDS_TRIGGERSinit_rwsem(&led_cdev->trigger_lock);...
这个注册函数的接口最终会被我们要开发的背光驱动调用,这个接口在/sys/class/leds/下又创建了一个设备接口,名字是led_cdev->name。好明显这里的led_cdev->name应该就是”lcd-backlight“,究竟是不是真的这样呢?继续看。这个led-class.c在实现两个设备属性,看代码:[cpp] view plain copy print ?
  1. staticstructdevice_attributeled_class_attrs[]={
  2. __ATTR(brightness,0644,led_brightness_show,led_brightness_store),
  3. __ATTR(max_brightness,0444,led_max_brightness_show,NULL),
  4. #ifdefCONFIG_LEDS_TRIGGERS
  5. __ATTR(trigger,0644,led_trigger_show,led_trigger_store),
  6. #endif
  7. __ATTR_NULL,
  8. };
static struct device_attribute led_class_attrs[] = {__ATTR(brightness, 0644, led_brightness_show, led_brightness_store),__ATTR(max_brightness, 0444, led_max_brightness_show, NULL),#ifdef CONFIG_LEDS_TRIGGERS__ATTR(trigger, 0644, led_trigger_show, led_trigger_store),#endif__ATTR_NULL,};
看到了属性名字为”brightness“,这似乎越来越接近解释"/sys/class/leds/lcd-backlight/brightness"的由来了。

5.Linux的背光驱动层

Linux的背光驱动层就是完全由开发者去实现了,其实这层很简单,无非就是通过pwm实现设置背光。在这一层要注意将背光亮度量化为0~255,这是Android上层约定的。
这一层的采用Linux的platform device/driver 模型。它最终会调用Linux内核层leds-class.c的接口。看看它的probe函数片段:[cpp] view plain copy print ?
  1. structdisplay_led_data{
  2. structled_classdevpri_display_class_dev;
  3. structled_classdevsec_display_class_dev;
  4. structomap4_disp_led_platform_data*led_pdata;
  5. structmutexpri_disp_lock;
  6. structmutexsec_disp_lock;
  7. };
  8. staticintomap4_XXX_display_probe(structplatform_device*pdev)
  9. {
  10. intret;
  11. structdisplay_led_data*info;
  12. pr_info("%s:Enter\n",__func__);
  13. if(pdev->dev.platform_data==NULL){
  14. pr_err("%s:platformdatarequired\n",__func__);
  15. return-ENODEV;
  16. }
  17. info=kzalloc(sizeof(structdisplay_led_data),GFP_KERNEL);
  18. if(info==NULL){
  19. ret=-ENOMEM;
  20. returnret;
  21. }
  22. info->led_pdata=pdev->dev.platform_data;
  23. platform_set_drvdata(pdev,info);
  24. info->pri_display_class_dev.name="lcd-backlight";
  25. info->pri_display_class_dev.brightness_set=omap4_xxx_primary_disp_store;
  26. ...
  27. ret=led_classdev_register(&pdev->dev,
  28. &info->pri_display_class_dev);
  29. if(ret<0){
  30. pr_err("%s:Registerledclassfailed\n",__func__);
  31. kfree(info);
  32. returnret;
  33. }
  34. if(info->led_pdata->flags&LEDS_CTRL_AS_TWO_DISPLAYS){
  35. pr_info("%s:ConfiguringthesecondaryLED\n",__func__);
  36. info->sec_display_class_dev.name="lcd-backlight2";
  37. info->sec_display_class_dev.brightness_set=
  38. omap4_mirage_secondary_disp_store;
  39. info->sec_display_class_dev.max_brightness=LED_OFF;
  40. mutex_init(&info->sec_disp_lock);
  41. ret=led_classdev_register(&pdev->dev,
  42. &info->sec_display_class_dev);
  43. ...
struct display_led_data {struct led_classdev pri_display_class_dev;struct led_classdev sec_display_class_dev;struct omap4_disp_led_platform_data *led_pdata;struct mutex pri_disp_lock;struct mutex sec_disp_lock;};static int omap4_XXX_display_probe(struct platform_device *pdev){int ret;struct display_led_data *info;pr_info("%s:Enter\n", __func__);if (pdev->dev.platform_data == NULL) {pr_err("%s: platform data required\n", __func__);return -ENODEV;}info = kzalloc(sizeof(struct display_led_data), GFP_KERNEL);if (info == NULL) {ret = -ENOMEM;return ret;}info->led_pdata = pdev->dev.platform_data;platform_set_drvdata(pdev, info);info->pri_display_class_dev.name = "lcd-backlight";info->pri_display_class_dev.brightness_set = omap4_xxx_primary_disp_store;...ret = led_classdev_register(&pdev->dev,    &info->pri_display_class_dev);if (ret < 0) {pr_err("%s: Register led class failed\n", __func__);kfree(info);return ret;}if (info->led_pdata->flags & LEDS_CTRL_AS_TWO_DISPLAYS) {pr_info("%s: Configuring the secondary LED\n", __func__);info->sec_display_class_dev.name = "lcd-backlight2";info->sec_display_class_dev.brightness_set =omap4_mirage_secondary_disp_store;info->sec_display_class_dev.max_brightness = LED_OFF;mutex_init(&info->sec_disp_lock);ret = led_classdev_register(&pdev->dev,    &info->sec_display_class_dev);...

需关注这里设置了info->pri_display_class_dev.name = "lcd-backlight";,然后调用led_classdev_register函数注册,所以完美解释了led_cdev->name就是"lcd-backlight",完美解释了"/sys/class/leds/lcd-backlight/brightness"的由来。
另外info->pri_display_class_dev.brightness_set = omap4_xxx_primary_disp_store;中的omap4_xxx_primary_disp_store()就是我们需要实现的设置背光亮度函数,函数里面就是pwm操作。到这里又有一个疑问4:为什么只实现设置背光亮度的接口,而没有实现读取当前亮度量化值的接口?其实Android上层自行处理了这个获取亮度量化值的事情,也就是说Android上层设置了亮度是多少,上层会执行保留设置结果。无需再通过下层读取。

6.总结

6.1针对之前的疑问1/2,其实LCD背光的sys接口路径是可以改的,但是需要Linux内核层和Android HAL层配合来改,单单改一方都是会导致Android Setting无法调节背光。6.2需注意在实现Linux背光驱动时的亮度量化关系,也就是注意上层传递下来的亮度设置范围是0~255。6.3Android底层的Linux驱动都是服务于上层Java的,在做Android底层的Linux驱动时需要明确和上层的接口依赖关系,否则无法重用google或芯片厂商实现的接口,从而导致功能无法用。6.4.再一次证明了Android系统服务运行效率极低。设置背光,其实最终就是设置了一下pwm寄存器即可,但是从Android最顶层一层层调用下来,真是“费尽周折”,怪不得Android设备的硬件配置明显远优于ios设备,但是流畅体验性却不明显优于ios设备。

更多相关文章

  1. C语言函数以及函数的使用
  2. Android OpenGL ES学习笔记之实现OpenGL ES接口
  3. Android支付宝接口集成
  4. Android’s HTTP Clients(Android的HTTP客户端接口)
  5. 【Android】_MyContentProvider_外部访问接口
  6. Android 利用隐藏API实现屏幕亮度调节
  7. android NDK JNI设置自己的log输出函数
  8. Android 使用SeekBar 变更屏幕亮度和声音音量
  9. 第三部分:Android 应用程序接口指南---第一节:应用程序组件---第六

随机推荐

  1. Android(安卓)轻松实现仿QQ消息下拉刷新
  2. ShareSDK 第三方分享
  3. Android开发者如何玩转应用开发
  4. android开发——框架理解及源码学习计划
  5. Android应用程序通用自动脱壳方法研究
  6. android 手机安装应用程序(APK)权限详细
  7. android 使用https请求请求数据
  8. android内存泄漏面试知识小结
  9. Android 仿淘宝2017添加地址
  10. 深入探索Android卡顿优化(上)