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

PCI总线学习(二):PCI总线驱动Linux 设备驱动开发 中讲到 PCI 只是一种总线 具体的 PCI 设备可以是字符设备 网络设备 USB 主机控制器等 因此一个通过 PCI 总线与系统连接的设备的驱动至少包含两部分 PCI 设备驱动和设备本身

大家好,欢迎来到IT知识分享网。

一、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驱动网卡案例

        

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/120793.html

(0)
上一篇 2025-10-27 15:00
下一篇 2025-10-27 15:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信