从旧 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" */
另请阅读:
- Linux kernel timers new API
- Example
- Linux kernel versions
我一直在尝试将 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" */
另请阅读:
- Linux kernel timers new API
- Example
- Linux kernel versions