[arm驱动]linux内核中断编程

简介:

第一部分获取中断(开启硬件中断)
一、中断的申请注销:
1)中断的申请

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

2)中断的注销

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

3)中断处理函数

1
static  irqreturn_t irq_handle( int  irq,  void  *dev__id);

   参数:irq:表示中断号,这个参数还保留由于历史遗留问题,往后可能越来越没用了。由于第二个参数信息更强大
dev__id:就是request_irq()中void *dev_id参数
二、中断申请函数参数

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

   1)参数:
   irq:是要申请的硬件中断号。
handler:是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它
    irqflags:是中断处理的属性,
       a)若设置了IRQF_DISABLED,则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;
       b)若设置了    IRQF_SHARED,则表示多个设备共享中断;//在另一篇文章会提到
       c)若设置了IRQF_SAMPLE_RANDOM,表示对系统熵有贡献,对系统获取随机数有好处。
           Tip:(flag是可以通过或的方式同时使用的
   devname:设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。
   dev_id:在中断共享时会用到,一般设置为这个设备的设备结构体或者不使用时为NULL。因为在共享中断中同一个中断线(或可以说同一个中断号)可能挂载好几个设备,当使用void free_irq(unsigned int irq, void *dev_id)时,根据irq和dev_id可以找到中断线为irq上的标识为dev_id的某个具体设备。dev_id也经常在不是共享中断中的驱动传递数据

   2)返回值:
   a)request_irq()返回0表示成功;
   b)返回-EINVAL表示无效的参数,如果返回这个值,应该看看传递给request_irq()的参数是否正确;
   c)返回-EBUSY表示中断已经被占用且不能共享;
   d)返回ENOMEM表示内存不足。嵌入式系统由于内存资源有限,经常会发生这样的错误。

   3)扩展---unsigned long irqflags值
   在include\linux\interrupt.h中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*
  * These correspond to the IORESOURCE_IRQ_* defines in
  * linux/ioport.h to select the interrupt line behaviour.  When
  * requesting an interrupt without specifying a IRQF_TRIGGER, the
  * setting should be assumed to be "as already configured", which
  * may be as per machine or firmware initialisation.
  */
#define IRQF_TRIGGER_NONE    0x00000000
#define IRQF_TRIGGER_RISING    0x00000001
#define IRQF_TRIGGER_FALLING    0x00000002
#define IRQF_TRIGGER_HIGH    0x00000004
#define IRQF_TRIGGER_LOW    0x00000008
#define IRQF_TRIGGER_MASK    (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
                  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
#define IRQF_TRIGGER_PROBE    0x00000010
/*
  * 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


   Tip:下面是老版本(2.4内核irqflags的值),不要在新版本使用。(2.6 内核及2.6以上内核都为新内核)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
  * Migration helpers. Scheduled for removal in 9/2007
  * Do not use for new code !//不要的新版本使用,2.6 内核及2.6以上内核都为新内核
  */
static  inline
unsigned  long  __deprecated deprecated_irq_flag(unsigned  long  flag)
{
     return  flag;
}
#define SA_INTERRUPT        deprecated_irq_flag(IRQF_DISABLED)
#define SA_SAMPLE_RANDOM    deprecated_irq_flag(IRQF_SAMPLE_RANDOM)
#define SA_SHIRQ        deprecated_irq_flag(IRQF_SHARED)
#define SA_PROBEIRQ        deprecated_irq_flag(IRQF_PROBE_SHARED)
#define SA_PERCPU        deprecated_irq_flag(IRQF_PERCPU)
#define SA_TRIGGER_LOW        deprecated_irq_flag(IRQF_TRIGGER_LOW)
#define SA_TRIGGER_HIGH        deprecated_irq_flag(IRQF_TRIGGER_HIGH)
#define SA_TRIGGER_FALLING    deprecated_irq_flag(IRQF_TRIGGER_FALLING)
#define SA_TRIGGER_RISING    deprecated_irq_flag(IRQF_TRIGGER_RISING)
#define SA_TRIGGER_MASK        deprecated_irq_flag(IRQF_TRIGGER_MASK)

三、使用模板
   使用步骤:以外部中断为例
a)定义结构体,相当于定义(void *dev_id)中的(void *)

1
2
3
4
5
struct pin_desc{ //声明一个引脚描述的结构体pin_desc
        unsigned  int  pin; //引脚值,参考数据手册及板子电路原理图
        unsigned  int  key_val; //值自已随便定义;看自己的项目需要
        //...................
    };

