从旧的init_timer适应新的timer_setup

时间:2018-12-18 19:12:27

标签: c linux linux-kernel linux-device-driver

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

原始驱动程序使用init_timer()并传入指向timer_list结构的指针。该limer_list结构的“数据”元素设置为指向另一个内存结构的指针,而“功能”元素设置为回调。在回调函数中,“数据”元素用于访问其他内容。

当前的计时器初始化方法使用timer_setup(timer_list *,callback,(unsigned int)标志);并且更改了timer_list结构以消除“数据”字段。

我不确定将等效的“数据”元素告知回调函数的最佳/正确方法是什么。谁能提供一些指导?

这是旧驱动程序的摘要...

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,以便在回调内部可以访问该结构。

但是使用新的timer方法时,只能使用一个4字节的int,但一个指针是8(或任何其他值)。

我想做的是这样

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

但是当然会生成编译错误,因为dev是类型为myDevice的指针,该指针不适合int。

我想念一些愚蠢的东西,不是吗?

1 个答案:

答案 0 :(得分:5)

从4.14 Linux内核开始存在带有三个参数的timer_setup()(仅供参考,在稍早的版本中就有setup_timer())。如果您维护一些与最新内核相关的代码,则每次API更改时都必须以适当的方式进行更改。现在,您可以通过基于container_of()的特殊功能from_timer()访问数据。

timer_list通常不用作struct内部的指针,因此该示例暗含正常用法,可能类似于:

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

另请参阅: