Linux环境下无配置信息PCI设备的驱动开发

来源:互联网 发布:编程先学英语吗 编辑:程序博客网 时间:2024/05/21 21:44

http://www.jdzj.com/datum/showart.asp?art_id=6137

 [ 来源:机电论文 | 类别:技术 | 时间:2009-3-16 10:52:26 ] [字体:大 中 小]

  Linux是非常优秀的开源操作系统,有着十分广泛的应用。基于该操作系统设备驱动程序的需求越来越多。PCI作为一种广泛采用的总线标准,在嵌入式系统中正被大量使用,而Linux的内核也能很好地支持PCI设备。为此,本文介绍了Linux下无配置信息PCI设备驱动程序的设计开发方法。

  1 PCI总线及无配置信息PCI设备

  1.1 PCI总线

  PCI是外围设备互连(Peripheral ComponentInterconnect)的简称,是一种通用的总线接口标准,原先是应用于计算机系统的。PCI提供了一组完整的总线接口规范,其目的是描述如何将计算机系统中的外围设备以一种结构化和可控化的方式连接在一起。该规范同时详细定义了计算机系统中各个不同部件之间应该如何正确地进行交互。在一般的计算机系统中,总线子系统与存储子系统被PCI总线分开,CPU通过一块称为PCI桥的设备来完成同总线子系统的交互,图1所示是一个PCI子系统的体系结构。


 

  尽管目前PCI设备大多采用32位数据总线,但PCI规范中已经给出了64位的扩展实现方案,从而使PCI总线能够更好地实现平台无关性。虽然PCI总线是由Intel公司提出的,但它不局限于Intel系列的处理器。当今流行的其它处理器系列如Alpha、PowerPC、APARC,以及多处理器结构的下一代处理器都可以使用PCI总线。具体而言,PCI总线包含的特点可简要描述为高性能、线性突发传输、极小的存取延误、采用总线主控和同步操作、独立于处理器、兼容性强、预留了发展空间、低成本、高效益、软件透明等等。

  1.2 PCI设备的配置空间

  标准的PCI设备上有三种地址空间:I/O空间、存储空间及配置空间。CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,主要用来实现PCI设备和Linux内核中设备驱动程序之间的通讯。而配置空间则装载着PCI设备的配置信息,主要由Linux内核中的PCI初始化代码使用。PCI设备的配置信息空间如图2所示。

 

  标准PCI设备配置信息空间的大小为256个字节,其中低64个字节称为头标区,这部分区域的格式是固定的。内容包括PCI设备号、厂商识别号、命令寄存器、状态寄存器、基址寄存器等重要信息;其余的192个字节称为设备有关区,不同的设备可以对这部分寄存器进行不同的定义。

  1.3 无配置信息的PCI设备

  目前的嵌入式系统往往会要求CPU和专用数据运算器之间以很高的速率通信。由于现行的总线规范中,PCI的高性能是最为突出的,因此PCI总线的连接方式被大量采用。数据运算器往往是针对某一系统设计的,通常会采用FPGA设计。即在FPGA中添加进PCI的接口设计,也就是把FPGA设计成为一块PCI设备。但是由于嵌入式系统的局限性,在某些FPGA的PCI接口设计中不能划分配置信息空间(I/O空间和存储空间是设备与CPU信息交互的基础,是必须存在的),因此这个设计也就是一块无配置信息的PCI设备。

  2 Linux设备驱动程序

  Linux的设备驱动程序大致可以分为驱动程序的注册与注销、设备的打开与释放、设备的读写操作、设备的控制操作、设备的中断和轮询处理几个部分。

  2.1 设备的注册与注销

  向系统增加一个驱动程序就要赋予它一个主设备号,这一赋值过程应该在驱动程序的初始化中完成,它通过调用函数register_chrdev()或reg-iste_blkdev ()向内核注册。接下来就是给程序一个设备驱动程序名,这个名字必须插入到/dev目录中,并与驱动程序的主设备号和次设备号相连。获得主设备号的方法是选择一个当前不用的设备号,或者在调用register_chrdev时让参数ma-jor为0,这样,其返回值便是设备的主设备号。另外,在关闭字符设备或块设备时,还需要通过unregisler_chrdev()或unregister_blkdev()从内核中注销设备,并释放主设备号。

  2.2 设备的打开与释放

  打开设备可由open()完成。在大部分驱动程序中,open主要用于检查设备相关错误(如设备尚未准备好等)、识别次设备号(如有必要更新当前read/write位置f_ops指针),以及分配和填写要放在file->private_data里的数据结构。

  释放设备由release()完成,release的作用与open相反,主要是释放file->private_data中open分配的内存,并在最后一次关闭操作时关闭设备。

  2.3 设备的读写操作

  字符设备使用各自的read()和write ()来对设备进行数据读写。块设备则使用通用block_read()和block_write()来对设备进行数据读写。这两个通用函数可以向请求表中增加读写请求,这样,内核就可以优化请求顺序。由于是对内存缓冲区而不是对设备进行操作,因而能加快读写请求。如果内存缓冲区内没有要读入的数据或者需要将写请求写入设备,那么就需要真正地执行数据传输。

  2.4 设备的控制操作和中断处理

  除了读写操作外,有时还需要控制设备。这在操作时可以通过设备驱动程序中的ioctl()来完成。另外,对于不支持中断的设备,读写时需要轮流查询设备状态,以决定是否继续进行数据传输。如果设备支持中断,则可按中断方式进行。

  3 无配置信息PCI设备驱动程序的设计

  无配置信息PCI设备驱动程序设计的关键在于初始化,其余部分与标准PCI设备驱动差别不大。其初始化的方法有两种:一是选用外接的EEPROM来存储该设备的配置信息;二是直接在驱动程序的探测模块里注册设备。

  用外接EEPROM配置方式时,内核启动后会检测EEPROM,然后读出其中的配置信息,并将设备的信息注册到pci dev里。

  在实际的系统应用中,如果无法外接EEP-ROM,就必须直接在驱动程序的探测模块里注册设备。在这种方式下,若系统中没有其它的即插即用PCI设备,则可能会导致检测设备失败,但事实上已经注册了该PCI设备,因此完全可以正常运行。

  笔者开发的嵌入式TDMA卫星通信系统中的CPU采用MPC8250芯片,基带信号处理模块采用Xilinx公司的X3SC4000(FG676)。MPC8250是Mo-torola公司开发的一款PowerPC系列嵌入式处理器,该处理器中有32位超标量体系结构Power-PC603e处理器内核,并集成有PCI桥、PCI仲裁器、存储器控制器等部件。FPGA的设计中则包括PCI接口、sdram控制器及编码调制运算模块。

  此操作系统采用Linux,内核版本为2.6。由于Linux能很好地支持PCI总线,本设计在CPU和FPGA之间采用了PCI总线连接方式。由于FPGA的设计要求,PCI总线的中断信号未被使用,而是另行设定了两条中断信号线通往MPC8250的通用设计口。该系统支持FPGA中bin文件的实时更新,因此没有采用配置EPROM来配置FPGA,而是把要下载到FPGA里的bin文件同Uboot、Linux内核及jffs2文件系统一起放在了FLASH里,然后通过MPC8250提供的SPI总线下载到FPGA中。实际上,如需要更新FPGA的.bin文件,则可通过以太网口将文件拷入FLASH中再下载。

  在系统上电启动后,由于Linux内核先于jffs2解压,而FPGA的文件又必须在jffs2解压完后才能释放到内核空间,然后再借助SPI总线下载到FP-GA中,因此无法在FPGA中创建PCI设备配置信息空间,所以,本设计采用在检测PCI设备时直接注册的方法。

  3.1 驱动程序的总体框架

  下面是笔者驱动的整体框架,从中可以很明显地看出几个模块是如何联系起来的:

 
 

  3.2 具体模块的实现

  由于本系统没有采用标准PCI总线提供的中断信号,因此驱动程序中无中断处理模块,下面着重介绍对本设计比较重要的初始化设备过程以及打开设备模块、读写模块的设计方法。

  (1) 初始化设备过程

  初始化设备过程也是本系统PCI设备驱动中最为关键的部分。由于本系统中允许PCI总线挂接其它的即插即用设备,因此,这部分程序还需要保留。其部分代码及注释如下:

 

  在2.4之前的内核版本中,需要手动调用pci_find_device()函数来查找PCI设备,但在2.4版本后,则可以调用probe探测函数来完成对硬件的检测及信息获取工作。其部分代码如下:

 

  在获取的PCI信息子函数pci_rewin_pci_re-sources_claim()和注册设备子函数pci_rewin_de-vice_register()里,笔者自己创建的PCI设备信息可以写人到pci_dev,然后由Liunx内核通过pci_register_drivet ()将此PCI设备信息创建在PCI设备列表中。

  (2) 打开设备模块

  打开设备模块主要用来检查设备号、开辟PCI总线映射空间。打开设备模块的部分代码及注释如下:

 

  (3) 读写模块

  读操作就是先通过memcpy_fromio函数将PCI上传来的数据搬移到内核空间中的接收缓冲区,再用copy_to_user搬移到用户数据空间。接收缓冲区和接收数据散列表都要在初始化模块中进行处理。读操作的部分代码及注释如下:

 

  写操作与读操作正好相反,它先通过copy_from_user函数将用户空间的数据搬移到内核空间中的发送缓冲区,再通过memcpy函数搬移到PCI总线上。由于发送的数据长度是可变的,所以每次发送都需要构造不同的发送散列表(发送缓冲区可以再初始化时分配)。写操作的代码与读操作类似,故此省略。

  值得注意的是,在PCI设备用I/O方式读写的时候,CPU将被迫停止工作以等待PCI设备完成此操作,且每次只允许一个设备访问。这个策略不利于提升系统性能。但利用MPC8250芯片提供的DMA(直接内存访问)机制则可大大提高PCI总线的性能,这也是笔者下一步需要改进的地方。

  4 结束语

  本文讨论了Linux2.6版本下开发设备驱动程序的原理和相关知识。着重介绍了无配置信息PCI设备驱动程序的开发方法。该驱动开发方法可成功应用于嵌入式TDMA卫星通信系统。测试证明:本系统可稳定有效工作。今后的工作将着重是提升系统性能并进行改进。


   作者:西安电子科技大学ISN国家重点实验室 陈宁 虢莉敏
 

 

 来源:[http://www.jdzj.com]机电之家·机电行业电子商务平台!

原创粉丝点击