Linux Uio 分析
UIO的出现以及功能
硬件设备可以根据功能分为网络设备,块设备,字符设备,或者根据与CPU相连的方式分为PCI设备,USB设备等。它们被不同的内核子系统支持。这些标准的设备的驱动编写较为容易而且容易维护。很容易加入主内核源码树。但是,又有很多设备难以划分到这些子系统中,比如I/O卡,现场总线接口或者定制的FPGA。通常这些非标准设备的驱动被实现为字符驱动。这些驱动使用了很多内核内部函数和宏。而这些内部函数和宏是变化的。这样驱动的编写者必须编写一个完全的内核驱动,而且一直维护这些代码。而且这些驱动进不了主内核源码。于是就出现了用户空间I/O框架(Userspace I/O framework)。简称UIO。此外UIO也是切入内核空间将部分协议栈在用户空间定制化的一种手段。
UIO 是怎么工作的?
-
存取设备的内存
UIO 核心实现了mmap()可以处理物理内存(physical memory),逻辑内存(logical memory), 虚拟内存(virtual memory)。UIO驱动的编写是就不需要再考虑这些繁琐的细节。 -
处理设备产生的中断
对于设备中断的应答必须在内核空间进行。所以在内核空间有一小部分代码 用来应答中断和禁止中断,但是其余的工作全部留给用户空间处理。 如果用户空间要等待一个设备中断,它只需要简单的阻塞在对 /dev/uioX的read()操作上。 当设备产生中断时,read()操作立即返回。UIO 也实现了poll()系统调用,你可以使用 select()来等待中断的发生。select()有一个超时参数可以用来实现有限时间内等待中断。 对设备的控制还可以通过/sys/class/uio下的各个文件的读写来完成。你注册的uio设备将会出现在该目录下。 假如你的uio设备是uio0那么映射的设备内存文件出现在 /sys/class/uio/uio0/maps/mapX,对该文件的读写就是 对设备内存的读写。 -
框架切入点
如下的图描述了uio驱动的内核部分,用户空间部分,和uio 框架以及内核内部函数的关系。
如图所示,在内核中使用uio框架连接在原有的内核设备上,做特殊处理和用户空间的相关uio接口对接,在用户空间抽象为特殊的uiox设备.
- 代码切入点
- cdev是基础的设备结构,上层统一抽象为file_operations,其中open,read, write等接口是设备的通用行为
- uio将自己的uio_info中的read, write, open等几个接口来做对接,为用户代码提供操作uio设备行为的底层支持
- uio将自己的handler等接口注册在设备的终端处,用于从内核空间直接截取数据到uio通道.