一. 简介
 前面我们讲了设备驱动的分离,并且引出了总线 (bus) 、驱动 (driver) 和设备 (device) 模型,比如  I2C 、 SPI 、 USB  等总线。 
 
 
 但是,在  SOC  中有些外设是没有总线这个概念的,但是又要使用总 线、驱动和设备模型该怎么办呢? 
 
 为了解决此问题, Linux  提出了  platform  这个虚拟总线,相应 的就有  platform_driver  和 platform_device 。  
 
 
本文来学习 Linux内核中的 platform总线。
二. Linux下platform总线
1. platform总线的结构体
 Linux 系统内核使用  bus_type  结构体表示总线,此结构体定义在文件 include/linux/device.h ,bus_type  结构体内容如下: 
 
 
struct bus_type {const char		*name;const char		*dev_name;struct device		*dev_root;struct device_attribute	*dev_attrs;	/* use dev_groups instead */const struct attribute_group **bus_groups;const struct attribute_group **dev_groups;const struct attribute_group **drv_groups;int (*match)(struct device *dev, struct device_driver *drv);int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;const struct iommu_ops *iommu_ops;struct subsys_private *p;struct lock_class_key lock_key;
};第 10 行,match 函数,此函数就是完成设备和驱动之间匹配的。总线就是使用 match 函数来根据注册的设备来查找对应的驱动,或者根据注册的驱动来查找相应的设备,因此,每一条总线都必须实现此函数。
match 函数有 两个参数:dev 和 drv,这两个参数分别为 device 和 device_driver 类型,也就是设备和驱动。
 platform  总线是  bus_type  的一个具体实例,定义在文件  drivers/base/platform.c , platform  总线定义如下:  
 
struct bus_type platform_bus_type = {.name		= "platform",.dev_groups	= platform_dev_groups,.match		= platform_match,.uevent		= platform_uevent,.pm		= &platform_dev_pm_ops,
}; platform_bus_type  就是  platform  平台总线。 其中, platform_match  就是匹配函数。 
 
 
2. 驱动与设备是如何匹配的?
 我们来看  一下驱动和设备是如何匹配的, platform_match  函数定义在文件  drivers/base/platform.c  中,函 数内容如下所示:  
 
 
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);/* When driver_override is set, only bind to the matching driver */if (pdev->driver_override)return !strcmp(pdev->driver_override, drv->name);/* Attempt an OF style match first */if (of_driver_match_device(dev, drv))return 1;/* Then try ACPI style match */if (acpi_driver_match_device(dev, drv))return 1;/* Then try to match against the id table */if (pdrv->id_table)return platform_match_id(pdrv->id_table, pdev) != NULL;/* fall-back to driver name match */return (strcmp(pdev->name, drv->name) == 0);
} 驱动和设备的匹配有四种方法,我们依次来看一下:  
 
 
 第 11~12  行,第一种匹配方式,  OF  类型的匹配,也就是设备树采用的匹配方式,  
 
 of_driver_match_device  函数定义在文件  include/linux/of_device.h  中。 
 
 device_driver 结构体  ( 表示 设备驱动 )  中有个名为  of_match_table 的成员变量,此成员变量保存着驱动的  compatible  匹配表,  设备树中的每个设备节点的  compatible  属性会和  of_match_table  表中的所有成员比较,查看是 否有相同的条目,如果有的话,就表示设备和此驱动匹配,设备和驱动匹配成功以后  probe  函数 就会执行。  
 
 
 第 15~16 行,第二种匹配方式, ACPI  匹配方式。  
 
 第 19~20 行,第三种匹配方式, id_table  匹配,每个  platform_driver  结构体有一个  id_table  
 
 成员变量,顾名思义,保存了很多  id  信息。这些  id  信息存放着这个  platform  驱动所支持的驱 动类型。  
 
 第 23  行,第四种匹配方式,如果第三种匹配方式的  id_table  不存在的话,就直接比较驱动和 设备的  name  字段,看看是不是相等,如果相等的话就匹配成功。  
 
 
 对于支持设备树的 Linux 版本号,一般设备驱动为了兼容性,都支持设备树和无设备树两种匹配方式。 
 
 也就是第一种匹配方式一般都会存在,第三种和第四种只要存在一种就可以,一般用的最多的还是第四种,也就是直接比较驱动和设备的 name 字段,毕竟这种方式最简单了。