字符设备驱动代码学习
注册字符设备cdev结构体
当我们在用户空间打开字符设备文件时,首先调用def_chr_fops->chrdev_open函数(字符设备都是调用这个函数),def_chr_fops->chrdev_open函数会调用kobj_lookup通过设备号找到cdev->kobject,从而得到设备的cdev,进而获得file_operations。
register_chrdev:大致作用为向内核注册cdev结构体,当在用户空间打开设备文件时,内核会根据此设备文件的主设备号快速定位cdev->file_operation结构体,从而调用底层驱动的open、read、write、ioctl等函数。如果有指定的主设备号传入,函数会去努力向内核申请,成功会返回0。如果传输的主设备好是0,则表示主设备号由内核自动分配。
老接口:register_chrdev:一个函数完成字符设备的注册。
新接口:register_chrdev_region/alloc_chrdev_region+cdev结构体
register_chrdev_region/alloc_chrdev_region只是申请了设备号,后续增加了cdev_init和cdev_add步骤来共同完成字符设备驱动注册。我猜测启用新方法的原因,可能是为了在设备驱动中引入设备类的概念,配合udev/mdev进行设备驱动文件的管理,这样的话只有真正在运行的驱动文件才会出现在内核的文件列表里。
新接口完成设备驱动注册,必须有以下步骤:
第一、使用alloc_chrdev_region/register_chrdev_region保留一个主设备号和若干此设备号
第二、使用class_create()创建自己的设备类,该函数在/sys/class 中定义
第三,创建一个struct file_operation(传递给cdev_init),每一个设备都需要创建,并调用cdev_init和cdev_add将这个设备文件注册到内核中。
第四、调用device_create()创建每个设备,并给一个合适的名字,这样就能再/dev下创建出设备文件。
示例代码:
RSIC处理器的IO内存映射
在linux内核中,I/O内存的映射分为动态映射和静态映射两种,都是将物理地址映射成为内核中的虚拟地址。
静态映射:linux移植时会建立一个I/O内存静态映射表,驱动程序员只能使用
动态映射:调用内核提供的映射机制实现,驱动程序员可以控制
将外设的IO端口(寄存器)动态映射到内存中,分为两步:
1、向内核申请虚拟地址空间
此函数的功能就是为I/O端口内存映射向内核从3G-4G的虚拟地址空间申请一段虚拟地址,成功返回非NULL,失败返回NULL;释放时使用release_mem_region();
2、I/O端口(寄存器)地址映射
ioremap函数通过__ioremap实现,只不过传给__ioremap的第三个参数为0.
ioremap函数时内核提供的用于将外设寄存器映射到主存的工具。
mmap:则是将物理内存映射到用户空间。
当然,驱动程序中的I/O内存的动态映射可以放在模块初始化函数或者open函数中。
如果一个物理地址已经进行了静态映射,再进行动态映射,这样的话,通过这两个虚拟地址都可以实现对该物理地址的访问。
使用案例: