关于PCI驱动的读书笔记

  • Post author:
  • Post category:其他


Linux的pci设备

首先要了解pci是什么,外围设备互联, Peripheral Component Interconnect,PCI外围设备互联外设的内核函数,PCI总线是当今广泛使用在桌面以及更大型的计算机上的外设总线,该总线是内核支持最好的总线。

PCI接口

PCI是替代ISA的,尽可能做到三个目标:1.性能好 2.跨平台 3.简化从平台的添加和删除

PCI寻址

PCI允许单个 系统有256个总线,每个 总线可支持32个设备,当然我们无需记住他的二进制地址,我们可以通过pci_dev来访问

尽管16位的硬件地址隐藏在struct pci_Dev对象中,但是有时候仍然可见

lspci

zhanglei@zhanglei-virtual-machine:~$ lspci
00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01)
00:01.0 PCI bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge (rev 01)
00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 08)
00:07.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)
00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08)
00:07.7 System peripheral: VMware Virtual Machine Communication Interface (rev 10)
00:0f.0 VGA compatible controller: VMware SVGA II Adapter
00:10.0 SCSI storage controller: Broadcom / LSI 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)
00:11.0 PCI bridge: VMware PCI bridge (rev 02)
00:15.0 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.1 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.2 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.3 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.4 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.5 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.6 PCI bridge: VMware PCI Express Root Port (rev 01)
00:15.7 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.0 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.1 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.2 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.3 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.4 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.5 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.6 PCI bridge: VMware PCI Express Root Port (rev 01)
00:16.7 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.0 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.1 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.2 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.3 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.4 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.5 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.6 PCI bridge: VMware PCI Express Root Port (rev 01)
00:17.7 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.0 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.1 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.2 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.3 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.4 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.5 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.6 PCI bridge: VMware PCI Express Root Port (rev 01)
00:18.7 PCI bridge: VMware PCI Express Root Port (rev 01)
02:00.0 USB controller: VMware USB1.1 UHCI Controller
02:01.0 Ethernet controller: Advanced Micro Devices, Inc. [AMD] 79c970 [PCnet32 LANCE] (rev 10)
02:02.0 Multimedia audio controller: Ensoniq ES1371/ES1373 / Creative Labs CT2518 (rev 02)
02:03.0 USB controller: VMware USB2 EHCI Controller
02:05.0 SATA controller: VMware SATA AHCI controller
zhanglei@zhanglei-virtual-machine:~$ 

还可以通过/proc/pci 和 /proc/bus去查询,当然/proc就是做查询用的目录/proc/bus/pci/devices,具体如下

zhanglei@zhanglei-virtual-machine:~$ cat /proc/bus/pci/devices 
0000    80867190    0                  0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    agpgart-intel
0008    80867191    0                  0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    
0038    80867110    0                  0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    
0039    80867111    0                1f0                 3f6                 170                 376                1061                   0               0                   8                   0                   8                   0                  10                   0               0    ata_piix
003b    80867113    9                  0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    
003f    15ad0740    10              1081            febfe004                   0                   0                   0                   0               0                  40                2000                   0                   0                   0                   0               0    vmw_vmci
0078    15ad0405    10              1071            e8000008            fe000000                   0                   0                   0           c0002                  10             8000000              800000                   0                   0                   0           20000    vmwgfx
0080    10000030    11              1401            feba0004                   0            febc0004                   0                   0        c0008000                 100               20000                   0               20000                   0                   0            4000    mptspi
0088    15ad0790    0                  0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    
00a8    15ad07a0    18                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00a9    15ad07a0    19                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00aa    15ad07a0    1a                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00ab    15ad07a0    1b                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00ac    15ad07a0    1c                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00ad    15ad07a0    1d                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00ae    15ad07a0    1e                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00af    15ad07a0    1f                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b0    15ad07a0    20                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b1    15ad07a0    21                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b2    15ad07a0    22                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b3    15ad07a0    23                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b4    15ad07a0    24                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b5    15ad07a0    25                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b6    15ad07a0    26                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b7    15ad07a0    27                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b8    15ad07a0    28                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00b9    15ad07a0    29                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00ba    15ad07a0    2a                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00bb    15ad07a0    2b                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00bc    15ad07a0    2c                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00bd    15ad07a0    2d                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00be    15ad07a0    2e                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00bf    15ad07a0    2f                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00c0    15ad07a0    30                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00c1    15ad07a0    31                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00c2    15ad07a0    32                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00c3    15ad07a0    33                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00c4    15ad07a0    34                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00c5    15ad07a0    35                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00c6    15ad07a0    36                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
00c7    15ad07a0    37                 0                   0                   0                   0                   0                   0               0                   0                   0                   0                   0                   0                   0               0    pcieport
0200    15ad0774    12                 0                   0                   0                   0                20c1                   0               0                   0                   0                   0                   0                  20                   0               0    uhci_hcd
0208    10222000    13              2001                   0                   0                   0                   0                   0        fd500000                  80                   0                   0                   0                   0                   0           10000    pcnet32
0210    12741371    10              2081                   0                   0                   0                   0                   0               0                  40                   0                   0                   0                   0                   0               0    snd_ens1371
0218    15ad0770    11          fd5ff000                   0                   0                   0                   0                   0               0                1000                   0                   0                   0                   0                   0               0    ehci-pci
0228    15ad07e0    38                 0                   0                   0                   0                   0            fd5fe000        fd510000                   0                   0                   0                   0                   0                1000           10000    ahci
zhanglei@zhanglei-virtual-machine:~$ 

