【问题标题】:Adaptation from old init_timer to new timer_setup从旧的 init_timer 适应新的 timer_setup
【发布时间】:2018-12-18 19:12:27
【问题描述】:

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

原始驱动程序使用init_timer() 并传入一个指向timer_list 结构的指针。 timer_list 结构的 data 元素被设置为指向另一个内存结构的指针,function 元素被设置为回调。在回调函数内部,data 元素用于访问其他内容。

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

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

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

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

这是老司机的sn-p:

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。

【问题讨论】:

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


    【解决方案1】:

    带有三个参数的timer_setup() 自 4.14 Linux 内核开始存在(仅供参考,在稍早的版本中存在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" */
    

    另请阅读:

    【讨论】:

    • 哎呀!而 timer_setup 应该是一种改进!?!
    • 不管怎样,我做了更改(显然 page_cache_release() 和 get_user_pages() 也得到了类似的改进)。但是我在使用 from_timer() 调用的回调函数中得到编译错误。错误是“container_of() 中的指针类型不匹配”。我应该提出任何/所有这些论点吗?错误消息没有提供很多关于哪个参数被标记的线索(据我所知)。
    • @ElRonaldo 如果 timer_list 在您的结构中声明为指针,则有关 container_of() 的错误消息是非常合理的。如上所述,示例不适用于大小写 typedef struct { struct timer_list *getIntrTimer; /*smth else*/ } myDevice;,但适用于大小写 typedef struct { struct timer_list getIntrTimer; /*smth else*/ } myDevice;跨度>
    • 哦,你的意思是我应该阅读你的整个回复!?!!??我的注意力太短了,伙计!
    • from_timer 要求 struct timer_list 是myDevice 结构中的第一个元素吗?就我而言,它不仅是一个指针,也不是第一个元素,坦率地说,我不遵循 container_of() 扩展。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-24
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多