Linux中断处理(二)

该文详细介绍了Linux中断处理中的上半部和下半部概念,以及基于软中断的tasklet和基于内核线程的工作队列(workqueue)机制。文中给出了按键驱动的示例,展示了如何使用tasklet和workqueue来处理中断事件,强调了两者在是否可以睡眠和执行时间上的区别。
摘要由CSDN通过智能技术生成

目录

五、上半部与下半部

六、下半部机制之tasklet ---- 基于软中断

6.1 结构体

6.2 定义tasklet的中断底半部处理函数

6.3 初始化tasklet

6.4 调度tasklet

七、按键驱动之tasklet版

八、下半部机制之workqueue  ----- 基于内核线程

8.1 工作队列结构体:

8.2 定义工作队列底半部处理函数

8.3 初始化工作队列

8.4 工作队列的调度函数

九、按键驱动之workqueue版

十、下半部机制比较


五、上半部与下半部

为什么中断需要分为上(顶)半部和下(底)半部?上半部和下半部的运行环境有什么区别?软中断 tasklet 工作队列_举世无双勇的博客-CSDN博客_中断为什么要区分上半部和下半部

起源:

1. 中断处理程序执行时间过长引起的问题(中断太长给用户的感觉就是一卡一卡的)

2. 有些设备的中断处理程序必须要处理一些耗时操作

(直接用软中断就能实现,或者用定时器,但是定时器也是基于软中断的。直接用软中断需要对汇编很熟用汇编写。)

六、下半部机制之tasklet ---- 基于软中断

6.1 结构体

struct tasklet_struct

{

​   struct tasklet_struct *next;

​   unsigned long state;

​   atomic_t count;

​   void (*func)(unsigned long);

​   unsigned long data;

};

6.2 定义tasklet的中断底半部处理函数

void tasklet_func(unsigned long data);

6.3 初始化tasklet

```c

DECLARE_TASKLET(name, func, data);

/*

定义变量并初始化

参数:name:中断底半部tasklet的名称

     Func:中断底半部处理函数的名字

     data:给中断底半部处理函数传递的参数

*/

```

```c

void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)

```

6.4 调度tasklet

```c

void tasklet_schedule(struct tasklet_struct *t)

//参数:t:tasklet的结构体

```

七、按键驱动之tasklet版

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#include "fs4412_key.h"


int major = 11;
int minor = 0;
int fs4412key2_num  = 1;

struct fs4412key2_dev
{
	struct cdev mydev;

	int gpio;
	int irqno;

	struct keyvalue data;
	int newflag;
	spinlock_t lock;

	wait_queue_head_t rq;

	struct tasklet_struct tsk;
};

struct fs4412key2_dev *pgmydev = NULL;

int fs4412key2_open(struct inode *pnode,struct file *pfile)
{
	pfile->private_data =(void *) (container_of(pnode->i_cdev,struct fs4412key2_dev,mydev));
	return 0;
}

int fs4412key2_close(struct inode *pnode,struct file *pfile)
{

	return 0;
}

ssize_t fs4412key2_read(struct file *pfile,char __user *puser,size_t count,loff_t *p_pos)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)pfile->private_data;
	int size = 0;
	int ret = 0;

	if(count < sizeof(struct keyvalue))
	{
		printk("expect read size is invalid\n");
		return -1;
	}

	spin_lock(&pmydev->lock);
	if(!pmydev->newflag)
	{
		if(pfile->f_flags & O_NONBLOCK)
		{//非阻塞
			spin_unlock(&pmydev->lock);
			printk("O_NONBLOCK No Data Read\n");
			return -1;
		}
		else
		{//阻塞
			spin_unlock(&pmydev->lock);
			ret = wait_event_interruptible(pmydev->rq,pmydev->newflag == 1);
			if(ret)
			{
				printk("Wake up by signal\n");
				return -ERESTARTSYS;
			}
			spin_lock(&pmydev->lock);
		}
	}

	if(count > sizeof(struct keyvalue))
	{
		size = sizeof(struct keyvalue);
	}
	else
	{
		size = count;
	}

	ret = copy_to_user(puser,&pmydev->data,size);
	if(ret)
	{
		spin_unlock(&pmydev->lock);
		printk("copy_to_user failed\n");
		return -1;
	}

	pmydev->newflag = 0;

	spin_unlock(&pmydev->lock);

	return size;
}