lspci是总依据

每个外设板的硬件电路对如下三种地址空间的查询进行应答:内存位置、IO端口和配置寄存器。

对驱动程序而言内存和IO是惯常的方式,我们可以通过readb和inb去进行读写。另一方面配置十五是调用特定的内核函数访问配置寄存器来执行的。关于中断,每个PCI槽有四个中断引脚,每个设备功能可使用其中一个。这种路由是计算机平台负责,在总线之外的。因为PCI中断规范要求中断是可共享的 pci区域所映射的地址可以从配置空间仲读取,因此linux驱动程序不需要探测就能访问设备。在读取寄存器之后,驱动程序就可以访问硬件了。

设备一般是指一组域编号、总线编号、设备编号和功能编号

引导阶段

PCI设备上电的时候处在未激活状态,当PCI设备上电后,进行系统引导,在每个PCI设备上执行配置事务,以便为它提供的每个地址区域提供一个安全的位置。当驱动程序访问它的内存和IO区域已经被映射到了处理器的地址空间。驱动程序可以修改默认配置,不过我们不需要这么做。

配置寄存器和初始化

PCI寄存器是小头的要注意大小端问题

PCI驱动程序可以使用不同的标识符来告诉内核它支持什么样子的设备。struct pci

device

id结构定义驱动程序支持不同的pci设备列表

看头文件 /usr/src/linux-headers-5.8.0-63-generic/include/linux/mod_devicetable.h

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 */
};

我们也可以通过两个辅助宏来初始化结构体

#define PCI_DEVICE(vend,dev) \
        .vendor = (vend), .device = (dev), \
        .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \
        .class = (dev_class), .class_mask = (dev_class_mask), \
        .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
        .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID

MODULE_DEVICE_TABLE

pci_device_id需要被导出到用户空间,是热插拔和模块装载系统知道什么模块针对什么硬件设备。

MODULE_DEVICE_TABLE(pci, i810_ids)

这个语句会创建一个名字为

mod_pci_device_table的局部变量,指向struct pci_device_id数组。如果找到了指责个符号,这个数据从模块中抽出,添加到/lib/modules/KERNEL

VERSION/modules.pcimap仲。当depmod结束后,内核模块支持所有的pci设备链同他们的模块名字都在文件仲被列出。热插拔系统使用modules.pcimap来寻找新的恰当的驱动程序。

注册PCI驱动程序

pci驱动要创建的主要结构体是pci_driver结构体。

我们看一下结构体内容

struct pci_driver {
        struct list_head        node;
        const char              *name;
        const struct pci_device_id *id_table;   /* Must be non-NULL for probe to be called */
        int  (*probe)(struct pci_dev *dev, const struct pci_device_id *id);     /* New device inserted */
        void (*remove)(struct pci_dev *dev);    /* Device removed (NULL if not a hot-plug capable driver) */
        int  (*suspend)(struct pci_dev *dev, pm_message_t state);       /* Device suspended */
        int  (*resume)(struct pci_dev *dev);    /* Device woken up */
        void (*shutdown)(struct pci_dev *dev);
        int  (*sriov_configure)(struct pci_dev *dev, int num_vfs); /* On PF */
        const struct pci_error_handlers *err_handler;
        const struct attribute_group **groups;
        struct device_driver    driver;
        struct pci_dynids       dynids;
};

