我是靠谱客的博主 能干鱼,这篇文章主要介绍Linux中驱动程序的分析,现在分享给大家,希望可以做个参考。

一、linux驱动的层次结构

二、驱动程序分析

内核中字符设备结构体的定义

复制代码
1
2
3
4
5
6
7
8
9
struct cdev { struct kobject kobj;          // 每个 cdev 都是一个 kobject    struct module *owner;        // 指向实现驱动的模块     const struct file_operations *ops;    // 操纵这个字符设备文件的方法  struct list_head list;        // 与 cdev 对应的字符设备文件的 inode->i_devices 的链表头 dev_t dev;                   // 起始设备编号   unsigned int count;        // 设备号范围大小 };

 

Linux内核对文件操作file_operations结构体的定义

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); };

 file_operations 成员大部分是文件指针,设备不支持的指针置为NULL。驱动程序的文件操作编写如下

复制代码
1
2
3
4
5
6
7
8
struct file_operations xxx_fops ={ .open = xxx_open,//xxx_open()函数是自己编写的对具体设备的打开操作 .read = xxx_read, .write = xxx_write, .release = xxx_release, };

 

 字符设备cdev结构体的初始化(静态),可单独写在一个函数xxx_setup_cdev()中,也可写在模块加载函数xxx_init()中。

复制代码
1
2
cdev_init(&cdev,&fops); cdev.owner = THIS_MODULE;

字符设备驱动模块加载与卸载的模板 

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//设备结构体 struct xxx_dev{ struct cdev cdev; ... }xxx_dev; //设备驱动模块加载函数 static int __init xxx_init(void){ cdev_init(&xxx_dev.cdev,&xxx_fops);//初始化cdev(静态) xxx_dev.cdev.owner = THIS_MODULE; dev_t xxx_dev_no =MKDEV(xxx_major,0); //获取字符设备号 if (xxx_major) { register_chrdev_region(xxx_dev_no,1,DEV_NAME); } else{ alloc_chrdev_region(&xxx_dev_no,0,DEV_NAME); } //注册设备 ret = cdev_add(&xxx_dev.cdev,xxx_dev_no,1)//参数xxx_dev_no是设备响应的第一个设备号,参数 1表示设备相关联的设备号的数目 return 0; } //设备驱动卸载模块函数 static void __exit xxx_exit(void){ unregister_chrdev_region(xxx_dev_no,1);//释放占用的设备号 cdev_del(&xxx_dev.cdev)//注销设备 } module_init(xxx_init); module_exit(xxx_exit); ......

      register_chrdev_region(xxx_dev_no,1,DEV_NAME)用于已知起始设备设备号的情况;alloc_chrdev_region(&xxx_dev_no,0,DEV_NAME)用于未知起始设备设备号的情况动态分配,会将设备号放入xxx_dev_no中。

Linux内核中存在chrdev[]数组来保存所有字符设备驱动程序信息 ,包含255个元素,每一个对应一主设备号。

三、总结

最后

以上就是能干鱼最近收集整理的关于Linux中驱动程序的分析的全部内容,更多相关Linux中驱动程序内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(71)

评论列表共有 0 条评论

立即
投稿
返回
顶部