Linux驱动学习记录-12.Linuxgpio中断

本文详细介绍了Linux中断处理,包括API函数如request_irq和free_irq的使用,中断处理函数的定义,以及如何使能和禁止中断。此外,还阐述了上半部和下半部的概念,软中断、tasklet和工作队列的应用。同时,讲解了设备树中断节点配置,并提供了获取中断号的方法。最后,讨论了驱动程序中中断处理的相关实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里介绍imx6u的重点,配置寄存器,设置服务中断函数。

一、中断API函数

每个中断都有一个中断号,linux有一个int变量表示中断号。

1.申请中断

int request_irq( unsigned int irq,
			   	irq_handler_t  handler,
				unsigned long flags,
				const char *name, 		
				void *dev)
  • irq: 要申请的中断号
  • handler: 中断处理函数
  • flags:中断标志
  • name: 中断名字,自己设置
  • dev: 一般是设备结构体,
  • return : 0申请成功,负值申请失败

2.释放中断

coid free_irq(unsigned int irq,
			  void *dev)
  • irq:要释放从中断
  • dev:设备结构体

3.中断处理函数

irqreturn_t (*irq_handler) (int, void *)
  • 参数一:中断处理函数要处理的中断号
  • 参数二:指向void的指针,需要与dev参数一致。
  • 返回值:枚举类型
enum irqreturn{
	IRQ_NONE        = (0<<0),
	IRQ_HANDLED     = (1<<0),
	IRQ_WAKE_THREAD = (1<<1), 
};
typedef enum irqretuen irqreturn_t;

4.使能和禁止

void enable_irq(unsigned int irq)
void diasble_irq(unsigned int irq)

输入为要处理的中断号,禁止中断会等到当前正在执行的中断处理函数执行完后才返回。即可能在处理函数中又被其他中断打断。不是立即禁止。

void disable_irq_nosync(unsigned int irq);

此函数调用后立即返回,不用等中断处理函数执行完。

local_irq_enable()
local_irq_disable()

用于全局中断的禁止和打开。

local_irq_save(flags)
local_irq_restore(flags)

这两个函数和上面一样,不过可以保存中断状态在flags。

二、上半部和下半部

Linux内核中断分为上半部和下半部的目的就是实现中断函数的快进快出,对时间敏感、执行速度快的操作放在上半部,时间长的放在下半部。
1.如果要处理的内容不希望被中断打断,放在上半部
2.处理的任务对时间敏感,放在上半部
3.处理的任务与硬件有关,放在上半部
4.其他任务,优先考虑放在下半部

1.软中断

struct softirq_action{
void (*action) (struct softirq_action *);
};

注册软中断处理函数

void open_softirq(int nr, void (*action)(struct softirq_action *))
  • nr:要开启的软中断
  • action:对应的处理函数
    注册好后需要激活
void raise_softirq(unsigned int nr)

软中断必须在编译的时候静态注册

void __init softirq_init(void)
{}

2.tasklet

tasklet是利用软中断实现的另一种下半部机制,建议使用tasklet

struct tasklet_struct{
	struct tasklet_struct  *next,     /*下一个tasklet*/
	unsigned long state,              /*tasklet状态*/
	atomic_t count,                   /*计数器,对tasklet的引用*/
	void (*func) (unsigned long),     /*执行的函数*/
	unsigned long data,               /*函数func的参数*/
};

如果要使用tasklet,需要先定义,再初始化:

void tasklet_init(struct tasklet_struct *t,  //要初始化的tasklet
				  void (*func)(unsigned long),      //处理函数  自定义
				  unsigned long data);              //输入函数的数据

可用下面一次性完成tasklet的初始化和定义

DECLARE_TASKLET(name, func, data)

初始化之后还没激活,需要在中断服务函数中调用函数

void tasklet_schedule(struct tasklet_struct *t)

使得tasklet在合适的时间开始运行
使用实例:

//定义
struct tasklet_struct  test;
//tasklet处理函数
void test_func(unsigned long data)
{
}
//中断服务函数
irqreturn_t test_handler(int irq, void *dev_id)
{
	//激活tasklet
	tasklet_schedule(&test);
}
//驱动入口
static int __init irq_init(void)
{
	tasklet_init(&test, test_func, data);  //初始化tasklet
	request_irq(XXX_irq, test_handler, 0, "xxx", &xxx_dev); //注册中断处理函数
}

3.工作队列

是下半部的另一种执行方式,如果你要推后的工作可以睡眠就选择工作队列,否则只能选择软中断或tasklet:

struct work_struct{
	atomic_long_t  data;
	atruct list_head entry;
	work_func_t  func;
};

每个worker对应一个队列,创建工作挺简单,和tasklet类似,先定义结构体,再初始化,再激活即可

#define INIT_WORK(_work, _func)  //初始化

bool schedule_work (struct work_struct *work) //激活

工作列表实例和上面tasklet类似,不做说明

三、设备树中断节点

linux通过读取设备树中断属性来配置中断
用一个例子来解释

gpio5: gpio@020ac000 {
				compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
				reg = <0x020ac000 0x4000>;
				interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
					     <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
				gpio-controller;
				#gpio-cells = <2>;
				interrupt-controller;
				#interrupt-cells = <2>;
			};

第四行表示,中断类型是SPI,出发电平都是IRQ_TYPE_LEVEL_HIGH,不过中断源分别是74、75,74是前16位,75是后16位。
第八行表示,interrupt-controller节点为空,为中断控制器
第九行表示,此中断控制器下的cells大小,为2

fxls8471@le {
	compatible = "fsl, fxls8471";
	reg = <0x1e>;
	position = <0>;
	interrupt-parent = <&gpio5>;
	interrupts = <0 8>;
};

第五行设置中断控制器,使用gpio5
第六行设置中断信息,0表示GPIO5——IO00, 8是低电平触发。
(为1上升沿触发,2下降沿触发,4高电平触发,8低电平触发)

四、获取中断号

unsigned int ire_of_parse_and_map(struct device_node  *dev, //设备节点
									int  index)             //索引号
									//返回 中断号
int gpio_to_irq(unsigned int gpio)//要获取的gpio编号
//返回 GPIO对应的中断号

第一个函数可以从interupts属性中,提取对应的设备号。
第二个函数来获取gpio对应的中断号

五、驱动程序

见下章

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值