从旧 init_timer 改编到新 timer_setup

Adaptation from old init_timer to new timer_setup

我一直在尝试将 driver 从 2.6 移植到 4.X 而没有原始主板制造商的支持(并且 Linux 经验非常有限)。

原来的driver使用init_timer(),传入一个指向timer_list结构体的指针。 timer_list 结构的 data 元素设置为指向另一个内存结构的指针,function 元素设置为回调。在回调函数中,data 元素用于访问其他内容。

当前计时器init-方法使用:

timer_setup( timer_list *, callback, (unsigned int) flags);

并且 timer_list 结构已更改以消除 data 字段。

我不确定通知等效 data 元素的回调函数的 best/proper 方法是什么。谁能提供一些指导?

这是旧 driver 的片段:

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,因此在回调中可以访问该结构。

但是对于新的计时器方法,只有一个 4 字节的 int 可用,但指针是 8(或其他)。

我想做的是:

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

但当然会产生编译错误,因为 dev 是指向类型 myDevice 的指针,它不适合 int.

自 4.14 Linux 内核以来就存在具有三个参数的 timer_setup()(仅供参考,在较早的版本中有 setup_timer())。如果您维护一些应该与最近的内核相关的代码——您必须在每次 API 更改时以适当的方式更改它。现在您可以通过基于 container_of().

的特殊函数 from_timer() 访问您的数据

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" */

另请阅读: