Linux中断

Linux 的中断处理分为两个半部,顶半部处理紧急的硬件操作,底半部处理不紧急的耗时操
作。tasklet 和工作队列都是调度中断底半部的良好机制,tasklet 基于软中断实现。内核定时器也
依靠软中断实现。

1.申请和释放中断

申请中断 int request_irq(unsigned int irq, irq_handler_t handler,  unsigned long irqflags, const char *devname, void *dev_id)

irq 是要申请的硬件中断号。

handler 是向系统登记的中断处理函数(顶半部),是一个回调函数,中断发生时,系统调用 这个函数,

dev_id 参数将被传递给它。

irqflags是中断处理的属性,可以指定中断的触发方式以及处理方式。在触发方式方面,可以是 IRQF_TRIGGER_RISING、IRQF_TRIGGER_FALLING、IRQF_TRIGGER_HIGH、IRQF_TRIGGER_ LOW 等。在处理方式方面,若设置了 IRQF_DISABLED,表明中断处理程序是快速处理程序,快 速处理程序被调用时屏蔽所有中断,慢速处理程序则不会屏蔽其他设备的驱动;若设置了 IRQF_SHARED,则表示多个设备共享中断,

dev_id 在中断共享时会用到,一般设置为这个设备 的设备结构体或者 NULL。

request_irq()返回 0 表示成功,返回-EINVAL 表示中断号无效或处理函数指针为 NULL,返 回-EBUSY 表示中断已经被占用且不能共享。

顶半部 handler 的类型 irq_handler_t 定义为:
typedef irqreturn_t (*irq_handler_t)(int, void *);
typedef int irqreturn_t;

释放中断

void free_irq(unsigned int irq,void *dev_id);

2.使能和屏蔽中断

void disable_irq(int irq);

void disable_irq_nosync(int irq);

void enable_irq(int irq); disable_irq_nosync()与 disable_irq()的区别在于前者立即返回,而后者等待目前的中断处理完 成。由于 disable_irq()会等待指定的中断被处理完,因此如果在 n 号中断的顶半部调用 disable_irq(n),会引起系统的死锁,这种情况下,只能调用 disable_irq_nosync(n)。

下列两个函数(或宏,具体实现依赖于 CPU 体系结构)将屏蔽本 CPU 内的所有中断:

#define local_irq_save(flags) ...

void local_irq_disable(void);

与上述两个禁止中断对应的恢复中断的函数(或宏)是:

#define local_irq_restore(flags) ...

void local_irq_enable(void);

3.底半部机制
Linux 实现底半部的机制主要有 tasklet、工作队列和软中断。

(1)tasklet

tasklet 的使用较简单,我们只需要定义 tasklet 及其处理函数并将两者关联,例如:
void my_tasklet_func(unsigned long); /*定义一个处理函数*/
DECLARE_TASKLET(my_tasklet, my_tasklet_func, data);
   /*定义一个 tasklet 结构 my_tasklet,与 my_tasklet_func(data)函数相关联 */

代码 DECLARE_TASKLET(my_tasklet,my_tasklet_func,data)实现了定义名称为 my_tasklet 的
tasklet 并将其与 my_tasklet_func()这个函数绑定,而传入这个函数的参数为 data。

在需要调度 tasklet 的时候引用一个 tasklet_schedule()函数就能使系统在适当的时候进行调度
运行:
tasklet_schedule(&my_tasklet);

(2).工作队列 工作队列的使用方法和 tasklet 非常相似,下面的代码用于定义一个工作队列和一个底半部执 行函数:

struct work_struct my_wq; /*定义一个工作队列*/

void my_wq_func(unsigned long); /*定义一个处理函数*/

通过 INIT_WORK()可以初始化这个工作队列并将工作队列与处理函数绑定:

INIT_WORK(&my_wq, (void (*)(void *)) my_wq_func, NULL);  /*初始化工作队列并将其与处理函数绑定*/

与 tasklet_schedule()对应的用于调度工作队列执行的函数为 schedule_work(),如:

schedule_work(&my_wq);/*调度工作队列执行*/

(3).软中断
软中断(softirq)也是一种传统的底半部处理机制,它的执行时机通常是顶半部返回的时候,asklet 是基于软中断实现的,因此也运行于软中断上下文。

在 Linux 内核中,用 softirq_action 结构体表征一个软中断,这个结构体中包含软中断处理函数指针和传递给该函数的参数。使用 open_softirq()函数可以注册软中断对应的处理函数,而raise_softirq()函数可以触发一个软中断。

软中断和 tasklet 运行于软中断上下文,仍然属于原子上下文的一种,而工作队列则运行于进
程上下文。因此,软中断和 tasklet 处理函数中不能睡眠,而工作队列处理函数中允许睡眠。

按键中断驱动程序:

四个按键(对应的IO口为GPH2(0),GPH2(1),GPH2(2),GPH2(3))) 分别对应外部中断为EINT16,17,18,19

加入了poll机制和异步通知fasync

  1. #include <linux/fs.h>
  2. #include <linux/init.h>
  3. #include <linux/delay.h>
  4. #include <linux/poll.h>
  5. #include <linux/irq.h>
  6. #include <asm/irq.h>
  7. #include <linux/wait.h>
  8. #include <linux/sched.h>
  9. #include <linux/interrupt.h>
  10. #include <asm/uaccess.h>
  11. #include <linux/gpio.h>
  12. #include <mach/regs-gpio.h>
  13. #include <mach/hardware.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/cdev.h>
  16. #include <linux/miscdevice.h>
  17.  
  18. #define KEYNAME "mykey"
  19. static unsigned char keymajor = ;
  20.  
  21. static struct cdev key_cdev;
  22.  
  23. static struct class *key_class;
  24. static struct device*key_device;
  25. static struct fasync_struct *fasync_queue;
  26.  
  27. static DECLARE_WAIT_QUEUE_HEAD(my_key_waitq); /*DECLARE_WAIT_QUEUE_HEAD (name)声明且初始化*/
  28. static unsigned char pressed = ;
  29.  
  30. static unsigned char key_value = ;
  31.  
  32. struct my_key_desc {
  33. unsigned int irq;
  34. unsigned int pin;
  35. unsigned char value;
  36. const char* name;
  37. };
  38.  
  39. static struct my_key_desc key_desc[] = {
  40. {IRQ_EINT16_31, S5PV210_GPH2(), 0x01, "KEY1"},
  41. {IRQ_EINT16_31, S5PV210_GPH2(), 0x02, "KEY2"},
  42. {IRQ_EINT16_31, S5PV210_GPH2(), 0x03, "KEY3"},
  43. {IRQ_EINT16_31, S5PV210_GPH2(), 0x04, "KEY4"},
  44. };
  45.  
  46. static irqreturn_t my_key_irq(int irq, void* dev_id)
  47. {
  48. volatile struct my_key_desc key_dr = *(volatile struct my_key_desc*)dev_id;
  49. int value;
  50. value = gpio_get_value(key_dr.pin);
  51.  
  52. if(value == ) /*有键按下key_desc.value = 0x8x*/
  53. key_value = key_dr.value|0x80;
  54. else
  55. key_value = key_dr.value ;
  56.  
  57. pressed = ;
  58. wake_up_interruptible(&my_key_waitq);
  59.  
  60. kill_fasync(&fasync_queue, SIGIO, POLLIN | POLLOUT);
  61. return ;
  62. }
  63.  
  64. static int my_key_open(struct inode *inode, struct file *file)
  65. {
  66. int ret;
  67. printk("request_irq setting\n");
  68. ret = request_irq( IRQ_EINT(), my_key_irq, IRQ_TYPE_EDGE_BOTH, "KEY1", (void*)&key_desc[]);
  69. if(ret) {
  70. printk("ret is %d\n", ret);
  71. return ret;
  72. }
  73. ret = request_irq( IRQ_EINT(), my_key_irq, IRQ_TYPE_EDGE_BOTH, "KEY2", (void*)&key_desc[]);
  74. if(ret)
  75. return ret;
  76. ret = request_irq( IRQ_EINT(), my_key_irq, IRQ_TYPE_EDGE_BOTH, "KEY3", (void*)&key_desc[]);
  77. if(ret)
  78. return ret;
  79. ret = request_irq( IRQ_EINT(), my_key_irq, IRQ_TYPE_EDGE_BOTH, "KEY4", (void*)&key_desc[]);
  80. if(ret)
  81. return ret;
  82. return ;
  83. }
  84.  
  85. /*static int my_key_open(struct inode * inode, struct file * file)
  86. {
  87. int ret;
  88. unsigned char i;
  89. for(i = 0; i < 4; i++) {
  90. // s3c_gpio_cfg(key_desc[i].pin, EINT_MODE ); sizeof(key_desc) / sizeof(key_desc[0])
  91. ret = request_irq(key_desc[i].irq, my_key_irq , IRQ_TYPE_EDGE_BOTH, key_desc[i].name,(void*)&key_desc[i]);
  92. if(ret) {
  93. printk(KERN_EMERG"request_irq error %d\n" , i);
  94. break;
  95. }
  96. }
  97. if(ret) {
  98. i--;
  99. for(; i > 0; i--) {
  100. free_irq(key_desc[i].irq, (void*)&key_desc[i]);
  101. return -EBUSY;
  102. }
  103. }
  104. return 0;
  105. }*/
  106.  
  107. static int my_key_fasync(int fd, struct file * file, int on){
  108. return fasync_helper(fd, file, on, &fasync_queue);
  109. }
  110.  
  111. static ssize_t my_key_read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
  112. {
  113. int ret;
  114. if(n != ) {
  115. printk(KERN_EMERG"The driver can only give one key value once!\n");
  116. return -EINVAL;
  117. }
  118.  
  119. if(filep->f_flags & O_NONBLOCK) {
  120. if(!pressed)
  121. return -EBUSY;
  122. } else {
  123. wait_event_interruptible(my_key_waitq, pressed);/*pressed为1时继续执行后面,否则休眠*/
  124. pressed = ;
  125.  
  126. ret = copy_to_user(outbuf, &key_value, );
  127. if(ret) {
  128. printk(KERN_EMERG"key copy_to_user error\n");
  129. return -ENOMEM;
  130. }
  131. }
  132. return ;
  133. }
  134.  
  135. static int my_key_write(struct file * filep,const char * buf,size_t n,loff_t * ppos)
  136. {
  137.  
  138. return ;
  139. }
  140.  
  141. static int my_key_close(struct inode * inode,struct file * file)
  142. {
  143. free_irq(IRQ_EINT(), (void*)&key_desc[]);
  144. free_irq(IRQ_EINT(), (void*)&key_desc[]);
  145. free_irq(IRQ_EINT(), (void*)&key_desc[]);
  146. free_irq(IRQ_EINT(), (void*)&key_desc[]);
  147. my_key_fasync(-, file, );
  148. return ;
  149. }
  150.  
  151. static unsigned int my_key_poll(struct file *filep, poll_table *wait)
  152. {
  153. unsigned int mask = ;
  154. poll_wait(filep, &my_key_waitq, wait);
  155.  
  156. if(pressed) {
  157. mask |= POLLIN | POLLRDNORM;
  158. }
  159.  
  160. return mask;
  161. }
  162.  
  163. struct file_operations key_fops= {
  164. .owner = THIS_MODULE,
  165. .open = my_key_open,
  166. .read = my_key_read,
  167. .write = my_key_write,
  168. .release = my_key_close,
  169. .poll = my_key_poll,
  170. .fasync = my_key_fasync,
  171. };
  172.  
  173. static int __init my_key_init(void)
  174. {
  175. int ret;
  176. int deno;
  177. deno = MKDEV(keymajor, );
  178. cdev_init(&key_cdev, &key_fops);
  179. if (keymajor) {
  180. register_chrdev_region(deno, , KEYNAME);
  181. printk(KERN_EMERG"key major is %d\n", keymajor);
  182. } else {
  183. alloc_chrdev_region(&deno, , , KEYNAME);
  184. keymajor = MAJOR(deno);
  185. printk(KERN_EMERG"key major is %d\n", keymajor);
  186. }
  187.  
  188. key_cdev.owner = THIS_MODULE;
  189. key_cdev.ops = &key_fops;
  190.  
  191. ret = cdev_add(&key_cdev, deno, );
  192. if(ret) {
  193. printk(KERN_EMERG"cdev_add error\n");
  194. goto add_error;
  195. }
  196.  
  197. key_class= class_create(THIS_MODULE, KEYNAME);
  198. if(IS_ERR(key_class)) {
  199. printk(KERN_EMERG"class_create error\n");
  200. goto class_error;
  201. }
  202.  
  203. key_device= device_create(key_class, NULL, deno, NULL, KEYNAME);
  204. if(IS_ERR(key_device)) {
  205. printk(KERN_EMERG"device_create error\n");
  206. goto device_error;
  207. }
  208.  
  209. // init_waitqueue_head(&my_key_waitq);
  210. return ;
  211.  
  212. device_error:
  213.  
  214. class_destroy(key_class);
  215.  
  216. class_error:
  217.  
  218. cdev_del(&key_cdev);
  219.  
  220. add_error:
  221.  
  222. unregister_chrdev_region(deno,);
  223.  
  224. return -ENODEV;
  225.  
  226. }
  227.  
  228. static void __exit my_key_exit(void)
  229. {
  230. device_destroy(key_class, MKDEV(keymajor, ));
  231. class_destroy(key_class);
  232. cdev_del(&key_cdev);
  233. unregister_chrdev_region(MKDEV(keymajor, ), );
  234. }
  235.  
  236. MODULE_LICENSE("GPL");
  237. MODULE_AUTHOR("qigaohua");
  238. module_init(my_key_init);
  239.  
  240. module_exit(my_key_exit);

