PCI总线学习(二):PCI总线驱动

一、pci_driver结构体

        《Linux设备驱动开发》中讲到,PCI只是一种总线,具体的PCI设备可以是字符设备、网络设备、USB主机控制器等,因此一个通过PCI总线与系统连接的设备的驱动至少包含两部分:PCI设备驱动设备本身的驱动。 对于这句话我的理解是,PCI驱动指实现对PCI设备的探测、移除、挂起\恢复等功能的代码部分。而设备本身的驱动指的是file_operations结构体实现的open、release、read、write等功能的代码部分。

        其中pci_driver的结构如下所示。其中的probe函数要完成对PCI设备的初始化及其设备本身身份(字符、TTY、网络等)驱动的注册。当Linux内核启动并完成对所有PCI设备进行扫描、登录和分配资源等初始化操作的同时,会建立起系统中所有PCI设备的拓扑结构,probe函数负责硬件的探测工作并保存配置信息。

struct pci_driver {
	struct list_head	node;
	const char		*name;
	const struct pci_device_id *id_table;	/* 不能为NULL,以便probe函数调用 */
	int  (*probe)(struct pci_dev *dev, const struct pci_device_id *id);	/* 新设备添加 */
	void (*remove)(struct pci_dev *dev);	/* 设备移除 */
	int  (*suspend)(struct pci_dev *dev, pm_message_t state);	/* 设备挂起 */
	int  (*resume)(struct pci_dev *dev);	/* 设备唤醒 */
	void (*shutdown)(struct pci_dev *dev);
	int  (*sriov_configure)(struct pci_dev *dev, int num_vfs); /* On PF */
	int  (*sriov_set_msix_vec_count)(struct pci_dev *vf, int msix_vec_count); /* On PF */
	u32  (*sriov_get_vf_total_msix)(struct pci_dev *pf);
	const struct pci_error_handlers *err_handler;
	const struct attribute_group **groups;
	const struct attribute_group **dev_groups;
	struct device_driver	driver;
	struct pci_dynids	dynids;
	bool driver_managed_dma;
};

         其中pci_device_id结构体如下所示。PCI_ANY_ID定义为~0,即对任意ID都适用。

struct pci_device_id {
	__u32 vendor;/* 设备供应商ID,如果为:PCI_ANY_ID则表示不检查此值*/
    __u32 device; /* 指定设备的设备ID,如果为:PCI_ANY_ID则表示不检查此值*/	
	__u32 subvendor;    /* 设备子供应商ID,如果为:PCI_ANY_ID则表示不检查此值*/
    __u32 subdevice;	/* 指定设备的子设备ID,如果为:PCI_ANY_ID则表示不检查此值 */
	__u32 class;        /* 指定设备的类代码,由基类、子类和接口组成 */
    __u32 class_mask;	/* 类代码的掩码,由基类、子类和接口组成 */
	kernel_ulong_t driver_data;	/* 指向驱动程序私有数据的指针 */
	__u32 override_only;
};

二、 PCI设备驱动的组成

        以下pci驱动示例代码以驱动字符设备为例,其一部分代码实现pci_driver成员函数,一部分代码实现字符设备的file_operations成员函数。

#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/bits.h>
#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/pmbus.h>
#include <linux/util_macros.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/platform_device.h>
#include <linux/pci.h>

int tmc_pci_open(struct inode *node, struct file *filp){
    /*......*/
}

int tmc_pci_release(struct inode *, struct file *)
{
    /*......*/
}

ssize_t tmc_pci_read(struct file *, char __user *, size_t, loff_t *)
{
    /*......*/
}

ssize_t tmc_pci_write(struct file *, const char __user *, size_t, loff_t *)
{
    /*......*/
}
struct file_operations tmc_pci_fops = {
    .open = tmc_pci_open,
    .release = tmc_pci_release,
    .read = tmc_pci_read,
    .write = tmc_pci_write,
};

int  tmc_spi_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
    /*......*/
}

void tmc_spi_remove(struct pci_dev *dev)
{
    /*......*/
}
const struct pci_device_id tmc_spi_idtable[] = {
    {/*非空*/},
    {}
};
struct pci_driver tmc_pci_drv = {
    .probe = tmc_spi_probe,
    .remove = tmc_spi_remove,
    .id_table = tmc_spi_idtable,

};

int tmc_pci_init()
{
    pci_register_driver(tmc_pci_drv);
    return 0;
}
void tmc_pci_exit
{
    pci_unregister_driver(tmc_pci_drv);
}
module_init(tmc_pci_init);
mosule_exit(tmc_pci_init);
MODULE_LICENSE("GPL");

三、PCI驱动网卡案例

        

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值