docs: driver-model: move it to the driver-api book
The audience for the Kernel driver-model is clearly Kernel hackers. Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> Acked-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> # ice driver changes
This commit is contained in:
98
Documentation/driver-api/driver-model/binding.rst
Normal file
98
Documentation/driver-api/driver-model/binding.rst
Normal file
@@ -0,0 +1,98 @@
|
||||
==============
|
||||
Driver Binding
|
||||
==============
|
||||
|
||||
Driver binding is the process of associating a device with a device
|
||||
driver that can control it. Bus drivers have typically handled this
|
||||
because there have been bus-specific structures to represent the
|
||||
devices and the drivers. With generic device and device driver
|
||||
structures, most of the binding can take place using common code.
|
||||
|
||||
|
||||
Bus
|
||||
~~~
|
||||
|
||||
The bus type structure contains a list of all devices that are on that bus
|
||||
type in the system. When device_register is called for a device, it is
|
||||
inserted into the end of this list. The bus object also contains a
|
||||
list of all drivers of that bus type. When driver_register is called
|
||||
for a driver, it is inserted at the end of this list. These are the
|
||||
two events which trigger driver binding.
|
||||
|
||||
|
||||
device_register
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
When a new device is added, the bus's list of drivers is iterated over
|
||||
to find one that supports it. In order to determine that, the device
|
||||
ID of the device must match one of the device IDs that the driver
|
||||
supports. The format and semantics for comparing IDs is bus-specific.
|
||||
Instead of trying to derive a complex state machine and matching
|
||||
algorithm, it is up to the bus driver to provide a callback to compare
|
||||
a device against the IDs of a driver. The bus returns 1 if a match was
|
||||
found; 0 otherwise.
|
||||
|
||||
int match(struct device * dev, struct device_driver * drv);
|
||||
|
||||
If a match is found, the device's driver field is set to the driver
|
||||
and the driver's probe callback is called. This gives the driver a
|
||||
chance to verify that it really does support the hardware, and that
|
||||
it's in a working state.
|
||||
|
||||
Device Class
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Upon the successful completion of probe, the device is registered with
|
||||
the class to which it belongs. Device drivers belong to one and only one
|
||||
class, and that is set in the driver's devclass field.
|
||||
devclass_add_device is called to enumerate the device within the class
|
||||
and actually register it with the class, which happens with the
|
||||
class's register_dev callback.
|
||||
|
||||
|
||||
Driver
|
||||
~~~~~~
|
||||
|
||||
When a driver is attached to a device, the device is inserted into the
|
||||
driver's list of devices.
|
||||
|
||||
|
||||
sysfs
|
||||
~~~~~
|
||||
|
||||
A symlink is created in the bus's 'devices' directory that points to
|
||||
the device's directory in the physical hierarchy.
|
||||
|
||||
A symlink is created in the driver's 'devices' directory that points
|
||||
to the device's directory in the physical hierarchy.
|
||||
|
||||
A directory for the device is created in the class's directory. A
|
||||
symlink is created in that directory that points to the device's
|
||||
physical location in the sysfs tree.
|
||||
|
||||
A symlink can be created (though this isn't done yet) in the device's
|
||||
physical directory to either its class directory, or the class's
|
||||
top-level directory. One can also be created to point to its driver's
|
||||
directory also.
|
||||
|
||||
|
||||
driver_register
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The process is almost identical for when a new driver is added.
|
||||
The bus's list of devices is iterated over to find a match. Devices
|
||||
that already have a driver are skipped. All the devices are iterated
|
||||
over, to bind as many devices as possible to the driver.
|
||||
|
||||
|
||||
Removal
|
||||
~~~~~~~
|
||||
|
||||
When a device is removed, the reference count for it will eventually
|
||||
go to 0. When it does, the remove callback of the driver is called. It
|
||||
is removed from the driver's list of devices and the reference count
|
||||
of the driver is decremented. All symlinks between the two are removed.
|
||||
|
||||
When a driver is removed, the list of devices that it supports is
|
||||
iterated over, and the driver's remove callback is called for each
|
||||
one. The device is removed from that list and the symlinks removed.
|
146
Documentation/driver-api/driver-model/bus.rst
Normal file
146
Documentation/driver-api/driver-model/bus.rst
Normal file
@@ -0,0 +1,146 @@
|
||||
=========
|
||||
Bus Types
|
||||
=========
|
||||
|
||||
Definition
|
||||
~~~~~~~~~~
|
||||
See the kerneldoc for the struct bus_type.
|
||||
|
||||
int bus_register(struct bus_type * bus);
|
||||
|
||||
|
||||
Declaration
|
||||
~~~~~~~~~~~
|
||||
|
||||
Each bus type in the kernel (PCI, USB, etc) should declare one static
|
||||
object of this type. They must initialize the name field, and may
|
||||
optionally initialize the match callback::
|
||||
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
.match = pci_bus_match,
|
||||
};
|
||||
|
||||
The structure should be exported to drivers in a header file:
|
||||
|
||||
extern struct bus_type pci_bus_type;
|
||||
|
||||
|
||||
Registration
|
||||
~~~~~~~~~~~~
|
||||
|
||||
When a bus driver is initialized, it calls bus_register. This
|
||||
initializes the rest of the fields in the bus object and inserts it
|
||||
into a global list of bus types. Once the bus object is registered,
|
||||
the fields in it are usable by the bus driver.
|
||||
|
||||
|
||||
Callbacks
|
||||
~~~~~~~~~
|
||||
|
||||
match(): Attaching Drivers to Devices
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The format of device ID structures and the semantics for comparing
|
||||
them are inherently bus-specific. Drivers typically declare an array
|
||||
of device IDs of devices they support that reside in a bus-specific
|
||||
driver structure.
|
||||
|
||||
The purpose of the match callback is to give the bus an opportunity to
|
||||
determine if a particular driver supports a particular device by
|
||||
comparing the device IDs the driver supports with the device ID of a
|
||||
particular device, without sacrificing bus-specific functionality or
|
||||
type-safety.
|
||||
|
||||
When a driver is registered with the bus, the bus's list of devices is
|
||||
iterated over, and the match callback is called for each device that
|
||||
does not have a driver associated with it.
|
||||
|
||||
|
||||
|
||||
Device and Driver Lists
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The lists of devices and drivers are intended to replace the local
|
||||
lists that many buses keep. They are lists of struct devices and
|
||||
struct device_drivers, respectively. Bus drivers are free to use the
|
||||
lists as they please, but conversion to the bus-specific type may be
|
||||
necessary.
|
||||
|
||||
The LDM core provides helper functions for iterating over each list::
|
||||
|
||||
int bus_for_each_dev(struct bus_type * bus, struct device * start,
|
||||
void * data,
|
||||
int (*fn)(struct device *, void *));
|
||||
|
||||
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
|
||||
void * data, int (*fn)(struct device_driver *, void *));
|
||||
|
||||
These helpers iterate over the respective list, and call the callback
|
||||
for each device or driver in the list. All list accesses are
|
||||
synchronized by taking the bus's lock (read currently). The reference
|
||||
count on each object in the list is incremented before the callback is
|
||||
called; it is decremented after the next object has been obtained. The
|
||||
lock is not held when calling the callback.
|
||||
|
||||
|
||||
sysfs
|
||||
~~~~~~~~
|
||||
There is a top-level directory named 'bus'.
|
||||
|
||||
Each bus gets a directory in the bus directory, along with two default
|
||||
directories::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
|
||||
Drivers registered with the bus get a directory in the bus's drivers
|
||||
directory::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
|-- Intel ICH
|
||||
|-- Intel ICH Joystick
|
||||
|-- agpgart
|
||||
`-- e100
|
||||
|
||||
Each device that is discovered on a bus of that type gets a symlink in
|
||||
the bus's devices directory to the device's directory in the physical
|
||||
hierarchy::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
| |-- 00:00.0 -> ../../../root/pci0/00:00.0
|
||||
| |-- 00:01.0 -> ../../../root/pci0/00:01.0
|
||||
| `-- 00:02.0 -> ../../../root/pci0/00:02.0
|
||||
`-- drivers
|
||||
|
||||
|
||||
Exporting Attributes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
struct bus_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct bus_type *, char * buf);
|
||||
ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
|
||||
};
|
||||
|
||||
Bus drivers can export attributes using the BUS_ATTR_RW macro that works
|
||||
similarly to the DEVICE_ATTR_RW macro for devices. For example, a
|
||||
definition like this::
|
||||
|
||||
static BUS_ATTR_RW(debug);
|
||||
|
||||
is equivalent to declaring::
|
||||
|
||||
static bus_attribute bus_attr_debug;
|
||||
|
||||
This can then be used to add and remove the attribute from the bus's
|
||||
sysfs directory using::
|
||||
|
||||
int bus_create_file(struct bus_type *, struct bus_attribute *);
|
||||
void bus_remove_file(struct bus_type *, struct bus_attribute *);
|
149
Documentation/driver-api/driver-model/class.rst
Normal file
149
Documentation/driver-api/driver-model/class.rst
Normal file
@@ -0,0 +1,149 @@
|
||||
==============
|
||||
Device Classes
|
||||
==============
|
||||
|
||||
Introduction
|
||||
~~~~~~~~~~~~
|
||||
A device class describes a type of device, like an audio or network
|
||||
device. The following device classes have been identified:
|
||||
|
||||
<Insert List of Device Classes Here>
|
||||
|
||||
|
||||
Each device class defines a set of semantics and a programming interface
|
||||
that devices of that class adhere to. Device drivers are the
|
||||
implementation of that programming interface for a particular device on
|
||||
a particular bus.
|
||||
|
||||
Device classes are agnostic with respect to what bus a device resides
|
||||
on.
|
||||
|
||||
|
||||
Programming Interface
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The device class structure looks like::
|
||||
|
||||
|
||||
typedef int (*devclass_add)(struct device *);
|
||||
typedef void (*devclass_remove)(struct device *);
|
||||
|
||||
See the kerneldoc for the struct class.
|
||||
|
||||
A typical device class definition would look like::
|
||||
|
||||
struct device_class input_devclass = {
|
||||
.name = "input",
|
||||
.add_device = input_add_device,
|
||||
.remove_device = input_remove_device,
|
||||
};
|
||||
|
||||
Each device class structure should be exported in a header file so it
|
||||
can be used by drivers, extensions and interfaces.
|
||||
|
||||
Device classes are registered and unregistered with the core using::
|
||||
|
||||
int devclass_register(struct device_class * cls);
|
||||
void devclass_unregister(struct device_class * cls);
|
||||
|
||||
|
||||
Devices
|
||||
~~~~~~~
|
||||
As devices are bound to drivers, they are added to the device class
|
||||
that the driver belongs to. Before the driver model core, this would
|
||||
typically happen during the driver's probe() callback, once the device
|
||||
has been initialized. It now happens after the probe() callback
|
||||
finishes from the core.
|
||||
|
||||
The device is enumerated in the class. Each time a device is added to
|
||||
the class, the class's devnum field is incremented and assigned to the
|
||||
device. The field is never decremented, so if the device is removed
|
||||
from the class and re-added, it will receive a different enumerated
|
||||
value.
|
||||
|
||||
The class is allowed to create a class-specific structure for the
|
||||
device and store it in the device's class_data pointer.
|
||||
|
||||
There is no list of devices in the device class. Each driver has a
|
||||
list of devices that it supports. The device class has a list of
|
||||
drivers of that particular class. To access all of the devices in the
|
||||
class, iterate over the device lists of each driver in the class.
|
||||
|
||||
|
||||
Device Drivers
|
||||
~~~~~~~~~~~~~~
|
||||
Device drivers are added to device classes when they are registered
|
||||
with the core. A driver specifies the class it belongs to by setting
|
||||
the struct device_driver::devclass field.
|
||||
|
||||
|
||||
sysfs directory structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
There is a top-level sysfs directory named 'class'.
|
||||
|
||||
Each class gets a directory in the class directory, along with two
|
||||
default subdirectories::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
|-- devices
|
||||
`-- drivers
|
||||
|
||||
|
||||
Drivers registered with the class get a symlink in the drivers/ directory
|
||||
that points to the driver's directory (under its bus directory)::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
|-- devices
|
||||
`-- drivers
|
||||
`-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/
|
||||
|
||||
|
||||
Each device gets a symlink in the devices/ directory that points to the
|
||||
device's directory in the physical hierarchy::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
|-- devices
|
||||
| `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
|
||||
`-- drivers
|
||||
|
||||
|
||||
Exporting Attributes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
struct devclass_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off);
|
||||
ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off);
|
||||
};
|
||||
|
||||
Class drivers can export attributes using the DEVCLASS_ATTR macro that works
|
||||
similarly to the DEVICE_ATTR macro for devices. For example, a definition
|
||||
like this::
|
||||
|
||||
static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);
|
||||
|
||||
is equivalent to declaring::
|
||||
|
||||
static devclass_attribute devclass_attr_debug;
|
||||
|
||||
The bus driver can add and remove the attribute from the class's
|
||||
sysfs directory using::
|
||||
|
||||
int devclass_create_file(struct device_class *, struct devclass_attribute *);
|
||||
void devclass_remove_file(struct device_class *, struct devclass_attribute *);
|
||||
|
||||
In the example above, the file will be named 'debug' in placed in the
|
||||
class's directory in sysfs.
|
||||
|
||||
|
||||
Interfaces
|
||||
~~~~~~~~~~
|
||||
There may exist multiple mechanisms for accessing the same device of a
|
||||
particular class type. Device interfaces describe these mechanisms.
|
||||
|
||||
When a device is added to a device class, the core attempts to add it
|
||||
to every interface that is registered with the device class.
|
116
Documentation/driver-api/driver-model/design-patterns.rst
Normal file
116
Documentation/driver-api/driver-model/design-patterns.rst
Normal file
@@ -0,0 +1,116 @@
|
||||
=============================
|
||||
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.
|
109
Documentation/driver-api/driver-model/device.rst
Normal file
109
Documentation/driver-api/driver-model/device.rst
Normal file
@@ -0,0 +1,109 @@
|
||||
==========================
|
||||
The Basic Device Structure
|
||||
==========================
|
||||
|
||||
See the kerneldoc for the struct device.
|
||||
|
||||
|
||||
Programming Interface
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The bus driver that discovers the device uses this to register the
|
||||
device with the core::
|
||||
|
||||
int device_register(struct device * dev);
|
||||
|
||||
The bus should initialize the following fields:
|
||||
|
||||
- parent
|
||||
- name
|
||||
- bus_id
|
||||
- bus
|
||||
|
||||
A device is removed from the core when its reference count goes to
|
||||
0. The reference count can be adjusted using::
|
||||
|
||||
struct device * get_device(struct device * dev);
|
||||
void put_device(struct device * dev);
|
||||
|
||||
get_device() will return a pointer to the struct device passed to it
|
||||
if the reference is not already 0 (if it's in the process of being
|
||||
removed already).
|
||||
|
||||
A driver can access the lock in the device structure using::
|
||||
|
||||
void lock_device(struct device * dev);
|
||||
void unlock_device(struct device * dev);
|
||||
|
||||
|
||||
Attributes
|
||||
~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
struct device_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
};
|
||||
|
||||
Attributes of devices can be exported by a device driver through sysfs.
|
||||
|
||||
Please see Documentation/filesystems/sysfs.txt for more information
|
||||
on how sysfs works.
|
||||
|
||||
As explained in Documentation/kobject.txt, device attributes must be
|
||||
created before the KOBJ_ADD uevent is generated. The only way to realize
|
||||
that is by defining an attribute group.
|
||||
|
||||
Attributes are declared using a macro called DEVICE_ATTR::
|
||||
|
||||
#define DEVICE_ATTR(name,mode,show,store)
|
||||
|
||||
Example:::
|
||||
|
||||
static DEVICE_ATTR(type, 0444, show_type, NULL);
|
||||
static DEVICE_ATTR(power, 0644, show_power, store_power);
|
||||
|
||||
This declares two structures of type struct device_attribute with respective
|
||||
names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be
|
||||
organized as follows into a group::
|
||||
|
||||
static struct attribute *dev_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_power.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group dev_attr_group = {
|
||||
.attrs = dev_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *dev_attr_groups[] = {
|
||||
&dev_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
This array of groups can then be associated with a device by setting the
|
||||
group pointer in struct device before device_register() is invoked::
|
||||
|
||||
dev->groups = dev_attr_groups;
|
||||
device_register(dev);
|
||||
|
||||
The device_register() function will use the 'groups' pointer to create the
|
||||
device attributes and the device_unregister() function will use this pointer
|
||||
to remove the device attributes.
|
||||
|
||||
Word of warning: While the kernel allows device_create_file() and
|
||||
device_remove_file() to be called on a device at any time, userspace has
|
||||
strict expectations on when attributes get created. When a new device is
|
||||
registered in the kernel, a uevent is generated to notify userspace (like
|
||||
udev) that a new device is available. If attributes are added after the
|
||||
device is registered, then userspace won't get notified and userspace will
|
||||
not know about the new attributes.
|
||||
|
||||
This is important for device driver that need to publish additional
|
||||
attributes for a device at driver probe time. If the device driver simply
|
||||
calls device_create_file() on the device structure passed to it, then
|
||||
userspace will never be notified of the new attributes.
|
414
Documentation/driver-api/driver-model/devres.rst
Normal file
414
Documentation/driver-api/driver-model/devres.rst
Normal file
@@ -0,0 +1,414 @@
|
||||
================================
|
||||
Devres - Managed Device Resource
|
||||
================================
|
||||
|
||||
Tejun Heo <teheo@suse.de>
|
||||
|
||||
First draft 10 January 2007
|
||||
|
||||
.. contents
|
||||
|
||||
1. Intro : Huh? Devres?
|
||||
2. Devres : Devres in a nutshell
|
||||
3. Devres Group : Group devres'es and release them together
|
||||
4. Details : Life time rules, calling context, ...
|
||||
5. Overhead : How much do we have to pay for this?
|
||||
6. List of managed interfaces: Currently implemented managed interfaces
|
||||
|
||||
|
||||
1. Intro
|
||||
--------
|
||||
|
||||
devres came up while trying to convert libata to use iomap. Each
|
||||
iomapped address should be kept and unmapped on driver detach. For
|
||||
example, a plain SFF ATA controller (that is, good old PCI IDE) in
|
||||
native mode makes use of 5 PCI BARs and all of them should be
|
||||
maintained.
|
||||
|
||||
As with many other device drivers, libata low level drivers have
|
||||
sufficient bugs in ->remove and ->probe failure path. Well, yes,
|
||||
that's probably because libata low level driver developers are lazy
|
||||
bunch, but aren't all low level driver developers? After spending a
|
||||
day fiddling with braindamaged hardware with no document or
|
||||
braindamaged document, if it's finally working, well, it's working.
|
||||
|
||||
For one reason or another, low level drivers don't receive as much
|
||||
attention or testing as core code, and bugs on driver detach or
|
||||
initialization failure don't happen often enough to be noticeable.
|
||||
Init failure path is worse because it's much less travelled while
|
||||
needs to handle multiple entry points.
|
||||
|
||||
So, many low level drivers end up leaking resources on driver detach
|
||||
and having half broken failure path implementation in ->probe() which
|
||||
would leak resources or even cause oops when failure occurs. iomap
|
||||
adds more to this mix. So do msi and msix.
|
||||
|
||||
|
||||
2. Devres
|
||||
---------
|
||||
|
||||
devres is basically linked list of arbitrarily sized memory areas
|
||||
associated with a struct device. Each devres entry is associated with
|
||||
a release function. A devres can be released in several ways. No
|
||||
matter what, all devres entries are released on driver detach. On
|
||||
release, the associated release function is invoked and then the
|
||||
devres entry is freed.
|
||||
|
||||
Managed interface is created for resources commonly used by device
|
||||
drivers using devres. For example, coherent DMA memory is acquired
|
||||
using dma_alloc_coherent(). The managed version is called
|
||||
dmam_alloc_coherent(). It is identical to dma_alloc_coherent() except
|
||||
for the DMA memory allocated using it is managed and will be
|
||||
automatically released on driver detach. Implementation looks like
|
||||
the following::
|
||||
|
||||
struct dma_devres {
|
||||
size_t size;
|
||||
void *vaddr;
|
||||
dma_addr_t dma_handle;
|
||||
};
|
||||
|
||||
static void dmam_coherent_release(struct device *dev, void *res)
|
||||
{
|
||||
struct dma_devres *this = res;
|
||||
|
||||
dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
|
||||
}
|
||||
|
||||
dmam_alloc_coherent(dev, size, dma_handle, gfp)
|
||||
{
|
||||
struct dma_devres *dr;
|
||||
void *vaddr;
|
||||
|
||||
dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
|
||||
...
|
||||
|
||||
/* alloc DMA memory as usual */
|
||||
vaddr = dma_alloc_coherent(...);
|
||||
...
|
||||
|
||||
/* record size, vaddr, dma_handle in dr */
|
||||
dr->vaddr = vaddr;
|
||||
...
|
||||
|
||||
devres_add(dev, dr);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
If a driver uses dmam_alloc_coherent(), the area is guaranteed to be
|
||||
freed whether initialization fails half-way or the device gets
|
||||
detached. If most resources are acquired using managed interface, a
|
||||
driver can have much simpler init and exit code. Init path basically
|
||||
looks like the following::
|
||||
|
||||
my_init_one()
|
||||
{
|
||||
struct mydev *d;
|
||||
|
||||
d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
d->ring = dmam_alloc_coherent(...);
|
||||
if (!d->ring)
|
||||
return -ENOMEM;
|
||||
|
||||
if (check something)
|
||||
return -EINVAL;
|
||||
...
|
||||
|
||||
return register_to_upper_layer(d);
|
||||
}
|
||||
|
||||
And exit path::
|
||||
|
||||
my_remove_one()
|
||||
{
|
||||
unregister_from_upper_layer(d);
|
||||
shutdown_my_hardware();
|
||||
}
|
||||
|
||||
As shown above, low level drivers can be simplified a lot by using
|
||||
devres. Complexity is shifted from less maintained low level drivers
|
||||
to better maintained higher layer. Also, as init failure path is
|
||||
shared with exit path, both can get more testing.
|
||||
|
||||
Note though that when converting current calls or assignments to
|
||||
managed devm_* versions it is up to you to check if internal operations
|
||||
like allocating memory, have failed. Managed resources pertains to the
|
||||
freeing of these resources *only* - all other checks needed are still
|
||||
on you. In some cases this may mean introducing checks that were not
|
||||
necessary before moving to the managed devm_* calls.
|
||||
|
||||
|
||||
3. Devres group
|
||||
---------------
|
||||
|
||||
Devres entries can be grouped using devres group. When a group is
|
||||
released, all contained normal devres entries and properly nested
|
||||
groups are released. One usage is to rollback series of acquired
|
||||
resources on failure. For example::
|
||||
|
||||
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
acquire A;
|
||||
if (failed)
|
||||
goto err;
|
||||
|
||||
acquire B;
|
||||
if (failed)
|
||||
goto err;
|
||||
...
|
||||
|
||||
devres_remove_group(dev, NULL);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
devres_release_group(dev, NULL);
|
||||
return err_code;
|
||||
|
||||
As resource acquisition failure usually means probe failure, constructs
|
||||
like above are usually useful in midlayer driver (e.g. libata core
|
||||
layer) where interface function shouldn't have side effect on failure.
|
||||
For LLDs, just returning error code suffices in most cases.
|
||||
|
||||
Each group is identified by `void *id`. It can either be explicitly
|
||||
specified by @id argument to devres_open_group() or automatically
|
||||
created by passing NULL as @id as in the above example. In both
|
||||
cases, devres_open_group() returns the group's id. The returned id
|
||||
can be passed to other devres functions to select the target group.
|
||||
If NULL is given to those functions, the latest open group is
|
||||
selected.
|
||||
|
||||
For example, you can do something like the following::
|
||||
|
||||
int my_midlayer_create_something()
|
||||
{
|
||||
if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
...
|
||||
|
||||
devres_close_group(dev, my_midlayer_create_something);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void my_midlayer_destroy_something()
|
||||
{
|
||||
devres_release_group(dev, my_midlayer_create_something);
|
||||
}
|
||||
|
||||
|
||||
4. Details
|
||||
----------
|
||||
|
||||
Lifetime of a devres entry begins on devres allocation and finishes
|
||||
when it is released or destroyed (removed and freed) - no reference
|
||||
counting.
|
||||
|
||||
devres core guarantees atomicity to all basic devres operations and
|
||||
has support for single-instance devres types (atomic
|
||||
lookup-and-add-if-not-found). Other than that, synchronizing
|
||||
concurrent accesses to allocated devres data is caller's
|
||||
responsibility. This is usually non-issue because bus ops and
|
||||
resource allocations already do the job.
|
||||
|
||||
For an example of single-instance devres type, read pcim_iomap_table()
|
||||
in lib/devres.c.
|
||||
|
||||
All devres interface functions can be called without context if the
|
||||
right gfp mask is given.
|
||||
|
||||
|
||||
5. Overhead
|
||||
-----------
|
||||
|
||||
Each devres bookkeeping info is allocated together with requested data
|
||||
area. With debug option turned off, bookkeeping info occupies 16
|
||||
bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded
|
||||
up to ull alignment). If singly linked list is used, it can be
|
||||
reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit).
|
||||
|
||||
Each devres group occupies 8 pointers. It can be reduced to 6 if
|
||||
singly linked list is used.
|
||||
|
||||
Memory space overhead on ahci controller with two ports is between 300
|
||||
and 400 bytes on 32bit machine after naive conversion (we can
|
||||
certainly invest a bit more effort into libata core layer).
|
||||
|
||||
|
||||
6. List of managed interfaces
|
||||
-----------------------------
|
||||
|
||||
CLOCK
|
||||
devm_clk_get()
|
||||
devm_clk_get_optional()
|
||||
devm_clk_put()
|
||||
devm_clk_hw_register()
|
||||
devm_of_clk_add_hw_provider()
|
||||
devm_clk_hw_register_clkdev()
|
||||
|
||||
DMA
|
||||
dmaenginem_async_device_register()
|
||||
dmam_alloc_coherent()
|
||||
dmam_alloc_attrs()
|
||||
dmam_free_coherent()
|
||||
dmam_pool_create()
|
||||
dmam_pool_destroy()
|
||||
|
||||
DRM
|
||||
devm_drm_dev_init()
|
||||
|
||||
GPIO
|
||||
devm_gpiod_get()
|
||||
devm_gpiod_get_index()
|
||||
devm_gpiod_get_index_optional()
|
||||
devm_gpiod_get_optional()
|
||||
devm_gpiod_put()
|
||||
devm_gpiod_unhinge()
|
||||
devm_gpiochip_add_data()
|
||||
devm_gpio_request()
|
||||
devm_gpio_request_one()
|
||||
devm_gpio_free()
|
||||
|
||||
I2C
|
||||
devm_i2c_new_dummy_device()
|
||||
|
||||
IIO
|
||||
devm_iio_device_alloc()
|
||||
devm_iio_device_free()
|
||||
devm_iio_device_register()
|
||||
devm_iio_device_unregister()
|
||||
devm_iio_kfifo_allocate()
|
||||
devm_iio_kfifo_free()
|
||||
devm_iio_triggered_buffer_setup()
|
||||
devm_iio_triggered_buffer_cleanup()
|
||||
devm_iio_trigger_alloc()
|
||||
devm_iio_trigger_free()
|
||||
devm_iio_trigger_register()
|
||||
devm_iio_trigger_unregister()
|
||||
devm_iio_channel_get()
|
||||
devm_iio_channel_release()
|
||||
devm_iio_channel_get_all()
|
||||
devm_iio_channel_release_all()
|
||||
|
||||
INPUT
|
||||
devm_input_allocate_device()
|
||||
|
||||
IO region
|
||||
devm_release_mem_region()
|
||||
devm_release_region()
|
||||
devm_release_resource()
|
||||
devm_request_mem_region()
|
||||
devm_request_region()
|
||||
devm_request_resource()
|
||||
|
||||
IOMAP
|
||||
devm_ioport_map()
|
||||
devm_ioport_unmap()
|
||||
devm_ioremap()
|
||||
devm_ioremap_nocache()
|
||||
devm_ioremap_wc()
|
||||
devm_ioremap_resource() : checks resource, requests memory region, ioremaps
|
||||
devm_iounmap()
|
||||
pcim_iomap()
|
||||
pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
|
||||
pcim_iomap_table() : array of mapped addresses indexed by BAR
|
||||
pcim_iounmap()
|
||||
|
||||
IRQ
|
||||
devm_free_irq()
|
||||
devm_request_any_context_irq()
|
||||
devm_request_irq()
|
||||
devm_request_threaded_irq()
|
||||
devm_irq_alloc_descs()
|
||||
devm_irq_alloc_desc()
|
||||
devm_irq_alloc_desc_at()
|
||||
devm_irq_alloc_desc_from()
|
||||
devm_irq_alloc_descs_from()
|
||||
devm_irq_alloc_generic_chip()
|
||||
devm_irq_setup_generic_chip()
|
||||
devm_irq_sim_init()
|
||||
|
||||
LED
|
||||
devm_led_classdev_register()
|
||||
devm_led_classdev_unregister()
|
||||
|
||||
MDIO
|
||||
devm_mdiobus_alloc()
|
||||
devm_mdiobus_alloc_size()
|
||||
devm_mdiobus_free()
|
||||
|
||||
MEM
|
||||
devm_free_pages()
|
||||
devm_get_free_pages()
|
||||
devm_kasprintf()
|
||||
devm_kcalloc()
|
||||
devm_kfree()
|
||||
devm_kmalloc()
|
||||
devm_kmalloc_array()
|
||||
devm_kmemdup()
|
||||
devm_kstrdup()
|
||||
devm_kvasprintf()
|
||||
devm_kzalloc()
|
||||
|
||||
MFD
|
||||
devm_mfd_add_devices()
|
||||
|
||||
MUX
|
||||
devm_mux_chip_alloc()
|
||||
devm_mux_chip_register()
|
||||
devm_mux_control_get()
|
||||
|
||||
PER-CPU MEM
|
||||
devm_alloc_percpu()
|
||||
devm_free_percpu()
|
||||
|
||||
PCI
|
||||
devm_pci_alloc_host_bridge() : managed PCI host bridge allocation
|
||||
devm_pci_remap_cfgspace() : ioremap PCI configuration space
|
||||
devm_pci_remap_cfg_resource() : ioremap PCI configuration space resource
|
||||
pcim_enable_device() : after success, all PCI ops become managed
|
||||
pcim_pin_device() : keep PCI device enabled after release
|
||||
|
||||
PHY
|
||||
devm_usb_get_phy()
|
||||
devm_usb_put_phy()
|
||||
|
||||
PINCTRL
|
||||
devm_pinctrl_get()
|
||||
devm_pinctrl_put()
|
||||
devm_pinctrl_register()
|
||||
devm_pinctrl_unregister()
|
||||
|
||||
POWER
|
||||
devm_reboot_mode_register()
|
||||
devm_reboot_mode_unregister()
|
||||
|
||||
PWM
|
||||
devm_pwm_get()
|
||||
devm_pwm_put()
|
||||
|
||||
REGULATOR
|
||||
devm_regulator_bulk_get()
|
||||
devm_regulator_get()
|
||||
devm_regulator_put()
|
||||
devm_regulator_register()
|
||||
|
||||
RESET
|
||||
devm_reset_control_get()
|
||||
devm_reset_controller_register()
|
||||
|
||||
SERDEV
|
||||
devm_serdev_device_open()
|
||||
|
||||
SLAVE DMA ENGINE
|
||||
devm_acpi_dma_controller_register()
|
||||
|
||||
SPI
|
||||
devm_spi_register_master()
|
||||
|
||||
WATCHDOG
|
||||
devm_watchdog_register_device()
|
223
Documentation/driver-api/driver-model/driver.rst
Normal file
223
Documentation/driver-api/driver-model/driver.rst
Normal file
@@ -0,0 +1,223 @@
|
||||
==============
|
||||
Device Drivers
|
||||
==============
|
||||
|
||||
See the kerneldoc for the struct device_driver.
|
||||
|
||||
|
||||
Allocation
|
||||
~~~~~~~~~~
|
||||
|
||||
Device drivers are statically allocated structures. Though there may
|
||||
be multiple devices in a system that a driver supports, struct
|
||||
device_driver represents the driver as a whole (not a particular
|
||||
device instance).
|
||||
|
||||
Initialization
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The driver must initialize at least the name and bus fields. It should
|
||||
also initialize the devclass field (when it arrives), so it may obtain
|
||||
the proper linkage internally. It should also initialize as many of
|
||||
the callbacks as possible, though each is optional.
|
||||
|
||||
Declaration
|
||||
~~~~~~~~~~~
|
||||
|
||||
As stated above, struct device_driver objects are statically
|
||||
allocated. Below is an example declaration of the eepro100
|
||||
driver. This declaration is hypothetical only; it relies on the driver
|
||||
being converted completely to the new model::
|
||||
|
||||
static struct device_driver eepro100_driver = {
|
||||
.name = "eepro100",
|
||||
.bus = &pci_bus_type,
|
||||
|
||||
.probe = eepro100_probe,
|
||||
.remove = eepro100_remove,
|
||||
.suspend = eepro100_suspend,
|
||||
.resume = eepro100_resume,
|
||||
};
|
||||
|
||||
Most drivers will not be able to be converted completely to the new
|
||||
model because the bus they belong to has a bus-specific structure with
|
||||
bus-specific fields that cannot be generalized.
|
||||
|
||||
The most common example of this are device ID structures. A driver
|
||||
typically defines an array of device IDs that it supports. The format
|
||||
of these structures and the semantics for comparing device IDs are
|
||||
completely bus-specific. Defining them as bus-specific entities would
|
||||
sacrifice type-safety, so we keep bus-specific structures around.
|
||||
|
||||
Bus-specific drivers should include a generic struct device_driver in
|
||||
the definition of the bus-specific driver. Like this::
|
||||
|
||||
struct pci_driver {
|
||||
const struct pci_device_id *id_table;
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
A definition that included bus-specific fields would look like
|
||||
(using the eepro100 driver again)::
|
||||
|
||||
static struct pci_driver eepro100_driver = {
|
||||
.id_table = eepro100_pci_tbl,
|
||||
.driver = {
|
||||
.name = "eepro100",
|
||||
.bus = &pci_bus_type,
|
||||
.probe = eepro100_probe,
|
||||
.remove = eepro100_remove,
|
||||
.suspend = eepro100_suspend,
|
||||
.resume = eepro100_resume,
|
||||
},
|
||||
};
|
||||
|
||||
Some may find the syntax of embedded struct initialization awkward or
|
||||
even a bit ugly. So far, it's the best way we've found to do what we want...
|
||||
|
||||
Registration
|
||||
~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
int driver_register(struct device_driver *drv);
|
||||
|
||||
The driver registers the structure on startup. For drivers that have
|
||||
no bus-specific fields (i.e. don't have a bus-specific driver
|
||||
structure), they would use driver_register and pass a pointer to their
|
||||
struct device_driver object.
|
||||
|
||||
Most drivers, however, will have a bus-specific structure and will
|
||||
need to register with the bus using something like pci_driver_register.
|
||||
|
||||
It is important that drivers register their driver structure as early as
|
||||
possible. Registration with the core initializes several fields in the
|
||||
struct device_driver object, including the reference count and the
|
||||
lock. These fields are assumed to be valid at all times and may be
|
||||
used by the device model core or the bus driver.
|
||||
|
||||
|
||||
Transition Bus Drivers
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By defining wrapper functions, the transition to the new model can be
|
||||
made easier. Drivers can ignore the generic structure altogether and
|
||||
let the bus wrapper fill in the fields. For the callbacks, the bus can
|
||||
define generic callbacks that forward the call to the bus-specific
|
||||
callbacks of the drivers.
|
||||
|
||||
This solution is intended to be only temporary. In order to get class
|
||||
information in the driver, the drivers must be modified anyway. Since
|
||||
converting drivers to the new model should reduce some infrastructural
|
||||
complexity and code size, it is recommended that they are converted as
|
||||
class information is added.
|
||||
|
||||
Access
|
||||
~~~~~~
|
||||
|
||||
Once the object has been registered, it may access the common fields of
|
||||
the object, like the lock and the list of devices::
|
||||
|
||||
int driver_for_each_dev(struct device_driver *drv, void *data,
|
||||
int (*callback)(struct device *dev, void *data));
|
||||
|
||||
The devices field is a list of all the devices that have been bound to
|
||||
the driver. The LDM core provides a helper function to operate on all
|
||||
the devices a driver controls. This helper locks the driver on each
|
||||
node access, and does proper reference counting on each device as it
|
||||
accesses it.
|
||||
|
||||
|
||||
sysfs
|
||||
~~~~~
|
||||
|
||||
When a driver is registered, a sysfs directory is created in its
|
||||
bus's directory. In this directory, the driver can export an interface
|
||||
to userspace to control operation of the driver on a global basis;
|
||||
e.g. toggling debugging output in the driver.
|
||||
|
||||
A future feature of this directory will be a 'devices' directory. This
|
||||
directory will contain symlinks to the directories of devices it
|
||||
supports.
|
||||
|
||||
|
||||
|
||||
Callbacks
|
||||
~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
int (*probe) (struct device *dev);
|
||||
|
||||
The probe() entry is called in task context, with the bus's rwsem locked
|
||||
and the driver partially bound to the device. Drivers commonly use
|
||||
container_of() to convert "dev" to a bus-specific type, both in probe()
|
||||
and other routines. That type often provides device resource data, such
|
||||
as pci_dev.resource[] or platform_device.resources, which is used in
|
||||
addition to dev->platform_data to initialize the driver.
|
||||
|
||||
This callback holds the driver-specific logic to bind the driver to a
|
||||
given device. That includes verifying that the device is present, that
|
||||
it's a version the driver can handle, that driver data structures can
|
||||
be allocated and initialized, and that any hardware can be initialized.
|
||||
Drivers often store a pointer to their state with dev_set_drvdata().
|
||||
When the driver has successfully bound itself to that device, then probe()
|
||||
returns zero and the driver model code will finish its part of binding
|
||||
the driver to that device.
|
||||
|
||||
A driver's probe() may return a negative errno value to indicate that
|
||||
the driver did not bind to this device, in which case it should have
|
||||
released all resources it allocated::
|
||||
|
||||
int (*remove) (struct device *dev);
|
||||
|
||||
remove is called to unbind a driver from a device. This may be
|
||||
called if a device is physically removed from the system, if the
|
||||
driver module is being unloaded, during a reboot sequence, or
|
||||
in other cases.
|
||||
|
||||
It is up to the driver to determine if the device is present or
|
||||
not. It should free any resources allocated specifically for the
|
||||
device; i.e. anything in the device's driver_data field.
|
||||
|
||||
If the device is still present, it should quiesce the device and place
|
||||
it into a supported low-power state::
|
||||
|
||||
int (*suspend) (struct device *dev, pm_message_t state);
|
||||
|
||||
suspend is called to put the device in a low power state::
|
||||
|
||||
int (*resume) (struct device *dev);
|
||||
|
||||
Resume is used to bring a device back from a low power state.
|
||||
|
||||
|
||||
Attributes
|
||||
~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
struct driver_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device_driver *driver, char *buf);
|
||||
ssize_t (*store)(struct device_driver *, const char *buf, size_t count);
|
||||
};
|
||||
|
||||
Device drivers can export attributes via their sysfs directories.
|
||||
Drivers can declare attributes using a DRIVER_ATTR_RW and DRIVER_ATTR_RO
|
||||
macro that works identically to the DEVICE_ATTR_RW and DEVICE_ATTR_RO
|
||||
macros.
|
||||
|
||||
Example::
|
||||
|
||||
DRIVER_ATTR_RW(debug);
|
||||
|
||||
This is equivalent to declaring::
|
||||
|
||||
struct driver_attribute driver_attr_debug;
|
||||
|
||||
This can then be used to add and remove the attribute from the
|
||||
driver's directory using::
|
||||
|
||||
int driver_create_file(struct device_driver *, const struct driver_attribute *);
|
||||
void driver_remove_file(struct device_driver *, const struct driver_attribute *);
|
24
Documentation/driver-api/driver-model/index.rst
Normal file
24
Documentation/driver-api/driver-model/index.rst
Normal file
@@ -0,0 +1,24 @@
|
||||
============
|
||||
Driver Model
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
binding
|
||||
bus
|
||||
class
|
||||
design-patterns
|
||||
device
|
||||
devres
|
||||
driver
|
||||
overview
|
||||
platform
|
||||
porting
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
124
Documentation/driver-api/driver-model/overview.rst
Normal file
124
Documentation/driver-api/driver-model/overview.rst
Normal file
@@ -0,0 +1,124 @@
|
||||
=============================
|
||||
The Linux Kernel Device Model
|
||||
=============================
|
||||
|
||||
Patrick Mochel <mochel@digitalimplant.org>
|
||||
|
||||
Drafted 26 August 2002
|
||||
Updated 31 January 2006
|
||||
|
||||
|
||||
Overview
|
||||
~~~~~~~~
|
||||
|
||||
The Linux Kernel Driver Model is a unification of all the disparate driver
|
||||
models that were previously used in the kernel. It is intended to augment the
|
||||
bus-specific drivers for bridges and devices by consolidating a set of data
|
||||
and operations into globally accessible data structures.
|
||||
|
||||
Traditional driver models implemented some sort of tree-like structure
|
||||
(sometimes just a list) for the devices they control. There wasn't any
|
||||
uniformity across the different bus types.
|
||||
|
||||
The current driver model provides a common, uniform data model for describing
|
||||
a bus and the devices that can appear under the bus. The unified bus
|
||||
model includes a set of common attributes which all busses carry, and a set
|
||||
of common callbacks, such as device discovery during bus probing, bus
|
||||
shutdown, bus power management, etc.
|
||||
|
||||
The common device and bridge interface reflects the goals of the modern
|
||||
computer: namely the ability to do seamless device "plug and play", power
|
||||
management, and hot plug. In particular, the model dictated by Intel and
|
||||
Microsoft (namely ACPI) ensures that almost every device on almost any bus
|
||||
on an x86-compatible system can work within this paradigm. Of course,
|
||||
not every bus is able to support all such operations, although most
|
||||
buses support most of those operations.
|
||||
|
||||
|
||||
Downstream Access
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Common data fields have been moved out of individual bus layers into a common
|
||||
data structure. These fields must still be accessed by the bus layers,
|
||||
and sometimes by the device-specific drivers.
|
||||
|
||||
Other bus layers are encouraged to do what has been done for the PCI layer.
|
||||
struct pci_dev now looks like this::
|
||||
|
||||
struct pci_dev {
|
||||
...
|
||||
|
||||
struct device dev; /* Generic device interface */
|
||||
...
|
||||
};
|
||||
|
||||
Note first that the struct device dev within the struct pci_dev is
|
||||
statically allocated. This means only one allocation on device discovery.
|
||||
|
||||
Note also that that struct device dev is not necessarily defined at the
|
||||
front of the pci_dev structure. This is to make people think about what
|
||||
they're doing when switching between the bus driver and the global driver,
|
||||
and to discourage meaningless and incorrect casts between the two.
|
||||
|
||||
The PCI bus layer freely accesses the fields of struct device. It knows about
|
||||
the structure of struct pci_dev, and it should know the structure of struct
|
||||
device. Individual PCI device drivers that have been converted to the current
|
||||
driver model generally do not and should not touch the fields of struct device,
|
||||
unless there is a compelling reason to do so.
|
||||
|
||||
The above abstraction prevents unnecessary pain during transitional phases.
|
||||
If it were not done this way, then when a field was renamed or removed, every
|
||||
downstream driver would break. On the other hand, if only the bus layer
|
||||
(and not the device layer) accesses the struct device, it is only the bus
|
||||
layer that needs to change.
|
||||
|
||||
|
||||
User Interface
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
By virtue of having a complete hierarchical view of all the devices in the
|
||||
system, exporting a complete hierarchical view to userspace becomes relatively
|
||||
easy. This has been accomplished by implementing a special purpose virtual
|
||||
file system named sysfs.
|
||||
|
||||
Almost all mainstream Linux distros mount this filesystem automatically; you
|
||||
can see some variation of the following in the output of the "mount" command::
|
||||
|
||||
$ mount
|
||||
...
|
||||
none on /sys type sysfs (rw,noexec,nosuid,nodev)
|
||||
...
|
||||
$
|
||||
|
||||
The auto-mounting of sysfs is typically accomplished by an entry similar to
|
||||
the following in the /etc/fstab file::
|
||||
|
||||
none /sys sysfs defaults 0 0
|
||||
|
||||
or something similar in the /lib/init/fstab file on Debian-based systems::
|
||||
|
||||
none /sys sysfs nodev,noexec,nosuid 0 0
|
||||
|
||||
If sysfs is not automatically mounted, you can always do it manually with::
|
||||
|
||||
# mount -t sysfs sysfs /sys
|
||||
|
||||
Whenever a device is inserted into the tree, a directory is created for it.
|
||||
This directory may be populated at each layer of discovery - the global layer,
|
||||
the bus layer, or the device layer.
|
||||
|
||||
The global layer currently creates two files - 'name' and 'power'. The
|
||||
former only reports the name of the device. The latter reports the
|
||||
current power state of the device. It will also be used to set the current
|
||||
power state.
|
||||
|
||||
The bus layer may also create files for the devices it finds while probing the
|
||||
bus. For example, the PCI layer currently creates 'irq' and 'resource' files
|
||||
for each PCI device.
|
||||
|
||||
A device-specific driver may also export files in its directory to expose
|
||||
device-specific data or tunable interfaces.
|
||||
|
||||
More information about the sysfs directory layout can be found in
|
||||
the other documents in this directory and in the file
|
||||
Documentation/filesystems/sysfs.txt.
|
246
Documentation/driver-api/driver-model/platform.rst
Normal file
246
Documentation/driver-api/driver-model/platform.rst
Normal file
@@ -0,0 +1,246 @@
|
||||
============================
|
||||
Platform Devices and Drivers
|
||||
============================
|
||||
|
||||
See <linux/platform_device.h> for the driver model interface to the
|
||||
platform bus: platform_device, and platform_driver. This pseudo-bus
|
||||
is used to connect devices on busses with minimal infrastructure,
|
||||
like those used to integrate peripherals on many system-on-chip
|
||||
processors, or some "legacy" PC interconnects; as opposed to large
|
||||
formally specified ones like PCI or USB.
|
||||
|
||||
|
||||
Platform devices
|
||||
~~~~~~~~~~~~~~~~
|
||||
Platform devices are devices that typically appear as autonomous
|
||||
entities in the system. This includes legacy port-based devices and
|
||||
host bridges to peripheral buses, and most controllers integrated
|
||||
into system-on-chip platforms. What they usually have in common
|
||||
is direct addressing from a CPU bus. Rarely, a platform_device will
|
||||
be connected through a segment of some other kind of bus; but its
|
||||
registers will still be directly addressable.
|
||||
|
||||
Platform devices are given a name, used in driver binding, and a
|
||||
list of resources such as addresses and IRQs::
|
||||
|
||||
struct platform_device {
|
||||
const char *name;
|
||||
u32 id;
|
||||
struct device dev;
|
||||
u32 num_resources;
|
||||
struct resource *resource;
|
||||
};
|
||||
|
||||
|
||||
Platform drivers
|
||||
~~~~~~~~~~~~~~~~
|
||||
Platform drivers follow the standard driver model convention, where
|
||||
discovery/enumeration is handled outside the drivers, and drivers
|
||||
provide probe() and remove() methods. They support power management
|
||||
and shutdown notifications using the standard conventions::
|
||||
|
||||
struct platform_driver {
|
||||
int (*probe)(struct platform_device *);
|
||||
int (*remove)(struct platform_device *);
|
||||
void (*shutdown)(struct platform_device *);
|
||||
int (*suspend)(struct platform_device *, pm_message_t state);
|
||||
int (*suspend_late)(struct platform_device *, pm_message_t state);
|
||||
int (*resume_early)(struct platform_device *);
|
||||
int (*resume)(struct platform_device *);
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
Note that probe() should in general verify that the specified device hardware
|
||||
actually exists; sometimes platform setup code can't be sure. The probing
|
||||
can use device resources, including clocks, and device platform_data.
|
||||
|
||||
Platform drivers register themselves the normal way::
|
||||
|
||||
int platform_driver_register(struct platform_driver *drv);
|
||||
|
||||
Or, in common situations where the device is known not to be hot-pluggable,
|
||||
the probe() routine can live in an init section to reduce the driver's
|
||||
runtime memory footprint::
|
||||
|
||||
int platform_driver_probe(struct platform_driver *drv,
|
||||
int (*probe)(struct platform_device *))
|
||||
|
||||
Kernel modules can be composed of several platform drivers. The platform core
|
||||
provides helpers to register and unregister an array of drivers::
|
||||
|
||||
int __platform_register_drivers(struct platform_driver * const *drivers,
|
||||
unsigned int count, struct module *owner);
|
||||
void platform_unregister_drivers(struct platform_driver * const *drivers,
|
||||
unsigned int count);
|
||||
|
||||
If one of the drivers fails to register, all drivers registered up to that
|
||||
point will be unregistered in reverse order. Note that there is a convenience
|
||||
macro that passes THIS_MODULE as owner parameter::
|
||||
|
||||
#define platform_register_drivers(drivers, count)
|
||||
|
||||
|
||||
Device Enumeration
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
As a rule, platform specific (and often board-specific) setup code will
|
||||
register platform devices::
|
||||
|
||||
int platform_device_register(struct platform_device *pdev);
|
||||
|
||||
int platform_add_devices(struct platform_device **pdevs, int ndev);
|
||||
|
||||
The general rule is to register only those devices that actually exist,
|
||||
but in some cases extra devices might be registered. For example, a kernel
|
||||
might be configured to work with an external network adapter that might not
|
||||
be populated on all boards, or likewise to work with an integrated controller
|
||||
that some boards might not hook up to any peripherals.
|
||||
|
||||
In some cases, boot firmware will export tables describing the devices
|
||||
that are populated on a given board. Without such tables, often the
|
||||
only way for system setup code to set up the correct devices is to build
|
||||
a kernel for a specific target board. Such board-specific kernels are
|
||||
common with embedded and custom systems development.
|
||||
|
||||
In many cases, the memory and IRQ resources associated with the platform
|
||||
device are not enough to let the device's driver work. Board setup code
|
||||
will often provide additional information using the device's platform_data
|
||||
field to hold additional information.
|
||||
|
||||
Embedded systems frequently need one or more clocks for platform devices,
|
||||
which are normally kept off until they're actively needed (to save power).
|
||||
System setup also associates those clocks with the device, so that that
|
||||
calls to clk_get(&pdev->dev, clock_name) return them as needed.
|
||||
|
||||
|
||||
Legacy Drivers: Device Probing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Some drivers are not fully converted to the driver model, because they take
|
||||
on a non-driver role: the driver registers its platform device, rather than
|
||||
leaving that for system infrastructure. Such drivers can't be hotplugged
|
||||
or coldplugged, since those mechanisms require device creation to be in a
|
||||
different system component than the driver.
|
||||
|
||||
The only "good" reason for this is to handle older system designs which, like
|
||||
original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware
|
||||
configuration. Newer systems have largely abandoned that model, in favor of
|
||||
bus-level support for dynamic configuration (PCI, USB), or device tables
|
||||
provided by the boot firmware (e.g. PNPACPI on x86). There are too many
|
||||
conflicting options about what might be where, and even educated guesses by
|
||||
an operating system will be wrong often enough to make trouble.
|
||||
|
||||
This style of driver is discouraged. If you're updating such a driver,
|
||||
please try to move the device enumeration to a more appropriate location,
|
||||
outside the driver. This will usually be cleanup, since such drivers
|
||||
tend to already have "normal" modes, such as ones using device nodes that
|
||||
were created by PNP or by platform device setup.
|
||||
|
||||
None the less, there are some APIs to support such legacy drivers. Avoid
|
||||
using these calls except with such hotplug-deficient drivers::
|
||||
|
||||
struct platform_device *platform_device_alloc(
|
||||
const char *name, int id);
|
||||
|
||||
You can use platform_device_alloc() to dynamically allocate a device, which
|
||||
you will then initialize with resources and platform_device_register().
|
||||
A better solution is usually::
|
||||
|
||||
struct platform_device *platform_device_register_simple(
|
||||
const char *name, int id,
|
||||
struct resource *res, unsigned int nres);
|
||||
|
||||
You can use platform_device_register_simple() as a one-step call to allocate
|
||||
and register a device.
|
||||
|
||||
|
||||
Device Naming and Driver Binding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The platform_device.dev.bus_id is the canonical name for the devices.
|
||||
It's built from two components:
|
||||
|
||||
* platform_device.name ... which is also used to for driver matching.
|
||||
|
||||
* platform_device.id ... the device instance number, or else "-1"
|
||||
to indicate there's only one.
|
||||
|
||||
These are concatenated, so name/id "serial"/0 indicates bus_id "serial.0", and
|
||||
"serial/3" indicates bus_id "serial.3"; both would use the platform_driver
|
||||
named "serial". While "my_rtc"/-1 would be bus_id "my_rtc" (no instance id)
|
||||
and use the platform_driver called "my_rtc".
|
||||
|
||||
Driver binding is performed automatically by the driver core, invoking
|
||||
driver probe() after finding a match between device and driver. If the
|
||||
probe() succeeds, the driver and device are bound as usual. There are
|
||||
three different ways to find such a match:
|
||||
|
||||
- Whenever a device is registered, the drivers for that bus are
|
||||
checked for matches. Platform devices should be registered very
|
||||
early during system boot.
|
||||
|
||||
- When a driver is registered using platform_driver_register(), all
|
||||
unbound devices on that bus are checked for matches. Drivers
|
||||
usually register later during booting, or by module loading.
|
||||
|
||||
- Registering a driver using platform_driver_probe() works just like
|
||||
using platform_driver_register(), except that the driver won't
|
||||
be probed later if another device registers. (Which is OK, since
|
||||
this interface is only for use with non-hotpluggable devices.)
|
||||
|
||||
|
||||
Early Platform Devices and Drivers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The early platform interfaces provide platform data to platform device
|
||||
drivers early on during the system boot. The code is built on top of the
|
||||
early_param() command line parsing and can be executed very early on.
|
||||
|
||||
Example: "earlyprintk" class early serial console in 6 steps
|
||||
|
||||
1. Registering early platform device data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The architecture code registers platform device data using the function
|
||||
early_platform_add_devices(). In the case of early serial console this
|
||||
should be hardware configuration for the serial port. Devices registered
|
||||
at this point will later on be matched against early platform drivers.
|
||||
|
||||
2. Parsing kernel command line
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The architecture code calls parse_early_param() to parse the kernel
|
||||
command line. This will execute all matching early_param() callbacks.
|
||||
User specified early platform devices will be registered at this point.
|
||||
For the early serial console case the user can specify port on the
|
||||
kernel command line as "earlyprintk=serial.0" where "earlyprintk" is
|
||||
the class string, "serial" is the name of the platform driver and
|
||||
0 is the platform device id. If the id is -1 then the dot and the
|
||||
id can be omitted.
|
||||
|
||||
3. Installing early platform drivers belonging to a certain class
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The architecture code may optionally force registration of all early
|
||||
platform drivers belonging to a certain class using the function
|
||||
early_platform_driver_register_all(). User specified devices from
|
||||
step 2 have priority over these. This step is omitted by the serial
|
||||
driver example since the early serial driver code should be disabled
|
||||
unless the user has specified port on the kernel command line.
|
||||
|
||||
4. Early platform driver registration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Compiled-in platform drivers making use of early_platform_init() are
|
||||
automatically registered during step 2 or 3. The serial driver example
|
||||
should use early_platform_init("earlyprintk", &platform_driver).
|
||||
|
||||
5. Probing of early platform drivers belonging to a certain class
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The architecture code calls early_platform_driver_probe() to match
|
||||
registered early platform devices associated with a certain class with
|
||||
registered early platform drivers. Matched devices will get probed().
|
||||
This step can be executed at any point during the early boot. As soon
|
||||
as possible may be good for the serial port case.
|
||||
|
||||
6. Inside the early platform driver probe()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The driver code needs to take special care during early boot, especially
|
||||
when it comes to memory allocation and interrupt registration. The code
|
||||
in the probe() function can use is_early_platform_device() to check if
|
||||
it is called at early platform device or at the regular platform device
|
||||
time. The early serial driver performs register_console() at this point.
|
||||
|
||||
For further information, see <linux/platform_device.h>.
|
448
Documentation/driver-api/driver-model/porting.rst
Normal file
448
Documentation/driver-api/driver-model/porting.rst
Normal file
@@ -0,0 +1,448 @@
|
||||
=======================================
|
||||
Porting Drivers to the New Driver Model
|
||||
=======================================
|
||||
|
||||
Patrick Mochel
|
||||
|
||||
7 January 2003
|
||||
|
||||
|
||||
Overview
|
||||
|
||||
Please refer to `Documentation/driver-api/driver-model/*.rst` for definitions of
|
||||
various driver types and concepts.
|
||||
|
||||
Most of the work of porting devices drivers to the new model happens
|
||||
at the bus driver layer. This was intentional, to minimize the
|
||||
negative effect on kernel drivers, and to allow a gradual transition
|
||||
of bus drivers.
|
||||
|
||||
In a nutshell, the driver model consists of a set of objects that can
|
||||
be embedded in larger, bus-specific objects. Fields in these generic
|
||||
objects can replace fields in the bus-specific objects.
|
||||
|
||||
The generic objects must be registered with the driver model core. By
|
||||
doing so, they will exported via the sysfs filesystem. sysfs can be
|
||||
mounted by doing::
|
||||
|
||||
# mount -t sysfs sysfs /sys
|
||||
|
||||
|
||||
|
||||
The Process
|
||||
|
||||
Step 0: Read include/linux/device.h for object and function definitions.
|
||||
|
||||
Step 1: Registering the bus driver.
|
||||
|
||||
|
||||
- Define a struct bus_type for the bus driver::
|
||||
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
};
|
||||
|
||||
|
||||
- Register the bus type.
|
||||
|
||||
This should be done in the initialization function for the bus type,
|
||||
which is usually the module_init(), or equivalent, function::
|
||||
|
||||
static int __init pci_driver_init(void)
|
||||
{
|
||||
return bus_register(&pci_bus_type);
|
||||
}
|
||||
|
||||
subsys_initcall(pci_driver_init);
|
||||
|
||||
|
||||
The bus type may be unregistered (if the bus driver may be compiled
|
||||
as a module) by doing::
|
||||
|
||||
bus_unregister(&pci_bus_type);
|
||||
|
||||
|
||||
- Export the bus type for others to use.
|
||||
|
||||
Other code may wish to reference the bus type, so declare it in a
|
||||
shared header file and export the symbol.
|
||||
|
||||
From include/linux/pci.h::
|
||||
|
||||
extern struct bus_type pci_bus_type;
|
||||
|
||||
|
||||
From file the above code appears in::
|
||||
|
||||
EXPORT_SYMBOL(pci_bus_type);
|
||||
|
||||
|
||||
|
||||
- This will cause the bus to show up in /sys/bus/pci/ with two
|
||||
subdirectories: 'devices' and 'drivers'::
|
||||
|
||||
# tree -d /sys/bus/pci/
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
|
||||
|
||||
|
||||
Step 2: Registering Devices.
|
||||
|
||||
struct device represents a single device. It mainly contains metadata
|
||||
describing the relationship the device has to other entities.
|
||||
|
||||
|
||||
- Embed a struct device in the bus-specific device type::
|
||||
|
||||
|
||||
struct pci_dev {
|
||||
...
|
||||
struct device dev; /* Generic device interface */
|
||||
...
|
||||
};
|
||||
|
||||
It is recommended that the generic device not be the first item in
|
||||
the struct to discourage programmers from doing mindless casts
|
||||
between the object types. Instead macros, or inline functions,
|
||||
should be created to convert from the generic object type::
|
||||
|
||||
|
||||
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
|
||||
|
||||
or
|
||||
|
||||
static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
|
||||
{
|
||||
return container_of(n, struct pci_dev, dev);
|
||||
}
|
||||
|
||||
This allows the compiler to verify type-safety of the operations
|
||||
that are performed (which is Good).
|
||||
|
||||
|
||||
- Initialize the device on registration.
|
||||
|
||||
When devices are discovered or registered with the bus type, the
|
||||
bus driver should initialize the generic device. The most important
|
||||
things to initialize are the bus_id, parent, and bus fields.
|
||||
|
||||
The bus_id is an ASCII string that contains the device's address on
|
||||
the bus. The format of this string is bus-specific. This is
|
||||
necessary for representing devices in sysfs.
|
||||
|
||||
parent is the physical parent of the device. It is important that
|
||||
the bus driver sets this field correctly.
|
||||
|
||||
The driver model maintains an ordered list of devices that it uses
|
||||
for power management. This list must be in order to guarantee that
|
||||
devices are shutdown before their physical parents, and vice versa.
|
||||
The order of this list is determined by the parent of registered
|
||||
devices.
|
||||
|
||||
Also, the location of the device's sysfs directory depends on a
|
||||
device's parent. sysfs exports a directory structure that mirrors
|
||||
the device hierarchy. Accurately setting the parent guarantees that
|
||||
sysfs will accurately represent the hierarchy.
|
||||
|
||||
The device's bus field is a pointer to the bus type the device
|
||||
belongs to. This should be set to the bus_type that was declared
|
||||
and initialized before.
|
||||
|
||||
Optionally, the bus driver may set the device's name and release
|
||||
fields.
|
||||
|
||||
The name field is an ASCII string describing the device, like
|
||||
|
||||
"ATI Technologies Inc Radeon QD"
|
||||
|
||||
The release field is a callback that the driver model core calls
|
||||
when the device has been removed, and all references to it have
|
||||
been released. More on this in a moment.
|
||||
|
||||
|
||||
- Register the device.
|
||||
|
||||
Once the generic device has been initialized, it can be registered
|
||||
with the driver model core by doing::
|
||||
|
||||
device_register(&dev->dev);
|
||||
|
||||
It can later be unregistered by doing::
|
||||
|
||||
device_unregister(&dev->dev);
|
||||
|
||||
This should happen on buses that support hotpluggable devices.
|
||||
If a bus driver unregisters a device, it should not immediately free
|
||||
it. It should instead wait for the driver model core to call the
|
||||
device's release method, then free the bus-specific object.
|
||||
(There may be other code that is currently referencing the device
|
||||
structure, and it would be rude to free the device while that is
|
||||
happening).
|
||||
|
||||
|
||||
When the device is registered, a directory in sysfs is created.
|
||||
The PCI tree in sysfs looks like::
|
||||
|
||||
/sys/devices/pci0/
|
||||
|-- 00:00.0
|
||||
|-- 00:01.0
|
||||
| `-- 01:00.0
|
||||
|-- 00:02.0
|
||||
| `-- 02:1f.0
|
||||
| `-- 03:00.0
|
||||
|-- 00:1e.0
|
||||
| `-- 04:04.0
|
||||
|-- 00:1f.0
|
||||
|-- 00:1f.1
|
||||
| |-- ide0
|
||||
| | |-- 0.0
|
||||
| | `-- 0.1
|
||||
| `-- ide1
|
||||
| `-- 1.0
|
||||
|-- 00:1f.2
|
||||
|-- 00:1f.3
|
||||
`-- 00:1f.5
|
||||
|
||||
Also, symlinks are created in the bus's 'devices' directory
|
||||
that point to the device's directory in the physical hierarchy::
|
||||
|
||||
/sys/bus/pci/devices/
|
||||
|-- 00:00.0 -> ../../../devices/pci0/00:00.0
|
||||
|-- 00:01.0 -> ../../../devices/pci0/00:01.0
|
||||
|-- 00:02.0 -> ../../../devices/pci0/00:02.0
|
||||
|-- 00:1e.0 -> ../../../devices/pci0/00:1e.0
|
||||
|-- 00:1f.0 -> ../../../devices/pci0/00:1f.0
|
||||
|-- 00:1f.1 -> ../../../devices/pci0/00:1f.1
|
||||
|-- 00:1f.2 -> ../../../devices/pci0/00:1f.2
|
||||
|-- 00:1f.3 -> ../../../devices/pci0/00:1f.3
|
||||
|-- 00:1f.5 -> ../../../devices/pci0/00:1f.5
|
||||
|-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0
|
||||
|-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0
|
||||
|-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0
|
||||
`-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0
|
||||
|
||||
|
||||
|
||||
Step 3: Registering Drivers.
|
||||
|
||||
struct device_driver is a simple driver structure that contains a set
|
||||
of operations that the driver model core may call.
|
||||
|
||||
|
||||
- Embed a struct device_driver in the bus-specific driver.
|
||||
|
||||
Just like with devices, do something like::
|
||||
|
||||
struct pci_driver {
|
||||
...
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
|
||||
- Initialize the generic driver structure.
|
||||
|
||||
When the driver registers with the bus (e.g. doing pci_register_driver()),
|
||||
initialize the necessary fields of the driver: the name and bus
|
||||
fields.
|
||||
|
||||
|
||||
- Register the driver.
|
||||
|
||||
After the generic driver has been initialized, call::
|
||||
|
||||
driver_register(&drv->driver);
|
||||
|
||||
to register the driver with the core.
|
||||
|
||||
When the driver is unregistered from the bus, unregister it from the
|
||||
core by doing::
|
||||
|
||||
driver_unregister(&drv->driver);
|
||||
|
||||
Note that this will block until all references to the driver have
|
||||
gone away. Normally, there will not be any.
|
||||
|
||||
|
||||
- Sysfs representation.
|
||||
|
||||
Drivers are exported via sysfs in their bus's 'driver's directory.
|
||||
For example::
|
||||
|
||||
/sys/bus/pci/drivers/
|
||||
|-- 3c59x
|
||||
|-- Ensoniq AudioPCI
|
||||
|-- agpgart-amdk7
|
||||
|-- e100
|
||||
`-- serial
|
||||
|
||||
|
||||
Step 4: Define Generic Methods for Drivers.
|
||||
|
||||
struct device_driver defines a set of operations that the driver model
|
||||
core calls. Most of these operations are probably similar to
|
||||
operations the bus already defines for drivers, but taking different
|
||||
parameters.
|
||||
|
||||
It would be difficult and tedious to force every driver on a bus to
|
||||
simultaneously convert their drivers to generic format. Instead, the
|
||||
bus driver should define single instances of the generic methods that
|
||||
forward call to the bus-specific drivers. For instance::
|
||||
|
||||
|
||||
static int pci_device_remove(struct device * dev)
|
||||
{
|
||||
struct pci_dev * pci_dev = to_pci_dev(dev);
|
||||
struct pci_driver * drv = pci_dev->driver;
|
||||
|
||||
if (drv) {
|
||||
if (drv->remove)
|
||||
drv->remove(pci_dev);
|
||||
pci_dev->driver = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
The generic driver should be initialized with these methods before it
|
||||
is registered::
|
||||
|
||||
/* initialize common driver fields */
|
||||
drv->driver.name = drv->name;
|
||||
drv->driver.bus = &pci_bus_type;
|
||||
drv->driver.probe = pci_device_probe;
|
||||
drv->driver.resume = pci_device_resume;
|
||||
drv->driver.suspend = pci_device_suspend;
|
||||
drv->driver.remove = pci_device_remove;
|
||||
|
||||
/* register with core */
|
||||
driver_register(&drv->driver);
|
||||
|
||||
|
||||
Ideally, the bus should only initialize the fields if they are not
|
||||
already set. This allows the drivers to implement their own generic
|
||||
methods.
|
||||
|
||||
|
||||
Step 5: Support generic driver binding.
|
||||
|
||||
The model assumes that a device or driver can be dynamically
|
||||
registered with the bus at any time. When registration happens,
|
||||
devices must be bound to a driver, or drivers must be bound to all
|
||||
devices that it supports.
|
||||
|
||||
A driver typically contains a list of device IDs that it supports. The
|
||||
bus driver compares these IDs to the IDs of devices registered with it.
|
||||
The format of the device IDs, and the semantics for comparing them are
|
||||
bus-specific, so the generic model does attempt to generalize them.
|
||||
|
||||
Instead, a bus may supply a method in struct bus_type that does the
|
||||
comparison::
|
||||
|
||||
int (*match)(struct device * dev, struct device_driver * drv);
|
||||
|
||||
match should return positive value if the driver supports the device,
|
||||
and zero otherwise. It may also return error code (for example
|
||||
-EPROBE_DEFER) if determining that given driver supports the device is
|
||||
not possible.
|
||||
|
||||
When a device is registered, the bus's list of drivers is iterated
|
||||
over. bus->match() is called for each one until a match is found.
|
||||
|
||||
When a driver is registered, the bus's list of devices is iterated
|
||||
over. bus->match() is called for each device that is not already
|
||||
claimed by a driver.
|
||||
|
||||
When a device is successfully bound to a driver, device->driver is
|
||||
set, the device is added to a per-driver list of devices, and a
|
||||
symlink is created in the driver's sysfs directory that points to the
|
||||
device's physical directory::
|
||||
|
||||
/sys/bus/pci/drivers/
|
||||
|-- 3c59x
|
||||
| `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0
|
||||
|-- Ensoniq AudioPCI
|
||||
|-- agpgart-amdk7
|
||||
| `-- 00:00.0 -> ../../../../devices/pci0/00:00.0
|
||||
|-- e100
|
||||
| `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0
|
||||
`-- serial
|
||||
|
||||
|
||||
This driver binding should replace the existing driver binding
|
||||
mechanism the bus currently uses.
|
||||
|
||||
|
||||
Step 6: Supply a hotplug callback.
|
||||
|
||||
Whenever a device is registered with the driver model core, the
|
||||
userspace program /sbin/hotplug is called to notify userspace.
|
||||
Users can define actions to perform when a device is inserted or
|
||||
removed.
|
||||
|
||||
The driver model core passes several arguments to userspace via
|
||||
environment variables, including
|
||||
|
||||
- ACTION: set to 'add' or 'remove'
|
||||
- DEVPATH: set to the device's physical path in sysfs.
|
||||
|
||||
A bus driver may also supply additional parameters for userspace to
|
||||
consume. To do this, a bus must implement the 'hotplug' method in
|
||||
struct bus_type::
|
||||
|
||||
int (*hotplug) (struct device *dev, char **envp,
|
||||
int num_envp, char *buffer, int buffer_size);
|
||||
|
||||
This is called immediately before /sbin/hotplug is executed.
|
||||
|
||||
|
||||
Step 7: Cleaning up the bus driver.
|
||||
|
||||
The generic bus, device, and driver structures provide several fields
|
||||
that can replace those defined privately to the bus driver.
|
||||
|
||||
- Device list.
|
||||
|
||||
struct bus_type contains a list of all devices registered with the bus
|
||||
type. This includes all devices on all instances of that bus type.
|
||||
An internal list that the bus uses may be removed, in favor of using
|
||||
this one.
|
||||
|
||||
The core provides an iterator to access these devices::
|
||||
|
||||
int bus_for_each_dev(struct bus_type * bus, struct device * start,
|
||||
void * data, int (*fn)(struct device *, void *));
|
||||
|
||||
|
||||
- Driver list.
|
||||
|
||||
struct bus_type also contains a list of all drivers registered with
|
||||
it. An internal list of drivers that the bus driver maintains may
|
||||
be removed in favor of using the generic one.
|
||||
|
||||
The drivers may be iterated over, like devices::
|
||||
|
||||
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
|
||||
void * data, int (*fn)(struct device_driver *, void *));
|
||||
|
||||
|
||||
Please see drivers/base/bus.c for more information.
|
||||
|
||||
|
||||
- rwsem
|
||||
|
||||
struct bus_type contains an rwsem that protects all core accesses to
|
||||
the device and driver lists. This can be used by the bus driver
|
||||
internally, and should be used when accessing the device or driver
|
||||
lists the bus maintains.
|
||||
|
||||
|
||||
- Device and driver fields.
|
||||
|
||||
Some of the fields in struct device and struct device_driver duplicate
|
||||
fields in the bus-specific representations of these objects. Feel free
|
||||
to remove the bus-specific ones and favor the generic ones. Note
|
||||
though, that this will likely mean fixing up all the drivers that
|
||||
reference the bus-specific fields (though those should all be 1-line
|
||||
changes).
|
@@ -399,7 +399,7 @@ symbol:
|
||||
will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
|
||||
callbacks need to embed the gpio_chip in its state container and obtain a
|
||||
pointer to the container using container_of().
|
||||
(See Documentation/driver-model/design-patterns.rst)
|
||||
(See Documentation/driver-api/driver-model/design-patterns.rst)
|
||||
|
||||
- gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
|
||||
as discussed above regarding different types of cascaded irqchips. The
|
||||
|
@@ -14,6 +14,7 @@ available subsections can be seen below.
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
driver-model/index
|
||||
basics
|
||||
infrastructure
|
||||
early-userspace/index
|
||||
|
Reference in New Issue
Block a user