LINUX.ORG.RU

Проблема с примером из книги The Linux Kernel Module Programming Guide


0

0

В книге The Linux Kernel Module Programming Guide Peter Jay Salzman Ori Pomerantz 2003-04-04 ver 2.4.0 (http://www.tldp.org/LDP/lkmpg/2.4/html/index.html) есть пример модуля котрый перехватывает прерывание клавиатуры(http://www.tldp.org/LDP/lkmpg/2.4/html/x1210.html#AEN1291). Если закоментировать макросы определения версий для ветки 2.0.х, то модуль(intrpt.c) компилируется под ядро 2.4.28. Но при запуске модуля(insmod intrpt.o) система падает

Kernel Panic: Aiee, killing interrupt handler! In interrupt handler - not syncing

Ведь вроде правильно прерывание захватывется. Меня интересует как правильно подправить модуль чтоб он правильно коректно работал(в лог писал сканкоды) под 2.4.28.

void irq_handler(int irq, void *dev_id, struct pt_regs *regs) { ... }

int init_module() {

free_irq(1, NULL);

return request_irq(1,irq_handler,SA_SHIRQ, "test_keyboard_irq_handler", NULL);

}

просто включи мозг :)

anonymous
()

Согласен с предыдущим оратором

псмотри в документации что делает функция request_irq

P.S. request_irq(1,irq_handler,SA_SHIRQ, "test_keyboard_irq_handler", NULL);

Внимательно посмотри на второй аргумент

anonymous
()
Ответ на: комментарий от anonymous

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

Вот обьявление этой функции в заголовочном файлу моего ядра(2.4.28).

extern int request_irq(unsigned int,

void (*handler)(int, void *, struct pt_regs *),

unsigned long, const char *, void *);

Перед тем как сюда написать я пробовал много вариантов,но безрезультатно... И сейчас не вижу новых... Поскольку опыта маловато, то спросил у ВАС ALL.

Буду очень признателен за более конкретный совет...

Valentin_vv
() автор топика

я не знаю, где и почему у вас kernel panic.

но вот этот вызов:
request_irq(1,irq_handler,SA_SHIRQ, "test_keyboard_irq_handler", NULL);

по идее, не должен завершиться успехом. у вас там SA_SHIRQ,
а драйвер клавиатуры захватывает прерывания exclusive.

кроме того, неправильно (хотя и не смертельно) передавать
dev_id == NULL при SA_SHIRQ.

idle ★★★★★
()
Ответ на: комментарий от idle

не заметил, у вас там free_irq(1, NULL).
вот сколько раз я призывал форматировать код.

тогда что-то в вашем irq handler происходит.

btw, надеюсь, вы отдаете себе отчет, что машину
придется перезагружать после загрузки такого модуля?

idle ★★★★★
()
Ответ на: комментарий от idle

Я сразу дал ссылку на полный код примера.То что прейдется презагружать
 машину,чтоб выгрузить модуль я знаю.НО он даже с таким условием при запуске выдает кернел паник(на ядре 2.4.28).Самое интересно что 2.6.x
вот этот код работает(ниже), но там подругому реализован запуск нижних
 половинок. НО ЗАХВАТ ПРЕРЫВАНИЯ РАБОТАЕТ. ТАКОЙ ЖЕ ЗАХВАТ ДЛЯ 2.4.х 
УЖЕ НЕ РАБОТАЕТ. ТАК ЖЕ НЕ РАБОТАЕТ И ЗАХВАТ ИЗ ПРИМЕРА В КНИГЕ ДЛЯ 
2.4.х. Если поменять в книжном примере SA_SHIRQ на SA_INTERRUPT,и 
убрать free_irq(1,NULL), то модуль не загружается,говорит девайс или 
ресурс занятый. Если оставить free_irq(1,NULL) то таже фигня - кернел 
паник. Вопрос остался открыт...


irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{  .........
  return IRQ_HANDLED;
}
..........
int init_module()
{
  free_irq(1, NULL);
  return request_irq(1,    /* Номер IRQ */
         irq_handler,      /* наш обработчик */
         SA_SHIRQ,
         "test_keyboard_irq_handler",
         (void *)(irq_handler));
}

Valentin_vv
() автор топика
Ответ на: комментарий от Valentin_vv

> Я сразу дал ссылку на полный код примера.

а лучше бы привели код здесь. мне, например, просто
лень кликать и смотреть было.

> ТАКОЙ ЖЕ ЗАХВАТ ДЛЯ 2.4.х УЖЕ НЕ РАБОТАЕТ. ТАК ЖЕ НЕ РАБОТАЕТ
> И ЗАХВАТ ИЗ ПРИМЕРА В КНИГЕ ДЛЯ 2.4.х.

да работет он, я думаю. как я уже писал, проблема
в самом irq_handler().

> Если поменять в книжном примере SA_SHIRQ на SA_INTERRUPT

не используйте SA_INTERRUPT никогда ....

> и убрать free_irq(1,NULL), то модуль не загружается,говорит
> девайс или ресурс занятый.

конечно, смотрите мой первый ответ.

> Вопрос остался открыт...

ok, смотрю по ссылке ...

void irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
        ...
        static struct tq_struct task = {NULL, 0, got_char, &scancode};
                                        ^^^^

