一个设备驱动的主要任务有两个:
- 1. 存取设备的内存
- 2. 处理设备产生的中断
对于第一个任务。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驱动代码
内核部分:
/*
* This is simple demon of uio driver.
* Version 1
*Compile:
* Save this file name it simple.c
* #echo "obj -m := simple.o" > Makefile
* #make -Wall -C /lib/modules/'uname -r'/build M='pwd' modules
*Load the module:
* #modprobe uio
* #insmod simple.ko
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/uio_driver.h>
#include <linux/slab.h>
/*struct uio_info {
struct uio_device *uio_dev; // 在__uio_register_device中初始化
const char *name; // 调用__uio_register_device之前必须初始化
const char *version; //调用__uio_register_device之前必须初始化
struct uio_mem mem[MAX_UIO_MAPS];
struct uio_port port[MAX_UIO_PORT_REGIONS];
long irq; //分配给uio设备的中断号,调用__uio_register_device之前必须初始化
unsigned long irq_flags;// 调用__uio_register_device之前必须初始化
void *priv; //
irqreturn_t (*handler)(int irq, struct uio_info *dev_info); //uio_interrupt中调用,用于中断处理
// 调用__uio_register_device之前必须初始化
int (*mmap)(struct uio_info *info, struct vm_area_struct *vma); //在uio_mmap中被调用,
// 执行设备打开特定操作
int (*open)(struct uio_info *info, struct inode *inode);//在uio_open中被调用,执行设备打开特定操作
int (*release)(struct uio_info *info, struct inode *inode);//在uio_device中被调用,执行设备打开特定操作
int (*irqcontrol)(struct uio_info *