设备驱动设计模式

描述了在设备驱动中使用的通用的设计模式,

  1. State Container
  2. container_of()

    State Container

    理论上来说,驱动程序的挂载都是只需要一次,但是实际上来说,设备驱动程序绑定的设备将会出现在多个实例当中。因此这意味这 probe()函数是属于可重入的。实现这个目的最简单的方法就是状态容器设计模式 __state container design pattern ```c struct foo { spinlock_t lock; / Example member / (…) };

static int foo_probe(…) { struct foo *foo;

  1. foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL);
  2. if (!foo)
  3. return -ENOMEM;
  4. spin_lock_init(&foo->lock);
  5. (...)

}

  1. _调用probe函数的时候,创建一个struct foo实例。这就是设备驱动的状态容器。当然还得注意一件事,就是需要访问这个状态实例的其他函数成员必须能够访问。_
  2. ```c
  3. static irqreturn_t foo_handler(int irq, void *arg)
  4. {
  5. struct foo *foo = arg;
  6. (...)
  7. }
  8. static int foo_probe(...)
  9. {
  10. struct foo *foo;
  11. (...)
  12. ret = request_irq(irq, foo_handler, 0, "foo", foo);
  13. }

我们可以看到这里很巧妙的使用的C语言的指针来实现这个功能,handler调用者不需要知道这个指针具体的类型,只需要传递一个空指针即可。

container_of()

上面是probe的实现,现在需要实现一个卸载的动作。

  1. struct foo {
  2. spinlock_t lock;
  3. struct workqueue_struct *wq;
  4. struct work_struct offload;
  5. (...)
  6. };
  7. static void foo_work(struct work_struct *work)
  8. {
  9. struct foo *foo = container_of(work, struct foo, offload);
  10. (...)
  11. }
  12. static irqreturn_t foo_handler(int irq, void *arg)
  13. {
  14. struct foo *foo = arg;
  15. /*This will queue the work to the CPU on which it was submitted,
  16. but if the CPU dies it can be processed by another CPU.*/
  17. queue_work(foo->wq, &foo->offload);
  18. (...)
  19. }
  20. static int foo_probe(...)
  21. {
  22. struct foo *foo;
  23. foo->wq = create_singlethread_workqueue("foo-wq");
  24. INIT_WORK(&foo->offload, foo_work);
  25. (...)
  26. }



_

参考资料

Linux Device Driver Tutorial Part 16 – Workqueue in Linux Kernel Part 3