linux按键驱动中断函数参数分析,针对上一篇按键中断驱动中一些关键函数分析...

上一篇实现按键采用了中断加延时消抖和进程休眠的方法实现,现在对里面的一些重要函数分析。

注册中断函数!

ret = request_irq(key_irqs[i].irq, key_interrupt, IRQF_DISABLED, key_irqs[i].name, (void  *)i);//最后一个参数为设备id

//申请中断,申请成功后返回0

函数原型:

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);

我们来看参数的意义

在发生对应于第 1个参数 irq 的中断时,则调用第 2 个参数 handler 指定的中断服务函数(也就是把 handler() 中断服务函数注册到内核中 )。

第 3 个参数 flags 指定了快速中断或中断共享等中断处理属性。在2.6内核里对它的描述如下:

/*

* These flags used only by the kernel as part of the

* irq handling routines.

*

* IRQF_DISABLED - keep irqs disabled when calling the action handler

* IRQF_SAMPLE_RANDOM - irq is used to feed the random generator

* IRQF_SHARED - allow sharing the irq among several devices

* IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur

* IRQF_TIMER - Flag to mark this interrupt as timer interrupt

* IRQF_PERCPU - Interrupt is per cpu

* IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing

* IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is

* registered first in an shared interrupt is considered for

* performance reasons)

*/

#define IRQF_DISABLED 0x00000020

#define IRQF_SAMPLE_RANDOM 0x00000040

#define IRQF_SHARED 0x00000080

#define IRQF_PROBE_SHARED 0x00000100

#define IRQF_TIMER 0x00000200

#define IRQF_PERCPU 0x00000400

#define IRQF_NOBALANCING 0x00000800

#define IRQF_IRQPOLL 0x00001000

第 4

个参数 name 通常是设备驱动程序的名称。改值用在 /proc/interrupt

系统 (虚拟)

文件上,或内核发生中断错误时使用。

第 5 个参数 dev_id

可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址。所以如果几个中断对于同一个中断处理函数,我们就需要用到这个参数了dev_id!

返回值:

函数运行正常时返回 0 ,否则返回对应错误的负值。

Open时第二处

如何注册定时器处理函数 如果采用定时消抖的话?

static struct timer_list key_timers[4];  //定义4个去抖定时器

使用时钟,先声明一个timer_list结构,调用init_timer对它进行初始化。time_list结构里expires是标明这个时钟的周期,单位采用jiffies的单位。jiffies是Linux一个全局变量,代表时间。它的单位随硬件平台的不同而不同。系统里定义了一个常数HZ,代表每秒种最小时间间隔的数目。这样jiffies的单位就是1/HZ。Intel平台jiffies的单位是1/100秒,这就是系统所能分辨的最小时间间隔了。所以expires/HZ就是以秒为单位的这个时钟的周期。function就是时间到了以后的回调函数,它的参数就是timer_list中的

data。data这个参数在初始化时钟的时候赋值,一般赋给它设备的device结构指针。在预置时间到系统调用function,同时系统把这个

time_list从定时队列里清除。所以如果需要一直使用定时函数,要在function里再次调用add_timer()把这个timer_list

加进定时队列。

首先定义一个timer_list数组

关于timer_list结构体原型如下:

struct timer_list {

struct list_head entry;

unsigned long expires;

void (*function)(unsigned long);  //指向定时器处理函数

定时到就进入

unsigned long data;

struct tvec_base *base;

#ifdef CONFIG_TIMER_STATS

void *start_site;

char start_comm[16];

int start_pid;

#endif

#ifdef CONFIG_LOCKDEP

struct lockdep_map lockdep_map;

#endif

};

key_timers[i].function = key_timer;       //注册定时器处理函数

key_timers[i].data = i;   //作为上面函数的形参

init_timer(&key_timers[i]);  //四个按键对应的4个定时器初始化

第三个:进程(使调用该驱动的应用程序)休眠

因为应用程序都是一个死循环,在死循环里面肯定会调用驱动中的read write等函数,如果每次调用驱动都响应,那么cpu资源也会被该应用程序占尽。解决办法就是采用休眠和唤醒机制。

static DECLARE_WAIT_QUEUE_HEAD(key_waitq);

//定义并初始化等待队列

static volatile int ev_press = 0;

//按键按下的标识

利用这个宏注册一个休眠队列

注册了之后什么时候让进程(应用程序)休眠,什么时候唤醒进程呢?

我们的思维是:没有发生我们预想的某个事件时,我们让进程休眠起来,当某个事件发生了后,我们唤醒该进程!

所以我们定义一个按键标识ev_press,当没有任何按键按下时它为0

所以当应用调用驱动的读时:我们将应用休眠起来

if(!ev_press)//0

表示没有产生按键按下

{

if(file->f_flags & O_NONBLOCK) //如果应用程序采用非阻塞方式读数据则返回错误

{

return -EAGAIN;  //返回重试的标识符

}

else //阻塞方式当没有按键按下时让等待队列进入睡眠

{

wait_event_interruptible(key_waitq, ev_press); //当ev_press不成立(为0),挂起队列

}

}

唤醒,唤醒后从休眠的地方继续执行

ev_press = 1;

wake_up_interruptible(&key_waitq);   //按键按下唤醒队列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值