The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"Помогите разобраться с драйвером!"
Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (C/C++)
Изначальное сообщение [ Отслеживать ]

"Помогите разобраться с драйвером!"  +/
Сообщение от Гагарина Машка email on 06-Дек-13, 14:20 
Добрый день!
Попал мне в лапы драйвер клавиатуры на архитектуре Intel.
Ниже привела исходники, которые нам выдал преподаватель.
Задание состоит в том, чтобы изменить код, написанный под старое второе ядро, так, чтобы драйвер компилировался, как модуль ядра, и работал правильно на новых версиях (3.2, например).
Даже не знаю,с чего начать, может, здесь есть люди, которые в этом понимают?)
Заранее очень благодарна.

/*
*  intrpt.c - Обработчик прерываний.
*
*  Copyright (C) 2001 by Peter Jay Salzman
*/
/*
* Standard in kernel modules
*/
#include <linux/kernel.h>    /* Все-таки мы работаем с ядром! */
#include <linux/module.h>    /* Необходимо для любого модуля */
#include <linux/workqueue.h> /* очереди задач */
#include <linux/sched.h>     /* Взаимодействие с планировщиком
*/
#include <linux/interrupt.h> /* определение irqreturn_t */
#include <asm/io.h>
#define MY_WORK_QUEUE_NAME "WQsched.c"
static struct workqueue_struct *my_workqueue;
/*
* Эта функция вызывается ядром, поэтому в ней будут безопасны
все действия
* которые допустимы в модулях ядра.
*/
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 work_struct task;
  unsigned char status;
  /*
   * Прочитать состояние клавиатуры
   */
  status = inb(0x64);
  scancode = inb(0x60);
  if (initialised == 0) {
    INIT_WORK(&task, got_char, &scancode);
    initialised = 1;
  } else {
    PREPARE_WORK(&task, got_char, &scancode);
}
  queue_work(my_workqueue, &task);
  return IRQ_HANDLED;
}
/*
* Инициализация модуля - регистрация обработчика прерывания
*/
int init_module()
{
  my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME);
  /*
   * Поскольку стандартный обработчик прерываний от клавиатуры

не может
   * сосуществовать с таким как наш, то придется запретить его
   * (освободить IRQ) прежде, чем что либо сделать.
   * Но поскольку мы не знаем где он находится в ядре, то мы
лишены
   * возможности переустановить его - поэтому компьютер придется
перезагрузить
   * после опробования этого примера.
   */
        free_irq(1, NULL);
  /*
   * Подставить свой обработчик (irq_handler) на IRQ 1.
   * SA_SHIRQ означает, что мы допускаем возможность совместного
   * обслуживания этого IRQ другими обработчиками.
   */
  return request_irq(1,    /* Номер IRQ */
         irq_handler,      /* наш обработчик */
         SA_SHIRQ,
         "test_keyboard_irq_handler",
         (void *)(irq_handler));
}
/*
* Завершение работы
*/
void cleanup_module()
{
  /*
   * Эта функция добавлена лишь для полноты изложения.
   * Она вообще бессмысленна, поскольку я не вижу способа
   * восстановить стандартный обработчик прерываний от
клавиатуры
   * поэтому необходимо выполнить перезагрузку системы.
   */
  free_irq(1, NULL);
}
/*
* некоторые функции, относящиеся к work_queue
* доступны только если модуль лицензирован под GPL
*/
MODULE_LICENSE("GPL");

Ответить | Правка | Cообщить модератору

Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 06-Дек-13, 17:40 
> чтобы драйвер компилировался, как модуль ядра

1. Есть 2 способа скомпилировать драйвер как модуль ядра: in-tree и out-of-tree. Т.е. внутри дерева исходников ядра или снаружи. Вам сначала нужно решить, какой способ вы хотите использовать (уточнить у препода?). В зависимости от этого будут разные Makefile. Моё предположение -- вам нужно использовать out-of-tree способ, т.к. он проще.

  a) in-tree

    * Создаете в drivers/ (в исходниках ядра) свой каталог, например "masha".
      - Туда кладете свой .c файл драйвера; назовём его "masha.c".
        Для начала можете забить туда этот код (для проверки), потом добавите код драйвера клавиатуры:


#include <linux/init.h>
#include <linux/module.h>

static int masha_init(void)
{
    pr_alert("Hello there\n");
    return 0;
}

static void masha_exit(void)
{
}

MODULE_LICENSE("GPL");

module_init(masha_init);
module_exit(masha_exit);


      - Там же создаете Kconfig файл примерно следующего содержания:


menuconfig MASHA
    tristate "Masha keyboard support"
    default m
    help
      Masha keyboard support
      this long line is just to trick kernel git hook system
      this long line is just to trick kernel git hook system
      this long line is just to trick kernel git hook system
      this long line is just to trick kernel git hook system
      this long line is just to trick kernel git hook system
      this long line is just to trick kernel git hook system

config MASHA_KEYBOARD
    tristate "Masha keyboard"
    depends on MASHA != n
    default m
    help
      bla bla


      - И еще там же создаете Makefile такого содержания:


obj-$(CONFIG_MASHA_KEYBOARD) += masha.o


    * в drivers/Kconfig добавляете:


source "drivers/masha/Kconfig"


    * в drivers/Makefile добавляете:


obj-$(CONFIG_MASHA)        += masha/


    * Собираете свой модуль таким образом (выполняете эти команды из корня дерева исходников ядра)


$ make Image -j4
$ make M=drivers/masha


      - после этого увидите .ko файл в drivers/masha -- это и будет ваш собранный модуль.


  b) out-of-tree

     * Тут всё проще. создаете в произвольном месте (не в каталоге исходников ядра) свой каталог (например /home/masha/projects/masha-kernel-module/), и в нем будет всего 2 файла: masha.c и Makefile. Исходник будет такой же, как и в случае in-the-tree, но Makefile будет примерно следующего содержания:


ifeq ($(KERNELRELEASE),)
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build

module:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) C=1 modules

clean:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) C=1 clean

.PHONY: module clean

else
    obj-m := masha.o
endif


     где KERNELDIR -- путь к корню дерева исходников ядра; если у вас своё дерево -- эту переменную надо изменить соответствующим образом.

   * дальше выполняете из этого каталога:


$ make module


     и получаете .ko файл -- это и есть ваш модуль. Как работает этот Makefile не буду объяснять, это долго.


2. Когда у вас получиться собрать "Hello world" модуль (код его я привел выше, см. "masha.c") -- вам нужно будет попросту вставить вместо того кода свой код, который вам дал преподаватель. Насколько я вижу, вам останется только дописать туда соответствующие макросы module_init() и module_exit() для уже готовых там функций init_module() и cleanup_module(). Да, еще наверное сигнатуру этих функций придется изменить так, как это в моем примере показано.


> и работал правильно на новых версиях (3.2, например).

Когда сделаете всё что написано выше -- попробуйте собрать на новом ядре ваш старый код и посмотреть, какие ошибки/предупреждения покажет компилятор. Починив эти ошибки, скорее всего получите работающий код

> Даже не знаю,с чего начать

Я сторонник мнения, что любую сложную проблему можно решить, разбив её на небольшие, решаемые части. Это называется планирование.

1. Для старого ядра сделайте проект "Hello world" модуля (код я привел выше), наверное это будет out-of-tree проект. Добейтесь, чтобы он собирался и на выходе получался .ko файл.

2. Вместо кода "Hello world" модуля вставьте код, который вам дал преподаватель. Добавьте module_init() и module_exit() макросы, как это было сделано у меня в "Hello world" модуле, изменив сигнатуры соответствующих функций должным образом. Добейтесь чтобы собиралось всё.

3. Протестируйте работу вашего модуля (команда insmod загружает модуль, команда dmesg показывает вывод ядра). Для этого надо разобраться, как модуль работает и как увидеть результат его работ.

   Я не особо разбирался, но вроде как этот недо-драйвер просто вешается на шаренное прерывание клавиатуры и выводит в журнал ядра скан-код нажатой клавиши, и нажата она или отжата; кстати, убедитесь что в оригинальном драйвере клавиатуры это прерывание сделано шаренным, иначе ничего работать не будет. И да, я бы переделал workqueue на threaded_irq, так проще было бы.

   Убедитесь, что всё работает.

4. Теперь попробуйте собрать модуль с новым ядром. Разберитесь с ошибками/предупреждениями компилятора и почините их.

5. Когда сможете собрать модуль для нового ядра -- проверьте его работу на новом ядре.


Если совсем ничего не понятно, советую к прочтению:
[1] http://rus-linux.net/MyLDP/BOOKS/drivers/linux-device-driver...
[2] http://lwn.net/Kernel/LDD3/

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

2. "Помогите разобраться с драйвером!"  +/
Сообщение от Гагарина Машка email on 06-Дек-13, 21:14 
Спасибо за такой развернутый ответ, но вопрос, в общем-то, заключался именно в изменении драйвера-модуля и подстройки его под новую версию ядра)
я не знаю,как поменять код,чтобы он правильно работал.
а собирать их я умею)
Ответить | Правка | ^ к родителю #1 | Наверх | Cообщить модератору

3. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 06-Дек-13, 22:45 
> Спасибо за такой развернутый ответ, но вопрос, в общем-то, заключался именно в
> изменении драйвера-модуля и подстройки его под новую версию ядра)
> я не знаю,как поменять код,чтобы он правильно работал.
> а собирать их я умею)

Вам рабочий или компилируемый? Рабочий - сложнее, так как у 90% народа USB-клавы,
и подобная фича делается через evdev

Ответить | Правка | ^ к родителю #2 | Наверх | Cообщить модератору

23. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 08-Дек-13, 07:19 
Тут правоверный код!


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/slab.h> /* kzalloc */
#include <asm/io.h>

struct scanwork {
        struct work_struct tsk;
        int sccode;
        unsigned char status;
};

static struct scanwork *sw;
static struct workqueue_struct *my_workqueue;

static void got_char(struct work_struct *tp)
{
        struct scanwork *ssw = container_of(tp, struct scanwork, tsk);
        printk(KERN_INFO "Scan Code %x %s.\n",
               ssw->sccode & 0x7F, ssw->sccode & 0x80 ? "Released" : "Pressed");
}

static irqreturn_t irq_handler(int irq, void *dev_id)
{
        static int initialised = 0;
        struct scanwork *sw = dev_id;

        sw->status = inb(0x64);
        sw->sccode = inb(0x60);

        if (initialised == 0) {
                INIT_WORK(&sw->tsk, got_char);
                initialised = 1;
        } else {
                PREPARE_WORK(&sw->tsk, got_char);
        }
        queue_work(my_workqueue, &sw->tsk);
        return IRQ_HANDLED;
}

static int __init init_kbd(void)
{
        my_workqueue = create_workqueue("Wrkque");
        sw = kzalloc(sizeof(struct scanwork), GFP_KERNEL);
        return request_irq(1, irq_handler, IRQF_SHARED, "test", sw);
}

static void __exit cleanup_kbd(void)
{
        free_irq(1, sw);
        kfree(sw);
}
module_init(init_kbd);
module_exit(cleanup_kbd);
MODULE_LICENSE("GPL");


Ответить | Правка | ^ к родителю #3 | Наверх | Cообщить модератору

25. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 08-Дек-13, 16:59 
> Тут правоверный код!

1. Почему int sccode, если достаточно char?
2. Зачем читать и хранить статус, если он не используется?
3. Зачем создавать свой workqueue, если можно использовать глобальный workqueue (через функцию schedule_work() вместо queue_work())?
4. Можно использовать DECLARE_WORK() вместо INIT_WORK() и PREPARE_WORK()

Если  уже делать BH через wq, то можно сделать проще (код проверен):


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <asm/io.h>

static void kbd2_do_work(struct work_struct *work);

static char scancode;
static DECLARE_WORK(kbd2_work, kbd2_do_work);

static void kbd2_do_work(struct work_struct *work)
{
    pr_info("Scan Code %x %s\n",
        scancode & 0x7F, scancode & 0x80 ? "Released" : "Pressed");
}

static irqreturn_t kbd2_isr(int irq, void *dev_id)
{
    scancode = inb(0x60);
    schedule_work(&kbd2_work);
    return IRQ_HANDLED;
}

static int __init kbd2_init(void)
{
    return request_irq(1, kbd2_isr, IRQF_SHARED, "kbd2", &scancode);
}

static void __exit kbd2_cleanup(void)
{
    free_irq(1, &scancode);
}

module_init(kbd2_init);
module_exit(kbd2_cleanup);

MODULE_LICENSE("GPL");


Ну и всё же magic numbers -- зло, я за замену их на осмысленные дефайны. И вообще, если задача портировать код на новое ядро -- то правильно это было бы сделать именно с использованием  threaded IRQ, как я это показал ниже.

Ответить | Правка | ^ к родителю #23 | Наверх | Cообщить модератору

27. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 08-Дек-13, 17:55 
>> Тут правоверный код!
> 1. Почему
> 2. Зачем
> 3. Зачем

Патамуша см. начальный код.

Ответить | Правка | ^ к родителю #25 | Наверх | Cообщить модератору

30. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 08-Дек-13, 21:04 
>>> Тут правоверный код!
>> 1. Почему
>> 2. Зачем
>> 3. Зачем
> Патамуша см. начальный код.

Если ваша цель была портировать код с минимальными правками -- то не сходится: зачем тогда вы добавили kzalloc() и свою структуру?

