国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【分析筆記】Linux 4.9 backlight 子系統(tǒng)分析

這篇具有很好參考價值的文章主要介紹了【分析筆記】Linux 4.9 backlight 子系統(tǒng)分析。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

相關信息

內(nèi)核版本:Linux version 4.9.56
驅動文件:lichee\linux-4.9\drivers\video\backlight\backlight.c

驅動作用

  1. 對上,面對應用層提供統(tǒng)一的設備節(jié)點入口
  2. 同級,面對驅動層提供設備驅動加載卸載通知事件,以及背光控制接口。
  3. 對下,面對硬件層提供背光控制調(diào)節(jié)的回調(diào)接口
  4. 監(jiān)聽 frambuffer 事件, 實現(xiàn)清屏聯(lián)動背光控制
  5. 監(jiān)聽系統(tǒng)休眠喚醒,實現(xiàn)休眠喚醒背光聯(lián)動控制

控制背光的來源:應用訪問、事件聯(lián)動、休眠喚醒

attribute_groups,Linux 驅動開發(fā),linux,驅動開發(fā)

源碼分析

一、驅動初始化

  1. 完成背光設備邏輯類的創(chuàng)建
  2. 初始化用于通知背光設備驅動加載卸載的事件
  3. 為該邏輯類設定五個背光控制相關的設備節(jié)點
/sys/class/backlight/xxx/type
/sys/class/backlight/xxx/bl_power
/sys/class/backlight/xxx/brightness
/sys/class/backlight/xxx/max_brightness
/sys/class/backlight/xxx/actual_brightness
代碼解析
static int __init backlight_class_init(void)
{
	// 創(chuàng)建背光設備邏輯類: /sys/class/backlight
	backlight_class = class_create(THIS_MODULE, "backlight");
	if (IS_ERR(backlight_class)) {
		pr_warn("Unable to create backlight class; errno = %ld\n", PTR_ERR(backlight_class));
		return PTR_ERR(backlight_class);
	}

	// 面對應用層提供統(tǒng)一的設備節(jié)點入口(預先設置好節(jié)點名稱和可讀寫權限)
	backlight_class->dev_groups = bl_device_groups;
	// 監(jiān)聽系統(tǒng)的休眠喚醒回調(diào)
	backlight_class->pm = &backlight_class_dev_pm_ops;

	// 初始化背光設備鏈表,用于被外部驅動查詢獲取
	INIT_LIST_HEAD(&backlight_dev_list);
	mutex_init(&backlight_dev_list_mutex);
	
	// 初始化內(nèi)核通知鏈, 用于通知驅動層背光設備注冊或卸載事件
	BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier);

	return 0;
}
ATTRIBUTE_GROUPS 宏定義解析:

直接搜索源碼是找不到 bl_device_groups 關鍵詞的,實際該變量是通過宏進行定義

static struct attribute *bl_device_attrs[] = {
	&dev_attr_bl_power.attr,
	&dev_attr_brightness.attr,
	&dev_attr_actual_brightness.attr,
	&dev_attr_max_brightness.attr,
	&dev_attr_type.attr,
	NULL,
};
ATTRIBUTE_GROUPS(bl_device);

宏定義:include\linux\sysfs.h

#define __ATTRIBUTE_GROUPS(_name)				\
static const struct attribute_group *_name##_groups[] = {	\
	&_name##_group,						\
	NULL,							\
}

#define ATTRIBUTE_GROUPS(_name)					\
static const struct attribute_group _name##_group = {		\
	.attrs = _name##_attrs,					\
};								\
__ATTRIBUTE_GROUPS(_name)

宏定義展開:ATTRIBUTE_GROUPS(bl_device)

#define __ATTRIBUTE_GROUPS(bl_device)				\
static const struct attribute_group *bl_device_groups[] = {	\
	&bl_device_group,						\
	NULL,							\
}

#define ATTRIBUTE_GROUPS(bl_device)					\
static const struct attribute_group bl_device_group = {		\
	.attrs = bl_device_attrs,					\
};								\
__ATTRIBUTE_GROUPS(bl_device)

宏替換后的效果

static struct attribute *bl_device_attrs[] = {
	&dev_attr_bl_power.attr,
	&dev_attr_brightness.attr,
	&dev_attr_actual_brightness.attr,
	&dev_attr_max_brightness.attr,
	&dev_attr_type.attr,
	NULL,
};

static const struct attribute_group bl_device_group = {		
	.attrs = bl_device_attrs,					
};

static const struct attribute_group *bl_device_groups[] = {	
	&bl_device_group,						
	NULL,							
};

DEVICE_ATTR_RW 宏定義解析:
static ssize_t brightness_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int rc;
	struct backlight_device *bd = to_backlight_device(dev);
	unsigned long brightness;

	rc = kstrtoul(buf, 0, &brightness);
	if (rc)
		return rc;

	rc = backlight_device_set_brightness(bd, brightness);

	return rc ? rc : count;
}
static DEVICE_ATTR_RW(brightness);

宏定義:include\linux\device.h include\linux\sysfs.h

#define DEVICE_ATTR_RW(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_RW(_name)

#define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO),		\
			 _name##_show, _name##_store)

宏定義展開,取其中一個設備節(jié)點的例子:static DEVICE_ATTR_RW(brightness)

#define DEVICE_ATTR_RW(brightness) \
	struct device_attribute dev_attr_brightness = __ATTR_RW(brightness)

#define __ATTR_RW(brightness) __ATTR(brightness, (S_IWUSR | S_IRUGO),		\
			 brightness_show, brightness_store)
			 
#define __ATTR(brightness, (S_IWUSR | S_IRUGO), brightness_show, brightness_store) { \
	.attr = {.name = __stringify(brightness),				\
		 .mode = VERIFY_OCTAL_PERMISSIONS((S_IWUSR | S_IRUGO)) },		\
	.show	= brightness_show,						\
	.store	= brightness_store,						\
}

宏替換后的效果

static struct device_attribute dev_attr_brightness = {
	.attr = {
		.name = __stringify(brightness),		
		.mode = VERIFY_OCTAL_PERMISSIONS((S_IWUSR | S_IRUGO)) 
	},
	.show	= brightness_show,	
	.store	= brightness_store,		
}

二、背光設備驅動注冊

假如 name=sunxi,那么調(diào)用此接口后將會產(chǎn)生如下幾個設備節(jié)點:
背光設備類型:/sys/class/backlight/sunxi/type
背光電源控制:/sys/class/backlight/sunxi/bl_power
背光亮度設置:/sys/class/backlight/sunxi/brightness
最大背光亮度:/sys/class/backlight/sunxi/max_brightness
真實背光亮度:/sys/class/backlight/sunxi/actual_brightness

// name:背光設備名稱	parent:父設備	devdata:私有數(shù)據(jù)	ops:背光控制調(diào)節(jié)的回調(diào)		props:默認的背光屬性
struct backlight_device *backlight_device_register(const char *name, struct device *parent, void *devdata, const struct backlight_ops *ops, const struct backlight_properties *props)
{
	struct backlight_device *new_bd;
	int rc;

	// 創(chuàng)建背光設備
	new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
	if (!new_bd)
		return ERR_PTR(-ENOMEM);

	mutex_init(&new_bd->update_lock);
	mutex_init(&new_bd->ops_lock);

	// 設置設備邏輯類為背光設備邏輯類, 在驅動初始化時完成的創(chuàng)建
	// 這里要注意, struct device 是直接嵌入到 struct backlight_device 里面的
	new_bd->dev.class = backlight_class;
	new_bd->dev.parent = parent;
	new_bd->dev.release = bl_device_release;
	
	// 設置名稱, 體現(xiàn)在: /sys/class/backlight/XXX
	dev_set_name(&new_bd->dev, "%s", name);
	dev_set_drvdata(&new_bd->dev, devdata);

	// 如果有指定的背光屬性, 則拷貝并作為默認的背光屬性
	if (props) {
		memcpy(&new_bd->props, props, sizeof(struct backlight_properties));
		if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) {
			WARN(1, "%s: invalid backlight type", name);
			new_bd->props.type = BACKLIGHT_RAW;
		}
	} else {
		new_bd->props.type = BACKLIGHT_RAW;
	}

	// 將此設備注冊到系統(tǒng)里面,里面會創(chuàng)建 backlight_class 預設的那幾個設備節(jié)點
	rc = device_register(&new_bd->dev);
	if (rc) {
		put_device(&new_bd->dev);
		return ERR_PTR(rc);
	}
	
	// 注冊監(jiān)聽 frambuffer 的事件通知鏈
	rc = backlight_register_fb(new_bd);
	if (rc) {
		device_unregister(&new_bd->dev);
		return ERR_PTR(rc);
	}

	// 指定背光控制接口
	new_bd->ops = ops;

	// 將此設備加入到鏈表內(nèi), 便于外部查詢獲取
	mutex_lock(&backlight_dev_list_mutex);
	list_add(&new_bd->entry, &backlight_dev_list);
	mutex_unlock(&backlight_dev_list_mutex);

	// 發(fā)出事件通知, 有新的背光設備被注冊到系統(tǒng)中
	blocking_notifier_call_chain(&backlight_notifier, BACKLIGHT_REGISTERED, new_bd);
	return new_bd;
}
EXPORT_SYMBOL(backlight_device_register);

