注:基於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()的分析就到這里,后面會以平台設備和平台驅動來說說是怎么利用這些東西讓它們“溝通”起來的,這也就是編寫驅動的人比較關心的內容。
附:本人也在學習中,第一次寫這些東西,寫得不好還請見諒。