unsigned int fs4412key2_poll(struct file *pfile,poll_table *ptb)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)pfile->private_data;
	unsigned int mask = 0;

	poll_wait(pfile,&pmydev->rq,ptb);

	spin_lock(&pmydev->lock);
	if(pmydev->newflag)
	{
		mask |= POLLIN | POLLRDNORM;
	}
	spin_unlock(&pmydev->lock);

	return mask;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = fs4412key2_open,
	.release = fs4412key2_close,
	.read = fs4412key2_read,
	.poll = fs4412key2_poll,
};

irqreturn_t key2_irq_handle(int no,void *arg)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;

	tasklet_schedule(&pmydev->tsk);

	return IRQ_HANDLED;
}

void bottom_irq_func(unsigned long arg)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;
	int status1 = 0;
	int status2 = 0;
	int status = 0;

	status1 = gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2 = gpio_get_value(pmydev->gpio);

	if(status1 != status2)
	{
		return;
	}

	status = status1;

	spin_lock(&pmydev->lock);
	if(status == pmydev->data.status)
	{
		spin_unlock(&pmydev->lock);
		return;
	}

	pmydev->data.code = KEY2;
	pmydev->data.status = status;
	pmydev->newflag = 1;

	spin_unlock(&pmydev->lock);
	wake_up(&pmydev->rq);

	return;
}

int __init fs4412key2_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);

	struct device_node *pnode = NULL;

	pnode = of_find_node_by_path("/mykey2_node");
	if(NULL == pnode)
	{
		printk("find node failed\n");
		return -1;
	}


	pgmydev = (struct fs4412key2_dev *)kmalloc(sizeof(struct fs4412key2_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmallc for struct fs4412key2_dev failed\n");
		return -1;
	}

	pgmydev->gpio = of_get_named_gpio(pnode,"key2-gpio",0);

	pgmydev->irqno = irq_of_parse_and_map(pnode,0);

	/*申请设备号*/
	ret = register_chrdev_region(devno,fs4412key2_num,"fs4412key2");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,fs4412key2_num,"fs4412key2");
		if(ret)
		{
			kfree(pgmydev);
			pgmydev = NULL;
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);//容易遗漏,注意
	}

	/*给struct cdev对象指定操作函数集*/	
	cdev_init(&pgmydev->mydev,&myops);

	/*将struct cdev对象添加到内核对应的数据结构里*/
	pgmydev->mydev.owner = THIS_MODULE;
	cdev_add(&pgmydev->mydev,devno,fs4412key2_num);


	init_waitqueue_head(&pgmydev->rq);

	spin_lock_init(&pgmydev->lock);

	tasklet_init(&pgmydev->tsk,bottom_irq_func,(unsigned long)pgmydev);
	
	ret = request_irq(pgmydev->irqno,key2_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key2",pgmydev);
	if(ret)
	{
		printk("request_irq failed\n");
		cdev_del(&pgmydev->mydev);
		kfree(pgmydev);
		pgmydev = NULL;
		unregister_chrdev_region(devno,fs4412key2_num);
		return -1;
	}
	return 0;
}

void __exit fs4412key2_exit(void)
{
	dev_t devno = MKDEV(major,minor);

	free_irq(pgmydev->irqno,pgmydev);

	cdev_del(&pgmydev->mydev);

	unregister_chrdev_region(devno,fs4412key2_num);

	kfree(pgmydev);
	pgmydev = NULL;
}


MODULE_LICENSE("GPL");

module_init(fs4412key2_init);
module_exit(fs4412key2_exit);

上面是key2下面是key3

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#include "fs4412_key.h"


int major = 11;
int minor = 0;
int fs4412key3_num  = 1;

struct fs4412key3_dev
{
	struct cdev mydev;

	int gpio;
	int irqno;

	struct keyvalue data;
	int newflag;
	spinlock_t lock;

	wait_queue_head_t rq;

	struct tasklet_struct tsk;
};

struct fs4412key3_dev *pgmydev = NULL;

int fs4412key3_open(struct inode *pnode,struct file *pfile)
{
	pfile->private_data =(void *) (container_of(pnode->i_cdev,struct fs4412key3_dev,mydev));
	return 0;
}

int fs4412key3_close(struct inode *pnode,struct file *pfile)
{

	return 0;
}

