Linux设备驱动子系统的构建过程

前面即便文章讲述了基本的数据结构和操作函数,这篇文章将从系统启动开始简述整个驱动子系统的构建过程。

从系统加电开始,首先是一系列初始化过程,这些过程一般由汇编语言代码完成,在成功初始化一些必要的设备之后,程序会执行第一个C函数start_kernel。为了找个驱动子系统的构建过程,需要沿着start_kernel的函数调用顺序差下去,start_kernel()-->rest_init(),在rest_init中启动了一个内核线程,该线程执行函数kernel_init。从kernel_init一路差下去,我们又要经过do_basic_setup,终于发现了driver_init()这个目标。

?
void __init driver_init( void )
{
         /* These are the core pieces */
         devtmpfs_init();
         devices_init();
         buses_init();
         classes_init();
         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();
}

这就是整个驱动子系统构建的初始过程,当然在这个过程之中只是构建一个大的框架,并没有什么真正的设备可以运行。接下来我们挨个看看这些函数。

1、devtmpfs_init()

这一部主要是构建一个临时的/dev文件系统,主要是VFS的内容,此处不述。

2、devices_init()

?
int __init devices_init( void )
{
         devices_kset = kset_create_and_add( "devices" , &device_uevent_ops, NULL);
         if (!devices_kset)
                 return -ENOMEM;
         dev_kobj = kobject_create_and_add( "dev" , NULL);
         if (!dev_kobj)
                 goto dev_kobj_err;
         sysfs_dev_block_kobj = kobject_create_and_add( "block" , dev_kobj);
         if (!sysfs_dev_block_kobj)
                 goto block_kobj_err;
         sysfs_dev_char_kobj = kobject_create_and_add( "char" , dev_kobj);
         if (!sysfs_dev_char_kobj)
                 goto char_kobj_err;
 
         return 0;
 
char_kobj_err:
         kobject_put(sysfs_dev_block_kobj);
block_kobj_err:
         kobject_put(dev_kobj);
dev_kobj_err:
         kset_unregister(devices_kset);
         return -ENOMEM;
}

这里创建了三个kobject和一个kset,其中devices_kset和dev_kobj是两个顶级节点,在sysfs文件系统中(一般是目录/sys)尤其对应的两个目录:/sys/devices和/sys/dev,而sysfs_dev_block_kobj和sysfs_dev_char_kobj则是dev_kobj的两个子节点,对应于目录/sys/dev/char和/sys/dev/char。

3、buses_init()

?
int __init buses_init( void )
{
         bus_kset = kset_create_and_add( "bus" , &bus_uevent_ops, NULL);
         if (!bus_kset)
                 return -ENOMEM;
         return 0;
}

这里创建了一个kset--bus_kset,这也是一个顶级节点,对应于目录/sys/bus。

4、classes_init

?
int __init classes_init( void )
{
         class_kset = kset_create_and_add( "class" , NULL, NULL);
         if (!class_kset)
                 return -ENOMEM;
         return 0;
}

这里创建了一个kset--class_kset,这也是一个顶级节点,对应于目录/sys/class。

5、firmware_init

?
int __init firmware_init( void )
{
         firmware_kobj = kobject_create_and_add( "firmware" , NULL);
         if (!firmware_kobj)
                 return -ENOMEM;
         return 0;
}

这里创建了一个kobject--firmware_kobj,这也是一个顶级节点,对应于目录/sys/firmware。

6、hypervisor_init

?
int __init hypervisor_init( void )<br>{<br>        hypervisor_kobj = kobject_create_and_add( "hypervisor" , NULL);<br>        if (!hypervisor_kobj)<br>                return -ENOMEM;<br>        return 0;<br>}

这里创建了一个kobject--hypervisor_kobj,这也是一个顶级节点,对应于目录/sys/firmware。

以此为界限,下面的几个函数不再是简单创建几个顶级节点这么简单。

7、platform_bus_init

?
int __init platform_bus_init( void )<br>{<br>        int error;<br><br>        early_platform_cleanup();<br><br>        error = device_register(&platform_bus);<br>        if (error)<br>                return error;<br>        error =  bus_register(&platform_bus_type);<br>        if (error)<br>                device_unregister(&platform_bus);<br>        return error;<br>}

在2.6版本的内核中引入了一种虚拟的总线类型--platform bus。它并不对应真实的总线。在该函数中,首先调用一个函数early_platform_cleanup(),我猜是对启动过程中的数据进行清理,然后会注册一个名为“platform”的设备,这个设备会作为所有platform设备的父节点。在struct device中有一个parent成员就是会了完成这种父子关系的构建。

除了注册一个名为“platform”的设备之外,还会注册一个同样名称的总线,所有的platform设备都被当作挂载到这个总线上。

8、system_bus_init

?
int __init system_bus_init( void )<br>{<br>        system_kset = kset_create_and_add( "system" , NULL, &devices_kset->kobj);<br>        if (!system_kset)<br>                return -ENOMEM;<br>        return 0;<br>}

这里创建了一个名为system的kset,其父节点为在devices_init中创建的devices_kset。在此kset中是一些和CPU、中断控制器、时钟之类的设备。

9、cpu_dev_init

?
int __init cpu_dev_init( void )<br>{<br>        int err;<br><br>        err = sysdev_class_register(&cpu_sysdev_class);<br># if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)<br>        if (!err)<br>                err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);<br>#endif<br><br>        return err;<br>}

这里注册了一个名为"CPU"的类,其父节点在system_bus_init中注册的system_kset。其对应的目录为/sys/devices/system/cpu,其中包含CPU相关的属性。

10、memory_dev_init

?
int __init memory_dev_init( void )
{
         unsigned int i;
         int ret;
         int err;
         unsigned long block_sz;
 
         memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops;
         ret = sysdev_class_register(&memory_sysdev_class);
         if (ret)
                 goto out;
 
         block_sz = get_memory_block_size();
         sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
 
         /*
          * Create entries for memory sections that were found
          * during boot and have been initialized
          */
         for (i = 0; i < NR_MEM_SECTIONS; i++) {
                 if (!present_section_nr(i))
                         continue ;
                 err = add_memory_section(0, __nr_to_section(i), MEM_ONLINE,
                                          BOOT);
                 if (!ret)
                         ret = err;
         }
 
         err = memory_probe_init();
         if (!ret)
                 ret = err;
         err = memory_fail_init();
         if (!ret)
                 ret = err;
         err = block_size_init();
         if (!ret)
                 ret = err;
out:
         if (ret)
                 printk(KERN_ERR "%s() failed: %d\n" , __func__, ret);
         return ret;
}

这里注册了一个名为"memory"的类,其父节点在system_bus_init中注册的system_kset。其对应的目录为/sys/devices/system/memory,其中包含内存相关的属性,如块大小等。

你可能感兴趣的:(Linux设备驱动子系统的构建过程)