The changes brought by the device tree to the device driver of the platform (the strongest analysis in history) [transfer]

When we first learned the device tree, the first example was key interrupt, which used the device tree method. We take this as an example to analyze the changes introduced by the device tree to the platform platform driver.

Tiny4412 Learning (4) Transplanting Linux -Device Tree (1) Basic knowledge of device tree and GPIO interrupt: http://blog.csdn.net/fengyuwuzu0519/article/details/74177978

1. Change and Unchanging

(1) The entry function of platform_driver is still registered with platform_driver_register (unchanged)

 

[cpp] view plain copy

 

 print?

  1. static int __init int_demo_init(void)    
  2. {    
  3.     int ret;    
  4.     
  5.     ret = platform_driver_register(&int_demo_driver);    
  6.     if (ret)    
  7.         printk(KERN_ERR "int demo: probe failed: %d\n", ret);    
  8.     
  9.     return ret;    
  10. }    
  11. module_init(int_demo_init);    


(2) Platform driver: a slight change, more of_match_table members

 

 

[cpp] view plain copy

 

 print?

  1. static struct platform_driver int_demo_driver = {    
  2.     .driver        = {    
  3.         .name      = "interrupt_demo",    
  4.         .of_match_table    = of_match_ptr(int_demo_dt_ids),    
  5.     },    
  6.     .probe         = int_demo_probe,    
  7.     .remove        = int_demo_remove,    
  8. };    

(3) Changes in matching methods:

 

If the device tree is not introduced, you also need to define a file similar to the following to match

 

[cpp] view plain copy

 

 print?

  1. static struct resource s3c_int_resource[] = {    
  2.     xxx;  
  3. };    
  4. struct platform_device s3c_device_rtc = {    
  5.     .name       = "interrupt_demo",    
  6.     .id     = -1,    
  7.     .num_resources  = ARRAY_SIZE(s3c_int_resource),    
  8.     .resource   = s3c_int_resource,    
  9. };    

In Common-smdk.c (linux-3.4.2\arch\arm\mach-s3c24xx)

 

 

[cpp] view plain copy

 

 print?

  1. static struct platform_device __initdata *smdk_devs[] = {  
  2.     &s3c_device_nand,  
  3.     &smdk_led4,  
  4.     &smdk_led5,  
  5.     &smdk_led6,  
  6.     &smdk_led7,  
  7. };  
  8. // Add the corresponding device when the kernel is initialized  
  9. platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));  

 

Before introducing the device tree, we used the device name matching method. When platform_driver_register, it will match a device named "interrupt_demo". If a device with the same name is found, the probe function will be called. Due to the introduction of the device tree, it is hard-coded in arch/arm/plat-xxx and arch/arm/mach-xxx, such as platform devices on the board, resource, i2c_board_info, spi_board_info and platform_data of various hardware will not exist. So where is the device information, when is it added into the kernel, and how does platform_driver match platform_device? The answer is that the device information is stored in the device tree, which is converted into a device structure when the device tree is loaded. The platform does not match the device name as before, but matches whether the .compatible in the driver is consistent with the compatible attribute of the corresponding node in the device tree, and is not case-sensitive. If it is consistent, the probe function is called. Let's analyze in detail why this is so.

 

[cpp] view plain copy

 

 print?

  1. static const struct of_device_id int_demo_dt_ids[] = {    
  2.     { .compatible = "tiny4412,interrupt_demo", },    
  3.     {},    
  4. };    
  5.     
  6. MODULE_DEVICE_TABLE(of, int_demo_dt_ids);    
  7.     
  8. static struct platform_driver int_demo_driver = {    
  9.     .driver        = {    
  10.         .name      = "interrupt_demo",    
  11.         .of_match_table    = of_match_ptr(int_demo_dt_ids),    
  12.     },    
  13.     .probe         = int_demo_probe,    
  14.     .remove        = int_demo_remove,    
  15. };    
  16.     
  17. static int __init int_demo_init(void)    
  18. {    
  19.     int ret;    
  20.     
  21.     ret = platform_driver_register(&int_demo_driver);    
  22.     if (ret)    
  23.         printk(KERN_ERR "int demo: probe failed: %d\n", ret);    
  24.     
  25.     return ret;    
  26. }    
  27. module_init(int_demo_init);    

See the complete code: http://blog.csdn.net/fengyuwuzu0519/article/details/74177978 .

 

 

Second, analyze the process of platform_match in detail

1. Function call process:

Go to the kernel to check, and you can find that it is called layer by layer.

platform_match-->of_driver_match_device-->of_match_device-->of_match_node-->of_device_is_compatible-->of_get_property/of_compat_cmp-->strcasecmp((s1), (s2))

