内核杂谈——关于platform device 创建

内核杂谈——关于platform device 创建当拿到driver,不能用起来的时候需要去检查device了。虽说device和bus通常都是系统中带的,但也不要想当然的认为这个系统是帮你建好的。通常busdevicedriver三者中,bus基本不用干预,device干预的少,driver干预的多。从设备树中生成device从设备树中识别device的入口为arch_initcall_sync(of_platform_default_populate_init);staticint__initof_platform_defa

大家好,又见面了,我是你们的朋友全栈君。

当拿到driver,不能用起来的时候需要去检查device了。虽说device和bus通常都是系统中带的,但也不要想当然的认为这个系统是帮你建好的。

通常 bus device driver三者中,bus基本不用干预,device 干预的少,driver 干预的多。

从设备树中生成device

从设备树中识别 device的入口为 arch_initcall_sync(of_platform_default_populate_init);

static int __init of_platform_default_populate_init(void)
{ 
   
// /firmware 节点
	node = of_find_node_by_path("/firmware");
	if (node) { 
   
		of_platform_populate(node, NULL, NULL, NULL);
		of_node_put(node);
	}
// 传参为NULL,默认获取 / 节点
	of_platform_default_populate(NULL, NULL, NULL);

	return 0;
}

往下调用

int of_platform_default_populate(struct device_node *root,
				 const struct of_dev_auxdata *lookup,
				 struct device *parent)
{ 
   
	return of_platform_populate(root, of_default_bus_match_table, lookup,
				    parent);
}

注意参数 of_default_bus_match_table

