Библиотека сайта rus-linux.net
Цилюрик О.И. Модули ядра Linux | ||
Назад | Внутренние механизмы ядра | Вперед |
Регистрация обработчика прерывания
Функции и определения, реализующие интерфейс регистрации прерывания, объявлены в <linux/interrupt.h>. Первое, что мы должны всегда сделать — это зарегистрировать функцию обработчик прерываний (все прототипы этого раздела взяты из ядра 2.6.37):
typedef irqreturn_t (*irq_handler_t)( int, void* ); int request_irq( unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev ); extern void free_irq( unsigned int irq, void *dev );
- где:
irq - номер линии запрашиваемого прерывания.
handler - указатель на функцию-обработчик.
flags - битовая маска опций (описываемая далее), связанная с управлением прерыванием.
name - символьная строка, используемая в /proc/interrupts, для отображения владельца прерывания.
dev - указатель на уникальный идентификатор устройства на линии IRQ, для не разделяемых прерываний (например шины ISA) может указываться NULL. Данные по указателю dev требуются для удаления только специфицируемого устройства на разделяемой линии IRQ. Первоначально накладывалось единственное требование, чтобы этот указатель был уникальным, например, при размещении-освобождении N однотипных устройств вполне допустимым могла бы быть конструкция:
for( int i = 0; i < N; i++ ) request_irq( irq, handler, 0, const char *name, (void*)i ); ... for( int i = 0; i < N; i++ ) free_irq( irq, (void*)i );
Но позже оказалось целесообразным и удобным использовать именно в качестве *dev — указатель на специфическую для устройства структуру, которая и содержит все характерные данные экземпляра: поскольку для каждого экземпляра создаётся своя копия структуры, то указатели на них и будут уникальны, что и требовалось. На сегодня это общеупотребимая практика увязывать обработчик прерывания со структурами данных устройства.
Примечание: прототипы irq_handler_t и флаги установки обработчика существенно меняются от версии к версии, например, радикально поменялись после 2.6.19, все флаги, именуемые сейчас IRQF_* до этого именовались SA_*. В результате этого можно встретиться с невозможностью компиляции даже относительно недавно разработанных модулей-драйверов.
Флаги установки обработчика:
- группа флагов установки обработчика по уровню (level-triggered) или фронту (edge-triggered):
#define IRQF_TRIGGER_NONE 0x00000000 #define IRQF_TRIGGER_RISING 0x00000001 #define IRQF_TRIGGER_FALLING 0x00000002 #define IRQF_TRIGGER_HIGH 0x00000004 #define IRQF_TRIGGER_LOW 0x00000008 #define IRQF_TRIGGER_MASK ( IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING ) #define IRQF_TRIGGER_PROBE 0x00000010
- другие (не все, только основные, часто используемые) флаги:
IRQF_SHARED — разрешить разделение (совместное использование) линии IRQ с другими устройствами (PCI шина и устройства).
IRQF_PROBE_SHARED — устанавливается вызывающим, когда он предполагает возможные проблемы с совместным использованием.
IRQF_TIMER — флаг, маркирующий это прерывание как таймерное.
IRQF_PERCPU — прерывание закреплённое монопольно за отдельным CPU.
IRQF_NOBALANCING — флаг, запрещающий вовлекать это прерывание в балансировку IRQ.
При успешной установке функция request_irq() возвращает нуль. Возврат ненулевого значения указывает на то, что произошла ошибка и указанный обработчик прерывания не был зарегистрирован. Наиболее часто встречающийся код ошибки — это значение -EBUSY (ошибки в ядре возвращаются отрицательными значениями!), что указывает на то, что данная линия запроса на прерывание уже занята (или при текущем вызове, или при предыдущем вызове для этой линии не был указан флаг IRQF_SHARED).
Предыдущий раздел: | Оглавление | Следующий раздел: |
Общая модель обработки прерывания | Отображение прерываний в /proc |