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::{LockDepMutex, TouchPowerPolicyEnabledLock};
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(self, kernel: &Kernel) {
34 let registry = &kernel.device_registry;
35 registry
36 .register_dyn_device(
37 kernel,
38 "touch_standby".into(),
39 registry.objects.starnix_class(),
40 self,
41 )
42 .expect("can register touch_standby device");
43 }
44
45 pub fn start_relay(
46 &self,
47 kernel: &Kernel,
48 touch_standby_receiver: LockupDetectorReceiver<bool>,
49 ) {
50 let slf = self.clone();
51 let closure = move |_current_task: &CurrentTask| {
52 let mut prev_enabled = true;
53 while let Ok(touch_enabled) = touch_standby_receiver.recv() {
54 if touch_enabled != prev_enabled {
55 slf.notify_standby_state_changed(touch_enabled);
56 }
57 prev_enabled = touch_enabled;
58 }
59 log_error!("touch_standby relay was terminated unexpectedly.");
60 };
61 let req = SpawnRequestBuilder::new()
62 .with_debug_name("touch-power-policy-relay")
63 .with_sync_closure(closure)
64 .build();
65 kernel.kthreads.spawner().spawn_from_request(req);
66 }
67
68 fn notify_standby_state_changed(&self, touch_enabled: bool) {
69 log_info!("touch enabled: {:?}", touch_enabled);
71 }
72}
73
74impl DeviceOps for TouchPowerPolicyDevice {
75 fn open(
76 &self,
77 _current_task: &CurrentTask,
78 _devt: DeviceId,
79 _node: &NamespaceNode,
80 _flags: OpenFlags,
81 ) -> Result<Box<dyn FileOps>, Errno> {
82 let touch_policy_file = self.touch_power_file.clone();
83 Ok(Box::new(touch_policy_file))
84 }
85}
86
87pub struct TouchPowerPolicyFile {
88 touch_enabled: LockDepMutex<bool, TouchPowerPolicyEnabledLock>,
90 touch_standby_sender: Sender<bool>,
92}
93
94impl TouchPowerPolicyFile {
95 pub fn new(touch_standby_sender: Sender<bool>) -> Arc<Self> {
96 Arc::new(TouchPowerPolicyFile { touch_enabled: true.into(), touch_standby_sender })
97 }
98}
99
100impl CloseFreeSafe for TouchPowerPolicyFile {}
102impl FileOps for TouchPowerPolicyFile {
103 fileops_impl_nonseekable!();
104 fileops_impl_noop_sync!();
105
106 fn read(
107 &self,
108 _file: &FileObject,
109 _current_task: &CurrentTask,
110 offset: usize,
111 data: &mut dyn OutputBuffer,
112 ) -> Result<usize, Errno> {
113 debug_assert!(offset == 0);
114 let touch_enabled = self.touch_enabled.lock().to_owned();
115 data.write_all(touch_enabled.as_bytes())
116 }
117
118 fn write(
119 &self,
120 _file: &FileObject,
121 _current_task: &CurrentTask,
122 _offset: usize,
123 data: &mut dyn InputBuffer,
124 ) -> Result<usize, Errno> {
125 let content = data.read_all()?;
126 let sys_touch_standby = match &*content {
127 b"0" | b"0\n" => false,
128 b"1" | b"1\n" => true,
129 _ => {
130 log_error!("Invalid touch_standby value - must be 0 or 1");
131 return error!(EINVAL);
132 }
133 };
134 *self.touch_enabled.lock() = sys_touch_standby;
135 if let Err(e) = self.touch_standby_sender.send(sys_touch_standby) {
136 log_error!("unable to send recent touch_standby state to device relay: {:?}", e);
137 }
138 Ok(content.len())
139 }
140}