PCI驱动开发手册

Linux2.6内核PCI驱动程序开发
一, PCI相关数据结构说明
1.1 struct pci_driver11眼
这个数据结构在文件/linux/pci.h里,这是Linux内核版本2.4之后为新型的PCI设备驱动程序所添加的,其中最主要的是用于识别设备的id_table结构,以及用于检测设备的函数probe( )和卸载设备的函数remove( )。
    struct pci_driver {
        struct list_head node;
        char *name;
        const struct pci_device_id *id_table;
        int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);
        void (*remove) (struct pci_dev *dev);
        int  (*save_state) (struct pci_dev *dev, u32 state);
        int  (*suspend)(struct pci_dev *dev, u32 state);
        int  (*resume) (struct pci_dev *dev);
        int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);
};
为创建一个正确的struct pci_driver 结构, 只有4个字段需要被初始化:name,id_table,probe和remove。
    其中id_table初始化可以用到宏PCI_DEVICE(VENDOR_ID,DEVICE_ID),VENDOR_ID和DEVICE_ID分别为设备和厂商编号,由板卡生产厂家指定。
Static const struct pci_device_id mypci[] =
    {
        {
            PCI_DEVICE(VENDOR_ID,DEVICE_ID)
},
{}
};
1.2 pci_dev
这个数据结构也在文件include/linux/pci.h里,它详细描述了一个PCI设备几乎所有的硬件信息,包括厂商ID、设备ID、各种资源等。可以根据需要使用其中的数据成员。
struct pci_dev {
    struct list_head global_list;
    struct list_head bus_list;
    struct pci_bus  *bus;
    struct pci_bus  *subordinate;
    void        *sysdata;
干成人
    struct proc_dir_entry *procent;
    unsigned int    devfn;
    unsigned short  vendor;
    unsigned short  device;
    unsigned short  subsystem_vendor;
    unsigned short  subsystem_device;
合成绝缘子    unsigned int    class;
    u8      hdr_type;
    u8      rom_base_reg;
    struct pci_driver *driver;
    void        *driver_data;
    u64    dma_mask;
    u32            current_state;
    unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
    unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
    unsigned int    irq;
    struct resource resource[DEVICE_COUNT_RESOURCE];
    struct resource dma_resource[DEVICE_COUNT_DMA];
粉煤灰三氧化硫    struct resource irq_resource[DEVICE_COUNT_IRQ];
    char        name[80];
    char        slot_name[8];
    int    active;
    int    ro;
    unsigned short  regs;
    int (*prepare)(struct pci_dev *dev);
    int (*activate)(struct pci_dev *dev);
    int (*deactivate)(struct pci_dev *dev);
};
二, PCI驱动基本框架
在用模块方式实现PCI设备驱动程序时,通常至少要实现以下几个部分:初始化设备模块、设备打开模块、数据读写和控制模块、中断处理模块、设备释放模块、设备卸载模块。下面给出一个典型的PCI设备驱动程序的基本框架。
/* 指明该驱动程序适用于哪一些PCI设备 */
static struct pci_device_id demo_pci_tbl [] __initdata = {
    {PCI_VENDOR_ID_DEMO, PCI_DEVICE_ID_DEMO,
    PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEMO},
    {0,}
};
/* 对特定PCI设备进行描述的数据结构 */
struct demo_card {
    unsigned int magic;
    /* 使用链表保存所有同类的PCI设备 */
    struct demo_card *next;
   
    /* ... */
}
l870/* 中断处理模块 */nokia6220
static void demo_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    /* ... */
}
/* 设备模块信息 */
static struct pci_driver demo_pci_driver = {
    name:      demo_MODULE_NAME,    /* 设备模块名称 */
    id_table:  demo_pci_tbl,    /* 能够驱动的设备列表 */
    probe:      demo_probe,    /* 查并初始化设备 */
    remove:    demo_remove    /* 卸载设备模块 */
    /* ... */
};
static int __init demo_init_module (void)
{
  pci_register_driver(&demo_pci_driver);
}
static void __exit demo_cleanup_module (void)
{
    pci_unregister_driver(&demo_pci_driver);
}
/* 加载驱动程序模块入口 */
module_init(demo_init_module);
/* 卸载驱动程序模块入口 */
module_exit(demo_cleanup_module);
三, PCI设备操作实现
3.1设备初始化
在demo_init_module 中,用pci_register_driver( )函数来注册PCI设备的驱动程序,此时需要提供一个pci_driver结构,在该结构中给出的probe探测例程将负责完成对硬件的检测工作。
在probe函数中,需要实现以下几个功能:
(1)使能PCI
在 PCI 驱动的探测函数中, 在驱动可存取 PCI 设备的任何设备资源(I/O 区或者中断)之前, 驱动必须调用 pci_enable_device 函数:
int pci_enable_device(struct pci_dev *dev);
这个函数实际上使能设备. 它唤醒设备以及在某些情况下也分配它的中断线和 I/O 区. 例如, 这发生在 CardBus 设备上(它在驱动层次上已经完全和 PCI 等同了).
(2)请求PCI资源
在初始化中很重要的一个操作就是让系统为PCI分配资源,如I/O端口等。
    pci_resource_regions(struct pci_dev  *dev, char * name);
(3)存取配置空间
因为微处理器无法直接存取配置空间, 计算机供应商不得不提供一个方法来完成它. 为存取配置空间, CPU 必须写和读 PCI 控制器中的寄存器, 但是确切的实现是依赖于供应商的, 并且和这个讨论无关, 因为 Linux提供了一个标准接口来存取配置空间.
对于驱动, 配置空间可通过8-位, 16-位, 或者 32-位数据传输来存取. 相关的函数原型定义于 <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);
从由 dev 所标识出的设备的配置空间读 1 个, 2 个或者 4 个字节. where 参数是从配置空间开始的字节偏移. 从配置空间取得的值通过 val 指针返回, 并且这个函数的返回值是一个错
误码. word 和 dword 函数转换刚刚读的值从小端到处理器的本地字节序, 因此你不必处理字节序.
int pci_write_config_byte(struct pci_dev *dev, int where, u8 val);

本文发布于:2024-09-24 13:21:55,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/167027.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:设备   模块   驱动程序   空间   配置   函数
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议