🎊 Linux 设备驱动之 UIO 机制(基本概念)

Linux 设备驱动之 UIO 机制(基本概念)

1、 函数: static int __init uio_init(void)

功能:申请字符设备号。设备。并注冊到系统中,注冊uio_class到系统中

调用模块:init_uio_class()

运行流程:

申请字符设备号。设备,并注冊到系统中,注冊uio_class到系统中 //init_uio_class

//创建”/sys/class/uio”

2、函数:uio_exit

功能:注销uio_class,注销字符设备编号,删除设备

调用模块:release_uio_class

运行流程:

注销uio_class,注销字符设备编号。删除设备 //release_uio_class

3、函数:static void release_uio_class(void)

功能:注销uio_class,注销字符设备编号,删除设备

运行流程:

注销uio_class//class_unregister

注销字符设备编号。删除设备 //uio_major_cleanup

4、函数:static int init_uio_class(void)

功能:申请字符设备号。设备,并注冊到系统中。注冊uio_class到系统中

调用模块: uio_major_init()

class_register()

运行流程:

申请字符设备编号,设备,并初始化//uio_major_init

注冊class 类型全局变量uio_class到系统//class_register

//ls -l /sys/class 查看

5、函数: static int uio_major_init(void)

功能:申请字符设备编号,设备,并初始化

调用模块:

alloc_chrdev_region()

cdev_alloc()

kobject_set_name()

cdev_add()

运行流程:

申请字符设备编号(多个)//alloc_chrdev_region

//2^UIO_MAX_DEVICES个从设备

//设备的名字为”uio”

分配一个表示字符设备的cdev结构//cdev_alloc

初始化cdev结构的file_operations类型字段//控制cdev设备的各种操作。

// 如 open, close, read, write…

设置cdev结构的kobj字段的name为uio //kobject_set_name

加入字符设备到系统中 //cdev_add。调用成功后,我们的设备就“活了”

// cat /proc/devices ,能够查看到分配到主设备号

保存主设备号到全局变量uio_major

保存设备指针到全局变量uio_cdev

返回

6、函数:static void uio_major_cleanup(void)

功能:注销字符设备编号。删除设备

调用模块:unregister_chrdev_region

运行流程:

注销字符设备编号//unregister_chrdev_region

删除设备uio_cdev //cdev_del

file_operations

7、 函数:static int uio_open(struct inode *inode, struct file *filep)

參数:inode:

filep:

功能:获得和次设备号关联的uio_device指针,创建一个辅助变量listener, 并调用info指向的uio_info结构中的open方法

运行流程:

获得保护uio_idr的锁 //mutex_lock

从inode 结构中获取次编号 //iminor

获得和次编号关联的uio_device指针 //idr_find 在那里进行地设置呢???

// 在 uio_get_minor 中分配的次设备编号并设置的关联

放弃锁 //mutex_unlock

添加uio_device类型指针指向的模块的引用计数 //try_module_get

分配一个uio_listener类型的listener //kmalloc

关联listener和 uio_device 指针

获得uio_device 指向设备的事件计数值。并存入listener //atomic_read

把listener指针保存到filep->private_data字段

调用uio_device的info字段指向的uio_info中的open方法//*

8、函数:static int uio_release(struct inode *inode, struct file *filep)

功能:从而调用uio_device的字段info指向的uio_info中的release方法

释放辅助结构体listener

运行流程:

从filep->private_data中获得uio_open中保存的listener指针。

利用listener指针找到指向uio_device类型结构指针

从而调用uio_device的字段info指向的uio_info中的release方法。

降低uio_device类型指针指向的模块的引用计数//module_put

释放listener结构体 //kfree

9、 函数:static int uio_fasync(int fd, struct file *filep, int on)

參数:

fd

filep

on : 0, 删除;非零,加入

功能: 管理uio_device的async_queue

调用模块:fasync_helper()

运行流程:

从filep->private_data中获得uio_open中保存的listener指针。

利用listener指针找到指向uio_device类型结构指针

设置uio_device的async_queue//fasync_helper

10、函数:static unsigned int uio_poll(struct file *filep, poll_table *wait)

功能: 使进程在传递到该系统调用的所有文件描写叙述符相应的等待队列上等待。并返回一个能否够马上无堵塞运行的位掩码

运行流程:

从filep->private_data中获得uio_open中保存的listener指针。

利用listener指针找到指向uio_device类型结构指针

推断用uio_device类型指针的info字段(uio_info类型)的irq成员不为0,则继续。

否则,返回IO错误

