摘自:http://hi.baidu.com/rwen2012/item/40f4383c3d8d8abc124b1451. 3背光驱动的实现 本RSU系统使用一个通用的背光层驱动和用户及内核的其他模块交互。该背光驱动作为PWM模块和用户/内核其他模块交互的中间层,接收来自用户或内核模块的命令,然后转化为对PWM的控制命令,如开启、关闭、调整等。 在用户接口方面,使用Linux 2.6内核特有的sysfs文件系统,实现内核与用户间的交互。Sysfs是一个可读写的文件系统,通过提供一些变量,内核输出设备的属性,如LCD背光的当前亮度值,最大亮度值等。用户可以通过改变这些变量的值,设置设备的属性。Sysfs文件系统提供的用户接口如下: /* interface for exporting device attributes */ struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); }; 其中,attr是设备的标识,show和store是两个函数指针。内核通过show向用户输出设备属性,用户层则通过store设置设备的属性。在LCD背光驱动中,定义了以下结构: #define __ATTR(_name,_mode,_show,_store) { \ .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ } static struct device_attribute bl_device_attributes[] = { __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power), __ATTR(brightness, 0644, backlight_show_brightness, backlight_store_brightness), __ATTR(actual_brightness, 0444, backlight_show_actual_brightness, NULL), __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), __ATTR_NULL, }; 如上,系统向用户层输出bl_power,brightness,actual_brightness,max_brightness四个属性值,其中前两个是可写的,后两个是只读的。例如,内核通过backlight_show_power向用户层输出属性bl_power的值。通过backlight_store_power接受来自用户层的输入值,然后将其设置为bl_power属性的当前值。 通过sysfs文件系统,本手持RSU系统为用户层提供两种背光调整方式。一为亮度等级的调整(bl_power),值为0~4,0为高亮,1、2、3次之,4为全灭。另一种是线性调整方式(brightness),其值为从0~TCNTB,其值越大,背光的亮度越高。 本系统通过通知链表(Notifier Chain)[8]技术,实现LCD背光驱动与内核其他模块(如LCD)的交互。通知链表是内核模块间的一种通讯方式,它的工作方式和中断类似。一旦某个模块有事件发生,它便通知已经注册到这个模块链表的其他模块。这样,其他模块就可以根据所发生的事件,调用相应的处理例程。 首先定义一个通知链表。LCD驱动中定义的通知链表如下: static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); 接着,外部模块注册到这个通知链表中,背光驱动注册如下: blocking_notifier_chain_register(&fb_notifier_list, nb); 其中,参数nb是如下一个结构,由外部模块提供: struct notifier_block { int (*notifier_call)(struct notifier_block *, unsigned long, void *); struct notifier_block *next; int priority; }; 完成注册操作后,一旦LCD模块有事件发生,它便会以该事件(even)作为参数,调用如下函数: blocking_notifier_call_chain(&fb_notifier_list, val, v); 该函数遍历在这个链表中注册过的notifier_block,并执行其中的处理例程。例如,当LCD发生UNBLANK事件时,它遍历相应的通知链表,执行背光系统注册的处理例程,将升压开关调整器的使能端置为0,关闭背光的输出。 综上,整个背光的控制流程如图4所示。 图4 LCD背光控制的框图 通过测试,可以得到如表2所示的和背光能耗相关一些数值。 表2 LCD功耗列表 TCMPB1 (TCNB1) 电流 (mA) 电压 (V) 功率 (mW) 1 113 20.0 2260.0 3/4 83 19.1 1585.3 1/2 55 18.0 990.0 1/4 23 16.9 388.7 1/8 10 16.2 162.0 1/16 5 15.9 79.5 在实际使用的过程中,设置1/2值的亮度即可,只有在特殊的场合才需要设置为高亮。而在系统等待的时候,可以将其值设置为1/16,这时背光的功耗只有79mW,约为最大功耗的1/28,大大节省了能耗。 |
|
来自: 写意人生 > 《backlight》