1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// SPDX-License-Identifier: GPL-2.0

//! Power management interfaces.
//!
//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)

#![allow(dead_code)]

use crate::{bindings, error::from_kernel_result, types::ForeignOwnable, Result};
use core::marker::PhantomData;

/// Corresponds to the kernel's `struct dev_pm_ops`.
///
/// It is meant to be implemented by drivers that support power-management operations.
pub trait Operations {
    /// The type of the context data stored by the driver on each device.
    type Data: ForeignOwnable + Sync + Send;

    /// Called before the system goes into a sleep state.
    fn suspend(_data: <Self::Data as ForeignOwnable>::Borrowed<'_>) -> Result {
        Ok(())
    }

    /// Called after the system comes back from a sleep state.
    fn resume(_data: <Self::Data as ForeignOwnable>::Borrowed<'_>) -> Result {
        Ok(())
    }

    /// Called before creating a hibernation image.
    fn freeze(_data: <Self::Data as ForeignOwnable>::Borrowed<'_>) -> Result {
        Ok(())
    }

    /// Called after the system is restored from a hibernation image.
    fn restore(_data: <Self::Data as ForeignOwnable>::Borrowed<'_>) -> Result {
        Ok(())
    }
}

macro_rules! pm_callback {
    ($callback:ident, $method:ident) => {
        unsafe extern "C" fn $callback<T: Operations>(
            dev: *mut bindings::device,
        ) -> core::ffi::c_int {
            from_kernel_result! {
                // SAFETY: `dev` is valid as it was passed in by the C portion.
                let ptr = unsafe { bindings::dev_get_drvdata(dev) };
                // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
                // from a previous call to `T::Data::into_foreign`.
                let data = unsafe { T::Data::borrow(ptr) };
                T::$method(data)?;
                Ok(0)
            }
        }
    };
}

pm_callback!(suspend_callback, suspend);
pm_callback!(resume_callback, resume);
pm_callback!(freeze_callback, freeze);
pm_callback!(restore_callback, restore);

pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);

impl<T: Operations> OpsTable<T> {
    const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
        prepare: None,
        complete: None,
        suspend: Some(suspend_callback::<T>),
        resume: Some(resume_callback::<T>),
        freeze: Some(freeze_callback::<T>),
        thaw: None,
        poweroff: None,
        restore: Some(restore_callback::<T>),
        suspend_late: None,
        resume_early: None,
        freeze_late: None,
        thaw_early: None,
        poweroff_late: None,
        restore_early: None,
        suspend_noirq: None,
        resume_noirq: None,
        freeze_noirq: None,
        thaw_noirq: None,
        poweroff_noirq: None,
        restore_noirq: None,
        runtime_suspend: None,
        runtime_resume: None,
        runtime_idle: None,
    };

    /// Builds an instance of `struct dev_pm_ops`.
    ///
    /// # Safety
    ///
    /// The caller must ensure that `dev_get_drvdata` will result in a value returned by
    /// [`T::Data::into_foreign`].
    pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
        &Self::VTABLE
    }
}

/// Implements the [`Operations`] trait as no-ops.
///
/// This is useful when one doesn't want to provide the implementation of any power-manager related
/// operation.
pub struct NoOperations<T: ForeignOwnable>(PhantomData<T>);

impl<T: ForeignOwnable + Send + Sync> Operations for NoOperations<T> {
    type Data = T;
}

// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
// different threads.
unsafe impl<T: ForeignOwnable> Sync for NoOperations<T> {}

// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
unsafe impl<T: ForeignOwnable> Send for NoOperations<T> {}