向poll_table类型的wait表中加入uio_device类型指针指向结构的wait等待队列//poll_wait

//!!!! 注意poll_wait并不堵塞

假设listener中的事件计数值event_count和uio_device的

事件计数值count不一致时// uio_interrupt调用了uio_event_notify对

//中断事件计数器增一

返回“通常”的数据可读的位掩码

11、函数:static ssize_t uio_read(struct file *filep, char __user *buf,

size_t count, loff_t *ppos)

功能:复制uio设备中断事件计数器的值到用户空间

运行流程:

从filep->private_data中获得uio_open中保存的listener指针

利用listener指针找到指向uio_device类型结构指针

创建一个等待队列的项 //DECLARE_WAITQUEUE

检查确认uio设备的设备info的中断号(0)不为零

加入本进程到uio设备的等待队列wait上 // add_wait_queue

//由uio_interrupt调用uio_event_notify唤醒

REP: 设置当前进程的 “可中断标志”

检查是否有中断事件发生。

假设有(listener中的中断事件计数值event_count)和uio设备中的中断事件

计数器值不一致),则将设备中断计数器的值拷贝到用户空间

并将listener中的中断事件计数值更新为设备的中断事件计数值

把当前进程设置为TASK_RUNNING状态,

并将当前进程从uio设备的等待队列wait上删除

假设文件读时设置了O_NONBLOCK标志,

那么,把当前进程设置为TASK_RUNNING状态。

并将当前进程从uio设备的等待队列wait上删除

返回 -EAGAIN

检查当前进程是否有信号处理 //signal_pending

//http://blog.chinaunix.net/space.php?

uid=20746501&do=blog&cuid=1820175

如有,把当前进程设置为TASK_RUNNING状态,

并将当前进程从uio设备的等待队列wait上删除

并返回 -ERESTARTSYS

运行调度 //schedule

JMP REP

12、uio_register_device

功能: 调用uio_info中注冊的handler中断处理函数,对设备的中断事件计数器增一并通知各读进程。有数据可读

运行流程:

从filep->private_data中获得uio_open中保存的listener指针

调用 uio_device类型指针的info字段(uio_info类型)的handler

假设属于本设备的中断,而且在handler中已经处理过

那么对设备的中断事件计数器增一,

并通知各读进程,有数据可读 //uio_event_notify

13、函数:void uio_event_notify(struct uio_info *info)

功能:“触发“ 一个中断事件。对设备的中断事件计数器增一,并通知各读进程,有数据可读

运行流程:

从filep->private_data中获得uio_open中保存的listener指针

对中断事件计数器增一

唤醒堵塞在设备等待队列wait上的读进程 //wake_up_interruptible

// 该队列上的进程在uio_read中加入

向异步等待队列async_queue发出可读信号 //kill_fasync

14、 函数:static ssize_t uio_write(struct file *filep, const char __user

*buf,size_t count, loff_t *ppos)

功能: 读取用户空间的值,并调用uio_device注冊的irqcontrol函数

运行流程:

从filep->private_data中获得uio_open中保存的listener指针

调用 uio_device类型指针的info字段(uio_info类型)的handler

检验info字段(uio_info类型)的中断号irq

读取从用户空间传过来的32位的值//copy_from_user

调用info字段(uio_info类型)的irqcontrol函数。将用户空间传递过来的32位值作为參数传入。

15、函数:static int uio_mmap(struct file *filep, struct vm_area_struct

*vma)

运行流程:

从filep->private_data中获得uio_open中保存的listener指针

调用 uio_device类型指针的info字段(uio_info类型)的handler

保存uio_device类型指针到 vma 的vm_private_data

返回映射区域的索引(比方 mapX,的X) //uio_find_mem_index

计算实际的页数和请求的页数

假设实际的页数小于请求的页数那么。返回-EINVAL

假设uio设备注冊有mmap函数。那么就调用它

当内存区域的类型为UIO_MEM_PHYS时,

//uio_mmap_physical

当内存区域的类型为UIO_MEM_LOGICAL、UIO_MEM_VIRTUAL时。

为虚拟内存区域设置操作,和告诉内存不要将

该区域交换出去。訪问计数器增一//uio_mmap_logical

🎁 相关推荐

一个色彩代表一座城,湖南14个市州代表颜色出炉,你的家乡什么色?
经方苓术剂探讨
🎯 best365体育邮箱地址

经方苓术剂探讨

📅 09-14 👀 971
水晶子弹
🎯 365分类信息发布

水晶子弹

📅 09-19 👀 6597