С другой стороны, попытка придерживаться старого кода при портировании -- это вообще нонсенс. Попробуйте портировать например драйвер датчика какой-нибудь, используя работу с sysfs напрямую. Он даже будет работать. Только не примут его в mainline, потому что уже на IIO датчики пишут, это позволяет в 2 раза меньше кода клепать. Вот и тут тоже самое: не нужно пытаться оставить всё как есть -- это неправильный подход при портировании. Нужно разобраться, как код работает, а потом изменить его с учетом текущего положения дел в ядре. Некоторые флаги депрекейтятся, некоторые фреймворки заменяются другими и т.д. Всё это надо учитывать при портировании. В идеале после портирования код должен выглядеть так, как если бы вы его написали для текущей версии ядра.

Ответить | Правка | ^ к родителю #27 | Наверх | Cообщить модератору

28. "Помогите разобраться с драйвером!"  –1 +/
Сообщение от pavlinux (ok) on 08-Дек-13, 18:05 
> И вообще, если задача портировать код на новое ядро -- то правильно это было бы сделать именно с использованием  threaded IRQ, как я это показал ниже.

Правильно -  input_dev *,  input_register_device, serio_write, input_event, input_report_key, ...

А для кейлоггера - все варианты тут представленные очень оверхедные, нужон asm()

Ответить | Правка | ^ к родителю #25 | Наверх | Cообщить модератору

29. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 08-Дек-13, 20:54 
>> И вообще, если задача портировать код на новое ядро -- то правильно это было бы сделать именно с использованием  threaded IRQ, как я это показал ниже.
> Правильно -  input_dev *,  input_register_device, serio_write, input_event, input_report_key,
> ...
> А для кейлоггера - все варианты тут представленные очень оверхедные, нужон asm()

Насколько я понимаю, суть задачи -- научиться работать с прерыванием -- реквестить его и обрабатывать, а также делать BH. Клава тут просто в качестве источника прерывания используется. Драйвер клавы-то уже написан. Это ж просто учебная задачка на прерывания. Вот почему я говорю, что threaded IRQ тут подходит как нельзя лучше. Он во-первых позволяет сосредоточиться на главной теме задания (и избавиться от кучи оверхеда в виде выделений памяти, ворков и прочик container_of), а во-вторых это то, как в новых ядрах делается нижняя половина прерывания.

Ответить | Правка | ^ к родителю #28 | Наверх | Cообщить модератору

31. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 09-Дек-13, 03:33 
> Насколько я понимаю, суть задачи -- научиться работать с прерыванием

Неа. Суть, во том, что init_module() и cleanup_module() заменили на
module_init() и module_exit(). (может SA_SHIRQ на IRQF_SHARED).

Думаю на трояк если модуль скомпилиться, на 4 если будет глюкать, и на 5 если за работает. :)  

Ответить | Правка | ^ к родителю #29 | Наверх | Cообщить модератору

8. "Помогите разобраться с драйвером!"  +1 +/
Сообщение от skb7 (ok) on 07-Дек-13, 06:19 
> Спасибо за такой развернутый ответ, но вопрос, в общем-то, заключался именно в
> изменении драйвера-модуля и подстройки его под новую версию ядра)
> я не знаю,как поменять код,чтобы он правильно работал.
> а собирать их я умею)

Раз пошла такая пьянка -- режь последний огурец :) Код проверен и работает.


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");

#define KBD_IRQ            1    /* IRQ number for keyboard (i8042) */
#define KBD_DATA        0x60    /* I/O port for keyboard data */
#define KBD_SCAN_CODE_MASK    0x7f
#define KBD_STATUS_MASK        0x80

static char scancode;

static irqreturn_t kbd2_isr(int irq, void *data)
{
    char *sc = (char *)data;

    *sc = inb(KBD_DATA);

    return IRQ_WAKE_THREAD;
}

static irqreturn_t kbd2_thread(int irq, void *data)
{
    char sc = *(char *)data;

    pr_alert("### Scan Code %#x %s\n",
            sc & KBD_SCAN_CODE_MASK,
            sc & KBD_STATUS_MASK ? "Released" : "Pressed");

    return IRQ_HANDLED;
}

static int __init kbd2_init(void)
{
    return request_threaded_irq(KBD_IRQ, kbd2_isr, kbd2_thread,
            IRQF_SHARED, "masha", &scancode);
}

static void __exit kbd2_clean(void)
{
    free_irq(KBD_IRQ, &scancode);
}

module_init(kbd2_init);
module_exit(kbd2_clean);


Проверить модуль можно так:


$ sudo insmod masha.ko
$ sudo tail -f /var/log/syslog | grep "Scan Code"


После этого понабирайте что-нибудь на PS/2 клавиатуре, вы должны увидеть что-то типа:


7Dec  7 04:20:27 joe-pc kernel: [ 3730.257933] ### Scan Code 0x8 Pressed
Dec  7 04:20:27 joe-pc kernel: [ 3730.351589] ### Scan Code 0x8 Released
8Dec  7 04:20:27 joe-pc kernel: [ 3730.595211] ### Scan Code 0x9 Pressed
Dec  7 04:20:27 joe-pc kernel: [ 3730.677482] ### Scan Code 0x9 Released
9Dec  7 04:20:28 joe-pc kernel: [ 3731.042015] ### Scan Code 0xa Pressed
Dec  7 04:20:28 joe-pc kernel: [ 3731.132826] ### Scan Code 0xa Released
0Dec  7 04:20:29 joe-pc kernel: [ 3732.655725] ### Scan Code 0xb Pressed
Dec  7 04:20:29 joe-pc kernel: [ 3732.743720] ### Scan Code 0xb Released


Преимущества по сравнению с оригинальной версией:
1. Использован механизм threaded IRQ вместо создания нижней половины прерывания с помощью workqueue, что позволило сократить код.
2. Не убивается прерывание, запрошенное драйвером клавиатуры, т.к. в драйвере клавиатуры это прерывание обозначено как shared. Таким образом, функционирование клавиатуры не нарушается и компьютер не нужно перезагружать после подгрузки (insmod) этого модуля.

Что было сделано для портирования драйвера (на новую версию ядра): механизм workqueue заменен на новый механизм threaded IRQ. Можно почитать про него здесь: http://lwn.net/Articles/302043/

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


module_init(kbd2_init);
module_exit(kbd2_clean);

Ответить | Правка | ^ к родителю #2 | Наверх | Cообщить модератору

44. "Помогите разобраться с драйвером!"  +/
Сообщение от linina (ok) on 29-Июн-15, 08:55 
Надеюсь, Вы еще обитаете на этом форуме
скажите, по какой причине может быть такое, что ничего не выводится в syslog во время тестирования этого кода?
Ответить | Правка | ^ к родителю #8 | Наверх | Cообщить модератору

45. "Помогите разобраться с драйвером!"  +/
Сообщение от ubob (??) on 16-Июл-15, 17:41 
> скажите, по какой причине может быть такое, что ничего не выводится в
> syslog во время тестирования этого кода?

посмотрите в dmesg

Ответить | Правка | ^ к родителю #44 | Наверх | Cообщить модератору

4. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 06-Дек-13, 23:10 
Ну держы и Машка!

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");

static void got_char(struct work_struct *);
static irqreturn_t irq_handler(int, void *);
static void __exit cleanup_kbd(void);
static int __init init_kbd(void);

struct scanwork {
        struct work_struct tsk;
        int sccode;
        unsigned char status;
};

static struct workqueue_struct *my_workqueue;

static void got_char(struct work_struct *tp)
{
        struct scanwork *sw = container_of(tp, struct scanwork, tsk);

        printk(KERN_INFO "Scan Code %x %s.\n",
               sw->sccode & 0x7F, sw->sccode & 0x80 ? "Released" : "Pressed");
}

static irqreturn_t irq_handler(int irq, void *dev_id)
{
        static int initialised = 0;
        struct scanwork *sw = kzalloc(sizeof(struct scanwork), GFP_KERNEL);

        sw->status = inb(0x64); /* накуя это нужно? */
        sw->sccode = inb(0x60);

        if (initialised == 0) {
                INIT_WORK(&sw->tsk, got_char);
                initialised = 1;
        } else {
                PREPARE_WORK(&sw->tsk, got_char);
        }
        schedule_work(&sw->tsk);
        return IRQ_RETVAL(IRQ_HANDLED);
}

static int __init init_kbd(void)
{
        my_workqueue = create_workqueue("PAVLINUX WAS HERE");
        free_irq(1, NULL);
        return request_irq(1, irq_handler, IRQF_SHARED,
                           "test_keyboard_irq_handler", irq_handler);
}

static void __exit cleanup_kbd(void)
{
        free_irq(1, irq_handler);
}

module_init(init_kbd);
module_exit(cleanup_kbd);


Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

6. "Помогите разобраться с драйвером!"  +1 +/
Сообщение от skb7 (ok) on 07-Дек-13, 04:41 
У вас там 2 грубых ошибки в одной строке.

struct scanwork *sw = kzalloc(sizeof(struct scanwork), GFP_KERNEL);


1. Утечка памяти. Этот код будет несколько раз вызываться на каждое нажатие клавиши и память будет течь, у вас она там не высвобождается нигде.

2. В атомарном контексте происходит выделение памяти используя GFP_KERNEL. А ведь этим вы говорите, что kzalloc() может спать. А спать в атомарном контексте (в прерывании в данном случае) ну никак нельзя. Будет вот такая ошибка у вас постоянно возникать:


BUG: scheduling while atomic: swapper/1/0/0x10010000
[44877.249899] Call Trace:
[44877.249900]  <IRQ>  [<ffffffff8138068b>] ? __schedule_bug+0x42/0x4f
[44877.249907]  [<ffffffff813849de>] ? __schedule+0x85/0x532
[44877.249911]  [<ffffffff810606f5>] ? __cond_resched+0x1d/0x26
[44877.249914]  [<ffffffff81384ed4>] ? _cond_resched+0x10/0x18
[44877.249917]  [<ffffffff810f9ea3>] ? kmem_cache_alloc_trace+0x25/0xcc
[44877.249921]  [<ffffffffa1024040>] ? irq_handler+0x16/0x7b [masha]

Правильно было бы использовать GFP_ATOMIC. А еще правильнее -- не выделять память в каждом прерывании.

Ну и вообще, ваш модуль не работает -- никакого вывода с него нет.


      sw->status = inb(0x64); /* накуя это нужно? */


А и не нужно. Очевидно же, что взяли чей-то пример и покромсали. Остались сопли. Можно смело удалять эту строку, это вычитывание статусного регистра клавиатуры из 16-битного адресного пространства x86. Дальше в коде нигде не используется, т.е. не нужен.


Еще я считаю, что некрасиво делать free_irq(), чтобы прибить прерывание драйвера клавиатуры. Намного правильнее было бы сделать шаренным прерывание в драйвере клавиатуры, а затем пересобрать и загрузить новый драйвер клавиатуры.


Ну и последнее -- зачем такие мучения с workqueue в качестве bottom half? Почему не использовать threaded IRQ, которое есть в новых ядрах? Сразу код в 2 раза меньше становится.

Ответить | Правка | ^ к родителю #4 | Наверх | Cообщить модератору

7. "Помогите разобраться с драйвером!"  +1 +/
Сообщение от skb7 (ok) on 07-Дек-13, 05:00 
> Еще я считаю, что некрасиво делать free_irq(), чтобы прибить прерывание драйвера клавиатуры.
> Намного правильнее было бы сделать шаренным прерывание в драйвере клавиатуры, а
> затем пересобрать и загрузить новый драйвер клавиатуры.

Более того, если посмотреть в drivers/input/serio/i8042.c, можно увидеть, что это прерывание и так уже шаренное:


error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
            "i8042", i8042_platform_device);


Так что по идее можно не делать free_irq(), и всё будет работать.

Ответить | Правка | ^ к родителю #6 | Наверх | Cообщить модератору

9. "Помогите разобраться с драйвером!"  +1 +/
Сообщение от skb7 (ok) on 07-Дек-13, 06:21 
Выше написал рабочий код:
https://www.opennet.ru/openforum/vsluhforumID9/9792.html#8
Ответить | Правка | ^ к родителю #7 | Наверх | Cообщить модератору

12. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 07-Дек-13, 15:44 
> Так что по идее можно не делать free_irq(), и всё будет работать.

Угу, а если предыдущий был c IRQF_DISABLED

Ответить | Правка | ^ к родителю #7 | Наверх | Cообщить модератору

15. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 07-Дек-13, 16:07 
>> Так что по идее можно не делать free_irq(), и всё будет работать.
> Угу, а если предыдущий был c IRQF_DISABLED

Да нет же, я проверил, что он в драйвере клавиатуры SHARED. Более того, смотрим в /include/linux/interrupt.h:


IRQF_DISABLED - keep irqs disabled when calling the action handler.
                DEPRECATED. This flag is a NOOP and scheduled to be removed


В любом случае, когда вы пытаетесь сделать такое:


free_irq(1, NULL);


то (по крайней мере на новой версии ядра) получите:


[  779.065079] Trying to free already-free IRQ 1
[  779.065142] Call Trace:
[  779.065147]  [<ffffffff8103bb5f>] ? warn_slowpath_common+0x5b/0x70
[  779.065150]  [<ffffffff8103bc0a>] ? warn_slowpath_fmt+0x47/0x49
[  779.065153]  [<ffffffff81099ce0>] ? __free_irq+0x91/0x155
[  779.065155]  [<ffffffff81099e06>] ? free_irq+0x62/0x87
[  779.065167]  [<ffffffffa003800c>] ? kbd2_init+0xc/0x1000 [masha]
[  779.065189] ---[ end trace f688fc88f1374d89 ]---


то есть так делать нельзя.

Ответить | Правка | ^ к родителю #12 | Наверх | Cообщить модератору

18. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 07-Дек-13, 16:56 
>
     
>     DEPRECATED. This flag is a NOOP and scheduled to be removed
>

Опа,...

Ответить | Правка | ^ к родителю #15 | Наверх | Cообщить модератору

10. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 07-Дек-13, 15:32 
> Ну и вообще, ваш модуль не работает -- никакого вывода с него нет.

