Linux驱动模型解析bus之platform bus

Posted georgeguo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux驱动模型解析bus之platform bus相关的知识,希望对你有一定的参考价值。

 这是内核启动之后要调用的驱动模型的开始代码:

drivers/base/init.c
/*
* * driver_init - initialize driver model. * * Call the driver model init functions to initialize their * subsystems. Called early from init/main.c. */ void __init driver_init(void) { /* These are the core pieces */ devices_init(); // /sys/devices buses_init(); // /sys/bus classes_init(); // /sys/class firmware_init(); hypervisor_init(); /* These are also core pieces, but must come after the * core core pieces. */ platform_bus_init(); system_bus_init(); cpu_dev_init(); memory_dev_init(); }

且看platform_bus_init

drivers/base/platform.c
struct device platform_bus = {
        .bus_id         = "platform",
};

 

struct bus_type platform_bus_type = {
        .name           = "platform",
        .dev_attrs      = platform_dev_attrs,
        .match          = platform_match,
        .uevent         = platform_uevent,
        .pm             = PLATFORM_PM_OPS_PTR,
};

int __init platform_bus_init(void)
{
        int error;
     /* /sys/devices/platform (this platform is bus_id‘s value) */
     error = device_register(&platform_bus);
     if (error)
        return error;
      /* /sys/bus/platform (this platform is the value of bus_type‘s name field) */
      error = bus_register(&platform_bus_type); 

     if (error)
         device_unregister(
&platform_bus);

     return error;
}

这里讲述 bus_register(&platform_bus_type):

/**
 * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
 *
 * @subsys - the struct kset that defines this bus.  This is the main kobject
 * @drivers_kset - the list of drivers associated with this bus
 * @devices_kset - the list of devices associated with this bus
 * @klist_devices - the klist to iterate over the @devices_kset
 * @klist_drivers - the klist to iterate over the @drivers_kset
 * @bus_notifier - the bus notifier list for anything that cares about things
 * on this bus.
 * @bus - pointer back to the struct bus_type that this structure is associated
 * with.
 *
 * This structure is the one that is the actual kobject allowing struct
 * bus_type to be statically allocated safely.  Nothing outside of the driver
 * core should ever touch these fields.
 */
struct bus_type_private {
        struct kset subsys;
        struct kset *drivers_kset;
        struct kset *devices_kset;
        struct klist klist_devices;
        struct klist klist_drivers;
        struct blocking_notifier_head bus_notifier;
        unsigned int drivers_autoprobe:1;
        struct bus_type *bus;
};
int bus_register(struct bus_type *bus)                                          
{                                                                               
        int retval;                                                             
        struct bus_type_private *priv;                                          
                                                                                
        priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);            
        if (!priv)                                                              
                return -ENOMEM;                                                 
                                                                                
        priv->bus = bus;                                                        
        bus->p = priv;                                                         
                                                                                
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);                       
                                                                                
        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);         
        if (retval)                                                             
                goto out;                                                       
                                                                                
        priv->subsys.kobj.kset = bus_kset;                                      
        priv->subsys.kobj.ktype = &bus_ktype;                                   
        priv->drivers_autoprobe = 1;                                            
                                                                                
        retval = kset_register(&priv->subsys);                                  
        if (retval)                                                             
                goto out;                                                       
                                                                                
        retval = bus_create_file(bus, &bus_attr_uevent);                        
        if (retval)                                                             
                goto bus_uevent_fail;                                           
                                                                                
        priv->devices_kset = kset_create_and_add("devices", NULL,               
                                                 &priv->subsys.kobj);   
        if (!priv->devices_kset) {                                              
                retval = -ENOMEM;                                               
                goto bus_devices_fail;                                          
        }                                                                       
                                                                                
        priv->drivers_kset = kset_create_and_add("drivers", NULL,               
                                                 &priv->subsys.kobj);           
        if (!priv->drivers_kset) {                                              
                retval = -ENOMEM;                                               
                goto bus_drivers_fail;                                          
        }                                                                       
                                                                                
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); 
        klist_init(&priv->klist_drivers, NULL, NULL);                           
                                                                                
        retval = add_probe_files(bus);                                          
        if (retval)                                                             
                goto bus_probe_files_fail;                                      
                                                                                
        retval = bus_add_attrs(bus);                                            
        if (retval)                                                             
                goto bus_attrs_fail;                                            
                                                                                
        pr_debug("bus: ‘%s‘: registered\n", bus->name);                         
        return 0;

 

struct bus_type_private *priv指向struct bus_type,这里会显示/sys/bus/platform

retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); 

priv->subsys.kobj.kset = bus_kset;

