• 一个简短的引论

    • 它给这一章总线架构的高级概述
    • 集中访问讨论Peripheral Component Interconnect(PCI,外围组件互连)外设内核函数
    • PCI公交车是最好的支持的内核总线
    • 本章主要介绍PCI驱动程序假设寻找其硬件和获得对它的訪问
    • 本章也会介绍ISA总线
  • PCI接口
    • PCI是一组完整的规范,定义了计算机的各个不同部分之间应该怎样交互
    • PCI规范涵盖了与计算机接口相关的大部分问题
    • PCI架构被设计为ISA标准的替代品,有三个主要目标
      • 获得在计算机和外设之间数据传输时更好的性能

        • 通过使用比ISA更高的时钟频率。PCI总线获得了更好的性能。它的时钟频率通常是25或者33MHz(实际的频率是系统时钟的系数)。最新的实现达到了66MHz甚至133MHz
        • 配备了32位的数据总线,并且规范已经包含了64位的扩展
      • 尽可能的平台无关性
      • 简化往系统中加入和删除外设的工作
    • PCI设备是无跳线设备,能够引导阶段自己主动配置
    • PCI寻址

      • 每一个PCI外设由一个总线编号、一个设备编号及一个功能编号来标识
      • PCI规范同意单个系统拥有高达256个总线,可是256个总线对于很多大型系统而言是不够的,因此,Linux眼下支持PCI域
      • 每一个PCI域能够拥有最多256个总线
      • 每一个总线上可支持32个设备,每一个设备能够是多功能板,最多可有八种功能
      • 每种功能都能够在硬件级由一个16位的地址来标识
      • 为Linux编写的设备驱动程序能够使用一种特殊的数据结构(pci_dev)来訪问设备
      • 当前的工作站一般配置有至少两个PCI总线。在单个系统中插入多个总线。可通过桥(bridge)来完毕,它是用来连接两个总线的特殊PCI外设
      • PCI系统的总体布局组织为树型,当中每一个总线连接到上一线总线,直到树根的0号总线
      • lspci
      • proc/pci
      • /proc/bus/pci/
        • 查看PCI设备清单和设备的配置寄存器
      • /sys/bus/pci/devices
      • 每一个外设板的硬件电路对例如以下三种地址空间的查询进行应答
        • 内存位置
        • I/Oport
        • 配置寄存器
      • 前两种地址空间由同一PCI总线上的全部设备共享
      • 配置空间利用了地理寻址
      • 配置查询每次仅仅对一个槽寻址
      • 每一个PCI槽有四个中断引脚,每一个设备功能可使用当中的一个
      • PCI总线中的I/O空间使用32位地址总线。而内存空间可通过32位或64位地址来訪问
    • 引导阶段
      • 当PCI设备上电时,硬件保持未激活状态

        • 不会有内存和I/Oport映射到计算机的地址空间
        • 禁止中断报告
      • 每一个PCI主板均配备有可以处理PCI的固件,称为BIOS、NVRAM或PROM。固件通过读写PCI控制器中的寄存器,提供了对设备配置地址空间的訪问
      • 系统引导时,固件在每一个PCI外设上运行配置事务。以便为它提供的每一个地址区域分配一个安全的位置
    • 配置寄存器和初始化
      • 全部的PCI设备都有至少256字节的地址空间

        • 前64字节是标准化的。而其余的是设备相关的
      • PCI寄存器始终是小端的
      • 驱动程序编写者在訪问多字节的配置寄存器时。要十分注意字节序,由于可以在PC上工作队的代码到其它平台上可能就无法工作
      • vendorID、deviceID和class是经常使用的三个寄存器
        • vendorID

          • 16位寄存器,用于标识硬件制造商
          • PCI Special Interest Group维护有一个全球的厂商编号注冊表,制造商必须申请一个唯一编号并赋于它们的寄存器
        • deviceID
          • 16位寄存器,由制造商选择。该ID通常和厂商ID配对生成生成一个唯一的32位硬件设备标识符
        • class
          • 每一个外部设备属于某个类
          • 16位寄存器,高8位标识了“基类(base class)”或者组
        • subsystem vendorID、subsystem deviceID
          • 这两个字段可用来进一步识别设备
      • struct pci_device_id用于定义驱动程序支持的不同类型的PCI设备列表
        • __u32 vendor;
        • __u32 device;
          • 以上两字段指定了设备的PCI厂商和设备ID,假设驱动程序能够处理不论什么厂商或者设备ID,这些字段应该使用值PCI_ANY_ID
        • __u32 subvendor;
        • __u32 subdevice;
          • 以上两字段指定设备的PCI子系统厂商和子系统设备ID,假设驱动程序能够处理不论什么类型的子系统ID,这些字段应该使用值PCI_ANY_ID
        • __u32 class;
        • __u32 class_mask;
          • 这两个值使驱动程序能够指定它支持一种PCI类(class)设备,假设驱动程序能够处理不论什么类型的子系统ID。这些字段应该使用值PCI_ANY_ID
        • kernel_ulong_t driver_data
          • 用来保存PCI驱动程序用于区分不同设备的信息
      • 初始化
        • PCI_DEVICE(vendor, device)
        • PCI_DEVICE_CLASS(device_class, device_class_mask)
    • MODULE_DEVICE_TABLE
      • MODULE_DEVICE_TABLE(pci, i810_ids);

        • 创建一个名为__mod_pci_device_table的局部变量,指向struct pci_device_id数组
        • 在内核构建过程中。depmod程序在全部的模块中搜索符号__mod_pci_device_table
        • 假设找到了该符号,它把数据从该模块中抽出,加入到文件/lib/modules/KERNEL_VERSION/modules.pcimap中
        • 当内核告知热插拔系统一个新的PCI设备已经被发现时,热插拔系统使用modules.pcimap文件来寻找要装载的恰当的驱动程序
    • 注冊PCI驱动程序
      • 所以的PCI驱动程序都必须创建的主要结构休是struct pci_driver

        • const char *name;

          • 驱动程序的名字
          • 当驱动程序执行在内核中时,它会出如今sysfs的/sys/bus/pci/drivers/以下
        • const struct pci_device_id *id_table
        • int (*probe) (struct pci_dev *dev, const struct pci_device_id *id);
          • 指向PCI驱动程序中的探測函数的指针同。当PCI核心有一个它觉得驱动程序须要控制的struct pci_dev时,就会调用该函数
        • void (*remove) (struct pci_dev *dev);
          • 指向一个移除函数的指针,当struct pci_dev被从系统中移除。或者PCI驱动程序正在从内核中卸载时。PCI核心调用该函数
        • void (*suspend) (struct pci_dev *dev, u32 state);
          • 指向一个恢复函数的指针,当struct pci_dev被恢复时PCI核心调用该函数
      • int pci_register_driver(struct pci_driver *drv);
        • 注冊成功返回0。否则,返回一个负的错误编号
      • void pci_unregister_driver(struct pci_driver *drv);
      • 在支持PCI热插拔的系统或者CardBus系统上,PCI设备能够在不论什么时刻出现或者消失
      • 2.6内核同意在驱动程序被装载之后动态地分配新的PCI ID给它
    • 老式PCI探測
      • struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from);
      • struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from);
      • struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
    • 激活PCI设备
      • int pci_enable_device(struct pci_dev *dev);
    • 訪问配置空间
      • 在驱动程序检測到设备之后,通常须要读取或写入三个地址空间

        • 内存
        • port
        • 配置
      • <linux/pci.h>
        • int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
        • int pci_read_config_word(struct pci_dev *dev, int where, u16 *val);
        • int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val);
        • int pci_write_config_byte(struct pci_dev *dev, int where, u8 *val);
        • int pci_write_config_word(struct pci_dev *dev, int where, u16 *val);
        • int pci_write_config_dword(struct pci_dev *dev, int where, u32 *val);
        • int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
        • int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
        • int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
        • int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
        • int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
        • int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
    • 訪问I/O和内存空间
      • 一个PCI设备可实现多达6个I/O地址区域
      • 一个接口板通过配置寄存器报告其区域的大小和当前位置,它们的符号名称为PCI_BASE_ADDRESS_0到PCI_BASE_ADDRESS_5
      • 在内核中,PCI设备的I/O区域已经被集成到通用资源管理,我们无需訪问配置变量来了解设备被映射到内存或I/O空间的何处
      • unsigned long pci_resource_start(struct pci_dev *dev, int bar);
      • unsigned long pci_resource_end(struct pci_dev *dev, int bar);
      • unsinged long pci_resource_flags(struct pci_dev *dev, int bar);
      • <linux/ioport.h>
        • IORESOURCE_IO
        • IORESOURCE_MEM
        • IORESOURCE_PREFETCH
        • IORESOURCE_READONLY
      • 中断号保存在配置寄存器60(PCI_INTERRUPT_LINE)中。该寄存器为一个字节宽
      • 假设设备不支持中断,寄存器61(PCI_INTERRUPT_PIN)是0
    • 硬件抽象
      • 在PCI管理中。唯一依赖于硬件的操作是读取和写入配置寄存器
      • 用于配置寄存器訪问的相关结构仅包括2个字段
        • struct pci_ops

          • int (*read) (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val);
          • int (*write) (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
      • 该结构在<linux/pci.h>中定义,并由drivers/pci/pci.c使用。后者定义了实际的公共函数
  • ISA回想
    • ISA总线在设计上相当陈旧并且其差劲的性能臭名昭著
    • 当要支持老主板而速度又不是很重要时,ISA比起PCI要占些优势
    • 假设你是一位电子爱好者,你能够很easy地设计开发自己的ISA设备
    • ISA的最大不足在于它被紧紧绑定在PC架构上
    • ISA设计的另外一个大问题是缺少地理寻址
    • 硬件资源
      • 一个ISA设备可配备有I/Oport、内存区域以及中断线
    • 即插即用规范
      • 某些新的ISA设备板遵循特殊的设计原则。须要一个特殊的初始化序列,以便简化附加接口板的安装和配置,这些接口板的设计规范称为PnP(Plug and Play,即插即用)。
      • PnP的目标是获得类似PCI设备那样的灵活性,而无需改动底层的电气接口(即ISA总线)。为此,该规范定义了一组设备无关的配置寄存器。以及地址寻址接口板的方法。

  • PC/104和PC/104+
    • 这两个标准都规定了印刷电路板的外形,以及板间互连的电气/机械规范,这些总线的实际优点在于,它们能够使用在设备一面的插头-插座类型的连接器把多个电路板垂直堆叠起来
    • 这两个总线的电子和逻辑布局和ISA(PC/104)及PCI(PC/104+)一样
  • 其它的PC总线
    • MCA

      • MCA(Micro Channel Architecture,微通道结构)是在PS/2计算机和某些笔记本电脑使用的IBM标准
      • 支持多主DMA、32位地址和数据线、共享中断线和用来訪问板载配置寄存器的地理寻址等
    • EISA
      • 扩展ISA(EISA)总线是对ISA总线的32扩展,同一时候具有兼容的接口连接器
      • 为无跳线设备而设计
      • 32位地址和数据线、多主DMA和共享中断线
    • VLB
      • VLB(VESA Local Bus,VESA局部总线)接口总线,它通过加入第三个纵向插槽对ISA连接器进行了扩展
  • SBus
    • 存在非常长一段时间了,具有相当高级的设计
    • 虽然仅仅有SPARC计算机使用该总线,但它的初衷却是处理器无关的。并针对I/O外设板进行了优化
  • NuBus
    • 能够在老式的Mac计算机(使用M68k系列CPU)中找到它
    • 全部的总线都是内存映射的。并且设备仅仅能被地理寻址
  • 外部总线
    • 外部总线包含:USB、FireWire和IEEE1284
    • 这些总线既不是功能完整的接口总线(比方PCI),也是哑的通信通道(比方串口)
    • 通常可划分为两个级别
      • 硬件控制器的驱动程序
      • 针对特定“客户”设备的司机

版权声明:本文博主原创文章,博客,未经同意不得转载。

《Linux Device Drivers》第十二章 PCI司机——note的更多相关文章

  1. 《Linux Device Drivers》 第十七章 网络驱动程序——note

    基本介绍 第三类是标准的网络接口Linux设备,本章介绍的内核,其余的交互网络接口描述 网络接口,必须使用特定的内核数据结构本身注册,与外部分组交换数据线打电话时准备 经常使用的文件上的网络接口操作是 ...

  2. 《Linux Device Drivers》第十一章 核心数据类型——note

    基本介绍 因为Linux多平台特性,不管是哪一个重要驱动力应该是便携 与内核代码相关的核心问题应该是访问的同时是数据项的已知长度.能力和利用不同的处理器 内核使用的数据类型主要分为三类 类似int这种 ...

  3. 鸟哥的linux私房菜——第十二章学习(Shell Scripts)

    第十二章  Shell Scripts 1.0).什么是shell scripts? script 是"脚本.剧本"的意思.整句话是说, shell script 是针对 shel ...

  4. 鸟哥的Linux私房菜——第十二章:档案的压缩与打包

    视频链接: 土豆:http://www.tudou.com/programs/view/GncwT0FJKsQ B站(推荐):http://www.bilibili.com/video/av98857 ...

  5. linux高级管理第十二章--rsync

    实验部分 1.安装rsync 2.配置文件 3.配置密码 4.后续 5.为了测试,创建几个文件 配置实时同步 1.调整inotify内核参数 安装inotify-tools 测试同步 编写脚本 验证 ...

  6. Linux学习笔记(第十二章)

    grep进阶 grep:以整行为单位进行截取 截取的特殊符号 正规表示法特殊字符 注意: sed用法 格式化打印 awk 用法 diff档案对比: path旧文档升级为新文档

  7. 《Linux命令行与shell脚本编程大全》 第二十二章 学习笔记

    第二十二章:使用其他shell 什么是dash shell Debian的dash shell是ash shell的直系后代,ash shell是Unix系统上原来地Bourne shell的简化版本 ...

  8. Gradle 1.12 翻译——第十二章 使用Gradle 图形用户界面

    有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...

  9. 《OpenCL异构并行编程实战》补充笔记散点,第五至十二章

    ▶ 第五章,OpenCL 的并发与执行模型 ● 内存对象与上下文相关而不是与设备相关.设备在不同设备之间的移动如下,如果 kernel 在第二个设备上运行,那么在第一个设备上产生的任何数据结果在第二个 ...

