Skip to content

Commit d6e26c1

Browse files
author
Danilo Krummrich
committed
device: rust: expand documentation for Device
The documentation for the generic Device type is outdated and deserves much more detail. Hence, expand the documentation and cover topics such as device types, device contexts, as well as information on how to use the generic device infrastructure to implement bus and class specific device types. Reviewed-by: Daniel Almeida <[email protected]> Reviewed-by: Greg Kroah-Hartman <[email protected]> Reviewed-by: Alexandre Courbot <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ Add empty line after code blocks, "in" -> "within", remove unnecessary pin annotations in class device example. - Danilo ] Signed-off-by: Danilo Krummrich <[email protected]>
1 parent 82b3644 commit d6e26c1

File tree

1 file changed

+126
-13
lines changed

1 file changed

+126
-13
lines changed

rust/kernel/device.rs

Lines changed: 126 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,130 @@ use crate::c_str;
1515

1616
pub mod property;
1717

18-
/// A reference-counted device.
18+
/// The core representation of a device in the kernel's driver model.
1919
///
20-
/// This structure represents the Rust abstraction for a C `struct device`. This implementation
21-
/// abstracts the usage of an already existing C `struct device` within Rust code that we get
22-
/// passed from the C side.
20+
/// This structure represents the Rust abstraction for a C `struct device`. A [`Device`] can either
21+
/// exist as temporary reference (see also [`Device::from_raw`]), which is only valid within a
22+
/// certain scope or as [`ARef<Device>`], owning a dedicated reference count.
2323
///
24-
/// An instance of this abstraction can be obtained temporarily or permanent.
24+
/// # Device Types
2525
///
26-
/// A temporary one is bound to the lifetime of the C `struct device` pointer used for creation.
27-
/// A permanent instance is always reference-counted and hence not restricted by any lifetime
28-
/// boundaries.
26+
/// A [`Device`] can represent either a bus device or a class device.
2927
///
30-
/// For subsystems it is recommended to create a permanent instance to wrap into a subsystem
31-
/// specific device structure (e.g. `pci::Device`). This is useful for passing it to drivers in
32-
/// `T::probe()`, such that a driver can store the `ARef<Device>` (equivalent to storing a
33-
/// `struct device` pointer in a C driver) for arbitrary purposes, e.g. allocating DMA coherent
34-
/// memory.
28+
/// ## Bus Devices
29+
///
30+
/// A bus device is a [`Device`] that is associated with a physical or virtual bus. Examples of
31+
/// buses include PCI, USB, I2C, and SPI. Devices attached to a bus are registered with a specific
32+
/// bus type, which facilitates matching devices with appropriate drivers based on IDs or other
33+
/// identifying information. Bus devices are visible in sysfs under `/sys/bus/<bus-name>/devices/`.
34+
///
35+
/// ## Class Devices
36+
///
37+
/// A class device is a [`Device`] that is associated with a logical category of functionality
38+
/// rather than a physical bus. Examples of classes include block devices, network interfaces, sound
39+
/// cards, and input devices. Class devices are grouped under a common class and exposed to
40+
/// userspace via entries in `/sys/class/<class-name>/`.
41+
///
42+
/// # Device Context
43+
///
44+
/// [`Device`] references are generic over a [`DeviceContext`], which represents the type state of
45+
/// a [`Device`].
46+
///
47+
/// As the name indicates, this type state represents the context of the scope the [`Device`]
48+
/// reference is valid in. For instance, the [`Bound`] context guarantees that the [`Device`] is
49+
/// bound to a driver for the entire duration of the existence of a [`Device<Bound>`] reference.
50+
///
51+
/// Other [`DeviceContext`] types besides [`Bound`] are [`Normal`], [`Core`] and [`CoreInternal`].
52+
///
53+
/// Unless selected otherwise [`Device`] defaults to the [`Normal`] [`DeviceContext`], which by
54+
/// itself has no additional requirements.
55+
///
56+
/// It is always up to the caller of [`Device::from_raw`] to select the correct [`DeviceContext`]
57+
/// type for the corresponding scope the [`Device`] reference is created in.
58+
///
59+
/// All [`DeviceContext`] types other than [`Normal`] are intended to be used with
60+
/// [bus devices](#bus-devices) only.
61+
///
62+
/// # Implementing Bus Devices
63+
///
64+
/// This section provides a guideline to implement bus specific devices, such as [`pci::Device`] or
65+
/// [`platform::Device`].
66+
///
67+
/// A bus specific device should be defined as follows.
68+
///
69+
/// ```ignore
70+
/// #[repr(transparent)]
71+
/// pub struct Device<Ctx: device::DeviceContext = device::Normal>(
72+
/// Opaque<bindings::bus_device_type>,
73+
/// PhantomData<Ctx>,
74+
/// );
75+
/// ```
76+
///
77+
/// Since devices are reference counted, [`AlwaysRefCounted`] should be implemented for `Device`
78+
/// (i.e. `Device<Normal>`). Note that [`AlwaysRefCounted`] must not be implemented for any other
79+
/// [`DeviceContext`], since all other device context types are only valid within a certain scope.
80+
///
81+
/// In order to be able to implement the [`DeviceContext`] dereference hierarchy, bus device
82+
/// implementations should call the [`impl_device_context_deref`] macro as shown below.
83+
///
84+
/// ```ignore
85+
/// // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s
86+
/// // generic argument.
87+
/// kernel::impl_device_context_deref!(unsafe { Device });
88+
/// ```
89+
///
90+
/// In order to convert from a any [`Device<Ctx>`] to [`ARef<Device>`], bus devices can implement
91+
/// the following macro call.
92+
///
93+
/// ```ignore
94+
/// kernel::impl_device_context_into_aref!(Device);
95+
/// ```
96+
///
97+
/// Bus devices should also implement the following [`AsRef`] implementation, such that users can
98+
/// easily derive a generic [`Device`] reference.
99+
///
100+
/// ```ignore
101+
/// impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
102+
/// fn as_ref(&self) -> &device::Device<Ctx> {
103+
/// ...
104+
/// }
105+
/// }
106+
/// ```
107+
///
108+
/// # Implementing Class Devices
109+
///
110+
/// Class device implementations require less infrastructure and depend slightly more on the
111+
/// specific subsystem.
112+
///
113+
/// An example implementation for a class device could look like this.
114+
///
115+
/// ```ignore
116+
/// #[repr(C)]
117+
/// pub struct Device<T: class::Driver> {
118+
/// dev: Opaque<bindings::class_device_type>,
119+
/// data: T::Data,
120+
/// }
121+
/// ```
122+
///
123+
/// This class device uses the sub-classing pattern to embed the driver's private data within the
124+
/// allocation of the class device. For this to be possible the class device is generic over the
125+
/// class specific `Driver` trait implementation.
126+
///
127+
/// Just like any device, class devices are reference counted and should hence implement
128+
/// [`AlwaysRefCounted`] for `Device`.
129+
///
130+
/// Class devices should also implement the following [`AsRef`] implementation, such that users can
131+
/// easily derive a generic [`Device`] reference.
132+
///
133+
/// ```ignore
134+
/// impl<T: class::Driver> AsRef<device::Device> for Device<T> {
135+
/// fn as_ref(&self) -> &device::Device {
136+
/// ...
137+
/// }
138+
/// }
139+
/// ```
140+
///
141+
/// An example for a class device implementation is [`drm::Device`].
35142
///
36143
/// # Invariants
37144
///
@@ -42,6 +149,12 @@ pub mod property;
42149
///
43150
/// `bindings::device::release` is valid to be called from any thread, hence `ARef<Device>` can be
44151
/// dropped from any thread.
152+
///
153+
/// [`AlwaysRefCounted`]: kernel::types::AlwaysRefCounted
154+
/// [`drm::Device`]: kernel::drm::Device
155+
/// [`impl_device_context_deref`]: kernel::impl_device_context_deref
156+
/// [`pci::Device`]: kernel::pci::Device
157+
/// [`platform::Device`]: kernel::platform::Device
45158
#[repr(transparent)]
46159
pub struct Device<Ctx: DeviceContext = Normal>(Opaque<bindings::device>, PhantomData<Ctx>);
47160

0 commit comments

Comments
 (0)