mirror of
https://github.com/torvalds/linux
synced 2024-09-20 02:57:25 +00:00
docs: driver-model: convert docs to ReST and rename to *.rst
Convert the various documents at the driver-model, preparing them to be part of the driver-api book. The conversion is actually: - add blank lines and identation in order to identify paragraphs; - fix tables markups; - add some lists markups; - mark literal blocks; - adjust title markups. At its new index.rst, let's add a :orphan: while this is not linked to the main index.rst file, in order to avoid build warnings. Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> Acked-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> # ice Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
58cb346c71
commit
4489f161b7
|
@ -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.txt)
|
||||
(See Documentation/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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
==============
|
||||
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
|
||||
|
@ -95,4 +96,3 @@ 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.
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
=========
|
||||
Bus Types
|
||||
=========
|
||||
|
||||
Definition
|
||||
~~~~~~~~~~
|
||||
|
@ -13,12 +14,12 @@ 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.
|
||||
optionally initialize the match callback::
|
||||
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
.match = pci_bus_match,
|
||||
};
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
.match = pci_bus_match,
|
||||
};
|
||||
|
||||
The structure should be exported to drivers in a header file:
|
||||
|
||||
|
@ -66,13 +67,14 @@ 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.
|
||||
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_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 *));
|
||||
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
|
||||
|
@ -87,14 +89,14 @@ sysfs
|
|||
There is a top-level directory named 'bus'.
|
||||
|
||||
Each bus gets a directory in the bus directory, along with two default
|
||||
directories:
|
||||
directories::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
|
||||
Drivers registered with the bus get a directory in the bus's drivers
|
||||
directory:
|
||||
directory::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
|
@ -106,7 +108,7 @@ directory:
|
|||
|
||||
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:
|
||||
hierarchy::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
|
@ -118,26 +120,27 @@ hierarchy:
|
|||
|
||||
Exporting Attributes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
struct bus_attribute {
|
||||
|
||||
::
|
||||
|
||||
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:
|
||||
definition like this::
|
||||
|
||||
static BUS_ATTR_RW(debug);
|
||||
static BUS_ATTR_RW(debug);
|
||||
|
||||
is equivalent to declaring:
|
||||
is equivalent to declaring::
|
||||
|
||||
static bus_attribute bus_attr_debug;
|
||||
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 *);
|
||||
|
||||
sysfs directory using::
|
||||
|
||||
int bus_create_file(struct bus_type *, struct bus_attribute *);
|
||||
void bus_remove_file(struct bus_type *, struct bus_attribute *);
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
==============
|
||||
Device Classes
|
||||
|
||||
==============
|
||||
|
||||
Introduction
|
||||
~~~~~~~~~~~~
|
||||
|
@ -21,29 +21,29 @@ on.
|
|||
|
||||
Programming Interface
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The device class structure looks like:
|
||||
The device class structure looks like::
|
||||
|
||||
|
||||
typedef int (*devclass_add)(struct device *);
|
||||
typedef void (*devclass_remove)(struct device *);
|
||||
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:
|
||||
A typical device class definition would look like::
|
||||
|
||||
struct device_class input_devclass = {
|
||||
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:
|
||||
Device classes are registered and unregistered with the core using::
|
||||
|
||||
int devclass_register(struct device_class * cls);
|
||||
void devclass_unregister(struct device_class * cls);
|
||||
int devclass_register(struct device_class * cls);
|
||||
void devclass_unregister(struct device_class * cls);
|
||||
|
||||
|
||||
Devices
|
||||
|
@ -81,7 +81,7 @@ 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:
|
||||
default subdirectories::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
|
@ -90,7 +90,7 @@ default subdirectories:
|
|||
|
||||
|
||||
Drivers registered with the class get a symlink in the drivers/ directory
|
||||
that points to the driver's directory (under its bus directory):
|
||||
that points to the driver's directory (under its bus directory)::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
|
@ -100,7 +100,7 @@ that points to the driver's directory (under its bus directory):
|
|||
|
||||
|
||||
Each device gets a symlink in the devices/ directory that points to the
|
||||
device's directory in the physical hierarchy:
|
||||
device's directory in the physical hierarchy::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
|
@ -111,27 +111,30 @@ device's directory in the physical hierarchy:
|
|||
|
||||
Exporting Attributes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
struct devclass_attribute {
|
||||
|
||||
::
|
||||
|
||||
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:
|
||||
like this::
|
||||
|
||||
static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);
|
||||
static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);
|
||||
|
||||
is equivalent to declaring:
|
||||
is equivalent to declaring::
|
||||
|
||||
static devclass_attribute devclass_attr_debug;
|
||||
static devclass_attribute devclass_attr_debug;
|
||||
|
||||
The bus driver can add and remove the attribute from the class's
|
||||
sysfs directory using:
|
||||
sysfs directory using::
|
||||
|
||||
int devclass_create_file(struct device_class *, struct devclass_attribute *);
|
||||
void devclass_remove_file(struct device_class *, struct devclass_attribute *);
|
||||
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.
|
||||
|
@ -144,4 +147,3 @@ 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.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
=============================
|
||||
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
|
||||
|
@ -19,23 +19,23 @@ 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:
|
||||
pattern. It usually has this form::
|
||||
|
||||
struct foo {
|
||||
spinlock_t lock; /* Example member */
|
||||
(...)
|
||||
};
|
||||
struct foo {
|
||||
spinlock_t lock; /* Example member */
|
||||
(...)
|
||||
};
|
||||
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
|
||||
foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL);
|
||||
if (!foo)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&foo->lock);
|
||||
(...)
|
||||
}
|
||||
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.
|
||||
|
@ -43,21 +43,21 @@ 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:
|
||||
pass around a pointer to struct foo like this::
|
||||
|
||||
static irqreturn_t foo_handler(int irq, void *arg)
|
||||
{
|
||||
struct foo *foo = arg;
|
||||
(...)
|
||||
}
|
||||
static irqreturn_t foo_handler(int irq, void *arg)
|
||||
{
|
||||
struct foo *foo = arg;
|
||||
(...)
|
||||
}
|
||||
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
|
||||
(...)
|
||||
ret = request_irq(irq, foo_handler, 0, "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.
|
||||
|
@ -66,38 +66,38 @@ your interrupt handler.
|
|||
2. container_of()
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Continuing on the above example we add an offloaded work:
|
||||
Continuing on the above example we add an offloaded work::
|
||||
|
||||
struct foo {
|
||||
spinlock_t lock;
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct offload;
|
||||
(...)
|
||||
};
|
||||
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 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;
|
||||
static irqreturn_t foo_handler(int irq, void *arg)
|
||||
{
|
||||
struct foo *foo = arg;
|
||||
|
||||
queue_work(foo->wq, &foo->offload);
|
||||
(...)
|
||||
}
|
||||
queue_work(foo->wq, &foo->offload);
|
||||
(...)
|
||||
}
|
||||
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
|
||||
foo->wq = create_singlethread_workqueue("foo-wq");
|
||||
INIT_WORK(&foo->offload, foo_work);
|
||||
(...)
|
||||
}
|
||||
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
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
==========================
|
||||
The Basic Device Structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
==========================
|
||||
|
||||
See the kerneldoc for the struct device.
|
||||
|
||||
|
@ -8,9 +8,9 @@ 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:
|
||||
device with the core::
|
||||
|
||||
int device_register(struct device * dev);
|
||||
int device_register(struct device * dev);
|
||||
|
||||
The bus should initialize the following fields:
|
||||
|
||||
|
@ -20,30 +20,33 @@ The bus should initialize the following fields:
|
|||
- bus
|
||||
|
||||
A device is removed from the core when its reference count goes to
|
||||
0. The reference count can be adjusted using:
|
||||
0. The reference count can be adjusted using::
|
||||
|
||||
struct device * get_device(struct device * dev);
|
||||
void put_device(struct device * dev);
|
||||
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:
|
||||
A driver can access the lock in the device structure using::
|
||||
|
||||
void lock_device(struct device * dev);
|
||||
void unlock_device(struct device * dev);
|
||||
void lock_device(struct device * dev);
|
||||
void unlock_device(struct device * dev);
|
||||
|
||||
|
||||
Attributes
|
||||
~~~~~~~~~~
|
||||
struct device_attribute {
|
||||
|
||||
::
|
||||
|
||||
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.
|
||||
|
||||
|
@ -54,39 +57,39 @@ 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:
|
||||
Attributes are declared using a macro called DEVICE_ATTR::
|
||||
|
||||
#define DEVICE_ATTR(name,mode,show,store)
|
||||
#define DEVICE_ATTR(name,mode,show,store)
|
||||
|
||||
Example:
|
||||
Example:::
|
||||
|
||||
static DEVICE_ATTR(type, 0444, show_type, NULL);
|
||||
static DEVICE_ATTR(power, 0644, show_power, store_power);
|
||||
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:
|
||||
organized as follows into a group::
|
||||
|
||||
static struct attribute *dev_attrs[] = {
|
||||
static struct attribute *dev_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_power.attr,
|
||||
NULL,
|
||||
};
|
||||
};
|
||||
|
||||
static struct attribute_group dev_attr_group = {
|
||||
static struct attribute_group dev_attr_group = {
|
||||
.attrs = dev_attrs,
|
||||
};
|
||||
};
|
||||
|
||||
static const struct attribute_group *dev_attr_groups[] = {
|
||||
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:
|
||||
group pointer in struct device before device_register() is invoked::
|
||||
|
||||
dev->groups = dev_attr_groups;
|
||||
device_register(dev);
|
||||
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
|
|
@ -1,3 +1,4 @@
|
|||
================================
|
||||
Devres - Managed Device Resource
|
||||
================================
|
||||
|
||||
|
@ -5,17 +6,18 @@ 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 : 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
|
||||
--------
|
||||
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
|
||||
|
@ -42,8 +44,8 @@ would leak resources or even cause oops when failure occurs. iomap
|
|||
adds more to this mix. So do msi and msix.
|
||||
|
||||
|
||||
2. Devres
|
||||
---------
|
||||
2. Devres
|
||||
---------
|
||||
|
||||
devres is basically linked list of arbitrarily sized memory areas
|
||||
associated with a struct device. Each devres entry is associated with
|
||||
|
@ -58,7 +60,7 @@ 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.
|
||||
the following::
|
||||
|
||||
struct dma_devres {
|
||||
size_t size;
|
||||
|
@ -98,7 +100,7 @@ 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.
|
||||
looks like the following::
|
||||
|
||||
my_init_one()
|
||||
{
|
||||
|
@ -119,7 +121,7 @@ looks like the following.
|
|||
return register_to_upper_layer(d);
|
||||
}
|
||||
|
||||
And exit path,
|
||||
And exit path::
|
||||
|
||||
my_remove_one()
|
||||
{
|
||||
|
@ -140,13 +142,13 @@ on you. In some cases this may mean introducing checks that were not
|
|||
necessary before moving to the managed devm_* calls.
|
||||
|
||||
|
||||
3. Devres group
|
||||
---------------
|
||||
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,
|
||||
resources on failure. For example::
|
||||
|
||||
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
@ -172,7 +174,7 @@ 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
|
||||
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
|
||||
|
@ -180,7 +182,7 @@ 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.
|
||||
For example, you can do something like the following::
|
||||
|
||||
int my_midlayer_create_something()
|
||||
{
|
||||
|
@ -199,8 +201,8 @@ For example, you can do something like the following.
|
|||
}
|
||||
|
||||
|
||||
4. Details
|
||||
----------
|
||||
4. Details
|
||||
----------
|
||||
|
||||
Lifetime of a devres entry begins on devres allocation and finishes
|
||||
when it is released or destroyed (removed and freed) - no reference
|
||||
|
@ -220,8 +222,8 @@ All devres interface functions can be called without context if the
|
|||
right gfp mask is given.
|
||||
|
||||
|
||||
5. Overhead
|
||||
-----------
|
||||
5. Overhead
|
||||
-----------
|
||||
|
||||
Each devres bookkeeping info is allocated together with requested data
|
||||
area. With debug option turned off, bookkeeping info occupies 16
|
||||
|
@ -237,8 +239,8 @@ 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
|
||||
-----------------------------
|
||||
6. List of managed interfaces
|
||||
-----------------------------
|
||||
|
||||
CLOCK
|
||||
devm_clk_get()
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
==============
|
||||
Device Drivers
|
||||
==============
|
||||
|
||||
See the kerneldoc for the struct device_driver.
|
||||
|
||||
|
@ -26,17 +27,17 @@ 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.
|
||||
being converted completely to the new model::
|
||||
|
||||
static struct device_driver eepro100_driver = {
|
||||
.name = "eepro100",
|
||||
.bus = &pci_bus_type,
|
||||
static struct device_driver eepro100_driver = {
|
||||
.name = "eepro100",
|
||||
.bus = &pci_bus_type,
|
||||
|
||||
.probe = eepro100_probe,
|
||||
.remove = eepro100_remove,
|
||||
.suspend = eepro100_suspend,
|
||||
.resume = eepro100_resume,
|
||||
};
|
||||
.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
|
||||
|
@ -49,27 +50,27 @@ 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:
|
||||
the definition of the bus-specific driver. Like this::
|
||||
|
||||
struct pci_driver {
|
||||
const struct pci_device_id *id_table;
|
||||
struct device_driver driver;
|
||||
};
|
||||
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):
|
||||
(using the eepro100 driver again)::
|
||||
|
||||
static struct pci_driver eepro100_driver = {
|
||||
.id_table = eepro100_pci_tbl,
|
||||
.driver = {
|
||||
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...
|
||||
|
@ -77,7 +78,9 @@ 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);
|
||||
::
|
||||
|
||||
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
|
||||
|
@ -113,10 +116,10 @@ Access
|
|||
~~~~~~
|
||||
|
||||
Once the object has been registered, it may access the common fields of
|
||||
the object, like the lock and the list of devices.
|
||||
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));
|
||||
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
|
||||
|
@ -142,7 +145,9 @@ supports.
|
|||
Callbacks
|
||||
~~~~~~~~~
|
||||
|
||||
int (*probe) (struct device * dev);
|
||||
::
|
||||
|
||||
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
|
||||
|
@ -162,9 +167,9 @@ 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.
|
||||
released all resources it allocated::
|
||||
|
||||
int (*remove) (struct device * dev);
|
||||
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
|
||||
|
@ -176,40 +181,43 @@ 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.
|
||||
it into a supported low-power state::
|
||||
|
||||
int (*suspend) (struct device * dev, pm_message_t state);
|
||||
int (*suspend) (struct device *dev, pm_message_t state);
|
||||
|
||||
suspend is called to put the device in a low power state.
|
||||
suspend is called to put the device in a low power state::
|
||||
|
||||
int (*resume) (struct device * dev);
|
||||
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);
|
||||
};
|
||||
|
||||
::
|
||||
|
||||
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:
|
||||
Example::
|
||||
|
||||
DRIVER_ATTR_RW(debug);
|
||||
DRIVER_ATTR_RW(debug);
|
||||
|
||||
This is equivalent to declaring:
|
||||
This is equivalent to declaring::
|
||||
|
||||
struct driver_attribute driver_attr_debug;
|
||||
struct driver_attribute driver_attr_debug;
|
||||
|
||||
This can then be used to add and remove the attribute from the
|
||||
driver's directory using:
|
||||
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 *);
|
||||
int driver_create_file(struct device_driver *, const struct driver_attribute *);
|
||||
void driver_remove_file(struct device_driver *, const struct driver_attribute *);
|
26
Documentation/driver-model/index.rst
Normal file
26
Documentation/driver-model/index.rst
Normal file
|
@ -0,0 +1,26 @@
|
|||
:orphan:
|
||||
|
||||
============
|
||||
Driver Model
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
binding
|
||||
bus
|
||||
class
|
||||
design-patterns
|
||||
device
|
||||
devres
|
||||
driver
|
||||
overview
|
||||
platform
|
||||
porting
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
|
@ -1,4 +1,6 @@
|
|||
=============================
|
||||
The Linux Kernel Device Model
|
||||
=============================
|
||||
|
||||
Patrick Mochel <mochel@digitalimplant.org>
|
||||
|
||||
|
@ -41,14 +43,14 @@ 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 now looks like this::
|
||||
|
||||
struct pci_dev {
|
||||
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.
|
||||
|
@ -80,26 +82,26 @@ 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:
|
||||
can see some variation of the following in the output of the "mount" command::
|
||||
|
||||
$ mount
|
||||
...
|
||||
none on /sys type sysfs (rw,noexec,nosuid,nodev)
|
||||
...
|
||||
$
|
||||
$ 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:
|
||||
the following in the /etc/fstab file::
|
||||
|
||||
none /sys sysfs defaults 0 0
|
||||
none /sys sysfs defaults 0 0
|
||||
|
||||
or something similar in the /lib/init/fstab file on Debian-based systems:
|
||||
or something similar in the /lib/init/fstab file on Debian-based systems::
|
||||
|
||||
none /sys sysfs nodev,noexec,nosuid 0 0
|
||||
none /sys sysfs nodev,noexec,nosuid 0 0
|
||||
|
||||
If sysfs is not automatically mounted, you can always do it manually with:
|
||||
If sysfs is not automatically mounted, you can always do it manually with::
|
||||
|
||||
# mount -t sysfs sysfs /sys
|
||||
# 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,
|
||||
|
@ -120,4 +122,3 @@ 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.
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
============================
|
||||
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,
|
||||
|
@ -19,15 +21,15 @@ 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.
|
||||
list of resources such as addresses and IRQs::
|
||||
|
||||
struct platform_device {
|
||||
struct platform_device {
|
||||
const char *name;
|
||||
u32 id;
|
||||
struct device dev;
|
||||
u32 num_resources;
|
||||
struct resource *resource;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Platform drivers
|
||||
|
@ -35,9 +37,9 @@ 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.
|
||||
and shutdown notifications using the standard conventions::
|
||||
|
||||
struct platform_driver {
|
||||
struct platform_driver {
|
||||
int (*probe)(struct platform_device *);
|
||||
int (*remove)(struct platform_device *);
|
||||
void (*shutdown)(struct platform_device *);
|
||||
|
@ -46,25 +48,25 @@ struct platform_driver {
|
|||
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:
|
||||
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:
|
||||
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:
|
||||
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);
|
||||
|
@ -73,7 +75,7 @@ provides helpers to register and unregister an array of drivers:
|
|||
|
||||
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:
|
||||
macro that passes THIS_MODULE as owner parameter::
|
||||
|
||||
#define platform_register_drivers(drivers, count)
|
||||
|
||||
|
@ -81,7 +83,7 @@ macro that passes THIS_MODULE as owner parameter:
|
|||
Device Enumeration
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
As a rule, platform specific (and often board-specific) setup code will
|
||||
register platform devices:
|
||||
register platform devices::
|
||||
|
||||
int platform_device_register(struct platform_device *pdev);
|
||||
|
||||
|
@ -133,14 +135,14 @@ 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.
|
||||
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:
|
||||
A better solution is usually::
|
||||
|
||||
struct platform_device *platform_device_register_simple(
|
||||
const char *name, int id,
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
=======================================
|
||||
Porting Drivers to the New Driver Model
|
||||
=======================================
|
||||
|
||||
Patrick Mochel
|
||||
|
||||
|
@ -8,7 +9,7 @@ Patrick Mochel
|
|||
|
||||
Overview
|
||||
|
||||
Please refer to Documentation/driver-model/*.txt for definitions of
|
||||
Please refer to `Documentation/driver-model/*.rst` for definitions of
|
||||
various driver types and concepts.
|
||||
|
||||
Most of the work of porting devices drivers to the new model happens
|
||||
|
@ -22,7 +23,7 @@ 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
|
||||
mounted by doing::
|
||||
|
||||
# mount -t sysfs sysfs /sys
|
||||
|
||||
|
@ -35,27 +36,28 @@ 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.
|
||||
- Define a struct bus_type for the bus driver::
|
||||
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
};
|
||||
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.
|
||||
which is usually the module_init(), or equivalent, function::
|
||||
|
||||
static int __init pci_driver_init(void)
|
||||
{
|
||||
return bus_register(&pci_bus_type);
|
||||
}
|
||||
static int __init pci_driver_init(void)
|
||||
{
|
||||
return bus_register(&pci_bus_type);
|
||||
}
|
||||
|
||||
subsys_initcall(pci_driver_init);
|
||||
subsys_initcall(pci_driver_init);
|
||||
|
||||
|
||||
The bus type may be unregistered (if the bus driver may be compiled
|
||||
as a module) by doing:
|
||||
as a module) by doing::
|
||||
|
||||
bus_unregister(&pci_bus_type);
|
||||
|
||||
|
@ -65,24 +67,24 @@ subsys_initcall(pci_driver_init);
|
|||
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:
|
||||
From include/linux/pci.h::
|
||||
|
||||
extern struct bus_type pci_bus_type;
|
||||
extern struct bus_type pci_bus_type;
|
||||
|
||||
|
||||
From file the above code appears in:
|
||||
From file the above code appears in::
|
||||
|
||||
EXPORT_SYMBOL(pci_bus_type);
|
||||
EXPORT_SYMBOL(pci_bus_type);
|
||||
|
||||
|
||||
|
||||
- This will cause the bus to show up in /sys/bus/pci/ with two
|
||||
subdirectories: 'devices' and 'drivers'.
|
||||
subdirectories: 'devices' and 'drivers'::
|
||||
|
||||
# tree -d /sys/bus/pci/
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
# tree -d /sys/bus/pci/
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
|
||||
|
||||
|
||||
|
@ -92,29 +94,29 @@ 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.
|
||||
- Embed a struct device in the bus-specific device type::
|
||||
|
||||
|
||||
struct pci_dev {
|
||||
...
|
||||
struct device dev; /* Generic device interface */
|
||||
...
|
||||
};
|
||||
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.
|
||||
should be created to convert from the generic object type::
|
||||
|
||||
|
||||
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
|
||||
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
|
||||
|
||||
or
|
||||
or
|
||||
|
||||
static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
|
||||
{
|
||||
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).
|
||||
|
@ -163,11 +165,11 @@ static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
|
|||
- Register the device.
|
||||
|
||||
Once the generic device has been initialized, it can be registered
|
||||
with the driver model core by doing:
|
||||
with the driver model core by doing::
|
||||
|
||||
device_register(&dev->dev);
|
||||
|
||||
It can later be unregistered by doing:
|
||||
It can later be unregistered by doing::
|
||||
|
||||
device_unregister(&dev->dev);
|
||||
|
||||
|
@ -181,45 +183,45 @@ static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
|
|||
|
||||
|
||||
When the device is registered, a directory in sysfs is created.
|
||||
The PCI tree in sysfs looks like:
|
||||
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
|
||||
/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.
|
||||
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
|
||||
/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
|
||||
|
||||
|
||||
|
||||
|
@ -231,12 +233,12 @@ 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:
|
||||
Just like with devices, do something like::
|
||||
|
||||
struct pci_driver {
|
||||
...
|
||||
struct device_driver driver;
|
||||
};
|
||||
struct pci_driver {
|
||||
...
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
|
||||
- Initialize the generic driver structure.
|
||||
|
@ -248,14 +250,14 @@ struct pci_driver {
|
|||
|
||||
- Register the driver.
|
||||
|
||||
After the generic driver has been initialized, call
|
||||
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:
|
||||
core by doing::
|
||||
|
||||
driver_unregister(&drv->driver);
|
||||
|
||||
|
@ -266,14 +268,14 @@ struct pci_driver {
|
|||
- Sysfs representation.
|
||||
|
||||
Drivers are exported via sysfs in their bus's 'driver's directory.
|
||||
For example:
|
||||
For example::
|
||||
|
||||
/sys/bus/pci/drivers/
|
||||
|-- 3c59x
|
||||
|-- Ensoniq AudioPCI
|
||||
|-- agpgart-amdk7
|
||||
|-- e100
|
||||
`-- serial
|
||||
/sys/bus/pci/drivers/
|
||||
|-- 3c59x
|
||||
|-- Ensoniq AudioPCI
|
||||
|-- agpgart-amdk7
|
||||
|-- e100
|
||||
`-- serial
|
||||
|
||||
|
||||
Step 4: Define Generic Methods for Drivers.
|
||||
|
@ -286,25 +288,25 @@ 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:
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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.
|
||||
is registered::
|
||||
|
||||
/* initialize common driver fields */
|
||||
drv->driver.name = drv->name;
|
||||
|
@ -336,7 +338,7 @@ 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:
|
||||
comparison::
|
||||
|
||||
int (*match)(struct device * dev, struct device_driver * drv);
|
||||
|
||||
|
@ -355,17 +357,17 @@ 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:
|
||||
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
|
||||
/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
|
||||
|
@ -387,7 +389,7 @@ environment variables, including
|
|||
|
||||
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:
|
||||
struct bus_type::
|
||||
|
||||
int (*hotplug) (struct device *dev, char **envp,
|
||||
int num_envp, char *buffer, int buffer_size);
|
||||
|
@ -407,10 +409,10 @@ 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.
|
||||
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 *));
|
||||
int bus_for_each_dev(struct bus_type * bus, struct device * start,
|
||||
void * data, int (*fn)(struct device *, void *));
|
||||
|
||||
|
||||
- Driver list.
|
||||
|
@ -419,10 +421,10 @@ 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:
|
||||
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 *));
|
||||
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.
|
||||
|
@ -444,4 +446,3 @@ 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).
|
||||
|
|
@ -103,7 +103,7 @@ id_table an array of NULL terminated EISA id strings,
|
|||
(driver_data).
|
||||
|
||||
driver a generic driver, such as described in
|
||||
Documentation/driver-model/driver.txt. Only .name,
|
||||
Documentation/driver-model/driver.rst. Only .name,
|
||||
.probe and .remove members are mandatory.
|
||||
=============== ====================================================
|
||||
|
||||
|
@ -152,7 +152,7 @@ state set of flags indicating the state of the device. Current
|
|||
flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
|
||||
res set of four 256 bytes I/O regions allocated to this device
|
||||
dma_mask DMA mask set from the parent device.
|
||||
dev generic device (see Documentation/driver-model/device.txt)
|
||||
dev generic device (see Documentation/driver-model/device.rst)
|
||||
======== ============================================================
|
||||
|
||||
You can get the 'struct eisa_device' from 'struct device' using the
|
||||
|
|
|
@ -89,7 +89,7 @@ increase the chances of your change being accepted.
|
|||
console. Excessive logging can seriously affect system performance.
|
||||
|
||||
* Use devres functions whenever possible to allocate resources. For rationale
|
||||
and supported functions, please see Documentation/driver-model/devres.txt.
|
||||
and supported functions, please see Documentation/driver-model/devres.rst.
|
||||
If a function is not supported by devres, consider using devm_add_action().
|
||||
|
||||
* If the driver has a detect function, make sure it is silent. Debug messages
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (c) 2002-3 Patrick Mochel
|
||||
* Copyright (c) 2002-3 Open Source Development Labs
|
||||
*
|
||||
* Please see Documentation/driver-model/platform.txt for more
|
||||
* Please see Documentation/driver-model/platform.rst for more
|
||||
* information.
|
||||
*/
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ MODULE_PARM_DESC(mask, "GPIO channel mask.");
|
|||
|
||||
/*
|
||||
* FIXME: convert this singleton driver to use the state container
|
||||
* design pattern, see Documentation/driver-model/design-patterns.txt
|
||||
* design pattern, see Documentation/driver-model/design-patterns.rst
|
||||
*/
|
||||
static struct cs5535_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
|
|
|
@ -2237,7 +2237,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
|||
struct ice_hw *hw;
|
||||
int err;
|
||||
|
||||
/* this driver uses devres, see Documentation/driver-model/devres.txt */
|
||||
/* this driver uses devres, see Documentation/driver-model/devres.rst */
|
||||
err = pcim_enable_device(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/// functions. Values allocated using the devm_functions are freed when
|
||||
/// the device is detached, and thus the use of the standard freeing
|
||||
/// function would cause a double free.
|
||||
/// See Documentation/driver-model/devres.txt for more information.
|
||||
/// See Documentation/driver-model/devres.rst for more information.
|
||||
///
|
||||
/// A difficulty of detecting this problem is that the standard freeing
|
||||
/// function might be called from a different function than the one
|
||||
|
|
Loading…
Reference in a new issue