Конечно, что я идиот, тестировать модули с прерываниями на своём компе. Я его даже не загружал :)

стухтуру можно сделать глобальной, казаллок() всунуть в init, фри() в ехит(),
в нужном месте обнулять...  
Короча, причёсывать - домашнее задание. И так 95% сделали.  
  

Ответить | Правка | ^ к родителю #6 | Наверх | Cообщить модератору

16. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 07-Дек-13, 16:14 
>> Ну и вообще, ваш модуль не работает -- никакого вывода с него нет.
> Конечно, что я идиот, тестировать модули с прерываниями на своём компе. Я
> его даже не загружал :)
> стухтуру можно сделать глобальной, казаллок() всунуть в init, фри() в ехит(),
> в нужном месте обнулять...
> Короча, причёсывать - домашнее задание. И так 95% сделали.

Поздно. Я выше привет 100% рабочий модуль сделал и проверил на своём компе. Наверное не нужно было изначально давать готовое решение. Мне в инсте таких заданий не давали, пускай бы сама лучше разобралась, спрашивая по ходу дела, оно полезнее было бы. А так получилось что мы просто показали какие мы молодцы. Ну да, молодцы, "hello world" модуль написали.


Ответить | Правка | ^ к родителю #10 | Наверх | Cообщить модератору

19. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 07-Дек-13, 23:11 
> Поздно. Я выше привет 100% рабочий модуль сделал и

Ну это завал на зачете, однозначо.

Ответить | Правка | ^ к родителю #16 | Наверх | Cообщить модератору

20. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 08-Дек-13, 00:48 
>> Поздно. Я выше привет 100% рабочий модуль сделал и
> Ну это завал на зачете, однозначо.

Моих пояснений достаточно, чтобы хм... удовлетворить любого преподавателя? В любом случае, автомат еще никто не отменял :)

Ответить | Правка | ^ к родителю #19 | Наверх | Cообщить модератору

21. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 08-Дек-13, 01:22 
>>> Поздно. Я выше привет 100% рабочий модуль сделал и
>> Ну это завал на зачете, однозначо.
> Моих пояснений достаточно, чтобы хм... удовлетворить любого преподавателя? В любом случае,
> автомат еще никто не отменял :)

А почему идет обращение к не инициализированной переменной scancode?
А что такое нижняя половина? И почему нижняя, а не верхняя?
Какие достоинства и недостатки workqueue против threaded irq?
Для чего нужны __init и __exit, и чё это ваще такое...

Короче завалить можно, было бы желание.

Ответить | Правка | ^ к родителю #20 | Наверх | Cообщить модератору

22. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 08-Дек-13, 05:16 
> А почему идет обращение к не инициализированной переменной scancode?
> А что такое нижняя половина? И почему нижняя, а не верхняя?
> Какие достоинства и недостатки workqueue против threaded irq?
> Для чего нужны __init и __exit, и чё это ваще такое...

Я на эти вопросы конечно могу ответить сходу, но пусть она сама поищет, если интересно ;)


> Короче завалить можно, было бы желание.

Конечно можно. Вне зависимости от того, сама она делала это задание или нашла готовое.
Не хотели, чтобы у неё было готовое решение? Так зачем вы ей его дали? Я лишь написал свой вариант решения, когда готовое уже было. Изначально я и хотел, чтобы она сама делала. Короче разговор ни о чём.

Ответить | Правка | ^ к родителю #21 | Наверх | Cообщить модератору

24. "Помогите разобраться с драйвером!"  –1 +/
Сообщение от pavlinux (ok) on 08-Дек-13, 07:22 
> ... ни о чём.

https://www.opennet.ru/openforum/vsluhforumID9/9792.html#23


                        _                         _
                       |_|                       |_|
                       | |         /^^^\         | |
                      _| |_      (| "o" |)      _| |_
                    _| | | | _    (_---_)    _ | | | |_
                   | | | | |' |    _| |_    | `| | | | |
                   |          |   /     \   |          |
                    \        /  / /(. .)\ \  \        /
                      \    /  / /  | . |  \ \  \    /
                        \  \/ /    ||Y||    \ \/  /
                         \__/      || ||      \__/
                                   () ()
                                   || ||
                                  ooO Ooo          

Ответить | Правка | ^ к родителю #22 | Наверх | Cообщить модератору

26. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 08-Дек-13, 17:03 
> https://www.opennet.ru/openforum/vsluhforumID9/9792.html#23

Рано еще такие картинки постить. Код у вас там over-engineered до жути. Читайте мой ответ.

Ответить | Правка | ^ к родителю #24 | Наверх | Cообщить модератору

11. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 07-Дек-13, 15:34 
> Ну и последнее -- зачем такие

Задача была - минимум изменений, для работы на ядре 3.2  
Я всунул структуру в контейнер и заменил SA_SHIRQ на IRQF_SHARED.
Кстати, queue_work(my_workqueue, &task); можно оставить.

Ответить | Правка | ^ к родителю #6 | Наверх | Cообщить модератору

14. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 07-Дек-13, 15:56 
>> Ну и последнее -- зачем такие
> Задача была - минимум изменений, для работы на ядре 3.2
> Я всунул структуру в контейнер и заменил SA_SHIRQ на IRQF_SHARED.
> Кстати, queue_work(my_workqueue, &task); можно оставить.

Да нет, про минимум там ничего не сказано:

> Задание состоит в том, чтобы изменить код, написанный под старое второе ядро, так, чтобы
> драйвер компилировался, как модуль ядра, и работал правильно на новых версиях (3.2,
> например).

Как по мне, логично было бы переделать на threaded IRQ, он для этого и придуман.

Ответить | Правка | ^ к родителю #11 | Наверх | Cообщить модератору

13. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 07-Дек-13, 15:56 
>
 
>       sw->status = inb(0x64); /* накуя это
> нужно? */
>

> А и не нужно. Очевидно же, что взяли чей-то пример и покромсали.
> Остались сопли. Можно смело удалять эту строку, это вычитывание статусного регистра
> клавиатуры из 16-битного адресного пространства x86. Дальше в коде нигде не
> используется, т.е. не нужен.

По феншую этот статус нужно считать, проверить, а дальше по результатам, что-то типа:


    sw->status = inb(0x64);
    ...
    if (sw->status != 0x14)
        goto err_exit;

Во!


The keyboard controller status register

The keyboard controller has an 8-bit status register. It can be inspected by the CPU
by reading port 0x64.

(Typically, it has the value 0x14: keyboard not locked, self-test completed.)

Bit 7: Parity error
    0: OK. 1: Parity error with last byte.

Bit 6: Timeout

    0: OK. 1: Timeout. On PS/2 systems: General timeout. On AT systems: Timeout on transmission
    from keyboard to keyboard controller. Possibly parity error (in which case both bits 6 and 7 are set).

