首先,我们来理解一下在platform架构中的知识点。
在Linux 2.6的设备驱动模型中,关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、I2 C、SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设等确不依附于此类总线。基于这一背景,Linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为 platform_driver。
也就是说platform的设备是外设或者其控制器,就像EC外设一样,被申请为platform结构。
整个platform架构主要涉及到三个结构体
struct platform_driver /*驱动*/
struct platform device /*设备*/
struct resource /*资源*/
下面来看一看各个结构体的组成
一.platform_driver
1 struct platform_driver { 2 3 int (*probe)(struct platform_device *); 4 5 int (*remove)(struct platform_device *); 6 7 void (*shutdown)(struct platform_device *); 8 9 int (*suspend)(struct platform_device *, pm_message_t state); 10 11 int (*resume)(struct platform_device *); 12 13 struct device_driver driver; 14 15 const struct platform_device_id *id_table; 16 17 };
我们可以看见其中包含了probe(),remove(),shutdown(),suspend(),resume()等的函数,这些都需要用驱动来实现。
其中最主要的就是下面这几项:
- int (*probe)(struct platform_device *);
这是一个匹配函数,通过比较platform_driver和platform_device的name来进行匹配。还有就是会在这个函数中初始化一些和该驱动有关的初始化。
例如,在3A代码中,wpce775l_probe()函数中实现了与EC相关的backlight,power等的初始化。
因此该函数是一个比较杂的函数,需要在具体的情况下具体分析吧。
- struct device_driver driver;
在这个结构体中,主要实现const char *name;和struct module *owner;这两个项。
其中name就是我们用来匹配设备和驱动的。必须与device的name一致。
owner则表明该模块的拥有者,一般都是THIS_MODULE。
- const struct platform_device_id *id_table;
这个虽然不是必实现的,但是这个的实现是另外一种匹配驱动和设备的方法。
这种方式中,匹配通过id_table来实现。这种实现的最终还是通过名字对应来匹配,但是匹配的名字被列在一个表中,platform_device的name和这个表中的每一个值进行比较,知道找到相同的那一个。
主要是为了实现一个platform_driver对应多个platform_device的情况。设备之间的区别是通过platform_device_id的.driver_data成员区分的,从而在连接设备与驱动时可以针对设备区别对加载的驱动程序进行调整。
二.platform_device
1 struct platform_device { 2 3 const char * name; 4 5 int id; 6 7 struct device dev; 8 9 u32 num_resources; 10 11 struct resource * resource; 12 13 const struct platform_device_id *id_entry; 14 15 struct pdev_archdata archdata; 16 17 };
我们看见其中主要的是一些device的属性。
我们需要注意的是以下几项:
- const char *name;
这个应该不需要过多的去说明了,就是我们匹配用的name。匹配中的关键,不管在driver中用什么哪种方式去匹配,归根结底还是用了name的方法。
- int id
设备id,用于给插入给该总线并且具有相同name的设备编号,如果只有一个设备的话填-1。
一般我们会见到XXX.0就是因为在这里的id=0的缘故。当id=-1是,显示出来的就是XXX。
- struct resource * resource;
资源数
- struct resource * resource;
用于存放资源的数组
三.resource
1 struct resource { 2 3 resource_size_t start; 4 5 resource_size_t end; 6 7 const char *name; 8 9 unsigned long flags; 10 11 struct resource *parent, *sibling, *child; 12 13 };
在该结构体中主要的就是资源的分配。具体就是资源的起始地址,结束地址,name以及flag标志。同样,这里的name要和platform_device和platform_driver中的name要一致。
这里复杂一点就是flag。flags可以为IORESOURCE_IO, IORESOURCE_MEM, IORESOURCE_IRQ, IORESOURCE_DMA等。start、end的含义会随着flags而变更。
如当flags为IORESOURCE_MEM时,start、end分别表示该platform_device占据的内存的开始地址和结束地址;当flags为IORESOURCE_IRQ时,start、end分别表示该platform_device使用的中断号的开始值和结束值,如果只使用了1个中断号,开始和结束值相同。 对于同种类型的资源而言,可以有多份,譬如说某设备占据了2个内存区域,则可以定义2个IORESOURCE_MEM资源。
这样,我们就将platform框架中有关的结构体简单的介绍了一下.
http://www.cnblogs.com/xiaoya901109/archive/2012/11/07/2759151.html