Linux驱动开发--中断处理原理

2023-11-04

目录

一、什么是中断

二、中断处理原理

三、中断接口

3.1 中断申请

3.2 中断释放

3.3 中断处理函数原型

四、按键驱动

代码示例:

五、中断上半部与下半部

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

6.1 结构体

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

6.3 初始化tasklet

6.4 调度tasklet

6.5 代码示例

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

7.1 工作队列结构体:

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

7.3 初始化工作队列

7.4 工作队列的调度函数

7.5 代码示例

八、下半部机制比较


一、什么是中断

一种硬件上的通知机制,用来通知CPU发生了某种需要立即处理的事件

分为:

  1. 内部中断 CPU执行程序的过程中,发生的一些硬件出错、运算出错事件(如分母为0、溢出等等),不可屏蔽
  2. 外部中断 外设发生某种情况,通过一个引脚的高、低电平变化来通知CPU (如外设产生了数据、某种处理完毕等等)

二、中断处理原理

任何一种中断产生,CPU都会暂停当前执行的程序,跳转到内存固定位置执行一段程序,该程序被称为总的中断服务程序,在该程序中区分中断源,然后进一步调用该中断源对应的处理函数。

中断源对应的处理函数被称为分中断处理程序,一般每一个分中断处理程序对应一个外设产生的中断

写驱动时,如果外设有中断,则需要编写一个函数(分中断处理程序)来处理这种中断。

三、中断接口

3.1 中断申请

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
/*
参数:
	irq:所申请的中断号
	handler:该中断号对应的中断处理函数
	flags:中断触发方式或处理方式 
		触发方式:IRQF_TRIGGER_NONE 		//无触发
		 	 	 IRQF_TRIGGER_RISING 	//上升沿触发
			 	 IRQF_TRIGGER_FALLING  //下降沿触发
				IRQF_TRIGGER_HIGH  	//高电平触发
				IRQF_TRIGGER_LOW 		//低电平触发
		处理方式:
			   IRQF_DISABLED		//用于快速中断,处理中屏蔽所有中断
				IRQF_SHARED		  //共享中断
		name:中断名 /proc/interrupts
		dev:传递给中断例程的参数,共享中断时用于区分那个设备,一般为对应设备的结构体地址,无共享中断时写NULL
返回值:成功:0 失败:错误码
*/

3.2 中断释放

void free_irq(unsigned int irq, void *dev_id);
/*
功能:释放中断号
参数:
	irq:设备号
	dev_id:共享中断时用于区分那个设备一般强转成设备号,无共享中断时写NULL
*/

3.3 中断处理函数原型

typedef irqreturn_t (*irq_handler_t)(int, void *);
/*
参数:
	int:中断号
	void*:对应的申请中断时的dev_id
返回值:
	typedef enum irqreturn irqreturn_t;	//中断返回值类型
	enum irqreturn {
		IRQ_NONE	= (0 << 0),
		IRQ_HANDLED	= (1 << 0),
		IRQ_WAKE_THREAD	= (1 << 1),
	};
	返回IRQ_HANDLED表示处理完了,返回IRQ_NONE在共享中断表示不处理
*/

四、按键驱动

按键原理图:

exynos4412-fs4412.dts中增加节点

mykey2_node {
	compatible = "mykey2,key2";
	key2-gpio = <&gpx1 1 0>;
	interrupt-parent = <&gpx1>;
	interrupts = <1 3>;
};

代码示例:

key.h

#ifndef FS4412_KEY_H
#define FS4412_KEY_H
 
enum KEYCODE
{
    KEY2 = 1002,
    KEY3,
    KEY4,
};
 
enum KEY_STATUS
{
    KEY_DOWN = 0,
    KEY_UP,
};
 
struct keyvalue
{
    int code;//which KEY
    int status;
};
 
#endif

key.c

#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 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;
    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 IRQ_NONE;
    }
 
    status = status1;
 
    spin_lock(&pmydev->lock);
    if(status == pmydev->data.status)
    {
        spin_unlock(&pmydev->lock);
        return IRQ_NONE;
    }
 
    pmydev->data.code = KEY2;
    pmydev->data.status = status;
    pmydev->newflag = 1;
 
    spin_unlock(&pmydev->lock);
    wake_up(&pmydev->rq);
 
    return IRQ_HANDLED;
}
 
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);
     
    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);

key_app.c

#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
 
#include <stdio.h>
 
#include "fs4412_key.h"
 