Bit 5: Auxiliary output buffer full

    On PS/2 systems: Bit 0 tells whether a read from port 0x60 will be valid. If it is valid, this bit 5 tells
    what data will be read from port 0x60.
         0: Keyboard data.
         1: Mouse data.
    On AT systems:
         0: OK.
         1: Timeout on transmission from keyboard controller to keyboard. This may indicate
            that no keyboard is present.

Bit 4: Keyboard lock

    0: Locked. 1: Not locked.

Bit 3: Command/Data

     0: Last write to input buffer was data (written via port 0x60).
     1: Last write to input buffer was a command (written via port 0x64).
        (This bit is also referred to as Address Line A2.)

Bit 2: System flag

     Set to 0 after power on reset.
     Set to 1 after successful completion of the keyboard controller self-test
     (Basic Assurance Test, BAT). Can also be set by command (see below).

Bit 1: Input buffer status

     0: Input buffer empty, can be written.
     1: Input buffer full, don't write yet.

Bit 0: Output buffer status

    0: Output buffer empty, don't read yet.
    1: Output buffer full, can be read. (In the PS/2 situation bit 5 tells whether the available data is from keyboard or mouse.)
       This bit is cleared when port 0x60 is read.


Ответить | Правка | ^ к родителю #6 | Наверх | Cообщить модератору

17. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 07-Дек-13, 16:29 
>The keyboard controller has an 8-bit status register. It can be inspected by the CPU
> by reading port 0x64.
> (Typically, it has the value 0x14: keyboard not locked, self-test completed.)

Да, всё верно. Эти биты кстати уже объявлены в drivers/input/serio/i8042.h:


/*
* Status register bits.
*/
#define I8042_STR_PARITY    0x80
#define I8042_STR_TIMEOUT    0x40
#define I8042_STR_AUXDATA    0x20
#define I8042_STR_KEYLOCK    0x10
#define I8042_STR_CMDDAT    0x08
#define I8042_STR_MUXERR    0x04
#define I8042_STR_IBF        0x02
#define    I8042_STR_OBF        0x01


Регистры объявлены в drivers/input/serio/i8042-io.h:


/*
* Register numbers.
*/
#define I8042_COMMAND_REG    0x64
#define I8042_STATUS_REG    0x64
#define I8042_DATA_REG        0x60


И дальше в drivers/input/serio/i8042.c статус проверяется в прерывании:


static irqreturn_t i8042_interrupt(int irq, void *dev_id)
{
    ...
    str = i8042_read_status();
    ...
        if (str & I8042_STR_MUXERR) {
            dbg("MUX error, status is x, data is x\n",
                str, data);


А на KEYLOCK статус проверяется один раз в ините:


static int i8042_controller_init(void)
{
    ...

/*
* Handle keylock.
*/

    spin_lock_irqsave(&i8042_lock, flags);
    if (~i8042_read_status() & I8042_STR_KEYLOCK) {
        if (i8042_unlock)
            i8042_ctr |= I8042_CTR_IGNKEYLOCK;
        else
            pr_warn("Warning: Keylock active\n");
    }
    spin_unlock_irqrestore(&i8042_lock, flags);

}


Ответить | Правка | ^ к родителю #13 | Наверх | Cообщить модератору

5. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 07-Дек-13, 00:34 
> /*
>  *  Copyright (C) 2001 by Peter Jay Salzman
>  */

Ой как не хорошо этот дядька сделал..., скопипастил и копирайты потёр.

/* Copyright (C) 1998 by Ori Pomerantz */
http://www.electro.fisica.unlp.edu.ar/temas/lkmpg/node25.html

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

32. "Помогите разобраться с драйвером!"  +/
Сообщение от BatFox email(ok) on 23-Дек-13, 10:44 
Прочла всё, что вы тут написали.
Решила проблему по-своему – просто изменила обработчик так, чтобы при вызове он напрямую обращался к функции вывода символа в системный журнал.
Вод код
#include <linux/kernel.h>    /* We're doing kernel work */
#include <linux/module.h>    /* Specifically, a module */
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>    /* We want an interrupt */
#include <asm/io.h>

#define MY_WORK_QUEUE_NAME "WQsched.c"
#define SA_SHIRQ IRQF_SHARED

//static struct workqueue_struct *my_workqueue;

static void got_char(void *scancode)
{
    printk(KERN_INFO "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 work_struct task;
    unsigned char status;

    status = inb(0x64);
    scancode = inb(0x60);

    /*if (initialised == 0) {
        INIT_WORK(&task, got_char, &scancode);
        initialised = 1;
    } else {
        PREPARE_WORK(&task, got_char, &scancode);
    }
    queue_work(my_workqueue, &task);*/
    
    got_char(&scancode);
    return IRQ_HANDLED;
}

int init_module()
{
    //my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME);


    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");


Он проверен и работает. Лабу я сдала)

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

33. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 25-Дек-13, 02:00 
> Он проверен и работает.

Каким боком? Если функция обработчика должна иметь два аргумента: (int, void *);
У тебя тут ещё структура pt_regs, которую уже в ядре 2.6.20 не стали использовать.

irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)

int init_module()
void cleanup_module()

Эти две тоже в 2.6.20 заменили, точнее расширили аттрибутами __init и __exit
... а задача была
>> и работал правильно на новых версиях (3.2, например).

.
> Лабу я сдала)

Скажем так, препод на тебя забил (как вариант - добрый и понимающий). :)

Ответить | Правка | ^ к родителю #32 | Наверх | Cообщить модератору

35. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 25-Дек-13, 05:14 
> Скажем так, препод на тебя забил (как вариант - добрый и понимающий).

Ну, вспоминая ваши слова:

> Думаю на трояк если модуль скомпилиться, на 4 если будет глюкать, и на 5 если за работает. :)

то таки 5 :) ибо на новом ядре компилится и работает. я бы сказал 4 -- потому что схитрила и выкинула WQ (хотя тут надо смотреть, какое было задание), плюс портирование кривое. Но таки догадалась, как можно сделать, и таки работает.

Ответить | Правка | ^ к родителю #33 | Наверх | Cообщить модератору

38. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 25-Дек-13, 14:20 
>> Скажем так, препод на тебя забил (как вариант - добрый и понимающий).
> Ну, вспоминая ваши слова:
>> Думаю на трояк если модуль скомпилиться, на 4 если будет глюкать, и на 5 если за работает. :)
> то таки 5 :) ибо на новом ядре компилится и работает. я
> бы сказал 4 -- потому что схитрила и выкинула WQ (хотя
> тут надо смотреть, какое было задание), плюс портирование кривое. Но таки
> догадалась, как можно сделать, и таки работает.

rmmod kod


