平台设备
集成SOC系统中的设备,从resource角度统一抽象为platform设备.它的优点就是实现了硬件信息和驱动的分离.
早起是通过板级文件(在内核中)修改, 但是那样需要重新编译内核,比较麻烦. 于是平台设备就**直接将硬件设备的信息放到
设备树 中, 从而驱动不在存放硬件信息, 实现硬件与驱动的分离.方便维护**
1. 把硬件设备添加到设备树:
在内核源码中arch/arm/boot/dts/exynos4412-mimi.dts
的根目录下添加硬件设备信息:
xxx_platfrom@xxxxx{
compatible = "company_name, device_name";
reg = <0x11000c40 1>,<0x11000c20 1>;
/*reg = <0x11000c40 2>;当多个连续的时,可以合在一起,访问不同的地址时,可以通过偏移实现不同地址的访问*/
};
关于ARM Data Tree 的相关介绍,查看….
2. 更改驱动程序中的加载入口:
不需要再使用字符设备的3大模块, 改为:
module_platform_driver(xxx_platform_driver); //入口声明
MODULE_LICENSE("Dual BSD/GPL"); //模块许可声明
模块的加载/卸载则通过一个结构体struct platform_driver来管理., 从入口声明的xxx_platform_driver结构体找到驱动的加载/卸载.
struct platform_driver xxx_platform_driver{
.driver = {
.name = "driver_name",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(xxx_dt_of_matches),
},
.probe = xxx_init,
.remove = xxx_exit,
};
说明:
1. 上结构体提供的.probe, .remove 对应的函数,就是模块加载/卸载的入口;
2. .of_match_table就是内核在设备驱动加载时查找的设备驱动表(这里表的名字xxx_dt_of_matches),我们的设备必须在这个表中注册后,内核才能通过这个表到 设备树中 去查有没有这个设备的注册信息. 如果有才会加载.
关于设备表的定义如下:(其中的.compatible 与 设备树中注册的相同,从而差找到)
static const struct of_device_id xxx_dt_of_matches[] = {
{ .compatible = "company_name,device_name"},
{},
};
//设备表声明
MODULE_DEVICE_TABLE(of, xxx_dt_of_matches);
3. 驱动程序的修改
模块入口函数xxx_init();函数的修改
由于原先的字符设备在初始化函数中,不需要传入参数, 而是直接通过ioremap
将硬件地址转化为内核地址, 所以是:
`int xxx_init(void);`
而通过平台设备从resource角度进行统一化管理后, 分离的驱动程序与硬件设备信息的直接转换, 转而有设备树中转了一下, 因此,在xxx_init() 函数中,需要把平台设备信息传给初始化函数, 具体的操作如下:
```
int xxx_init(struct platform_device * pdev){
KMDEV();
register_chrdev_region();
cdev_init();
cdev_add();
//以上字符设备的初始化等基本操作不变, 需要改变的就是不在直接使用物理地址,专用资源的方式访问;
struct resource *xxx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //这个resource由于会被很多地方使用, 可放在全局定义
/*这样通过resource结构体来访问,实现了硬件的屏蔽*/
unsigned int *p = ioremap(xxx_res->start, 4);
.......
}
```