name 是驱动名字

probe函数地址,当pci核心有一个认为驱动程序要控制的pci

dev的时候会调用这个函数,PCI程序要做判断pci

dev中的pci_device

id也被传递给这个函数。如果确认传递给他的struct

dev,就应该确认他,返回0,否则返回负数。

remove函数地址,当pci程序从系统中一处或从内核中卸载。

suspend函数,当struct pci_Dev被挂起的时候调用这个函数。挂起状态用state传递。

resume函数,struct pci_dev被挂起后恢复触发这个函数

初始化一个pci_driver 需要初始化四个字段

struct pci_driver pci_driver = {
    .name = "11",
    .id_table = ids,
    .probe = probe,
    .close = close
}

为了把pci_driver成功注册到内核需要调用

pci_register_driver(&pci_driver);

卸载需要 pci

unregister

driver(&pci_driver);

老式的pci探测

pci_register_driver 存在危险,如果内核中的设备被移出,驱动程序还是在操作设备那么内核极有可能崩溃,所以我们应该使用下面面的函数查找,

struct pci_dev* pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from);

这个函数扫描当前系统中存在的PCI设备列表,如果输入参数和指定的厂商设备的ID匹配的话,增加了发现struct pci

dev变量的引用技术,然后把它返回给调用者,这避免了struct pci

dev无声无息的小时,struct pic_dev返回后必须调用pci

dev

put来吧使用计数器减小,如果没有则返回null

from 开找到最近一个设备,传null 就是第一个

上面的函数不能用在中断上下文中

激活pci 设备

在驱动程序可以访问PCI设备的任何资源之前,驱动程序必须调用pci

enable

device函数

int pci_enable_device(struct pci_dev *dev);

访问配置空间

通常需要读取写入三个地址空间:内存 端口和配置,对驱动程序而言访问配置空间十分重要,因为这是找到设备映射到内存和IO空间位置的唯一途径

相关函数在 <linux/pci.h> 中

int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val);
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val);
int pci_read_config_dword(const struct pci_dev *dev, int where, u32 *val);
int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val);
int pci_write_config_word(const struct pci_dev *dev, int where, u16 val);
int pci_write_config_dword(const struct pci_dev *dev, int where, u32 val);

在驱动程序struct pci_dev不能访问的时候可以用下面的函数访问怀疑是总线

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);

访问IO和内存空间

一个PCI设备可实现6个IO地址区域,每个区域可以是内存也可以是IO地址,大多数设备在内存区域实现IO寄存器。但是不像常规内存,IO寄存器不应该让CPU缓存。

在内核中,PCI设备的IO区域已经被集成到通用资源管理。

//6个IO区域首地址
#define pci_resource_start(dev, bar)    ((dev)->resource[(bar)].start)
//6个IO区域尾部地址
#define pci_resource_end(dev, bar)      ((dev)->resource[(bar)].end)
//返回和获取资源标志位
#define pci_resource_flags(dev, bar)    ((dev)->resource[(bar)].flags)

标志位:

IORESOURCE

IO IORESOURCE

MEM 相关IO区域存在,设置这些标志之一

IORESOURCE

PREFETCH IORESOURCE

READONLY 相关IO区域存在,设置这些标志表明内存区域是否是可预取的和/或是写保护的,从而不会设置后面那个标志。

PCI中断

PCI的终端号在引导阶段就确定好的了,我们驱动程序只需要用这个中断号就可以了,中断号就保存在寄存器60中,从PCI

INTERRUPT

LINE去获取就行了,这个寄存器有1个字节那么宽,意味着有256个中断线。

result = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &myirq);

关于总线

总线是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线、地址总线和控制总线,分别用来传输数据、数据地址和控制信号。

比如说没有数据传输的时候是高电平,有数据来了是低电平,然后去读取相应的 起始位 + 数据位+ 校验位 + 结束位 就可以了

