内核驱动 - 中断分层技术

一、背景

Linux系统处理中断响应时,如果有新中断产生,Linux系统对新中断的处理方法与正在处理的中断类型有关,分为慢中断、快中断两种。

慢中断:Linux处理慢中断时,中断总开关是打开的,允许其他中断产生。即会产生中断嵌套

         如,Linux正在处理串口慢速中断,此时网卡产生中断,则CPU会转去处理网卡中断,等到网卡中断执行完毕之后继续执行串口中断;

              如果,正在处理串口慢速中断时,产生了新的串口中断,则CPU就会忽略这次新产生的串口中断,这就导致了一些中断无法得到处理。

二、目的

中断分层技术,可以有效的减少中断丢失的概率。

三、工作方式

中断分层方式:软中断、tasklet、工作队列(主流)

工作队列:是一种将任务推后执行的方式,将推后的任务交由一个内核线程去执行,这样如果在中断函数中使用中断分层(工作队列方式),中断函数的第二部分就会在进程的上下文中得到执行,它允许重新调度甚至睡眠。每个被推后的任务叫做“工作”,由这些工作组成的队列叫做工作队列。


每个CPU下面都会有一个任务链表,被提交的任务就会挂在到任务链表下等待执行。


四、使用方法

step1. 创建工作队列

create_workqueue
step2. 创建工作
INIT_WORK
step3. 提交工作

queue_work

一般情况不需要自己创建工作队列,可以使用内核默认的工作队列keventd_wq 中,

提交工作

schedule_work

五、Key_中断分层 代码下载 点击打开链接
#include <linux/module.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/slab.h>

#define	GPH0CON 0xE0200C00
#define	GPH0DAT 0xE0200C04
#define DEVICE_NAME	"tqkey"


#define	LEDCON 0xE0200060
#define LEDDAT 0xE0200064

volatile unsigned int *led_config;
volatile unsigned int *led_data;

//1、定义工作
struct work_struct *work;

void work_func(struct work_struct *work)
{
	volatile unsigned short data;

	data = readw(led_data);
	if(data == 0)
	{
		data = 0xFF;
	}
	else
	{
		data = 0;
	}
	
	writel(data, led_data);
}

static irqreturn_t key_int(int irq, void *dev_id)
{
	//3、提交下半部至内核默认工作队列keventd_wq 
	schedule_work(work);
	return 0;
}

void key_hw_init(void)
{
	volatile unsigned short data;
	volatile unsigned int *gpio_config;
	gpio_config = (volatile unsigned int *)ioremap(GPH0CON, 4);
	data = readw(gpio_config);		//读出原有寄存器中的值
	data &= ~0x0F;
	data |= 0x0F;
	writew(data, gpio_config);
	printk("key_hw_init!\n");

	
	led_config = (volatile unsigned int *)ioremap(LEDCON, 4);	//物理地址转换为虚拟地址
	writel(0x00011000, led_config);

	led_data = (volatile unsigned int *)ioremap(LEDDAT, 4);
	writel(0xFF, led_data);
}

/*static long key_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	return -EINVAL;
}*/

static int key_open(struct inode *inode, struct file *file)
{
	return 0;
}


static struct file_operations key_fops =
{
	.owner = THIS_MODULE,
	//.unlocked_ioctl = key_ioctl,
	.open = key_open,
	.release = NULL,
};

struct miscdevice key_miscdev = 
{
	.minor = 200,
	.name = DEVICE_NAME,
	.fops = &key_fops,
};

//注册函数
static int __init button_init(void)
{
	int ret = 0;

	misc_register(&key_miscdev);

	//注册中断处理程序
	ret = request_irq(IRQ_EINT0, key_int, IRQF_TRIGGER_FALLING, DEVICE_NAME, 0);

	//硬件初始化
	key_hw_init();

	//2、工作初始化
	work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
	//(注:GFP_KERNEL是内核内存分配时最常用的,无内存可用时可引起休眠)
	INIT_WORK(work, work_func);  //创建工作,关联工作函数
	
	return 0;
}

//注销函数
static void __exit button_exit(void)
{
	misc_deregister(&key_miscdev);

	//注销中断程序
	free_irq(IRQ_EINT0, 0);
}

module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jerry.Gou");
MODULE_DESCRIPTION("TQ210 button driver");



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值