Как добавить peridic обратного вызова таймера в модуль ядра Linux


Я работаю над модулем ядра Linux, который регистрирует обратный вызов для прерываний, поступающих с пользовательской платы, и помещает полученные данные в очередь за интерфейсом устройства char для обработки приложением. Этот модуль должен постоянно отслеживать и измерять прерывания и данные, поступающие с платы, даже если прерывания не поступают с платы, поэтому у него есть еще один обратный вызов, который срабатывает в соответствии со временем.

Текущая реализация использует прерывание RTC в качестве константы источник таймера. Я отключаю драйверы ядра RTC (CONFIG_RTC_DRV_CMOS) и запрашиваю IRQ 8 и подключаю обратный вызов таймера в качестве обработчика прерываний RTC. Прерывания генерируются каждую секунду от чипа RTC.

Проблема в том, что мы должны потерять часть способности Linux управлять временем таким образом, потому что только один из rtc-cmos или модуль платы может быть загружен сразу (и, очевидно, мы выбрали модуль платы).

Целевая архитектура - i386 PC.

Я не разработчик ядра и поэтому не имею большого картинка на разработке модуля ядра, но я пытаюсь найти свой путь, и это самое близкое к решению, которое приходит мне на ум:

  • как-то разделить IRQ 8 между обоими модулями (может быть, как request_irq(8, rtc_handler, IRQF_SHARED, rtc_handler)?) или обработчики IRQ chainload.
  • поиск другого способа подключить обработчик из модуля ядра к прерыванию RTC, а не регистрироваться для IRQ 8.
  • поиск другого источника событий 1-секундного таймера, который может быть использован из модуля ядра, возможно, существует стандарт ядро API для этого, я не знаю.
Я полагаю, что может быть простой и стандартный способ сделать это, и я был бы рад, если бы кто-нибудь прокомментировал одно из этих решений или предложил другие.
2 7

2 ответа:

Таймер высокого разрешения ядра Linux hrtimer - это опция. http://lwn.net/Articles/167897/

Вот что я делаю:

#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/sched.h>

static struct hrtimer htimer;
static ktime_t kt_periode;

static void timer_init(void)
{
    kt_periode = ktime_set(0, 104167); //seconds,nanoseconds
    hrtimer_init (& htimer, CLOCK_REALTIME, HRTIMER_MODE_REL);
    htimer.function = timer_function;
    hrtimer_start(& htimer, kt_periode, HRTIMER_MODE_REL);
}

static void timer_cleanup(void)
{
    hrtimer_cancel(& htimer);
}

static enum hrtimer_restart timer_function(struct hrtimer * timer)
{
    // @Do your work here. 

    hrtimer_forward_now(timer, kt_periode);

    return HRTIMER_RESTART;
}

Вероятно, вы хотите использовать тасклет, см. linux/interrupt.h.