概述
一、linux驱动的层次结构
二、驱动程序分析
内核中字符设备结构体的定义
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结构体的定义
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。驱动程序的文件操作编写如下
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()中。
cdev_init(&cdev,&fops);
cdev.owner = THIS_MODULE;
字符设备驱动模块加载与卸载的模板
//设备结构体
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中驱动程序的分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复