平台设备和驱动是怎么匹配的?
在Linux源码的sourceindight工程下搜索platform_device.h,这个文件是设备结构体,驱动结构体的定义,还有操作这两个结构体的函数如:平台设备注册,平台驱动注册。先看两个结构体:
//平台设备
struct platform_device {
const char * name; //设备名,可以用来和驱动进行匹配
int id; //作用?
struct device dev; // platform_device相当于是从dev继承派生而来的
u32 num_resources; //资源数目
struct resource * resource; //资源数组首地址
struct platform_device_id *id_entry; //和驱动匹配后用来记录下此设备属于驱动idtable中的哪一个
/* arch specific additions */
struct pdev_archdata archdata;
};
//平台驱动
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 (*resume)(struct platform_device *);
struct device_driver driver;//匹配的设备的所有信息,platform_driver相当于是从driver继承派生而来的
struct platform_device_id *id_table; //所有可以匹配的设备的idtable
};
/**********************/转载请注明原文地址 http://blog.youkuaiyun.com/oyhb_1992/article/details/77477112
struct device_driver {
const char *name; //匹配的设备名
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
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);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
//匹配算法:打开driver\base\platform.c文件,有个匹配函数
方法一:用id_table进行匹配
static int platform_match(struct device *dev, struct device_driver *drv)
{
//由前面介绍platform_device相当于是从dev继承派生而来的,platform_driver相当于是从driver继承派生而来的,这里由结构体中的成员变量可以反推出整个结构体变量的首地址
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* match against the id table first */
if (pdrv->id_table)//如果id_table不为空,则用id进行匹配,然后直接返回不再调用name匹配算法
return platform_match_id(pdrv->id_table, pdev) != NULL;
//匹配方法二
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
static const struct platform_device_id *platform_match_id(
struct platform_device_id *id,
struct platform_device *pdev)
{
while (id->name[0]) { //id_table数组没有到尾
if (strcmp(pdev->name, id->name) == 0) { //本质上还是还是通过名字对应来匹配,但是匹配的名字被列在一个表中,这样一个驱动就可以匹配多个不同name的驱动了,只要设备的pdev->name在id_table数组列表的name中就可以匹配。
pdev->id_entry = id; //和设备匹配后用来记录下此设备属于驱动idtable中的哪一个
return id;
}
id++; //指向id_table数组的下一个数组成员
}
return NULL;
}
方法二:用设备名和驱动名进行匹配,这样就只能一个驱动匹配一个设备
源码举例1:
/drivers/mtd/nand/S3C2410.c
static struct platform_device_id s3c24xx_driver_ids[] = {
{
.name = "s3c2410-nand",
.driver_data = TYPE_S3C2410,
}, {
.name = "s3c2440-nand",
.driver_data = TYPE_S3C2440,
}, {
.name = "s3c2412-nand",
.driver_data = TYPE_S3C2412,
}, {
.name = "s3c6400-nand",
.driver_data = TYPE_S3C2412, /* compatible with 2412 */
},
{ }
};
static struct platform_driver s3c24xx_nand_driver = {
.probe = s3c24xx_nand_probe,
.remove = s3c24xx_nand_remove,
.suspend = s3c24xx_nand_suspend,
.resume = s3c24xx_nand_resume,
.id_table = s3c24xx_driver_ids,//这个驱动支持的设备id表
.driver = {
.name = "s3c24xx-nand",
.owner = THIS_MODULE,
},
};
源码举例2:
static struct platform_device_id s3c_rtc_driver_ids[] = {
{
.name = "s3c2410-rtc",
.driver_data = TYPE_S3C2410,
}, {
.name = "s3c2416-rtc",
.driver_data = TYPE_S3C2416,
}, {
.name = "s3c2443-rtc",
.driver_data = TYPE_S3C2443,
}, {
.name = "s3c64xx-rtc",
.driver_data = TYPE_S3C64XX,
},
{ }
};
static struct platform_device_id s3c_rtc_driver_ids[] = {
{
.name = "s3c2410-rtc",
.driver_data = TYPE_S3C2410,
}, {
.name = "s3c2416-rtc",
.driver_data = TYPE_S3C2416,
}, {
.name = "s3c2443-rtc",
.driver_data = TYPE_S3C2443,
}, {
.name = "s3c64xx-rtc",
.driver_data = TYPE_S3C64XX,
},
{ }
};
上面就是platform_device_id,可以看到这个驱动支持的设备不只一种,包括2410、2416等等。而Platform_driver定义如下:
static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = __devexit_p(s3c_rtc_remove),
.suspend = s3c_rtc_suspend,
.resume = s3c_rtc_resume,
.id_table = s3c_rtc_driver_ids,
.driver = {
.name = "s3c-rtc",
.owner = THIS_MODULE,
.of_match_table = s3c_rtc_dt_match,
},
};
2410的platfrom_device定义如下:
struct platform_device s3c_device_rtc = {
.name = "s3c2410-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_rtc_resource),
.resource = s3c_rtc_resource,
};
通过id_table这种方式有什么好处呢,如果只是简单的比较驱动里的.driver.name字段和设备里的.name是否相同,那么一个驱动只能支持特定的一个设备,而如果通过id_table的方式呢,一个驱动.id_table可以和多个驱动的设备里的.name匹配是否相同,支持很多个设备,而它们只是name字段不同而已。