const struct of_device_id of_default_bus_match_table[] = { 
   
	{ 
    .compatible = "simple-bus", },
	{ 
    .compatible = "simple-mfd", },
	{ 
    .compatible = "isa", },
#ifdef CONFIG_ARM_AMBA
	{ 
    .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */
	{ 
   } /* Empty terminated list */
};

到函数of_platform_populate后,出现两个条件情况
第一个 root = node = of_find_node_by_path(“/firmware”);
第二个 root = of_find_node_by_path(“/”) + of_default_bus_match_table[]
然后执行 of_platform_bus_create(child, matches, lookup, parent, true);
第一种情况:child 从 “/firmware” 节点开始找,没有match限制
第二种情况:child 从 “/” 节点开始找,有match限制
这两种情况中,通常第二点作为创建platform device的主要规则

进入该函数,该函数就是创建 platform device 的

static int of_platform_bus_create(struct device_node *bus,
				  const struct of_device_id *matches,
				  const struct of_dev_auxdata *lookup,
				  struct device *parent, bool strict)
{ 
   
	struct platform_device *dev;
	int rc = 0;

	/* 节点 必须要有 compatible 词条 */
	if (strict && (!of_get_property(bus, "compatible", NULL))) 
		return 0;

	/* 节点含有 of_skipped_node_table中定义的 compatible 词条,不做 device */
	if (unlikely(of_match_node(of_skipped_node_table, bus)))
		return 0;
		
// 属性为 arm,primecell ,创建完就退出。针对 arm 的
	if (of_device_is_compatible(bus, "arm,primecell")) { 
   
		of_amba_device_create(bus, bus_id, platform_data, parent);
		return 0;
	}
// --------------------********重点重点重点在下面,规则的体现********-------------- 
// 需要有 of_default_bus_match_table 中定义的 compatible 词条
	dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
// 走到此处需要停下来 ,静静思考:若当前节点含有compatible词条,但词条不在
// of_default_bus_match_table 中,则当前节点下面的所有子节点,不做为platform device
	if (!dev || !of_match_node(matches, bus))
		return 0;
//词条在of_default_bus_match_table 中,则当前节点的下一个子节点,做为platform device
	for_each_child_of_node(bus, child) { 
   
// 若节点还有子节点,递归创建device,条件为上述,直到不满足条件退出
		rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
		if (rc) { 
   
			of_node_put(child);
			break;
		}
	}
	return rc;
}

of_platform_device_create_pdata 就是 具体创建 设备树中符合条件的device,将节点相关信息解析并保存到struct platform_device中。比如 irq,resource (内存信息,地址等)等。

一般情况 从 ” / ” 节点,找child,作为bus node ,child 节点是否有 compatible ,有则往下走;将child创建为device,然后判断child是否含有of_default_bus_match_table中的compatible,有,则child作为platform device就成了。然后继续以child 作为 parent,继续循环下去,找child,作为bus node ,child 节点是否有 compatible ,有则往下走;将child创建为device,然后判断child是否含有of_default_bus_match_table中的compatible,有,则child作为platform device就成了 …

所以,格式如下

1 最常规的,/ 下,A成了platform device
/ { 
   
	A { 
   
		compatible = "xxx"
    }
}
2 A成了platform device,b不为platform device,一般我们都是这么写的
A { 
   
	compatible = " of_default_bus_match_table. compatible"
	B { 
   
		compatible = " xxx"
	}
}
3 无限接力的.基本不存在
A { 
   
	compatible = " of_default_bus_match_table. compatible"
	B { 
   
		compatible = " of_default_bus_match_table. compatible "
		C { 
   
			...compatible 同上
		};
	};
};

平台总线的设备对应的bus为platform_bus_type,不属于这个bus范畴就不是platform device。
dev->dev.bus = &platform_bus_type;
platform bus的设备对应目录 /sys/bus/platform/devices

题外话
注意到属性arm,primecell,这个是arm中的AMBA总线。含有amba属性的节点会被注册成amba设备,不会成为platform设备。比如pl011串口,还有其他pl0xx乱七八糟其他arm特有的设备。
dev->dev.bus = &amba_bustype;
amba bus的设备对应目录 /sys/bus/amba/devices/

有人看到/sys/devices/platform这个目录,是社么?
虽然带有platform字眼,但是这个目录表示的是所有外部设备,soc外接的所有设备都汇总在这个目录下。不是平台总线。毕竟目录中没有总线bus这个词!
至于这目录怎么创建出来的,不懂。

从ACPI 生成device

acpi初始化函数

static struct acpi_scan_handler apd_handler = { 
   
	.ids = acpi_apd_device_ids,
	.attach = acpi_apd_create_device,
};

void __init acpi_apd_init(void)
{ 
   
	acpi_scan_add_handler(&apd_handler);
}

其中的ids,存放了 acpi中定义的属性,如下格式。这些都是厂商私有数据,不像设备树的of_default_bus_match_table 为通用属性。

static const struct acpi_device_id acpi_apd_device_ids[] = { 
   
	/* Generic apd devices */
#ifdef CONFIG_ARM64
	{ 
    "NXP0001", APD_ADDR(nxp_i2c_desc) },
#endif
// 自定义的描述符,需要添加到此处,否则系统起来,不会添加。和设备树比起来,多了一步。
	{ 
    }
};

当然也有禁用的 acpi 描述符 存放在forbidden_id_list

第一个字符串id 类比设备树里的 compatible 。注意在acpi table中的描述文件中也要添加该字符串
第二个是描述信息

static const struct apd_device_desc nxp_i2c_desc = { 
   
//如果这个 desc 没有定义 fixed_clk_rate, setup 函数直接 return 0
	.setup = acpi_apd_setup,
	.fixed_clk_rate = 350000000,
};

创建入口为 acpi_apd_create_device ——- acpi_create_platform_device —– platform_device_register_full

device 保存路径

最终会调用device_add,以kobject的形式呈现在sysfs下
/sys/devices/platform

I2C设备

i2c总线节点,一般是在 “ / ” 下,所以默认生成 platform device

i2c0: i2c@10002000 { 
   
	#address-cells = <1>;
	#size-cells = <0>;
	compatible = "arm,versatile-i2c";
	reg = <0x10002000 0x1000>;

	rtc@68 { 
   
		compatible = "dallas,ds1338";
		reg = <0x68>;
	};
};

如上 i2c节点在“ / ” 下,i2c@10002000会被注册成 platform device。
i2c节点下有 compatible ,但不是of_default_bus_match_table中的词条,所以该节点的子节点rtc不会被注册成 platform device,但是会注册成 i2c device。
到 i2c 代码初始化后,i2c@10002000 会被注册成 i2c adapter,以 i2c-0/1/2/…形式展示,然后会将其下的i节点注册成i2c device。
详见函数 of_i2c_register_devices

和 i2c 区别的是:
platform device 对应driver使用 module_platform_driver,
i2c device 对应的driver使用 module_i2c_driver。
两者匹配上也比较相似。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/163790.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • centos利用yum安装卸载软件常用命令

    centos利用yum安装卸载软件常用命令

  • 信赖铃音的PS2游戏目录2017.6

    信赖铃音的PS2游戏目录2017.6信赖铃音PS2无损镜像游戏光碟分类目录淘宝最全1600个游戏上架大家扫我加我微信可以直接在微店或者微信红包购买PS2游戏哦!微信号298337705或者直接扫我或者保存图片长按识别二维码就可以加我了!感谢大家支持信赖铃音的无损PS2游戏光碟选好可以直接给我名单拍件数或者直接用购物车选购店址:https://playstation2.taobao.com/PS2搜索信赖铃音PS…

    2022年10月24日
  • 基于1DCNN(一维卷积神经网络)的机械振动故障诊断

    基于1DCNN(一维卷积神经网络)的机械振动故障诊断基于1DCNN(一维卷积神经网络)的机械振动故障诊断机械振动故障诊断最为经典的还是凯斯西储实验室的轴承故障诊断,开学一周了,上次改编鸢尾花分类的代码可用,但是并不准确。开学一周重新改编了别人的一篇代码,亲测好用。不多咧咧直接放上去(基于Tensorflow2.0)(Spyder4软件上跑的)数据集时本人把凯西轴承实验驱动端内圈损坏尺寸0.14和0.21做的二分类,数据集中0代表的0.14而1代表的0.21具体看下面最后#-*-coding:utf-8-*-“””CreatedonTue

  • filter pitcher是什么意思_EncodingFilter

    filter pitcher是什么意思_EncodingFilterorg.apache.struts2.dispatcher.FilterDispatcher是Struts2的主要的Filter,负责四个方面的功能:       (1)执行Actions       (2)清除ActionContext       (3)维护静态内容       (4)清除request生命周期内的XWork的interceptors   另注:该

  • linux配置ip转发

    linux配置ip转发====ip转发======1、vim/etc/sysctl.conf修改配置net.ipv4.ip_forward=1重启sysctl-p2、192.168.1.1:3307转发到192.168.1.2:3307shell下执行:iptables-tnat-APREROUTING-ptcp–dport3307-jDNAT–to-de…

  • java websocket client_前端和后端哪个累

    java websocket client_前端和后端哪个累一.WebSocket简单介绍随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号