@@ -9,7 +9,7 @@ use crate::{
99 str:: CStr ,
1010 types:: { ARef , Opaque } ,
1111} ;
12- use core:: { fmt, ptr} ;
12+ use core:: { fmt, marker :: PhantomData , ptr} ;
1313
1414#[ cfg( CONFIG_PRINTK ) ]
1515use crate :: c_str;
@@ -42,7 +42,7 @@ use crate::c_str;
4242/// `bindings::device::release` is valid to be called from any thread, hence `ARef<Device>` can be
4343/// dropped from any thread.
4444#[ repr( transparent) ]
45- pub struct Device ( Opaque < bindings:: device > ) ;
45+ pub struct Device < Ctx : DeviceContext = Normal > ( Opaque < bindings:: device > , PhantomData < Ctx > ) ;
4646
4747impl Device {
4848 /// Creates a new reference-counted abstraction instance of an existing `struct device` pointer.
@@ -59,7 +59,9 @@ impl Device {
5959 // SAFETY: By the safety requirements ptr is valid
6060 unsafe { Self :: as_ref ( ptr) } . into ( )
6161 }
62+ }
6263
64+ impl < Ctx : DeviceContext > Device < Ctx > {
6365 /// Obtain the raw `struct device *`.
6466 pub ( crate ) fn as_raw ( & self ) -> * mut bindings:: device {
6567 self . 0 . get ( )
@@ -189,6 +191,11 @@ impl Device {
189191 }
190192}
191193
194+ // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
195+ // argument.
196+ kernel:: impl_device_context_deref!( unsafe { Device } ) ;
197+ kernel:: impl_device_context_into_aref!( Device ) ;
198+
192199// SAFETY: Instances of `Device` are always reference-counted.
193200unsafe impl crate :: types:: AlwaysRefCounted for Device {
194201 fn inc_ref ( & self ) {
@@ -225,16 +232,95 @@ pub struct Normal;
225232/// any of the bus callbacks, such as `probe()`.
226233pub struct Core ;
227234
235+ /// The [`Bound`] context is the context of a bus specific device reference when it is guaranteed to
236+ /// be bound for the duration of its lifetime.
237+ pub struct Bound ;
238+
228239mod private {
229240 pub trait Sealed { }
230241
242+ impl Sealed for super :: Bound { }
231243 impl Sealed for super :: Core { }
232244 impl Sealed for super :: Normal { }
233245}
234246
247+ impl DeviceContext for Bound { }
235248impl DeviceContext for Core { }
236249impl DeviceContext for Normal { }
237250
251+ /// # Safety
252+ ///
253+ /// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the
254+ /// generic argument of `$device`.
255+ #[ doc( hidden) ]
256+ #[ macro_export]
257+ macro_rules! __impl_device_context_deref {
258+ ( unsafe { $device: ident, $src: ty => $dst: ty } ) => {
259+ impl :: core:: ops:: Deref for $device<$src> {
260+ type Target = $device<$dst>;
261+
262+ fn deref( & self ) -> & Self :: Target {
263+ let ptr: * const Self = self ;
264+
265+ // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the
266+ // safety requirement of the macro.
267+ let ptr = ptr. cast:: <Self :: Target >( ) ;
268+
269+ // SAFETY: `ptr` was derived from `&self`.
270+ unsafe { & * ptr }
271+ }
272+ }
273+ } ;
274+ }
275+
276+ /// Implement [`core::ops::Deref`] traits for allowed [`DeviceContext`] conversions of a (bus
277+ /// specific) device.
278+ ///
279+ /// # Safety
280+ ///
281+ /// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the
282+ /// generic argument of `$device`.
283+ #[ macro_export]
284+ macro_rules! impl_device_context_deref {
285+ ( unsafe { $device: ident } ) => {
286+ // SAFETY: This macro has the exact same safety requirement as
287+ // `__impl_device_context_deref!`.
288+ :: kernel:: __impl_device_context_deref!( unsafe {
289+ $device,
290+ $crate:: device:: Core => $crate:: device:: Bound
291+ } ) ;
292+
293+ // SAFETY: This macro has the exact same safety requirement as
294+ // `__impl_device_context_deref!`.
295+ :: kernel:: __impl_device_context_deref!( unsafe {
296+ $device,
297+ $crate:: device:: Bound => $crate:: device:: Normal
298+ } ) ;
299+ } ;
300+ }
301+
302+ #[ doc( hidden) ]
303+ #[ macro_export]
304+ macro_rules! __impl_device_context_into_aref {
305+ ( $src: ty, $device: tt) => {
306+ impl :: core:: convert:: From <& $device<$src>> for $crate:: types:: ARef <$device> {
307+ fn from( dev: & $device<$src>) -> Self {
308+ ( & * * dev) . into( )
309+ }
310+ }
311+ } ;
312+ }
313+
314+ /// Implement [`core::convert::From`], such that all `&Device<Ctx>` can be converted to an
315+ /// `ARef<Device>`.
316+ #[ macro_export]
317+ macro_rules! impl_device_context_into_aref {
318+ ( $device: tt) => {
319+ :: kernel:: __impl_device_context_into_aref!( $crate:: device:: Core , $device) ;
320+ :: kernel:: __impl_device_context_into_aref!( $crate:: device:: Bound , $device) ;
321+ } ;
322+ }
323+
238324#[ doc( hidden) ]
239325#[ macro_export]
240326macro_rules! dev_printk {
0 commit comments