b)实例化结构体,相当于(void *dev_id)中的 dev_id

1
2
3
4
5
struct  pin_desc pins_desc[3] = { //实例化结构体,以jz2440按键为列
        {S3C2410_GPF0, 0x01}, //S3C2410_GPFn在内核中定义好了
        {S3C2410_GPF2, 0x02},
        {S3C2410_GPG3, 0x03},
    };

c)定义中断处理函数

1
2
3
4
5
static  irqreturn_t irq_handle( int  irq,  void  *dev__id){
     struct pin_desc *pindesc = (struct pin_desc *)dev__id;
     //................
     return  IRQ_RETVAL(IRQ_HANDLED); //返回IRQ_HANDLED表示中断已经处理
     }

d)申请中断

1
2
3
request_irq(IRQ_EINT0, irq_handle, IRQ_TYPE_EDGE_BOTH,  "s2" , &pins_desc[0]); //IRQ_EINTn在内核中定义好了
    request_irq(IRQ_EINT2, irq_handle, IRQ_TYPE_EDGE_BOTH,  "s3" , &pins_desc[1]);
    request_irq(IRQ_EINT11, irq_handle, IRQ_TYPE_EDGE_BOTH,  "s4" , &pins_desc[2]);

e)释放内存

1
2
3
free_irq(IRQ_EINT0, &pins_desc[0]);
     free_irq(IRQ_EINT2, &pins_desc[1]);
     free_irq(IRQ_EINT11, &pins_desc[2]);


Tip:可以直接将IRQ_EINTn也在pins_desc定义,然后

1
2
3
4
int  i =  0 ;
    for (i =  0 ; i <  3 ; i++){
    free_irq(pins_desc[i].irqnum, &pins_desc[i]);
    }

   实例见[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作 中的实例(按键中断双边沿触发)



本文转自lilin9105 51CTO博客,原文链接:http://blog.51cto.com/7071976/1392439,如需转载请自行联系原作者

目录
打赏
0
0
0
0
69
分享
相关文章
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
126 67
|
7天前
|
Linux内核中的current机制解析
总的来说,current机制是Linux内核中进程管理的基础,它通过获取当前进程的task_struct结构的地址,可以方便地获取和修改进程的信息。这个机制在内核中的使用非常广泛,对于理解Linux内核的工作原理有着重要的意义。
32 11
Linux 内核源码分析---proc 文件系统
`proc`文件系统是Linux内核中一个灵活而强大的工具,提供了一个与内核数据结构交互的接口。通过本文的分析,我们深入探讨了 `proc`文件系统的实现原理,包括其初始化、文件的创建与操作、动态内容生成等方面。通过对这些内容的理解,开发者可以更好地利用 `proc`文件系统来监控和调试内核,同时也为系统管理提供了便利的工具。
74 16
Intel Linux 内核测试套件-LKVS介绍 | 龙蜥大讲堂104期
《Intel Linux内核测试套件-LKVS介绍》(龙蜥大讲堂104期)主要介绍了LKVS的定义、使用方法、测试范围、典型案例及其优势。LKVS是轻量级、低耦合且高代码覆盖率的测试工具,涵盖20多个硬件和内核属性,已开源并集成到多个社区CICD系统中。课程详细讲解了如何使用LKVS进行CPU、电源管理和安全特性(如TDX、CET)的测试,并展示了其在实际应用中的价值。
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
220 15
深入探索Linux内核的内存管理机制
本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
Linux操作系统的内核优化与性能调优####
本文深入探讨了Linux操作系统内核的优化策略与性能调优方法,旨在为系统管理员和高级用户提供一套实用的指南。通过分析内核参数调整、文件系统选择、内存管理及网络配置等关键方面,本文揭示了如何有效提升Linux系统的稳定性和运行效率。不同于常规摘要仅概述内容的做法,本摘要直接指出文章的核心价值——提供具体可行的优化措施,助力读者实现系统性能的飞跃。 ####
深入探索Linux内核调度机制:公平与效率的平衡####
本文旨在剖析Linux操作系统内核中的进程调度机制,特别是其如何通过CFS(完全公平调度器)算法实现多任务环境下资源分配的公平性与系统响应速度之间的微妙平衡。不同于传统摘要的概览性质,本文摘要将直接聚焦于CFS的核心原理、设计目标及面临的挑战,为读者揭开Linux高效调度的秘密。 ####
89 3
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####