设备驱动的艺术之旅 - Platform 总线的应用

来源:互联网 发布:广告宣传音频制作软件 编辑:程序博客网 时间:2024/05/22 15:33

From: 设备驱动的艺术之旅

前程往事,历历在目 - 佚名

总线的故事

2011年linux创始人Linus Torvalds在社区的一句脏话,引发了社区震动!从而导致代码大换血!Dts(device tree source)则就是这个时候被应用在我们的各种处理器中目录下的!早期这种模式被用于IBM PowerPC等体系架构下使用的Flattened Device Tree(FDT)。Device Tree是一种描述硬件的数据结构,它起源于 OpenFirmware (OF)。在Linux 2.6中,各种架构的板极硬件过多地被硬编码在arch/xxx/plat-xxx和arch/xxx/mach-xxx,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在上述代码中进行大量的冗余编码。
具体Device Tree介绍等到这里查看:

凡是走platform架构的所有device都可以用于此模型:如:CPU的数量和类别内存基地址和大小总线和桥外设连接中断控制器和中断使用情况GPIO控制器和GPIO使用情况Clock控制器和Clock使用情况Ethernet控制器等等都是可以被集成到dts中的!

一、Platform 概述

Platform_driver 驱动模型是内核中比较常用的一种模型!因为这是一种虚拟总线,其好处就是不管是字符设备块设备都可以通过此总线来实现设备集中!驱动模型的铁三角那就是:总线,设备,驱动!
那么首先回顾一下2.6中的platform架构驱动的写法:
常规的写法都是通过platform_deiverplatform_device来进行一个类似月老牵线式的匹配!platform_driver填充

{.probe = ,.remove = ,.driver = {.name = “”,.owner = “”,},}Plarform_device 则在BSP(math-xxx)中填充:Struct platform_device{const char *name;u32 id;u32 num_resource;sruct resource *resource;}

然后进行匹配!主要看name字段是否相同!

int platform_match(struct device* dev,struct device_driver *drv){struct platform_device *pdev;pdev = container_of(dev,struct platform_device,dev);return (strncmp(pdev->name,drv->name,BUS_ID_SIZE) == 0);}

用下面的两张图也许更生动!
Old_platform
老的Probing…
probing
那么我们的3.x又是如何写的呢?

二、开始工作?

1、dts 中的节点属性含义 –出现频率最多的就是compible这个属性 
2、那么如何匹配呢?– 月老肯定还在,但是换了一个月老(21世纪了)!

三、添加一个自己的platform设备

static struct of_device_id nlm_common_ide_dt_ids[] = {         {.compatible = "netlogic,xlp-ide-commpact"},};static struct platform_driver nlm_common_ide_driver = {         .driver = {                 .name = "xlp-ide-commpact",                .owner = THIS_MODULE,                .of_match_table = nlm_common_ide_dt_ids,        },          .probe          = nlm_drv_ide_probe,        .remove         = nlm_common_ide_remove,};

上述就是新世纪(3.x)中的写法啦!

四、如何”被”执行?

/ {
#address-cells = <2>;
#size-cells = <2>;
soc {
#address-cells = <2>;
#size-cells = <1>;
compatible = “simple-bus”;
ranges = <0 0 0 0x18000000 0x04000000
1 0 0 0x16000000 0x02000000>;
serial0: serial@30000 {
…………………
};
commpact: xlp_commpact@35000 {
compatible = “netlogic,xlp-ide-commpact”;
reg = <0 0x35100 0x1000>;

                    #interrupt-cells = <1>;                    interrupts = <39>;                    interrupt-controller;            };    };    chosen {            bootargs = "console=ttyS0,9600 rdinit=/sbin/init";    };

};
看到compatible了吗?
这就是他们匹配的变量!和以前一样也是判断字符串是否相等!
那么在那匹配?
在扳级硬件编码中有如下的代码

 void __init device_tree_init(void) {         unsigned long dt_size;         void    *blob;         if (!initial_boot_params)                 panic("No device tree!\n");         /*          * boot mem available now, make a copy of the blob, and          * update initial_boot_params to point there.          */         dt_size = be32_to_cpu(initial_boot_params->totalsize);         blob = early_init_dt_alloc_memory_arch(dt_size, 8);         if (blob == NULL)                 panic("Could not allocate initial_boot_params\n");         memcpy(blob, initial_boot_params, dt_size);         nlm_fdt_blob = initial_boot_params = blob;         pr_info("fdt copied to %p, size %ld\n", blob, dt_size);         unflatten_device_tree(); } static struct of_device_id __initdata xlp_ids[] = {         { .compatible = "simple-bus", },         {}, }; int __init xlp8xx_ds_publish_devices(void) {         if (!of_have_populated_dt())                 return 0;         return of_platform_bus_probe(NULL, xlp_ids, NULL); } device_initcall(xlp8xx_ds_publish_devices);

一眼就看出了是初始化device tree的代码!
看代码流程走向…
从下往上看:
device_initcall(xlp8xx_ds_publish_devices);
注册的是xlp8xx_ds_publish_devices这个函数
跳到此函数!到174行
看到执行了两个函数
一个of_have_poplated_dr()
一个of_platform_bus_probe()
第一个函数为检查dts节点是否为空的!
如果为空则返回0
第二个函数为

 /**  * of_platform_bus_probe() - Probe the device-tree for platform buses  * @root: parent of the first level to probe or NULL for the root of the tree  * @matches: match table for bus nodes  * @parent: parent to hook devices from, NULL for toplevel  *  * Note that children of the provided root are not instantiated as devices  * unless the specified root itself matches the bus list and is not NULL.  */

可以理解为探测xlp_ids是否存在!并且是否匹配!如果匹配,创建子节点!其实就是展开子节点!
在xlp_ids 我们又看到了compible这个属性!
这里填充了simple-bus..
何为simple-bus
这种虚拟总线可以兼容很多总线设备!
到这里基本上所有的疑惑已经解开了!

五、总结

3.x版本其实改变了很多原来的东西!可以看出来Linus一怒是非常的牛逼的!而且是带着“腥风谢雨”的!
附注:Linux OF API
在drivers/of/platform.c下


By: Keven - 点滴积累

0 0