资源预览内容
第1页 / 共45页
第2页 / 共45页
第3页 / 共45页
第4页 / 共45页
第5页 / 共45页
第6页 / 共45页
第7页 / 共45页
第8页 / 共45页
第9页 / 共45页
第10页 / 共45页
亲,该文档总共45页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
Linux中断及设备管理,www.embedu.org,本章的要求,第九章、Linux中断及设备管理 熟悉Linux中断的基本概念 熟悉Linux内核中断子系统 熟练Linux 中断处理程序的编写 熟悉Linux中断底半部机制 熟悉Linux设备管理,www.embedu.org,9.1 Linux中断的基本概念,4,中断的基本概念,中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂时中断的程序。 Linux内核与中断相关的部分包括硬件中断、下半部任务和内核线程几种。,www.embedu.org,9.2 Linux内核中断子系统,6,Linux内核中断子系统,体系结构对中断支持 ARM处理器异常处理与中断系统 内核的中断系统结构 中断服务程序注册与编写,中断处理,中断机制提供了硬件和软件之间异步传递信息的方式 硬件设备在发生某个事件时通过中断通知软件进行处理 中断实现了硬件设备按需获得处理器关注的机制,与查询方式相比可以大大节省CPU时间,Linux中断处理子系统,根据中断号找到正确的中断处理代码 Linux定义了名字为irq_desc的中断例程描述符表: (include/linux/irq.h) 该表struct irqdesc 结构组成 struct irqdesc irq_descNR_IRQS;/ NR_IRQS表示中断源的数目 irq_desc结构体中的成员action指向该中断号对应的irqaction结构体链表。irqaction结构体定义如下:,Linux中断处理子系统(cont.),全局中断控制,全局中断控制包括启用和禁用中断(ARM) raw_local_irq_save(x) 用来禁用所有的中断 raw_local_irq_enable 用来取消中断禁用 尽量不要对全局中断进行操作,static inline int atomic_sub_return(int i, atomic_t *v) unsigned long flags; int val; raw_local_irq_save(flags); val = v-counter; v-counter = val -= i; raw_local_irq_restore(flags); return val; ,www.embedu.org,9.3 Linux内核中断处理程序编写,中断处理程序编写,注册中断处理程序 Linux中断处理子系统原理 中断处理程序的实现,申请IRQ,中断处理程序注册的两个功能:注册中断号和注册中断处理函数 typedef irqreturn_t (*irq_handler_t)(int, void *); int request_irq( unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev_id); 驱动程序可以选择在初始化的时候安装中断处理程序,也可以在用户打开设备时再安装,申请IRQ (cont.),irq是要申请的硬件中断号。 handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev参数将被传递给它。 flags是中断处理的属性,若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版中已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的) dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。 name设置中断名称,在cat /proc/interrupts中可以看到此名称。,释放IRQ,与request_irq()向对应的函数为free_irq(),free_irq()的原型如下: void free_irq(unsigned int irq,void *dev_id); Free_irq()中参数的定义与request_irq()相同。,使能和屏蔽中断,下列3个函数用于屏蔽和使能一个中断源。 void disable_irq(int irq); void disable_irq_nosync(int irq); void enable_irq(int irq); disable_irq_nosync()与disable_irq()的区别在于前者立即返回,而后者等待目前的中断处理完成。注意,这3个函数作用于可编程中断控制器,因此,对系统内的所有CPU都生效。,中断共享,多个设备共享一根硬件中断线的情况在实际的硬件系统中广泛存在 申请共享中断 result = request_irq(sh_irq, xxx_interrupt, SA_SHIRQ, “xxx“, xxx_dev);,中断共享处理,irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs) . int status = read_int_status();/*获知中断源*/ if(!is_myint(dev_id,status)/*判断是否是本设备中断*/ return IRQ_NONE; /*立即返回*/ . return IRQ_HANDLED; ,中断处理程序的实现,中断处理程序ISR是在中断发生时被调用的用来处理中断的函数 在中断期间运行,不能执行有可能睡眠的操作,不能同用户空间交换数据,不能调用schedule函数放弃调度 实现中断处理有一个原则,就是尽可能快地处理并返回,冗长计算处理工作应该交给tasklet或任务队列在安全的时间内进行,www.embedu.org,9.4 Linux内核中断底半部任务,Linux中断底半部机制,两个半部的理念: 解决既要中断执行快,又要做的事情多的矛盾。 下半部机制 软中断 Tasklet 工作队列,Linux软中断机制,软中断是利用硬件中断的概念,用软件方式进行模拟,实现宏观上的异步执行效果。硬中断是外部设备对CPU的中断“,“软中断通常是硬中断服务程序对内核的中断“ 软中断的一种典型应用就是所谓的“下半部“(bottom half),驱动程序延缓执行机制,Tasklet和下半部处理 workqueue和下半部处理 内核定时器,tasklet和下半部处理,常用tasklet和workqueue两种机制实现下半部 tasklet机制: tasklet和任务队列都把任务延迟到安全时间执行的一种方式,都在中断期间运行 每个tasklet都和一个函数相关联。当tasklet被运行时,该函数就被调用,并且tasklet可以调度自己,Tasklet的实现,定义一个处理函数 void my_tasklet_func(unsigned long); 定义一个tasklet结构my_tasklet,与my_tasklet_func(data)函数相关联 DECLARE_TASKLET(my_tasklet, my_tasklet_func, data); 调度tasklet tasklet_schedule(,工作队列和下半部处理,工作队列的使用方法和tasklet非常相似 tasklet运行于中断上下文 工作队列运行于进程上下文 tasklet处理函数中不能睡眠,而工作队列处理函数中允许睡眠,工作队列的实现,定义一个工作队列 struct work_struct my_wq; 定义一个处理函数 void my_wq_func(unsigned long) ; 初始化工作队列并将其与处理函数绑定 INIT_WORK(,内核中的时间流,设备驱动程序需要获得时间信息以及定时服务,包括获取高低分辨率的时间 内核中关于时间的一个重要概念jiffies Jiffies每隔一个固定时间就会增加1,这个固定间隔由定时器中断来实现 每秒钟产生多少个定时器中断,由在中定义的宏HZ确定,获取当前时间,获取当前时间一般通过jiffies,通常用来测量不同事件之间的时间间隔 如果要获取当前时间,可以使用do_gettimeofday函数,该函数填充一个struct timeval结构,接近微秒的分辨率 调用get_fast_time,直接访问xtime变量(2.4) Current_kernel_time,延迟执行,驱动程序为了让硬件有足够的事件完成一些任务,常常需要将特定的代码延后一段时间来执行 长延迟,定义为延迟时间多于若干个jiffies,实现长延迟可以用查询jiffies的方法:timebefore(old_jiffies); timeafter(old_jiffies); 超时等待sleep_on_timeout函数,该函数在阻塞IO部分 另一种延迟方式是调用schedule_timeout 短延迟定义为延迟时间接近或短于一个jiffies 调用udelay和mdelay,忙等待函数,大量消耗CPU时间 函数udelay使用软件循环来延迟指定数目的微秒数 函数mdelay使用udelay嵌套来实现更长的毫秒级延迟,内核定时器,驱动程序可以注册一个内核定时器,来指定一个函数在未来某个时间执行 定时器只执行一次,当超时后就会被内核调用一次 超时值是一个jiffies值,当jiffies值大于超时值timer-expires时,timer-function函数就会被运行,内核定时器的实现,定义一个名为my_timer的定时器 struct timer_list my_timer; 初始化定时器 void init_timer(struct timer_list * timer); 初始化定时器并赋值其成员 static inline void setup_timer(struct timer_list * timer, void (*function)(unsigned long), unsigned long data) timer-function = function; timer-data = data; init_timer(timer); 增加定时器 void add_timer(struct timer_list * timer); 删除定时器 int del_timer(struct timer_list * timer);,www.embedu.org,9.5 Linux设备管理,设备分类,可以从不同的角度对设备进行分类。 (1)按系统和用户分:系统设备、用户设备。 (2)按输入/输出传送方式分(UNIX或Linux操作系统):字符设备、块设备。 (3)按资源特点分:独享设备、共享设备、虚拟设备。 (4)按设备硬件物理特性分:顺序存取设备、直接存取设备。 (5)按设备使用分:物理设备、逻辑设备、伪设备。 (6)按数据组织分:块设备、字符设备。 (7)按数据传输率分:低速设备、中速设备、高速设备。,设备分类,Linux把所有外部设备按其数据交换的特性分为3类: (1)字符设备是以字符为单位进行输入/输出的设备,如打印机、显示终端。 (2)块设备是以数据块为单位进行输入/输出的设备,如磁盘、光盘等。 (3)网络设备是以数据包为单位进行数据交换的设备,如以太网卡。备、中速设备、高速设备。,36,块设备与字符设备的区别,Linux网络设备,网络设备,又叫网络接口是Linux第三类标准设备 网络设备和块设备类似,在内核的特
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号