int main(int argc,char *argv[])
{
    int fd = -1;
    struct keyvalue keydata = {0};
    int ret = 0;
 
    if(argc < 2)
    {
        printf("The argument is too few\n");
        return 1;
    }
 
    fd = open(argv[1],O_RDONLY);
    if(fd < 0)
    {
        printf("open %s failed\n",argv[1]);
        return 3;
    }
 
    while((ret = read(fd,&keydata,sizeof(keydata))) == sizeof(keydata))
    {
        if(keydata.status == KEY_DOWN)
        {
            printf("Key2 is down!\n");
        }
        else
        {
            printf("Key2 is up!\n");
        }
    }
 
    close(fd);
    fd = -1;
    return 0;
}

五、中断上半部与下半部

起源:

  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

DECLARE_TASKLET(name, func, data);
/*
定义变量并初始化
参数:name:中断底半部tasklet的名称
	 Func:中断底半部处理函数的名字
	 data:给中断底半部处理函数传递的参数
*/
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)

6.4 调度tasklet

void tasklet_schedule(struct tasklet_struct *t)
//参数:t:tasklet的结构体

6.5 代码示例

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

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

7.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

};

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

void work_queue_func(struct work_struct *work);

7.3 初始化工作队列

struct work_struct work_queue;

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

INIT_WORK(struct work_struct * pwork, _func) ;

参数:pwork:工作队列

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

7.4 工作队列的调度函数

bool schedule_work(struct work_struct *work);

7.5 代码示例

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

八、下半部机制比较

任务机制

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

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

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux驱动开发--中断处理原理 的相关文章

  • 应用层通过/sys/class/gpio文件操作gpio口

    1 内核gpio子系统介绍 应用层通过sysfs操作gpio的前提是内核中已经向gpio子系统注册了gpio资源 并且在 sys class 目录下可以看到gpio类 详细情况参考博客 2 6 35内核的gpio子系统详解 2 sys cl
  • Rockchip CAN FD 开发文档

    Rockchip CAN FD 开发文档 前言 概述 产品版本 芯片名称 内核版本 RK356X 4 19 5 10 RK3588 5 10 目录 文章目录 Rockchip CAN FD 开发文档 toc CAN FD 驱动 驱动文件 D
  • EDK II Module Writers Guide上

    一 EDK2简介 1 EDK2工作流 二 EDK2 Packages 1 Packages介绍 EDK2 Packages是一个容器 其中包含一组模块及模块的相关定义 每个Package是一个EDK2单元 整个Project的源代码可以被分
  • AutoSar标准下ADC的结果访问(Adc_ReadGroup与Adc_GetStreamLastPointer)的异同

    系列文章目录 等待更新中 文章目录 系列文章目录 前言 1 什么是ADC的结果访问 2 ADC访问模式 3 AUTOSAR标准配置案例分析 3 1 Configuration 3 2 图形展示结果指针初始化 3 3 使用Adc GetStr
  • 驱动开发 作业 day7 9/18

    基于GPIO子系统实现led灯点亮 head h ifndef HEAD H define HEAD H 构建LED开关的功能码 不添加ioctl第三个参数 define LED ON IO l 1 define LED OFF IO l
  • windows driver双机调试环境搭建,用windbg或者debug view查看内核调试输出

    本地环境 本地开发环境 win 10 visual studio installer 2022版 visual studio 2022 VMware player 目的 本地环境作为开发环境 VM作为测试和调试环境 用debug view查
  • Robot Framework 自动化测试详解

    一 Robot Framework 简介 1 界面自动化测试工具 界面自动化测试 即UI自动化测试 比较常见的工具有 QTP AutoIt Selenium等 像QTP经历了很多版本 最新的版本好像叫UFT了 对初学者来说 录制回放是相当容
  • ARM(IMX6U)裸机模仿STM32驱动开发实验(定义外设结构体)

    参考 Linux之ARM IMX6U 裸机模仿STM32驱动开发格式 作者 一只青木呀 发布时间 2020 08 15 12 11 56 网址 https blog csdn net weixin 45309916 article deta
  • STM32寄存器

    问题 什么是寄存器 什么是存储器映射 什么是寄存器映射 STM32架构 程序存放在FLASH中 const的常量存放在FLASH中 变量 全局 静态变量 存放在SRAM中 System总线主要读取寄存器 AHB 高速 总线上挂着SDIO 复
  • Failed to execute /linuxrc. Attempting defaults... 解决方案

    今天想移植个根文件系统 使用的板子是友善之臂的S3C2440 这个很多书上都有介绍 难度倒也不是很大 按照手册一步步的来 移植完之后 烧写到flash里面 发现不能运行 怎么回事 检查了一遍 发现和教材上一样 难道教材有问题 在网上找了移植
  • 隔离式栅极驱动器输入级对电机驱动应用的影响

    介绍 在电机驱动应用中为功率级选择隔离式栅极驱动器时 您有多种选择 栅极驱动器可简单可复杂 具有集成米勒箝位 分离输出或绝缘栅双极晶体管 IGBT 发射极的欠压 UVLO 锁定参考等功能 输入级有两个选项 电压输入级或电流输入级 在本文中
  • 驱动学习(六)ioctl

    驱动学习 六 ioctl 文章目录 驱动学习 六 ioctl 1 ioctl 2 命令码 2 1 自定义命令码 2 2 标准命令码 2 2 1 合成标准命令码的宏函数 3 测试ioctl linux内核给用户提供了两类系统调用函数 一类是数
  • 一个主设备号是如何支持多个次设备?

    1 主次设备号 参考博客 字符设备驱动详解 主次设备号 注册 卸载字符设备驱动 创建设备节点 地址映射 2 次设备号介绍 1 在老的驱动程序里是不需要次设备号的 在老版内核中注册驱动用register chrdev 函数 只需要传入主设备号
  • Macronix MX25L25645G NOR Flash无法擦除问题分析

    1 问题现象描述 处理器使用的 SAM9X60 使用的内核版本是 5 10 80 在调试 Macronix MX25L25645G NOR Flash时 发现flash驱动加载成功后 使用 mtd debug 工具 erase flash时
  • Linux I2C 驱动实验

    一 I2C 驱动 本章同样以 I MX6U ALPHA 开发板上的 AP3216C 这个三合一环境光传感器为例 通过 AP3216C 讲解一下如何编写 Linux 下的 I2C 设备驱动程序 Linux 的驱动分离与分层的思想 因此 Lin
  • inux字符驱动之read、write部分

    本期主题 linux字符驱动之read write部分 往期链接 linux设备驱动中的并发 linux设备驱动中的编译乱序和执行乱序 linux设备驱动之内核模块 linux字符驱动 linux字符驱动之ioctl部分 linux字符驱动
  • printk()和printf()的比较

    1 前言 print函数和printf函数是对孪生兄弟 在功能作用上几乎是一样的 在使用上有一些区别 1 printk 和printf 之间的一个显著区别在于printk 允许通过指定一个标志来设置优先级 从而决定这条打印是否需要打印出来
  • LCD笔记(4)分析内核自带的LCD驱动程序

    1 驱动程序框架 Linux驱动程序 驱动程序框架 硬件编程 在前面已经基于QEMU编写了LCD驱动程序 对LCD驱动程序的框架已经分析清楚 核心就是 分配fb info 设置fb info 注册fb info 硬件相关的设置 1 1 入口
  • LCD背光调节实验

    目录 LCD 背光调节简介 硬件原理分析 实验程序编写 编译下载验证 编写Makefile 和链接脚本 编译下载 不管是使用显示器还是手机 其屏幕背光都是可以调节的 通过调节背光就可以控制屏幕的亮度 在户外阳光强烈的时候可以通过调高背光来看
  • 深入分析linux内核的内存分配函数devm_kzalloc

    在分析驱动代码的时候 经常会遇到使用devm kzalloc 为一个设备分配一片内存的情况 devm kzalloc 是内核用来分配内存的函数 同样可以分配内存的内核函数还有devm kmalloc kzalloc kmalloc 它们之间

