starnix_modules_touch_power_policy/
lib.rs1use starnix_core::device::DeviceOps;
6use starnix_core::task::dynamic_thread_spawner::SpawnRequestBuilder;
7use starnix_core::task::{CurrentTask, Kernel, LockupDetectorReceiver};
8use starnix_core::vfs::buffers::{InputBuffer, OutputBuffer};
9use starnix_core::vfs::{
10 CloseFreeSafe, FileObject, FileOps, NamespaceNode, fileops_impl_nonseekable,
11 fileops_impl_noop_sync,
12};
13use starnix_logging::{log_error, log_info};
14use starnix_sync::{FileOpsCore, LockDepMutex, LockEqualOrBefore, Locked, TerminalLock, Unlocked};
15use starnix_uapi::device_id::DeviceId;
16use starnix_uapi::error;
17use starnix_uapi::errors::Errno;
18use starnix_uapi::open_flags::OpenFlags;
19use std::sync::Arc;
20use std::sync::mpsc::Sender;
21use zerocopy::IntoBytes;
22
23#[derive(Clone)]
24pub struct TouchPowerPolicyDevice {
25 touch_power_file: Arc<TouchPowerPolicyFile>,
26}
27
28impl TouchPowerPolicyDevice {
29 pub fn new(touch_standby_sender: Sender<bool>) -> Self {
30 TouchPowerPolicyDevice { touch_power_file: TouchPowerPolicyFile::new(touch_standby_sender) }
31 }
32
33 pub fn register<L>(self, locked: &mut Locked<L>, system_task: &CurrentTask)
34 where
35 L: LockEqualOrBefore<FileOpsCore>,
36 {
37 let kernel = system_task.kernel();
38 let registry = &kernel.device_registry;
39 registry
40 .register_dyn_device(
41 locked,
42 system_task,
43 "touch_standby".into(),
44 registry.objects.starnix_class(),
45 self,
46 )
47 .expect("can register touch_standby device");
48 }
49
50 pub fn start_relay(
51 &self,
52 kernel: &Kernel,
53 touch_standby_receiver: LockupDetectorReceiver<bool>,
54 ) {
55 let slf = self.clone();
56 let closure = move |_lock_context: &mut Locked<Unlocked>, _current_task: &CurrentTask| {
57 let mut prev_enabled = true;
58 while let Ok(touch_enabled) = touch_standby_receiver.recv() {
59 if touch_enabled != prev_enabled {
60 slf.notify_standby_state_changed(touch_enabled);
61 }
62 prev_enabled = touch_enabled;
63 }
64 log_error!("touch_standby relay was terminated unexpectedly.");
65 };
66 let req = SpawnRequestBuilder::new()
67 .with_debug_name("touch-power-policy-relay")
68 .with_sync_closure(closure)
69 .build();
70 kernel.kthreads.spawner().spawn_from_request(req);
71 }
72
73 fn notify_standby_state_changed(&self, touch_enabled: bool) {
74 log_info!("touch enabled: {:?}", touch_enabled);
76 }
77}
78
79impl DeviceOps for TouchPowerPolicyDevice {
80 fn open(
81 &self,
82 _locked: &mut Locked<FileOpsCore>,
83 _current_task: &CurrentTask,
84 _devt: DeviceId,
85 _node: &NamespaceNode,
86 _flags: OpenFlags,
87 ) -> Result<Box<dyn FileOps>, Errno> {
88 let touch_policy_file = self.touch_power_file.clone();
89 Ok(Box::new(touch_policy_file))
90 }
91}
92
93pub struct TouchPowerPolicyFile {
94 touch_enabled: LockDepMutex<bool, TerminalLock>,
96 touch_standby_sender: Sender<bool>,
98}
99
100impl TouchPowerPolicyFile {
101 pub fn new(touch_standby_sender: Sender<bool>) -> Arc<Self> {
102 Arc::new(TouchPowerPolicyFile {
103 touch_enabled: LockDepMutex::new(true),
104 touch_standby_sender,
105 })
106 }
107}
108
109impl CloseFreeSafe for TouchPowerPolicyFile {}
111impl FileOps for TouchPowerPolicyFile {
112 fileops_impl_nonseekable!();
113 fileops_impl_noop_sync!();
114
115 fn read(
116 &self,
117 _locked: &mut Locked<FileOpsCore>,
118 _file: &FileObject,
119 _current_task: &CurrentTask,
120 offset: usize,
121 data: &mut dyn OutputBuffer,
122 ) -> Result<usize, Errno> {
123 debug_assert!(offset == 0);
124 let touch_enabled = self.touch_enabled.lock().to_owned();
125 data.write_all(touch_enabled.as_bytes())
126 }
127
128 fn write(
129 &self,
130 _locked: &mut Locked<FileOpsCore>,
131 _file: &FileObject,
132 _current_task: &CurrentTask,
133 _offset: usize,
134 data: &mut dyn InputBuffer,
135 ) -> Result<usize, Errno> {
136 let content = data.read_all()?;
137 let sys_touch_standby = match &*content {
138 b"0" | b"0\n" => false,
139 b"1" | b"1\n" => true,
140 _ => {
141 log_error!("Invalid touch_standby value - must be 0 or 1");
142 return error!(EINVAL);
143 }
144 };
145 *self.touch_enabled.lock() = sys_touch_standby;
146 if let Err(e) = self.touch_standby_sender.send(sys_touch_standby) {
147 log_error!("unable to send recent touch_standby state to device relay: {:?}", e);
148 }
149 Ok(content.len())
150 }
151}