linux设备驱动的中断

1、设备驱动的基本概念

在访问设备时,如果不管设备是否有数据都死等它的数据,那别的设备就得不到访问。
因此在硬件设计中引进了中断机制。
内核中对时钟的处理也采用中断方式,而内核软件定时器最终依赖于时钟中断。
中断处理和进程是CPU上两类完全独立的执行体。中断处理例程和其他代码并发运行
这就讲引起并发问题,对并发控制技术的透彻理解对处理中断来讲是非常重要。


设备中断的到来会打断内核中进程的正常调度和运行。为了在中断执行时间尽可能短
和中断处理需完成大量工作之间找个平衡点,Linux将中断程序分解为顶半部(top half)
和底半部(buttom half)。
top half : 往往只是简单地读取寄存器中的中断状态并清除中断标志后就进行“登记中断”
(挂到底半部执行队列)的工作;
bottom half : 完成中断事件的绝大多数任务。


2、Linux中断编程
 2.1申请和释放中断

使用中断的设备需要申请和释放对应中断(IRQ)。
	1)、申请IRQ 
	申请IRQ,在硬件上体现为关联上了某条中断信号线:
	int request_irq(unsigned int irq,
		irqreturn_t (*handler)(int, void *, struct pt_regs *),
		unsigned long irqflags, const char * devname, void *dev_id)
	
 *	request_irq - allocate an interrupt line
 *	@irq: Interrupt line to allocate
 *	@handler: Function to be called when the IRQ occurs
 *	@irqflags: Interrupt type flags
 *	@devname: An ascii name for the claiming device
 *	@dev_id: A cookie passed back to the handler function
 Flags:
 *
 *	SA_SHIRQ		Interrupt is shared
 *	SA_INTERRUPT		Disable local interrupts while processing
 *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy(如果设备以真正
 随机的周期产生中断,就应该设置该标志位)
 
 request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,
 返回-EBUSY表示中断已经被占用且不能共享。
	2)、释放IRQ	
 void free_irq(unsigned int irq, void *dev_id)
 
 *	free_irq - free an interrupt allocated with request_irq
 *	@irq: Interrupt line to free
 *	@dev_id: Device identity to free
 
 2.2使能和屏蔽中断
 
	屏蔽一个中断源,以下三个函数对系统内所有CPU都生效,其中(1)和(3)的区别在于
 (3)立即返回,而(1)等待目前的中断处理完成。在拥有自旋锁的时候需要阻塞中断,但
 应该注意尽量少禁用中断
	(1) void disable_irq(unsigned int irq)
	
 *	disable_irq - disable an irq and wait for completion
 *	@irq: Interrupt to disable
	
	(2) void enable_irq(unsigned int irq)
	
 *	enable_irq - enable handling of an irq
 *	@irq: Interrupt to enable
 
	(3) void disable_irq_nosync(unsigned int irq)
	
 *	disable_irq_nosync - disable an irq without waiting
 *	@irq: Interrupt to disable
 
 以上三个函数对系统内所有CPU都生效,对于本CPU内的中断屏蔽,
	local_irq_save(flags)
	local_irq_disable(void)
	
	local_irq_restore(flags)
	local_irq_enable(void)
	
3、底半部机制

	底半部的实现机制主要有tasklet、工作队列、和软中断。其中软中断和
tasklet处理函数中不能休眠,而工作队列处理函数中允许休眠,中断处理程序
的一个典型任务是:如果中断通知进程所等待的事件已经发生,比如新的数
据到达,就会唤醒该设备上休眠的进程。	
 3.1tasklet
	所有tasklet代码都必须是原子的。
 
	/* Set up our tasklet if we're doing that. */
	void xxx_do_tasklet(unsigned long); /*定义一个处理函数*/
	/*定义一tasklet结构xxx_tasklet,与xxx_do_tasklet函数关联*/
	DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);
	
	调度指定的tasklet函数:
	tasklet_schedule(&xxx_tasklet);  /*调度一个tasklet运行*/
	
	使用tasklet作为底半部处理中断的设备驱动程序模板:	
	//定义tasklet和底半部函数并关联	
	void xxx_do_tasklet(unsigned long); /*定义一个处理函数*/
	/*定义一tasklet结构xxx_tasklet,与xxx_do_tasklet函数关联*/
	DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);
	
	//中断处理底半部
	void xxx_do_tasklet(unsigned long)
	{
		....
	}
	
	//中断处理底半部
	irqreturn_t xxx_interrupt(int irq, void *dev_id)
	{
		....
		tasklet_schedule(&xxx_tasklet);
		....
	}
	
	//设备驱动模块加载函数
	int __init xxx_init(void)
	{
		...
		申请中断
		result = request_irq(short_irq, short_interrupt,
				0x0, "xxx", NULL);
		...
	}

	//设备驱动模块卸载函数
	int __exit xxx_exit(void)
	{
		...
		free_irq(xxx_irq, xxx_interrupt);
		...
	}
	
3.2工作队列
	可以具有高的延迟,但允许休眠。
	
	static struct work_struct xxx_wq; //定义一个工作队列
	irqreturn_t xxx_wq_interrupt(int irq, void *dev_id) //定义一个处理函数
	//初始化工作队列,并将工作队列与处理函数绑定
	INIT_WORK(&xxx_wq, (void (*)(struct work_struct *)) xxx_do_tasklet);
	schedule_work(&xxx_wq);
	
	用工作队列处理中断底半部的设备驱动程序模板
	//定义工作队列
	static struct work_struct xxx_wq;
	void xxx_do_work(unsigned long);	
	
	//中断处理底半部
	void xxx_do_work(unsigned long)
	{
		....
	}
	
	//中断处理底半部
	irqreturn_t xxx_interrupt(int irq, void *dev_id)
	{
		....
		schedule_work(&xxx_work);
		....
	}
	
	//设备驱动模块加载函数
	int __init xxx_init(void)
	{
		...
		申请中断
		result = request_irq(short_irq, short_interrupt,
				0x0, "xxx", NULL);
		...
		
		INIT_WORK(&xxx_wq, (void (*)(struct work_struct *)) xxx_do_tasklet);
		...
	}

	//设备驱动模块卸载函数
	int __exit xxx_exit(void)
	{
		...
		free_irq(xxx_irq, xxx_interrupt);
		...
	}
	




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值