Linux驱动知识:中断

时间:2022-04-04 02:37:14

常用函数和宏定义

These symbols related to interrupt management were introduced in this chapter:

#include <linux/interrupt.h>
int request_irq(unsigned int irq, irqreturn_t (*handler)( ), unsigned long flags, const char *dev_name, void *dev_id);
void free_irq(unsigned int irq, void *dev_id);

Calls that register and unregister an interrupt handler.

dev_name为显示在/proc/interrupts中的名字

dev_id为回调中断处理程序时所给的参数,通常为本地dev结构的地址指针。

 

#include <linux/irq.h.h>
int can_request_irq(unsigned int irq, unsigned long flags);

This function, available on the i386 and x86_64 architectures, returns a nonzero value if an attempt to allocate the given interrupt line succeeds.

 

#include <asm/signal.h>

SA_INTERRUPT
SA_SHIRQ
SA_SAMPLE_RANDOM

Flags for request_irq. SA_INTERRUPT requests installation of a fast handler (as opposed to a slow one). SA_SHIRQ installs a shared handler, and the third flag asserts that interrupt timestamps can be used to generate system entropy.

Modern hardware, of course, has been designed to allow the sharing of interrupts; the PCI bus requires it.

 

/proc/interrupts

/proc/stat

Filesystem nodes that report information about hardware interrupts and installed handlers.

 

unsigned long probe_irq_on(void);
int probe_irq_off(unsigned long);

Functions used by the driver when it has to probe to determine which interrupt line is being used by a device. The result of probe_irq_onmust be passed back to probe_irq_off after the interrupt has been generated. The return value of probe_irq_off is the detected interrupt number.

The programmer should be careful to enable interrupts on the device after the call to probe_irq_on and to disable them before callingprobe_irq_off

 

IRQ_NONE
IRQ_HANDLED
IRQ_RETVAL(int x)

The possible return values from an interrupt handler, indicating whether an actual interrupt from the device was present.

 

void disable_irq(int irq);        //关中断且等待当前的中断处理程序完成
void disable_irq_nosync(int irq); //不等待,有风险
void enable_irq(int irq);

A driver can enable and disable interrupt reporting. If the hardware tries to generate an interrupt while interrupts are disabled, the interrupt is lost forever. A driver using a shared handler must not use these functions.

 

void local_irq_save(unsigned long flags);
void local_irq_restore(unsigned long flags);

Use local_irq_save to disable interrupts on the local processor and remember their previous state. The flags can be passed to local_irq_restore to restore the previous interrupt state.

 

void local_irq_disable(void);
void local_irq_enable(void);

Functions that unconditionally disable and enable interrupts on the current processor.

上下半区

规范的驱动处理一般都分上下半区,上半区为注册的中断处理函数,快速响应中断,关中断,并激活下半区。

下半区处理较耗时的任务,并允许中断,由tasklet或workqueue实现。

tasklet代码必须是原子的,而workqueue则允许睡眠。

tasklet在软中断中被执行。

DECLARE_TASKLET(name, function, data);
tasklet_schedule(&tasklet_name);

在某次tasklet被执行之前,所有schedule都是不可累积的,也就是说不管被schedule多少次,taskletk并不会被执行多次。

workqueue在专门的work process上下文中被执行。因为是process,所以可以sleep,但是不能向user space传送数据。

static struct work_struct wq;
INIT_WORK(&wq, (void (*)(void *)) do_workqueue, NULL);

schedule_work(&wq);