解析完了PCI的那些内核参数,再翻过多少座山跨过多少条河,内核就会遇到init/main.c里一个名叫do_initcalls的函数。do_initcalls对内核来说只不过是漫长冒险旅程中的一个驿站,对PCI这个故事来说却是命运转轮的开始,内核在它里边完成了对.initcall.init节里各种xxx_initcall函数的执行,PCI的那些自然也包括在内。你不用像新东方老罗“我走来走去,为中国的命运苦苦思索。”那样走来走去为PCI的命运思索,因为决定PCI命运的那些xxx_initcall早列在之前的那张表里了,也不用你再去蓦然回首,这里会再贴一遍。
文件
|
函数
|
入口
|
内存位置
|
arch/i386/pci/acpi.c
|
pci_acpi_init
|
subsys_initcall
|
.initcall4.init
|
arch/i386/pci/common.c
|
pcibios_init
|
subsys_initcall
|
.initcall4.init
|
arch/i386/pci/i386.c
|
pcibios_assign_resources
|
fs_initcall
|
.initcall5.init
|
arch/i386/pci/legacy.c
|
pci_legacy_init
|
subsys_initcall
|
.initcall4.init
|
drivers/pci/pci-acpi.c
|
acpi_pci_init
|
arch_initcall
|
.initcall3.init
|
drivers/pci/pci- driver.c
|
pci_driver_init
|
postcore_initcall
|
.initcall2.init
|
drivers/pci/pci- sysfs.c
|
pci_sysfs_init
|
late_initcall
|
.initcall7.init
|
drivers/pci/pci.c
|
pci_init
|
device_initcall
|
.initcall6.init
|
drivers/pci/probe.c
|
pcibus_class_init
|
postcore_initcall
|
.initcall2.init
|
drivers/pci/proc.c
|
pci_proc_init
|
__initcall
|
.initcall6.init
|
arch/i386/pci/init.c
|
pci_access_init
|
arch_initcall
|
.initcall3.init
|
atm dma graphics hwmon i<chmetcnv w:st="on" unitname="C" sourcevalue="2" hasspace="False" negative="False" numbertype="1" tcsc="0">2c</chmetcnv>-adapter input
mem misc net pci_bus scsi_device scsi_disk
scsi_hostsound spi_host spi_master spi_transport tty
usb_device usb_endpoint usb_host vc vtconsole
想当初,usb子系统初始化的时候,调用了一次class_create(THIS_MODULE, "usb_host"),然后上边儿就多了一个usb_host目录,那么现在调用这个class_register,上边儿又会多出什么?这个大家一眼就能看出来,即使一眼看不出来两眼也能看出来了,赚钱买猪肉的本事没有,寻找这种敏感地带的本事还都是有的,凭空多出来的就是那个pci_bus。从这点儿看,create还是register对咱们来说都差不多,都是在/sys/class下边儿创建了一个类,usb_host类的目录里是各个具体的主机控制器,pci_bus类的目录里对应的就是各个pci总线了。本来难得糊涂一下明白这些就成了,不过如果真想稍微不那么糊涂一点儿,可以去扫两眼class_create的定义,你就会发现它里面最终也会调用一个class_register,这两个的差别就是class_create要更傻瓜一些,你指定个类的名称就可以调用它了,它里面会帮你创建一个struct class结构体,而class_register则更费事一些,你需要自己亲自动手创建一个struct class结构体。如果你觉得自己挺特殊,需要指定自己的release函数等,那就必须得使用class_register了,PCI就属于这种情况,至于它怎么个特殊,就是后话了。
pcibus_class_init之后,接着就应该是pci_driver_init
542 struct bus_type pci_bus_type = {
544 .match = pci_bus_match,
545 .uevent = pci_uevent,
546 .probe = pci_device_probe,
547 .remove = pci_device_remove,
548 .suspend = pci_device_suspend,
549 .suspend_late = pci_device_suspend_late,
550 .resume_early = pci_device_resume_early,
551 .resume = pci_device_resume,
552 .shutdown = pci_device_shutdown,
553 .dev_attrs = pci_dev_attrs,
554 };
556 static int __init pci_driver_init(void)
557 {
558 return bus_register(&pci_bus_type);
559 }
还记得linux设备模型里存在于总线、设备、驱动之间的那个著名的三角关系么?如果不记得,那就先听俺讲个小故事:
话说多少年以前有个人非常的健忘,他老婆很无奈,就对他说:“听说南村的谁谁谁专治女性不孕男性健忘,你还是去找他医一下吧!” 好男人准则第一条就是要听老婆的话,于是这个人就背上弓箭,骑上马出发了。人不是都有三急么,半道儿上他想大便,就把马拴在一棵大树上,躲在树后,顺手把箭插在地上。方便过后,正在顺爽,顺爽,一顺再顺,顺出新自我,忽然看见了地上的箭,惊出了一身冷汗,“好险,不知谁射来的箭,差点要了我的小命!”紧赶的往外跑,一脚踩在大便上,不禁连皱眉头,大骂不已:“谁这么缺德,不讲公共卫生,在这里随地大小便……”。等到看到拴在树上的马,又高兴起来,心想:虽然吃了点儿苦头,捡到一匹马着实得美,就像金帝美滋滋巧克力,全新的色彩,全新的味道。于是他骑上马晕晕乎乎不知所之,沿着原路折了回去。一边想着我这是在哪儿呢,一边瞧见了一座房子。“咦,这房子好生面熟?……”这个时候,他老婆正从屋里看见他糊里糊涂的样子,气不打一处来,出门儿来责备他。只见他不卑不亢的作了一个揖,说:“这位大嫂,你我素昧平生,何苦出言不逊?”
这个故事的教育意义就在于告诉我们健忘是一种病态,善忘是一种境界,做人不能健忘到如此地步。那个三角关系中的总线落实在USB就是usb_bus_type,落实在PCI就是上面的pci_bus_type,pci_driver_init函数的目的就是注册PCI总线,只有总线存在了,才会有设备的那条链表和驱动的那条链表,才会有设备和驱动之间的match。