目录
八、下半部机制之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 ----- 无具体延后时间要求时
定时器 -----有具体延后时间要求时