retval = kset_register(&priv->subsys);// subsys is a kset.

这里显示/sys/bus/platform/devices

priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj);

这里显示/sys/bus/platform/drivers

priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);

 kset_create_and_add--->kset_register

/**                                                                                
 * kset_register - initialize and add a kset.                                      
 * @k: kset.                                                                       
 */                                                                                
int kset_register(struct kset *k)                                                  
{                                                                                  
        int err;                                                                   
                                                                                   
        if (!k)                                                                    
                return -EINVAL;                                                    
                                                                                   
        kset_init(k); // INIT_LIST_HEAD(&k->kobj->entry); INIT_LIST_HEAD(&k->list);                                                             
        err = kobject_add_internal(&k->kobj);                                      
        if (err)                                                                   
                return err;                                                        
        kobject_uevent(&k->kobj, KOBJ_ADD);                                                                                                      
        return 0;                                                                  
} 
static int kobject_add_internal(struct kobject *kobj)                           
{   
    kobj_kset_join(kobj);
    error = create_dir(kobj); // /sys/bus/platform
}
/* add the kobject to its kset‘s list */                                        
static void kobj_kset_join(struct kobject *kobj)                                                                                                 
{                                                                               
        if (!kobj->kset)                                                        
                return;                                                         
                                                                                
        kset_get(kobj->kset);                                                   
        spin_lock(&kobj->kset->list_lock);                                      
        list_add_tail(&kobj->entry, &kobj->kset->list);                         
        spin_unlock(&kobj->kset->list_lock);                                    
} 

If a kset is associated with a kobject, then the parent for the kobject can be set to
NULL in the call to kobject_add() and then the kobject‘s parent will be the kset itself.

struct kobject {                                                                   
        const char              *name;                                             
        struct list_head        entry;                                             
        struct kobject          *parent;                                           
        struct kset             *kset;                                             
        struct kobj_type        *ktype;                                            
        struct sysfs_dirent     *sd;                                               
        struct kref             kref;                                              
        unsigned int state_initialized:1;                                          
        unsigned int state_in_sysfs:1;                                             
        unsigned int state_add_uevent_sent:1;                                                                                                    
        unsigned int state_remove_uevent_sent:1;                                   
}; 
 *                                                                              
 * A kset defines a group of kobjects.  They can be individually                
 * different "types" but overall these kobjects all want to be grouped          
 * together and operated on in the same manner.  ksets are used to              
 * define the attribute callbacks and other common events that happen to        
 * a kobject.                                                                   
 *                                                                              
 * @list: the list of all kobjects for this kset                                
 * @list_lock: a lock for iterating over the kobjects                           
 * @kobj: the embedded kobject for this kset (recursion, isnt it fun...)       
 * @uevent_ops: the set of uevent operations for this kset.  These are          
 * called whenever a kobject has something happen to it so that the kset           
 * can add new environment variables, or filter out the uevents if so              
 * desired.                                                                        
 */                                                                                
struct kset {                                                                                                                                    
        struct list_head list;                                                  
        spinlock_t list_lock;                                                      
        struct kobject kobj;                                                       
        struct kset_uevent_ops *uevent_ops;                                        
};
struct list_head {                                                                                                                               
        struct list_head *next, *prev;                                          
}; 

从list_add_tail(&kobj->entry, &kobj->kset->list); 调用中,我们一下子就明白了,

bus =&struct bus_type platform_bus_type;
bus->p->->subsys.kobj.kset = bus_kset;// bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); 创建了bus的kset显示/sys/bus
所以&kobj->kset->list就是bus_kset->list,list_add_tail就是把
bus->p->->subsys.kobj.entry加入到bus_kset->list链表中。
bus_kset包含不同bus的subsys的kset,而代表subsys的kset的就是这个kset中的kobject。所以把kobjetct的entry加入到表示kset的kset->list中。
换句话说,struct kset这个集合包含的内容由其嵌入的struct list_head list来表示,这个struct kset自身由其嵌入的struct kobject kobj来表示。
所以这里就是把platform这个kset加入到bus这个kset中。用户空间的视图表示就是
/sys/bus/platform。
 
















以上是关于Linux驱动模型解析bus之platform bus的主要内容,如果未能解决你的问题,请参考以下文章

linux设备驱动之platform平台总线工作原理

linux内核源码分析之设备驱动(platform)

linux platform device/driver--Platform Device和Platform_driver注册过程之代码对比

Linux驱动子系统剖析 | Linux设备与驱动分离思想的代表作——platform总线模型

Linux驱动子系统剖析 | Linux设备与驱动分离思想的代表作——platform总线模型

深入解析Linux Platform_device 及驱动