Адаптация от старого init_timer к новому timer_setup - PullRequest
0 голосов
/ 18 декабря 2018

Я пытался портировать драйвер с версии 2.6 до 4.n без поддержки оригинального производителя платы (и очень ограниченный опыт работы с Linux).

Исходный драйвер использует init_timer () и передает указатель на структуру timer_list.Элемент 'data' этой структуры limer_list был установлен в качестве указателя на другую структуру памяти, а элемент 'function' - в обратный вызов.Внутри функции обратного вызова элемент 'data' использовался для доступа к другим частям.

Текущий метод инициализации таймера использует timer_setup (timer_list *, callback, (unsigned int) flags);и структура timer_list была изменена, чтобы исключить поле 'data'.

Я не уверен, каков наилучший / правильный способ сообщить функции обратного вызова эквивалентный элемент данных.Кто-нибудь может дать какое-нибудь руководство?

Вот фрагмент старого драйвера ...

myDevice * dev;

dev->getIntrTimer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);    
init_timer(dev->getIntrTimer);

dev->getIntrTimer->data = (unsigned long) dev;
dev->getIntrTimer->function = GetIntrTimerCallback;

Функция обратного вызова запускается так:

void GetIntrTimerCallback(unsigned long devAddr)
{
    myDevice *dev = (myDevice *) devAddr;
    dev->blahBlah++; // etc.

Итакстарый код получает указатель на myDevice, поэтому внутри функции обратного вызова можно получить доступ к этой структуре.

Но с помощью нового метода таймера доступно только int, равное 4 байта, а указатель 8 (или любой другой).

Я хотел бы сделать следующее:

dev->getIntrTimer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
timer_setup(dev->getIntrTimer, GetIntrTimerCallback, dev);

, но, конечно, это приводит к ошибкам компиляции, поскольку dev является указателем на тип myDevice, который не помещается в int.

Мне не хватает чего-то глупого, не так ли?

1 Ответ

0 голосов
/ 19 декабря 2018

timer_setup() с тремя аргументами присутствует начиная с 4.14 ядра Linux (к вашему сведению было setup_timer() в немного более ранних версиях).Если вы поддерживаете некоторый код, который должен быть актуален до последних ядер - вы должны соответствующим образом изменять его каждый раз, когда изменяется API.Теперь вы можете получить доступ к вашим данным через специальную функцию from_timer(), основанную на container_of().

timer_list, которая обычно используется не как указатель внутри структуры, поэтому пример подразумевает нормальное использование иможет быть что-то вроде:

#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
    init_timer(&dev->getIntrTimer);
    dev->getIntrTimer.data = (unsigned long) dev;
    dev->getIntrTimer.function = GetIntrTimerCallback;
    /* ... */
    add_timer(&dev->getIntrTimer);
#else
    timer_setup(&dev->getIntrTimer, GetIntrTimerCallback, 0);
    /* the third argument may include TIMER_* flags */
    /* ... */
#endif

Функция обратного вызова:

#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
void GetIntrTimerCallback(unsigned long devAddr)
{
    myDevice *dev = (myDevice *) devAddr;
#else
void GetIntrTimerCallback(struct timer_list *t)
{
    myDevice *dev = from_timer(dev, t, getIntrTimer);
#endif
    /* Do something with "dev" */

Читайте также:

...