例子(从网上找到的)

参考地址:https://blog.csdn.net/wq897387/article/details/108697610

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/signal.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("pcie device driver");

#define DEV_NAME "hello_pci"
#define DEBUG

#ifdef DEBUG
    #define DEBUG_ERR(format,args...)\
    do{ \
        printk("[%s:%d] ",__FUNCTION__,__LINE__); \
        printk(format,##args); \
    }while(0)
#else
    #define DEBUG_PRINT(format,args...)
#endif

#define DMA_BUFFER_SIZE 1*1024*1024
#define FASYNC_MINOR 1
#define FASYNC_MAJOR 244
#define DEVICE_NUMBER 1

static struct class * hello_class;
static struct device * hello_class_dev;

struct hello_device
{
    struct pci_dev *pci_dev;
    struct cdev cdev;
    dev_t devno;
}my_device;

unsigned long bar0_phy;
unsigned long bar0_vir;
unsigned long bar0_length;
unsigned long bar1_phy;
unsigned long bar1_vir;
unsigned long bar1_length;

dma_addr_t dma_src_phy;
dma_addr_t dma_src_vir;
dma_addr_t dma_dst_phy;
dma_addr_t dma_dst_vir;

#define HELLO_VENDOR_ID 0x666
#define HELLO_DEVICE_ID 0x999

static struct pci_device_id hello_ids[] = {
    {HELLO_VENDOR_ID,HELLO_DEVICE_ID,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
    {0,}
};

MODULE_DEVICE_TABLE(pci,hello_ids);

static int hello_probe(struct pci_dev  *pdev,const struct pci_device_id *id);
static void hello_remove(struct pci_dev *pdev);
static irqreturn_t hello_interrupt(int irq, void *dev);

void iATU_write_config_dword(struct pci_dev *pdev, int offset, int value)
{
}

static void iATU_bar0(void)
{
}

int dma_read_config_dword(struct pci_dev *pdev, int offset)
{
    int value = 0;
    return value;
}

void dma_write_config_dword(struct pci_dev *pdev, int offset, int value)
{
}

void dma_init(void)
{
    int pos;
    u16 msi_control;
    u32 msi_addr_l;
    u32 msi_addr_h;
    u32 msi_data;

    pos = pci_find_capability(my_device.pci_dev, PCI_CAP_ID_MSI);

    pci_read_config_word(my_device.pci_dev, pos+2, &msi_control);

    pci_read_config_dword(my_device.pci_dev, pos+4, &msi_addr_l);

    if(msi_control&0x80)
    {
        pci_read_config_dword(my_device.pci_dev,pos+0x8,&msi_addr_h);
        pci_read_config_dword(my_device.pci_dev,pos+0xc,&msi_data);
    }else{
        pci_read_config_dword(my_device.pci_dev,pos+0x8,&msi_data);
    }
}

static int hello_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
    int i;
    int result;

    if (pci_enable_device(pdev))
    {
        result = -EIO;
        goto end;
    }

    pci_set_master(pdev);
    my_device.pci_dev = pdev;

    if(unlikely(pci_request_regions(pdev,DEV_NAME)))
    {
        DEBUG_ERR("failed: pci_request_regions\n");
        result = -EIO;
        goto enable_device_err;
    }

    bar0_phy = pci_resource_start(pdev,0);
    if(bar0_phy<0)
    {
        DEBUG_ERR("failed: pci_resource_start\n");
        result = -EIO;
        goto request_regions_err;
    }

    bar0_length = pci_resource_len(pdev,0);
    if(bar0_length!=0)
    {
        bar0_vir = (unsigned long)ioremap(bar0_phy,bar0_length);
    }

    dma_src_vir = (dma_addr_t)pci_alloc_consistent(pdev,DMA_BUFFER_SIZE,&dma_src_phy);
    if(dma_src_vir != 0)
    {
        for(i=0;i<DMA_BUFFER_SIZE/PAGE_SIZE;i++)
        {
            SetPageReserved(virt_to_page(dma_dst_phy+i*PAGE_SIZE));
        }
    }else{
        goto free_bar0;
    }

    dma_dst_vir = (dma_addr_t)pci_alloc_consistent(pdev,DMA_BUFFER_SIZE,&dma_src_phy);
    if(dma_dst_vir != 0)
    {
        for(i=0;i<DMA_BUFFER_SIZE/PAGE_SIZE;i++)
        {
            SetPageReserved(virt_to_page(dma_dst_phy+i*PAGE_SIZE));
        }
    }else{
        goto enable_msi_error;
    }

    dma_init();

enable_msi_error:
    pci_disable_msi(pdev);

alloc_dma_dst_err:
    for(i=0;i<DMA_BUFFER_SIZE/PAGE_SIZE;i++)
    {
        ClearPageReserved(virt_to_page(dma_dst_phy+i*PAGE_SIZE));
    }
    pci_free_consistent(pdev,DMA_BUFFER_SIZE,(void *)dma_dst_vir,dma_dst_phy);

alloc_dma_src_err:
    for(i=0;i<DMA_BUFFER_SIZE/PAGE_SIZE;i++)
    {
        ClearPageReserved(virt_to_page(dma_src_phy+i*PAGE_SIZE));
    }
    pci_free_consistent(pdev,DMA_BUFFER_SIZE,(void *)dma_src_vir,dma_src_phy);

free_bar0:
    iounmap((void *)bar0_vir);
request_regions_err:
    pci_release_regions(pdev);
enable_device_err:
    pci_disable_device(pdev);
end:
    return result;
}

static void hello_remove(struct pci_dev *pdev)
{
    int i;

    free_irq(pdev->irq,my_device.pci_dev);
    pci_disable_msi(pdev);

    for(i=0;i<DMA_BUFFER_SIZE/PAGE_SIZE;i++)
    {
        ClearPageReserved(virt_to_page(dma_dst_phy+i*PAGE_SIZE));
    }
    pci_free_consistent(pdev,DMA_BUFFER_SIZE,(void *)dma_dst_vir,dma_dst_phy);

    for(i=0;i<DMA_BUFFER_SIZE/PAGE_SIZE;i++)
    {
        ClearPageReserved(virt_to_page(dma_src_phy+i*PAGE_SIZE));
    }
    pci_free_consistent(pdev,DMA_BUFFER_SIZE,(void *)dma_src_vir,dma_src_phy);

    iounmap((void *)bar0_vir);
    pci_release_regions(pdev);
    pci_disable_device(pdev);
}

static irqreturn_t hello_interrupt(int irq, void *dev)
{
    return 0;
}

static struct pci_driver hello_driver = {
    .name = DEV_NAME,
    .id_table = hello_ids,
    .probe = hello_probe,
    .remove = hello_remove,
};

static int hello_open(struct inode *inode, struct file *file)
{
    printk("driver: hello_open");
    return 0;
}

int hello_close(struct inode *inode, struct file *file)
{
    printk("driver: hello_close");
    return 0;
}

long hello_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    iATU_bar0();
    return 0;
}

