精华内容
下载资源
问答
  • Linux使用设备树的i2c驱动与设备匹配有3种方式: of_driver_match_device acpi_driver_match_device i2c_match_id 源码: static int i2c_device_match(struct device *dev, struct device_driver *drv) { ...

    Linux使用设备树的i2c驱动与设备匹配有3种方式:

    • of_driver_match_device
    • acpi_driver_match_device
    • i2c_match_id

    源码:

    static int i2c_device_match(struct device *dev, struct device_driver *drv)
    {
            struct i2c_client       *client = i2c_verify_client(dev);
            struct i2c_driver       *driver;
    
            if (!client)
                    return 0;
    
            /* Attempt an OF style match */
            if (of_driver_match_device(dev, drv))
                    return 1;
    
            /* Then ACPI style match */
            if (acpi_driver_match_device(dev, drv))
                    return 1;
    
            driver = to_i2c_driver(drv);
            /* match on an id table if there is one */
            if (driver->id_table)
                    return i2c_match_id(driver->id_table, client) != NULL;
    
            return 0;
    }
    

    一、of_driver_match_device

    这种方式是所有驱动匹配通用的,使用of_device_id 的compatible部分字符

    struct of_device_id
    {
        char    name[32];
        char    type[32];
        char    compatible[128];
        const void *data;
    };

    dts :

            i2c0: i2c@01c2ac00 {  /* 控制器的设备节点 */
            ...
                mydht12 {   /* 增加的设备子节点  */
                    compatible = "mydht12";
                    reg = <0x5c>; /* 设备地址 */
                };
    
            };

    驱动 :

    struct of_device_id ids[] = {
        {.compatible = "mydht12"},
        {},
    };
    
    struct i2c_driver mydrv = {
        .probe_new = probe, 
        .remove = remove,
    
        .driver = {
            .owner = THIS_MODULE,
            .name = "mydrv",
            .of_match_table = ids,
        },
    };

    二、acpi_driver_match_device

    主要用于电源管理,很少用到,这里不做介绍。

    三、i2c_match_id

    I2C设备特有匹配方式,使用i2c_device_id :

    struct i2c_device_id {
        char name[I2C_NAME_SIZE];
        kernel_ulong_t driver_data;    /* Data private to the driver */
    };
    struct i2c_device_id ids2[] = {
        {"mydht12"},
        {},
    };
    struct i2c_driver mydrv = {
        .probe_new = probe,
        .remove = remove,
    
        .driver = {
            .owner = THIS_MODULE,
            .name = "mydrv",
    //      .of_match_table = ids,
        },
        .id_table = ids2,  //使用id_table匹配
    };

     

     

    展开全文
  • 平台设备驱动是怎么匹配的?

    千次阅读 2017-08-22 10:38:21
    平台设备驱动是怎么匹配的? 在Linux源码的sourceindight工程下搜索platform_device.h,这个文件是设备结构体,驱动结构体的定义,还有操作这两个结构体的函数如:平台设备注册,平台驱动注册。先看两个结构体: /...
    平台设备和驱动是怎么匹配的? 
    

    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.csdn.net/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字段不同而已。
    
    
    


     

    
    展开全文
  • Linux设备驱动匹配过程

    千次阅读 2017-03-24 18:04:45
    Linux设备驱动注册过程如下所示:xxxx_driver_register()----->driver_register()----->bus_add_driver()----->driver_attach()-----> __driver_attach()Linux设备添加过程如下所示:xxxx_device_add()----->...

    一、bus_type结构体及涉及的函数:
    (1)bus_type结构体
    	struct bus_type {
    		const char		*name;
    		const char		*dev_name;
    		struct device		*dev_root;
    		struct bus_attribute	*bus_attrs;
    		struct device_attribute	*dev_attrs;
    		struct driver_attribute	*drv_attrs;
    
    		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 (*suspend)(struct device *dev, pm_message_t state);
    		int (*resume)(struct device *dev);
    
    		const struct dev_pm_ops *pm;
    
    		struct iommu_ops *iommu_ops;
    
    		struct subsys_private *p;
    		struct lock_class_key lock_key;
    	};
    
    (2)涉及的函数
    
    	kernel/linux-3.10/drivers/base/core.c:
    		 device_create()、device_register()、device_add()
    
    	kernel/linux-3.10/drivers/base/driver.c:
    		 driver_register()
    
    	kernel/linux-3.10/drivers/base/busc:
    		 bus_add_driver()、bus_add_device()、bus_probe_device()
    
    	kernel/linux-3.10/drivers/base/dd.c:
    		 device_attach()、__device_attach()、driver_attach()、__driver_attach()
    
    	kernel/linux-3.10/drivers/base/base.h:
    		 driver_match_device()、driver_probe_device()
    
    二、注册过程:
    
    Linux设备驱动注册过程如下所示:
    
    xxxx_driver_register()/xxxx_register_driver()--->driver_register()---> bus_add_driver()--->driver_attach()--->__driver_attach()
    如:platform_driver_register()、spi_register_driver()、i2c_register_driver()
    
    
    Linux设备添加过程如下所示:
    
    device_create()/xxxx_device_register()/xxxx_new_device()--->device_register()/xxxx_device_add()/xxxx_add_device()
    --->device_add()--->bus_add_device()--->bus_probe_device()---> device_attach()---> __device_attach()
        (1)可以直接使用device_create()创建设备,其最终会调用device_register()函数创建设备。
        (2)platform_device_register()--->platform_device_add()。
        (3)spi_new_device()--->spi_add_device()。                                                                                       (4)i2c_new_device()--->device_register()。                                                                                          
        从设备和驱动的注册过程可以看到两者处理的过程是非常类似,下面分别从最后的函数展开进行深入探索。
    
    三、驱动匹配设备过程
    static int __driver_attach(struct device *dev, void *data)
    {
    	struct device_driver *drv = data;
    
    	if (!driver_match_device(drv, dev))
    		return 0;
    
    	if (dev->parent) /* Needed for USB */
    		device_lock(dev->parent);
    	
    	device_lock(dev);
    	if (!dev->driver)
    		driver_probe_device(drv, dev);
    	device_unlock(dev);
    
    	if (dev->parent)
    		device_unlock(dev->parent);
    
    	return 0;
    }
        从上述函数可以看到在driver注册时调用函数driver_match_device进行driver和device的匹配,在匹配之后执行driver的probe函数进行初始化等操作。我们主要看一下driver和device的匹配过程,不再详细研究probe过程。
    
    static inline int driver_match_device(struct device_driver *drv, struct device *dev)
    {
        return drv->bus->match ?drv->bus->match(dev, drv) : 1;
    }
    
       可以看到,会调用相应总线的match函数来匹配driver和device。一般总线的调用过程如下所示,具体可参考每个总线的match函数。
    
    static int xxxx_match(struct device *dev,struct device_driver *drv) 
    { 
    	struct xxxx_device *xxxdev = to_xxxx_device(dev); 
    	struct xxxx_driver *xxxdrv =to_xxxx_driver(drv); 
    
    	/* Attempt an OF style match first */ 
    	if((of_driver_match_device(dev, drv)) 
    		return 1; 
    
    	/* Then ACPI style match */
    	if((acpi_driver_match_device(dev, drv))
    		return 1;
    
    	/* Then try to match against the id table*/ 
    	if((xxxdrv->id_table) 
    		return xxxx_match_id(xxxdrv->id_table,xxxdev) != NULL;  
    
    	/* fall-back to driver name match */ 
    	return (strcmp([xxxdev/dev]->[name/modalias], drv->name)== 0); 
    }
       可以看到基本上有四种方式,第一种是调用of_driver_match_device()函数;第二种方式是是ACPI系统专用的;第三种通过driver的id_table;第四种比较简单,是通过设备的名称或别名和驱动的名称进行匹配的。
    
       下面详细看一下前第一种和第三种匹配方式:
    
    (1)、of_driver_match_device()
    
       该函数的调用过程如下:
    static inline int of_driver_match_device(struct device *dev, const structdevice_driver *drv)
    {
        returnof_match_device(drv->of_match_table, dev) != NULL;
    }
    
    const struct of_device_id *of_match_device(const struct of_device_id *matches, conststruct device *dev)
    {
    	if ((!matches) || (!dev->of_node))
    		return NULL;
    	return of_match_node(matches, dev->of_node);
    }
    
    const struct of_device_id *of_match_node(const struct of_device_id *matches, conststruct device_node *node)
    {
    	const struct of_device_id *match;
    	unsigned long flags; 
    
    	raw_spin_lock_irqsave(&devtree_lock,flags);
    	match = __of_match_node(matches, node);
    	raw_spin_unlock_irqrestore(&devtree_lock,flags);
    
    	return match;
    }
    
    static const struct of_device_id *__of_match_node(const struct of_device_id *matches,const struct device_node *node)
    {
          if (!matches)
             return NULL;
    
          while (matches->name[0] ||matches->type[0] || matches->compatible[0]) {
             int match = 1;
             if (matches->name[0])
                match &= node->name &&!strcmp(matches->name, node->name);
             if (matches->type[0])
                match &= node->type &&!strcmp(matches->type, node->type);
             if (matches->compatible[0])
                match &= __of_device_is_compatible(node,matches->compatible);
             if (match)
                return matches;
             matches++;
          }
    
          return NULL;
    }
        可以发现最终匹配会调用__of_match_node,该函数通过of_device_id的名称、类型和兼容性和设备节点的名称、类型和兼容性进行匹配,其中兼容性具有最高优先级,如果兼容性不匹配,即使前两者匹配,最终结果还是不匹配。另外,of_device_id中一般只有兼容性一项。
        在进行兼容性匹配时会调用__of_device_is_compatible(),该函数最终会调用strcasecmp函数,比较兼容性字符串是否一致,一致则匹配。调用过程如下:
    
    static int__of_device_is_compatible(const struct device_node *device, const char *compat)
    {    
       const char* cp;
       int cplen, l;
    
       cp = __of_get_property(device,"compatible", &cplen);
    
       if (cp == NULL)
          return0;
    
       while (cplen > 0) {
    		if (of_compat_cmp(cp, compat,strlen(compat)) == 0)
    			return 1;
    		l = strlen(cp) + 1;
    		cp += l;
    		cplen -= l;
       }
    
       return 0;
    }
    
    #defineof_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) 
    
    (2)、id_table
    
        一般是调用xxxx_match_id函数比较id_table的名称和设备相关属性的名称来进行匹配。xxxx_match_id的一般形式如下,具体可以参考各个总线的函数。
    static const struct xxxx_device_id *xxxx_match_id(const struct xxxx_device_id *id,const struct  _xxxx *xxxx)
    {
        while (id->name[0]) {
            if (strcmp(xxxx->name, id->name) == 0)
                return id;
            id++;
        }
    
        return NULL;
    }
    
    我们可以看一下i2c总线和SPI总线的xxxx_match_id函数,如下所示:
    static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, conststruct i2c_client *client)
    {
        while (id->name[0]) {
            if (strcmp(client->name, id->name) == 0)
               return id;
            id++;
        }
    
        return NULL;
    }
    可以看到I2C总线使用i2c_client的名称和id_table的名称来进行匹配。
    static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, conststruct spi_device *sdev)
    {
        while (id->name[0]) {
    		if (!strcmp(sdev->modalias, id->name))
    		   return id;
    		id++;
          }
    
          return NULL;
    } 
    
    可以看到SPI总线使用SPI设备的别名和id_table的名称来进行匹配。其它总线的匹配方式请自行查看,再此不再赘述。
    
    四、设备匹配驱动过程
    
    static int__device_attach(struct device_driver *drv, void *data)
    {
        struct device *dev = data;
        if (!driver_match_device(drv, dev))
            return 0;
        return driver_probe_device(drv, dev);
    }
    
    staticinline int driver_match_device(struct device_driver *drv, struct device *dev)
    {
         return drv->bus->match ?drv->bus->match(dev, drv) : 1;
    }
        从上述函数可以看到device注册时也是调用函数driver_match_device来进行driver和device的匹配,在匹配之后执行driver的probe函数进行初始化等操作。
    
        由此可见无论是设备还是驱动注册,都是调用总线的match函数进行匹配。在设备和驱动匹配之后,会调用driver_probe_device()函数,调用驱动的probe函数进行初始化工作。
    
    五、常见总线的match函数:
    
    (1)platform_bus:
    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);
    
    	/* 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);//比较平台设备的名称和驱动名称进行匹配
    }
    
    (2)spi_bus:
    static int spi_match_device(struct device *dev, struct device_driver *drv)
    {
    	const struct spi_device	*spi = to_spi_device(dev);
    	const struct spi_driver	*sdrv = to_spi_driver(drv);
    
    	/* Attempt an OF style match */
    	if (of_driver_match_device(dev, drv))
    		return 1;
    
    	/* Then try ACPI */
    	if (acpi_driver_match_device(dev, drv))
    		return 1;
    
    	if (sdrv->id_table)
    		return !!spi_match_id(sdrv->id_table, spi);
    
    	return strcmp(spi->modalias, drv->name) == 0;//通过比较spi_device的别名和驱动的名称进行匹配
    }
    
    (3)i2c_bus:
    
    static int i2c_device_match(struct device *dev, struct device_driver *drv)
    {
    	struct i2c_client	*client = i2c_verify_client(dev);
    	struct i2c_driver	*driver;
    
    	if (!client)
    		return 0;
    
    	/* Attempt an OF style match */
    	if (of_driver_match_device(dev, drv))
    		return 1;
    
    	/* Then ACPI style match */
    	if (acpi_driver_match_device(dev, drv))
    		return 1;
    
    	driver = to_i2c_driver(drv);
    	/* match on an id table if there is one */
    	if (driver->id_table)
    		return i2c_match_id(driver->id_table, client) != NULL;
    
    	return 0;
    }
    
    
    
    
    
    
    
    
    

    
    展开全文
  • 文章目录1.... 设备端2.1 platform_device 结构体2.2 device 结构体1.3 设备端 match 的调用过程 1. 驱动端  内核中相关结构体的命名规则定义如下: platform_driver --> pdrv device_dr...

    1. 驱动端

     内核中相关结构体的命名规则定义如下:

    platform_driver --> pdrv
    device_driver   --> drv 
    

    1.1 platform_driver 结构体

     下面是 platform_driver 结构体,将结构体中元素位置调换,常用的变量和函数接口调整在最前面。

    struct platform_driver {
        struct device_driver driver;                // 设备驱动结构体
        const struct platform_device_id *id_table;
        int (*probe)(struct platform_device *);     // probe函数,在设备和驱动匹配时调用
        int (*remove)(struct platform_device *);    // remove函数,在移除设备时调用
        
        void (*shutdown)(struct platform_device *);
        int (*suspend)(struct platform_device *, pm_message_t state);
        int (*resume)(struct platform_device *);
        bool prevent_deferred_probe;
    };
    

    1.2 device_driver 结构体

     在 platform_driver 结构体中有一个很重要的变量 struct device_driver,接着介绍该结构体的定义,同样将常用的元素至于前面。

    struct device_driver {
        struct module *owner;   // THIS_MODULE
        const char     *name;   // 设备驱动的名字,
        struct bus_type *bus;   // 总线类型,有platform,IIC,SPI等
        const struct of_device_id *of_match_table;
        int (*probe) (struct device *dev);      // probe函数,这个接口调用真正的 probe 函数
        int (*remove) (struct device *dev);     // remove函数,这个接口调用真正的 remove 函数
        struct driver_private *p;               // 私有数据指针
    
        const char *mod_name;       /* used for built-in modules */
        bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */
        enum probe_type probe_type;
        const struct acpi_device_id	*acpi_match_table;
        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;            // 电源管理相关
    };
    

    1.3 驱动中 platform_driver 结构体的实现

    struct platform_driver demo_drv = {
    	.probe = demo_probe,
    	.remove = demo_remove,
    	.driver = {
    		.name = "demo_platform",	// 用于和平台设备匹配的名字
    		.owner = THIS_MODULE,
    	},
    };
    

    1.4 驱动端 probe 的调用过程

    #define platform_driver_register(pdrv) __platform_driver_register(pdrv, THIS_MODULE) (include\linux\platform_device.h)	// 平台驱动注册函数
    	|-> pdrv->driver.bus = &platform_bus_type;	(drivers\base\platform.c)
    			|-> platform_bus_type.name = "platform"		// 总线的名字
    			|-> platform_bus_type.match = platform_match// match函数
    		pdrv->driver.probe = platform_drv_probe;		// probe 函数 
    		pdrv->driver.remove = platform_drv_remove;		// remove函数
    		|-> driver_register(struct device_driver *drv) (drivers\base\driver.c)
    			|-> bus_add_driver(struct device_driver *drv) (drivers\base\bus.c)	// 添加驱动到总线上
    				|-> driver_attach(struct device_driver *drv) (drivers\base\dd.c)
    					|-> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) (drivers\base\bus.c)
    						|-> __driver_attach(struct device *dev, void *data) (drivers\base\dd.c)
    							|-> driver_match_device(struct device_driver *drv, struct device *dev) (drivers\base\base.h)	// 驱动和设备匹配
    								|-> return drv->bus->match ? drv->bus->match(dev, drv) : 1
    									|-> platform_match(struct device *dev, struct device_driver *drv) (drivers\base\platform.c) // 匹配函数
    										|-> strcmp(pdev->driver_override, drv->name)	// 通常不设置
    										|-> platform_match_id(pdrv->id_table, pdev)		// 匹配ID表
    											|-> strcmp(pdev->name, pdrv->id_table->name)
    										|-> strcmp(pdev->name, drv->name)				// 最后匹配名字,以上三种匹配方式只要有一个成功,返回1
    							|-> driver_probe_device(drv, dev) (drivers\base\dd.c)		// 驱动和设备匹配成功后,执行probe函数		
    								|-> really_probe(drv, dev) (drivers\base\dd.c)			// 执行真正的 probe 函数
    									|->	if (dev->bus->probe) {				// 没有定义
    											ret = dev->bus->probe(dev);
    											if (ret)
    												goto probe_failed;
    										} else if (drv->probe) {			// 执行 device_driver 里面的 probe 函数
    											ret = drv->probe(dev);
    											if (ret)
    												goto probe_failed;
    										}
    									|-> if (dev->bus->remove)				// remove 函数
    											dev->bus->remove(dev);
    										else if (drv->remove)				// 在这里调用真正的自己定义的remove函数
    											drv->remove(dev);
    										|-> platform_drv_probe(struct device *_dev) (drivers\base\platform.c)
    											|-> struct platform_driver *drv = to_platform_driver(_dev->driver)	// 找到 platform_driver 结构体
    												|-> #define to_platform_driver(drv)	(container_of((drv), struct platform_driver, driver)) (include\linux\platform_device.h)
    											|-> struct platform_device *dev = to_platform_device(_dev)
    												|-> #define to_platform_device(x) container_of((x), struct platform_device, dev)
    											|-> if (drv->probe) {
    													ret = drv->probe(dev);	// 执行真正的probe函数,也就是在 platform_driver 中自己定义的,并将 pdev 传入进去
    													if (ret)
    														dev_pm_domain_detach(_dev, true);
    												} else {
    													/* don't fail if just dev_pm_domain_attach failed */
    													ret = 0;
    												}
    
    

     platform_match 匹配函数在内核中的定义如下,从里面可以看出驱动和设备匹配的优先顺序。

    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))	// ACPI风格
    		return 1;
    
    	/* Then try to match against the id table */
    	if (pdrv->id_table)						// 匹配ID表
    		return platform_match_id(pdrv->id_table, pdev) != NULL;
    
    	/* fall-back to driver name match */
    	return (strcmp(pdev->name, drv->name) == 0);	// 匹配名字
    }
    

    2. 设备端

     内核中相关结构体的命名规则定义如下:

    platform_device --> pdrv
    device          --> drv 
    

    2.1 platform_device 结构体

    struct platform_device {
    	const char	*name;
    	int		id;
    	bool		id_auto;
    	struct device	dev;
    	u32		num_resources;
    	struct resource	*resource;
    
    	const struct platform_device_id	*id_entry;
    	char *driver_override; /* Driver name to force a match */
    
    	/* MFD cell pointer */
    	struct mfd_cell *mfd_cell;
    
    	/* arch specific additions */
    	struct pdev_archdata	archdata;
    };
    

    2.2 device 结构体

    struct device {
    	struct device		*parent;
    
    	struct device_private	*p;
    
    	struct kobject kobj;
    	const char		*init_name; /* initial name of the device */
    	const struct device_type *type;
    
    	struct mutex		mutex;	/* mutex to synchronize calls to
    					 * its driver.
    					 */
    
    	struct bus_type	*bus;		/* type of bus device is on */
    	struct device_driver *driver;	/* which driver has allocated this
    					   device */
    	void		*platform_data;	/* Platform specific data, device
    					   core doesn't touch it */
    	void		*driver_data;	/* Driver data, set and get with
    					   dev_set/get_drvdata */
    	struct dev_pm_info	power;
    	struct dev_pm_domain	*pm_domain;
    
    #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
    	struct irq_domain	*msi_domain;
    #endif
    #ifdef CONFIG_PINCTRL
    	struct dev_pin_info	*pins;
    #endif
    #ifdef CONFIG_GENERIC_MSI_IRQ
    	struct list_head	msi_list;
    #endif
    
    #ifdef CONFIG_NUMA
    	int		numa_node;	/* NUMA node this device is close to */
    #endif
    	u64		*dma_mask;	/* dma mask (if dma'able device) */
    	u64		coherent_dma_mask;/* Like dma_mask, but for
    					     alloc_coherent mappings as
    					     not all hardware supports
    					     64 bit addresses for consistent
    					     allocations such descriptors. */
    	unsigned long	dma_pfn_offset;
    
    	struct device_dma_parameters *dma_parms;
    
    	struct list_head	dma_pools;	/* dma pools (if dma'ble) */
    
    	struct dma_coherent_mem	*dma_mem; /* internal for coherent mem
    					     override */
    #ifdef CONFIG_DMA_CMA
    	struct cma *cma_area;		/* contiguous memory area for dma
    					   allocations */
    #endif
    	/* arch specific additions */
    	struct dev_archdata	archdata;
    
    	struct device_node	*of_node; /* associated device tree node */
    	struct fwnode_handle	*fwnode; /* firmware device node */
    
    	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
    	u32			id;	/* device instance */
    
    	spinlock_t		devres_lock;
    	struct list_head	devres_head;
    
    	struct klist_node	knode_class;
    	struct class		*class;
    	const struct attribute_group **groups;	/* optional groups */
    
    	void	(*release)(struct device *dev);
    	struct iommu_group	*iommu_group;
    	struct iommu_fwspec	*iommu_fwspec;
    
    	bool			offline_disabled:1;
    	bool			offline:1;
    };
    

    2.3 platform_device 结构体的实现

    struct resource resources[] = {
    	{
    		.start = GROUP_PIN(3,1),	// 引脚号
    		.flags = IORESOURCE_IRQ,
    		.name = "led1",
    	},
    	{
    		.start = GROUP_PIN(5,8),	// 引脚号
    		.flags = IORESOURCE_IRQ,
    		.name = "led2",
    	},
    };
    
    struct platform_device demo_dev = {
    	.name = "demo_platform",
    	.num_resources = ARRAY_SIZE(resources),
    	.resource = resources,
    	.dev = {
    		.release = demo_release,
    	},
    };	
    

    2.4 设备端 match 的调用过程

    platform_device_register(struct platform_device *pdev) (drivers\base\platform.c) //平台设备注册函数
    	|-> platform_device_add(pdev) (drivers\base\platform.c)
    		|-> pdev->dev.bus = &platform_bus_type
    			|-> platform_bus_type.name = "platform"		// 总线的名字
    				platform_bus_type.match = platform_match// match函数
    		|-> device_add(&pdev->dev) (drivers\base\core.c)
    			|-> bus_probe_device(dev) (drivers\base\bus.c)
    				|-> device_initial_probe(dev) (drivers\base\dd.c)	
    					|-> __device_attach(dev, true) (drivers\base\dd.c)	
    						|-> bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver) (drivers\base\bus.c)
    							|-> __device_attach_driver(struct device_driver *drv, void *_data) (drivers\base\dd.c)
    								|-> driver_match_device(drv, dev) (drivers\base\base.h)
    									|-> return drv->bus->match ? drv->bus->match(dev, drv) : 1
    									...	...	// 与驱动注册后面一致
    								|-> driver_probe_device(drv, dev) (drivers\base\dd.c)		// 驱动和设备匹配成功后,执行probe函数	
    									...	... // 与驱动注册后面一致	
    
    展开全文
  • 查看系统上所有,特别是未安装驱动设备设备范例ID 和驱动进行匹配,将匹配设备范例ID 写在config.ini上即识别到,适合于开发 驱动自动识别程序,便利驱动识别和安装
  • SPI 总线驱动设备驱动匹配

    千次阅读 2018-08-12 08:03:10
    关于spi_driver和spi_device的匹配: 第一种情况: spidev.c中spi_driver中name字段 static struct spi_driver spidev_spi_driver = {  .driver = {  .name = "spidev",  .owner = THIS_MODULE, ...
  • 使用设备树时,给驱动程序调用的过程 我们把设备树.dts 变成plantform_device的资源 过程一步步了解清楚 吃
  • 问题一:为什么需要设备树? 在目前广泛使用的Linux kernel 2.6.x版本中,对于不同平台、不同硬件,往往存在着大量的不同的、移植性差的板级描述代码,以达到对这些不同平台和不同硬件特殊适配的 需求。但是过多的...
  • 一、设备树节点转化为platform_device的过程 1、dts文件转化过程 dts文件编译成为dtb文件之后供给内核解析,设备树中...(1)根节点下的含有compatible属性的子节点,compatible属性是用于匹配驱动 如:节点key1和节点l
  • i2c设备与驱动匹配过程

    千次阅读 2017-09-13 19:01:15
    设备(device) + 驱动(device_driver) 组成,在该模型下,所有的设备通过总线连接起来,即使有些设备没有连接到一根物理总线上,linux为其设置了一个内部的、虚拟的platform总线,用以维持总线、驱动设备的...
  • Linux设备驱动设备匹配过程 在写驱动时我们都会用到一些注册函数比如:platform_driver_register、spi_register_driver、 i2c_add_driver,接下来我们就一路追踪看看内核是怎样将我们的驱动设备匹配起来并且调用...
  • linux 设备与驱动的关系

    千次阅读 多人点赞 2019-07-07 16:54:53
    一开接触设备树,我就不知道设备与驱动的关系,设备树是在内核3.0以后才有的。不过3.0以前的和3.0以后的驱动其实变化不大。 驱动的开发方法可以分为三种:传统方法,总线方法,设备树方法。 这篇文章围绕点亮...
  • linux 驱动设备和 dts 匹配过程

    千次阅读 2019-01-07 23:13:08
    linux 设备驱动文件在 dts 中的设备板级硬件信息匹配的关键字是 compatible 属性。即比较驱动文件中 of_device_id 结构体元素的 .compatible 成员变量和 dts 文件中 node 中 compatible 属性两个字符串。...
  • Linux SPI 子系统驱动开发之Linux spi设备驱动与SPI控制器驱动匹配问题。1.SPI协议层驱动是怎么SPI控制器(spi_master)匹配的。2.spi控制器是怎么区分多个spi设备的。在SPI协议层中,spi_device是通过spi_...
  • Table of Contents 一、匹配函数platform_match 1.1、设备匹配方法 1.2、id_table匹配方法 ...平台设备驱动分为设备层和驱动层,每当有新的设备或者新的设备驱动注册时都要首先调用匹配函数进行匹配 ...
  • i2c在设备树下的匹配注册过程
  • Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离。相当于从驱动代码分离出来的配置文件,比如串口的波特率通过设备树配置,当需要改变波特率时,就不用修改驱动,直接修改配置文件则可。 ...
  • 行业分类-设备装置-智能操作系统平台中实现设备与驱动动态匹配的系统及方法
  • USB设备标识字符串、Service键值、Class键值、INF文件、搜寻驱动程序
  • 从match函数中可以看到,platform总线匹配设备驱动有4种方法: 一是通过platform_driver中的id_table,如果id_table不存在,则只是简单的比较设备中的name字段和驱动中的name字段是否相同。 后面一种方法呢...
  • 今天第一次编写驱动程序,心里有些激动,但跟多的是惶恐,我相信很多同学和我一样,当你开始接触一个新的领域时,心中的惶恐很可能会大于兴奋。所以我们一步一步的跟着老师的视频做,唯恐在哪里出现一点错误而导致...
  • Linux设备与驱动

    千次阅读 2020-03-20 09:08:43
    文章目录源头内核head.s对dtb的简单处理bootloader启动内核时,回设置r0,r1,r2三个寄存器head.s工作步骤对设备树平台信息的处理(选择machine_desc)start_kernel的调用过程对设备树中运行时配置信息的处理dtb转换为...
  • 一开接触设备树,我就不知道设备与驱动的关系,设备树是在内核3.0以后才有的。不过3.0以前的和3.0以后的驱动其实变化不大。     驱动的开发方法可以分为三种:传统方法,总线方法,设备树方法。 &...
  • 驱动人-驱动智能匹配

    2011-03-14 18:25:41
    驱动智能匹配、快速下载、自动安装一键完成 驱动人生提供便捷的多版本选择下载,让用户更加方便 驱动全方位人性化管理,一键备份、轻松还原、自由卸载
  • linux驱动-设备

    千次阅读 2018-01-22 11:38:34
    设备树 -小白总结,谨慎参考 设备树是从软件的角度描述硬件,DTS是设备树源文件。DTC是负责将DTS转换成DTB,DTB是DTS的二进制形式,供机器使用。 设备树,首先是一个树形结构,除了根节点外其他子节点都有唯一的父...
  • 它包括以下功能:①允许设备驱动匹配对应设备;②提供驱动程序访问硬件的机制;③软件其他部分访问设备功能;④在VxWorks系统中,实现设备驱动的模块化。VxBus在总线控制器驱动程序服务的支持下,能在总线上发现设备,并...
  • Linux驱动之IIC实验(基于设备树编程)

    千次阅读 2019-11-19 20:22:16
    I2C驱动分为两个部分:主机驱动(SOC的I2C控制器驱动),设备驱动(针对具体设备编写的驱动)。—和platform驱动相似。 一般i2c控制器驱动SOC厂商已经写好了,我们只需要编写设备驱动。 本实验基于IIC2端口读取...
  • 它包括以下功能:①允许设备驱动匹配对应设备;②提供驱动程序访问硬件的机制;③软件其他部分访问设备功能;④在VxWorks系统中,实现设备驱动的模块化。VxBus在总线控制器驱动程序服务的支持下,能在总线上发现设备,并...
  • 1、在设备树文件(.dts)中的相应节点下添加要注册设备的节点  &soc {  ......  plf_char_dev: mytest,plf_char_dev {  compatible = "mytest,plf_c

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 92,379
精华内容 36,951
关键字:

驱动与设备匹配