ssize_t fs4412key3_read(struct file *pfile,char __user *puser,size_t count,loff_t *p_pos)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)pfile->private_data;
	int size = 0;
	int ret = 0;

	if(count < sizeof(struct keyvalue))
	{
		printk("expect read size is invalid\n");
		return -1;
	}

	spin_lock(&pmydev->lock);
	if(!pmydev->newflag)
	{
		if(pfile->f_flags & O_NONBLOCK)
		{//非阻塞
			spin_unlock(&pmydev->lock);
			printk("O_NONBLOCK No Data Read\n");
			return -1;
		}
		else
		{//阻塞
			spin_unlock(&pmydev->lock);
			ret = wait_event_interruptible(pmydev->rq,pmydev->newflag == 1);
			if(ret)
			{
				printk("Wake up by signal\n");
				return -ERESTARTSYS;
			}
			spin_lock(&pmydev->lock);
		}
	}

	if(count > sizeof(struct keyvalue))
	{
		size = sizeof(struct keyvalue);
	}
	else
	{
		size = count;
	}

	ret = copy_to_user(puser,&pmydev->data,size);
	if(ret)
	{
		spin_unlock(&pmydev->lock);
		printk("copy_to_user failed\n");
		return -1;
	}

	pmydev->newflag = 0;

	spin_unlock(&pmydev->lock);

	return size;
}

unsigned int fs4412key3_poll(struct file *pfile,poll_table *ptb)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)pfile->private_data;
	unsigned int mask = 0;

	poll_wait(pfile,&pmydev->rq,ptb);

	spin_lock(&pmydev->lock);
	if(pmydev->newflag)
	{
		mask |= POLLIN | POLLRDNORM;
	}
	spin_unlock(&pmydev->lock);

	return mask;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = fs4412key3_open,
	.release = fs4412key3_close,
	.read = fs4412key3_read,
	.poll = fs4412key3_poll,
};

irqreturn_t key3_irq_handle(int no,void *arg)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)arg;

	tasklet_schedule(&pmydev->tsk);

	return IRQ_HANDLED;
}

void bottom_irq_func(unsigned long arg)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)arg;
	int status1 = 0;
	int status2 = 0;
	int status = 0;

	status1 = gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2 = gpio_get_value(pmydev->gpio);

	if(status1 != status2)
	{
		return;
	}

	status = status1;

	spin_lock(&pmydev->lock);
	if(status == pmydev->data.status)
	{
		spin_unlock(&pmydev->lock);
		return;
	}

	pmydev->data.code = KEY3;
	pmydev->data.status = status;
	pmydev->newflag = 1;

	spin_unlock(&pmydev->lock);
	wake_up(&pmydev->rq);

	return;
}

int __init fs4412key3_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);

	struct device_node *pnode = NULL;

	pnode = of_find_node_by_path("/mykey3_node");
	if(NULL == pnode)
	{
		printk("find node failed\n");
		return -1;
	}


	pgmydev = (struct fs4412key3_dev *)kmalloc(sizeof(struct fs4412key3_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmallc for struct fs4412key3_dev failed\n");
		return -1;
	}

	pgmydev->gpio = of_get_named_gpio(pnode,"key3-gpio",0);

	pgmydev->irqno = irq_of_parse_and_map(pnode,0);

	/*申请设备号*/
	ret = register_chrdev_region(devno,fs4412key3_num,"fs4412key3");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,fs4412key3_num,"fs4412key3");
		if(ret)
		{
			kfree(pgmydev);
			pgmydev = NULL;
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);//容易遗漏,注意
	}

	/*给struct cdev对象指定操作函数集*/	
	cdev_init(&pgmydev->mydev,&myops);

	/*将struct cdev对象添加到内核对应的数据结构里*/
	pgmydev->mydev.owner = THIS_MODULE;
	cdev_add(&pgmydev->mydev,devno,fs4412key3_num);


	init_waitqueue_head(&pgmydev->rq);

	spin_lock_init(&pgmydev->lock);

	tasklet_init(&pgmydev->tsk,bottom_irq_func,(unsigned long)pgmydev);
	
	ret = request_irq(pgmydev->irqno,key3_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key3",pgmydev);
	if(ret)
	{
		printk("request_irq failed\n");
		cdev_del(&pgmydev->mydev);
		kfree(pgmydev);
		pgmydev = NULL;
		unregister_chrdev_region(devno,fs4412key3_num);
		return -1;
	}
	return 0;
}

void __exit fs4412key3_exit(void)
{
	dev_t devno = MKDEV(major,minor);

	free_irq(pgmydev->irqno,pgmydev);

	cdev_del(&pgmydev->mydev);

	unregister_chrdev_region(devno,fs4412key3_num);

	kfree(pgmydev);
	pgmydev = NULL;
}


MODULE_LICENSE("GPL");

