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