1、内核和芯片初始化代码已经将异常或者中断的架构处理了。此时需要用户提供处理函数。也就说用户需要告诉内核当某一个中发生时,处理哪些内容!!

需要使用到的注册函数request_irq

int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)
{

(1)分配一个irqaction结构

    action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
    if (!action)
        return -ENOMEM;

    action->handler = handler;
    action->flags = irqflags;
    cpus_clear(action->mask);
    action->name = devname;
    action->next = NULL;
    action->dev_id = dev_id;

(2)设置中断

retval = setup_irq(irq, action);

int setup_irq(unsigned int irq, struct irqaction *new)
{

(3)以中断号为信息,找到了irq_desc[]的数组项

  struct irq_desc *desc = irq_desc + irq;

(4)先判断链表头是否有东西,如果irq_desc[irqno]->action链表挂着多个项就表明是共享中断。

    p = &desc->action;
    old = *p;
    if (old) {

     }

(5)设置中断引脚,使能中断

desc->chip->set_type(irq,
                        new->flags & IRQF_TRIGGER_MASK)

}

需要使用到的注册函数free_irq

void free_irq(unsigned int irq, void *dev_id)
{ 删除结构体,禁止中断。}

2、编写程序

查看芯片手册中断号

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/irq.h>

static struct class *seconddrv_class;
static struct class_device *seconddrv_class_dev;
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;

volatile unsigned long *gpgcon = NULL;
volatile unsigned long *gpgdat = NULL;

struct pin_desc{
	unsigned int pin;
	unsigned int key_val;
	
};
/*
键值:按下0x01 0x02 0x03 0x04
不按下0x81 0x82 0x83 0x84
*/
static unsigned char key_val;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press;
struct pin_desc pin_desc[4]={
	{S3C2410_GPF0,0x01},
	{S3C2410_GPF2,0x02},
	{S3C2410_GPG3,0x03},
	{S3C2410_GPG11,0x04}
	
};

static irqreturn_t buttons_irq(int irq, void *dev_id)
{
	struct pin_desc* pindesc = (struct pin_desc*)dev_id;
	unsigned int pinval;
	
	pinval=s3c2440_gpio_getpin(pindesc->pin);
	if(pinval)
	{
		//松开
		key_val= 0x80 | pindesc->key_val;	
	}
	else
	{
		//按下
		key_val= pindesc->key_val;	
	}
	
	ev_press=1;//表示中段发生了
	wakeup_up_interruptible(&button_waitq);//唤醒进程
	
	printk("irq=%d",irq);
	return IRQ_HANDLED;
}

static int second_drv_open(struct inode *inode, struct file *file)
{
	/*进行配置引脚,配置GPF 0 2为输入引脚
	*gpfcon &=~((0x3<<(0*2)) |(0x3<<(2*2)));
	gpgcon &=~((0x3<<(3*2)) |(0x3<<(11*2)));
	进行配置引脚,配置GPG 3 11为输入引脚*/
	//改用中断的方式,不需要直接设置引脚的属性了。request_irq函数已经将引脚设置号
	//中断号怎么确定呢??看原理图
	request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE,"s2",&pin_desc[0]);
	request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE,"s3",&pin_desc[1]);
	request_irq(IRQ_EINT11,buttons_irq, IRQT_BOTHEDGE,"s4",&pin_desc[2]);
	request_irq(IRQ_EINT19,buttons_irq, IRQT_BOTHEDGE,"s5",&pin_desc[3]);

	return 0;
}


static int second_drv_read(struct inode *inode, char __user *buf, size_t size, loff_t *ppos)
{
	/*
	//返回4个引脚的电平
	unsigned char key_vals[4];
	int regval;
	
	//读GPF0 2,其实已经有系统函数可以实现读取引脚
	//s3c2440_gpio_getpin()
	regval = *gpfdat;
	key_vals[0] =(regval & (1<<0)) ? 1:0;
	key_vals[1] =(regval & (1<<2)) ? 1:0;
	
	//读GPF3 11
	regval = *gpgdat;
	key_vals[0] =(regval & (1<<3)) ? 1:0;
	key_vals[1] =(regval & (1<<11)) ? 1:0;
	
	copy_to_user(buf, &key_vals, sizeof(key_vals));
	*/
	//如果没有按键发生,休眠,否则有按键发生直接放回
	wait_event_interruptible(button_waitq, ev_press);
	
	//如果有按键发生,返回中,并清零
	copy_to_user(buf,&key_val,1);
	ev_press=0;
	return 1;
}
int second_drv_close(struct inode *inode, struct file *file)
{
	free_irq(IRQ_EINT0,&pin_desc[0]);
	free_irq(IRQ_EINT2,&pin_desc[1]);
	free_irq(IRQ_EINT11,&pin_desc[2]);
	free_irq(IRQ_EINT19,&pin_desc[3]);
	
	
	return 0;
}


static const struct file_operations second_drv_fops = {//这个结构体要注册在入口函数里面
	.owner = THIS_MODULE,
	.open = second_drv_open,
	.read = second_drv_read,
	.release = second_drv_close,
};
int major;
static int second_drv_init(void)
{
        major = register_chrdev(0,"second_drv",&second_drv_fops);
        seconddrv_class = class_create(THIS_MODULE, "seconddrv");
        seconddrv_class_dev = class_device_create(seconddrv_class, NULL, MKDEV(major,0), NULL,"buttons");
        gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
        gpfdat = gpfcon + 1;
        gpgcon = (volatile unsigned long *)ioremap(0x56000060,16);
        gpgdat = gpgcon + 1;

        return 0;
}
void second_drv_exit(void)
{
//驱动的入口函数来调用注册函数
	unregister_chrdev(major, "second_drv");//卸载
	class_device_unregister(seconddrv_class_dev);
	class_destroy(seconddrv_class);
	unmmap(gpfcon);
	unmmap(gpgcon);
}
module_init(second_drv_init);
module_exit(second_drv_exit);
MODULE_LICENSE("GPL");

Logo

更多推荐