platform总线

1.一个重要思想
分离思想:将设备和驱动进行分离,各自管理。直到一端加入到总线,进行匹配。
模型
2、什么是platform总线?
相对于USB、PCI、I2C、SPI等物理总线来说,platform总线是一种虚拟、抽象出来的总线,实际中并不存在这样的总线。那为什么需要platform总线呢?其实是Linux设备驱动模型为了保持设备驱动的统一性而虚拟出来的总线。因为对于usb设备、i2c设备、pci设备、spi设备等等,他们与cpu的通信都是直接挂在相应的总线下面与我们的cpu进行数据交互的,但是在我们的嵌入式系统当中,并不是所有的设备都能够归属于这些常见的总线,在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设却不依附与此类总线。所以Linux驱动模型为了保持完整性,将这些设备挂在一条虚拟的总线上(platform总线),而不至于使得有些设备挂在总线上,另一些设备没有挂在总线上。
platform总线相关代码声明:linux/platform_device.h 文件

3、platform总线的两个重点结构体platform_device和platform_driver
对于任何一种Linux设备驱动模型下的总线都由两个部分组成:描述设备相关的结构体和描述驱动相关的结构体在platform总线下就是platform_device和platform_driver,下面是对两个结构体的各个元素进行分析:
(1)platform_device结构体及其中的结构体分析

struct platform_device {           
      const char * name;      //平台设备的名字
      int id;                 //ID区分设备名字,如果一个驱动对应一个设备,传-1
      struct device dev;      //描述设备信息device结构体
      u32 num_resources;      //资源结构体数量,资源信息结构体数组的大小
      struct resource * resource; //资源结构体,一般定义一个数组
};
struct device {
    struct device_driver *driver;  //设备驱动的结构体指针
    struct device_node *of_node;   //设备树节点
    u32 id;	
    void (*release)(struct device *dev);  //设备端卸载的时候,须调用的函数
};
struct resource {
	resource_size_t start;      //起始地址
	resource_size_t end;        //结束地址
	const char *name;           //资源名字
	unsigned long flags;        //标志 IORESOURCE_IO IORESOURCE_MEM 
                               //IORESOURCE_IRQ
}; 

设备端调用的代码

int platform_device_register(struct platform_device *pdev);
功能:platfrom平台总线设备注册
参数:
    @pdev    platform平台总线设备端结构体指针
返回值:成功返回0,失败返回负数错误码

void platform_device_unregister(struct platform_device *); 
功能:platfrom平台总线设备卸载
参数:
    @pdev    platform平台总线设备端结构体指针
返回值:成功返回0,失败返回负数错误码

(2)platform_driver结构体及其中的结构体分析

struct platform_driver {
	int (*probe)(struct platform_device *);   //获取设备信息,在匹配成功调用
	int (*remove)(struct platform_device *);   //在移除的时候调用
	struct device_driver driver;
	const struct platform_device_id *id_table; //id_table表
};

struct device_driver {
	const char		*name;    //名字  匹配
	struct bus_type		*bus;     //总线信息结构体
	struct module		*owner;   //THIS_MODULE
	const struct of_device_id	*of_match_table;    //设备树的相关信息
};

struct platform_device_id {
	char name[PLATFORM_NAME_SIZE];   //名字
	kernel_ulong_t driver_dat;
};

驱动端调用的代码

int platform_driver_register(struct platform_driver *pdrv);
功能:platform平台总线驱动端注册函数
参数:
    @pdrv   platform平台总线驱动端结构体指针
返回值:成功返回0,失败返回负数错误码    

void platform_driver_unregister(struct platform_driver *);
功能:platform平台总线驱动端卸载函数
参数:
    @pdrv   platform平台总线驱动端结构体指针
返回值:成功返回0,失败返回负数错误码  

重点:
一.platform驱动注册过程:

platform_driver_register
  --->>>driver_register(&drv->driver);
      --->>>bus_add_driver(drv);
          --->>>driver_attach(drv);   //驱动绑定设备
                  /*遍历设备端的链表,完成匹配*/
              --->>>bus_for_each_dev(drv->bus, NULL, drv,__driver_attach); 
                  --->>>__driver_attach
                      --->>>driver_match_device(drv, dev)
static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);
    /*和设备树进行匹配*/
	if (of_driver_match_device(dev, drv))
		return 1;

	/* 和id_table表进行匹配 */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* 和名字进行匹配*/
	return (strcmp(pdev->name, drv->name) == 0);
}

二.platform设备端注册:

platform_device_register
  --->>>platform_device_add(pdev);
    --->>>device_add(&pdev->dev);
       --->>>bus_probe_device(dev);
         --->>>device_attach(dev);
           --->>>bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

以上调用的最后:

**driver_probe_device**

总结:platform平台总线,设备和驱动在注册的过程中,都会遍历对方的链表,来查找是否有匹配的,如果有匹配的,就会调用驱动中的probe探测函数,获取设备信息。

发布了3 篇原创文章 · 获赞 22 · 访问量 1158

猜你喜欢

转载自blog.csdn.net/xjpyinxll/article/details/104522648
今日推荐