随机推荐

  1. errno.h 错误码描述.

    描述:一般说的Linux源码的目录,默认是基于 /usr/include/ 的. 使用 char *strerror(int errnum); 函数打印错误代码的描述.我简单对比了一下,发现描述大体一 ...

  2. mssql定时执行作业。

    ---2000 企业管理器 --管理 --SQL Server代理 --右键作业 --新建作业 --"常规"项中输入作业名称 --"步骤"项 --新建 --&q ...

  3. 《Linux内核分析》 week2作业-时间片轮转

    一.基于时间片轮转调度代码的解读 代码结构主要由三个文件组成: 1.mypcb.h 2.myinterrupt.c 3.mymain.c 1.进程控制块(mypcb.h) /* CPU-specifi ...

  4. jq仿虾米网flash效果

    这是很久以前写的一个效果了,之前虾米音乐网首页的一个flash效果,最初觉得这flash效果也可以完全用jq来写,于是空余时间就写了下当作练习吧,现在就拿出来跟大家分享下其中的实现原理! 先上最终效果 ...

  5. 模拟键盘输入首先要用到一个API函数:keybd_event

    转自:http://www.cnblogs.com/cpcpc/archive/2011/02/22/2123055.html 模拟键盘输入首先要用到一个API函数:keybd_event. 模拟按键 ...

  6. HTML5 初始文档声明

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  7. ionic框架,快速开发webAPP神器。

    官网地址 http://www.ionicframework.com/ 这个国外框架已经很火了.会使用插件的话更好,例如支付宝支付插件,调用摄像头拍照,二维码扫描,通讯录,文件上传,推送信息等等. 最 ...

  8. Centos下删除文件名乱码文件

    centos下通过rm命令来删除文件,但是如果要删除文件名乱码的文件,就不能直接使用rm命令了,因为压根就无法输出文件名来.不过借助find命令可以实现对其删除.在linux下对于每个文件都一个对应的 ...

  9. Python一路走来 - python基础 数据类型

    对于Python,一切事物都是对象,对象基于类创建 Python数据类型 python主要的数据类型主要包括以下几种类型: (1) 数字型 (2) 字符串 (3) 列表 (4) 元组 (5) 字典 ( ...

  10. Spark学习笔记--Graphx

    浅谈Graphx: http://blog.csdn.net/shangwen_/article/details/38645601 Pregel: http://blog.csdn.net/shang ...