linux驱动学习记录(二)-PCI驱动框架
发布日期:2021-10-10 05:30:57 浏览次数:34 分类:技术文章

本文共 4138 字,大约阅读时间需要 13 分钟。

1. PCI设备驱动的组成

 

PCI 驱动只是为了辅助设备本身的驱动,它不是目的,而是手段。例如,对于通过PCI 总线与系统连接的字符设备,则驱动中除了要实现PCI 驱动部分外,其主体仍然是设备作为字符设备本身的驱动,即实现file_operations成员函数并注册cdev。

 

在Linux 内核中,用pci_driver 结构体来定义PCI 驱动,该结构体中包含了PCI 设备的探测/移除、挂起/恢复等函数,其定义如下

struct pci_driver {

struct list_head node;

char *name;

struct module *owner;

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 (*suspend_late) (struct pci_dev *dev, pm_message_t state);

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

int(*resume)(struct pci_dev *dev); /* 设备唤醒 */

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

struct pm_ext_ops *pm;

struct pci_error_handlers *err_handler;

struct device_driver driver;

struct pci_dynids dynids;

};

 

pci_device_id 用于标识一个PCI 设备。它的成员包括:厂商ID、设备ID、子厂商ID、子设备ID、类别、类别掩码(类可分为基类、子类)和私有数据。每一个PCI 设备的驱动程序都有一个pci_device_id 的数组,用于告诉PCI 核心自己能够驱动哪些设备,pci_device_id 结构体的定义如下

struct pci_device_id {

_ _u32 vendor, device; /* 厂商和设备ID PCI_ANY_ID*/

_ _u32 subvendor, subdevice; /* 子厂商ID PCI_ANY_ID */

 _ _u32 class, class_mask; /* (类、子类、prog-if) 三元组 */

kernel_ulong_t driver_data; /* 驱动私有数据 */

};

2. PCI设备驱动框架

以下为一个简单PCI驱动框架示例代码,没有任何功能。

#include        #include          #include            #include              #include                 #include                   //预定义主设备号 #define LS_MAJOR 150 static int lspci_major = LS_MAJOR; module_param(lspci_major, int, S_IRUGO); //自定义设备结构体 struct lspci_dev { struct cdev cdev; //在Linux内核中,使用cdev结构体描述一个字符设备 }; struct lspci_dev *lspci_devp; /* 字符设备file_operations open 成员函数 */ static int xxx_open(struct inode *inode, struct file *filp) { return 0; } /* 字符设备file_operations ioctl 成员函数 */ static long xxx_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { return 0; } /* 字符设备file_operations read 成员函数 */ static ssize_t xxx_read(struct file *filp, char __user * buf, size_t size, loff_t * ppos) { return 0; } /* 字符设备file_operations write成员函数 */ static ssize_t xxx_write(struct file *filp, const char __user *buf,size_t size, loff_t *ppos) { return 0; } /* 字符设备file_operations release成员函数 */ static int xxx_release(struct inode *inode, struct file *filp) { return 0; } /* 设备文件操作接口 */ static const struct file_operations xxx_fops = { .owner = THIS_MODULE, /* xxx_fops 所属的设备模块 */ .read = xxx_read, /* 读设备操作*/ .write = xxx_write, /* 写设备操作*/ .unlocked_ioctl = xxx_ioctl, /* 控制设备操作*/ .open = xxx_open, /* 打开设备操作*/ .release = xxx_release, /* 释放设备操作*/ }; /*pci_device_id 用于标识一个PCI 设备。 它的成员包括:厂商ID、设备ID、子厂商ID、子设备ID、 类别、类别掩码(类可分为基类、子类)和私有数据。*/ static struct pci_device_id xxx_pci_tbl [] __initdata = { {0x10ee, 0x0050,PCI_ANY_ID, PCI_ANY_ID, }, {0,} }; MODULE_DEVICE_TABLE(pci, xxx_pci_tbl); /* pci_driver 的probe 成员函数 */ static int xxx_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { //申请字符设备号 dev_t xxx_dev_no = MKDEV(lspci_major, 0); register_chrdev_region(xxx_dev_no, 1, "driver_test"); //为自定义设备结构体申请内存 lspci_devp = kzalloc(sizeof(struct lspci_dev), GFP_KERNEL); //将自定义设备结构体内的cdev成员与file_operations设备文件操作接口绑定 cdev_init(&lspci_devp->cdev,&xxx_fops); //拥有该结构的模块的指针,一般为THIS_MODULES lspci_devp->cdev.owner = THIS_MODULE; //注册设备 cdev_add(&lspci_devp->cdev, xxx_dev_no, 1); pci_set_master(pci_dev);//设置成总线主DMA 模式 pci_request_regions(pci_dev, PCI_NAME);// 申请I/O 资源 return 0; } /* pci_driver 的remove 成员函数 */ static void xxx_remove(struct pci_dev *pdev) { /* 注销字符设备 */ cdev_del(&lspci_dev->cdev); /* 释放占用的设备号 */ unregister_chrdev_region(MKDEV(ls_major, 0), 1); kfree(lspci_devp); } /* PCI设备模块信息 */ static struct pci_driver xxx_pci_driver = { .name = PCI_NAME, /* 设备模块名称 */ .id_table = xxx_pci_tbl, /* 能够驱动的设备列表 */ .probe = xxx_probe, /* 查找并初始化设备 */ .remove = xxx_remove, /* 卸载设备模块 */ }; static int __init xxx_init_module (void) { //注册pci驱动,进入probe函数 pci_register_driver(&xxx_pci_driver); return 0; } static void __exit xxx_cleanup_module (void) { //注销pci驱动 pci_unregister_driver(&xxx_pci_driver); } /* 驱动模块加载函数 */ module_init(xxx_init_module); /* 驱动模块卸载函数 */ module_exit(xxx_cleanup_module); MODULE_AUTHOR("LuoSheng"); MODULE_LICENSE("GPL v2");

