《PCI设备快速编程27157.pdf》由会员分享,可在线阅读,更多相关《PCI设备快速编程27157.pdf(23页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、 PCI 是 Peripheral Component Interconnect(外设部件互连标准)的缩写,它是目前个人电脑中使用最为广泛的接口,其位宽为 32 位或 64 位,工作频率为33MHz,最大数据传输率为 133MB/sec(32 位)和 266MB/sec(64 位)。可插接显卡、声卡、网卡、内置 Modem、内置 ADSL Modem、USB2.0 卡、IEEE1394 卡、IDE 接口卡、RAID 卡、电视卡、视频采集卡以及其它种类繁多的扩展卡.目前 PCI-E 是 PCI 最新的发展方向,串行,点对点传输,每个传输通道独享带宽;支持双向传输模式和数据分通道传输模式;在 PC
2、I-E 3.0 规范中,X32 端口的双向速率高达 320Gbps,可以满足新一代的 I/O 接口,比如:千兆(GE)、万兆(10GE)的以太网技术、4G/8G 的 FC 技术 一.PCI 引脚 1.接口控制管脚(出问题时常测这些管脚)FRAME#:帧周期信号。Master 驱动,表示一次访问的开始和持续时间。FRAME#无效时,是传输的最后一个数据周期。IRDY#:Master 准备好信号。TRDY#:Slave 准备好信号。当这两者同时有效时,才能进行完整的数据传输,否则即为等待周期。在写周期,IRDY#信号有效时,表示有效的数据信号已在 AD0AD31 中建立;在读周期,IRDY#信号有
3、效时,表示 Master 已做好接收数据的准备。在写周期,TRDY#信号有效,表示 Slave 已做好了接收数据的准备。在读周期,TRDY#信号有效,表示有效数据已被送入 AD0AD31 中,STOP#:停止数据传送信号,由 Slave 发出。当它有效时,表示 Slave请求 Master 终止当前的数据传送。IDSEL:初始化设备选择信号。在读写配置空间时,用作 Slave 的片选信号(Slave 通常把 IDSEL 连到 AD31:0上的一根,PFA 中的 device id就是这么确定的)DEVSEL#:设备选择信号,由 Slave 驱动,该信号有效时,当前 Slave设备已被选中 二.
4、时序 读时序 写时序:三.PCI 配置空间 256字节的PCI配置空间分为64字节的头标区和192字节的设备相关区两部分。头标区的各个寄存器用来唯一地识别设备;设备相关区则保存一些与设备相关的数据。配置空间的头标区又分为两部分:前 16 个字节的定义在各种类型的 PCI 设备中都是一样的;剩余的字节随设备类型不同而有所不同。位于偏移地址 0EH处的头标类型字段规定了头标区的布局结构。目前,规范定义了三种头标类型。头标类型 设备 2 PCI-CardBus 桥 1 PCI-PCI 桥 0 除上述桥外的所有设备 因为 PCI 网卡的头标类型是 0,所以下面我们就来详细说说其布局结构,至于其他类型的
5、头标请读者自行阅读。图 3 就是头标类型 0 的头标区的布局。头标区中的寄存器根据功能可分成下面几组:1.设备的识别(1)供应商代码:该寄存器用于识别 PCI 设备的制造商,具体代码由PCI SIG()分配。0FFFFH 是无效的供应商代码。(2)设备代码。该寄存器用来标识某供应商生产的具体设备,代码由各供应商定义。供应商代码和设备代码,读者可以到网站查阅。图 3 头标类型 0 的头标区的布局 (3)版本号。该寄存器用来定义指定设备的版本信息。(4)头标类型。该字段的第 7 位为“1”标识该设备是多功能设备,为“0”标识为单功能设备;该字段的 06 位就是上文表中所述的头标类型。(5)设备分类
6、代码。用来标识设备的总体功能和特定的寄存器级编程接口。上面 5 个字段均为只读类型,所有的 PCI 设备都必须实现其功能。2.设备控制和设备状态(1)命令寄存器为一个设备发出和响应 PCI 总线命令提供粗略的控制。图 4 就是命令寄存器格式。图 4 命令寄存器格式 我们比较感兴趣的位有:a.位 0(I/O 空间控制):控制对 I/O 空间访问的响应。该位为 0 时,禁止设备响应对 I/O 空间的访问;该位为 1 时,允许设备响应 I/O空间的访问。缺省设置为 0。b.位 1(存储器空间控制):控制一个设备对存储器空间访问的响应。该位为0时,禁止响应;该位为 1 时,允许设备响应对存储器空间的访
7、问。缺省设置为 0。至于其他位的功能,读者若有兴趣可以自行查阅。(2)状态寄存器用来记录 PCI 总线有关的状态信息。3.基址寄存器 PCI 设备中,除了配置空间外,还有两个物理空间:内存空间和 I/O 空间。为了访问这两个地址空间,就必须使用基址寄存器。头标类型 0 中涉及 3 种基址寄存器:内存空间基址寄存器、I/O 空间基址寄存器和扩展 ROM 基址寄存器。关于基址寄存器,我们下一章重点讲述。4.其他寄存器 其他寄存器包括一些本文不涉及到的寄存器,如中断引脚、中断线等等。有兴趣的读者可以自行阅读。四.PCI 配置空间的访问 上面说过,PCI 规范使用从 0CF8H0CFFH 这 8 个
8、I/O 地址来访问所有设备的 PCI 配置空间。这 8 个字节实际上构成了两个 32 位寄存器:0CF8H 寄存器叫做“配置地址寄存器”;0CFCH 叫做“配置数据寄存器”。当要访问配置空间的寄存器时,先向地址寄存器写上目标地址,然后就可以从数据寄存器中读写数据了。我们说过,PCI 配置空间对应于一个 PCI 逻辑设备,所以要访问一个配置空间的某个寄存器,必须要指定:PCI 总线号、PCI 设备号、PCI 设备功能号和寄存器号。配置地址寄存器的格式如下:31 30 24 23 16 15 11 10 8 7 2 1 0 使能位 保留 总线号 设备号 功能号 寄存器号 0 0 第 0、1 位上的
9、“0”是用来要求你只能按双字(4 字节)来读写配置空间寄存器。第 31 位“使能位”用来决定是否允许访问配置空间:为“1”时表示可以访问;为“0”时表示不可以访问。例如,为了读总线号 0、设备号 17H、功能号 0 的 30H 寄存器,你可以使用下面的代码:MOV EAX,8000B830H MOV DX,0CF8H OUT DX,EAX MOV DX,0CFCH IN EAX,DA 五.PCI 配置空间的遍历 从上面的配置地址寄存器的格式我们可以看出:总线号从 0255、设备号从031、功能号从 07。根据配置空间的第 0 个寄存器是否返回 0FFFFH 值来判断是否存在该 PCI 设备。下
10、面是 PCI 配置空间遍历的流程图:图 5 遍历 PCI 配置空间流程图 六.基址寄存器 PCI 设备中,除了配置空间外,还有两个物理空间:内存空间和I/O 空间。为了访问这两个地址空间,就必须使用基址寄存器。头标类型 0 中涉及 3 种基址寄存器:内存空间基址寄存器、I/O 空间基址寄存器和扩展ROM 基址寄存器。PCI 设备可以在地址空间中浮动是 PCI 局部总线中最重要的功能之一。它能够简化设备的配置过程。在系统上电时,与设备无关的系统软件必须确定有哪些设备存在,同时建立一个统一的地址映射关系,并确定一个设备是否有扩展 ROM。1.地址映射 加电软件在引导操作系统之前必须建立一个统一的地
11、址映射。也就是说,必须确定在系统中有多少存储器以及系统中的 I/O 控制器要求多少地址空间。当这些信息确定之后,加电软件便可以把 I/O 控制器映射到合理的地址空间并引导系统。为了使这种映射能够做到与响应的设备无关,从而在配置空间的头标区中安排了一个供映射时使用的基址寄存器。在所有的基址寄存器中,位 0 均为只读位并且用来决定能够是存储器空间还是 I/O 空间。如果该位为 0,则表示映射到存储器空间;若为 1 则表示映射到 I/O 地址空间。2.存储器基地址寄存器 映射到存储器空间的基址寄存器可以是 32 位宽度,也可以是 64 位宽度(支持映射到一个 64 位地址空间时)(如图 6)。图 6
12、 32/64 存储器基地址寄存器格式 其中位 0 要用硬件方法使其恒为 0。而位 2 和位 1 两位用来表示映射类型,具体如下:位 2 和位 1 映射类型 00 基地址寄存器为 32 位宽,可以在 32 位表示的存储器地址范围的任何地方进行映射 01 保留 10 基地址寄存器为 64 位宽,可以映射到以 64 位表示的存储器空间的任何地方 11 保留 至于位 3,若数据是可预取的,就应将它置为 1,否则清 0。该寄存器的区域各位用来将一设备映射到存储器空间。基地址寄存器中用于 32 位存储器译码器的位【31:4】和用于 64 位存储器译码器的位【63:4】称为基地址单元。它的作用是:确定与译码
13、器相关的存储器的大小;给译码器分配地址。如果存储器设备需要小于 4K 的存储空间,规范建议存储器范围强行设为 4KB。3.I/O 基地址寄存器 映射到 I/O 空间的基址寄存器宽度总是 32 位(如图 7):图 7 I/O 基地址寄存器格式 其中位 0 值为 1(用硬件实现的),位 1 为保留位并且其读出值必须为0,其余各位用来把设备映射到I/O 空间。当基地址寄存器位 0 的返回值为 1 时,表示这是一个 I/O 译码器,而不是存储器译码器,位 1 保留并总是返回 0,【31:2】是基地址单元,并用于确定需要的 I/O 块容量,设置它的起始地址。规范要求映射它的控制寄存器组到I/O空间的 设
14、备不必请求每个I/O基地址寄存器超过 256 个单元。4.确定块容量和分配地址范围 要确定存储器的容量或 I/O 空间大小可以通过简单地向基地址寄存器写入全“1”并回读来确定。若返回一个是 0 值,则表示未实现基地址寄存器;如果读回地值为非 0,则编程人员通过从基地址单元的最低有效位向上扫描返回值以找到第一个被成功置“1”的位来确定所需存储器的容量或 I/0 空间的大小。假设寄存器的位 0 是一个加权二进制 1,那么位 1 的值就是 2,位 2 的值就是 4,依此类推。这样,在基地址单元中第一个发现的 1 所对应的加权二进制值便是所需的空间数。这也是寄存器的第一个可读/可写位,在它之上的所有位
15、钧定义为可读/可写位。这个信息发现后,程序将 32/64 位存储器起始地址或 32 位 I/O地址写入基地址寄存器中。5.扩展 ROM 基地址寄存器 有些 PCI 设备,尤其是那些准备用于 PC 结构扩展板上的设备,需要 EPROM作为扩展 ROM。为此,在配置空间偏移地址 30H 处开始定义了四个字节的寄存器,用来处理这个扩展 ROM 的基地址和大小。(如图 8)图 8 扩展 ROM 基地址寄存器格式 该寄存器和 32 位基地址寄存器相比,除了位的编码和用途不同之外,其它功能完全相似。它的高 21 位对应于扩展 ROM 基地址的高 21 位。一个设备实际实现的位数取决于该设备要求多大的地址空
16、间。例如,一个设备要求它的扩展 ROM映射到一 64KB 存储区域时,它就应该实现此寄存器的高 16 位,其它 5 位用硬件方法使它们恒为 0。凡是支持扩展 ROM 的设备必须实现这个寄存器。与设备无关的配置软件通过对扩展 ROM 基址寄存器的地址位上写入全“1”,然后再读回以确定设备要求多大的地址范围。所有的无关位上都返回 0,从而有效地指出了地址边界,也就知道了设备要求的这一块地址空间的大小。一个设备要求的地址空间范围不能超过 16MB。这个寄存器的位 0 用来控制相应的设备是否能够接受对其扩展 ROM 的访问。当该位为 0 时,禁止访问设备的扩展 ROM 地址空间;当该位为 1 时,允许
17、将本寄存器的其它位作为参数进行地址译码。命令寄存器中的存储器空间位优先于扩展 ROM 的使能位,但是,如果存储器空间位和扩展 ROM 的的使能位同时为 1 时,设备就必须响应对其扩展 ROM 的访问。扩展 ROM 的使能位在复位后应该为 0。七.PCI 拓扑结构 PCI 拓扑结构,有如下例子 在上图的总线结构中,ethernet 设备和 pci-pci bridge的资源空间必须要是 pci bus0 的一个子集 同理,SCSI 和 VIDEO 同类型资源必须要是 pci_bus1 的子集。CPU 访问 PCI 的过程是这样的(只有一个根总线和 pci-pci bridge过滤窗口功能打开的情
18、况):1.cpu 向 pci 发出一个 I/O 请求。首先经过根总线.它会判断是否在它的资源范围内.如果在它的范围,它就会丢向总线所在的每一个设备.包括 pci bridge.如果没有在根总线的资源范围,则不会处理这个请求.2.如果 pci 设备判断该地址属于它的资源范围,则处理后发出应答 3.pci bridge 接收到这个请求,它会判断 I/O 地址是否在它的资源范围内.如果在它的范围,它会把它丢到它的下层子线.4.下层总线经过经过相同的处理后,就会找到这个 PCI 设备了 一个 PCI 设备访问其它 PCI 设备或者其它外设的过程:1.首先这个 PCI 发出一个请求,这个请求会在总线上广
19、播 2.如果要请求的设备是在同级总线,就会产生应答 3.请求的设备不是在同层总线,就会进行 pci bridge.pci 桥判断该请求不在它的范围内(目的地不是它下层的设备),就会将它丢向上层.4.这样辗转之后,就能找到对应的设备了 八.PCI 枚举过程 通过 PCI 枚举,CPU 知道当前系统上有多少 PCI 设备,多少根 PCI 总线,PCI 配置空间初始化。PCI 总线扫描的原理是从总线 0 扫描到总线 255,对于每条总线,系统都会扫描所有(总线号,设备号,功能号),读出每个设备配置空间的Device ID 和 Vendor ID 寄存器,如果这两个寄存器的值是个无效值(0 xFFFF
20、),则说明当前位置上没有设备,接着扫描下一个位置。如果是有效值(非 0 xFFFF),当前位置是个有效的 PCI 设备/桥。进而再读取该设备的 Header Type 寄存器,如果该寄存器为 1,则表示当前设备是 PCI 桥,否则是 PCI 设备。Register Number:配置空间寄存器偏移量 Function Number:多功能设备有多个功能号 Device Number:设备编号 Bus Number:总线编号 对所有 PCI 总线进行编号 PCI 桥如何知道它所连接的 PCI 总线情况呢?这就需要对 PCI 桥进行总线编号。前面介绍过 PCI 桥提供了 Primary Bus N
21、umber、Secondary Bus Number 和 Subordinate Bus Number 三个寄存器用于标志该桥所连接的 PCI 总线,下面通过一个示例来说明内核对于 PCI 总线是如何进行编号的。1.系统运行初始,Bus A 为 0,通过上面的 PCI 总线扫描得到连接在 Bus A 上的 PCI 桥(即图中 Bridge 1)2.下面开始设置 Bridge 1 的 Bus 寄存器。将 Primary Bus Number 寄存器设置成 Bus A 的编号,即 0。将 Secondary Bus Number 寄存器设置成 Bus B 的编号,它的值等于(Bus A+1),也就
22、是 1。由于暂时无法知道该桥所能访问的所有下行总线数目,Subordinate Bus Number 寄存器暂时设置成 0 xFF。3.当扫描完所有 Bus A 上所有(设备号,功能号)后,开始扫描 Bus B,Bus B 的编号在扫描完 Bus A 后已经得到,为 1。Bus B 的扫描方法同步骤(1),先扫描出 Bus B 上的 PCI 桥(即图中的 Bridge 2),然后配置 Primary Bus Number 寄存器为 1,Secondary Bus Number 寄存器为 2,而 Subordinate Bus Number 寄存器依然为 0 xFF。4.Bus B 扫描完后得到
23、 Bus C 的编号,为 2。下面开始扫描 Bus C,因为 Bus C 上没有 PCI 桥,于是在扫描完其它(设备号,功能号)后,Bus C 的扫描结束。5.由于 Bridge 2 所能访问到的最大 Bus 编号是 2,因此重新设置 Bridge 2 的 Subordinate Bus Number 寄存器为 2。6.由于 Bridge 1 所能访问到的最大 Bus 编号也是 2,因此重新设置 Bridge 1 的 Subordinate Bus Number 寄存器为 2。7.总线编号结束。九.Linux 内核 PCI 数据结构 内核(linux-2.6.24)提供了三类数据结构用以描述
24、PCI 控制器、PCI 设备以及 PCI 总线。数据结构关系如下所示 PCI 控制器 用 pci_controller 结构来描述,它有以下几个主要的属性:index:该属性标志 PCI 控制器的编号。next:该属性指向下一个 PCI 控制器,通过 next 属性,PCI 控制器可以形成一个单向链表。first_busno:该属性标志了连接在该控制器上第一条总线的编号。last_busno:该属性标志了连接在该控制器上最后一条总线的编号。ops:该属性标志了当前 PCI 控制器所对应的 PCI 配制空间读写操作函数。io_space:该属性标志了当前 PCI 控制器所支持的 IO 地址空间。
25、mem_space:该属性标志了当前 PCI 控制器所支持的 Memory 地址区间。cfg_addr:该属性标志了当前 PCI 控制器发起 Configuration 访问方式时所需要写入的地址空间。cfg_data:该属性标志了当前 PCI 控制器发起 Configuration 访问方式时所需要读写的数据空间。bus:该属性标志了当前 PCI 控制器所连接的 PCI 总线,它对应的数据结构是 pci_bus。PCI 总线 用 pci_bus 结构来描述,它有以下几个主要的属性:parent:可通过该属性索引到上层 PCI 总线。self:该属性标志了连接的上行 PCI 桥(对应的数据结构
26、是 pci_dev)。children:该属性标志了总线连接的所有 PCI 子总线链表。devices:该属性标志了总线连接的所有 PCI 设备链表。ops:该属性标志了总线上所有 PCI 设备的配制空间读写操作函数。number:该属性标志了当前 PCI 总线的编号。primary:该属性标志了 PCI 上行总线编号。secondary:该属性标志了 PCI 下行总线编号。subordinate:该属性标志了能够访问到的最大总线编号。resource:该属性标志了 Memory/IO 地址空间。PCI 设备 用 pci_dev 结构来描述,它有以下几个主要的属性:global_list:Li
27、nux 定义了一个全局列表来索引所有PCI 设备,该属性标志了这个全局列表的首指针。bus:该属性标志了当前设备所在的 PCI 总线(对应的数据结构是 pci_bus)。devfn:该属性标志了设备编号和功能编号。vendor:该属性标志了供应商编号。device:该属性标志了设备编号。driver:该属性标志了设备对应的驱动代码(对应的数据结构是 pci_driver)。irq:该属性标志了中断号。resource:该属性标志了 Memory/IO 地址区间。当 Linux 内核在做 PCI 初始化工作时,它会根据建立一个由 pci_controller、pci_bus 和 pci_dev
28、三者组成的一个组织结构图。根据这个结构,软件开发者可以很方便的通过 PCI 控制器索引到每个 PCI 设备或者 PCI 总线。十.linux 的 PCI 子系统初始化流程 第一步:Linux 分配数据结构 pci_contoller,并初始化,包括 PCI 的 mem/io空间范围和访问 PCI 配置空间所需的 handler。第二步:PCI 设备的枚举:扫描系统上所有 PCI 设备,初始化它们的配置空间。(硬件上的初始化)第三步:用数据结构将 PCI 设备信息联系起来,构建 PCI 树。(软件上的初始化)第四步:加载 PCI 设备驱动。1 初始化 PCI 控制器 pci_controller
29、结构是内核描述 PCI 子系统信息的数据结构,里面定义了可供 PCI 设备使用的 mem 资源和 io 资源的范围,访问 pci 设备配置空间的 handler 等等。函数调用关系:1.start_kernel-mpc8560ads_setup_arch-mpc85xx_setup_hose()2.3.此函数分配并初始化了 pci_controller 4.mpc85xx_setup_hose()5.-pcibios_alloc_controller()/分配数据结构 pci_controller 6.7.8.ppc_md.pci_map_irq=mpc85xx_map_irq;/用来获得 p
30、ci 设备 irq 号的 handler 9.10.11.-setup_indirect_pci()/设置 pci_controller 里访问 PCI 配置空间的钩子函数 12.13.14./使用 ioremap 后的 CFG_ADDR 和 CFG_DATA 的虚拟地址 15.16.17.-mpc85xx_setup_pci1()/设置 PCI inbound 和 outbound 窗口寄存器。18.19.20.PCI 子系统的 mem 和 io 地址空间范围也在函数 mpc85xx_setup_hose()中定义:21.pci_controller*hose_a;22.hose_a-mem
31、_space.start=MPC85XX_PCI1_LOWER_MEM;23.hose_a-mem_space.end=MPC85XX_PCI1_UPPER_MEM;24.hose_a-io_space.start=MPC85XX_PCI1_LOWER_IO;25.hose_a-io_space.end=MPC85XX_PCI1_UPPER_IO;2 PCI 枚举过程 目前为止,内核只知道 PCI 子系统总的 mem 资源和 io 资源地址范围。接下来,内核需要扫描所有 PCI 设备,把这些资源分配给 PCI 设备,具体方法参考前面讲的 PCI 枚举过程。内核分配 mem 资源时是从高地址开始
32、分配的。1.mpc85xx_setup_hose()2.3.-pciauto_bus_scan()4.for(pci_devfn=0;pci_devfn pcibios_init()/所在文件 arch/ppc/kernel/pci.c 4.5.6.pcibios_init()7.(1):为 PCI 设备构造数据结构,组织成 PCI 树 8.9.-pci_scan_bus(hose-first_busno,hose-ops,hose)/hose 就是上面的 pci_controller 结构 10.11.12.13.-pci_scan_bus_parented 14.15.-pci_creat
33、e_bus/建立 PCI bus 0 对应的数据结构,这个 bus 的资源尚未初始化 16.17.18.-pci_scan_child_bus/从 PCI bus 0 开始扫描生成 PCI 树,使用了递归 19.20.21.22.-pci_scan_slot 23.24.-pci_scan_single_dev 25.-pci_scan_device()/创建 pci_dev 结构 26.27.28.-pci_setup_device()/区分桥与设备,分别进行初始化 29.30.31.-pci_read_bases();pci_dev-resouce中保存的才是 cpu internal a
34、ddress(EA),可以对这些地址进行用 ioremap,在驱动程序对 bar 所指位置读写的时候一定要用这 (2)给 PCI 设备分配 IRQ 号 1.-pci_fixup_irqs()2.3./遍历所有 pci 设备,调用 pdev_fixup_irq()4.5.6.-pdev_fixup_irq 7.-ppc_md.pci_swizzle()/实际调用 common_swizzle(),获得 pci 所在 slot编号 8.9.10.读 PCI 设备配置空间 PCI_INTERRUPT_PIN,获得中断 pin 编号1 到 4 11.12.之所以是 1 到 4,因为 PCI 规范里设备
35、最多 4 个管脚(除第一个外,其他 3 个仅用于多功能设备)13.-ppc_md.pci_map_irq()/实际调用 mpc85xx_map_irq()14.15.16./根据 slot,pin 和 pci_irq_table4 17.18.19./来计算出 irq 号 20.21.22.-pcibios_update_irq(pci_dev,irq)23./将 irq 号写入 pci 设备的配置空间 PCI_INTERRUPT_LINE 24.25.26./注意,这里寄存器只是用来保存结果,例如把其值 8 改为 9,并不能改变中断号 27.28.29.(3)PCI 结构树有了,现在构建 P
36、CI 的资源树,有冲突就修改 30.-pcibios_allocate_bus_resource()31./只考虑 pci_bus,形成 bus 级资源树(并同时 check,资源冲突了就修改)32.33.34.-pcibios_allocate_resources()35.4 加载 PCI 设备驱动 以 e1000 PCI 网卡 82546GB 为例,讲解一个 PCI 驱动的加载过程 驱动里有如下代码:1.static struct pci_driver e1000_driver=2.3.name=e1000_driver_name,4.id_table=e1000_pci_tbl,5.pr
37、obe=e1000_probe,6.remove=_devexit_p(e1000_remove),7.#ifdef CONFIG_PM 8./*Power Managment Hooks*/9.suspend=e1000_suspend,10.resume=e1000_resume,11.#endif 12.shutdown=e1000_shutdown,13.err_handler=&e1000_err_handler 14.;15.module_init(e1000_init_module);16.do_initcalls()17.-e1000_init_module 18.pci_re
38、gister_driver(&e1000_driver)19./e1000_driver.driver.bus=&pci_bus_type;20.21.22.-driver_register(e1000_driver.driver);23./pci_bus_type.probe()非空,即调用 pci_device_probe()24.25.26.pci_device_probe(*device)27.-_pci_device_probe(*pci_driver,*pci_dev)28.-pci_match_device(*pci_driver,*pci_dev)29.-pci_call_probe(*pci_driver,*pci_dev,pci_device_id)30.-drv-probe(*pci_device,*pci_device_id)31.即执行 e1000_probe(*pci_device,*pci_device_id)接下来就是 e1000 PCI 网卡驱动的具体代码。