基于Linux平台PCI设备驱动程序设计(2)

发表于:2007-07-04来源:作者:点击数: 标签:
第二章 PCI总线简介 2.1 Linux 对PCI总线的支持 PC机发展至今,出现了许多的总线标准:PCI、ISA、MCA、EISA、VLB、Sbus等都是当今PC市场上能找得到的总线标准。其中PCI和ISA是PC世界最常用的外设接口,但由于ISA在设计上已经相当陈旧了,现在有PCI将全面替

  第二章 PCI总线简介
  2.1 Linux对PCI总线的支持
  PC机发展至今,出现了许多的总线标准:PCI、ISA、MCA、EISA、VLB、Sbus等都是当今PC市场上能找得到的总线标准。其中PCI和ISA是PC世界最常用的外设接口,但由于ISA在设计上已经相当陈旧了,现在有PCI将全面替代ISA的趋势,因此,PCI总线已成为当今最常用的外设总线,也是Linux内核支持最好的总线。
  2.2 PCI总线概览
  PCI是一组完全的规范,它定义了计算机的不同部分是如何交互的。PCI规范覆盖了与计算机接口相关的绝大多数方面,本文主要讨论一个PCI驱动程序是如何找到它的硬件,并获得对它的访问的。
  PCI外设由一个总线号、一个设备号、和一个功能号确定。
  PCI设备有三种地址空间,分别是:内存空间、I/O共享空间和配置空间。前两个地址空间由PCI总线上的所有设备共享,而配置空间则是设备私有的。每个PCI插槽有一个配置事务的私用使能线,PCI控制器一次只能访问一个外设,不会有地址冲突。所有这些空间对于CPU来说都是可以访问的。在初始化阶段,外设的配置信息被Linux内核中的初始化程序从配置空间读出。这样,一旦配置寄存器被读出,不需通过探测,驱动程序就可以访问它的硬件了。
  2.3 PCI配置寄存器
  2.3.1 配置寄存器布局
  PCI配置寄存器的布局是标准化的,由256字节的地址空间组成,其中前64个字节是标准化的,其余的则与具体设备相关。
  下表显示了与设备无关配置空间的布局 。
  配置地址偏移 寄存器英文名 寄存器中文名
  00H—01H Vendor ID 制造商标识
  02H—03H Device ID 设备标识
  04H—05H Command 命令寄存器
  06H—07H Status 状态寄存器
  08H Revision ID 版本识别号寄存器
  09H—0bH Class Code 分类代码寄存器
  0cH Cache Line Size CACHE行长度寄存器
  0dH Latency Timer 主设备延迟时间寄存器
  0eH Header Type 头标类型寄存器
  0fH Bulit-in-teset Register 内含自测试寄存器
  10H—13H Base Address Register 0 基地址寄存器0
  14H—17H Base Address Register 1 基地址寄存器1
  18H—1bH Base Address Register 2 基地址寄存器2
  1cH—19H Base Address Register 3 基地址寄存器3
  20H—23H Base Address Register 4 基地址寄存器4
  24H—27H Base Address Register 5 基地址寄存器5
  28H—2bH Cardbus CIS Pointer 设备总线CIS指针寄存器
  2cH—2dH Subsystem Vendor ID 子设备制造商标识
  2eH—2fH Subsystem Device ID 子设备标识
  30H—33H Expasion ROM Base Address 扩展ROM基地址
  34H—3bH ——— 保留
  3cH Interrupt Line 中断线寄存器
  3dH Interrupt Pin 中断引脚寄存器
  3eH Min_Gnt 最小授权寄存器
  3fH Max_Lat 最大延迟寄存器
  讨论所有的配置项显然超出了本文的讨论范围,通常,与设备一起发布的技术资料会详细描述它支持的寄存器。我们只对那些有助于驱动程序找到设备的配置项感兴趣,它们是:VendorID、DeviceID和ClassCode。每个PCI外设都会把自己的值放入这些只读寄存器,驱动程序可以用它们来查找设备。
  下面的头文件,宏,以及函数都将被PCI驱动程序用来寻找它的硬件设备:
  #include
   驱动程序需要知道PCI函数在核心是否是可用的。通过包含这个头文件,驱动程序获得了对CONFIG_宏的访问,包括CONFIG_PCI。
  CONFIG_PCI
  如果核心支持对PCI BIOS的调用,那么这个宏被定义。并不是每台计算机都有PCI总线,所以核心的开发者应该把 PCI的支持做成编译时的可选项,从而在无PCI的计算机上运行Linux时节省内存。如果CONFIG_PCI没有定义,那么这个列表中其它的函数都不可用,驱动程序应使用预编译的条件语句将针对PCI的语句全都排除在外。
  #include ios32.h>
  这个头文件声明了以下介绍的函数。这个头文件还定义了函数返回的错误代码的符号值。
  int pcibios_present(void)
  由于与PCI相关的函数在无PCI总线的计算机上是毫无意义的,pcibios_present函数就是告诉驱动程序计算机是否支持PCI;如果支持,它返回一个为真布尔值。在调用下面介绍的函数之前最好先检查一下pcibios_present,以保证计算机支持PCI。
  #include
  这个头文件定义了下面函数使用的所有数值的符号名。并不是所有的设备ID都在这个文件中列出了,但这个文件内容一直在增加,因为不断有新设备的符号定义被加入。
  int pcibios_find_device(unsigned short vendor,
  unsigned short id,
  unsigned short index,
  unsigned char *bus,
  unsigned char *function);
  如果CONFIG_PCI被定义了,并且pcibios_present也是真,这个函数被用来从BIOS请求相关设备的信息。vendor / id对用来确定设备。index用来支持具有同样的vendor / id对的几个设备。对这个函数的调用返回设备在总线上的位置以及函数指针。返回代码为0表示成功,非0表示失败。
  int pcibios_find_class(unsigned int class_code,
  unsigned short index,
  unsigned char *bus,
  unsigned char *function);
  这个函数和上一个类似,但它寻找属于特定类的设备。返回代码为0表示成功,非0表示有错。
  char *pcibios_strerror(int error)
  这个函数用来将一个PCI错误代码翻译为字符串。
  2.3.2 访问配置寄存器
  当驱动程序检测到设备后,就可以对内存、I/O和配置空间进行读或写了。特别地,访问配置空间对于驱动程序来说极为重要,因为这是它发现设备被映射到内存和I/O空间某地方的唯一方法。
  驱动程序或Linux内核可以使用以下的软件接口,以8位、16位、32位的数据来访问配置空间。这些函数都是标准化的,相关原型在中:
  int pcibios_read_config_byte( unsigned char bus,
  unsigned char function,
  unsigned char where,
  unsigned char *ptr);
  int pcibios_read_config_word(unsigned char bus,
  unsigned char function,
  unsigned char where,
  unsigned char *ptr);
  int pcibios_read_config_dword(unsigned char bus,
  unsigned char function,
  unsigned char where,
  unsigned char *ptr);
  它们分别从由bus和function确定的设备的配置空间读取1,2,4个字节。参数where是从配置空间开始处的字节偏移, 从配置空间取出的值通过ptr返回。如果出错,这些函数的返回值是错误代码。
  int pcibios_write_config_byte( unsigned char bus,
  unsigned char function,
  unsigned char where,
  unsigned char val);
  int pcibios_ write_config_word(unsigned char bus,
  unsigned char function,
  unsigned char where,
  unsigned char val);
  int pcibios_ write_config_dword( unsigned char bus,
  unsigned char function,
  unsigned char where,
  unsigned char val);
  它们分别向配置空间里写1,2,4个字节。设备仍由bus和function确定,要写的值由val传递。
  
  

原文转自:http://www.ltesting.net