module_init(fs4412key3_init);
module_exit(fs4412key3_exit);

 

八、下半部机制之workqueue  ----- 基于内核线程

(workqueue不是基于软中断的)

8.1 工作队列结构体:

typedef void (*work_func_t)(struct work_struct  *work)



struct work_struct {



​       atomic_long_t data;



​       struct list_head entry;



​       work_func_t func;



\#ifdef CONFIG_LOCKDEP



​           struct lockdep_map lockdep_map;



\#endif



};

8.2 定义工作队列底半部处理函数

 void work_queue_func(struct work_struct  *work);

8.3 初始化工作队列

struct work_struct  work_queue;

初始化:绑定工作队列及工作队列的底半部处理函数

 INIT_WORK(struct work_struct * pwork, _func)   ;

参数:pwork:工作队列

​       func:工作队列的底半部处理函数

8.4 工作队列的调度函数

bool schedule_work(struct work_struct *work);

九、按键驱动之workqueue版

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#include "fs4412_key.h"


int major = 11;
int minor = 0;
int fs4412key2_num  = 1;

struct fs4412key2_dev
{
	struct cdev mydev;

	int gpio;
	int irqno;

	struct keyvalue data;
	int newflag;
	spinlock_t lock;

	wait_queue_head_t rq;

	//struct tasklet_struct tsk;
	struct work_struct wk;
};

struct fs4412key2_dev *pgmydev = NULL;

int fs4412key2_open(struct inode *pnode,struct file *pfile)
{
	pfile->private_data =(void *) (container_of(pnode->i_cdev,struct fs4412key2_dev,mydev));
	return 0;
}

int fs4412key2_close(struct inode *pnode,struct file *pfile)
{

	return 0;
}

ssize_t fs4412key2_read(struct file *pfile,char __user *puser,size_t count,loff_t *p_pos)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)pfile->private_data;
	int size = 0;
	int ret = 0;

	if(count < sizeof(struct keyvalue))
	{
		printk("expect read size is invalid\n");
		return -1;
	}

	spin_lock(&pmydev->lock);
	if(!pmydev->newflag)
	{
		if(pfile->f_flags & O_NONBLOCK)
		{//非阻塞
			spin_unlock(&pmydev->lock);
			printk("O_NONBLOCK No Data Read\n");
			return -1;
		}
		else
		{//阻塞
			spin_unlock(&pmydev->lock);
			ret = wait_event_interruptible(pmydev->rq,pmydev->newflag == 1);
			if(ret)
			{
				printk("Wake up by signal\n");
				return -ERESTARTSYS;
			}
			spin_lock(&pmydev->lock);
		}
	}

	if(count > sizeof(struct keyvalue))
	{
		size = sizeof(struct keyvalue);
	}
	else
	{
		size = count;
	}

	ret = copy_to_user(puser,&pmydev->data,size);
	if(ret)
	{
		spin_unlock(&pmydev->lock);
		printk("copy_to_user failed\n");
		return -1;
	}

	pmydev->newflag = 0;

	spin_unlock(&pmydev->lock);

	return size;
}

unsigned int fs4412key2_poll(struct file *pfile,poll_table *ptb)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)pfile->private_data;
	unsigned int mask = 0;

	poll_wait(pfile,&pmydev->rq,ptb);

	spin_lock(&pmydev->lock);
	if(pmydev->newflag)
	{
		mask |= POLLIN | POLLRDNORM;
	}
	spin_unlock(&pmydev->lock);

	return mask;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = fs4412key2_open,
	.release = fs4412key2_close,
	.read = fs4412key2_read,
	.poll = fs4412key2_poll,
};

irqreturn_t key2_irq_handle(int no,void *arg)
{
	struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;

	//tasklet_schedule(&pmydev->tsk);
	schedule_work(&pmydev->wk);

	return IRQ_HANDLED;
}

//void bottom_irq_func(unsigned long arg)
void bottom_irq_func(struct work_struct *pwk)
{
	//struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;
	struct fs4412key2_dev *pmydev = container_of(pwk,struct fs4412key2_dev,wk);
	int status1 = 0;
	int status2 = 0;
	int status = 0;

	status1 = gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2 = gpio_get_value(pmydev->gpio);

	if(status1 != status2)
	{
		return;
	}

	status = status1;

	spin_lock(&pmydev->lock);
	if(status == pmydev->data.status)
	{
		spin_unlock(&pmydev->lock);
		return;
	}

	pmydev->data.code = KEY2;
	pmydev->data.status = status;
	pmydev->newflag = 1;

	spin_unlock(&pmydev->lock);
	wake_up(&pmydev->rq);

	return;
}

