Adaptation from old init_timer to new timer_setup

只愿长相守 提交于 2019-12-11 03:05:21

问题


I have been trying to port a driver from 2.6 to 4.n without support from the original board manufacturer (and very limited Linux experience).

The original driver uses init_timer() and passes in a pointer to the timer_list structure. That limer_list structure's 'data' element was set to a pointer to another memory structure and the 'function' element set to the callback. Inside the callback function the 'data' element was used to access other bits of stuff.

The current timer init method uses timer_setup( timer_list *, callback, (unsigned int) flags); and the timer_list structure has changed to eliminate the 'data' field.

I'm not sure what is the best/proper way to inform the callback function of the equivalent 'data' element. Can anyone provide some guidance?

Here is a snippet of the old 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;

The callback function starts off like this:

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

So the old code gets passed the pointer to myDevice so inside the callback that structure can be accessed.

But with the new timer method only has available an int that is 4 bytes but a pointer is 8 (or whatever).

What I'd like to do is this:

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

but of course that generates compile errors because dev is a pointer to type myDevice, which does not fit in an int.

I'm missing something silly, aren't I?


回答1:


The timer_setup() with three args is present since 4.14 Linux kernel (FYI there was setup_timer() in slightly earlier versions). If you maintain some code which should be relevant up to recent kernels - you have to change it in appropriate way every time the API changes. Now you can access your data through the special function from_timer() based on container_of().

timer_list is normally used not as pointer inside struct, so the example implies normal usage and could be something like:

#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

The callback function:

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

Read also:

  • Linux kernel timers new API
  • Example
  • Linux kernel versions


来源:https://stackoverflow.com/questions/53839625/adaptation-from-old-init-timer-to-new-timer-setup

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!