PCI总线驱动概要

本文主要介绍了Linux内核2.6.23版本中PCI总线驱动的三层架构,包括总线驱动、协议层和设备驱动。在Linux内核中,PCI协议层已实现,开发者主要关注总线驱动和设备驱动。PCI设备驱动程序员利用内核提供的接口进行设备的注册、配置等,而总线驱动则更为复杂,涉及CPU体系结构和具体的硬件交互。PCI总线驱动的初始化过程包括探测硬件、分配资源和添加设备。在ARM架构下,PCI总线驱动的初始化通常由pci_common_init()函数完成,该函数需要一系列与硬件手册密切相关的回调函数来完成PCI设备的配置空间访问、中断映射等操作。
摘要由CSDN通过智能技术生成

《Linux内核修炼之道》里,文章作者对如何使用Kconfig和Makefile定位内核源码有精彩的阐述。并且该作者还在《Linux那些事儿 之 我是PCI》系列文章中对X86架构下的PCI总线和设备驱动做了很详细的分析。由于工作需要,我在此基础上分析了ARM体系结构的PCI总线驱动,并把心得和笔记整理一下,或许对日后解析其他子系统有所帮助。以下涉及到的Linux内核源码均为2.6.23版本。

 

PCI是一种总线标准。一般已经形成xxx标准的东西,尤其是总线这样可以被叫做“子系统”的东西,在Linux内核里基本上都已经得到了很好的支持。内核一般把PCI总线这类子系统的驱动分成三层:总线驱动、协议、设备驱动。其中Linux内核早已把协议层实现完毕,最大程度地精简了总线驱动和设备驱动这两层与硬件密切相关的工作。

 

PCI设备驱动相关知识在《Linux设备驱动程序 第三版》中已经有了详细介绍。在这一层里工作的程序员不必知道PCI总线驱动的实现细节,他们只需要利用内核提供的PCI设备驱动相关接口,就可以成功地注册、配置、控制和卸载任何PCI设备,无论那个设备究竟是一个大容量存储器、一个USB HUB、还是一个视频采集卡。正因为有了那些内核接口,设备驱动层的程序员们才能把大量的精力用在实现具体设备的功能的完善和性能的优化上。假如此时你正在为你的笔记本电脑编写一个PCI设备的驱动(现在的笔记本都有PCIE热插拔的插槽,所以有这样的设备是很可能的~),那么你就正在PCI设备驱动层上工作着。

 

当然,对于设备驱动层的程序员来说,一切的前提是这块开发板上的PCI总线驱动已经有人写好了,因为如果没有底层总线驱动的支持,协议层和设备驱动层写得再精彩也只是空中楼阁。可是如果开发板上并没有PCI总线驱动怎么办?要想在一个裸体开发板上使用某个PCI设备,很明显,写驱动的程序员就必须先把PCI的总线驱动给写了,然后再写设备的驱动。

 

相比设备驱动,总线驱动显得更加神秘和高深莫测,因为它总是跟CPU体系结构、跟具体的芯片或芯片组密切相关,它的工作非常抽象,而不像设备驱动那么具体和显而易见。不论如何,PCI总线也是一种硬件设备,处理器访问和控制任何设备的方式,无非就是探测某些管脚的电平的高低,以及把某些管脚的电平拉高或拉低(先不管这个过程中间可能经历的千山万水)。再抽象一点,其实就是CPU向设备上的某个寄存器读和写,也就是访问传说中的“I/O端口和I/O内存”(有关I/O端口和I/O内存的知识,参考《Linux设备驱动程序》“第九章 与硬件通信”)。芯片手册上通常会用很多篇幅来介绍如何访问寄存器,以及寄存器与设备功能之间的关系。

注:中断也是设备控制的重要方式,但并非所有设备都需要中断。

 

不过就算知道了有关硬件I/O的知识,如果不知道PCI驱动的架构,不知道Linux内核应该在何时何地与芯片手册上介绍的寄存器发生关系,也不可能写出PCI总线的驱动来。既然Linux内核已经把PCI子系统的架子搭了起来,并且还派了一些内核接口来跑龙套,那我们写总线驱动的程序员作为主角总要知道自己应该唱哪一出戏。

 

话说Linux内核里有一帮子专业龙套。最著名的要算module_init()宏,它甚至作为半个主角出现在Helloworld模块那为数不多的几行代码里。不过它也只是__define_initcall()的若干标准Pose之一。这个叫做__define_initcall()的宏,套上不同的行头摆出不同的Pose,几乎出现在Linux内核的每个模块里。周杰伦看完内核代码也不禁感叹“你出现在我诗的每一页”。有关__define_initcall()的定义,都在linux/init.h文件中。

 

 

__define_initcall()宏的作用,其实是告诉编译器在编译的时候,把它所修饰的函数按照已经定义好的顺序放入程序段中。而内核在初始化的过程中,会调用到init/main.c中的一个名为do_initcalls()的函数,在那里,所有的被__define_initcall()修饰的函数会严格地按照标准顺序执行一遍。你懂的,这就是传说中的模块入口。其实模块本没有入口,但是内核的模块多了,就有了模块的入口;写模块时重启系统的次数多了,就有了模块的动态加载。

 

终于要说到PCI子系统框架的入口了。说起PCI框架入口,不得不佩服Linux内核的模块化布局。有关PCI子系统的源码,实际上只会出现在两个地方,一个是dr

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值