Exynos4412 中断驱动开发(一)—— 中断基础及中断的注册过程

一、中断基础概念

        所谓中断,指CPU在执行程序的过程中,出现了某些突发事件即待处理,CPU必须暂停当前的程序。转去处理突发事件,处理完毕后CPU又返回原程序被中断的位置并继续执行。

1、中断分类

a -- 内部中断和外部中断

      根据中断的的来源,中断可以分为内部中断和外部中断:

内部中断,其中断源来自CPU内部(软件中断指令、溢出、除法错误等),例如,操作系统从用户态切换到内核态需借助CPU内部的软中断;

外部中断,其中断源来自CPU外部,由外设提出请求;

b -- 可屏蔽中断与不屏蔽中断

      根据中断是否可以屏蔽分为可屏蔽中断与不屏蔽中断:

可屏蔽中断,其可以通过屏蔽字被屏蔽,屏蔽后,该中断不再得到响应;

不屏蔽中断,其不能被屏蔽;

c -- 向量中断和非向量中断

     根据中断入口跳转方法的不同,分为向量中断和非向量中断:

向量中断,采用向量中断的CPU通常为不同的中断分配不同的中断号,当检测到某中断号的中断到来后,就自动跳转到与该中断号对应的地址执行。不同的中断号有不同的入口地址;

非向量中断,其多个中断共享一个入口地址,进入该入口地址后再通过软件判断中断标志来标识具体是哪个中断。

    也就是说,向量中断由硬件提供中断服务程序入口地址,非向量中断由软件提供中断服务入口地址


2、中断ID

a -- IRQ number

      cpu给中断的一个编号,一个IRQ number是一个虚拟的interrupt ID,和硬件无关;

b -- HW interrupt ID

       对于中断控制器而言,它收集了多个外设的irq request line,要向cpu传递,GIC要对外设进行编码,GIC就用HW interrupt ID来标示外部中断;


3、SMP情况下中断两种形态

1-Nmode :只有一个processor处理器

N-N :所有的processor都是独立收到中断的

      GIC:SPI使用1-Nmode   PPI 和 sgi使用N-Nmode


二、中断编程

1、 申请IRQ

      在linux内核中用于申请中断的函数是request_irq(),函数原型在Kernel/irq/manage.c中定义:

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

相关参数:

a -- irq是要申请的硬件中断号。另外,这里要思考的问题是,这个irq 是怎么得到的?这里我们在设备树中获取,具体解析见:

b -- handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。

c -- irqflags是中断处理的属性,若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)

d -- devname设置中断名称,在cat /proc/interrupts中可以看到此名称。

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

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

      顶半部 handler 的类型 irq_handler_t 定义为:

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

参数1:中断号
参数2 :参数
在Interrupt.h (e:\linux-3.14-fs4412\include\linux)    18323    2014/3/31中定义
IRQ_NONE       共享中断,如果不是我的设备产生的中断,就返回该值
IRQ_HANDLED     中断处理函数正确执行了就返回该值
IRQ_WAKE_THREAD        = (1 << 1)

    

2、释放IRQ

      与request_irq()相对应的函数为 free_irq(),free_irq()的原型为:

void free_irq(unsigned int irq, void *dev_id)

 free_irq()参数的定义与request_irq()相同。


三、中断注册过程分析

       我们每次用中断的时候就是注册一个中断函数。request_irq首先生成一个irqaction结构,其次根据中断号 找到irq_desc数组项(还记得吧,内核中irq_desc是一个数组,没一项对应一个中断号),然后将irqaction结构添加到 irq_desc中的action链表中。当然还做一些其他的工作,注册完成后,中断函数就可以发生并被处理了。

      irq_desc 内核中记录一个irq_desc的数组,数组的每一项对应一个中断或者一组中断使用同一个中断号,一句话irq_desc几乎记录所有中断相关的东西,这个结构是中断的核心。其中包括俩个重要的结构irq_chip 和irqaction 。

