驱动:5.2中断处理函数的特点及底半部登记方式

函数的可重入性问题:
判断一个函数是否具有可重入性的标准,就是函数是否使用了全局变量
如果使用了全局变量,那么它就不具有可重入性

1.中断处理函数的特点:

1)短而有效率(很快直接结束)
中断处理函数中不应该调用那些执行速度比较慢 比较耗时子函数
2)Linux中断处理函数中,不能调用引起阻塞或者睡眠的函数
copy_to_user / copy_from_user / msleep
3)Linux系统中中断处理函数运行于中断上下文,
使用独立的栈空间,该栈空间通常为1个物理内存页(4KB)意味着中断处理函数中不应该分配静态大数组

每个线程有独立的栈空间,有两个栈,一个是内核态,一个是用户态


Linux系统支持大量硬件设备
往往有些硬件产生中断后,中断处理函数执行速度快不了
例如网卡,接收数据后会产生中断,处理大量的数据和各阶层协议
为了解决该矛盾,linux系统中将中断整个处理过程人为的分为两个半部
1)顶半部 top half: 完成那些最紧急的工作
往往是一些特殊功能寄存器的读写操作
退出中断前要完成底半部的登记
执行完毕后就退出中断
2)底半部 bottom half: 完成那些耗时的不太紧急的工作

2、底半部登记的方式

2.1 软中断
需要修改内核源码,不能以模块形式出现
用起来不方便

2.2 tasklet
基于软中断机制实现的

  核心数据结构
    struct tasklet_struct  //interrupt.h
{
	//保存底半部函数的地址
	void (*func)(unsigned long);
	//系统调用func时传递给func的参数值
	unsigned long data;
	...
};
  使用步骤:
     1)定义一个tasklet变量
        struct tasklet_struct btn_tasklet;
     2) 初始化tasklet变量
        void tasklet_init(struct tasklet_struct *t,
	              void (*func)(unsigned long), unsigned long data)	
        以上两步也可以使用DECLARE_TASKLET(name, func, data)来替换,使用此宏直接放在函数外面就可以  
        	例如:DECLARE_TASKLET(btn_tasklet, btn_tasklet_func, (unsigned int)&mydata);
     3)使用tasklet变量完成底半部的登记
        void tasklet_schedule(struct tasklet_struct *t)

实验代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <mach/platform.h>
#include <linux/delay.h>

MODULE_LICENSE("GPL");

typedef struct btn_desc
{
   
    char *name ;//名称
    int  irq;//中断号
}btn_desc_t;

btn_desc_t buttons[]={
   
    {
   "up", IRQ_GPIO_A_START+28},
    {
   "down", IRQ_GPIO_B_START+30},
    {
   "left", IRQ_GPIO_B_START+31},
    {
   "right", IRQ_GPIO_B_START+9},
};
/*定义一个tasklet变量*/
struct tasklet_struct btn_tasklet;

/*
 *irq, 中断号
 *dev, 注册时给定的最后一个参数 
 * */

irqreturn_t btn_isr(int irq, void *dev)
{
   
    btn_desc_t *pdata = dev;
    printk("<2>" "enter top half do emerg things ....\n");
    printk("<2>" "%s key is pressed!\n", pdata->name);

    /*登记底半部*/
    printk("<2>"  "register bottom half\n");
    tasklet_schedule(&btn_tasklet);
    printk("<2>" "exit from top half\n");
    /*中断出来完毕*/
    return IRQ_HANDLED;
}
int mydata = 0x100;
void btn_tasklet_func(unsigned long data)
{
   
    int *pdata = (int *)data;
    printk("<2>" "enter bottom half: do no emerg things....\n");
    printk("<2>" 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值