三、應用層進行背光調(diào)節(jié)路徑

代碼解析
static ssize_t brightness_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int rc;
	// 通過 dev 計算出 backlight_device 地址, 取得對應背光設備對象
	struct backlight_device *bd = to_backlight_device(dev);
	unsigned long brightness;

	// 字符串轉換為數(shù)值
	rc = kstrtoul(buf, 0, &brightness);
	if (rc)
		return rc;

	// 調(diào)用設置背光接口, 該接口也被開放給其它驅動程序調(diào)用
	rc = backlight_device_set_brightness(bd, brightness);

	return rc ? rc : count;
}
static DEVICE_ATTR_RW(brightness);

int backlight_device_set_brightness(struct backlight_device *bd,
				    unsigned long brightness)
{
	int rc = -ENXIO;

	// 有多個路徑調(diào)用, 存在并發(fā)調(diào)用, 借助互斥鎖保護
	mutex_lock(&bd->ops_lock);
	// 檢查是否設置了回調(diào)
	if (bd->ops) {
		// 檢查所設置的背光數(shù)值是否超出最大值
		if (brightness > bd->props.max_brightness)
			rc = -EINVAL;
		else {
			// 填充要設置的背光值并更新
			bd->props.brightness = brightness;
			backlight_update_status(bd);
			rc = 0;
		}
	}
	mutex_unlock(&bd->ops_lock);

	backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);

	return rc;
}
EXPORT_SYMBOL(backlight_device_set_brightness);

static inline int backlight_update_status(struct backlight_device *bd)
{
	int ret = -ENOENT;

	// 從這里可以看出, 最終調(diào)用的背光設備驅動的 ops->update_status() 接口
	mutex_lock(&bd->update_lock);
	if (bd->ops && bd->ops->update_status)
		ret = bd->ops->update_status(bd);
	mutex_unlock(&bd->update_lock);

	return ret;
}
關鍵解析

這里最主要的是搞清楚是如何區(qū)分應用層操作哪個背光設備(這部分實現(xiàn)很有意思,其原理會另寫文章解析)。

  1. Linux 最常用的是通過結構體嵌套的方式,實現(xiàn)以某個成員的內(nèi)存地址計算出結構體的首地址,從而訪問到其它的成員。
  2. struct device 是直接嵌入到 struct backlight_device 里面,就可以通過 struct device 找到對應 struct backlight_device。
  3. 應用層通過 /sys/class/backlight/xxx 來訪問 xxx 背光設備,就可確定 device, 根據(jù) device 找出 backlight_device,調(diào)用對應背光設備驅動的 ops 成員。
struct backlight_device {
	......
	struct device dev;
	......
};
#define to_backlight_device(obj) container_of(obj, struct backlight_device, dev)

四、事件聯(lián)動進行背光調(diào)節(jié)路徑

在背光設備驅動注冊的時候,就調(diào)用 backlight_register_fb 來監(jiān)聽 fb 事件。

Xorg 就通過 FBIOBLANK 指令實現(xiàn)熄屏,但若沒有對應的背光設備接口,就會出現(xiàn)顯示屏全黑但是背光還亮著的問題。

代碼解析
static int backlight_register_fb(struct backlight_device *bd)
{
	// 當有背光
	memset(&bd->fb_notif, 0, sizeof(bd->fb_notif));
	bd->fb_notif.notifier_call = fb_notifier_callback;

	return fb_register_client(&bd->fb_notif);
}

// drivers\video\fbdev\core\fb_notify.c
int fb_register_client(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&fb_notifier_list, nb);
}
EXPORT_SYMBOL(fb_register_client);

