驱动编写--中断,互斥和自旋锁

中断:

一般中断:

if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL))
   {
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
        return -EBUSY; 
   }

/*
参数1:参数一: 中断号:   内核在移植的时候,给了所有中断号   //irqs.h  kernel\arch\arm\mach-s5pv210\include\mach\irqs.h
参数2:中断函数 
typedef irqreturn_t (*irq_handler_t)(int, void *);
参数2.1:int 中断号 
参数2.2:void *: 当为共享中断的时候 这个作为区分使用的
参数3:flags表示 kernel\include\linux\interrupt.h  
// 参数4:参数的名字  -----在cat /proc/interrupts 系统中可以查看
参数5:dev  :作为私有数据 
*/

void free_irq(unsigned int irq, void *dev_id)


特别的中断:中断上半部分 中断下班部分

理论解释:



进程上下文是:一个进程是可以被打断的,一个进程打断之后,进程处于休眠状态
CPU在之后的调度的时候还是会运行这个进程


中断上下文:
处在中断处理程序,不能被调度的。 中断中不能像用户空间发送数据和读取数据(copy_to_user)这些函数可能交出CPU,不能调用sleep这类交出CPU的函数。打断之后CPU再也回不来了,因为中断是不能参与CPU调度的。

中断处理的注意点

(1)中断上下文,不能和用户空间数据交互
(2)不能交出CPU(不能休眠、不能schedule)
(3)ISR运行时间尽可能短,越长则系统响应特性越差

解决方案:

(1)为什么要分上半部(top half,又叫顶半部)和下半部(bottom half,又叫底半部)
(2)下半部处理策略1:tasklet(小任务)
(3)下半部处理策略2:workqueue(工作队列)

上半部分和下半部分的分工:

上半部分主要是解决:

//第一件事:标记中断(硬件 和 软件)
//第二件事:调用下半部 (激活下半部)

 事件段,任务紧张

下半部分主要解决:

//真正干活的


tasklet实战:实战演示tasklet实现下半部.

举例:

// 下半部函数
void func(unsigned long data)
{
int flag;

printk("key-s5pv210: this is bottom half\n");

s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0)); // input模式
flag = gpio_get_value(S5PV210_GPH0(2));
s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0f)); // eint2模式


input_report_key(button_dev, KEY_LEFT, !flag);
input_sync(button_dev);
}


DECLARE_TASKLET(mytasklet, func, 0);


static irqreturn_t button_interrupt(int irq, void *dummy) 

printk("key-s5pv210: this is top half\n");

tasklet_schedule(&mytasklet);

return IRQ_HANDLED; 
}

workqueue实战演示


// 下半部函数
void func(struct work_struct *work)
{
int flag;

printk("key-s5pv210: this is workqueue bottom half\n");

s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0)); // input模式
flag = gpio_get_value(S5PV210_GPH0(2));
s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0f)); // eint2模式


input_report_key(button_dev, KEY_LEFT, !flag);
input_sync(button_dev);
}


DECLARE_WORK(mywork, func);


static irqreturn_t button_interrupt(int irq, void *dummy) 

printk("key-s5pv210: this is workqueue top half\n");

schedule_work(&mywork);

return IRQ_HANDLED; 
}



tasklet 和workqueue 的区别和联系

 第一点:workqueue 类似于处在一个线程中可以被休眠的,处于一个进程上下文中的。参与
  进程上下文调度的。

第二点:tasklet 是由于软中断引起,(如果没有的中断到来)就会触发调用tasklet,一旦调用了

tasklet这个函数,就会不能进入休眠,tasklet就类似于中断上下文



中断上下半部处理原则
(1)必须立即进行紧急处理的极少量任务放入在中断的顶半部中,此时屏蔽了与自己同类型的中断,由于任务量少,所以可以迅速不受打扰地处理完紧急任务。
//在这里是已经屏蔽了同等级别的中断




(2)需要较少时间的中等数量的急迫任务放在tasklet中。此时不会屏蔽任何中断(包括与自己的顶半部同类型的中断),所以不影响顶半部对紧急事务的处理;同时又不会进行用户进程调度,从而保证了自己急迫任务得以迅速完成。
//这里并没有打断任何同等级别的任何中断
//schedule_work(&mywork) 这里 
/*
中断执行了 schedule_work(&mywork)这个函数之后
什么时候才执行mywork函数。这段时间的长度。操作系统由一套机制来衡量
当前的是否来执行mywork。执行标准是:当前负载量,到底忙还是不忙。
这个时候如果没有别的中断,那么就会执行中断下半部(这个时候是不会被打断的)。
*/




(3)需要较多时间且并不急迫(允许被操作系统剥夺运行权)的大量任务放在workqueue中。此时操作系统会尽量快速处理完这个任务,但如果任务量太大,期间操作系统也会有机会调度别的用户进程运行,从而保证不会因为这个任务需要运行时间将其它用户进程无法进行。
//这个是可以被打断的


(4)可能引起睡眠的任务放在workqueue中。因为在workqueue中睡眠是安全的。
在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O操作时,用workqueue很合适。
//如果你在中断处理函数的时候(主要是下半部分),进行一些操作可能会引起睡眠的时候,那么这个时候
//就需要用到workqueue

学习方法:
/*
总结:需要清除了解两大部分
第一大部分:靠清楚上下部分的中断 给用户留下的接口是什么

第二大部分:搞清楚这几大部分的区别

第三部分:  看别人的代码积累经验
*/



互斥和自旋锁-----------------------可以百度

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


知识点三:中断的方式
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL))
   {
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
        return -EBUSY; 
   }

/*
参数1:参数一: 中断号:   内核在移植的时候,给了所有中断号   //irqs.h  kernel\arch\arm\mach-s5pv210\include\mach\irqs.h
参数2:中断函数 
typedef irqreturn_t (*irq_handler_t)(int, void *);
参数2.1:int 中断号 
参数2.2:void *: 当为共享中断的时候 这个作为区分使用的
参数3:flags表示 kernel\include\linux\interrupt.h  
// 参数4:参数的名字  -----在cat /proc/interrupts 系统中可以查看
参数5:dev  :作为私有数据 
*/

void free_irq(unsigned int irq, void *dev_id)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值