Прерывание от клавиатуры linux

Get Keyboard Interrupt in C

The above program stops when the time reaches 0. My requirement is during the runtime of the program, If I press any key like spacebar or any other key, the program gets paused and once again I press the key, the program gets resumed. So for doing this, before execution of while condition, we submit the signal handler for keyboard interrupt. In C how to do this. What is the function used to get keyboard interrupt. I dont want to get input from the user, I want to handle the interrupt generated by the user through keyboard. Thanks in Advance.

@venki and vish4071 Please expand on how signals can be used to get keyboard presses. There isn’t a way that I know of. Signals can be used to catch certain key combinations such as ctrl-c. But the question seems to be about getting arbitrary key presses.

On Linux you can receive key presses via the Input subsystem. Read about it here. Basically an input device is opened such as /dev/input/event0 which corresponds to the keyboard device. Then events can be read from that device. Each key press and release will generate an event.

3 Answers 3

You need conio.h for your requirement.It defines kbhit() and getch() both wait for input from keyboard.

Whenever kbhit() is called, it checks the keyboard buffer and returns a nonzero value if the buffer has any keypress otherwise 0 is returned.

The conio.h is used by MSDOS compilers and is not the part of standard C libraries (ISO). It is also not defined in POSIX.

#include #include int main() < while(1) < while(!kbhit()) < //works continuously until interrupted by keyboard input. printf("M Tired. Break Me\n"); >getch(); > return 0; > 

For linux you may use the following snippet to implement kbhit() by using fnctl() from fnctl.h for signal handling:

 #include #include #include int kbhit(void) < struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) < ungetc(ch, stdin); return 1; >return 0; > 

The keyboard does not exist in purely standard C99 or C11 (stdin is not a keyboard, and could be a pipe(7) so is not always a tty(4); you might read from /dev/tty . ).

So it is much less simple that what you want it to be, and it is operating system specific. I am focusing on Linux.

Read much more about ttys, notably read the tty demystified. Notice that tty are usually in cooked mode, where the kernel is buffering lines (in addition of stdin being line buffered).

The reasonable way is to use a terminal library like ncurses or readline. These libraries are setting the tty in raw mode (which you might do by yourself, see this and termios(3); you’ll probably need also to poll(2)). Be sure to exit properly and reset the tty to cooked mode before exiting.

Читайте также:  Открыть файл консоли линукс

But your life is probably too short to dive into termios(3) and tty_ioctl(4) so just use ncurses or readline

You could also consider some GUI application (e.g. above X11 or Wayland). Then use a toolkit (GTK, Qt, . ).

Источник

11.1. Обработка прерываний

Везде, кроме предыдущей главы, все наши действия в ядре сводилось к ответам на разные запросы от процессов, к работе со специальными файлом, посылке команд ioctl или запуску системных вызовов. Однако работа ядра не может сводится только к обработке запросов. Еще одна немаловажная задача — это работа с аппаратурой компьютера.

Существует два типа взаимодействий между CPU и остальной аппаратной частью компьютера. Первый — передача команд аппаратным средствам, второй — прием ответов от аппаратуры. Второй тип взаимодействия — прерывания, является наиболее тяжелым в обработке, потому что прерывания возникают тогда, когда это удобно устройству, а не CPU. Аппаратные устройства обычно имеют весьма ограниченный объем ОЗУ, и если не считать поставляемую ими информацию немедленно, то она может потеряться.

В Linux аппаратные прерывания называются IRQ (сокращенно от Interrupt ReQuests — Запросы на Прерывание). [14] Имеется два типа IRQ: «короткие» и «длинные». «Короткие» IRQ занимают очень короткий период времени, в течение которого работа операционной системы будет заблокирована, а так же будет невозможна обработка других прерываний. «Длинные» IRQ могут занять довольно продолжительное время, в течение которого могут обрабатываться и другие прерывания (но не прерывания из того же самого устройства). Поэтому, иногда бывает благоразумным разбить выполнение работы на исполняемую внутри обработчика прерываний (т.е. подтверждение прерывания, изменение состояния и пр.) и работу, которая может быть отложена на некоторое время (например постобработка данных, активизация процессов, ожидающих эти данные и т.п.). Если это возможно, лучше объявлять обработчики прерывания «длинными».

