123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- Device Driver Design Patterns
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- This document describes a few common design patterns found in device drivers.
- It is likely that subsystem maintainers will ask driver developers to
- conform to these design patterns.
- 1. State Container
- 2. container_of()
- 1. State Container
- ~~~~~~~~~~~~~~~~~~
- While the kernel contains a few device drivers that assume that they will
- only be probed() once on a certain system (singletons), it is custom to assume
- that the device the driver binds to will appear in several instances. This
- means that the probe() function and all callbacks need to be reentrant.
- The most common way to achieve this is to use the state container design
- pattern. It usually has this form:
- 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);
- (...)
- }
- This will create an instance of struct foo in memory every time probe() is
- called. This is our state container for this instance of the device driver.
- Of course it is then necessary to always pass this instance of the
- state around to all functions that need access to the state and its members.
- For example, if the driver is registering an interrupt handler, you would
- pass around a pointer to struct foo like this:
- 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);
- }
- This way you always get a pointer back to the correct instance of foo in
- your interrupt handler.
- 2. container_of()
- ~~~~~~~~~~~~~~~~~
- Continuing on the above example we add an offloaded work:
- 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;
- 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);
- (...)
- }
- The design pattern is the same for an hrtimer or something similar that will
- return a single argument which is a pointer to a struct member in the
- callback.
- container_of() is a macro defined in <linux/kernel.h>
- What container_of() does is to obtain a pointer to the containing struct from
- a pointer to a member by a simple subtraction using the offsetof() macro from
- standard C, which allows something similar to object oriented behaviours.
- Notice that the contained member must not be a pointer, but an actual member
- for this to work.
- We can see here that we avoid having global pointers to our struct foo *
- instance this way, while still keeping the number of parameters passed to the
- work function to a single pointer.
|