level 6
西安恩仪联教育
楼主
外设的处理速度一般慢于CPU,CPU不能一直等待外部事件,所以设备必须有一种方法来通知cpu它的工作进度,这种方法就是中断。
一、中断注册
在linux驱动程序设计中,为设备实现一个中断包含两个步骤:
1、向内核注册中断
request_irq用于实现中断的注册功能:
2.4内核
int request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id);
2.6 内核
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);
函数返回0表示程序,否则返回一个负的错误码。
(1) unsigned int irq :中断号
(2)void (*handler)(int, void *, struct pt_regs *):中断处理函数
(3)unsigned long flags:与中断有关的各种选项。
IRQF_DISABLED(SA_INTERRUPT):如果设置该位,表示是一个“快速”中断处理程序;如果没有设置该位,那么是一个“慢速”中断处理程序。
IRQF_SHARED(SA_SHIRQ):该位表示中断可以在设备间共享。
注:这两种类型的中断处理程序的主要区别在于:快速中断保证中断处理的原子性(不被打断),而慢速中断则不保证。换句话说,也就是“开启中断”标志位在运行快速中断处理器程序时是关闭的,因此在服务该中断时,不会被其他类型的中断打断;而调用慢速中断处理时,其它类型的中断仍可以得到服务。
(4)const char *device:设备名字
(5)void *dev_id:共享中断时使用。
共享中断就是将不同的设备挂到同一个中断信号线上。
共享中断也是通过request_irq函数来注册:但有三点要注意:
i.申请共享中断时,必须在flags参数中指定I RQF_SHARED位。
ii. Dev_id参数必须是唯一的。
iii.共享中断的处理程序中,不能使用disable_irq(unsigned int irq).如果使用了该函数,共享中断信号线的其它设备将同样无法使用中断,也就无法正常工作。
二、 中断处理函数
什么是中断处理程序,有何特别之处?中断处理程序就是普通的c代码。特别之处在于中断处理程序是在中断上下文中运行的,它的行为受到了某些限制:不能向用户空间发送或接受数据、不能使用可能引起阻塞的函数、不能使用可能引起调度的函数。
中断函数的处理流程:
Void short_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
/*判断是否是本设备产生了中断*/
Value=inb(short_base);
If(!(value&0x80)) return;
/*清楚中断位(如果设备支持自动清楚,则不需要这步)*/
Out(value &0x7f,short_base);
/*中断处理,通常是数据接收*/
……………
/*唤醒等待数据的进程*/
Wake_up_interruptible(&short_queue);
}
释放中断
当设备不再需要使用中断时(通常在驱动卸载时),应当把它们返还给系统,使用
void free_irq(unsigned int irq,void *dev_id)
三、中断使用案例
使用开发板key1键产生中断信号,引发系统中断执行中断处理函数验证中断的过程。在以下示例程序中注意:
(1)中断注册函数和中断注销函数的用法。
(2)中断函数的编写方法。
(3)键值的读取方式。
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <plat/regs-gpio.h>
#include <linux/irq.h>
#include <asm/unistd.h>
#include <plat/gpio-bank-n.h>
#define BUTTON_IRQ0 IRQ_EINT(0)
#define DEVICE_NAME "button-interrupt"
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{ int tmp,key_value;
printk("interrupt is occuered");
tmp=readl(S3C64XX_GPNDAT);
key_value=tmp&0x3f;
printk("k1 is pressed %d",key_value);
return 0;
}
static int __init buttons_init(void)
{
int ret;
ret = request_irq(BUTTON_IRQ0 , buttons_interrupt, IRQ_TYPE_EDGE_FALLING, DEVICE_NAME , NULL);
if(ret)
{
printk("K1_IRQ: could not register interrupt\n");
return ret;
}
printk(DEVICE_NAME "initialized\n");
return 0;
}
static void __exit buttons_exit(void)
{
free_irq(BUTTON_IRQ0,NULL);
printk(DEVICE_NAME "exit\n");
}
MODULE_AUTHOR("http://www.3gosc.com");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ok6410 Buttons Driver");
module_init(buttons_init);
module_exit(buttons_exit);
四、总结
中断过程:在响应一个中断是,内核会执行该信号对应的一个函数,该函数就叫做该中断对应的中断处理函数。一般来说,中断的优先级是最高的,一但接收到中断,内核就会调用对应的中断处理函数。中断信号传入处理器后,接下来的工作就是由内核来实现了,那是一个复杂的机制,但是,内核提供了相关的接口(中断注册注销函数),编程者只要通过接口告诉内核,当来了指定中断时,内核该执行哪个中断处理函数。使用中断注册函数时要查询中断号,在S3C2440中,这些中断号定义在文件"include/mach/irqs.h"中。其实要实现中断,大部分的工作已经给内核包了,我们只需要做的就是告诉内核,当来了什么中断要执行怎么样的函数,其实步骤很简单:
1)调用两个函数:requesr_irq和free_irq。
2)实现中断处理函数:irq_handler()。
2026年01月29日 08点01分
1
一、中断注册
在linux驱动程序设计中,为设备实现一个中断包含两个步骤:
1、向内核注册中断
request_irq用于实现中断的注册功能:
2.4内核
int request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id);
2.6 内核
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);
函数返回0表示程序,否则返回一个负的错误码。
(1) unsigned int irq :中断号
(2)void (*handler)(int, void *, struct pt_regs *):中断处理函数
(3)unsigned long flags:与中断有关的各种选项。
IRQF_DISABLED(SA_INTERRUPT):如果设置该位,表示是一个“快速”中断处理程序;如果没有设置该位,那么是一个“慢速”中断处理程序。
IRQF_SHARED(SA_SHIRQ):该位表示中断可以在设备间共享。
注:这两种类型的中断处理程序的主要区别在于:快速中断保证中断处理的原子性(不被打断),而慢速中断则不保证。换句话说,也就是“开启中断”标志位在运行快速中断处理器程序时是关闭的,因此在服务该中断时,不会被其他类型的中断打断;而调用慢速中断处理时,其它类型的中断仍可以得到服务。
(4)const char *device:设备名字
(5)void *dev_id:共享中断时使用。
共享中断就是将不同的设备挂到同一个中断信号线上。
共享中断也是通过request_irq函数来注册:但有三点要注意:
i.申请共享中断时,必须在flags参数中指定I RQF_SHARED位。
ii. Dev_id参数必须是唯一的。
iii.共享中断的处理程序中,不能使用disable_irq(unsigned int irq).如果使用了该函数,共享中断信号线的其它设备将同样无法使用中断,也就无法正常工作。
二、 中断处理函数
什么是中断处理程序,有何特别之处?中断处理程序就是普通的c代码。特别之处在于中断处理程序是在中断上下文中运行的,它的行为受到了某些限制:不能向用户空间发送或接受数据、不能使用可能引起阻塞的函数、不能使用可能引起调度的函数。
中断函数的处理流程:
Void short_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
/*判断是否是本设备产生了中断*/
Value=inb(short_base);
If(!(value&0x80)) return;
/*清楚中断位(如果设备支持自动清楚,则不需要这步)*/
Out(value &0x7f,short_base);
/*中断处理,通常是数据接收*/
……………
/*唤醒等待数据的进程*/
Wake_up_interruptible(&short_queue);
}
释放中断
当设备不再需要使用中断时(通常在驱动卸载时),应当把它们返还给系统,使用
void free_irq(unsigned int irq,void *dev_id)
三、中断使用案例
使用开发板key1键产生中断信号,引发系统中断执行中断处理函数验证中断的过程。在以下示例程序中注意:
(1)中断注册函数和中断注销函数的用法。
(2)中断函数的编写方法。
(3)键值的读取方式。
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <plat/regs-gpio.h>
#include <linux/irq.h>
#include <asm/unistd.h>
#include <plat/gpio-bank-n.h>
#define BUTTON_IRQ0 IRQ_EINT(0)
#define DEVICE_NAME "button-interrupt"
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{ int tmp,key_value;
printk("interrupt is occuered");
tmp=readl(S3C64XX_GPNDAT);
key_value=tmp&0x3f;
printk("k1 is pressed %d",key_value);
return 0;
}
static int __init buttons_init(void)
{
int ret;
ret = request_irq(BUTTON_IRQ0 , buttons_interrupt, IRQ_TYPE_EDGE_FALLING, DEVICE_NAME , NULL);
if(ret)
{
printk("K1_IRQ: could not register interrupt\n");
return ret;
}
printk(DEVICE_NAME "initialized\n");
return 0;
}
static void __exit buttons_exit(void)
{
free_irq(BUTTON_IRQ0,NULL);
printk(DEVICE_NAME "exit\n");
}
MODULE_AUTHOR("http://www.3gosc.com");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ok6410 Buttons Driver");
module_init(buttons_init);
module_exit(buttons_exit);
四、总结
中断过程:在响应一个中断是,内核会执行该信号对应的一个函数,该函数就叫做该中断对应的中断处理函数。一般来说,中断的优先级是最高的,一但接收到中断,内核就会调用对应的中断处理函数。中断信号传入处理器后,接下来的工作就是由内核来实现了,那是一个复杂的机制,但是,内核提供了相关的接口(中断注册注销函数),编程者只要通过接口告诉内核,当来了指定中断时,内核该执行哪个中断处理函数。使用中断注册函数时要查询中断号,在S3C2440中,这些中断号定义在文件"include/mach/irqs.h"中。其实要实现中断,大部分的工作已经给内核包了,我们只需要做的就是告诉内核,当来了什么中断要执行怎么样的函数,其实步骤很简单:
1)调用两个函数:requesr_irq和free_irq。
2)实现中断处理函数:irq_handler()。