Когда CPU получает прерывание, он останавливает любые процессы (если это не более приоритетное прерывание, тогда обработка пришедшего прерывания произойдет только тогда, когда более приоритетное будет завершено), сохраняет некоторые параметры в стеке и вызывает обработчик прерывания. Это означает, что не все действия допустимы внутри обработчика прерывания, потому что система находится в неизвестном состоянии. Решение проблемы: обработчик прерывания определяет — что должно быть сделано немедленно (обычно что-то прочитать из устройства или что-то послать ему), а затем запланировать обработку поступившей информации на более позднее время (это называется «bottom halves» — «нижние половины») и вернуть управление. Ядро гарантирует вызов «нижней половины» так быстро, насколько это возможно. Когда это произойдет, то наш обработчик — «нижняя половина», уже не будет стеснен какими-то рамками и ему будет доступно все то, что доступно обычным модулям ядра.

Устанавливается обработчик прерывания вызовом request_irq. Ей передаются номер IRQ, имя функции-обработчика, флаги, имя для /proc/interrupts и дополнительный параметр для обработчика прерываний. Флаги могут включать SA_SHIRQ, чтобы указать, что прерывание может обслуживаться несколькими обработчиками (обычно, по той простой причине, что на одном IRQ может «сидеть» несколько устройств) и SA_INTERRUPT, чтобы указать, что это «короткое» прерывание. Эта функция установит обработчик только в том случае, если на заданном IRQ еще нет обработчика прерывания, или если существующий обработчик зарегистрировал совместную обработку прерывания флагом SA_SHIRQ.

Читайте также:  Открыть html файл linux

Во время обработки прерывания, из функции-обработчика прерывания, мы можем получить данные от устройства и затем, с помощью queue_task_irq, tq_immediate и mark_bh(BH_IMMEDIATE), запланировать «нижнюю половину». В ранних версиях Linux имелся массив только из 32 «нижних половин», теперь же, одна из них (а именно BH_IMMEDIATE) используется для обслуживания целого списка «нижних половин» драйверов. Вызов mark_bh(BH_IMMEDIATE) как раз и вставляет «нижнюю половину» драйвера в этот список, планируя таким образом ее исполнение.

11.2. Клавиатура на архитектуре Intel

Материал, рассматриваемый в оставшейся части этой главы, может быть применим исключительно к архитектуре Intel. На других платформах код примера работать не будет.

Было очень трудно выбрать тип драйвера, который можно было бы использовать в качестве примера в этой главе. С одной стороны пример должен быть достаточно полезным, он должен работать на любом компьютере и быть достаточно выразительным. С другой стороны, в ядро уже включено огромное количество драйверов практически для всех общеизвестных и широкораспространенных устройств. Эти драйверы не смогли бы совместно работать с тем, что я собирался написать. Наконец я принял решение представить в качестве примера — обработчик прерываний от клавиатуры, но для демонстрации работоспособности кода сначала придется отключить стандартный обработчик прерываний от клавиатуры, а так как этот символ объявлен как static (в файле drivers/char/keyboard.c), то нет никакого способа восстановить обработчик. Поэтому, прежде чем вы дадите команду insmod, перейдите в другую консоль и дайте команду sleep 120; reboot, если ваша файловая система представляет для вас хоть какую-нибудь ценность.

Этот пример захватывает обработку IRQ 1 — прерывание от клавиатуры на архитектуре Intel. При получении прерывания обработчик читает состояние клавиатуры (inb(0x64)) и скан-код нажатой клавиши. Затем, как только ядро сочтет возможным, оно вызывает got_char (она играет роль «нижней половины»), которая выводит, через printk, код клавиши (младшие семь бит скан-кода) и признак «нажата/отпущена» (8-й бит скан-кода — 0 или 1 соответственно).

Пример 11-1. intrpt.c

/* * intrpt.c - Обработчик прерываний. * * Copyright (C) 2001 by Peter Jay Salzman */ /* * Standard in kernel modules */ #include /* Все-таки мы работаем с ядром! */ #include /* Необходимо для любого модуля */ #include /* очереди задач */ #include /* Взаимодействие с планировщиком */ #include /* определение irqreturn_t */ #include  #define MY_WORK_QUEUE_NAME "WQsched.c" static struct workqueue_struct *my_workqueue; /* * Эта функция вызывается ядром, поэтому в ней будут безопасны все действия * которые допустимы в модулях ядра. */ static void got_char(void *scancode) { printk("Scan Code %x %s.\n", (int)*((char *)scancode) & 0x7F, *((char *)scancode) & 0x80 ? "Released" : "Pressed"); } /* * Обработчик прерываний от клавиатуры. Он считывает информацию с клавиатуры * и передает ее менее критичной по времени исполнения части, * которая будет запущена сразу же, как только ядро сочтет это возможным. */ irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs) { /* * Эти переменные объявлены статическими, чтобы имелась возможность * доступа к ним (посредством указателей) из "нижней половины". */ static int initialised = 0; static unsigned char scancode; static struct work_struct task; unsigned char status; /* * Прочитать состояние клавиатуры */ status = inb(0x64); scancode = inb(0x60); if (initialised == 0) { INIT_WORK(&task, got_char, &scancode); initialised = 1; } else { PREPARE_WORK(&task, got_char, &scancode); } queue_work(my_workqueue, &task); return IRQ_HANDLED; } /* * Инициализация модуля - регистрация обработчика прерывания */ int init_module() { my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME); /* * Поскольку стандартный обработчик прерываний от клавиатуры не может * сосуществовать с таким как наш, то придется запретить его * (освободить IRQ) прежде, чем что либо сделать. * Но поскольку мы не знаем где он находится в ядре, то мы лишены * возможности переустановить его - поэтому компьютер придется перезагрузить * после опробования этого примера. */ free_irq(1, NULL); /* * Подставить свой обработчик (irq_handler) на IRQ 1. * SA_SHIRQ означает, что мы допускаем возможность совместного * обслуживания этого IRQ другими обработчиками. */ return request_irq(1, /* Номер IRQ */ irq_handler, /* наш обработчик */ SA_SHIRQ, "test_keyboard_irq_handler", (void *)(irq_handler)); } /* * Завершение работы */ void cleanup_module() { /* * Эта функция добавлена лишь для полноты изложения. * Она вообще бессмысленна, поскольку я не вижу способа * восстановить стандартный обработчик прерываний от клавиатуры * поэтому необходимо выполнить перезагрузку системы. */ free_irq(1, NULL); } /* * некоторые функции, относящиеся к work_queue * доступны только если модуль лицензирован под GPL */ MODULE_LICENSE("GPL"); 

Источник

Читайте также:  Cryptopro csp for linux

Русские Блоги

Обработка прерывания Linux —- Использование линии прерывания клавиатуры

Код привода: использование линии прерывания № 1 (система X86, линия прерывания используется для клавиатуры)
chardev.c

#include #include #include #include #include #include #include #include #include struct char_dev< char dev_name[10]; struct file_operations dev_fops; dev_t dev_number; struct cdev *dev_cdev; >my_dev; irqreturn_t my_interrupt(int irq, void *dev_id, struct pt_regs *regs) < printk(KERN_EMERG"*******interrupt******\n"); return IRQ_HANDLED; >static int char_open(struct inode *inode, struct file *file)< int ret; printk(KERN_EMERG"******open*****\n"); ret = request_irq(1, my_interrupt, IRQF_SHARED , my_dev.dev_name, &my_dev); if(ret == -EINVAL)< printk(KERN_EMERG"Failed to apply for the interrupt number ,reason:-EINVAL\n"); >else if(ret == -EBUSY) < printk(KERN_EMERG"Failed to apply for the interrupt number ,reason:-EBUSY\n"); >printk(KERN_EMERG"******open end*****\n"); return 0; > static int __init chardev_init(void) < printk(KERN_EMERG"############chardev_init############\n"); int ret; memset(&my_dev, 0,sizeof(my_dev)); strcpy(my_dev.dev_name,"chardev"); my_dev.dev_fops.owner = THIS_MODULE; my_dev.dev_fops.open = char_open; // apply for dev number ret = alloc_chrdev_region(&my_dev.dev_number, 0, 1, my_dev.dev_name); if (ret < 0)< printk(KERN_EMERG"alloc_chrdev_region fail\n"); return ret; >//add cdev to kernel cdev_init(&my_dev.dev_cdev, &my_dev.dev_fops); cdev_add (&my_dev.dev_cdev, my_dev.dev_number, 1); printk(KERN_EMERG"############chardev_init end############\n"); return 0; > static void __exit chardev_exit(void) module_init(chardev_init); module_exit(chardev_exit); MODULE_LICENSE("GPL"); 
ifneq ($(KERNELRELEASE),) obj-m := chardev.o else PWD := $(shell pwd) KVER := $(shell uname -r) KDIR := /lib/modules/$(KVER)/build all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: rm -fr .*.cmd *.o *.mod.c *.ko .tmp_versions modules.* Module.* endif 

Сценарии загрузки модулей: где параметр 1 является основным номером, вам нужно получить Cat / Proc / Devices

#!/bin/sh insmod chardev.ko mknod /dev/chardev c $1 0 chmod 777 /dev/chardev 
#!/bin/sh rm -rf /dev/chardev rmmod chardev.ko 

Тестовый код: TEST.C, после запуска программы тестирования, каждая кнопка будет вызвать прерывание, распечатать информацию, удалить модуль, отменить печать

#include #include #include int main(void) < int fd; fd=open("/dev/chardev",O_RDWR); if(fd<0)< printf("fd<0\n"); >else < printf("fd:%d\n",fd); >> 

Источник

Оцените статью
Adblock
detector