int __init fs4412key2_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);

	struct device_node *pnode = NULL;

	pnode = of_find_node_by_path("/mykey2_node");
	if(NULL == pnode)
	{
		printk("find node failed\n");
		return -1;
	}


	pgmydev = (struct fs4412key2_dev *)kmalloc(sizeof(struct fs4412key2_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmallc for struct fs4412key2_dev failed\n");
		return -1;
	}

	pgmydev->gpio = of_get_named_gpio(pnode,"key2-gpio",0);

	pgmydev->irqno = irq_of_parse_and_map(pnode,0);

	/*申请设备号*/
	ret = register_chrdev_region(devno,fs4412key2_num,"fs4412key2");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,fs4412key2_num,"fs4412key2");
		if(ret)
		{
			kfree(pgmydev);
			pgmydev = NULL;
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);//容易遗漏,注意
	}

	/*给struct cdev对象指定操作函数集*/	
	cdev_init(&pgmydev->mydev,&myops);

	/*将struct cdev对象添加到内核对应的数据结构里*/
	pgmydev->mydev.owner = THIS_MODULE;
	cdev_add(&pgmydev->mydev,devno,fs4412key2_num);


	init_waitqueue_head(&pgmydev->rq);

	spin_lock_init(&pgmydev->lock);

	//tasklet_init(&pgmydev->tsk,bottom_irq_func,(unsigned long)pgmydev);
	INIT_WORK(&pgmydev->wk,bottom_irq_func);
	
	ret = request_irq(pgmydev->irqno,key2_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key2",pgmydev);
	if(ret)
	{
		printk("request_irq failed\n");
		cdev_del(&pgmydev->mydev);
		kfree(pgmydev);
		pgmydev = NULL;
		unregister_chrdev_region(devno,fs4412key2_num);
		return -1;
	}
	return 0;
}

void __exit fs4412key2_exit(void)
{
	dev_t devno = MKDEV(major,minor);

	free_irq(pgmydev->irqno,pgmydev);

	cdev_del(&pgmydev->mydev);

	unregister_chrdev_region(devno,fs4412key2_num);

	kfree(pgmydev);
	pgmydev = NULL;
}


MODULE_LICENSE("GPL");

module_init(fs4412key2_init);
module_exit(fs4412key2_exit);

上面是key2下面是key3

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#include "fs4412_key.h"


int major = 11;
int minor = 0;
int fs4412key3_num  = 1;

struct fs4412key3_dev
{
	struct cdev mydev;

	int gpio;
	int irqno;

	struct keyvalue data;
	int newflag;
	spinlock_t lock;

	wait_queue_head_t rq;

	//struct tasklet_struct tsk;
	struct work_struct wk;
};

struct fs4412key3_dev *pgmydev = NULL;

int fs4412key3_open(struct inode *pnode,struct file *pfile)
{
	pfile->private_data =(void *) (container_of(pnode->i_cdev,struct fs4412key3_dev,mydev));
	return 0;
}

int fs4412key3_close(struct inode *pnode,struct file *pfile)
{

	return 0;
}

ssize_t fs4412key3_read(struct file *pfile,char __user *puser,size_t count,loff_t *p_pos)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)pfile->private_data;
	int size = 0;
	int ret = 0;

	if(count < sizeof(struct keyvalue))
	{
		printk("expect read size is invalid\n");
		return -1;
	}

	spin_lock(&pmydev->lock);
	if(!pmydev->newflag)
	{
		if(pfile->f_flags & O_NONBLOCK)
		{//非阻塞
			spin_unlock(&pmydev->lock);
			printk("O_NONBLOCK No Data Read\n");
			return -1;
		}
		else
		{//阻塞
			spin_unlock(&pmydev->lock);
			ret = wait_event_interruptible(pmydev->rq,pmydev->newflag == 1);
			if(ret)
			{
				printk("Wake up by signal\n");
				return -ERESTARTSYS;
			}
			spin_lock(&pmydev->lock);
		}
	}

	if(count > sizeof(struct keyvalue))
	{
		size = sizeof(struct keyvalue);
	}
	else
	{
		size = count;
	}

	ret = copy_to_user(puser,&pmydev->data,size);
	if(ret)
	{
		spin_unlock(&pmydev->lock);
		printk("copy_to_user failed\n");
		return -1;
	}

	pmydev->newflag = 0;

	spin_unlock(&pmydev->lock);

	return size;
}

