К отладочной плате SK-AT91SAM9G45-XC6SLX_V1B с установленным на нее Linux kernel, подключена матрица кнопок с подтяжкой к питанию. Написал модуль линукса, чтобы он мне в устройстве "\dev\Keys" показывал какая кнопка нажата. Линии матрицы я подвязал к прерываниям, а столбцы к нулям. При нажатии на кнопку, модуль по отрицательному фронту запускает прерывание и начинает сканировать все кнопки, создавая еще прерывания и так, пока не выдаст ошибку или пока не отпустить кнопку.
Как сделать так, чтобы прерывания не вызывались во время выполнения функции прерывания??
Флаги все перебрал, disable_irq вообще не вариант((
Ошибка в командной строке появляется после нажатия на кнопку более секунды!
#irq 88: nobody cared (try booting with the "irqpoll" option)
[<c002f584>] (unwind_backtrace+0x0/0xf4) from [<c0066dc8>] (__report_bad_irq+0x74/0xa4)
[<c0066dc8>] (__report_bad_irq+0x74/0xa4) from [<c0066f7c>] (note_interrupt+0x184/0x1f4)
[<c0066f7c>] (note_interrupt+0x184/0x1f4) from [<c00678a0>] (handle_simple_irq+0x7c/0x94)
[<c00678a0>] (handle_simple_irq+0x7c/0x94) from [<c0033448>] (gpio_irq_handler+0xb8/0xdc)
[<c0033448>] (gpio_irq_handler+0xb8/0xdc) from [<c0029044>] (asm_do_IRQ+0x44/0xa4)
[<c0029044>] (asm_do_IRQ+0x44/0xa4) from [<c0029ad4>] (__irq_svc+0x34/0x60)
Exception stack(0xc042df70 to 0xc042dfb8)
df60: 00000000 0005317f 0005217f 60000013
df80: c042c000 c04526e8 c042fb88 c042fb80 70022f5c 41069265 70022f28 00000000
dfa0: 600000d3 c042dfb8 c002b52c c002b538 60000013 ffffffff
[<c0029ad4>] (__irq_svc+0x34/0x60) from [<c002b538>] (default_idle+0x2c/0x34)
[<c002b538>] (default_idle+0x2c/0x34) from [<c002b3c0>] (cpu_idle+0x6c/0xa4)
[<c002b3c0>] (cpu_idle+0x6c/0xa4) from [<c03150e0>] (rest_init+0xc8/0x120)
[<c03150e0>] (rest_init+0xc8/0x120) from [<c0008e60>] (start_kernel+0x414/0x5ac)
[<c0008e60>] (start_kernel+0x414/0x5ac) from [<70008034>] (0x70008034)
handlers:
[<c01fef60>] (my_interrupt+0x0/0x22c)
Disabling IRQ #88
После одной ошибки на линии прерывания он больше не выполняет прерывание по фронтам, а делает прерывание самостоятельно через какое-то время. А в столбце "CPU0" в таблице "#cat /dev/interrupts" ничего не меняется!
Пробовал даже переназначать порты input на output (а output на input) в цикле опроса, чтобы прерываний не происходило, но и это не помогло((
Код
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <mach/gpio.h>
#include <asm-generic/gpio.h>
#include <mach/at91_pio.h>
#include <asm/gpio.h>
static int my_dev_id;
int bline[6];
unsigned long save_key = 0;
const char button_name[30][15] = {
{"Button Clear\n"},{"Left line 1\n"},{"Left line 2\n"},{"Left line 3\n"},{"Left line 4\n"},{"Return\n"},\
{"Escape\n"},{"Right line 1\n"},{"Right line 2\n"},{"Right line 3\n"},{"Right line 4\n"},{"Down\n"},\
{"Up\n"},{"Bk Sp\n"},{"Enter\n"},{"7\n"},{"4\n"},{"1\n"},{"0\n"},{"F1\n"},{"8\n"},\
{"5\n"},{"2\n"},{".\n"},{"F2\n"},{"9\n"},{"6\n"},{"3\n"},{"+/-\n"},{"F3\n"}};
char * str_word (void)
{
unsigned int count;
for (count = 29; count>=1; count--) if (save_key&(0x1<<count)) break;
return &button_name[count];
}
static ssize_t hello_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
char *hello_str = str_word ();
int len;
len = strlen(hello_str);
if (count < len) return -EINVAL;
if (*ppos != 0) return 0;
if (copy_to_user(buf, hello_str, len)) return -EINVAL;
*ppos = len;
return len;
}
static irqreturn_t my_interrupt (int irq, void *dev_id) {
unsigned char line;
unsigned long key = 0;
at91_set_gpio_output(AT91_PIN_PB6, 1);
at91_set_gpio_output(AT91_PIN_PB7, 1);
at91_set_gpio_output(AT91_PIN_PB8, 1);
at91_set_gpio_output(AT91_PIN_PB9, 1);
at91_set_gpio_output(AT91_PIN_PB10, 1);
key = 0;
for (line =1; line<=5; line++) {
if (line == 5) at91_set_gpio_output(AT91_PIN_PB6, 0);
if (line == 4) at91_set_gpio_output(AT91_PIN_PB7, 0);
if (line == 3) at91_set_gpio_output(AT91_PIN_PB8, 0);
if (line == 2) at91_set_gpio_output(AT91_PIN_PB9, 0);
if (line == 1) at91_set_gpio_output(AT91_PIN_PB10, 0);
key <<= 6;
if (!at91_get_gpio_value(AT91_PIN_PB26)) key |= (0x1<<6);
if (!at91_get_gpio_value(AT91_PIN_PB25)) key |= (0x1<<5);
if (!at91_get_gpio_value(AT91_PIN_PB24)) key |= (0x1<<4);
if (!at91_get_gpio_value(AT91_PIN_PB23)) key |= (0x1<<3);
if (!at91_get_gpio_value(AT91_PIN_PB22)) key |= (0x1<<2);
if (!at91_get_gpio_value(AT91_PIN_PB28)) key |= (0x1<<1);
if (line == 5) at91_set_gpio_output(AT91_PIN_PB6, 1);
if (line == 4) at91_set_gpio_output(AT91_PIN_PB7, 1);
if (line == 3) at91_set_gpio_output(AT91_PIN_PB8, 1);
if (line == 2) at91_set_gpio_output(AT91_PIN_PB9, 1);
if (line == 1) at91_set_gpio_output(AT91_PIN_PB10, 1);
}
if (key==0) save_key |= 0x1;
else save_key = key;
at91_set_gpio_output(AT91_PIN_PB6, 0);
at91_set_gpio_output(AT91_PIN_PB7, 0);
at91_set_gpio_output(AT91_PIN_PB8, 0);
at91_set_gpio_output(AT91_PIN_PB9, 0);
at91_set_gpio_output(AT91_PIN_PB10, 0);
return IRQ_NONE;
}
static const struct file_operations hello_fops = {
.owner = THIS_MODULE,
.read = hello_read,
};
static struct miscdevice hello_dev = {
MISC_DYNAMIC_MINOR,
"Key",
&hello_fops
};
static int __init my_init ( void){
unsigned long irqflags;
printk(KERN_INFO "My_init\n");
at91_set_gpio_output(AT91_PIN_PB6, 0);
at91_set_gpio_output(AT91_PIN_PB7, 0);
at91_set_gpio_output(AT91_PIN_PB8, 0);
at91_set_gpio_output(AT91_PIN_PB9, 0);
at91_set_gpio_output(AT91_PIN_PB10, 0);
at91_set_gpio_input(AT91_PIN_PB22, 1);
at91_set_gpio_input(AT91_PIN_PB23, 1);
at91_set_gpio_input(AT91_PIN_PB24, 1);
at91_set_gpio_input(AT91_PIN_PB25, 1);
at91_set_gpio_input(AT91_PIN_PB26, 1);
at91_set_gpio_input(AT91_PIN_PB28, 1);
bline[0] = gpio_to_irq(AT91_PIN_PB22);
if (bline[0] < 0) {printk(KERN_INFO "\n\nError_button_22_irq!!\n\n");}
bline[1] = gpio_to_irq(AT91_PIN_PB23);
if (bline[1] < 0) {printk(KERN_INFO "\n\nError_button_23_irq!!\n\n");}
bline[2] = gpio_to_irq(AT91_PIN_PB24);
if (bline[2] < 0) {printk(KERN_INFO "\n\nError_button_24_irq!!\n\n");}
bline[3] = gpio_to_irq(AT91_PIN_PB25);
if (bline[3] < 0) {printk(KERN_INFO "\n\nError_button_25_irq!!\n\n");}
bline[4] = gpio_to_irq(AT91_PIN_PB26);
if (bline[4] < 0) {printk(KERN_INFO "\n\nError_button_26_irq!!\n\n");}
bline[5] = gpio_to_irq(AT91_PIN_PB28);
if (bline[5] < 0) {printk(KERN_INFO "\n\nError_button_28_irq!!\n\n");}
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED;
if (request_irq( bline[0], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[1], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[2], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[3], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[4], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[5], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (misc_register(&hello_dev)) printk(KERN_ERR "Error\n");
printk( KERN_INFO "Siccessfully loading ISR handler on IRQ %d\n", irqq );
return 0;
}
static void __exit my_exit(void) {
int x;
for (x=0; x<=5; x++) synchronize_irq (bline[x]);
for (x=0; x<=5; x++) free_irq(bline[x], &my_dev_id);
printk(KERN_INFO "Successfully unloading, irq_counter = %d\n", irq_counter);
}
module_init(my_init);
module_exit(my_exit);
MODULE_AUTHOR("My_copy_internet");
MODULE_DESCRIPTION("LDD:1.0 s_08/lab1_interrupt.c");
MODULE_LICENSE( "GPL v2");
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <mach/gpio.h>
#include <asm-generic/gpio.h>
#include <mach/at91_pio.h>
#include <asm/gpio.h>
static int my_dev_id;
int bline[6];
unsigned long save_key = 0;
const char button_name[30][15] = {
{"Button Clear\n"},{"Left line 1\n"},{"Left line 2\n"},{"Left line 3\n"},{"Left line 4\n"},{"Return\n"},\
{"Escape\n"},{"Right line 1\n"},{"Right line 2\n"},{"Right line 3\n"},{"Right line 4\n"},{"Down\n"},\
{"Up\n"},{"Bk Sp\n"},{"Enter\n"},{"7\n"},{"4\n"},{"1\n"},{"0\n"},{"F1\n"},{"8\n"},\
{"5\n"},{"2\n"},{".\n"},{"F2\n"},{"9\n"},{"6\n"},{"3\n"},{"+/-\n"},{"F3\n"}};
char * str_word (void)
{
unsigned int count;
for (count = 29; count>=1; count--) if (save_key&(0x1<<count)) break;
return &button_name[count];
}
static ssize_t hello_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
char *hello_str = str_word ();
int len;
len = strlen(hello_str);
if (count < len) return -EINVAL;
if (*ppos != 0) return 0;
if (copy_to_user(buf, hello_str, len)) return -EINVAL;
*ppos = len;
return len;
}
static irqreturn_t my_interrupt (int irq, void *dev_id) {
unsigned char line;
unsigned long key = 0;
at91_set_gpio_output(AT91_PIN_PB6, 1);
at91_set_gpio_output(AT91_PIN_PB7, 1);
at91_set_gpio_output(AT91_PIN_PB8, 1);
at91_set_gpio_output(AT91_PIN_PB9, 1);
at91_set_gpio_output(AT91_PIN_PB10, 1);
key = 0;
for (line =1; line<=5; line++) {
if (line == 5) at91_set_gpio_output(AT91_PIN_PB6, 0);
if (line == 4) at91_set_gpio_output(AT91_PIN_PB7, 0);
if (line == 3) at91_set_gpio_output(AT91_PIN_PB8, 0);
if (line == 2) at91_set_gpio_output(AT91_PIN_PB9, 0);
if (line == 1) at91_set_gpio_output(AT91_PIN_PB10, 0);
key <<= 6;
if (!at91_get_gpio_value(AT91_PIN_PB26)) key |= (0x1<<6);
if (!at91_get_gpio_value(AT91_PIN_PB25)) key |= (0x1<<5);
if (!at91_get_gpio_value(AT91_PIN_PB24)) key |= (0x1<<4);
if (!at91_get_gpio_value(AT91_PIN_PB23)) key |= (0x1<<3);
if (!at91_get_gpio_value(AT91_PIN_PB22)) key |= (0x1<<2);
if (!at91_get_gpio_value(AT91_PIN_PB28)) key |= (0x1<<1);
if (line == 5) at91_set_gpio_output(AT91_PIN_PB6, 1);
if (line == 4) at91_set_gpio_output(AT91_PIN_PB7, 1);
if (line == 3) at91_set_gpio_output(AT91_PIN_PB8, 1);
if (line == 2) at91_set_gpio_output(AT91_PIN_PB9, 1);
if (line == 1) at91_set_gpio_output(AT91_PIN_PB10, 1);
}
if (key==0) save_key |= 0x1;
else save_key = key;
at91_set_gpio_output(AT91_PIN_PB6, 0);
at91_set_gpio_output(AT91_PIN_PB7, 0);
at91_set_gpio_output(AT91_PIN_PB8, 0);
at91_set_gpio_output(AT91_PIN_PB9, 0);
at91_set_gpio_output(AT91_PIN_PB10, 0);
return IRQ_NONE;
}
static const struct file_operations hello_fops = {
.owner = THIS_MODULE,
.read = hello_read,
};
static struct miscdevice hello_dev = {
MISC_DYNAMIC_MINOR,
"Key",
&hello_fops
};
static int __init my_init ( void){
unsigned long irqflags;
printk(KERN_INFO "My_init\n");
at91_set_gpio_output(AT91_PIN_PB6, 0);
at91_set_gpio_output(AT91_PIN_PB7, 0);
at91_set_gpio_output(AT91_PIN_PB8, 0);
at91_set_gpio_output(AT91_PIN_PB9, 0);
at91_set_gpio_output(AT91_PIN_PB10, 0);
at91_set_gpio_input(AT91_PIN_PB22, 1);
at91_set_gpio_input(AT91_PIN_PB23, 1);
at91_set_gpio_input(AT91_PIN_PB24, 1);
at91_set_gpio_input(AT91_PIN_PB25, 1);
at91_set_gpio_input(AT91_PIN_PB26, 1);
at91_set_gpio_input(AT91_PIN_PB28, 1);
bline[0] = gpio_to_irq(AT91_PIN_PB22);
if (bline[0] < 0) {printk(KERN_INFO "\n\nError_button_22_irq!!\n\n");}
bline[1] = gpio_to_irq(AT91_PIN_PB23);
if (bline[1] < 0) {printk(KERN_INFO "\n\nError_button_23_irq!!\n\n");}
bline[2] = gpio_to_irq(AT91_PIN_PB24);
if (bline[2] < 0) {printk(KERN_INFO "\n\nError_button_24_irq!!\n\n");}
bline[3] = gpio_to_irq(AT91_PIN_PB25);
if (bline[3] < 0) {printk(KERN_INFO "\n\nError_button_25_irq!!\n\n");}
bline[4] = gpio_to_irq(AT91_PIN_PB26);
if (bline[4] < 0) {printk(KERN_INFO "\n\nError_button_26_irq!!\n\n");}
bline[5] = gpio_to_irq(AT91_PIN_PB28);
if (bline[5] < 0) {printk(KERN_INFO "\n\nError_button_28_irq!!\n\n");}
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED;
if (request_irq( bline[0], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[1], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[2], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[3], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[4], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[5], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (misc_register(&hello_dev)) printk(KERN_ERR "Error\n");
printk( KERN_INFO "Siccessfully loading ISR handler on IRQ %d\n", irqq );
return 0;
}
static void __exit my_exit(void) {
int x;
for (x=0; x<=5; x++) synchronize_irq (bline[x]);
for (x=0; x<=5; x++) free_irq(bline[x], &my_dev_id);
printk(KERN_INFO "Successfully unloading, irq_counter = %d\n", irq_counter);
}
module_init(my_init);
module_exit(my_exit);
MODULE_AUTHOR("My_copy_internet");
MODULE_DESCRIPTION("LDD:1.0 s_08/lab1_interrupt.c");
MODULE_LICENSE( "GPL v2");