------------[ cut here ]------------
WARNING: CPU: 0 PID: 2659 at kernel/irq/manage.c:1342 __free_irq+0x84/0x1b0()
Trying to free already-free IRQ 1
Modules linked in: kod(O-) usbhid ehci_pci uhci_hcd ehci_hcd usbcore usb_common intel_agp vmxnet3 intel_gtt
CPU: 0 PID: 2659 Comm: rmmod Tainted: G        W  O 3.12.3-rt4 #1
Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/31/2013
00000009 c14332ca f0ca1f0c c1038255 c150244c f0ca1f24 00000a63 c14ffff8
0000053e c106ed74 c106ed74 00000000 f60060c0 00000001 00000000 c1038313
00000009 f0ca1f0c c150244c f0ca1f24 c106ed74 c14ffff8 0000053e c150244c
Call Trace:
[<c14332ca>] ? dump_stack+0x48/0x78
[<c1038255>] ? warn_slowpath_common+0x85/0xb0
[<c106ed74>] ? __free_irq+0x84/0x1b0
[<c106ed74>] ? __free_irq+0x84/0x1b0
[<c1038313>] ? warn_slowpath_fmt+0x33/0x40
[<c106ed74>] ? __free_irq+0x84/0x1b0
[<c106eedd>] ? free_irq+0x3d/0xa0
[<c1083394>] ? SyS_delete_module+0x134/0x240
[<c10c9ab3>] ? __fput+0x123/0x1d0
[<c1058708>] ? lg_local_lock+0x8/0x20
[<c104e8c6>] ? task_work_run+0x76/0xa0
[<c14375c4>] ? sysenter_do_call+0x12/0x2c
---[ end trace 0000000000000003 ]---
BUG: unable to handle kernel paging request at f9498000
IP: [<f9498000>] 0xf9497fff
*pde = 34b73067 *pte = 00000000

task: f3ebc9a0 ti: f3f86000 task.ti: f3f86000
EIP: 0060:[<f9498000>] EFLAGS: 00010246 CPU: 0
EIP is at 0xf9498000
EAX: 00000001 EBX: f3f18a00 ECX: f3ebc9a0 EDX: f9498000
ESI: f60060c0 EDI: f60060c0 EBP: f3ebc9a0 ESP: f3f87f34
DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
CR0: 8005003b CR2: f9498000 CR3: 33f13000 CR4: 000007d0
Stack:
c106f1b0 f3f18a00 f3ebc9a0 f60060c0 c106f477 32f37042 00000000 c106f190
00000000 00000000 00000000 c106f0a0 f0ca1d98 f3f18a00 c106f390 f3f86000
c1051568 00000000 f3ebf1c4 f3f18a00 00000000 c1000000 f3f87f8c f3f87f8c
Call Trace:
[<c106f1b0>] ? irq_forced_thread_fn+0x20/0x50
[<c106f477>] ? irq_thread+0xe7/0x130
[<c106f190>] ? irq_thread_fn+0x40/0x40
[<c106f0a0>] ? irq_finalize_oneshot+0xc0/0xc0
[<c106f390>] ? irq_thread_check_affinity+0x70/0x70
[<c1051568>] ? kthread+0x88/0x90
[<c1437537>] ? ret_from_kernel_thread+0x1b/0x28
[<c10514e0>] ? kthread_create_on_node+0xd0/0xd0
Code:  Bad EIP value.
EIP: [<f9498000>] 0xf9498000 SS:ESP 0068:f3f87f34
CR2: 00000000f9498000
---[ end trace 0000000000000004 ]---
BUG: unable to handle kernel paging request at ffffffec
IP: [<c1051696>] kthread_data+0x6/0x10
*pde = 01629067 *pte = 00000000
Oops: 0000 [#2] PREEMPT SMP
Modules linked in: usbhid ehci_pci uhci_hcd ehci_hcd usbcore usb_common intel_agp vmxnet3 intel_gtt [last unloaded: kod]
CPU: 0 PID: 2657 Comm: irq/1-test_keyb Tainted: G      D W  O 3.12.3-rt4 #1
Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/31/2013
task: f3ebc9a0 ti: f3f86000 task.ti: f3f86000
EIP: 0060:[<c1051696>] EFLAGS: 00010002 CPU: 0
EIP is at kthread_data+0x6/0x10
EAX: 00000000 EBX: c1633d68 ECX: 00000000 EDX: f3f87f5c
ESI: f3ebc9a0 EDI: f3ebc9a0 EBP: 00000000 ESP: f3f87d88
DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
CR0: 8005003b CR2: ffffffec CR3: 33f13000 CR4: 000007d0
Stack:
c106f0b9 f3ebc9a0 c1035ff9 c1592c60 00000036 c1633d68 f3ebcd3c c104e8c1
00000000 00000009 f3ebc9a0 f9498000 c1039dc6 00000046 00000000 c1654ea2
00000046 00000009 00000000 f9498000 c1430108 00000000 00000001 00000000
Call Trace:
[<c106f0b9>] ? irq_thread_dtor+0x19/0xb0
[<c1035ff9>] ? mm_release+0x89/0x120
[<c104e8c1>] ? task_work_run+0x71/0xa0
[<c1039dc6>] ? do_exit+0x676/0x8c0
[<c1430108>] ? printk+0x37/0x3b
[<c10381c3>] ? print_oops_end_marker+0x33/0x40
[<c1005172>] ? oops_end+0x72/0xf0
[<c142f770>] ? no_context+0x16e/0x176
[<c142f893>] ? __bad_area_nosemaphore+0x11b/0x123
[<c1073868>] ? ktime_get+0x58/0xf0
[<c1030bc0>] ? vmalloc_sync_all+0x170/0x170
[<c142f8aa>] ? bad_area_nosemaphore+0xf/0x11
[<c10306d6>] ? __do_page_fault+0xc6/0x440
[<c1067c37>] ? dequeue_rt_stack+0x77/0x1c0
[<c1059b52>] ? finish_task_switch+0x42/0xb0
[<c143511b>] ? __schedule+0x1fb/0x4f0
[<c1030bc0>] ? vmalloc_sync_all+0x170/0x170
[<c143734a>] ? error_code+0x5a/0x60
[<c1030bc0>] ? vmalloc_sync_all+0x170/0x170
[<c106f1b0>] ? irq_forced_thread_fn+0x20/0x50
[<c106f477>] ? irq_thread+0xe7/0x130
[<c106f190>] ? irq_thread_fn+0x40/0x40
[<c106f0a0>] ? irq_finalize_oneshot+0xc0/0xc0
[<c106f390>] ? irq_thread_check_affinity+0x70/0x70
[<c1051568>] ? kthread+0x88/0x90
[<c1437537>] ? ret_from_kernel_thread+0x1b/0x28
[<c10514e0>] ? kthread_create_on_node+0xd0/0xd0
Code: eb a6 8d 76 00 64 a1 90 96 61 c1 8b 80 ac 01 00 00 8b 40 e4 c1 e8 02 83 e0 01 c3 8d 76 00 8d bc 27 00 00 00 00 8b 80 ac 01 00 00 <8b> 40 ec c3 8d b6 00 00 00 00 83 ec 04 8b 90 ac 01 00 00 b9 04
EIP: [<c1051696>] kthread_data+0x6/0x10 SS:ESP 0068:f3f87d88
CR2: 00000000ffffffec
---[ end trace 0000000000000005 ]---
Fixing recursive fault but reboot is needed!


Ответить | Правка | ^ к родителю #35 | Наверх | Cообщить модератору

42. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 25-Дек-13, 17:10 
> rmmod kod
>
 
> Trying to free already-free IRQ 1
> Fixing recursive fault but reboot is needed!
>

Да, я об этом тоже писал. Ну тогда сойдёмся на четверке :)

