Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1364386
  • 博文数量: 284
  • 博客积分: 3251
  • 博客等级: 中校
  • 技术积分: 3046
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-26 17:23
文章分类

全部博文(284)

文章存档

2019年(2)

2018年(5)

2015年(19)

2014年(13)

2013年(10)

2012年(235)

分类:

2012-11-27 15:42:40

原文地址:linux设备:初始化 作者:zengxg14


事情是如何发生的?

当按下开机键后,电脑经过自检,执行引导程序,内核初始化,然后创建了内核线程init线程,init线程调用do_basic_setup()来初始化外部设备,加载驱动程序....  (这一段实在其他地方看来的,并不表示我看过内核初始化的代码)

  1. static void __init do_basic_setup(void)
  2. {
  3.     init_workqueues();
  4.     cpuset_init_smp();
  5.     usermodehelper_init();
  6.     init_tmpfs();
  7.     driver_init();    /* 初始化设备 */
  8.     init_irq_proc;
  9.     do_ctors();
  10.     do_initcalls();
  11. }

下面是driver_init()函数

  1. void __init driver_init(void)
  2. {
  3.     /* These are the core pieces */
  4.     devtmpfs_init();
  5.     devices_init();   /* 设备初始化 */
  6.     buses_init();     /* 总线初始化 */
  7.     classes_init();   /* 类初始化 */
  8.     firmware_init();
  9.     hypervisor_init();

  10.     /* These are also core pieces, but must come after the
  11.      * core core pieces.
  12.      */
  13.     platform_bus_init();
  14.     system_bus_init();
  15.     cpu_dev_init();
  16.     memory_dev_init();
  17. }
它又调用了devices_init()、buses_init()、chasses_init();

下面是devices_init()

  1. int __init devices_init(void)
  2. {
  3.     /* 创建/sys/devices目录 和 devices_kset */
  4.     devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
  5.     if (!devices_kset)
  6.         return -ENOMEM;
  7.     /* 创建/sys/dev目录 和 dev_kobj */
  8.     dev_kobj = kobject_create_and_add("dev", NULL);
  9.     if (!dev_kobj)
  10.         goto dev_kobj_err;
  11.     /* 创建/sys/dev/block目录 和sysfs_dev_block_kobj */
  12.     sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
  13.     if (!sysfs_dev_block_kobj)
  14.         goto block_kobj_err;
  15.     /* 创建/sys/dev/char目录 和 sysfs_dev_char_kobj */
  16.     sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
  17.     if (!sysfs_dev_char_kobj)
  18.         goto char_kobj_err;

  19.     return 0;

  20.  char_kobj_err:
  21.     kobject_put(sysfs_dev_block_kobj);
  22.  block_kobj_err:
  23.     kobject_put(dev_kobj);
  24.  dev_kobj_err:
  25.     kset_unregister(devices_kset);
  26.     return -ENOMEM;
  27. }
因此devices_init()就是调用kset_create_and_add和kobject_create_and_add函数来创建kset和kobject对象。
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
dev_kobj = kobject_create_and_add("dev", NULL);
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);

下面的buses_init,classes_init,firmware_init,hypervisor_init与此类似,下面列出这些函数创建的kset和kobject对象。在创建这些对象的时候也会在/sys目录下创建相应的目录。

  1. buses_init:
  2.      bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);

  3. classes_init:
  4.      class_kset = kset_create_and_add("class", NULL, NULL);

  5. firmware_init:
  6.      firmware_kobj = kobject_create_and_add("firmware", NULL);

  7. hypervisor_init:
  8.      hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);

接着是函数:platform_bus_init(),

  1. int __init platform_bus_init(void)
  2. {
  3.     int error;
  4.     early_platform_cleanup();
  5.     /* 注册了platform_bus, 即在/sys/devices目录下创建了platform目录,以及目录下的相关属性文件*/
  6.     error = device_register(&platform_bus);
  7.     if(error) return error;
  8.     /* 注册platform_bus_type, 在/sys/bus/目录下创建了platform目录,及相应的属性文件 */
  9.     error = bus_register(&platform_bus_type);
  10.     if(error) device_unregister(&platform_bus);
  11.     return error;
  12. }
  13.  
  14. /* platform_bus的定义 */
  15. struct device platform_bus = {
  16.     .init_name = "platform",
  17. };
  18.  
  19. /* platform_bus_type的定义 */
  20. struct bus_type platform_bus_type = {
  21.     .name      = "platform",
  22.     .dev_attrs = platform_dev_attrs,
  23.     .match     = platform_match,
  24.     .uevent    = platform_uevent,
  25.     .pm        = &platform_dev_pm_ops
  26. };

