基于platform机制的驱动模型
2013-02-23 18:34
441 查看
1、 哪些适用于plarform驱动?
platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,这样拥有更好的可移植性。platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。Platform driver通过platform bus获取platform_device。
通常情况下只要和内核本身运行依赖性不大的外围设备,相对独立的,拥有各自独立的资源(地址总线和IRQs),都可以用 platform_driver来管理,而timer,irq等小系统之内的设备则最好不用platfrom_driver机制。
platform_device最大的特定是CPU直接寻址设备的寄存器空间,即使对于其他总线设备,设备本身的寄存器无法通过CPU总线访问,但总线的controller仍然需要通过platform bus来管理。
总之,platfrom_driver的根本目的是为了统一管理系统的外设资源,为驱动程序提供统一的接口来访问系统资源,将驱动和资源分离,提高程序的可移植性。
2、 基于platform总线的驱动开发流程
基于Platform总线的驱动开发流程如下:
• 定义初始化platform bus
• 定义各种platform devices
• 注册各种platform devices
• 定义相关platform driver
• 注册相关platform driver
• 操作相关设备
3、 何谓platform bus?
Linux系统中许多部分对设备是如何链接的并不感兴趣,但是他们需要知道哪些类型的设备是可以使用的。设备模型提供了一种机制来对设备进行分类,在更高的功能层面上描述这些设备,并使得这些设备对用户空间可见。因此从2.6内核开始引入了设备模型。
总线是处理器和一个或多个设备之间的通道,在设备模型中, 所有的设备都通过总线相连。总线可以相互插入。设备模型展示了总线和它们所控制的设备之间的实际连接。
Platform总线是2.6 kernel中最近引入的一种虚拟总线,主要用来管理CPU的片上资源,具有更好的移植性,因此在2.6 kernel中,很多驱动都用platform改写了。
platform_bus_type的定义如下:
http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L609
609struct bus_type platform_bus_type = {
610 .name = "platform",
611 .dev_attrs = platform_dev_attrs,
612 .match = platform_match,
613 .uevent = platform_uevent,
614 .suspend = platform_suspend,
615 .suspend_late = platform_suspend_late,
616 .resume_early = platform_resume_early,
617 .resume = platform_resume,
618};
619EXPORT_SYMBOL_GPL(platform_bus_type);
http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L55
55struct bus_type {
56 const char *name;
57 struct bus_attribute *bus_attrs;
58 struct device_attribute *dev_attrs;
59 struct driver_attribute *drv_attrs;
60
61 int (*match)(struct device *dev, struct device_driver *drv);
62 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
63 int (*probe)(struct device *dev);
64 int (*remove)(struct device *dev);
65 void (*shutdown)(struct device *dev);
66
67 int (*suspend)(struct device *dev, pm_message_t state);
68 int (*suspend_late)(struct device *dev, pm_message_t state);
69 int (*resume_early)(struct device *dev);
70 int (*resume)(struct device *dev);
71
72 struct bus_type_private *p;
73};
总线名称是"platform",其只是bus_type的一种,定义了总线的属性,同时platform_bus_type还有相关操作方法,如挂起、中止、匹配及hotplug事件等。
总线bus是联系driver和device的中间枢纽。Device通过所属的bus找到driver,由match操作方法进行匹配。
4 bus、device及driver三者之间的关系
在数据结构设计上,总线、设备及驱动三者相互关联。
platform device包含device,根据device可以获得相应的bus及driver。
设备添加到总线上后形成一个双向循环链表,根据总线可以获得其上挂接的所有device,进而获得了 platform device。根据device也可以获得驱动该总线上所有设备的相关driver。
platform driver包含driver,根据driver可以获得相应的bus,进而获得bus上所有的device,进一步获得platform device,根据name对driver与platform device进行匹配,匹配成功后将device与相应的driver关联起来,即实现了platform device和platform driver的关联。
匹配成功后调用driver的probe进而调用platform driver的probe,在probe里实现驱动特定的功能。
5、 device和platform_device
Plarform device会有一个名字用于driver binding(在注册driver的时候会查找driver的目标设备的bus位置,这个过程称为driver binding),另外IRQ以及地址空间等资源也要给出 。
platform_device结构体用来描述设备的名称、资源信息等。该结构被定义在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L16中,定义原型如下:
struct platform_device
{
const char * name;
//定义平台设备的名称,此处设备的命名应和相应驱动程序命名一致
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
//定义平台设备的资源
};
在这个结构里封装了struct device及struct resource。可知:platform_device由device派生而来,是一种特殊的device。
下面来看一下platform_device结构体中最重要的一个成员struct resource * resource。struct resource被定义在http://lxr.linux.no/#linux+v2.6.25/include/linux/ioport.h#L18中,定义原型如下:
struct resource {
resource_size_t start;
//定义资源的起始地址
resource_size_t end;
//定义资源的结束地址
const char *name;
//定义资源的名称
unsigned long flags; 定义资源的类型,比如MEM,IO,IRQ,DMA类型
struct resource *parent,
*sibling,
*child;
};
这个结构表示设备所拥有的资源,即I/O端口、I/O映射内存、中断及DMA等。这里的地址指的是物理地址。
6、device_register和platform_device_register
int device_register(struct device
*dev)
{
device_initialize(dev);
return device_add(dev);
}
//初始化一个设备,然后加入到系统中
int platform_device_register(struct platform_device
*pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
我们看到注册一个platform device分为了两部分,初始化这个platform_device,然后将此platform_device添加到platform总线中。输入参数platform_device可以是静态的全局设备。
另外一种机制就是动态申请platform_device_alloc一个platform_device设备,然后通过platform_device_add_resources及platform_device_add_data等添加相关资源和属性。
无论哪一种platform_device,最终都将通过platform_device_add这册到platform总线上。
device_register()和platform_device_register()都会首先初始化设备
区别在于第二步:其实platform_device_add()包括device_add(),不过要先注册resources,然后将设备挂接到特定的platform总线。
7 device_driver和platform driver
Platform device是一种device自己是不会做事情的,要有人为它做事情,那就是platform driver。platform driver遵循linux系统的driver model。对于device的discovery/enumerate都不是driver自己完成的而是由由系统的driver注册机制完成。driver编写人员只要将注册必须的数据结构初始化并调用注册driver的kernel API就可以了。
接下来来看platform_driver结构体的原型定义,在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L48中,代码如下:
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 device_driver driver;
};
可见,它包含了设备操作的几个功能函数,同时包含了一个device_driver结构,说明device_driver是platform_driver的基类。驱动程序中需要初始化这个变量。下面看一下这个变量的定义,位于http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L121中:
struct device_driver
{
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name;
/* used
for built-in modules
*/
int (*probe)
(struct device *dev);
int (*remove)
(struct device *dev);
void (*shutdown)
(struct device *dev);
int (*suspend)
(struct device *dev, pm_message_t state);
int (*resume)
(struct device *dev);
struct attribute_group **groups;
struct driver_private *p;
};
device_driver提供了一些操作接口,但其并没有实现,相当于一些虚函数,由派生类platform_driver进行重载,无论何种类型的driver都是基于device_driver派生而来的,具体的各种操作都是基于统一的基类接口的,这样就实现了面向对象的设计。
需要注意这两个变量:name和owner。其作用主要是为了和相关的platform_device关联起来,owner的作用是说明模块的所有者,驱动程序中一般初始化为THIS_MODULE。
device_driver结构中也有一个name变量。platform_driver从字面上来看就知道是设备驱动。设备驱动是为谁服务的呢?当然是设备了。内核正是通过这个一致性来为驱动程序找到资源,即 platform_device中的resource。
8 driver_register 和platform_driver_register
内核提供的platform_driver结构体的注册函数为platform_driver_register(),其原型定义在http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L458文件中,具体实现代码如下:
int platform_driver_register(struct platform_driver
*drv)
{
drv->driver.bus
= &platform_bus_type;
/*设置成platform_bus_type这个很重要,因为driver和device是通过bus联系在一起的,具体在本例中是通过 platform_bus_type中注册的回调例程和属性来是实现的, driver与device的匹配就是通过 platform_bus_type注册的回调例程platform_match
()来完成的。*/
if (drv->probe)
drv->driver.probe
= platform_drv_probe;
//在really_probe函数中,回调了platform_drv_probe函数
if (drv->remove)
drv->driver.remove
= platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown
= platform_drv_shutdown;
if (drv->suspend)
drv->driver.suspend
= platform_drv_suspend;
if (drv->resume)
drv->driver.resume
= platform_drv_resume;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_register);
不要被上面的platform_drv_XXX吓倒了,它们其实很简单,就是将struct device转换为struct platform_device和struct platform_driver,然后调用platform_driver中的相应接口函数。那为什么不直接调用platform_drv_XXX等接口呢?这就是Linux内核中面向对象的设计思想。
device_driver提供了一些操作接口,但其并没有实现,相当于一些虚函数,由派生类platform_driver进行重载,无论何种类型的driver都是基于device_driver派生而来的,device_driver中具体的各种操作都是基于统一的基类接口的,这样就实现了面向对象的设计。
更详细的请看:/article/7600929.html
platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,这样拥有更好的可移植性。platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。Platform driver通过platform bus获取platform_device。
通常情况下只要和内核本身运行依赖性不大的外围设备,相对独立的,拥有各自独立的资源(地址总线和IRQs),都可以用 platform_driver来管理,而timer,irq等小系统之内的设备则最好不用platfrom_driver机制。
platform_device最大的特定是CPU直接寻址设备的寄存器空间,即使对于其他总线设备,设备本身的寄存器无法通过CPU总线访问,但总线的controller仍然需要通过platform bus来管理。
总之,platfrom_driver的根本目的是为了统一管理系统的外设资源,为驱动程序提供统一的接口来访问系统资源,将驱动和资源分离,提高程序的可移植性。
2、 基于platform总线的驱动开发流程
基于Platform总线的驱动开发流程如下:
• 定义初始化platform bus
• 定义各种platform devices
• 注册各种platform devices
• 定义相关platform driver
• 注册相关platform driver
• 操作相关设备
3、 何谓platform bus?
Linux系统中许多部分对设备是如何链接的并不感兴趣,但是他们需要知道哪些类型的设备是可以使用的。设备模型提供了一种机制来对设备进行分类,在更高的功能层面上描述这些设备,并使得这些设备对用户空间可见。因此从2.6内核开始引入了设备模型。
总线是处理器和一个或多个设备之间的通道,在设备模型中, 所有的设备都通过总线相连。总线可以相互插入。设备模型展示了总线和它们所控制的设备之间的实际连接。
Platform总线是2.6 kernel中最近引入的一种虚拟总线,主要用来管理CPU的片上资源,具有更好的移植性,因此在2.6 kernel中,很多驱动都用platform改写了。
platform_bus_type的定义如下:
http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L609
609struct bus_type platform_bus_type = {
610 .name = "platform",
611 .dev_attrs = platform_dev_attrs,
612 .match = platform_match,
613 .uevent = platform_uevent,
614 .suspend = platform_suspend,
615 .suspend_late = platform_suspend_late,
616 .resume_early = platform_resume_early,
617 .resume = platform_resume,
618};
619EXPORT_SYMBOL_GPL(platform_bus_type);
http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L55
55struct bus_type {
56 const char *name;
57 struct bus_attribute *bus_attrs;
58 struct device_attribute *dev_attrs;
59 struct driver_attribute *drv_attrs;
60
61 int (*match)(struct device *dev, struct device_driver *drv);
62 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
63 int (*probe)(struct device *dev);
64 int (*remove)(struct device *dev);
65 void (*shutdown)(struct device *dev);
66
67 int (*suspend)(struct device *dev, pm_message_t state);
68 int (*suspend_late)(struct device *dev, pm_message_t state);
69 int (*resume_early)(struct device *dev);
70 int (*resume)(struct device *dev);
71
72 struct bus_type_private *p;
73};
总线名称是"platform",其只是bus_type的一种,定义了总线的属性,同时platform_bus_type还有相关操作方法,如挂起、中止、匹配及hotplug事件等。
总线bus是联系driver和device的中间枢纽。Device通过所属的bus找到driver,由match操作方法进行匹配。
4 bus、device及driver三者之间的关系
在数据结构设计上,总线、设备及驱动三者相互关联。
platform device包含device,根据device可以获得相应的bus及driver。
设备添加到总线上后形成一个双向循环链表,根据总线可以获得其上挂接的所有device,进而获得了 platform device。根据device也可以获得驱动该总线上所有设备的相关driver。
platform driver包含driver,根据driver可以获得相应的bus,进而获得bus上所有的device,进一步获得platform device,根据name对driver与platform device进行匹配,匹配成功后将device与相应的driver关联起来,即实现了platform device和platform driver的关联。
匹配成功后调用driver的probe进而调用platform driver的probe,在probe里实现驱动特定的功能。
5、 device和platform_device
Plarform device会有一个名字用于driver binding(在注册driver的时候会查找driver的目标设备的bus位置,这个过程称为driver binding),另外IRQ以及地址空间等资源也要给出 。
platform_device结构体用来描述设备的名称、资源信息等。该结构被定义在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L16中,定义原型如下:
struct platform_device
{
const char * name;
//定义平台设备的名称,此处设备的命名应和相应驱动程序命名一致
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
//定义平台设备的资源
};
在这个结构里封装了struct device及struct resource。可知:platform_device由device派生而来,是一种特殊的device。
下面来看一下platform_device结构体中最重要的一个成员struct resource * resource。struct resource被定义在http://lxr.linux.no/#linux+v2.6.25/include/linux/ioport.h#L18中,定义原型如下:
struct resource {
resource_size_t start;
//定义资源的起始地址
resource_size_t end;
//定义资源的结束地址
const char *name;
//定义资源的名称
unsigned long flags; 定义资源的类型,比如MEM,IO,IRQ,DMA类型
struct resource *parent,
*sibling,
*child;
};
这个结构表示设备所拥有的资源,即I/O端口、I/O映射内存、中断及DMA等。这里的地址指的是物理地址。
6、device_register和platform_device_register
int device_register(struct device
*dev)
{
device_initialize(dev);
return device_add(dev);
}
//初始化一个设备,然后加入到系统中
int platform_device_register(struct platform_device
*pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
我们看到注册一个platform device分为了两部分,初始化这个platform_device,然后将此platform_device添加到platform总线中。输入参数platform_device可以是静态的全局设备。
另外一种机制就是动态申请platform_device_alloc一个platform_device设备,然后通过platform_device_add_resources及platform_device_add_data等添加相关资源和属性。
无论哪一种platform_device,最终都将通过platform_device_add这册到platform总线上。
device_register()和platform_device_register()都会首先初始化设备
区别在于第二步:其实platform_device_add()包括device_add(),不过要先注册resources,然后将设备挂接到特定的platform总线。
7 device_driver和platform driver
Platform device是一种device自己是不会做事情的,要有人为它做事情,那就是platform driver。platform driver遵循linux系统的driver model。对于device的discovery/enumerate都不是driver自己完成的而是由由系统的driver注册机制完成。driver编写人员只要将注册必须的数据结构初始化并调用注册driver的kernel API就可以了。
接下来来看platform_driver结构体的原型定义,在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L48中,代码如下:
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 device_driver driver;
};
可见,它包含了设备操作的几个功能函数,同时包含了一个device_driver结构,说明device_driver是platform_driver的基类。驱动程序中需要初始化这个变量。下面看一下这个变量的定义,位于http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L121中:
struct device_driver
{
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name;
/* used
for built-in modules
*/
int (*probe)
(struct device *dev);
int (*remove)
(struct device *dev);
void (*shutdown)
(struct device *dev);
int (*suspend)
(struct device *dev, pm_message_t state);
int (*resume)
(struct device *dev);
struct attribute_group **groups;
struct driver_private *p;
};
device_driver提供了一些操作接口,但其并没有实现,相当于一些虚函数,由派生类platform_driver进行重载,无论何种类型的driver都是基于device_driver派生而来的,具体的各种操作都是基于统一的基类接口的,这样就实现了面向对象的设计。
需要注意这两个变量:name和owner。其作用主要是为了和相关的platform_device关联起来,owner的作用是说明模块的所有者,驱动程序中一般初始化为THIS_MODULE。
device_driver结构中也有一个name变量。platform_driver从字面上来看就知道是设备驱动。设备驱动是为谁服务的呢?当然是设备了。内核正是通过这个一致性来为驱动程序找到资源,即 platform_device中的resource。
8 driver_register 和platform_driver_register
内核提供的platform_driver结构体的注册函数为platform_driver_register(),其原型定义在http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L458文件中,具体实现代码如下:
int platform_driver_register(struct platform_driver
*drv)
{
drv->driver.bus
= &platform_bus_type;
/*设置成platform_bus_type这个很重要,因为driver和device是通过bus联系在一起的,具体在本例中是通过 platform_bus_type中注册的回调例程和属性来是实现的, driver与device的匹配就是通过 platform_bus_type注册的回调例程platform_match
()来完成的。*/
if (drv->probe)
drv->driver.probe
= platform_drv_probe;
//在really_probe函数中,回调了platform_drv_probe函数
if (drv->remove)
drv->driver.remove
= platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown
= platform_drv_shutdown;
if (drv->suspend)
drv->driver.suspend
= platform_drv_suspend;
if (drv->resume)
drv->driver.resume
= platform_drv_resume;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_register);
不要被上面的platform_drv_XXX吓倒了,它们其实很简单,就是将struct device转换为struct platform_device和struct platform_driver,然后调用platform_driver中的相应接口函数。那为什么不直接调用platform_drv_XXX等接口呢?这就是Linux内核中面向对象的设计思想。
device_driver提供了一些操作接口,但其并没有实现,相当于一些虚函数,由派生类platform_driver进行重载,无论何种类型的driver都是基于device_driver派生而来的,device_driver中具体的各种操作都是基于统一的基类接口的,这样就实现了面向对象的设计。
更详细的请看:/article/7600929.html
相关文章推荐
- 详解Linux2.6内核中基于platform机制的驱动模型
- 【嵌入式Linux学习七步曲之第四篇 Linux内核移植】详解Linux2.6内核中基于platform机制的驱动模型
- [转]Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型(续)
- 详解Linux2.6内核中基于platform机制的驱动模型
- Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型<强烈推荐,这是一篇学习驱动模型千年一遇的好文章>
- (转)详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型-
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型 (经典)
- 详解Linux2.6内核中基于platform机制的驱动模型
- 详解Linux2.6内核中基于platform机制的驱动模型