平台设备和驱动是怎么匹配的?

本文介绍了Linux系统中平台设备(platform_device)与平台驱动(platform_driver)的匹配原理及过程。详细解析了两种匹配方式:使用id_table进行匹配和使用设备名与驱动名进行匹配,并通过代码示例展示了如何实现多设备的兼容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

平台设备和驱动是怎么匹配的?

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字段不同而已。



 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值