Android电源管理系统调研报告-(5)

2 kernel sysfs 接口函数的建立

这里所分析的代码基于三星公司的手机产品 i5700 。涉及到电源管理的设备,该设备驱动应该增添相应的代码以支持相应的电源管理,如 suspend resume 。同时应该有相应的代码向 sysfs 提供相应的 entry 供用户使用。由于该流程分析的是 Lcd 亮度的调节,所以涉及到 Lcd 驱动向 sysfs 提供的 entry suspend resume 等功能在 android 层调用

int release_wake_lock(const char* id);

int acquire_wake_lock(int lock, const char* id);

时起作用。

 

i5700 中, Lcd 驱动包括两个文件,一个是与特定硬件相关的 s3cfb_s6d05a.c ,该文件实现了与硬件相关的操作,包括 GPIO 口的初始化和电源管理的相关功能函数等;一个是三星通用的 s3cfb.c ,作为桥梁作用联系着 sysfs 提供的 entry s3cfb_s6d05a.c 中相关功能函数

 

1 )、 /drivers/video/samsung/s3cfb.c

该文件向 sys 提供了三个 entry ,让我们来看看这三个 entry 的建立流程。

 

(1) entry 对应的读、写功能函数:

三个 entry 分别是 lcd_power backlight_power backlight_level ,这几个 entry android 系统起来后,在终端通过 adb shell ,敲入如下命令就可以看到:

# ls /sys/devices/platform/s3c-lcd

其中 *show* 表示读操作的功能函数, *store* 表示写操作的功能函数。在后面会对其中一个函数有进行详细的分析。

static int s3cfb_sysfs_show_lcd_power(struct device *dev, struct device_attribute *attr, char *buf)

static int s3cfb_sysfs_store_lcd_power(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)

static int s3cfb_sysfs_show_backlight_power(struct device *dev, struct device_attribute *attr, char *buf)

static int s3cfb_sysfs_store_backlight_power(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)

static int s3cfb_sysfs_show_backlight_level(struct device *dev, struct device_attribute *attr, char *buf)

static int s3cfb_sysfs_store_backlight_level(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)

 

(2) entry 属性的建立:

内核 中, sysfs  属性一般是由  __ATTR  系列的宏来声明的,如对设备的使用  DEVICE_ATTR  ,对总线使用  BUS_ATTR  ,对驱动使用 DRIVER_ATTR  ,对类别 (class) 使用  CLASS_ATTR,  这四个高级的宏来自于 <include/linux/device.h> 。在 s3cfb.c 里,使用的是 DEVICE_ATTR 来建立 entry sysfs 中的属性。

static DEVICE_ATTR(lcd_power, 0666,

                      s3cfb_sysfs_show_lcd_power,

                      s3cfb_sysfs_store_lcd_power);

 

static DEVICE_ATTR(backlight_power, 0666,

                      s3cfb_sysfs_show_backlight_power,

                      s3cfb_sysfs_store_backlight_power);

 

static DEVICE_ATTR(backlight_level, 0644,

                      s3cfb_sysfs_show_backlight_level,

                      s3cfb_sysfs_store_backlight_level);

 

DEVICE_ATTR  宏声明有四个参数,分别是名称、权限位、读函数、写函数。其中读函数和写函数是读写功能函数的函数名。

 

(3) entry 的创建

entry 的创建是通过函数 device_create_file 完成,在 static int __inits3cfb_probe(struct platform_device *pdev) 函数内实现的。

        ret = device_create_file(&(pdev->dev), &dev_attr_backlight_power);

 

        if (ret < 0)

               printk(KERN_WARNING "s3cfb: failed to add entries/n");

 

        ret = device_create_file(&(pdev->dev), &dev_attr_backlight_level);

 

        if (ret < 0)

               printk(KERN_WARNING "s3cfb: failed to add entries/n");

 

        ret = device_create_file(&(pdev->dev), &dev_attr_lcd_power);

 

        if (ret < 0)

               printk(KERN_WARNING "s3cfb: failed to add entries/n");

 

通过以上简单的三个步骤,就可以在 shell 终端查看到这三个 entry 了。当我们将数据 echo 到这几个 entry 中时,在上层实际上完成了一次 write 操作,对应到 kernel ,分别调用了 lcd 驱动中的三个 *store* 。同理,当我们 cat 一个 entry 时则会调用 *show* 。通过在 *show* *store* 中插桩就可以看到效果。到这里,只是简单的建立了 android 层到 kernel 的桥梁,真正实现对硬件操作的,还是在 *show* *store* 中完成的。

 

 

 

 

 

(4) backlight_level  entry 写函数分析

static int s3cfb_sysfs_store_backlight_level(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)

{

        unsigned long value = simple_strtoul(buf, NULL, 10);

 

        if (value < s3c_fimd.backlight_min || value > s3c_fimd.backlight_max)

               return -ERANGE;

 

        s3cfb_set_backlight_level(value);

 

        return len;

}

 

这里调用了 s3cfb_set_backlight_level(value);

static void s3cfb_set_backlight_level(int to)

{

        backlight_level = to;

 

        if (s3c_fimd.set_brightness)

               (s3c_fimd.set_brightness)(to);

}

 

 

在这个函数里, s3c_fimd.set_brightness 是一个函数指针,如果不为空,刚调用 (s3c_fimd.set_brightness)(to); 。在这里还看不到到底调用了哪个函数,在 s3cfb_s6d05a.c 中有能该函数指针的初始化以及最终功能函数的实现。

 

 

2 )、 /drivers/video/samsung/s3cfb_s6d05a.c

上文提到的函数接口的初始化是在 static voids3cfb_set_fimd_info(void) 中完成的:

        s3c_fimd.set_lcd_power               = lcd_power_ctrl;

        s3c_fimd.set_backlight_power = backlight_power_ctrl;

        s3c_fimd.set_brightness        = backlight_level_ctrl;

 

因此 (s3c_fimd.set_brightness)(to); 实际上是调用了 backlight_level_ctrl(to);

void backlight_level_ctrl(s32 value)

{

        if ((value < BACKLIGHT_LEVEL_MIN) ||       /* Invalid Value */

               (value > BACKLIGHT_LEVEL_MAX) ||

               (value == backlight_level))   /* Same Value */

               return;

 

        if (backlight_power)

               backlight_ctrl(value);   

       

        backlight_level = value;      

}

 

这个函数实现的是 LCD 背光的调节,可以参考程杰SX的博客:

http://hi.baidu.com/aokikyon/blog/item/ea947e36e42949d0a2cc2b55.html

你可能感兴趣的:(Android电源管理系统调研报告-(5))