вот это уже может вызвать panic, т.к:
4.26/include/linux/tqueue.h:struct tq_struct {
        struct list_head list;
                         ^^^^

initializer, видимо, рассчитывет на указатель здесь.

смотрим на код код из 2.20:
struct tq_struct {
        struct tq_struct *next;         /* linked list of active bh's */

ну, точно.

idle ★★★★★
()
Ответ на: комментарий от idle

указатель на что? У меня в фале tqueue.h:
 tq_struct {
        struct list_head list; /* linked list of active bh's */


Это тоже самое что ты привел в 2.2,только там указатель на next.
Может я в чем то не прав, но я пробовал и  

1)static struct tq_struct task = {0, 0, got_char, &scancode};
и
2)static struct tq_struct task = {&tq_immediate, 0, got_char, &scancode};

Результат - кернел паник.
Что конкретно ты предлагаешь туда подставить чтобы заработало?

Valentin_vv
() автор топика
Ответ на: комментарий от Valentin_vv

> указатель на что? У меня в фале tqueue.h:
> tq_struct {
>     struct list_head list; /* linked list of active bh's */

ну так а я о чем ???

> Что конкретно ты предлагаешь туда подставить чтобы заработало?

я бы - не воспринимайте как наезд - предложил бы немножко
подучить C.

> Может я в чем то не прав, но я пробовал и
>
> 1)static struct tq_struct task = {0, 0, got_char, &scancode};
> и
> 2)static struct tq_struct task = {&tq_immediate, 0, got_char, &scancode};

ну конечно же, оба варианта неправильны.

попробуйте так, например:

static struct tq_struct task = {
        .routine = got_char,
        .data    = &scancode
};

если оно у вас будет продолжать падать, попробуйте разобраться
сами!

ну запустите сначала свой модуль с "пустым" irq_handler(),
вставьте потом printk() перед queue_task(). у вас копеечная
проблема, а вы уже который день ждете, что вам ее решат здесь.
да и польза реальная будет, если сами разберетесь.

idle ★★★★★
()
Ответ на: комментарий от idle

Я добился того что сканкоды клавиш пишет в лог, но клава не 
рабочая(просто пишет в лог, но ниче не пишет на экран и никакие 
команды не работают).Вот исходник.Но как добится того чтобы 
сохранялась работоспособность клавы?В логе говорит что что 
test_keyboard_irq_handler вызвано без dev_id! Дальше идут сканкоды.
Код:

#include <linux/kernel.h>               
#include <linux/module.h>               
#include <linux/sched.h>
#include <linux/tqueue.h>
#include <linux/interrupt.h>
#include <asm/io.h>
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 tq_struct task ={
        .routine=got_char,
        .data=&scancode
    };
   unsigned char status;

   /* Read keyboard status */
   status = inb(0x64);
   scancode = inb(0x60);

  if (initialised == 0) {
    INIT_TQUEUE(&task, got_char, &scancode);
    initialised = 1;
  } else {
    PREPARE_TQUEUE(&task, got_char, &scancode);
  }

   queue_task(&task, &tq_immediate);
   mark_bh(IMMEDIATE_BH);
  return IRQ_HANDLED;
}
 Initialize the module - register the IRQ handler */
int init_module()
{
   free_irq(1, NULL);
return request_irq(1,   /* The number of the keyboard IRQ on PCs */
              irq_handler, /* our handler */
              SA_SHIRQ,
              "test_keyboard_irq_handler", (void *)(irq_handler));
   
}

void cleanup_module()
{
   free_irq(1, NULL);
}
MODULE_LICENSE("GPL");





Valentin_vv
() автор топика
Ответ на: комментарий от Valentin_vv

> Я добился того что сканкоды клавиш пишет в лог, но клава не
> рабочая(просто пишет в лог, но ниче не пишет на экран и никакие
> команды не работают).

ну вы даете. вы жу сами убиваете обработчик, делая
free_irq(1).

скажите лучше, что вам надо сделать?

> В логе говорит что что test_keyboard_irq_handler вызвано без dev_id!

ох... ну если вы задаете вопросы, вы хотя бы читайте,
что вам пишут в ответ!

>     if (initialised == 0) {
>       INIT_TQUEUE(&task, got_char, &scancode);
>       initialised = 1;
>     } else {
>       PREPARE_TQUEUE(&task, got_char, &scancode);
>     }

а это зачем? task уже проинициализирована. что, не
работает без этого (ну правда, глупого) кода?

idle ★★★★★
()
Ответ на: комментарий от idle

Нада сделать так чтобы этот модуль нормально загружался и писал в лог сканкоды, но при этом система сохраняла работоспособность. Было бы очень класно чтобы при выгрузке модуля система тоже сохраняла работоспособность.

Valentin_vv
() автор топика
Ответ на: комментарий от Valentin_vv

я думаю проще всего вам будет вставить нужный
вам код в drivers/char/pc_keyb.c, например в
handle_kbd_event().

либо можно перехватить оригинальный разработчик,
irq_desc[1], но он, похоже не экспортирован.

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

конечно, вы можете прочитать idt, узнать irq_entries_start,
перехватить прерывание на низком уровне.... но как-то
это все скучно.

а зачем, если не секрет?

idle ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.