中断poll测试程序:

  1. #include <sys/types.h>
  2.  
  3. #include <sys/stat.h>
  4.  
  5. #include <fcntl.h>
  6.  
  7. #include <stdio.h>
  8.  
  9. #include <poll.h>
  10.  
  11. #include <signal.h>
  12.  
  13. int main()
  14. {
  15. int fd;
  16. int ret;
  17. unsigned char key_value;
  18. struct pollfd fds[];
  19.  
  20. fd = open("/dev/mykey", O_RDWR);
  21. if(fd < ) {
  22. perror("/dev/mykey open error\n");
  23. return ;
  24. }
  25.  
  26. fds[].fd = fd;
  27. fds[].events = POLLIN;
  28.  
  29. while() {
  30. ret = poll(fds, , );
  31. if(ret == ) {
  32. printf("timeout\n");
  33. }else {
  34.  
  35. read(fd, &key_value, );
  36. printf("key_value = 0x%x\n", key_value);
  37. }
  38. }
  39. }

异步通知fasync中断测试程序:

  1. #include <sys/types.h>
  2.  
  3. #include <sys/stat.h>
  4.  
  5. #include <fcntl.h>
  6.  
  7. #include <stdio.h>
  8.  
  9. #include <poll.h>
  10.  
  11. #include <signal.h>
  12.  
  13. int main()
  14. {
  15. int oflags;
  16.  
  17. fd = open("/dev/mykey", O_RDWR);
  18. if(fd < ) {
  19. printf("/dev/mykey open error\n");
  20. return -EBUSY;
  21. }
  22.  
  23. signal(SIGIO, my_sinal_fun);
  24. fcntl(fd, F_SETOWN, getpid());
  25. oflags = fcntl(fd, F_GETFL);
  26. fcntl(fd, F_SETFL, oflags | FASYNC);
  27.  
  28. while() {
  29. sleep();
  30. printf("hello\n");
  31. }
  32.  
  33. }