接着是:system_bus_init();
该函数创建了system_kset,以及/sys/devices下的system目录:
= ("system", , &devices_kset->);


接着是:cpu_dev_init();

  1. int __init cpu_dev_init(void)
  2. {
  3.     int err;
  4.     /* 见下面 */
  5.     err = sysdev_class_register(&cpu_sysdev_class);
  6.     if (!err)
  7. /*  调用了sysdev_class_create_file(&cpu_sysdev_class, []);
  8.     为数组cpu_state_attr中的属性创建文件,即创建了online, possible, present, kernel_max,offline .
  9.     读这些文件时会调用相应的函数:print_cpus_online, print_cpus_kernel_max, print_cpus_onlinetype, print_cpus_possibletype, print_cpus_presenttype */
  10.         err = cpu_states_init();

  11. #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
  12.     if (!err)
  13.         err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
  14. #endif

  15.     return err;
  16. }
  17.  
  18. struct sysdev_class cpu_sysdev_class = {
  19. .name = "cpu",
  20. };

  21. struct sysdev_class {
  22. const char *name;
  23. struct list_head drivers;

  24. /* Default operations for these types of devices */
  25. int (*shutdown)(struct sys_device *);
  26. int (*suspend)(struct sys_device *, pm_message_t state);
  27. int (*resume)(struct sys_device *);
  28. struct kset kset;
  29. };
这里的sysdev_class结构体类似与bus_type和device。

在system_bus_init函数创建了system_kset,
下面是sysdev_class_register()函数

  1. int sysdev_class_register(struct sysdev_class *cls)
  2. {
  3. ...
  4.     INIT_LIST_HEAD(&cls->drivers);
  5.     memset(&cls->kset.kobj, 0x00, sizeof(struct kobject));
  6.     cls->kset.kobj.parent = &system_kset->kobj;
  7.     cls->kset.kobj.ktype = &ktype_sysdev_class;
  8.     cls->kset.kobj.kset = system_kset;

  9.     retval = kobject_set_name(&cls->kset.kobj, "%s", cls->name);
  10. ...
  11.     return kset_register(&cls->kset);
  12. }
可见这里就是将cpu_sysdev_class加入到设备模型中去,该对象的父kset为system_kset,ktype为ktype_sysdev_class。
因此在/sys/devices/system目录下创建了cpu目录


最后是memory_dev_init函数
简单看下该函数就知道这个和上面的cpu_dev_init是类似的。

  1. int __init memory_dev_init(void)
  2. {
  3.     unsigned int i;
  4.     int ret;
  5.     int err;

  6.     memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops;
  7.     ret = sysdev_class_register(&memory_sysdev_class);
  8.     if (ret)
  9.         goto out;

  10.     /*
  11.      * Create entries for memory sections that were found
  12.      * during boot and have been initialized
  13.      */
  14.     for (i = 0; i < NR_MEM_SECTIONS; i++) {
  15.         if (!present_section_nr(i))
  16.             continue;
  17.         err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE,
  18.                     0, BOOT);
  19.         if (!ret)
  20.             ret = err;
  21.     }

  22.     err = memory_probe_init();
  23.     if (!ret)
  24.         ret = err;
  25.     err = block_size_init();
  26.     if (!ret)
  27.         ret = err;
  28. out:
  29.     if (ret)
  30.         printk(KERN_ERR "%s() failed: %d\n", __func__, ret);
  31.     return ret;
  32. }
(非常奇怪,在我的ubuntu 10.10上竟然没有找到/sys/device/system/memory目录,内核版本是2.6.35-32-generic, x86,不该呀,有人知道原因吗?)


可以看出整个driver_init()只是在/sys下创建了一系列的kset和kobject对象和相应的目录,但没有创建任何真正的设备,或者虚拟的设备。比如/sys/devices/system/cpu目录下的cpu0目录的创建,这些可能是在do_initcalls中处理的,我得先搞清楚这个函数是怎么起作用的。








阅读(683) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~