VFS
三种设备类型
字符设备:字符设备是能够以字节流形式被访问的设备,字符设备驱动程序通常至少实现open,close,read和write系统调用,参数和返回值都是字符或字节流。例如:串口、鼠标、键盘、摄像头等。
块设备:块设备是存储以“块”为单位存储数据的设备,例如:磁盘设备、光盘或者U盘。
驱动设备加载与卸载
insmod或modprobe命令可以加载内核模块,模块的加载函数会执行,完成本模块的相关初始化工作。
rmmod命令可以卸载某模块,模块的卸载函数会执行,完成与模块加载函数相反的功能。
另外depmod(depend module)可检测模块的相依性,供modprobe在安装模块时使用。初次加载需要。
外设地址
外设的控制都是通过读写设备上的寄存器来进行的,外设的寄存器通常被连续编址,并且根据CPU的体系架构不同CPU对IO端口的编址方式有两种。IO映射方式(IO-mapped):比较典型的有X86处理器为外设专门实现了一个单独的地址空间,称为“IO端口空间”或者“IO地址空间”,此时CPU可以通过专门的指令(比如X86的IN和OUT)来访问这个“IO端口空间”。内存映射方式(memory-mapped):RISC指令系统的CPU一般只实现一个物理地址空间,外设IO端口成为内存的一部分。此时CPU可以访问外设的IO端口,就像访问自己的内存一样方便,不必再设置专门的指令来访问。在驱动开发过程中一般使用内存映射方式。
外设寄存器的物理地址是已知的,但不能直接访问,必须将其映射到内存空间,在Linux内核的io.h头文件中声明了ioremap()函数,用来将IO内存资源映射到核心虚拟地址空间(3Gb~4GB)中,当然不用了可以将其取消映射iounmap()。
设备树
描述设备树的文件叫做 DTS(Device Tree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息。
Bootloader会将这棵树传递给内核,然后内核来识别这棵树,并根据它展开出Linux内核中的各种设备,而这些设备用到的内存、IRQ等资源,也被传递给内核,内核会将这些资源绑定给展开的相应设备。
Linux 内核在启动的时候会解析 DTB 文件,然后在/proc/device-tree 目录下生成相应的设备树节点文件。
驱动的套路
在Linux内核中:使用cdev结构体来描述字符设备;通过其成员dev_t来定义设备号(分为主、次设备号)以确定字符设备的唯一性;通过其成员file_operations来定义字符设备驱动提供给VFS的接口函数,如常见的open()、read()、write()等。
驱动框架中:模块加载函数通过 register_chrdev_region( ) 或 alloc_chrdev_region( )来静态或者动态获取设备号;通过 cdev_init( ) 建立cdev与 file_operations之间的连接,通过 cdev_add( ) 向系统添加一个cdev以完成注册;模块卸载函数通过dev_del( )来注销cdev,通过 unregister_chrdev_region( )来释放设备号。
“一切皆文件”,驱动加载成功以后,会在/dev/xxx下面出现一个文件,应用层通过open、close等函数,操作驱动设备。
中断上半部与下半部
上半部:上半部就是中断处理函数,那些处理过程比较快,不会占用很长时间的处理就可以放在上半部完成。
下半部:如果中断处理过程比较耗时,那么就将这些比较耗时的代码提出来,交给下半部去执行,这样中断处理函数就会快进快出。
软中断必须在编译的时候静态注册!
下半部的实现方式很多:小任务(tasklet),工作队列,软中断。
上半部立刻执行,下半部执行时间由内核负责。
下半部分被上半部分所调用。
tasklet、软中断、工作队列
tasklet 是利用软中断来实现的另外一种下半部机制。由于软中断必须使用可重入函数,这就导致设计上的复杂度变高,tasklet,它具有以下特性:一种特定类型的tasklet只能运行在一个CPU上,不能并行,只能串行执行;多个不同类型的tasklet可以并行在多个CPU上;软中断是静态分配的,在内核编译好之后,就不能改变。但tasklet就灵活许多,可以在运行时改变(比如添加模块时)。
工作队列(work queue)可以实现一些tasklet不能实现的工作,比如工作队列机制可以睡眠。这种差异的本质原因是,在工作队列机制中,将推后的工作交给一个称之为工作者线程(worker thread)的内核线程去完成(单核下一般会交给默认的线程events/0)。因此,在该机制中,当内核在执行中断的剩余工作时就处在进程上下文(process context)中。也就是说由工作队列所执行的中断代码会表现出进程的一些特性,最典型的就是可以重新调度甚至睡眠。
对于tasklet机制(中断处理程序也是如此),内核在执行时处于中断上下文(interrupt context)中。而中断上下文不能睡眠。
ioremap
https://blog.csdn.net/renzemingcsdn/article/details/119256808
Linux内核五大模块
https://blog.csdn.net/daaikuaichuan/article/details/82957655