嵌入式linux驱动中断编程笔记

1、中断申请函数request_irq

 

函数原型:

request_irq(unsigned int  irq,  irq_handler_t   handler,

                   unsigned long  flags, const char  *name, void  *dev);

参数详解:

1、irq:中断编号(每个中断源有唯一编号),中断来临时,通过该编号识别中断,并调用处理程序

 一般通过函数gpio_to_irq(unsigned int gpio),将对应引脚号转换为中断号


2、handler:中断服务函数指针,原型typedef irqreturn_t (*irq_handler_t)(int , void *);

void *是由request_irq注册函数传递的*dev数据,在handler中可以可以取出数据dev以备使用


3、flag:中断属性,如快速中断,共享中断,如果是外部中断还有:上升沿,下降沿触发这类标志。

#define IRQF_TRIGGER_NONE       0x00000000
#define IRQF_TRIGGER_RISING     0x00000001
#define IRQF_TRIGGER_FALLING    0x00000002
#define IRQF_TRIGGER_HIGH       0x00000004
#define IRQF_TRIGGER_LOW        0x00000008
#define IRQF_TRIGGER_PROBE      0x00000010

#define IRQF_TRIGGER_MASK   (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)


4、name:中断名字,注册后会在/proc/irq/``irq号name文件夹出现。


5、dev:   一般来说都会传递一个有意义的指针,一般是驱动程序管理的与设备相关的数据结构对象的指针作为dev的实参,然后传递给中断处理函数使用


6、返回值:0表示成功,返回-EINVAL表示中断号无效 ,返回-EBUSY表示中断被占用。

 

2、中断释放函数free_irq

函数原型:

void free_irq(unsigned int irq, void *dev_id)

参数意义同上

 

3、中断例程

 

#if 0
1.本例子使用面向对象的思想来编写
2.开发板上的4个按键,每个按键是操作的方法是一样,
所以把一个按键需要使用的信息封装成一个结构体,要多个按键只需要定义结构体数组即可。
3.展示如何使用dev_id来简化编程
4.按键信息: gpio编号,按键编号,按键名
#endif

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>

#define        KEY_NUM    4

//定义按键缓冲区,'0'表示松开,'1'表示按下
char keybuf[KEY_NUM] = {'0', '0', '0', '0'};

//定义按键对象
typedef struct button_desc{
	int gpio;     //io编号 
	int num;      //按键编号
	char *name;   //按键名
}button_desc_t;



//定义结构体数组
button_desc_t  buttons[KEY_NUM]={
	{EXYNOS4_GPX3(2),0,"KEY1"},
	{EXYNOS4_GPX3(3),1,"KEY2"},
	{EXYNOS4_GPX3(4),2,"KEY3"},
	{EXYNOS4_GPX3(5),3,"KEY4"}
};

//以下是文件操作方法的具体实现代码
static int xxx_open(struct inode *pinode, struct file *pfile )
{
    printk(KERN_EMERG"file:%s\r\nline:%d, %s is call\n", __FILE__, __LINE__, __FUNCTION__);
    return 0;
}
static int xxx_release (struct inode *pinode, struct file *pfile)
{
    printk(KERN_EMERG"file:%s\r\nline:%d, %s is call\n", __FILE__, __LINE__, __FUNCTION__);
    return 0;
}

static ssize_t xxx_read(struct file *pfile,
                        char __user *buf,
                        size_t count, loff_t *poff)
{
    int ret;

    if(count > KEY_NUM) {
        count = KEY_NUM;
    }

    //给用户返回按键的状态
    ret = copy_to_user(buf, keybuf, count);
    if(ret) {
        printk("copy_to_user error!");
        return -EFAULT;
    }

    return count;
}


//文件操作方法集合指针
static const struct file_operations mymisc_fops = {
    .open           =   xxx_open,
    .read           =   xxx_read,
    .release        =   xxx_release,
};


//定义核心结构
static struct miscdevice  misc = {
    .minor = 255,
    .name  = "mybutton",     ///dev目录下的设备名
    .fops  = &mymisc_fops,
};

//中断服务函数
//注意:request_irq时候传递了每个按键元素首地址做为dev_id
irqreturn_t mybuttons_handler(int  irq, void *dev_id)
{
    int id ;
	button_desc_t * pdata;

	//把void*类型转换成原来传入的类型,得到按键的结构内存首地址
	pdata = (button_desc_t*)dev_id;

    id =  pdata->num;
    if(!gpio_get_value(pdata->gpio)) { /*按下*/
        keybuf[id]  = '1';
		printk("%s is dn\n",pdata->name);
    } else {
        keybuf[id]  = '0';
		printk("%s is up\n",pdata->name);
    }
 
    return IRQ_HANDLED;
}



static int __init mymisdevice_init(void)
{
    int i;
    int ret;
    unsigned int  irq;
    unsigned long flags;

    //看原理图可以知道使用外部中断 26~29四个中断
    for ( i = 0 ; i < 4 ; i++ ) {

		//通过io编号转换成中断编号
        irq = gpio_to_irq(buttons[i].gpio);

        //中断标志:对于外部中断才有IRQF_TRIGGER_FALLING,IRQF_TRIGGER_RISING
        //IRQF_SHARED 对于共用 中断编号的情况需要指定,如果不指定,则这个中断号只能被注册一次
        //IRQF_SAMPLE_RANDOM 表示对系统产生随机数据有贡献,要不要都可以。
        //flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
        flags =  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING  ;

		//注意:这里传递了每个按键元素首地址做为dev_id
        ret =  request_irq(irq, mybuttons_handler, flags, buttons[i].name, (void *)&buttons[i]);
        if(ret < 0) {
            printk("request_irq error\r\n");
            return ret;
        }
        printk("request irq:%d,\n", irq);
    }


    //注册核心结构
    ret = misc_register(&misc);
    if(ret < 0) {
        printk(KERN_EMERG"misc_register error\n");
        return ret;
    }
    printk(KERN_EMERG"misc_register  ok\n");


    return 0;
}

static void __exit mymisdevice_exit(void)
{
    int ret;
    int i;
    int irq;
	
    //注销核心结构
    ret = misc_deregister(&misc);
    if(ret < 0) {
        printk(KERN_EMERG"misc_deregister error\n");
        return ;
    }

    //释放中断
    for ( i = 0 ; i < 4 ; i++ ) {
        irq = gpio_to_irq(buttons[i].gpio);
        free_irq(irq, (void *)&buttons[i]);
    }

    printk(KERN_EMERG"misc_deregister ok\n");

}

module_init(mymisdevice_init);
module_exit(mymisdevice_exit);
MODULE_LICENSE("GPL");

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值