标签:数据信息 dmesg res 释放 null 指针 初始 img 简介
1. 简介:
转自: https://blog.csdn.net/qqliyunpeng/article/details/52700331
1.1 platform 总线是虚拟总线,当使用这个虚拟总线是带来的好处主要有两点:
(1)使得设备被挂接在一个总线上,因此,符合 Linux 2.6 的设备模型。其结果是,配套的sysfs 结点、设备电源管理都成为可能。
(2)隔离BSP和驱动。在BSP中定义platform 设备和设备使用的资源、设备的具体配置信息,而在驱动中,只需要通过通用 API 去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。
1.2 对platform中的设备和驱动的理解可以用如下的比喻:
总线是红娘,设备是男方,驱动是女方:
红娘负责男方和女方的撮合
男方或女方找到红娘,来登记,看有没有合适的姑娘 -- 设备或驱动的注册
红娘这个时候看看有没有合适的八字(二者的name字段) -- match 函数进行匹配,看name是不是相同
如果没有,就等着,知道匹配的了,就结婚,结完婚,男方向女方交代,我有多少存款,我的房子在哪,钱放哪等等(struct resource *resource),女方去拿存款买菜啦,买衣服了等等(匹配成功后执行 int (*probe)(struct platform_device *) 匹配成功后执行的第一个函数),当然,如果男的跟小三跑了,女方也不会继续下去的。
1.3 在 linux 系统中,设备可以是:
模块文件
平台文件 (arch/arm/mach-s3c24xx/mach-mini2440.c)
设备树文件 (arch/arm/boot/dts/)
2. 下面就介绍介绍如何使用 platform 总线:
2.1 函数原型
①设备:相关结构体是 struct platform_device
②驱动:相关结构体是 struct platform_driver
需要包含的头文件是:linux/platform_device.h
struct platform_device {
const char * name; / * 设备名 */
u32 id;
struct device dev;
u32 num_resources; / * 设备所使用各类资源数量 */
struct resource * resource; / * 资源 */
};
struct platform_driver {
int (*probe)(struct platform_device *);//驱动和设备匹配成功,内核自动调用
int (*remove)(struct platform_device *);//匹配后分开的时候,执行
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct pm_ext_ops *pm;
struct device_driver driver;
};
①②的实现都遵循: --定义,初始化,注册,释放,
过程 |
设备 |
驱动 |
定义 |
成员.dev.release 的函数实现 |
.probe .remove 的函数实现 |
初始化 |
struct platform_device test_device = {...} |
struct platform_driver test_driver = {...} |
注册 |
platform_device_register(&test_device); |
platform_driver_register(&test_driver); |
释放 |
platform_device_unregister(&test_device); |
platform_driver_unregister(&test_driver); |
总线的匹配函数在 platform_bus_type 实例中的 match 函数,匹配的方法是看 device 和 driver 的名字是不是相同
2.2 注册和注销
platform_device的定义通常在 BSP 的板文件中实现,在板文件中,将 platform_device 归纳为一个数组,最终通过 platform_add_devices() 函数统一注册。
platform_add_devices() 函数可以将平台设备添加到系统中,这个函数的原型为:
int platform_add_devices(struct platform_device **devs, int num);
devs,平台设备数组的指针
num,平台设备的数量
它内部调用了 platform_device_register() 函数用于注册单个的平台设备。
platform_driver 通过platform_driver_register()、platform_driver_unregister()函数进行platform_driver 的注册与注销,而原先对于模块中的字符设备的注册和注销工作要移交到 platform_driver 的 probe() 和 remove() 成员函数中。
2.3 为设备添加资源和数据
在 struct platform_device 中填充 struct resource结构体:
struct resource test_res={
.start = 11,
.end = 22,
.flags = IORESOURCE_MEM,
};
内容:
.start,区域的开始地址,如果是内存类型,表示内存的开始地址,如果是IRQ,则表示中断号的开始值
.end,区域的结束地址,如果是内存类型,表示内存的结束地址,如果是IRQ,则表示中断号的结束值,如果只有一个中断,则开始值和结束值相同
.flags,类型:
IORESOURCE_MEM ,内存类型
IORESOURCE_IRQ ,中断类型
IORESOURCE_DMA ,
...
驱动侧用platform_get_resource 来获得设备信息:
一般使用方法:
struct resource * res =NULL;
res=platform_get_resource(dev,IORESOURCE_MEM,0);
函数的原型:
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num)
参数:
dev,struct platform_device 结构体
type,同传递过来的设备信息中的flags,有IORESOURCE_MEM 、IORESOURCE_IRQ ...
num,同类设备信息的索引,比如类型相同的IORESOURCE_MEM,num会被系统自动分配,从0开始
设备除了可以在 BSP 中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断、内存、DMA 通道以外,可能还会有一些配置信息,而这些配置信息也依赖于板,不适宜直接放置在设备驱动本身,因此,platform 也提供了 platform_data 的支持。platform_data 的形式是自定义的,如对于 DM9000 网卡而言,platform_data 为一个 dm9000_plat_data 结构体,我们就可以将 MAC 地址、总线宽度、板上有无 EEPROM 信息等放入 platform_data:
static struct dm9000_plat_data ldd6410_dm9000_platdata = {
.flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM,
.dev_addr = { 0x0, 0x16, 0xd4, 0x9f, 0xed, 0xa4 },
};
static struct platform_device ldd6410_dm9000 = {
.name= "dm9000",
.id= 0,
.num_resources= ARRAY_SIZE(ldd6410_dm9000_resource),
.resource =ldd6410_dm9000_resource,
.dev = {
.platform_data = &ldd6410_dm9000_platdata,
}
};
而在 DM9000 网卡的驱动中,通过如下方式就拿到了 platform_data:
struct dm9000_plat_data *pdata = pdev->dev.platform_data;
其中,pdev 为 platform_device 的指针。
2.4 对platform的理解可以用如下图:
3. 例子:
3.1 对于一个普通的platform架构的程序很简单:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
MODULE_LICENSE("Dual BSD/GPL");
static int driver_probe(struct platform_device *dev)
{
printk("platform: match ok!\n");
return 0;
}
static int driver_remove(struct platform_device *dev)
{
printk("platform: driver remove\n");
return 0;
}
static void device_release(struct device *dev)
{
printk("platform: device release\n");
}
struct platform_device test_device = {
.id = -1,
.name = "test_device1",
.dev.release = device_release,
};
struct platform_driver test_driver = {
.probe = driver_probe,
.remove = driver_remove,
.driver = {
.name = "test_device",
},
};
static int __init s5pc100_platform_init(void)
{
platform_device_register(&test_device);
platform_driver_register(&test_driver);
return 0;
}
static void __exit s5pc100_platform_exit(void)
{
platform_device_unregister(&test_device);
platform_driver_unregister(&test_driver);
}
module_init(s5pc100_platform_init);
module_exit(s5pc100_platform_exit);
Makefile 参照前边的内容,是一样的
3.2 而对于设备资源的取得例子如下:
一个设备信息:
.
├── dev
│ ├── dev.c
│ └── Makefile
└── dri
├── dri.c
└── Makefile
dev.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
MODULE_LICENSE("Dual BSD/GPL");
struct resource test_res={
.start = 11,
.end = 22,
.flags = IORESOURCE_MEM,
};
static void device_release(struct device *dev)
{
printk("platform: device release\n");
}
struct platform_device test_device = {
.id = -1,
.name = "test_device",
.dev.release = device_release,
.num_resources =1,
.resource = &test_res,
};
static int __init s5pc100_platform_init(void)
{
printk("dev init\n");
platform_device_register(&test_device);
return 0;
}
static void __exit s5pc100_platform_exit(void)
{
printk("dev exit\n");
platform_device_unregister(&test_device);
}
module_init(s5pc100_platform_init);
module_exit(s5pc100_platform_exit);
dri.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
MODULE_LICENSE("Dual BSD/GPL");
static int driver_probe(struct platform_device *dev)
{
struct resource * res =NULL;
printk("platform: match ok!\n");
res=platform_get_resource(dev,IORESOURCE_MEM,0);
if(res == NULL)
{
printk("platform_get_resource error\n");
return -EINVAL;
}
printk("res->start:%d\n",res->start); //11
printk("res->end:%d\n",res->end); //22
printk("res->flags:%#x\n",res->flags); //0x200
printk("platform probe end\n");
return 0;
}
static int driver_remove(struct platform_device *dev)
{
printk("platform: driver remove\n");
return 0;
}
struct platform_driver test_driver = {
.probe = driver_probe,
.remove = driver_remove,
.driver = {
.name = "test_device",
},
};
static int __init s5pc100_platform_init(void)
{
printk("dri init\n");
platform_driver_register(&test_driver);
return 0;
}
static void __exit s5pc100_platform_exit(void)
{
printk("dri exit\n");
platform_driver_unregister(&test_driver);
}
module_init(s5pc100_platform_init);
module_exit(s5pc100_platform_exit);
Makefile这里也不写出来,参照前边的写法
运行结果如下:
$sudo insmod dev.ko
$ dmesg
[ 2988.851954] dev init
$ cd ../dri/
$ sudo insmod dri.ko
$ dmesg
[ 2988.851954] dev init
[ 3008.968420] dri init
[ 3008.968466] platform: match ok!
[ 3008.968467] res->start:11
[ 3008.968468] res->end:22
[ 3008.968469] res->flags:0x200
[ 3008.968469] platform probe end
$ sudo rmmod dev
$ dmesg
[ 2988.851954] dev init
[ 3008.968420] dri init
[ 3008.968466] platform: match ok!
[ 3008.968467] res->start:11
[ 3008.968468] res->end:22
[ 3008.968469] res->flags:0x200
[ 3008.968469] platform probe end
[ 3025.176478] dev exit
[ 3025.176508] platform: driver remove
[ 3025.176556] platform: device release
$ sudo rmmod dri
$ sudo rmmod dri
$ dmesg
[ 2988.851954] dev init
[ 3008.968420] dri init
[ 3008.968466] platform: match ok!
[ 3008.968467] res->start:11
[ 3008.968468] res->end:22
[ 3008.968469] res->flags:0x200
[ 3008.968469] platform probe end
[ 3025.176478] dev exit
[ 3025.176508] platform: driver remove
[ 3025.176556] platform: device release
[ 3035.936023] dri exit
3.3 多个设备信息:
结构如上边一个设备信息
dev.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
MODULE_LICENSE("Dual BSD/GPL");
struct resource test_res[]={
[0]={
.start = 11,
.end = 22,
.flags = IORESOURCE_MEM,
},
[1]={
.start = 99,
.end = 99,
.flags = IORESOURCE_IRQ,
},
[2]={
.start = 33,
.end = 44,
.flags = IORESOURCE_MEM,
},
};
static void device_release(struct device *dev)
{
printk("platform: device release\n");
}
struct platform_device test_device = {
.id = -1,
.name = "test_device",
.dev.release = device_release,
.num_resources =ARRAY_SIZE(test_res),
.resource = test_res,
};
static int __init s5pc100_platform_init(void)
{
printk("dev init\n");
platform_device_register(&test_device);
return 0;
}
static void __exit s5pc100_platform_exit(void)
{
printk("dev exit\n");
platform_device_unregister(&test_device);
}
module_init(s5pc100_platform_init);
module_exit(s5pc100_platform_exit);
dri.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
MODULE_LICENSE("Dual BSD/GPL");
static int driver_probe(struct platform_device *dev)
{
struct resource * res =NULL;
printk("platform: match ok!\n");
res=platform_get_resource(dev, IORESOURCE_MEM, 0);
if(res == NULL)
{
printk("platform_get_resource error\n");
return -EINVAL;
}
printk("res->start:%d\n",res->start); //11
printk("res->end:%d\n",res->end); //22
printk("res->flags:%#x\n",res->flags); //0x200
res=platform_get_resource(dev, IORESOURCE_MEM, 1);
if(res == NULL)
{
printk("platform_get_resource error\n");
return -EINVAL;
}
printk("res->start:%d\n",res->start); //33
printk("res->end:%d\n",res->end); //44
printk("res->flags:%#x\n",res->flags); //0x200
res=platform_get_resource(dev,IORESOURCE_IRQ,0);
if(res == NULL)
{
printk("platform_get_resource error\n");
return -EINVAL;
}
printk("res->start:%d\n",res->start); //99
printk("res->end:%d\n",res->end); //99
printk("res->flags:%#x\n",res->flags); //0x400
printk("platform probe end\n");
return 0;
}
static int driver_remove(struct platform_device *dev)
{
printk("platform: driver remove\n");
return 0;
}
struct platform_driver test_driver = {
.probe = driver_probe,
.remove = driver_remove,
.driver = {
.name = "test_device",
},
};
static int __init s5pc100_platform_init(void)
{
printk("dri init\n");
platform_driver_register(&test_driver);
return 0;
}
static void __exit s5pc100_platform_exit(void)
{
printk("dri exit\n");
platform_driver_unregister(&test_driver);
}
module_init(s5pc100_platform_init);
module_exit(s5pc100_platform_exit);
运行结果也不再打印
platform 架构
标签:数据信息 dmesg res 释放 null 指针 初始 img 简介
原文地址:https://www.cnblogs.com/S-ong/p/9313910.html