1、  irq_chip

      irq_chip  里面基本上是一些回调函数,其中大多用于操作底层硬件,设置寄存器,其中包括设置GPIO为中断输入就是其中的一个回调函数,分析一些源代码

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. struct irq_chip {  
  2.         const char     *name;  
  3.         unsigned int   (*startup)(unsigned int irq); //启动中断  
  4.         void           (*shutdown)(unsigned int irq); //关闭中断  
  5.         void           (*enable)(unsigned int irq);  // 使能中断  
  6.         void           (*disable)(unsigned int irq); // 禁止中断  
  7.    
  8.         void           (*ack)(unsigned int irq);   //中断应答函数,就是清除中断标识函数  
  9.         void           (*mask)(unsigned int irq);   //中断屏蔽函数  
  10.         void           (*mask_ack)(unsigned int irq); //屏蔽中断应答函数,一般用于电平触发方式,需要先屏蔽再应答  
  11.         void           (*unmask)(unsigned int irq);  //开启中断  
  12.         void           (*eoi)(unsigned int irq);  
  13.    
  14.         void           (*end)(unsigned int irq);  
  15.         int            (*set_affinity)(unsigned int irq,  
  16.                                       const struct cpumask *dest);  
  17.         int            (*retrigger)(unsigned int irq);  
  18.         int            (*set_type)(unsigned int irq, unsigned int flow_type); //设置中断类型,其中包括设置GPIO口为中断输入  
  19.         int            (*set_wake)(unsigned int irq, unsigned int on);  
  20.    
  21.         void           (*bus_lock)(unsigned int irq);  //上锁函数  
  22.         void           (*bus_sync_unlock)(unsigned int irq); //解锁  
  23.    
  24.         /* Currently used only by UML, might disappear one day.*/  
  25. #ifdef CONFIG_IRQ_RELEASE_METHOD  
  26.         void           (*release)(unsigned int irq, void *dev_id);  
  27. #endif  
  28.         /* 
  29.          * For compatibility, ->typename is copied into ->name. 
  30.          * Will disappear. 
  31.          */  
  32.         const char     *typename;  
  33. };  


       我们可以看到这里实现的是一个框架,需要我们进一步的填充里面的函数。我们在分析另一个结构irqaction

2、irqaction

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. include/linux/interrupt.h  
  2. struct irqaction {  
  3.         irq_handler_t handler;  //用户注册的中断处理函数  
  4.         unsigned long flags;    //中断标识  
  5.         const char *name;       //用户注册的中断名字,cat/proc/interrupts时可以看到  
  6.         void *dev_id;           //可以是用户传递的参数或者用来区分共享中断  
  7.         struct irqaction *next; //irqaction结构链,一个共享中断可以有多个中断处理函数  
  8.         int irq;                //中断号  
  9.         struct proc_dir_entry *dir;  
  10.         irq_handler_t thread_fn;  
  11.         struct task_struct *thread;  
  12.         unsigned long thread_flags;  
  13. };  
     

      我们用irq_request函数注册中断时,主要做俩个事情,根据中断号生成一个irqaction结构并添加到irq_desc中的 action结构链表,另一发面做一些初始化的工作,其中包括设置中断触发方式,设置一些irq_chip结构中没有初始化的函数为默认,开启中断,设置 GPIO口为中断输入模式(这里后面有详细流程分析)。

四、实例分析

        下面是一个按键中断驱动的编写,具体硬件分析在:Exynos4412 中断驱动开发(三)—— 设备树中中断节点的创建 