转载地址:https://blog.csdn.net/qq_22042587/article/details/78175503 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:linux驱动学习记录(三)-PCI IO读写、中断、DMA传输
下一篇:linux驱动学习记录(一)-字符设备框架

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年03月15日 01时04分18秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

onmessage websocket 收不到信息_WebSocket断开重连解决方案,心跳重连实践 2019-04-21
hibernate mysql 缓存_hibernate和mysql的缓存问题,没辙了! 2019-04-21
abp框架 mysql_ABP框架使用Mysql数据库 2019-04-21
mysql树形递归删除_使用递归删除树形结构的所有子节点(java和mysql实现) 2019-04-21
linux mysql 不能连接远程_linux mysql 远程连接 2019-04-21
mysql $lt_mongodb中比较级查询条件:($lt $lte $gt $gte)(大于、小于)、查找条件... 2019-04-21
install python_Install python on AIX 7 2019-04-21
jquery查找div下第一个input_jquery查找div元素第一个元素id 2019-04-21
如何修改手机屏幕显示的长宽比例_屏幕分辨率 尺寸 比例 长宽 如何计算 2019-04-21
mysql 的版本 命名规则_MySQL版本和命名规则 2019-04-21
no java stack_Java Stack contains()用法及代码示例 2019-04-21
java动态代码_Java Agent入门学习之动态修改代码 2019-04-21
python集合如何去除重复数据_Python 迭代删除重复项,集合删除重复项 2019-04-21
iview 自定义时间选择器组件_Vue.js中使用iView日期选择器并设置开始时间结束时间校验功能... 2019-04-21
java 验证码校验_JavaWeb验证码校验功能代码实例 2019-04-21
java多线程初学者指南_Java多线程初学者指南(4):线程的生命周期 2019-04-21
java进程user是jenkins_java 学习:在java中启动其他应用,由jenkins想到的 2019-04-21
java添加资源文件_如何在eclipse中将资源文件夹添加到我的Java项目中 2019-04-21
java的三种修饰符_3分钟弄明白JAVA三大修饰符 2019-04-21
mysql source skip_redis mysql 中的跳表(skip list) 查找树(btree) 2019-04-21