| 
	 在分析设备模型的bus之前,我们看一下初始化的过程,很有意思: 
	     start_kernel-->rest_init-->kernel_init-->do_basic_setup 
	     在do_basic_setup中有个usermodehelper_init有意思,凭感觉,这个函数与kobject_uevent有联系,kobject_uevent做什么的,就是内核空间来通知用户空间的,比如udev就是利用这个来在/dev创建设备文件的,再比如在嵌入式中,插拔个硬盘或者USB,gui总会提示插入或者拨出之类的提示,这个一般是内核中驱动模型根据kobject的uevent来告诉用户态的,如果通信的,是通过netlink这种特殊的socket来像用户空间广播的,这样gui中可以用socket来接受信息,并解析,然后显示出来。先提到这里,usermodehelper_init是不是这么回事,还需要更多的时间去研究。 
	      好,继续看do_basic_setup中的其它函数:driver_init 
	       
	
	看下这个函数的注释,就清楚它就是接下来要分析的设备模型 的初始化。
		
			 
			 
			 
			 
			 
			  
			void __init driver_init(void)  
			{  
			      
			    devtmpfs_init();  
			    devices_init();  
			    buses_init();  
			    classes_init();  
			    firmware_init();  
			    hypervisor_init();  
			  
			     
			 
			  
			    platform_bus_init();  
			    system_bus_init();  
			    cpu_dev_init();  
			    memory_dev_init();  
			}   
	  
	      devtmpfs_init是什么?是在/dev下面挂载的一个内存文件系统,具体可以看《linux设备模型之字符设备》一文,与驱动是有一定联系,应该是2.6.32之后加入的。 
	      今天我们只分析core core pieces中的buses_init: 
	  
	
	很简单,新增一个kset,在/sys下有了bus目录。
		
			int __init buses_init(void)  
			{  
			    bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);  
			    if (!bus_kset)  
			        return -ENOMEM;  
			    return 0;  
			}   
	  
	       我们的重心在后面,如何在bus目录下添加总线类型: 
	       描述总线的结构体:bus_type 
	  
	
	与bus_type紧密相关的结构体:struct bus_type_private
		
			struct bus_type {  
			    const char      *name;     
			    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 bus_type_private *p;      
			};   
	  
	  
	
	总线的注册:bus_register
		
			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;      
			};   
	  
	         
	
	总线的注册方法就是上面这么多,比如platform总线的注册,就是在/sys/bus目录下多了个platform目录,而在platform目录下:
		
			 
			 
			 
			 
			 
			 
			 
			  
			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;  
			  
			bus_attrs_fail:  
			    remove_probe_files(bus);  
			bus_probe_files_fail:  
			    kset_unregister(bus->p->drivers_kset);  
			bus_drivers_fail:  
			    kset_unregister(bus->p->devices_kset);  
			bus_devices_fail:  
			    bus_remove_file(bus, &bus_attr_uevent);  
			bus_uevent_fail:  
			    kset_unregister(&bus->p->subsys);  
			    kfree(bus->p);  
			out:  
			    bus->p = NULL;  
			    return retval;  
			}   
	  
	        devices  drivers  drivers_autoprobe  drivers_probe  uevent 
	        总线远没有目前看到的这么简单,因为它的方法我们还没用到。在分析完设备和驱动后,我们再分析一个完整的过程。(责任编辑:IT) |