1、driver.c

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <linux/module.h>  
  2. #include <linux/device.h>  
  3. #include <linux/platform_device.h>  
  4. #include <linux/interrupt.h>  
  5. #include <linux/fs.h>  
  6. #include <linux/wait.h>  
  7. #include <linux/sched.h>  
  8. #include <asm/uaccess.h>  
  9. static int major = 250;  
  10.   
  11.   
  12. static wait_queue_head_t wq;  
  13. static int have_data = 0;  
  14. static int key;  
  15. static struct resource *res1;  
  16. static struct resource *res2;  
  17. static  irqreturn_t key_handler(int irqno, void *dev)  
  18. {  
  19. //  printk("key_handler irqno =%d \n",irqno);  
  20.     if(irqno == res1->start)  
  21.     {  
  22.         key = 1;  
  23.     }  
  24.     if(irqno == res2->start)  
  25.     {  
  26.         key = 2;  
  27.     }     
  28.     have_data = 1;  
  29.     wake_up_interruptible(&wq);  
  30.     return IRQ_HANDLED;  
  31. }  
  32. static int key_open (struct inode *inod, struct file *filep)  
  33. {  
  34.   
  35.     return 0;  
  36. }  
  37. static ssize_t key_read(struct file *filep, char __user *buf, size_t len, loff_t *pos)  
  38. {  
  39.     wait_event_interruptible(wq, have_data==1);  
  40.     if(copy_to_user(buf,&key,sizeof(int)))  
  41.     {  
  42.         return -EFAULT;  
  43.     }  
  44.     have_data = 0;  
  45.     return len;  
  46. }  
  47. static  int key_release(struct inode *inode, struct file *filep)  
  48. {  
  49.     return 0;  
  50. }  
  51. static struct file_operations  key_ops =  
  52. {  
  53.     .open = key_open,  
  54.     .release = key_release,  
  55.     .read = key_read,  
  56. };  
  57.   
  58.   
  59. static int hello_probe(struct platform_device *pdev)  
  60. {  
  61.     int ret;  
  62.     printk("match 0k \n");  
  63.   
  64.     res1 = platform_get_resource(pdev,IORESOURCE_IRQ, 0);  
  65.     res2 = platform_get_resource(pdev,IORESOURCE_IRQ, 1);   
  66.          
  67.     ret = request_irq(res1->start,key_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED,"key1",NULL);  
  68.     ret = request_irq(res2->start,key_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED,"key2",NULL);  
  69.   
  70.     register_chrdev( major, "key", &key_ops);  
  71.   
  72.   
  73.     init_waitqueue_head(&wq);  
  74.       
  75.     return 0;  
  76. }  
  77. static int hello_remove(struct platform_device *pdev)  
  78. {  
  79.     free_irq(res1->start,NULL);  
  80.     free_irq(res2->start,NULL);    
  81.     unregister_chrdev( major, "key");  
  82.     return 0;  
  83. }  
  84.   
  85. static struct of_device_id key_id[]=  
  86. {  
  87.     {.compatible = "fs4412,key" },  
  88. };  
  89.   
  90. static struct platform_driver hello_driver=  
  91. {  
  92.       
  93.     .probe = hello_probe,  
  94.     .remove = hello_remove,  
  95.     .driver ={  
  96.         .name = "bigbang",  
  97.         .of_match_table = key_id,  
  98.     },  
  99. };  
  100.   
  101. static int hello_init(void)  
  102. {  
  103.     printk("hello_init");  
  104.     return platform_driver_register(&hello_driver);  
  105. }  
  106. static void hello_exit(void)  
  107. {  
  108.     platform_driver_unregister(&hello_driver);  
  109.     printk("hello_exit \n");  
  110.     return;  
  111. }  
  112. MODULE_LICENSE("GPL");  
  113. module_init(hello_init);  
  114. module_exit(hello_exit);  