static struct file_operations hello_fops = {
    .owner = THIS_MODULE,
    .open = hello_open,
    .release = hello_close,
    .unlocked_ioctl = hello_unlocked_ioctl,
};

static int hello_drv_init(void)
{
    int ret;
    ret = pci_register_driver(&hello_driver);
    if(ret<0)
    {
        printk("failed: pci_register_driver\n");
        return ret;
    }

    ret = alloc_chrdev_region(&my_device.devno,0,DEVICE_NUMBER,"hello");
    if(ret<0)
    {
        printk("failed: register_chrdev_region\n");
        return ret;
    }

    cdev_init(&my_device.cdev,&hello_fops);
    ret = cdev_add(&my_device.cdev, my_device.devno,DEVICE_NUMBER);
    if(ret<0)
    {
        printk("failed: cdev_add\n");
        return ret;
    }

    hello_class = class_create(THIS_MODULE, "hello_class");
    hello_class_dev = device_create(hello_class,NULL,my_device.devno,NULL,"hello_device");

    return 0;
}

static void hello_drv_exit(void)
{
    device_destroy(hello_class,my_device.devno);
    class_destroy(hello_class);

    cdev_del(&(my_device.cdev));
    unregister_chrdev_region(my_device.devno,DEVICE_NUMBER);
    pci_unregister_driver(&hello_driver);
}

module_init(hello_drv_init);
module_exit(hello_drv_exit);



版权声明:本文为qq_32783703原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。