The OpenNET Project / Index page

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



Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (C/C++)
Режим отображения только ответов первого уровня [ Отслеживать ]

Оглавление

Помогите разобраться с драйвером!, Гагарина Машка (?), 06-Дек-13, (0) [смотреть все]

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


1. "Помогите разобраться с драйвером!"  +/
Сообщение от skb7 (ok), 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/

Ответить | Правка | Наверх | Cообщить модератору
есть ответы, показать

4. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok), 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);


Ответить | Правка | Наверх | Cообщить модератору
есть ответы, показать

5. "Помогите разобраться с драйвером!"  +/
Сообщение от pavlinux (ok), 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

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

32. "Помогите разобраться с драйвером!"  +/
Сообщение от BatFoxemail (ok), 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");


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

Ответить | Правка | Наверх | Cообщить модератору
есть ответы, показать

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

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




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

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