• Linux驱动学习(一)


    注:基于linux-2.6.38

            在linux源码的根目录下有一个叫drivers的目录,可以发现linux源码根目录下也就那么十来二十个目录,linux把drivers作为根目录下的一个独立的目录,足见drivers在linux里占有的分量有多重。

           打开drivers目录一看,有一种晕呼呼的感觉,好几十个目录就这样“活生生”地摆在眼前,不知该如何下手。任何东西如果多了,但没有秩序去维持,肯定会变得很混乱,显然linux不会让这种情况出现。一般来说,里面的每一个目录可以说代表一类驱动,但linux整个driver的初始化操作在哪里?根据前人的探索和经验可知,没错,就在/drivers/base/init.c里,打开它发现里面就一个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 
    11         /* These are also core pieces, but must come after the
    12          * core core pieces.
    13          */
    14         platform_bus_init();
    15         system_bus_init();
    16         cpu_dev_init();
    17         memory_dev_init();
    18 }

    哟,原来是“禾草盖珍珠”,该函数内部全都是函数调用,其实这种现象在linux里多的是。在这里我主要想沿着一条主线“走下去”,而不是走着走着就“跑到”老远去,然后再回来。对于学习这件事情,我更偏向于先看到结果然后再努力去搞懂其内在的原理。好吧,接下就去寻找我想要的结果。

    第4行调用devtmpfs_init()函数,从它的名字去理解它,就是/dev文件系统的初始化。第5行调用devices_init()函数,在drivers/base/core.c里定义,看看它怎么实现的:

     1 int __init devices_init(void)
     2 {
     3         devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
     4         if (!devices_kset)
     5                 return -ENOMEM;
     6         dev_kobj = kobject_create_and_add("dev", NULL);
     7         if (!dev_kobj)
     8                 goto dev_kobj_err;
     9         sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
    10         if (!sysfs_dev_block_kobj)
    11                 goto block_kobj_err;
    12         sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
    13         if (!sysfs_dev_char_kobj)
    14                 goto char_kobj_err;
    15 
    16         return 0;
    17  
    18  char_kobj_err:
    19         kobject_put(sysfs_dev_block_kobj);
    20  block_kobj_err:
    21         kobject_put(dev_kobj);
    22  dev_kobj_err:
    23         kset_unregister(devices_kset);
    24         return -ENOMEM;
    25 }

     还是比较简单的,第3行在/sys目录下创建了devices目录,第6行在/sys下创建了dev目录,第9,12行分别在/sys/dev下创建了block和char这两个目录。

    接下来看在drivers/base/bus.c里定义的buses_init()函数:

    1 int __init buses_init(void)
    2 {
    3         bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
    4         if (!bus_kset)
    5                 return -ENOMEM;
    6         return 0;
    7 }

    第3行在/sys下创建了bus目录。

    drivers/base/class.c里定义的classes_init()函数:

    1 int __init classes_init(void)
    2 {
    3         class_kset = kset_create_and_add("class", NULL, NULL);
    4         if (!class_kset)
    5                 return -ENOMEM;
    6         return 0;
    7 }

    第3行在/sys下创建了class目录。

    对于firmware_init()和hypervisor_init这两个函数暂时掠过。

    在drivers/base/platform.c里定义的platform_bus_init()函数:

     1 int __init platform_bus_init(void)
     2 {
     3         int error;
     4         
     5         early_platform_cleanup();
     6 
     7         error = device_register(&platform_bus);
     8         if (error)
     9                 return error;
    10         
    11         error =  bus_register(&platform_bus_type);
    12         if (error)
    13                 device_unregister(&platform_bus);
    14         return error;
    15 }

    第5行,在early_platform_cleanup()函数里通过遍历链表清除之前的平台代码。第7行,设备注册,不要被它的参数的名字骗了,先看参数platform_bus的定义:

    1 struct device platform_bus = {
    2         .init_name      = "platform",
    3 };

    只定义了设备的名字为platform。再看device_register()函数:

    1 int device_register(struct device *dev)
    2 {       
    3         device_initialize(dev);
    4         return device_add(dev);
    5 } 

     只有两个函数调用,先看device_initialize()函数:

     1 void device_initialize(struct device *dev)
     2 {
     3         dev->kobj.kset = devices_kset;
     4         kobject_init(&dev->kobj, &device_ktype);
     5         INIT_LIST_HEAD(&dev->dma_pools);
     6         mutex_init(&dev->mutex);
     7         lockdep_set_novalidate_class(&dev->mutex);
     8         spin_lock_init(&dev->devres_lock);
     9         INIT_LIST_HEAD(&dev->devres_head);
    10         device_pm_init(dev);
    11         set_dev_node(dev, -1);
    12 }

    第3行的devices_kset由之前的devices_init()里被赋值,作为所有设备的顶层kset。第4行初始化当前设备的kobject。第10行是该设备电源管理的初始化。第11行,看一下:

    1 static inline void set_dev_node(struct device *dev, int node)
    2 {       
    3         dev->numa_node = node;
    4 }

    没什么,就给dev里的成员numa_node赋值为node(这里是-1)。

    回到device_register()里的device_add()函数,这个函数比较长,涉及的内容也很多,不过还是得看,暂时将它分为两部分吧,先看第一部分:

     1 int device_add(struct device *dev)
     2 {
     3         struct device *parent = NULL;
     4         struct class_interface *class_intf;
     5         int error = -EINVAL;
     6 
     7         dev = get_device(dev);
     8         if (!dev)
     9                 goto done;
    10 
    11         if (!dev->p) {
    12                 error = device_private_init(dev);
    13                 if (error)
    14                         goto done;
    15         }
    16 
    17         /*
    18          * for statically allocated devices, which should all be converted
    19          * some day, we need to initialize the name. We prevent reading back
    20          * the name, and force the use of dev_name()
    21          */
    22         if (dev->init_name) {
    23                 dev_set_name(dev, "%s", dev->init_name);
    24                 dev->init_name = NULL;
    25         }
    26 
    27         if (!dev_name(dev)) {
    28                 error = -EINVAL;
    29                 goto name_error;
    30         }
    31 
    32         pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
    33 
    34         parent = get_device(dev->parent);
    35         setup_parent(dev, parent);
    36 
    37         /* use parent numa_node */
    38         if (parent)
    39                 set_dev_node(dev, dev_to_node(parent));
    40 
    41         /* first, register with generic layer. */
    42         /* we require the name to be set before, and pass NULL */
    43         error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
    44         if (error)
    45                 goto Error;
    46 
    47         /* notify platform of device entry */
    48         if (platform_notify)
    49                 platform_notify(dev);
    50 
    51         error = device_create_file(dev, &uevent_attr);
    52         if (error)
    53                 goto attrError;
    54 
    55         if (MAJOR(dev->devt)) {
    56                 error = device_create_file(dev, &devt_attr);
    57                 if (error)
    58                         goto ueventattrError;
    59 
    60                 error = device_create_sys_dev_entry(dev);
    61                 if (error)
    62                         goto devtattrError;
    63                 
    64                 devtmpfs_create_node(dev);
    65         }
    66         error = device_add_class_symlinks(dev);
    67         if (error)
    68                 goto SymlinkError;
    69         error = device_add_attrs(dev);
    70         if (error)
    71                 goto AttrsError;
    72         error = bus_add_device(dev);
    73         if (error)
    74                 goto BusError;
    75         error = dpm_sysfs_add(dev);
    76         if (error)
    77                 goto DPMError;
    78         device_pm_add(dev);
    .....................

    第7行,增加该设备的引用计数;第12行,主要为dev->p成员分配内存,然后对p里面的一些成员作初始化;第22~30行是关与dev->name的一些操作;第35行,设置当前设备的父设备;第39行,看注释就知道是将父设备numa_node成员的值赋给当前设备;第43行,调用kobject_add(),这个函数的内部调用关系挺复杂的,主要功能是建立当前设备与父设备的kobject对象关系和在/sys相应的目录下建立一个目录;第51行,创建设备的属性文件;第55行,如果该设备定义了主设备号的话就再生成一个设备文件,还有就是通过devtmpfs_create_node()函数在/dev下动态创建设备节点。第66~77行主要涉及sysfs文件系统的操作,在此暂时掠过;第78行是与电源管理相关的。

    接下来看device_add()函数的第2部分:

     1         if (dev->bus)
     2                 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
     3                                              BUS_NOTIFY_ADD_DEVICE, dev);
     4         
     5         kobject_uevent(&dev->kobj, KOBJ_ADD);
     6         bus_probe_device(dev);
     7         if (parent)
     8                 klist_add_tail(&dev->p->knode_parent,
     9                                &parent->p->klist_children);
    10 
    11         if (dev->class) {
    12                 mutex_lock(&dev->class->p->class_mutex);
    13                 /* tie the class to the device */
    14                 klist_add_tail(&dev->knode_class,
    15                                &dev->class->p->klist_devices);
    16 
    17                 /* notify any interfaces that the device is here */
    18                 list_for_each_entry(class_intf,
    19                                     &dev->class->p->class_interfaces, node)
    20                         if (class_intf->add_dev)
    21                                 class_intf->add_dev(dev, class_intf);
    22                 mutex_unlock(&dev->class->p->class_mutex);
    23         }
    24 done:
    25         put_device(dev);
    26         return error;
    27  DPMError:
    28         bus_remove_device(dev);
    29  BusError:
    30         device_remove_attrs(dev);
    31  AttrsError:
    32         device_remove_class_symlinks(dev);
    33  SymlinkError:
    34         if (MAJOR(dev->devt))
    35                 devtmpfs_delete_node(dev);
    36         if (MAJOR(dev->devt))
    37                 device_remove_sys_dev_entry(dev);
    38  devtattrError:
    39         if (MAJOR(dev->devt))
    40                 device_remove_file(dev, &devt_attr);
    41  ueventattrError:
    42         device_remove_file(dev, &uevent_attr);
    43  attrError:
    44         kobject_uevent(&dev->kobj, KOBJ_REMOVE);
    45         kobject_del(&dev->kobj);
    46  Error:
    47         cleanup_device_parent(dev);
    48         if (parent)
    49                 put_device(parent);
    50 name_error:
    51         kfree(dev->p);
    52         dev->p = NULL;
    53         goto done;
    54 }

    第5行kobject_uevent()这个函数的实现不是一般的复杂,主要是向用户空间发送消息,实现热插拔,暂时用不到,先掠过;第6行,bus_probe_device()这个函数非常重要,因此尽可能详细地分析一下,看它在drivers/base/bus.c里定义:

     1 void bus_probe_device(struct device *dev)
     2 {
     3         struct bus_type *bus = dev->bus;
     4         int ret;
     5 
     6         if (bus && bus->p->drivers_autoprobe) {
     7                 ret = device_attach(dev);
     8                 WARN_ON(ret < 0);
     9         }
    10 }

    别看它那么短,其实没那么简单。if的条件很显然,直接看第7行的device_attach()函数,在drivers/base/dd.c里定义为:

     1 int device_attach(struct device *dev)
     2 {
     3         int ret = 0;
     4         
     5         device_lock(dev);
     6         if (dev->driver) {
     7                 ret = device_bind_driver(dev);
     8                 if (ret == 0) 
     9                         ret = 1;
    10                 else {                
    11                         dev->driver = NULL;
    12                         ret = 0;
    13                 }
    14         } else {
    15                 pm_runtime_get_noresume(dev);
    16                 ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
    17                 pm_runtime_put_sync(dev);
    18         }
    19         device_unlock(dev);
    20         return ret;
    21 }

    第6行,如果当前设备已经绑定了相应的驱动程序,那么就调用device_bind_driver()。在这里有个疑问:先有设备还是先有驱动?一般来说是先有设备再有驱动,但对于热插拔设备来说的话则相反。不管怎样,去看看它是怎么定义的:

    1 int device_bind_driver(struct device *dev)
    2 {
    3         int ret;
    4 
    5         ret = driver_sysfs_add(dev);
    6         if (!ret)
    7                 driver_bound(dev);
    8         return ret;
    9 }

    第5行是与sysfs有关的,直接看第7行的driver_bound()函数:

     1 static void driver_bound(struct device *dev)
     2 {
     3         if (klist_node_attached(&dev->p->knode_driver)) {
     4                 printk(KERN_WARNING "%s: device %s already bound\n",
     5                         __func__, kobject_name(&dev->kobj));
     6                 return;
     7         }
     8 
     9         pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
    10                  __func__, dev->driver->name);
    11 
    12         klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
    13 
    14         if (dev->bus)
    15                 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
    16                                              BUS_NOTIFY_BOUND_DRIVER, dev);
    17 }

    咋一看,都是与链表操作相关的,关键是第12行,实现将驱动程序和设备联系起来。

    回到device_attach()函数的第16行,调用bus_for_each_drv()函数遍历设备所在总线上所有已经挂载了的驱动,每遍历一个就调用一次__device_attach()函数,直接看__device_attach()的定义:

    1 static int __device_attach(struct device_driver *drv, void *data)
    2 {
    3         struct device *dev = data;
    4         
    5         if (!driver_match_device(drv, dev))
    6                 return 0;
    7 
    8         return driver_probe_device(drv, dev);
    9 }

    第5行的函数是在drivers/base/base.h头文件中定义的,只有一行:

    1 static inline int driver_match_device(struct device_driver *drv,
    2                                       struct device *dev)
    3 {       
    4         return drv->bus->match ? drv->bus->match(dev, drv) : 1;
    5 }

    如果驱动所在的总线上定义了match函数,那么就调用它,否则返回1。

    如果driver_match_device()成功,接下来就调用driver_probe_device():

     1 int driver_probe_device(struct device_driver *drv, struct device *dev)
     2 {
     3         int ret = 0;
     4 
     5         if (!device_is_registered(dev))
     6                 return -ENODEV;
     7 
     8         pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
     9                  drv->bus->name, __func__, dev_name(dev), drv->name);
    10 
    11         pm_runtime_get_noresume(dev);
    12         pm_runtime_barrier(dev);
    13         ret = really_probe(dev, drv);
    14         pm_runtime_put_sync(dev);
    15 
    16         return ret;
    17 } 

    主要是第13行的really_probe(),该函数有点长,主要看它的核心部分:

     1 static int really_probe(struct device *dev, struct device_driver *drv)
     2 {
     3 ..................................
     4         dev->driver = drv;
     5         if (driver_sysfs_add(dev)) {
     6                 printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
     7                         __func__, dev_name(dev));
     8                 goto probe_failed;
     9         }
    10 
    11         
    12         if (dev->bus->probe) {
    13                 ret = dev->bus->probe(dev);
    14                 if (ret)
    15                         goto probe_failed;
    16         } else if (drv->probe) {
    17                 ret = drv->probe(dev);
    18                 if (ret)
    19                         goto probe_failed;
    20         }
    21 
    22         driver_bound(dev);
    23 ..............................

    第4行,不用说;第12行,如果设备所在的总线定义了probe()函数则调用它,否则如果设备对应的驱动定义了probe()函数则调用它,在这里可以说第16行的条件一般会满足,至少对于平台设备来说是这样的(研究过平台设备和平台驱动的同学应该懂我的意思)。第22行的driver_bound()函数在上面已经说过了。

    已经“跑”得很远了,回到device_add()函数,发现后面的内容基本上就是一些相应的出错处理。好了,device_register()的分析到这里,回到platform_bus_init()第11行调用的bus_register(),这个函数还是很长,不贴出代码了,主要是涉及kobject,kset和klist等一些操作。

    好了,回到最初的函数driver_init(),第15行调用system_bus_init():

    1 int __init system_bus_init(void)
    2 {
    3         system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
    4         if (!system_kset)
    5                 return -ENOMEM;
    6         return 0;
    7 }

    第3行,在一个/sys/devices下创建system目录。

    driver_init()中最后2个函数是cpu和内存初始化相关的,暂掠过。

    driver_init()的分析就到这里,后面会以平台设备和平台驱动来说说是怎么利用这些东西让它们“沟通”起来的,这也就是编写驱动的人比较关心的内容。

     

    附:本人也在学习中,第一次写这些东西,写得不好还请见谅。

  • 相关阅读:
    MySQL索引底层的实现
    mysql索引深入优化
    explain详解与索引最佳实践
    (MYSQL)回表查询原理,利用联合索引实现索引覆盖
    为什么重复值高的字段不能建索引(比如性别字段等)
    Spring的事务
    为什么要用Redis?Redis为什么这么快?
    spring AOP
    钩子教程
    钩子教程
  • 原文地址:https://www.cnblogs.com/lknlfy/p/2486653.html
Copyright © 2020-2023  润新知