初识中断

由于I/O操作的不确定因素以及处理器和I/O设备之间速度的不匹配(I/O设备的速度要比处理器慢很多),设备往往通过某种硬件信号异步地唤醒起处理器的注意。这些硬件信号就是中断。每个中断设备都被分配了一个相关的标识符,被称为中断请求(IRQ)号。当处理器检测到某一IRQ号对应的中断产生时,它将停止现在的工作,并启动该IRQ所对应的中断服务例程(ISR)。中断处理函数在中断上下文执行。

模块在使用中断前要先请求一个中断通道(或者中断请求IRQ),然后在使用后释放该通道。

可以在kernel-4.9\include\linux\interrupt.h找到它们的定义:

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);
}


/**
 *	request_threaded_irq - allocate an interrupt line
 *	@irq: Interrupt line to allocate
 *	@handler: Function to be called when the IRQ occurs.
 *		  Primary handler for threaded interrupts
 *		  If NULL and thread_fn != NULL the default
 *		  primary handler is installed
 *	@thread_fn: Function called from the irq handler thread
 *		    If NULL, no irq thread is created
 *	@irqflags: Interrupt type flags
 *	@devname: An ascii name for the claiming device
 *	@dev_id: A cookie passed back to the handler function
 *
 *	This call allocates interrupt resources and enables the
 *	interrupt line and IRQ handling. From the point this
 *	call is made your handler function may be invoked. Since
 *	your handler function must clear any interrupt the board
 *	raises, you must take care both to initialise your hardware
 *	and to set up the interrupt handler in the right order.
 *
 *	If you want to set up a threaded irq handler for your device
 *	then you need to supply @handler and @thread_fn. @handler is
 *	still called in hard interrupt context and has to check
 *	whether the interrupt originates from the device. If yes it
 *	needs to disable the interrupt on the device and return
 *	IRQ_WAKE_THREAD which will wake up the handler thread and run
 *	@thread_fn. This split handler design is necessary to support
 *	shared interrupts.
 *
 *	Dev_id must be globally unique. Normally the address of the
 *	device data structure is used as the cookie. Since the handler
 *	receives this value it makes sense to use it.
 *
 *	If your interrupt is shared you must pass a non NULL dev_id
 *	as this is required when freeing the interrupt.
 *
 *	Flags:
 *
 *	IRQF_SHARED		Interrupt is shared
 *	IRQF_TRIGGER_*		Specify active edge(s) or level
 *
 */
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)

通常,reques_irq函数返回给请求函数的值为0时表示申请成功,为负值时表示错误码。函数返回-EBUSY表示已经有另一个驱动程序占用了你要请求的中断信号线。

参数irq是要请求的中断号;

handler是向系统注册的中断处理函数,是一个回调函数,中断发生时系统调用这个函数;

flags是中断处理相关的一个位掩码;

      SA_INTERRUPT/IRQF_DISABLED:表明这是一个快速中断处理例程。快速中断处理例程运行在中断的禁用状态下。

      SA_SHIRQ/IRQF_SHARED:表明中断可以在设备之间共享。

      SA_SAMPLE_RANDOM/IRQF_SAMPLE_RANDOM:表明产生中断能对/dev/random设备和/dev/urandom设备使用的熵池有贡献。从这些设备读取,将会返回真正的随机数,从而有助于应用软件选择用于加密的安全秘钥。这些随机数是从一个熵池中得到的,各种随机事件都会对该熵池作出贡献,

name是会中断的名字,用来在/proc/interrupts中显示中断的拥有者;

dev是用于共享的中断信号线。它是唯一的标识符,在中断信号线空闲时可以使用它,驱动程序也可以使用它指向驱动程序自己的私有数据区(用来识别哪个设备产生中断)。在没有强制使用共享方式时,dev可以被设置为NULL,总之用它来指向设备的数据结构是一个比较好的思路。

 

free_irq的参数

/**
 *	free_irq - free an interrupt allocated with request_irq
 *	@irq: Interrupt line to free
 *	@dev_id: Device identity to free
 *
 *	Remove an interrupt handler. The handler is removed and if the
 *	interrupt line is no longer in use by any driver it is disabled.
 *	On a shared IRQ the caller must ensure the interrupt is disabled
 *	on the card it drives before calling this function. The function
 *	does not return until any executing interrupts for this IRQ
 *	have completed.
 *
 *	This function must not be called from interrupt context.
 */
void free_irq(unsigned int irq, void *dev_id)

 

中断处理例程可在驱动程序初始化时或设备第一次打开时安装。虽然在模块的初始化函数中安装中断处理例程看起来是个好主意,但实际上并非如此。因为中断信号线的数量是非常有限的,我们不想肆意浪费。计算机拥有的设备通常要比中断信号线多得多,如果一个模块在初始化时请求了IRQ,那么即使驱动程序只是占用它而从未使用,也将会阻止任意一个其他的驱动程序使用该中断。而在设备打开的时候申请中断,则可以共享这些有限的资源。

因此,调用request_irq的正确位置应该是在设备第一次打开、硬件被告知产生中断之前。调用free_irq的位置是最后一次关闭设备、硬件被告知不再中断处理器之后。这种技术的缺点是必须为每一个设备维护一个打开计数,这样我们才能知道什么时候可以禁用中断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值