unsigned int fs4412key3_poll(struct file *pfile,poll_table *ptb)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)pfile->private_data;
	unsigned int mask = 0;

	poll_wait(pfile,&pmydev->rq,ptb);

	spin_lock(&pmydev->lock);
	if(pmydev->newflag)
	{
		mask |= POLLIN | POLLRDNORM;
	}
	spin_unlock(&pmydev->lock);

	return mask;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = fs4412key3_open,
	.release = fs4412key3_close,
	.read = fs4412key3_read,
	.poll = fs4412key3_poll,
};

irqreturn_t key3_irq_handle(int no,void *arg)
{
	struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)arg;

	//tasklet_schedule(&pmydev->tsk);
	schedule_work(&pmydev->wk);

	return IRQ_HANDLED;
}

//void bottom_irq_func(unsigned long arg)
void bottom_irq_func(struct work_struct *pwk)
{
	//struct fs4412key3_dev *pmydev = (struct fs4412key3_dev *)arg;
	struct fs4412key3_dev *pmydev = container_of(pwk,struct fs4412key3_dev,wk);
	int status1 = 0;
	int status2 = 0;
	int status = 0;

	status1 = gpio_get_value(pmydev->gpio);
	mdelay(1);
	status2 = gpio_get_value(pmydev->gpio);

	if(status1 != status2)
	{
		return;
	}

	status = status1;

	spin_lock(&pmydev->lock);
	if(status == pmydev->data.status)
	{
		spin_unlock(&pmydev->lock);
		return;
	}

	pmydev->data.code = KEY3;
	pmydev->data.status = status;
	pmydev->newflag = 1;

	spin_unlock(&pmydev->lock);
	wake_up(&pmydev->rq);

	return;
}

int __init fs4412key3_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);

	struct device_node *pnode = NULL;

	pnode = of_find_node_by_path("/mykey3_node");
	if(NULL == pnode)
	{
		printk("find node failed\n");
		return -1;
	}


	pgmydev = (struct fs4412key3_dev *)kmalloc(sizeof(struct fs4412key3_dev),GFP_KERNEL);
	if(NULL == pgmydev)
	{
		printk("kmallc for struct fs4412key3_dev failed\n");
		return -1;
	}

	pgmydev->gpio = of_get_named_gpio(pnode,"key3-gpio",0);

	pgmydev->irqno = irq_of_parse_and_map(pnode,0);

	/*申请设备号*/
	ret = register_chrdev_region(devno,fs4412key3_num,"fs4412key3");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,fs4412key3_num,"fs4412key3");
		if(ret)
		{
			kfree(pgmydev);
			pgmydev = NULL;
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);//容易遗漏,注意
	}

	/*给struct cdev对象指定操作函数集*/	
	cdev_init(&pgmydev->mydev,&myops);

	/*将struct cdev对象添加到内核对应的数据结构里*/
	pgmydev->mydev.owner = THIS_MODULE;
	cdev_add(&pgmydev->mydev,devno,fs4412key3_num);


	init_waitqueue_head(&pgmydev->rq);

	spin_lock_init(&pgmydev->lock);

	//tasklet_init(&pgmydev->tsk,bottom_irq_func,(unsigned long)pgmydev);
	INIT_WORK(&pgmydev->wk,bottom_irq_func);
	
	ret = request_irq(pgmydev->irqno,key3_irq_handle,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"fs4412key3",pgmydev);
	if(ret)
	{
		printk("request_irq failed\n");
		cdev_del(&pgmydev->mydev);
		kfree(pgmydev);
		pgmydev = NULL;
		unregister_chrdev_region(devno,fs4412key3_num);
		return -1;
	}
	return 0;
}

void __exit fs4412key3_exit(void)
{
	dev_t devno = MKDEV(major,minor);

	free_irq(pgmydev->irqno,pgmydev);

	cdev_del(&pgmydev->mydev);

	unregister_chrdev_region(devno,fs4412key3_num);

	kfree(pgmydev);
	pgmydev = NULL;
}


MODULE_LICENSE("GPL");

module_init(fs4412key3_init);
module_exit(fs4412key3_exit);



 

十、下半部机制比较

任务机制

workqueue  ----- 内核线程  能睡眠  运行时间无限制

异常机制  -------  不能睡眠  下半部执行时间不宜太长( < 1s)

软中断  ----  接口不方便

tasklet  ----- 无具体延后时间要求时

定时器  -----有具体延后时间要求时

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇努力学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值