天嵌 ARM开发社区

 找回密码
 注册
查看: 2145|回复: 0

Linux矩阵键盘驱动程序,中断服务程序中控制中断的问题

[复制链接]
naiker 发表于 2009-10-11 22:35:10 | 显示全部楼层 |阅读模式
内核版本使用的是linux-2.6.30.4
驱动程序使用模块装载方式

这是一个6×7的矩阵键盘,6行设置成中断模式的IO口,外接10k上拉电阻;
常态下6行端口都成高电平;
7列为扫描口,设置为输出模式的IO口,外接二极管;
常态下7列端口都设置成低电平;
以上参见函数port_init();

当按键按下时,某行和某列接通,某一行端口被拉低,产生下降沿(使用下降沿中断),即确定了行端口,进入中断服务程序;
在中断服务程序中,通过端口的0111111(低电平依次移动在不同的列扫描端口上),来确认接通的是列端口;
参见函数key_scan();

问题是列扫描过程中会产生新的下降沿中断信号,为了避免这种情况,我在列扫描之前使用函数disable_irq(),来关闭中断;但是这个函数不好用,不但关闭中断而且这个函数执行完,就立即退出了中断服务程序,后面的键盘扫描都没执行;

查过资料disable_irq函数应该是能保证接下来的程序能继续执行的,会不会是2.6.30内核版本问题;
有没有别的方法解决?

希望大家能帮我解决这个问题或提出好的建议!

struct button_desc
{
int pin;
int set_outp;
};

struct button_irq_desc
{
int irq;
int pin;
int set_eint;
int set_inp;
int row;
char *name;
};

static struct button_irq_desc button_cfg_row [] = // 6个IO口作为,中断口
{
{IRQ_EINT1, S3C2410_GPF1, S3C2410_GPF1_EINT1, S3C2410_GPF1_INP, 1, "KEY1"},  
{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, S3C2410_GPF2_INP, 2, "KEY2"},  
{IRQ_EINT3, S3C2410_GPF3, S3C2410_GPF3_EINT3, S3C2410_GPF3_INP, 3, "KEY3"},  
                                                               
{IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, S3C2410_GPF4_INP, 4, "KEY4"},  
{IRQ_EINT5, S3C2410_GPF5, S3C2410_GPF5_EINT5, S3C2410_GPF5_INP, 5, "KEY5"},
{IRQ_EINT6, S3C2410_GPF6, S3C2410_GPF6_EINT6, S3C2410_GPF6_INP, 6, "KEY6"},  
};

static struct button_desc  button_cfg_col [] =
{
{S3C2440_GPJ0, S3C2440_GPJ0_OUTP},  
{S3C2440_GPJ1, S3C2440_GPJ1_OUTP},  
{S3C2440_GPJ2, S3C2440_GPJ2_OUTP},  
{S3C2440_GPJ3, S3C2440_GPJ3_OUTP},  
{S3C2440_GPJ4, S3C2440_GPJ4_OUTP},
{S3C2440_GPJ5, S3C2440_GPJ5_OUTP},  
{S3C2440_GPJ6, S3C2440_GPJ6_OUTP},  
{S3C2440_GPJ7, S3C2440_GPJ7_OUTP},  
};

static int  key_scan(void)
{
    int i, row, col, ret=0;
   
    for (col=0; col <sizeof(button_cfg_col)/sizeof(button_cfg_col[0]); col++)
    {              
    for (i=0; i <sizeof(button_cfg_col)/sizeof(button_cfg_col[0]); i++)
    {
        if (i == col)
        {
        s3c2410_gpio_setpin(button_cfg_col[i].pin, 0);
        }
        else
      {
      s3c2410_gpio_setpin(button_cfg_col[i].pin, 1);
      }
    }
   
    for (row=0; row <sizeof(button_cfg_row)/sizeof(button_cfg_row[0]); row++)
    {
        if (s3c2410_gpio_getpin(button_cfg_row[row].pin) == 0)
        {
        printk("irq row=%d col=%d\n", row+1, col+1);
        
            ret=(col+1)*10 + (row+1);
            
            return ret;
        }
    }
    }  
      
    return ret;   
}

static void port_init(void)
{
    int i;
   
    for (i=0; i <sizeof(button_cfg_col)/sizeof(button_cfg_col[0]); i++)
    {
s3c2410_gpio_cfgpin(button_cfg_col[i].pin, button_cfg_col[i].set_outp);//设置为输出模式
s3c2410_gpio_pullup(button_cfg_col[i].pin, 0);//关闭内部上拉电阻
s3c2410_gpio_setpin(button_cfg_col[i].pin, 0);//端口全清0,设置为低电平
    }
  
    for (i=0; i <sizeof(button_cfg_row)/sizeof(button_cfg_row[0]); i++)
    {                        
s3c2410_gpio_cfgpin(button_cfg_row[i].pin, button_cfg_row[i].set_eint);  //端口设置为在中断模式   
set_irq_type(button_cfg_row[i].irq, IRQ_TYPE_EDGE_FALLING);                    
    }
}

static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
    int i;
   
    struct button_irq_desc *button_cfg_row = (struct button_irq_desc *)dev_id;
   
    printk("interrupt %s  \n", button_cfg_row->name);  
  
    disable_irq(button_cfg_row->irq);
        
    // disable_irq(),关闭中断,问题就出在这,中断是关闭了,但程序也从这退出了,
    // 接下来扫描键盘的工作都没执行;
    // 如果不执行这句,不关中断,在整个按键按下的过程中总是不断的在进入这个中断服务程序,
    // 产生n多个按键按下的信号;
      
    printk("1\n");

    for (i=0; i <sizeof(button_cfg_row)/sizeof(button_cfg_row[0]);i++)
    {
s3c2410_gpio_cfgpin(button_cfg_row[i].pin, button_cfg_row[i].set_inp);
    }
   
    mdelay(10);
      
    key_scan();  // 键盘扫描

    port_init(); // 重新设置各端口的初始状态

    enable_irq(button_cfg_row->irq);

    return IRQ_RETVAL(IRQ_HANDLED);
}

static int EmbedSky_buttons_open(struct inode *inode, struct file *file)
{
int i;
int err;

port_init();

for (i=0; i <sizeof(button_cfg_row)/sizeof(button_cfg_row[0]); i++)
{                                                
      err = request_irq(button_cfg_row[i].irq, buttons_interrupt, IRQF_TRIGGER_FALLING,  
                                    button_cfg_row[i].name, (void *)&button_cfg_row[i]);
if (err)
{
printk("request irq err");
break;
}
}

if (err)
{
for (; i >= 0; i--)
{
disable_irq(button_cfg_row[i].irq);
free_irq(button_cfg_row[i].irq, (void *)&button_cfg_row[i]);
}
printk("button open Err %d\n", err);

return -EBUSY;
}

printk("button open ok\n");
return 0;
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号-2 )

GMT+8, 2024-6-29 16:44 , Processed in 1.062500 second(s), 18 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表