Linux驱动开发-中断处理模型笔记 5
Posted hntea-hong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux驱动开发-中断处理模型笔记 5相关的知识,希望对你有一定的参考价值。
中断处理模型
1、概念解析
a) I/O操作的不确定因素以及处理器和I/O设备之间速度不匹配,设备往往通过某种硬件信号异步唤起处理器的注意
b) 这些硬件信号就称为 中断,每个设备都被分配了一个相关的标示符,别称为中断请求号(IRQ)
c) 处理器检测到某一 IRQ 号对应的中断产生时,它将停止工作并启动IRQ所对应的中断服务程序
d) 共享中断:多个设备使用同一个中断源;注销区分用设备号dev_id和 服务函数区分,共享中断的多个设备在申请中断时都要使用SA_SHIRQ标志,而一个设备以SA_SHIRQ申请某中断成功的前提是之前申请该中断的所有设备也都以SA_SHIRQ标志申请
2、分配IRQ(中断)号
a) 现代设备可直接分配
b) TQ210的硬件中断号是从32开始的,0-31的中断号分配给软中断
c) 现代设备能够响应对IRQ的查询(系统启动过程中由Bios分配)
d) 系统中活动的IRQ列表:/proc/interrupts 文件中由记录
3、中断结构体详解
a) struct irq_desc 中的主要成员
i. * @irq_data: per irq and chip data passed down to chip functions
ii. * @action: the irq action chain,/* IRQ action list */
1. struct irqaction
irq_handler_t handler; /*用户注册的中断处理函数放在这里*/
unsigned long flags; /*中断模式*/
void *dev_id; /*设备号*/
struct irqaction *next; /*将共享中断连接成单向链表*/
int irq; /*中断号*/
irq_handler_t thread_fn;
struct task_struct *thread;
unsigned long thread_flags;
unsigned long thread_mask;
const char *name; /*中断设备名*/
struct proc_dir_entry *dir; /*pointer to the proc/irq/NN/name entry*/
4、Linux 中断驱动设计函数解析
a) 头文件:
/*
参数说明:
irq:中断号 所在目录linux/arch/arm/mach-xxx/include/mach/irqs.h
dev_id:传递给中断处理函数的变量,无传参一般写为0
函数返回:
0表示成功
-INCAL表示中断号无效或处理函数指针为 NULL
-EBUSY表示中断已经被占用且不能共享
*/
static irqreturn_t xxx_interrupt(int irq,void *dev_id);
c) 注册中断处理函数
/*
参数说明:
irq:中断号
在源码目录linux/arch/arm/mach-xxx/include/mach/irqs.h中有定义
hander:中断函数服务函数
flags:中断类型标志:中断触发方式----- <linux/interrupt.h>
devname:产生中断的设备名
*/
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *devname, void *dev_id);
d) 注销中断处理函数
/*
irq:注册的中断号
dev_id:传递给中断处理函数的数据
*/
void free_irq(unsigned int irq, void *dev_id);
5、使能与屏蔽中断函数解析
a) 屏蔽一个中断源
i. void disable_irq(int irq):立即返回
ii. void disable_irq_nosync(int irq):等待目前的中断处理完
iii. void enable_irq(int irq):取消屏蔽
注:这三个函数作用于可编程中断控制器,对系统内的所有CPU都生效
b) 屏蔽CPU内所有中断
i. void local_irq_restore(unsigned long flags);
ii. void local_irq_enable(void)
注:local_开头的方法作用范围是本CPU内,也就是上面的中断与屏蔽,只有执行该local_xxx_xxx()函数的CPU才会有响应
6、编程套路
a) 编写中断服务函数
b) 请求(注册)中断号
c) 释放(注销)中断号
模板:
<.......> 头文件
static irqreturn_t xxx_interrupt(int irq,void *dev_id)
.....
static int xxx_init()
int ret = 0;
ret = request_irq(irq_num,xxx_interrupt,
xxxflag, “devname”, 0/....)
return ret;
static void xxx_exit()
free(irq,xxx_interrupt);
module_init(xxx_init);
module_exit(xxx_exit);
7、小结:
a) 对比之前的字符设备和混杂字符设备,LINUX模块编程的套路就是
i. 申请资源
ii. 注销资源
b) 一个明显的特点是彼此之间没有干扰,就像使用LINUX中断的流程和使用LINUX字符设备的流程都可以分割出来,没半毛钱关系。
8、下面就操起小刀测试
a) 开发板:tq210
b) 注意事项:
i. 测试该驱动时,应该查看中断号是否被使用了,如果被使用了,从新配置内核,把驱动选项中的输入设备中的按键支持去掉;命令:
cat /proc/interrupts
按键中断驱动程序设计
/******************************************
author : hntea
date: 2016/3/14
function : key interrupt test
******************************************/
#include<linux/module.h>
#include<linux/init.h>
#include<linux/miscdevice.h>
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/io.h>
#include<linux/interrupt.h>
#define DEV_MINIR 11 /*自己随便取咯*/
#define DEV_NAME "key" /*自己随便取咯,该设备名会在 /dev目录下生成相应的设备文件*/
#define KEY_GPH0CON 0xE0200C00 /*key_1 /key_2 EXIT0/1*/
#define EXT_INT_0_CON 0xE0200E00 /*配置电平触发方式,在中断注册程序中已经解释*/
#define EXT_INT_0_MASK 0xE0200F00 /*外部中断掩码寄存器*/
#define VIC0INTENABLE 0xF2000010 /*中断使能寄存器*/
#define EXINT0ENABLE (1) /*打开中断0*/
#define EXINT1ENABLE (1<<1) /*打开中断1*/
/******************************************
函数名: key_hardinit
函数功能:硬件初始化
******************************************/
void key_hardinit(void)
unsigned int *key_ioconfig = 0;
unsigned int *irq_mask = 0;
unsigned int *irq_enable = 0;
unsigned int temdata = 0;
/*GPIO初始化 32位寄存器*/
key_ioconfig = ioremap(KEY_GPH0CON,4); /*按键1和2设置成外部中断*/
temdata = ioread32(key_ioconfig);
temdata &= (~0xff);
temdata |= 0xff;
iowrite32(temdata,key_ioconfig);
/*中断控制初始化,这个在中断注册时内核帮我们初始化了*/
/******************************************
函数名: key_interrupt
函数功能:中断服务函数入口
******************************************/
static irqreturn_t key_interrupt (int irq, void *dev_id)
printk("key interrupt .........\\n");
printk(“i get dev_id is:%d”,(int)dev_id);
return 0;
/******************************************
函数名: key_open
函数功能:文件操作
******************************************/
int key_open(struct inode *inode, struct file *filp)
key_hardinit();
return 0;
/******************************************
函数名:
函数功能:文件操作
******************************************/
struct file_operations key_fop =
.open = key_open,
;
struct miscdevice key=
.minor = DEV_MINIR ,
.name = DEV_NAME,
.fops = &key_fop,
;
static int keyInit(void)
int ret = 0;
/*1、注册设备文件*/
ret = misc_register(&key);
/*2、注册中断号*/
ret = request_irq(IRQ_EINT0,key_interrupt,
IRQF_SHARED, "key", 1); /
printk("ret val is:%d\\n",ret); //-16:中断号已经被申请;-22:中断号错误
if(ret < 0)
printk("EXINT0 request fail!\\n");
else
printk("EXINT0 request sucess!\\n");
return 0;
static void keyExit(void)
int ret = 0;
/*注销中断*/
free_irq(IRQ_EINT0, 1);
/*注销混杂设备*/
ret = misc_deregister(&key);
/*注销设备*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hntea");
module_init(keyInit);
module_exit(keyExit);
以上是关于Linux驱动开发-中断处理模型笔记 5的主要内容,如果未能解决你的问题,请参考以下文章