We found that in the end we were comparing whether the contents of the strings are consistent, so we only need to analyze the member lists of these methods to see which two strings are being compared.

2. Method Analysis

platform_driver_register, first call the following matching function.

platform_match(device,device_driver)

device: The guess is that the device tree was built

device_driver: encapsulated by platform_driver, which is our int_demo_driver

 

[cpp] view plain copy

 

 print?

  1. static int platform_match(struct device *dev, struct device_driver *drv)  
  2. {  
  3.     struct platform_device *pdev = to_platform_device(dev);  
  4.     struct platform_driver *pdrv = to_platform_driver(drv);  
  5.   
  6.     /* Attempt an OF style match first */  
  7.     if (of_driver_match_device(dev, drv))  
  8.         return 1;  
  9.   
  10.     /* Then try to match against the id table */  
  11.     if (pdrv->id_table)  
  12.         return platform_match_id(pdrv->id_table, pdev) != NULL;  
  13.   
  14.     /* fall-back to driver name match */  
  15.     return (strcmp(pdev->name, drv->name) == 0);  
  16. }  

 

of_driver_match_device(device,device_driver)

[cpp] view plain copy

 

 print?

  1. static inline int of_driver_match_device(struct device *dev,  
  2.                      const struct device_driver *drv)  
  3. {  
  4.     return of_match_device(drv->of_match_table, dev) != NULL;  
  5. }  

of_match_device(of_device_id,device)

of_device_id: device_driver>of_match_table=of_match_ptr(int_demo_dt_ids): This is not the of_match_table member we defined in the driver

device: The guess is that the device tree was built

[cpp] view plain copy

 

 print?

  1. const struct of_device_id *of_match_device(const struct of_device_id *matches,  
  2.                        const struct device *dev)  
  3. {  
  4.     if ((!matches) || (!dev->of_node))  
  5.         return NULL;  
  6.     return of_match_node(matches, dev->of_node);  
  7. }  

 

of_match_node(of_device_id,device_node)

of_device_id:of_match_ptr(int_demo_dt_ids)

device_node: device->of_node (the device tree has completed the initialization of of_node) continue:

[cpp] view plain copy

 

 print?

  1. const struct of_device_id *of_match_node(const struct of_device_id *matches,  
  2.                      const struct device_node *node)  
  3. {  
  4.     if (!matches)  
  5.         return NULL;  
  6.   
  7.     while (matches->name[0] || matches->type[0] || matches->compatible[0]) {  
  8.         int match = 1;  
  9.         if (matches->name[0])  
  10.             match &= node->name  
  11.                 && !strcmp(matches->name, node->name);  
  12.         if (matches->type[0])  
  13.             match &= node->type  
  14.                 && !strcmp(matches->type, node->type);  
  15.         if (matches->compatible[0])  
  16.             match &= of_device_is_compatible(node,  
  17.                         matches->compatible);  
  18.         if (match)  
  19.             return matches;  
  20.         matches++;  
  21.     }  
  22.     return NULL;  
  23. }  

 

of_device_is_compatible(device_node,char *compat)=of_device_is_compatible(device_node,“tiny4412,interrupt_demo”)

device_node: device->of_node (the device tree has completed the initialization of of_node)

char *compat:of_device_id->compatible=tiny4412,interrupt_demo

At this point, we can already find that it is now compared with the compatible member of the of_device_id structure defined in the driver, so who is it to compare with? Let's move on to the next function:

[cpp] view plain copy

 

 print?

  1. int of_device_is_compatible(const struct device_node *device,  
  2.         const char *compat)  
  3. {  
  4.     const char* cp;  
  5.     you cplen, l;  
  6.   
  7.     cp = of_get_property(device, "compatible", &cplen);  
  8.     if (cp == NULL)  
  9.         return 0;  
  10.     while (cplen > 0) {  
  11.         if (of_compat_cmp(cp, compat, strlen(compat)) == 0)  
  12.             return 1;  
  13.         l = strlen(cp) + 1;  
  14.         cp += l;  
  15.         cplen -= l;  
  16.     }  
  17.   
  18.     return 0;  
  19. }  

 

cp = of_get_property(device_node,"compatible", &cplen)

device_node: device->of_node (the device tree has completed the initialization of of_node)

When the device tree is loaded, the device device is built and the of_node member is initialized. Now we obtain the compatible attribute corresponding to the node according to of_node. cp is equal to the compatible attribute value of the node we defined in the device tree. The above function of_device_is_compatible compares the compatibility of the nodes in the device tree with the device with the same name as we defined. If it exists, return 1;

 