test.c

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <sys/types.h>  
  2. #include <sys/stat.h>  
  3. #include <fcntl.h>  
  4. #include <stdio.h>  
  5.   
  6.   
  7. main()  
  8. {  
  9.     int fd,len;  
  10.     int key;  
  11.     fd = open("/dev/hello",O_RDWR);  
  12.     if(fd<0)  
  13.     {  
  14.         perror("open fail \n");  
  15.         return ;  
  16.     }  
  17.   
  18.     while(1)  
  19.     {  
  20.         read(fd,&key,4);  
  21.         printf("============key%d==================\n",key);  
  22.     }  
  23.   
  24.     close(fd);  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402222.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rubymine 调试 redmine

1、安装debase和ruby-debug-ide包。&#xff08;注意版本&#xff0c;rubymine 8.0.2下&#xff0c;bitnami下的版本需安装debase -v 0.2.1版本&#xff0c;网上有文章说用debase -v 0.2.2beta6。容易在rubymine启动调试时出现找不到ruby-debug-ide等错误提示&#xff09; 启动…

Linux 设备驱动中的 I/O模型(二)—— 异步通知和异步I/O

阻塞和非阻塞访问、poll() 函数提供了较多地解决设备访问的机制&#xff0c;但是如果有了异步通知整套机制就更加完善了。 异步通知的意思是&#xff1a;一旦设备就绪&#xff0c;则主动通知应用程序&#xff0c;这样应用程序根本就不需要查询设备状态&#xff0c;这一点非常类…

判断链表是否有环

链表有环的情况一般是链表的尾指向前面的节点而不是null&#xff0c;如head->node1->node2->node3->node4->tail->node2&#xff0c;该链表存在环。判断环是否存在可以借助两个指针&#xff0c;一个指针每次迭代只移动一步&#xff0c;第二个指针每次迭代移动…

Linux 设备驱动中的 I/O模型(一)—— 阻塞和非阻塞I/O

在前面学习网络编程时&#xff0c;曾经学过I/O模型 Linux 系统应用编程——网络编程&#xff08;I/O模型&#xff09;&#xff0c;下面学习一下I/O模型在设备驱动中的应用。 回顾一下在Unix/Linux下共有五种I/O模型&#xff0c;分别是&#xff1a; a -- 阻塞I/O b -- 非阻塞I/O…

Python 爬虫进阶六之多进程的用法

python 中的多线程其实并不是真正的多线程&#xff0c;并不能做到充分利用多核 CPU 资源。 如果想要充分利用&#xff0c;在 python 中大部分情况需要使用多进程&#xff0c;那么这个包就叫做 multiprocessing。 借助它&#xff0c;可以轻松完成从单进程到并发执行的转换。mult…

Linux 设备驱动的并发控制

Linux 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问&#xff0c;并发的访问会导致竞态&#xff0c;即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。 一、基础概念 1、Linux 并发相关基础概念 a -- 并发&#xff08;concurrency&#…

第三章:多坐标系

第一节&#xff1a;为什么要有多坐标系 当我们使用一个坐标系来描绘整个场景的时候&#xff0c;场景中的任意点都可以用该坐标系描述&#xff0c;此时如果有一只羊一遍摇动着耳朵&#xff0c;一边走&#xff0c;这个时候如果进行坐标的转换会发现异常的麻烦&#xff0c;此时如果…

Linux 设备驱动开发 —— 设备树在platform设备驱动中的使用

关与设备树的概念&#xff0c;我们在Exynos4412 内核移植&#xff08;六&#xff09;—— 设备树解析 里面已经学习过&#xff0c;下面看一下设备树在设备驱动开发中起到的作用 Device Tree是一种描述硬件的数据结构&#xff0c;设备树源(Device Tree Source)文件&#xff08;以…

Android 网络通信框架Volley简介(Google IO 2013)

1. 什么是Volley 在这之前&#xff0c;我们在程序中需要和网络通信的时候&#xff0c;大体使用的东西莫过于AsyncTaskLoader&#xff0c;HttpURLConnection&#xff0c;AsyncTask&#xff0c;HTTPClient&#xff08;Apache&#xff09;等&#xff0c;今年的Google I/O 2013上&…

Linux 设备驱动开发 —— platform设备驱动应用实例解析

前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 &#xff0c;下面将通过一个实例来深入我们的学习。 一、platform 驱动的工作过程 platform模型驱动编程&#xff0c;需要实现platform_device(设备)与platform_driver&#xff08;驱动&am…

Python爬虫入门四urllib库的高级用法

1.设置headers 有些网站不会同意程序直接用上面的方式进行访问&#xff0c;如果识别有问题&#xff0c;那么站点根本不会响应&#xff0c;所以为了完全模拟浏览器的工作&#xff0c;我们需要设置一些 Headers 的属性。 首先&#xff0c;打开我们的浏览器&#xff0c;调试浏览器…

进程上下文、中断上下文及原子上下文

谈论进程上下文 、中断上下文 、 原子上下文之前&#xff0c;有必要讨论下两个概念&#xff1a; a -- 上下文 上下文是从英文context翻译过来&#xff0c;指的是一种环境。相对于进程而言&#xff0c;就是进程执行时的环境&#xff1b; 具体来说就是各个变量和数据&#xff0c;…

Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型

提到 sysfs 文件系统 &#xff0c;必须先需要了解的是Linux设备模型&#xff0c;什么是Linux设备模型呢&#xff1f; 一、Linux 设备模型 1、设备模型概述 从2.6版本开始&#xff0c;Linux开发团队便为内核建立起一个统一的设备模型。在以前的内核中没有独立的数据结构用来让内…

Python爬虫入门七正则表达式

已经搞定了怎样获取页面的内容&#xff0c;不过还差一步&#xff0c;这么多杂乱的代码夹杂文字我们怎样把它提取出来整理呢&#xff1f;下面就开始介绍一个十分强大的工具&#xff0c;正则表达式 1.了解正则表达式 正则表达式是用来匹配字符串非常强大的工具&#xff0c;在其…

Linux 文件系统与设备文件系统 (一)—— udev 设备文件系统

一、什么是Linux设备文件系统 首先我们不看定义&#xff0c;定义总是太抽象很难理解&#xff0c;我们先看现象。当我们往开发板上移植了一个新的文件系统之后&#xff08;假如各种设备驱动也移植好了&#xff09;&#xff0c;启动开发板&#xff0c;我们用串口工具进入开发板&a…

情人节,教大家使用css画出一朵玫瑰花。

情人节到了&#xff0c;给大家来一朵高端的玫瑰花。 在网上看到的一个canvas实现的玫瑰花&#xff0c;效果很好&#xff0c;但是代码被压缩过&#xff0c;也没有注释&#xff0c;看的云里雾里的。 今天我教大脚用CSS来实现一朵玫瑰花。 先看效果 首先我们画出一个花瓣 1、画出一…

Linux 字符设备驱动开发基础(六)—— VFS 虚拟文件系统解析

一、VFS 虚拟文件系统基础概念 Linux 允许众多不同的文件系统共存&#xff0c;并支持跨文件系统的文件操作&#xff0c;这是因为有虚拟文件系统的存在。虚拟文件系统&#xff0c;即VFS&#xff08;Virtual File System&#xff09;是 Linux 内核中的一个软件抽象层。它通过一些…

vim使用—实现程序的自动补齐(C语言)

使用过Source Insight的人一定对它的自动补全功能印象深刻&#xff0c;在很多的集成开发环境中&#xff0c;也都支持自动补全。vim做为一个出色的编辑器&#xff0c;这样的功能当然少不了。至于如何实现程序自动补全&#xff0c;网上教程很多。这里&#xff0c;我将自己配置过程…

[C#]Attribute特性(3)——AttributeUsage特性和特性标识符

相关文章 [C#]Attribute特性 [C#]Attribute特性(2)——方法的特性及特性参数 AttributeUsage特性 除了可以定制自己的特性来注释常用的C#类型外&#xff0c;您可以用AttributeUsage特性来定义您想怎样使用这些特性。AttributeUsage特性采用如下的调用惯例&#xff1a; 1 [Attri…

Linux 命令 ——less命令

less 工具也是对文件或其它输出进行分页显示的工具&#xff0c;应该说是linux正统查看文件内容的工具&#xff0c;功能极其强大。less 的用法比起 more 更加的有弹性。在 more 的时候&#xff0c;我们并没有办法向前面翻&#xff0c; 只能往后面看&#xff0c;但若使用了 less …