jz2440:第三个驱动程序,按键中断(6)

中断流程分析

  1. __irq_svc:执行irq_handler获取中断源
  2. 跳转到asm_do_IRQ,执行中断处理逻辑

__irq_svc:                   //1.中断统一入口函数
    svc_entry                //保存现场

#ifdef CONFIG_TRACE_IRQFLAGS  
    bl    trace_hardirqs_off
#endif
#ifdef CONFIG_PREEMPT
    get_thread_info tsk
    ldr    r8, [tsk, #TI_PREEMPT]        @ get preempt count
    add    r7, r8, #1            @ increment it
    str    r7, [tsk, #TI_PREEMPT]
#endif

    irq_handler     //2.1执行irq_handler

/*
 * Interrupt handling.  Preserves r7, r8, r9
 */
    .macro    irq_handler     // 2.2 irq_handler的宏定义
    get_irqnr_preamble r5, lr
1:    get_irqnr_and_base r0, r6, r5, lr      //3.获取中断源
    movne    r1, sp
    @
    @ routine called with r0 = irq number, r1 = struct pt_regs *
    @
    adrne    lr, 1b
    bne    asm_do_IRQ  //4.执行asm_do_IRQ()函数

handle_edge_irq-------desc->chip->ack(irq)清中断----------handle_IRQ_event

按下按键---CPU进入异常模式---跳转到 b vector_irq + ........----调用到__irq_usr----调用irq_handler

中断的注册,处理,注销

  • 1.注册:
int request_irq(unsigned int irq,
           void (*handler)(int, void*, structpt_regs *),
           unsigned long flags,
           const char *devname,
           void *dev_id)

unsigned int irq                   中断号。

void (*handler)(int,void *)    中断处理函数。

unsigned long flags             与中断管理有关的各种选项。

const char * devname         设备名

void *dev_id                         共享中断时使用。

  • 注销
void free_irq(unsigned int irq, void *dev_id)

简单的demo:注册中断,中断处理,中断释放

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


static struct class *irq_button_drv_class;
static struct class_device	*irq_button_drv_class_dev;

//GPF端口
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;

//GPG端口
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;

//dev 就是request_irq的最后一个参数
static irqreturn_t buttons_irq(int irq, void *dev) 
{
    printk("irq = %d\n",irq);
    return 0;
}

static int irq_button_drv_open(struct inode * inode, struct file * file)
{
    // 配置GPF2,0为输入引脚  GPF2 = 00 GPF0 = 00
    // 配置GPG3,11为输入引脚  GPG3 = 00 GPG11 = 00
    // 中断源,中断处理函数,检测上升下降沿,中断设备名,...
	request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", 0);
	request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", 0);
	request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", 0);
	request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", 0);	
    printk("open irq\n");
    return 0;
}



ssize_t irq_button_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos){
    //返回四个引脚电平
    unsigned char key_val[4];
    int ret_val;


    //读取GPF0 2
    ret_val = *gpfdat;
    key_val[0] = (ret_val & (1 << 0)) ? 1:0;
    key_val[1] = (ret_val & (1 << 2)) ? 1:0;

    //读取GPG3 11
    ret_val = *gpgdat;
    key_val[2] = (ret_val & (1 << 3)) ? 1:0;
    key_val[3] = (ret_val & (1 << 11)) ? 1:0;

    copy_to_user(buf,key_val,sizeof(key_val));
    return sizeof(key_val);
}

int irq_button_close (struct inode * inode, struct file * file) {
    //释放IRQ
    free_irq(IRQ_EINT0,0);
    free_irq(IRQ_EINT2,0);
    free_irq(IRQ_EINT11,0);
    free_irq(IRQ_EINT19,0);
    printk("free irq\n");
    return 0;
}

static struct file_operations button_drv_fops = {
    .owner  =   THIS_MODULE,   
    .open   =   irq_button_drv_open,     
	.read	=	irq_button_drv_read,
    .release =  irq_button_close,    
};




int major;
static int irq_button_drv_init(void)
{
    major = register_chrdev(0,"irq_button_drv", &button_drv_fops);

	irq_button_drv_class = class_create(THIS_MODULE, "irq_button_drv"); 
	irq_button_drv_class_dev = class_device_create(irq_button_drv_class, NULL, MKDEV(major, 0), NULL, "button"); /* /dev/xyz */

	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);  //地址映射:从0x56000050开始的16个字节的内存映射到gpfcon
	gpfdat = gpfcon + 1;

 	gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);  //地址映射:从0x56000050开始的16个字节的内存映射到gpfcon
	gpgdat = gpgcon + 1;

    return 0;
}

static void irq_button_drv_exit(void)
{
    unregister_chrdev(major,"irq_button_drv");

	class_device_unregister(irq_button_drv_class_dev);
	class_destroy(irq_button_drv_class);

    iounmap(gpfcon);
    iounmap(gpgcon);
    return 0;
}



module_init(irq_button_drv_init);
module_exit(irq_button_drv_exit);
MODULE_LICENSE("GPL");

具体的操作流程:

  1. request_irq();注册中断号,中断处理函数。。
  2. 检测到中断后,执行button_irq()打印irq值
  3. sudo make编译生成xxx.ko----insmod xxx.ko---lsmod
  4. ps(查看 -sh的PID 为772,用于接下来的命令)
  5. ls -l proc/772]/fd
  6. exec 5</dev/button(执行文件--即注册中断)---并且打印"open irq"
  7. 然后点击按键即可看到打印irq = ...,说明进入了中断处理函数
  8. 再ls -l proc/772即可看到设备文件/dev/button
  9. exec 5<&-    即可释放中断---并且打印“free irq”
  10. lsmod即可看到没有dev/button了

要使用软中断,必须先使用 open_softirq 函数注册对应的软中断处理函数

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值