[cpp] view plain copy

 

 print?

  1. const void *of_get_property(const struct device_node *np, const char *name,  
  2.              int *lenp)  
  3. {  
  4.     struct property *pp = of_find_property(np, name, lenp);  
  5.   
  6.     return pp ? pp->value : NULL;  
  7. }  

of_compat_cmp: ignore case comparison string.

 

#define of_compat_cmp(s1, s2, l)strcasecmp((s1), (s2))

3. Related structures

(1)device  Device.h (linux-3.4.2\include\linux)

[cpp] view plain copy

 

 print?

  1. <span style="font-size:14px;">struct device {  
  2.     struct device       *parent;  
  3.   
  4.     struct device_private   *p;  
  5.   
  6.     struct kobject kobj;  
  7.     const char      *init_name; /* initial name of the device */  
  8.     const struct device_type *type;  
  9.   
  10.     struct mutex        mutex;  /* mutex to synchronize calls to 
  11.                      * its driver. 
  12.                      */  
  13.   
  14.     struct bus_type *bus;       /* type of bus device is on */  
  15.     struct device_driver *driver;   /* which driver has allocated this 
  16.                        device */  
  17.     void        *platform_data; /* Platform specific data, device 
  18.                        core doesn't touch it */  
  19.     struct dev_pm_info  power;  
  20.     struct dev_pm_domain    *pm_domain;  
  21.   
  22. #ifdef CONFIG_NUMA  
  23.     int     numa_node;  /* NUMA node this device is close to */  
  24. #endif  
  25.     u64     *dma_mask;  /* dma mask (if dma'able device) */  
  26.     u64     coherent_dma_mask;/* Like dma_mask, but for 
  27.                          alloc_coherent mappings as 
  28.                          not all hardware supports 
  29.                          64 bit addresses for consistent 
  30.                          allocations such descriptors. */  
  31.   
  32.     struct device_dma_parameters *dma_parms;  
  33.   
  34.     struct list_head    dma_pools;  /* dma pools (if dma'ble) */  
  35.   
  36.     struct dma_coherent_mem *dma_mem; /* internal for coherent mem 
  37.                          override */  
  38.     /* arch specific additions */  
  39.     struct dev_archdata archdata;  
  40.   
  41.     struct device_node  *of_node; /* associated device tree node */  
  42.   
  43.     dev_t           devt;   /* dev_t, creates the sysfs "dev" */  
  44.     u32         id; /* device instance */  
  45.   
  46.     spinlock_t      devres_lock;  
  47.     struct list_head    devres_head;  
  48.   
  49.     struct klist_node   knode_class;  
  50.     struct class        *class;  
  51.     const struct attribute_group **groups;  /* optional groups */  
  52.   
  53.     void    (*release)(struct device *dev);  
  54. };</span>  

(2)device_driver   Device.h (linux-3.4.2\include\linux)

[cpp] view plain copy

 

 print?

  1. struct device_driver {  
  2.     const char      *name;  
  3.     struct bus_type     *bus;  
  4.   
  5.     struct module       *owner;  
  6.     const char      *mod_name;  /* used for built-in modules */  
  7.   
  8.     bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */  
  9.   
  10.     const struct of_device_id   *of_match_table;  
  11.   
  12.     int (*probe) (struct device *dev);  
  13.     int (*remove) (struct device *dev);  
  14.     void (*shutdown) (struct device *dev);  
  15.     int (*suspend) (struct device *dev, pm_message_t state);  
  16.     int (*resume) (struct device *dev);  
  17.     const struct attribute_group **groups;  
  18.   
  19.     const struct dev_pm_ops *pm;  
  20.   
  21.     struct driver_private *p;  
  22. };  


 

3. Summary

At this point we know. It is to determine whether to execute the probe function by comparing the compatible name in the structure of_device_id type defined in the driver with the compatible of the device tree node. We did not initialize platform_device, these are done for us when the kernel loads the device tree, and the of_node member is initialized according to the device tree node, we can find the member attributes corresponding to the node according to of_node. That is, after the device tree is loaded, the kernel will automatically convert the device tree node into the format of platform_device, and put the name in the place of_node at the same time.

Another point is that the structure we used above is device, and device_driver, why not the platform_device and platform_driver we defined? In fact, the platform is a layer of encapsulation for the device. Viewing the source code, we can find the function calling process:

platform_device--》device            platform_device_register  --》device_add
 platform_driver--》device_driver        platform_driver_register--》device_register
所以platform是对struct device和struct device_driver的封装。

For device and device_driver, we will analyze it later.

Guess you like

Origin blog.csdn.net/wenyue043/article/details/104843824