Ответить | Правка | ^ к родителю #38 | Наверх | Cообщить модератору

34. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 25-Дек-13, 05:06 
> Он проверен и работает

Невероятно, но факт. Специально проверил на своем ядре 3.11, до последнего не верил что заработает. Как минимум, за самостоятельное решение оценку вы заработали. Но покритиковать код надо.


> Решила проблему по-своему – просто изменила обработчик так, чтобы при вызове он напрямую
> обращался к функции вывода символа в системный журнал.

Оценку "отл." за такое надо вам поставить. "Обманула Товарища Лектора" то есть :)

Вы делаете всю работу в хардварном прерывании, избавившись от bottom half. Чтобы не портировать код workqueue. Но:
1. Ведь BH там был не просто так: обработчик прерывания должен завершаться как можно быстрее, а printk, как и любая операция ввода/вывода, занимает весьма немало времени. Так что, как говорится, за изобретение ставлю пять, а за экзамен...
2. Более того, в этом же была суть задания -- спортировать весь код, а вы просто половину кода выкинули.


>  free_irq(1, NULL);

Будет матюкаться в журнал ядра (dmesg), что невозможно освободить незанятое прерывание. Я уже выше описывал, почему этого делать нельзя. Просто проверьте свой dmesg после insmod.


> #define SA_SHIRQ IRQF_SHARED

Интересный способ портирования устаревших флагов...


> int init_module()
> void cleanup_module()

Забыли указать аргументы void в них, это важно. Ну и надо заметить, в новых ядрах принято использовать макросы module_init() и module_exit() для этого.


> irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)

Посмотрите, какая сигнатура для ISR функций в новом ядре (88-я строка):
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux....


В общем, с вашим подходом правильно было бы "спортировать" так:


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>

static irqreturn_t kbd2_isr(int irq, void *dev_id)
{
    char scancode;

    scancode = inb(0x60);
    pr_info("Scan Code %x %s\n",
        scancode & 0x7F, scancode & 0x80 ? "Released" : "Pressed");

    return IRQ_HANDLED;
}

static int __init kbd2_init(void)
{
    return request_irq(1, kbd2_isr, IRQF_SHARED, "kbd2", NULL);
}

static void __exit kbd2_cleanup(void)
{
    free_irq(1, NULL);
}

module_init(kbd2_init);
module_exit(kbd2_cleanup);

MODULE_LICENSE("GPL");


Ответить | Правка | ^ к родителю #32 | Наверх | Cообщить модератору

36. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 25-Дек-13, 05:30 
По поводу ваших ошибок: просто читайте вывод сборки и исправляйте ворнинги. Вот например для вашего кода вывод сборки, с проверкой sparse (C=1) и cppcheck:


$ make

make -C ... M=... C=1 modules
make[1]: Entering directory `/usr/src/linux-headers-3.11-2-amd64'

  CHECK   masha.c
masha.c:43:17: warning: non-ANSI function declaration of function 'init_module'
masha.c:55:21: warning: non-ANSI function declaration of function 'cleanup_module'
masha.c:20:13: warning: symbol 'irq_handler' was not declared. Should it be static?
masha.c:50:16: warning: incorrect type in argument 2 (different argument counts)
masha.c:50:16:    expected int enum irqreturn ( *[usertype] handler )( ... )
masha.c:50:16:    got int enum irqreturn ( extern [toplevel] *<noident> )( ... )

  CC [M]  masha.o
masha.c: In function ‘init_module’:
masha.c:52:16: warning: passing argument 2 of ‘request_irq’ from incompatible pointer type [enabled by default]
                (void *)(irq_handler));
                ^
In file included from masha.c:5:0:
include/linux/interrupt.h:130:1: note:
   expected ‘irq_handler_t’
   but argument is of type ‘enum irqreturn_t (*)(int,  void *, struct pt_regs *)’

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
^


$ cppcheck --enable=all masha.c

Checking masha.c...
[masha.c:28]: (style) Variable 'status' is assigned a value that is never used.


Ответить | Правка | ^ к родителю #34 | Наверх | Cообщить модератору

39. "Помогите разобраться с драйвером!"  +1 +/
Сообщение от pavlinux (ok) on 25-Дек-13, 14:46 
Всё равно при rmmod глюкать будет, нужно  функциям request_irq и free_irq вместо NULL
передавать указатель на обработчик..

return request_irq(1, kbd2_isr, IRQF_SHARED, "kbd2", (void *)kbd2_isr);
free_irq(1, (void *)kbd2_isr);

Ответить | Правка | ^ к родителю #36 | Наверх | Cообщить модератору

40. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 25-Дек-13, 17:04 
> Всё равно при rmmod глюкать будет, нужно  функциям request_irq и free_irq
> вместо NULL
> передавать указатель на обработчик..
> return request_irq(1, kbd2_isr, IRQF_SHARED, "kbd2", (void *)kbd2_isr);
> free_irq(1, (void *)kbd2_isr);

да, всё верно, не досмотрел

Ответить | Правка | ^ к родителю #39 | Наверх | Cообщить модератору

37. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok) on 25-Дек-13, 13:39 
>> #define SA_SHIRQ IRQF_SHARED
> Интересный способ портирования устаревших флагов...

http://lxr.free-electrons.com/source/drivers/staging/rt2860/...

Ответить | Правка | ^ к родителю #34 | Наверх | Cообщить модератору

41. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok) on 25-Дек-13, 17:07 
>>> #define SA_SHIRQ IRQF_SHARED
>> Интересный способ портирования устаревших флагов...
> http://lxr.free-electrons.com/source/drivers/staging/rt2860/...

http://lxr.free-electrons.com/ident?v=3.0;i=SA_SHIRQ

ну и? если кто-то так сделал (в 2.6.32 при чем, в 3.0 уже такого безобразия нет), это не значит, что так делать правильно

Ответить | Правка | ^ к родителю #37 | Наверх | Cообщить модератору

43. "Помогите разобраться с драйвером!"  +1 +/
Сообщение от pavlinux (ok) on 25-Дек-13, 19:48 
>>>> #define SA_SHIRQ IRQF_SHARED
>>> Интересный способ портирования устаревших флагов...
>> http://lxr.free-electrons.com/source/drivers/staging/rt2860/...
> http://lxr.free-electrons.com/ident?v=3.0;i=SA_SHIRQ
> ну и? если кто-то так сделал (в 2.6.32 при чем, в 3.0
> уже такого безобразия нет), это не значит, что так делать правильно

#define - это как косметика, может украсить, а может хелловин получиться. :)


Ответить | Правка | ^ к родителю #41 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2021 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру