您的位置:首页 > 其它

在驱动中定义中断

2015-11-23 10:23 190 查看
1. 中断



涉及头文件:

#include <linux/interrupts>



中断的注册

int

request_irq(

unsigned int irq,

irq_handler_t handler,

unsigned long flags,

const char *name,

void *dev

);

@irq: 中断号

外部中断号:

a. irqnum gpio_to_irq(gpio);

EXYNOS4X12_GPM4();

//arm/mach-exynos/include/mach/gpio.h

b. IRQ_EINT(eintnum);

//arm/plat-samsung/include/plat/irqs.h

内部中断:

arch/arm/mach-exynos/include/mach/irqs.h

@handler: 中断处理函数



typedef irqreturn_t (*irq_handler_t)(int, void *);

中断处理函数的返回值:IRQ_HANDLED, IRQ_NONE;



型参:第一个int对应的是发生中断的中断号。

第二个void*型的实参是注册中断时的第5个参数dev。

@flags: 注册中断的标记

#define IRQF_TRIGGER_NONE 0x00000000

#define IRQF_TRIGGER_RISING 0x00000001

#define IRQF_TRIGGER_FALLING 0x00000002 //

#define IRQF_TRIGGER_HIGH 0x00000004 //高电平

#define IRQF_TRIGGER_LOW 0x00000008 //低电平

#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \



#define IRQF_SHARED 0x00000080

@name: 中断的名字

@dev: 传给中断处理函数的第二参数的实参

中断的共享

2. 中断的下半部

-------------------------------------------------------------------

实现中断的下半部机制1: tasklet 机制

涉及到的核心结构体:

struct tasklet_struct

{

struct tasklet_struct *next;

unsigned long state;

atomic_t count;

void (*func)(unsigned long); //下半部的任务函数

unsigned long data; //下半部的任务函数需要的参数

};

使用步骤:

首先,实例化一个struct tasklet_struct的对象,代表下半部将被内核调度器调度的任务。

a. struct tasklet_struct task;



tasklet_init(&task, service_bh, dev);

b. DECLARE_TASKLET(task, service_bh, dev); //task是给tasklet起的名字,service_bh是执行tasklet时调用的函数,dev是一个用来传递给tasklet函数的ul类型的值

其次,在中断处理函数(上半部)中将下半部的任务交给调度器调度

tasklet_schedule(&task);

最后,如果写的是驱动模块,需要在模块的出口移除下半部的任务



tasklet_kill(&task);

-------------------------------------------------------------------

中断下半部的实现机制2: 工作队列机制

涉及到的核心结构体:

struct work_struct {

atomic_long_t data;

struct list_head entry;

work_func_t func; //下半部的任务函数

#ifdef CONFIG_LOCKDEP

struct lockdep_map lockdep_map;

#endif

};

//下半部任务函数的类型:

typedef void (*work_func_t)(struct work_struct *work);

实现步骤:

首先,实例化对象

方法1,

struct work_struct work;

INIT_WORK(&work, service_bh);



方法2,

DECLARE_WORK(work, service_bh); \

其次,在中断的上半部将下半部的任务交给调度器调度

schedule_work(&work);

最后,驱动模块的出口需要等待下半部的任务完成

flush_work(&work);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: