昨天写完了虚拟字符驱动,并进行了测试,可以写入字符,读取字符,但是对代码还不是很了解,所以今天又进行了简单的分析,
---------------------------------------------------------------------------------------------------------------------
一 驱动加载
globalmem_init()
1. 是否分配了设备编号?
如果分配,则注册设备register_chrdev_region()
如果未非分配, 则动态申请alloc_chrdev_region()
2. 为设备结构体申请内存,并初始化
kmalloc() // 申请设备结构体
memset(globalmem_devp, 0, sizeof(struct globalmem_dev))
3. 初始化并注册cdev结构体
globalmem_setup_cdev()
|
|
cdev_init() //初始化设备结构体中的cdev结构体
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &globalmem_fops; //注册文件操作结构体 → cdev结构体
cdev_add() //向系统中追加一个cdev的结构体
---------------------------------------------------------------------------------------------------------------------
二 数据写入到设备
/*文件操作结构体*/
static const struct file_operations globalmem_fops =
{
.owner = THIS_MODULE, // 组件
.llseek = globalmem_llseek, // seek方法
.read = globalmem_read, // 读取数据方法
.write = globalmem_write, // 写入数据方法
.unlocked_ioctl = globalmem_ioctl, /* 在2.6.x的内核版本中,文件操作结构体中,才会有ioctl的字段,高版本中使用unlocked_ioctl */
.open = globalmem_open, // 文件打开方法
.release = globalmem_release, // 文件释放方法
};
1. 在进行数据写入时,打开文件
globalmem_open() // 将设备结构体指针,传递给文件指针
2. 操作文件指针,进行数据写入
globalmem_write() // 对接收到文件指针后,将文件指针中的数据写入到内核空间
|
copy_from_user(内核地址指针, 用户空间数据地址, 数据长度)
---------------------------------------------------------------------------------------------------------------------
三 从设备中读取数据
如果文件是已经打开的状态,则可以直接进行数据读取,否则也需要开发文件操作,
globalmem_read() // 接收到文件指针后,将读取到的数据写入到文件指针中,
|
copy_to_user(用户空间数据地址, 内容空间地址指针, 数据长度)
---------------------------------------------------------------------------------------------------------------------
四 驱动卸载
globalmem_exit() // 完成设备卸载的主要内容
|
cdev_del() // 注销文件操作结构体中的cdev结构,从系统注销字符设备之后
Kfree() // 释放文件操作结构
unregister_chrdev_region() // 释放设备驱动的设备编号