才疏学浅 如有错误 欢迎指出
字符设备驱动主要实现file_operations结构体 包含常使用的read write ioctrl等函数 实现应用程序按照(应用程序 - C库 - 内核系统调用 - 具体驱动)到具体硬件的控制。
驱动程序可以直接编译进内核 (obj-y 生成.o文件) 也可以编译成模块(obj-m 生成.ko文件)
模块使用
insmod xxx.ko 加载驱动 – module_init(xxx_init)
rmmod xxx.ko 卸载驱动 – module_exit(xxx_exit)
其中insmod 不自动处理模块的依赖关系
因此挂载设备通常使用 modprobe xxx.ko 使用前需要depmod 命令处理依赖关系
编写字符设备驱动代码首先需要
注册模块module_init(xxx_init)
注销模块module_exit(xxx_exit)
初始化xxx_init()
创建字符设备流程
-
申请设备号
-
初始化并添加 cdev //使用cdev描述字符设备
-
自动创建设备节点 a.创建类 b.创建设备
内核对具体硬件的操作使用的是虚拟地址,因此需要对物理地址进行内存映射以得到对应的虚拟地址使用的函数如下:
ioremap 映射
iounmap 取消映射
CPU使用的是虚拟地址 因此需要使用ioremap将物理地址映射为虚拟地址 供内核使用
设置私有数据:对于一个设备的所有属性信息我们最好将其做成一个结构体,编写驱动 open函数的时候将设备结构体作为私有数据添加到设备文件中。
/* 设备结构体 */
truct test_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
......
;
struct test_dev testdev;
/* open 函数 */
static int test_open(struct inode *inode, struct file *filp)
{
filp->private_data = &testdev; /* 设置私有数据 */
return 0;
}
这样在其他操作函数里直接读取 private_data 即可得到结构体
注销 xxx_exit()
把注册的字符设备和申请的资源都释放掉