• PCI驱动程序


    配置寄存器和初始化
    struct pci_device_id {  
      __u32 vendor, device;        /* Vendor and device ID or PCI_ANY_ID*/  
      __u32 subvendor, subdevice;      /* Subsystem ID's or PCI_ANY_ID */  
      __u32 class, class_mask;      /* (class,subclass,prog-if) triplet */  
      kernel_ulong_t driver_data;     /* Data private to the driver */
    };
    1、 vendor  (厂商号)这个寄存器标识一个硬件制造商,例如,每个Intel的设备都标有相贩供应商号, 0x8086, 这样的号有一个全球注册,由PCI特别利益体所维护, 并且供应商必须申请有一个唯一的分配给它们的编号
    2、device  (设备号) 这个寄存器,由供应商选择。
    3、subvendor  (子厂商号)  如果驱动可处理任何类型的子系统ID, 值PCI_ANY_ID应该用于设置此域
    4、subdevice  (子设备号)  如果驱动可处理任何类型的子系统ID, 值PCI_ANY_ID应该用于设置此域 
    5、class      (类别)      如果驱动可处理任何类型的子系统ID, 值PCI_ANY_ID应该用于设置此域
    6、class_mask  (类别掩码)  如果驱动可处理任何类型的子系统ID, 值PCI_ANY_ID应该用于设置此域
    7、driver_data  (私有数据)
     
    再介绍两个宏定义用来初始化struct pci_device_id
     
    PCI_DEVICE(vendor, device)   :   这个创建一个 struct pci_device_id, 它匹配特定的供应商和设备ID,这个宏设置这个结构的子供应商和子设备号为PCI_ANY_ID
     
    PCI_DEVICE_CLASS(device_class, device_class_mask)   : 这个创建一个struct pci_device_id它匹配一个特定的PCI类。
     
    MODULE_DEVICE_TABLE宏
    MODULE_DEVICE_TABLE   : 用于将pci_device_id结构输出到用户空间,来允许执插拔各模块加载系统知道什么模块使用什么硬件设备。示例: 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。在depmod完成后,所有的被内核中的模块支持的PCI设备被列出,带有它们模块名子,在那个文件中,当内核告知热插拔系统有新的PCI设备已找到,热插拔系统使用modules.pcimap文件来找到正确的驱动来加载。
     
    注册PCI驱动程序
    为了被正确注册到内核, 所有的 PCI 驱动必须创建的主结构是 struct pci_driver 结构。这个结构包含许多函数回调和变量, 来描述 PCI 驱动给 PCI核心。这里是这个结构的一个 PCI 驱动需要知道的成员:
    const char *name;

    驱动的名字。在内核中所有 PCI 驱动里中它必须是唯一的。通常被设置为和驱动模块名字相同的名子。当驱动程序运行在内核中时,它显示在 sysfs 中在/sys/bus/pci/drivers/ 下面。
     
    const struct pci_device_id *id_table;

    指向 struct pci_device_id 表的指针。
     
    int (*probe) (struct pci_dev *dev, const struct pci_device_id *id);

    指向 PCI 驱动中 probe 函数的指针。当PCI 核心有一个它认为驱动程序需要控制的 struct pci_dev 时,就会调用这个函数。 PCI 核心用来做判断的 struct pci_device_id 指针也被的, 也被传递给这个函数。如果PCI驱动程序确认传递给它的 struct pci_dev,则应该恰当地初始化这个设备并且返回 0。如果这个驱动确认该设备,或者发生了错误,它应当返回一个负的错误值。

    void (*remove) (struct pci_dev *dev);

    指向一个移除函数的指针,当 struct pci_dev被从系统中移除,或者PCI驱动程序正在从内核中卸载时,PCI核心调用该函数。
     
    int (*suspend) (struct pci_dev *dev, u32 state);

    当 struct pci_dev 被挂起时 PCI 核心调用的函数的指针. 挂起状态在 state 变量里传递. 这个函数是可选的; 一个驱动不必提供它.

    int (*resume) (struct pci_dev *dev);

    当 pci_dev 被恢复时 PCI 核心调用的函数的指针. 它总是在挂起函数已经被调用之后被调用。这个函数时可选的; 一个驱动不必提供它.
     
    总之, 为创建一个正确的 struct pci_driver 结构, 只需要四个字段被初始化:
    static struct pci_driver pci_driver = {
      .name = "pci_skel",
      .id_table = ids,
      .probe = probe,
      .remove = remove,
    };
     
    为了把struct pci_driver注册到PCI核心中,需要调用以 struct pci_driver 指针为参数的pci_register_driver函数。通常在PCI驱动程序的模块初始化代码中完成该工作:
    static int __init pci_skel_init(void)
    {
      return pci_register_driver(&pci_driver);
    }
    如果注册成功,pci_register_driver函数返回 0;否则,返回一个负的错误编号。
     
    当PCI驱动程序将要被卸载的时候,需要把struct pci_driver从内核注销。这是通过调用pci_unregister_driver来完成的。当该函数被调用时,当前绑定到该驱动程序的任何PCI设备都被移除,该PCI驱动程序的移除函数在pci_ungister_driver函数返回之前被调用。
    static void __init pci_skel_exit(void)
    {
      pci_unregister_driver(&pci_driver);
    }
     
    激活PCI设备
    在PCI驱动程序的探测函数中,在驱动程序可以访问PCI设备的任何设备资源之前(I/O区域或者中断), 驱动程序必须调用pci_enable_device函数:
    int pci_enable_device(struct pci_dev *dev);
     
    访问I/O和内存空间
    unsigned long pci_resource_start(struct pci_dev *dev, int bar);

    该函数返回六个PCI I/O区域之一的首地址(内存地址或I/O端口号)。该区域由整数的bar(base address register,基地址寄存器)指定,bar的取值为 0 到 5。
     
    unsigned long pci_resource_end(struct pci_dev *dev, int bar);

    这个函数返回第bar个I/O区域的尾地址。注意这是最后一个可用地址,而不是该区域之后的第一个地址。
     
    unsigned long pci_resource_flags(struct pci_dev *dev, int bar);

    这个函数返回与这个资源相关联的标志。

    资源标识用来定义单个资源的一些特性。对于和 PCI I/O 区相关联的 PCI 资源,这个信息从基地址寄存器中抽取出来,但是对于和 PCI 设备无关的资源,它可能来自其他地方。
     
    所有资源标志定义在<linux/ioport.h>中,其中最重要的几个:
    IORESOURCE_IO
    IORESOURCE_MEM
           如果相关的I/O区域存在,将设置这些标志之一。
    IORESOURCE_PREFETCH
    IORESOURCE_READONLY
           这些标志表明内存区域是否为可预取的和/或是写保护的。对于PCI资源来说,从来不会设置后面的那个标志。
     
  • 相关阅读:
    devops思想
    获取元素大小、偏移量及鼠标位置 journeyof
    20192424 王昭云 《网络与系统攻防技术》实验五实验报告
    2022春天回归
    文件挂载,匿名挂载和具名挂载
    .gitignore 规则示例
    js键值对的数据集合处理(Map)
    jeecgboot 3.1.0版本 https的部署
    EB_Tresos工具安装uip文件类型问题
    EB的tresos_cmd.bat关于legacy convert命令输入/输出文件类型
  • 原文地址:https://www.cnblogs.com/gjfhopeful/p/3670306.html
Copyright © 2020-2023  润新知