Разработка ядра Linux | страница 94



, если же номер прерывания является совместно используемым, то необходимо указывать уникальный идентификатор (cookie) (если устройство не подключено к тине ISA, то, скорее всего, оно поддерживает совместно используемые номера прерываний).

Этот параметр также передается обработчику прерывания при каждом вызове. Обычная практика — это передача указателя на структуру устройства (контекст устройства), так как этот параметр является уникальным, и, кроме того, в обработчике прерывания может быть полезным иметь указатель на эту структуру.

В случае успеха функция >request_irq() возвращает нуль. Возврат ненулевого значения указывает на то, что произошла ошибка и указанный обработчик прерывания не был зарегистрирован. Наиболее часто встречающийся код ошибки — это значение >-EBUSY, что указывает на то, что данная линия запроса на прерывание уже занята (и или при текущем вызове, или при первом вызове не был указан флаг >SA_SHIRQ).

Следует обратить внимание, что функция >request_irq() может переходить в состояние ожидания (sleep) и, соответственно, не может вызываться из контекста прерывания, или в других ситуациях, когда код не может блокироваться. Распространенной ошибкой является мнение, что функцию >request_irq() можно безопасно вызывать в случаях, когда нельзя переходить в состояние ожидания. Это происходит отчасти от того, что действительно сразу непонятно, почему функция >request_irq() должна чего-то ожидать. Дело в том. что при регистрации происходит добавление информации о линии прерывания в каталоге >/proc/irq. Функция >proc_mkdir() используется для создания новых элементов на файловой системе >procfs. Эта функция вызывает функцию >proc_create() для создания новых элементов файловой системы >procfs, которая в свою очередь вызывает функцию >kmalloc() для выделения памяти. Как будет показано в главе 11, "Управление памятью", функция >kmalloc() может переходить в состояние ожидания. Вот так вот!

Для регистрации линии прерывания и инсталляции обработчика в коде драйвера можно использовать следующий вызов.

>if (request_irq(irqn, my_interrupt, SA_SHIRQ, "my_device", dev)) {

> printk(KERN_ERR "my_device: cannot register IRQ %d\n", irqn);

> return -EIO;

>}

В этом примере параметр >irqn — это запрошенный номер линии запроса на прерывание, параметр >my_interrupt — это обработчик этой линии прерывания, линия запроса на прерывание может быть совместно используемой, имя устройства — >"my_device", >dev — значение параметра