设备驱动设计模式
描述了在设备驱动中使用的通用的设计模式,
- State Container
container_of()
State Container
理论上来说,驱动程序的挂载都是只需要一次,但是实际上来说,设备驱动程序绑定的设备将会出现在多个实例当中。因此这意味这 probe()函数是属于可重入的。实现这个目的最简单的方法就是状态容器设计模式 __state container design pattern ```c struct foo { spinlock_t lock; / Example member / (…) };
static int foo_probe(…) { struct foo *foo;
foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL);
if (!foo)
return -ENOMEM;
spin_lock_init(&foo->lock);
(...)
}
_调用probe函数的时候,创建一个struct foo实例。这就是设备驱动的状态容器。当然还得注意一件事,就是需要访问这个状态实例的其他函数成员必须能够访问。_
```c
static irqreturn_t foo_handler(int irq, void *arg)
{
struct foo *foo = arg;
(...)
}
static int foo_probe(...)
{
struct foo *foo;
(...)
ret = request_irq(irq, foo_handler, 0, "foo", foo);
}
我们可以看到这里很巧妙的使用的C语言的指针来实现这个功能,handler调用者不需要知道这个指针具体的类型,只需要传递一个空指针即可。
container_of()
上面是probe的实现,现在需要实现一个卸载的动作。
struct foo {
spinlock_t lock;
struct workqueue_struct *wq;
struct work_struct offload;
(...)
};
static void foo_work(struct work_struct *work)
{
struct foo *foo = container_of(work, struct foo, offload);
(...)
}
static irqreturn_t foo_handler(int irq, void *arg)
{
struct foo *foo = arg;
/*This will queue the work to the CPU on which it was submitted,
but if the CPU dies it can be processed by another CPU.*/
queue_work(foo->wq, &foo->offload);
(...)
}
static int foo_probe(...)
{
struct foo *foo;
foo->wq = create_singlethread_workqueue("foo-wq");
INIT_WORK(&foo->offload, foo_work);
(...)
}
参考资料
Linux Device Driver Tutorial Part 16 – Workqueue in Linux Kernel Part 3