Разработка ядра Linux | страница 99
>if (request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL) {
> printk(KERN_ERR "rtc: cannot register IRQ %d\n" , rtc_irq);
> return -EIO;
>}
Из данного примера видно, что номер линии прерывания — это константа >RTC_IRQ
, значение которой определяется отдельно для каждой аппаратной платформы с помощью препроцессора. Например, для персональных компьютеров это значение всегда соответствует >IRQ 8
. Второй параметр— это обработчик прерывания, >rtc_interrupt
, при выполнении которого запрещены все прерывания в связи с указанием флага >SA_INTERRUPT
. Из четвертого параметра можно заключить, что драйвер будет иметь имя >"rtc"
. Так как наше устройство не может использовать линию прерывания совместно с другими устройствами и обработчик прерывания не используется для каких-либо других целей, в качестве параметра >dev_id
передается значение >NULL
.
И наконец, собственно сам обработчик прерывания.
>/*
>* Очень маленький обработчик прерывания. Он выполняется с
>* установленным флагом SA_INTERRUPT, однако существует
>* возможность конфликта с выполнением функции set_rtc_mmss()
>* (обработчик прерывания rtc и обработчик прерывания системного
>* таймера могут выполняться одновременно на двух разных
>* процессорах). Следовательно, необходимо сериализировать доступ
>* к микросхеме с помощью спин-блокировки rtc_lock, что должно
>* быть сделано для всех аппаратных платформ в коде работы с
>* таймером. (Тело функции set_rtc_mmss() ищите в файлах
>* ./arch/XXXX/kernel/time.c)
>*/
>static irqreturn_t rtc_interrupt(int irq, void *dev_id,
> struct pt_regs *regs) {
> /*
> * Прерывание может оказаться прерыванием таймера, прерыванием
> * завершения обновления или периодическим прерыванием.
> * Состояние (причина) прерывания хранится в самом
> * младшем байте, а общее количество прерывание — в оставшейся
> * части переменной rtc_irq_data
> */
> spin_lock(&rtc_lock);
> rtc_irq_data += 0x100;
> rtc_irq_data &= ~0xff;
> rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
> if (rtc_status & RTC_TIMER_ON)
> mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
> spin_unlock(&rtc_lock);
> /*
> * Теперь выполним остальные действия
> */
> spin_lock(&rtc_task_lock);
> if (rtc_callback)
> rtc_callback->func(rtc_callback->private_data);
> spin_unlock(&rtc_task_lock);
> wake_up_interruptible(&rtc_wait);
> kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
> return IRQ_HANDLED;
>}
Эта функция вызывается всякий раз, когда система получает прерывание от устройства RTC. Прежде всего, следует обратить внимание на вызовы функций работы со спин-блокировками: первая группа вызовов гарантирует, что к переменной