static int fb_notifier_callback(struct notifier_block *self,
				unsigned long event, void *data)
{
	struct backlight_device *bd;
	struct fb_event *evdata = data;
	int node = evdata->info->node;
	int fb_blank = 0;

	// 僅對顯示空白事件感興趣
	if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
		return 0;

	// 一樣的操作, 通過 device 找到 backlight_device
	bd = container_of(self, struct backlight_device, fb_notif);
	mutex_lock(&bd->ops_lock);
	if (bd->ops)
		if (!bd->ops->check_fb ||
		    bd->ops->check_fb(bd, evdata->info)) {
			fb_blank = *(int *)evdata->data;
			if (fb_blank == FB_BLANK_UNBLANK && !bd->fb_bl_on[node]) {
				bd->fb_bl_on[node] = true;
				if (!bd->use_count++) {
					// 如果需要正常顯示,則亮起背光
					bd->props.state &= ~BL_CORE_FBBLANK;
					bd->props.fb_blank = FB_BLANK_UNBLANK;
					backlight_update_status(bd);
				}
			} else if (fb_blank != FB_BLANK_UNBLANK && bd->fb_bl_on[node]) {
				bd->fb_bl_on[node] = false;
				if (!(--bd->use_count)) {
					// 如果顯示空白畫面,則熄滅背光
					bd->props.state |= BL_CORE_FBBLANK;
					bd->props.fb_blank = fb_blank;
					backlight_update_status(bd);
				}
			}
		}
	mutex_unlock(&bd->ops_lock);
	return 0;
}

五、最簡單的背光設備驅動文章來源地址http://www.zghlxwxcb.cn/news/detail-672800.html

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/backlight.h>

static struct backlight_device *bdev = NULL;

// 更新背光亮度
static int mybl_bl_ops_update_bl(struct backlight_device *bdev)
{
	//......
	
	return 0;
}

// 獲取背光亮度
static int mybl_bl_ops_get_brightness(struct backlight_device *bdev)
{
	//......
	
	return brightness;
}

static const struct backlight_ops mybl_bl_ops = {
	.update_status	= mybl_bl_ops_update_bl,
	.get_brightness	= mybl_bl_ops_get_brightness,
};

static int mybl_probe(struct platform_device *pdev)
{
	bdev = backlight_device_register("mydriver", &pdev->dev, NULL, &mybl_bl_ops, NULL);
	if(IS_ERR(bdev)){
		return -1;
	}
	return 0;
}

static int mybl_remove(struct platform_device *pdev)
{
	backlight_device_unregister(bdev);
	return 0;
}

static const struct of_device_id mybl_ids[] = {
	{ .compatible = "mybl"},{}
};

static struct platform_driver mybl_driver = {
	.probe	= mybl_probe,
	.remove	= mybl_remove,
	.driver	= {
		.owner	= THIS_MODULE,
		.name = "mybl",
		.of_match_table	= mybl_ids,
	},
};

module_platform_driver(mybl_driver);
MODULE_LICENSE("GPL");

到了這里,關于【分析筆記】Linux 4.9 backlight 子系統(tǒng)分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 一、LED子系統(tǒng)框架分析

    個人主頁:董哥聊技術 我是董哥,嵌入式領域新星創(chuàng)作者 創(chuàng)作理念:專注分享高質(zhì)量嵌入式文章,讓大家讀有所得!

    2023年04月09日
    瀏覽(20)
  • 【W(wǎng)indows 11】安裝 Android子系統(tǒng) 和 Linux子系統(tǒng)

    【W(wǎng)indows 11】安裝 Android子系統(tǒng) 和 Linux子系統(tǒng)

    本文使用電腦系統(tǒng): 主要就是安裝一個名為: 適用于Android的Windows子系統(tǒng) (WSA)的軟件。 首先在電腦的設置里面:時間和語言——語言和地區(qū)里面把地區(qū)改為美國。 然后到微軟商店搜索: Amazon AppStore 。 安裝亞馬遜應用商店的時候,會首先提示你安裝前面說的WSA。如此,我

    2024年02月09日
    瀏覽(31)
  • OpenHarmony3.1安全子系統(tǒng)-簽名系統(tǒng)分析

    OpenHarmony3.1安全子系統(tǒng)-簽名系統(tǒng)分析

    應用簽名系統(tǒng)主要負責鴻蒙hap應用包的簽名完整性校驗,以及應用來源識別等功能。 子系統(tǒng)間接口: 應用完整性校驗模塊給其他模塊提供的接口; 完整性校驗: 通過驗簽,保障應用包完整性,防篡改; 應用來源識別: 通過匹配簽名證書鏈與可信源列表,識別應用來源。

    2024年02月05日
    瀏覽(20)
  • Window10安裝linux子系統(tǒng)及子系統(tǒng)安裝1Panel面板

    Window10安裝linux子系統(tǒng)及子系統(tǒng)安裝1Panel面板

    原文地址:Window10安裝linux子系統(tǒng)及子系統(tǒng)安裝1Panel面板 - Stars-One的雜貨小窩 最近看到halo博客發(fā)布了2.10.0,終于是新增了個備份功能,于是有了念頭想要升級下 但是目前我還是使用halo1.5版本,所以跨版本遷移可能會有問題,官方提議還是先用個測試環(huán)境進行測試驗證是否有問題 但

    2024年02月08日
    瀏覽(26)
  • 字符設備驅動之輸入子系統(tǒng)分析(二)

    作者: Bright-Ho 聯(lián)系方式: 836665637@qq.com input 輸入子系統(tǒng)框架分析(純軟件方面): ? 上一節(jié),我們簡單的描述的 什么是輸入子系統(tǒng) ; 什么是字符設備 ; 以及其作用 ;重點是我們講到分析 輸入子系統(tǒng)必須結合硬件設備來分析 ;那么這一節(jié),我們主要講解輸入子系統(tǒng)的 軟

    2024年02月15日
    瀏覽(24)
  • 字符設備驅動之輸入子系統(tǒng)分析(一)

    作者: Bright-Ho 聯(lián)系方式: 836665637@qq.com 前言背景描述: 雖然在網(wǎng)上看了很多有關輸入子系統(tǒng)的資料和視頻,但是真正的,系統(tǒng)的,全面的,來弄清輸入子系統(tǒng),還是要花些時間和精力的!現(xiàn)在我以一個初學者的角度來分析 input 輸入子系統(tǒng); 那么分析 input 輸入子系統(tǒng)之前,

    2024年02月15日
    瀏覽(23)
  • Android13音頻子系統(tǒng)分析(一)---整體架構

    Android13音頻子系統(tǒng)分析(一)---整體架構

    ???????? 目錄 一、應用API層 二、Java框架層 三、Native核心層 3.1 AudioFlinger模塊 3.2 AudioPolicyService模塊 四、HAL層 ????????本文基于AOSP13源碼進行分析解讀。所以與各個SoC平臺廠商提供的運行在真實設備上的源碼會有細微差異,但核心原理區(qū)別不大。 ????????音頻子系

    2024年02月07日
    瀏覽(20)
  • Linux reset子系統(tǒng)

    文章代碼分析基于linux-5.19.13,架構基于aarch64(ARM64)。 復雜IC內(nèi)部有很多具有獨立功能的硬件模塊,例如CPU cores、GPU cores、USB控制器、MMC控制器、等等,出于功耗、穩(wěn)定性等方面的考慮,有些IC在內(nèi)部為這些硬件模塊設計了復位信號(reset signals),軟件可通過寄存器(一般

    2024年02月16日
    瀏覽(24)
  • Linux Input子系統(tǒng)

    Linux Input子系統(tǒng)

    按鍵、鼠標、鍵盤、觸摸屏等都屬于輸入(input)設備,Linux 內(nèi)核為此專門做了一個叫做? input 子系統(tǒng) 的 框架 來處理輸入事件。本質(zhì)屬于字符設備。 1. input子系統(tǒng)結構如下: ?input 子系統(tǒng)分為 input 驅動層、input 核心層、input 事件處理層,最終給用戶空間提供可訪問的設備節(jié)點

    2024年02月10日
    瀏覽(12)
  • Linux內(nèi)核(十四)Input 子系統(tǒng)詳解 I —— 子系統(tǒng)介紹以及相關結構體解析

    Linux內(nèi)核(十四)Input 子系統(tǒng)詳解 I —— 子系統(tǒng)介紹以及相關結構體解析

    input子系統(tǒng)就是管理輸入的子系統(tǒng) ,和Linux其他子系統(tǒng)一樣,都是Linux內(nèi)核針對某一類設備而創(chuàng)建的框架。 鼠標、鍵盤、觸摸屏等都屬于輸入設備,Linux將這些設備的共同特性抽象出來,這就形成了input子系統(tǒng)的框架。 Linux內(nèi)核只需要通過input框架向用戶層上報輸入事件 (如:

    2024年02月05日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包