fademike 0 14 октября, 2013 Опубликовано 14 октября, 2013 · Жалоба Помогите, пожалуйста с проблемой очень начинающему "программисту"! К отладочной плате 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"); gpio_keys.txt Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 9 14 октября, 2013 Опубликовано 14 октября, 2013 · Жалоба Помогите, пожалуйста с проблемой очень начинающему "программисту"! http://lxr.free-electrons.com/source/drive...rix_keypad.c#L2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xor.kruger 0 14 октября, 2013 Опубликовано 14 октября, 2013 · Жалоба Доброго времени суток. Сразу вопрос: почему возникла надобность писать свой модуль? Можно ведь воспользоватся готовым - для этого необходимо установить опцию в ядре CONFIG_KEYBOARD_MATRIX и описать в платформе или DTS как подключены кнопки. update: sasamy опередил :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 9 14 октября, 2013 Опубликовано 14 октября, 2013 · Жалоба Сразу вопрос: почему возникла надобность писать свой модуль? Можно ведь воспользоватся готовым - для этого необходимо установить опцию в ядре CONFIG_KEYBOARD_MATRIX и описать в платформе или DTS как подключены кнопки. У меня случайно даже пример есть как подключить на неиспользуемом ISI матрицу 4х4 :) arch/arm/mach-at91/board-sam9m10g45ek.c ... #include <linux/input/matrix_keypad.h> ... /* * GPIO keyboard */ #if defined(CONFIG_KEYBOARD_MATRIX) || defined(CONFIG_KEYBOARD_MATRIX_MODULE) static const uint32_t ek_keymap[] = { /* KEY(row, col, keycode) */ KEY(0, 0, KEY_0), KEY(0, 1, KEY_1), KEY(0, 2, KEY_2), KEY(0, 3, KEY_3), KEY(1, 0, KEY_4), KEY(1, 1, KEY_5), KEY(1, 2, KEY_6), KEY(1, 3, KEY_7), KEY(2, 0, KEY_8), KEY(2, 1, KEY_9), KEY(2, 2, KEY_COMMA), KEY(2, 3, KEY_ESC), KEY(3, 0, KEY_E), KEY(3, 1, KEY_UP), KEY(3, 2, KEY_ENTER), KEY(3, 3, KEY_DOWN), }; static const struct matrix_keymap_data ek_keymap_data = { .keymap = ek_keymap, .keymap_size = ARRAY_SIZE(ek_keymap), }; static const uint32_t ek_row_gpios[] = { AT91_PIN_PB21, AT91_PIN_PB22, AT91_PIN_PB24, AT91_PIN_PB26 }; static const uint32_t ek_col_gpios[] = { AT91_PIN_PB28, AT91_PIN_PB23, AT91_PIN_PB25, AT91_PIN_PB27 }; static struct matrix_keypad_platform_data ek_mkp_pdata = { .keymap_data = &ek_keymap_data, .row_gpios = ek_row_gpios, .col_gpios = ek_col_gpios, .num_row_gpios = ARRAY_SIZE(ek_row_gpios), .num_col_gpios = ARRAY_SIZE(ek_col_gpios), .col_scan_delay_us = 10, .debounce_ms = 10, .wakeup = 1, .active_low = 1, }; static struct platform_device ek_mkp_device = { .name = "matrix-keypad", .id = -1, .dev = { .platform_data = &ek_mkp_pdata, }, }; static void __init ek_add_device_mkp(void) { int i; for (i = 0; i < ARRAY_SIZE(ek_row_gpios); i++) { at91_set_GPIO_periph(ek_row_gpios[i], 1); at91_set_deglitch(ek_row_gpios[i], 1); } for (i = 0; i < ARRAY_SIZE(ek_col_gpios); i++) at91_set_gpio_output(ek_col_gpios[i], 0); platform_device_register(&ek_mkp_device); } #else static void __init ek_add_device_mkp(void) {} #endif ..... static void __init ek_board_init(void) { .... /* GPIO keyboard */ ek_add_device_mkp(); .... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fademike 0 14 октября, 2013 Опубликовано 14 октября, 2013 · Жалоба Сразу вопрос: почему возникла надобность писать свой модуль? Можно ведь воспользоватся готовым - для этого необходимо установить опцию в ядре CONFIG_KEYBOARD_MATRIX и описать в платформе или DTS как подключены кнопки. Просто, для изучения ОС писал простой модуль опроса матрицы и наткнулся на ошибку в прерываниях, как избавиться от нее я не понял.. Ну, буду тогда использовать Linux/drivers/input/keyboard/matrix_keypad.c sasamy, спасибо за пример! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fademike 0 14 октября, 2013 Опубликовано 14 октября, 2013 · Жалоба А кто-нибудь может подсказать, как вывести консоль на дисплей (/dev/tty1), используя клавиатуру матрицы кнопок с драйвером "Linux/drivers/input/keyboard/matrix_keypad.c"??? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 14 октября, 2013 Опубликовано 14 октября, 2013 (изменено) · Жалоба А кто-нибудь может подсказать, как вывести консоль на дисплей (/dev/tty1), используя клавиатуру матрицы кнопок с драйвером "Linux/drivers/input/keyboard/matrix_keypad.c"??? Я помню только принцип, т.к. в последний раз с год назад возился. Все мыши и клавиатуры определены как класс input: /dev/input/ by-id event0 event10 event12 event3 event5 event7 event9 mouse0 by-path event1 event11 event2 event4 event6 event8 mice Точнее вам надо, чтобы устройство возникло здесь: /sys/class/input/ а в /dev/input/ оно попадет автоматически. Для каждого eventX можно посмотреть к какому устройству он принадлежит cat /sys/class/input/event0/device/name Надо написать еще один драйвер, взаимодействующий с тем, что читает кнопки, либо модифицировать ваш, чтобы он попал в input. В документации ядра есть информация, а также куча примеров в самом ядре. Остальное делается в пользовательском пространстве. Я делал только для Х11, но уверен, что и для остального это совсем не сложно. Изменено 14 октября, 2013 пользователем Tarbal Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sasamy 9 14 октября, 2013 Опубликовано 14 октября, 2013 (изменено) · Жалоба А кто-нибудь может подсказать, как вывести консоль на дисплей (/dev/tty1), используя клавиатуру матрицы кнопок с драйвером "Linux/drivers/input/keyboard/matrix_keypad.c"??? Если корневая собрана в buildroot или вообще стандартный init, то добавить в /etc/inittab строку (если ее нет) tty1::respawn:/sbin/getty 38400 tty1 linux матричная клавиатура - стандартное устройство ввода, ничего дополнительно для нее не нужно, разве что включить в ядре интерфейс, если не включен http://lxr.free-electrons.com/source/drive...ut/Kconfig#L142 Изменено 14 октября, 2013 пользователем sasamy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 14 октября, 2013 Опубликовано 14 октября, 2013 (изменено) · Жалоба Точно. В кернеле ничего делать не надо. http://lxr.free-electrons.com/source/drive...rix_keypad.c#L2 драйвер оперирует с устройством input_dev. Значит вы сможете увидеть, что устройство появилось в системе прочитав имя в одном из /sys/class/input/event0/device/name она совпадет с заданным в строке 567 файла: http://lxr.free-electrons.com/source/drive...rix_keypad.c#L2 .name = "matrix-keypad", Изменено 14 октября, 2013 пользователем Tarbal Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fademike 0 15 октября, 2013 Опубликовано 15 октября, 2013 · Жалоба Все заработало!)) Огромное Вам спасибо!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться