linux 中断返回值作用,Linux内核中断之中断申请接口

本文基于RockPI 4A单板Linux4.4内核介绍中断申请的常用接口函数。

一、request_threaded_irq()

1、文件

kernel/irq/manage.c

2、定义

int request_threaded_irq(unsigned int irq, irq_handler_t handler,

irq_handler_t thread_fn, unsigned long irqflags,

const char *devname, void *dev_id)

{

...

## 此处解释了共享中断和dev_id的关系

/*

* Sanity-check: shared interrupts must pass in a real dev-ID,

* otherwise we'll have trouble later trying to figure out

* which interrupt is which (messes up the interrupt freeing

* logic etc).

*

* Also IRQF_COND_SUSPEND only makes sense for shared interrupts and

* it cannot be set along with IRQF_NO_SUSPEND.

*/

if (((irqflags & IRQF_SHARED) && !dev_id) ||

(!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) ||

((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND)))

return -EINVAL;

## 获取irq描述符

desc = irq_to_desc(irq);

...

action->handler = handler;

action->thread_fn = thread_fn;

action->flags = irqflags;

action->name = devname;

action->dev_id = dev_id;

...

## 把描述符加入到IRQ链表,完成中断的动态申请及注册。后续介绍

retval = __setup_irq(irq, desc, action);

...

}

说明:

1)、irq:要申请的中断号,可通过platform_get_irq()获取,见“Linux内核中断之获取中断号”。

2)、handler:中断处理函数,发生中断时,先处理中断处理函数,然后返回IRQ_WAKE_THREAD唤醒中断处理线程。中断处理函数尽可能简单。

中断处理函数定义:typedef irqreturn_t (*irq_handler_t)(int, void *);

中断返回值如下:

/**

* enum irqreturn

* @IRQ_NONE interrupt was not from this device or was not handled

* @IRQ_HANDLED interrupt was handled by this device

* @IRQ_WAKE_THREAD handler requests to wake the handler thread

*/

enum irqreturn {

IRQ_NONE = (0 << 0), ## 不是该设备中断或中断未处理

IRQ_HANDLED = (1 << 0), ## 中断已处理

IRQ_WAKE_THREAD = (1 << 1), ## 唤醒中断处理线程

};

3)、thread_fn:中断处理线程,该参数可为NULL。类似于中断处理函数的下半部分。

4)、irqflags:中断类型标志。

定义文件:include/linux/interrupt.h,内容如下:

#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_SHARED 0x00000080 ## 多设备共享中断

...

5)、devname:中断名称,可使用cat /proc/interrupts命令查看。

6)、dev_id:设备ID,该值唯一。

在使用共享中断时(即设置IRQF_SHARED),必须传入dev_id,在中断处理和释放函数中都会使用该参数。

注:

1、request_threaded_irq()函数可替代request_irq加tasklet或workqueue的方式。

2、对应的中断释放函数为:void free_irq(unsigned int, void *),需要和中断申请函数成对出现。

二、request_irq()

1、文件

include/linux/interrupt.h

2、定义

static inline int __must_check

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,

const char *name, void *dev)

{

return request_threaded_irq(irq, handler, NULL, flags, name, dev);

}

说明:

1)、__must_check:指调用函数一定要处理函数的返回值,否则编译器会给出警告。

2)、request_irq()函数本质上是中断处理线程thread_fn为空的request_threaded_irq()函数。

注:

对应的中断释放函数为:void free_irq(unsigned int, void *),需要和中断申请函数成对出现。

三、devm_request_threaded_irq()

1、文件

kernel/irq/devres.c

2、定义

int devm_request_threaded_irq(struct device *dev, unsigned int irq,

irq_handler_t handler, irq_handler_t thread_fn,

unsigned long irqflags, const char *devname,

void *dev_id)

{

...

## 1.申请设备资源

dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres),

GFP_KERNEL);

...

## 2.调用request_threaded_irq()函数

rc = request_threaded_irq(irq, handler, thread_fn, irqflags, devname,

dev_id);

...

## 3.添加到设备资源列表中

devres_add(dev, dr);

...

}

说明:

devm_request_threaded_irq()本质上还是使用request_threaded_irq()函数实现中断申请。

两者区别:

1)多了一个dev参数;

2)在设备驱动卸载时,中断会自动释放;

3)如果想单独释放中断,可使用void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id)函数。

四、devm_request_irq()

1、文件

include/linux/interrupt.h

2、定义

static inline int __must_check

devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,

unsigned long irqflags, const char *devname, void *dev_id)

{

return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags,

devname, dev_id);

}

devm_request_irq()函数本质上是中断处理线程thread_fn为空的devm_request_threaded_irq()函数。

五、代码举例

1、获取中断号

static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,

void *data)

{

...

## 从dts中获取中断号,irq返回值为55

irq = platform_get_irq(pdev, 0);

if (irq < 0)

return irq;

...

ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);

...

}

2、申请中断

int dw_hdmi_bind(struct device *dev, struct device *master,

void *data, struct drm_encoder *encoder,

struct resource *iores, int irq,

const struct dw_hdmi_plat_data *plat_data)

{

...

## 申请中断,使用的是IRQF_SHARED,dev_id必须传入参数

ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,

dw_hdmi_irq, IRQF_SHARED,

dev_name(dev), hdmi);

...

}

3、中断处理函数

static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)

{

...

irqreturn_t ret = IRQ_NONE; ## 中断返回值

...

intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);

if (intr_stat) {

hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);

return IRQ_WAKE_THREAD; ## 中断返回值,唤醒中断处理线程

}

...

return ret;

}

4、中断处理线程

static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)

{

struct dw_hdmi *hdmi = dev_id;

...

hdcp_stat = hdmi_readb(hdmi, HDMI_A_APIINTSTAT);

if (hdcp_stat) {

if (hdmi->hdcp && hdmi->hdcp->hdcp_isr)

hdmi->hdcp->hdcp_isr(hdmi->hdcp, hdcp_stat);

hdmi_writeb(hdmi, hdcp_stat, HDMI_A_APIINTCLR);

hdmi_writeb(hdmi, 0x00, HDMI_A_APIINTMSK);

}

return IRQ_HANDLED; ## 中断已处理

}

5、查看中断

root@linaro-alip:~# cat /proc/interrupts

CPU0 CPU1 CPU2 CPU3 CPU4 CPU5

14: 0 0 0 0 0 0 GICv3 29 Edge arch_timer

15: 14722 1928 1966 1848 3725 4894 GICv3 30 Edge arch_timer

...

55: 0 0 0 0 0 0 GICv3 55 Level ff940000.hdmi, dw-hdmi-cec

...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值