|
内核版本使用的是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;
} |
|