随机推荐

  • FPGA设计:制作一个频率计

    这次把自己做过的一个频率计拿出来跟大家分享一下 项目采用VHDL语言来编写 一 功能介绍 对信号源输入信号的频率进行正确测量并显示 测量范围 0 9999Hz 测量精度 1Hz 测量误差 1Hz 因为用的FPGA板只有四个数码管 所以就采用
  • 84.Robot Framework简介及安装验证方法

    文章目录 requirements 简介 Robot Framework架构 安装Robot Framework 转载请注明原始链接 https blog csdn net a464057216 article details 104369
  • 距离向量(DV)算法的问题

    上一篇将了DV协议的基本内容 DV算法固然简单易懂 但应用于实际后 人们很快发现这种算法在某些特定情况下是会出现一些致命的问题的 在这篇文章中 我们来讨论下这些问题及其解决方法 分割线 选路环路 routing loop 和计数到无穷 co
  • 嵌入式毕业设计选题推荐 题目汇总

    文章目录 1前言 2 如何选题 2 1 不要给自己挖坑 2 2 难度把控 2 3 如何命名题目 3 单片机 嵌入式 选题大全 3 1 嵌入式方向 3 2 算法方向 3 3 移动通信方向 3 4 学长作品展示 4 最后 1前言 近期不少学弟学
  • linux开机dracut界面_CentOS启动报错dracut Warning: Boot has failed的解决方法

    CentOS无法启动 启动分区无法找到 然后就报了个堆栈信息 ACPI wmi Mapper loaded dracut Warning No root device block dev sda4 found dracut Warning
  • 数据分析课程笔记(四)pandas、series、dataframe、索引数据和缺失数据处理

    数据分析课程笔记 pandas 为什么要学习pandas 常见数据类型 创建series Series切片和索引 Series的索引和值 读取外部数据 DataFrame 索引数据 loc iloc 布尔索引 字符串方法 缺失数据处理 pa
  • map/unordered_map原理和使用整理

    1 结论 新版的hash map都是unordered map了 这里只说unordered map和map 运行效率方面 unordered map最高 而map效率较低但 提供了稳定效率和有序的序列 占用内存方面 map内存占用略低 u
  • Linux下std::ifstream成员函数对应系统调用验证

    最近在分析离线数据使用时的bug 发现代码中对std ifstream成员函数使用存在疑问 所以就写了个简单测试程序来分析std ifstream成员函数对应那些系统调用 目录 1 gcount 2 seekg和tellg 3 read 代
  • 用C语言编写程序求一个1!+2!+3!+4!...(两种方法)

    方法一 思路 用两个for循环 一个用于计算阶乘 n 一个用于计算和 sum 代码如下 自己感悟 int main int sum 0 for int i 1 i lt 4 i 此循环用于求和 即求1 2 3 4 int ret 1 for
  • CPU长期不足3%(负载不足)系统吞吐量不够,资源浪费,必须JVM调优

    除了上述内存泄漏外 我们还发现CPU长期不足3 系统吞吐量不够 针对8core 16G 64bit的Linux服务器来说 是严重的资源浪费 在CPU负载不足的同时 偶尔会有用户反映请求的时间过长 我们意识到必须对程序及JVM进行调优 从以下
  • 基于tensorflow搭建神经网络

    基于tensorflow搭建神经网络 一 tf keras搭建神经网络步骤 六步法 import train test model tf keras models Sequential model compile model fit mod
  • 大学计算机组成原理试题答案,重庆大学计算机组成原理试题集含部分答案.doc...

    计算机组成原理 试题集 一 选择题 在每小题列出的四个备选项中只有一个是符合题目要求的 请将其代码填写在题后的括号内 1 反映计算机基本功能的是 A 操作系统 B 系统软件 C 指令系统 D 数据库系统 2 若二进制数为1111 101 则
  • HBase Compaction 原理与线上调优实践

    作者 vivo 互联网存储技术团队 Hang Zhengbo 本文对 HBase Compaction 的原理 流程以及限流的策略进行了详细的介绍 列举了几个线上进行调优的案例 最后对 Compaction 的相关参数进行了总结 一 Com
  • 【Java】BF算法(串模式匹配算法)

    什么是BF算法 BF算法 即暴力算法 是普通的模式匹配算法 BF算法的思想就是将目标串S的第一个与模式串T的第一个字符串进行匹配 若相等 则继续比较S的第二个字符和T的第二个字符 若不相等 则比较S的第二个字符和T的第一个字符 依次比较下去
  • 【LeetCode】层数最深叶子节点的和(python)

    题目描述 给你一棵二叉树 请你返回层数最深的叶子节点的和 解题思路 深度搜索优先遍历二叉树 先找到叶子节点 然后求和 Definition for a binary tree node class TreeNode def init sel
  • 中文NLP的第一步:分词,基于 PaddleHub 实现,绝对小白友好(学习心得)

    接下来的几天 会分步进行阐述 NLP 的实际程序操作 由于深度学习硬件资源的稀缺性 所以了 PaddlePaddle 作为这次实操的框架平台 虽然 Paddle 在国际上的流行度比不上 tensorflow 等架构 但是在国内 Paddle
  • Git 使用教程:最详细、最傻瓜、最浅显、真正手把手教

    一 Git是什么 二 SVN与Git的最主要的区别 三 在windows上如何安装Git 四 如何操作 四 Git撤销修改和删除文件操作 五 远程仓库 六 创建与合并分支 七 bug分支 八 多人协作 一 Git是什么 Git是目前世界上最
  • 快速理解SurfaceFlinger 一、编译

    1 代码路径 android 7 1 frameworks native services surfaceflinger 1 1代码结构 Android mk Barrier h Client cpp Client h clz h Colo
  • C++ 类型别名

    C 为类型创建别名有两种方式 一种是使用预处理器 define aliasName typeName aliasName为别名 这样 预处理器将在编译程序时用aliasName替换所有typeName 第二种方式时使用关键字typedef来
  • Linux驱动开发--中断处理原理

    目录 一 什么是中断 二 中断处理原理 三 中断接口 3 1 中断申请 3 2 中断释放 3 3 中断处理函数原型 四 按键驱动 代码示例 五 中断上半部与下半部 六 下半部机制之tasklet 基于软中断 6 1 结构体 6 2 定义ta