| ============================= | |
| 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/container_of.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. |