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,
};
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");
?
|