Smart210学习记录-------linux驱动中断的更多相关文章

  1. Smart210学习记录-------linux内核模块

    Linux 驱动工程师需要牢固地掌握 Linux 内核的编译方法以为嵌入式系统构建可运行的Linux 操作系统映像.在编译 LDD6410 的内核时,需要配置内核,可以使用下面命令中的 一个: #ma ...

  2. Smart210学习记录-----Linux i2c驱动

    一:Linux i2c子系统简介: 1.Linux 的 I2C 体系结构分为 3 个组成部分: (1) I2C 核心. I2C 核心提供了 I2C 总线驱动和设备驱动的注册.注销方法,I2C 通信方法 ...

  3. Smart210学习记录------linux串口驱动

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...

  4. Smart210学习记录-------Linux设备驱动结构

    cdev结构体 1 struct cdev { 2 struct kobject kobj; /* 内嵌的 kobject 对象 */ 3 struct module *owner; /*所属模块*/ ...

  5. Smart210学习记录-----linux定时器

    1.内核定时器: Linux 内核所提供的用于操作定时器的数据结构和函数如下: (1) timer_list 在 Linux 内核中,timer_list 结构体的一个实例对应一个定时器 1 stru ...

  6. Smart210学习记录-----SD/MMC/SDIO驱动

    转自:http://jingpin.jikexueyuan.com/article/23369.html http://blog.csdn.net/evilcode/article/details/7 ...

  7. Smart210学习记录------块设备

    转自:http://bbs.chinaunix.net/thread-2017377-1-1.html 本章的目的用尽可能最简单的方法写出一个能用的块设备驱动.所谓的能用,是指我们可以对这个驱动生成的 ...

  8. Smart210学习记录----beep linux字符设备驱动

    今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...

  9. Smart210学习记录------nor flash驱动

    nor flash驱动与nand flash驱动的差别不大,只是设置不同的结构体而已,, nor flash驱动代码: #include <linux/module.h> #include ...

随机推荐

  1. 5 echo展开

    一.(字符)展开 1.echo在标准输出中打印出他的文本 echo this is a test 输出 this is a test 2.输出通配符时,比如*代表匹配文件名的任何字符 echo * 输 ...

  2. 继承多态绕点 C#篇

    最近在看博客的时候看到一块很绕的地方,有点类似于以前学习C语言是的i++,++i组合到一起使用的情况,很坑b的,绝对会比i++,++i这种情况更有用,虽然实际代码里面确实很少出现. 面对象像三大特点不 ...

  3. c# 关键字delegate、event(委托与事件)[MSDN原文摘录][1]

    A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. ...

  4. getWritableDatabase()与getReadableDatabase()方法

    一旦在程序中得到了SQLiteOpenHelper对象之后,程序无须使用SQLiteDatabase的静态方法创建SQLiteDatabase实例,而且可以使用getWritableDatabase( ...

  5. javascript——拖拽(完整兼容代码)

    拖拽,是JS经常会用到的效果,在网上有很多的这样那样的拖拽效果,但其中往往大多有各种各养的问题,功能不全,无法兼容,而且修改的时候 也是十分麻烦. 其实拖拽的原理很简单,无非是鼠标的三个动作的解析,以 ...

  6. Redis系列-存储篇sorted set主要操作函数小结

    redis支持有序集合,即sorted set.sorted set在set的基础上,增加了排序属性,是set的升级版.这里简要谈谈sorted set的常用函数: 1)insert a)  zadd ...

  7. MVC 3个重要的描述对象之ControllerDescriptor

    1.ControllerDescriptor 1.1 ReflectedControllerDescriptor public class HomeController : Controller { ...

  8. 使用ASP.Net WebAPI构建REST服务(四)——参数绑定

    默认绑定方式 WebAPI把参数分成了简单类型和复杂类型: 简单类型主要包括CLR的primitive types,(int.double.bool等),系统内置的几个strcut类型(TimeSpa ...

  9. 字符集与字符编码 (charset & encoding)

    乱码是个大坑,相信每个人都遇过,而且是个绕不过去的坑.我理解每个程序员都应该写一篇编码相关的博文,梳理自己对这一块的理解,下面是我反复理解多次之后的学习小结. 1.从记事本的不同编码说起: 打开记事本 ...

  10. C语言:文件操作

    以附加方式打开文件,输入数据,关闭文件. #include<stdio.h> #include<stdlib.h> int main() { FILE *fp = NULL; ...