1use anyhow::{Context, Error, anyhow, format_err};
6use fidl::endpoints::SynchronousProxy;
7use starnix_core::device::kobject::Device;
8use starnix_core::fs::sysfs::build_device_directory;
9use starnix_core::task::{CurrentTask, Kernel};
10use starnix_core::vfs::FsNodeOps;
11use starnix_core::vfs::pseudo::simple_directory::SimpleDirectoryMutator;
12use starnix_core::vfs::pseudo::simple_file::{BytesFile, BytesFileOps};
13use starnix_logging::{log_error, log_warn};
14use starnix_sync::{Locked, Mutex, Unlocked};
15use starnix_uapi::errors::{Errno, errno};
16use starnix_uapi::file_mode::mode;
17use std::borrow::Cow;
18use std::sync::Arc;
19use zx::MonotonicInstant;
20use {fidl_fuchsia_power_battery as fbattery, fidl_fuchsia_power_cpu as fcpu};
21
22const BATTERY_CHARGER_SERVICE_DIRECTORY: &str = "/svc/fuchsia.power.battery.ChargerService";
23
24trait CoolingOps: Send + Sync + 'static {
25 fn get_max_state(&self) -> u32;
26 fn get_state(&self) -> Result<u32, Errno>;
27 fn set_state(&self, state: u32) -> Result<(), Errno>;
28}
29
30impl<T: CoolingOps> CoolingOps for Arc<T> {
31 fn get_max_state(&self) -> u32 {
32 self.as_ref().get_max_state()
33 }
34
35 fn get_state(&self) -> Result<u32, Errno> {
36 self.as_ref().get_state()
37 }
38
39 fn set_state(&self, state: u32) -> Result<(), Errno> {
40 self.as_ref().set_state(state)
41 }
42}
43
44struct CoolingDevice<T: CoolingOps> {
45 device_id: u32,
46 device_type: String,
47 ops: T,
48}
49
50impl<T: CoolingOps> CoolingDevice<T> {
51 fn get_device_name(&self) -> String {
52 format!("cooling_device{}", self.device_id)
53 }
54
55 fn build_device_dir(self: Arc<Self>, device: &Device, dir: &SimpleDirectoryMutator) {
56 build_device_directory(device, dir);
57 dir.entry(
58 "max_state",
59 BytesFile::new_node(format!("{}\n", self.ops.get_max_state()).into_bytes()),
60 mode!(IFREG, 0o444),
61 );
62 dir.entry(
63 "type",
64 BytesFile::new_node(format!("{}\n", self.device_type).into_bytes()),
65 mode!(IFREG, 0o444),
66 );
67 dir.entry("cur_state", CurStateFile::new_node(self), mode!(IFREG, 0o644));
68 }
69}
70
71struct CurStateFile<T: CoolingOps> {
73 cooling_device: Arc<CoolingDevice<T>>,
74}
75
76impl<T: CoolingOps> CurStateFile<T> {
77 fn new_node(cooling_device: Arc<CoolingDevice<T>>) -> impl FsNodeOps {
78 BytesFile::new_node(Self { cooling_device })
79 }
80}
81
82impl<T: CoolingOps> BytesFileOps for CurStateFile<T> {
83 fn read(&self, _current_task: &CurrentTask) -> Result<Cow<'_, [u8]>, Errno> {
84 let state = self.cooling_device.ops.get_state()?;
85 Ok(format!("{}\n", state).into_bytes().into())
86 }
87
88 fn write(&self, _current_task: &CurrentTask, data: Vec<u8>) -> Result<(), Errno> {
89 let input = str::from_utf8(&data).map_err(|_| errno!(EINVAL))?;
90 let input_num = input.trim().parse().map_err(|_| errno!(EINVAL))?;
91 self.cooling_device.ops.set_state(input_num)
92 }
93}
94
95struct CoolingDeviceRegistrar {
97 next_id: u32,
98}
99
100impl CoolingDeviceRegistrar {
101 fn new() -> Self {
102 Self { next_id: 0 }
103 }
104
105 fn get_next_id(&mut self) -> u32 {
106 let id = self.next_id;
107 self.next_id += 1;
108 id
109 }
110
111 fn register<T: CoolingOps>(
113 &mut self,
114 locked: &mut Locked<Unlocked>,
115 kernel: &Kernel,
116 device_type: String,
117 ops: T,
118 ) -> Device {
119 let device_registry = &kernel.device_registry;
120 let device_class = device_registry.objects.virtual_thermal_class();
121
122 let cooling_device =
123 Arc::new(CoolingDevice::<T> { device_id: self.get_next_id(), device_type, ops });
124
125 device_registry.add_numberless_device(
126 locked,
127 cooling_device.get_device_name().as_str().into(),
128 device_class,
129 |device, dir| cooling_device.build_device_dir(device, dir),
130 )
131 }
132}
133
134struct CpuCoolingOps {
135 domain_controller: Arc<fcpu::DomainControllerSynchronousProxy>,
136 domain_id: u64,
137 available_frequencies_hz: Vec<u64>,
138}
139
140impl CoolingOps for CpuCoolingOps {
141 fn get_max_state(&self) -> u32 {
142 (self.available_frequencies_hz.len() - 1) as u32
143 }
144 fn get_state(&self) -> Result<u32, Errno> {
145 let max_frequency_index = self
146 .domain_controller
147 .get_max_frequency(self.domain_id, MonotonicInstant::INFINITE)
148 .map_err(|e| errno!(EIO, anyhow!("Failed to send get_max_frequency call: {:?}", e)))?
149 .map_err(|e| errno!(EIO, anyhow!("Failed response from get_max_frequency: {:?}", e)))?;
150 Ok(max_frequency_index as u32)
151 }
152 fn set_state(&self, state: u32) -> Result<(), Errno> {
153 if state == 0 {
154 self.domain_controller
155 .clear_max_frequency(self.domain_id, MonotonicInstant::INFINITE)
156 .map_err(|e| {
157 errno!(EIO, anyhow!("Failed to send clear_max_frequency call: {:?}", e))
158 })?
159 .map_err(|e| {
160 errno!(EIO, anyhow!("Failed response from clear_max_frequency: {:?}", e))
161 })
162 } else {
163 self.domain_controller
164 .set_max_frequency(self.domain_id, state.into(), MonotonicInstant::INFINITE)
165 .map_err(|e| {
166 errno!(EIO, anyhow!("Failed to send set_max_frequency call: {:?}", e))
167 })?
168 .map_err(|e| {
169 errno!(EIO, anyhow!("Failed response from set_max_frequency: {:?}", e))
170 })
171 }
172 }
173}
174
175fn register_cpu_domains(
176 locked: &mut Locked<Unlocked>,
177 kernel: &Kernel,
178 registrar: &mut CoolingDeviceRegistrar,
179) -> Result<(), Error> {
180 let domain_controller = Arc::new(
181 fuchsia_component::client::connect_to_protocol_sync::<fcpu::DomainControllerMarker>()
182 .map_err(|error| anyhow!("Failed to connect to DomainController: {:?}", error))?,
183 );
184 let domains = domain_controller
185 .list_domains(MonotonicInstant::INFINITE)
186 .map_err(|e| anyhow!("list_domains failed: {}", e))?;
187
188 for domain in domains {
190 let device_type = domain.name.expect("name not provided");
191 let ops = CpuCoolingOps {
192 domain_controller: domain_controller.clone(),
193 domain_id: domain.id.expect("id not provided"),
194 available_frequencies_hz: domain
195 .available_frequencies_hz
196 .expect("available_frequencies_hz not provided"),
197 };
198 registrar.register(locked, kernel, device_type, ops);
199 }
200 Ok(())
201}
202
203pub fn cooling_device_init(
210 locked: &mut Locked<Unlocked>,
211 kernel: &Kernel,
212 devices: Vec<String>,
213) -> Result<(), Error> {
214 let mut registrar = CoolingDeviceRegistrar::new();
215 for device_spec in devices.into_iter() {
216 let (device_type, device_param) = device_spec
217 .split_once('=')
218 .map_or_else(|| (device_spec.as_str(), None), |(t, p)| (t, Some(p)));
219 match device_type {
220 "fcc" => {
221 if let Err(e) = register_fcc_device(
223 locked,
224 kernel,
225 &mut registrar,
226 device_param
227 .ok_or_else(|| format_err!("Missing parameter for 'fcc' cooling device"))?,
228 ) {
229 log_error!("Failed to register 'fcc' cooling device: {e:?}");
230 }
231 }
232 "cpu" => register_cpu_domains(locked, kernel, &mut registrar)?,
233 t => {
234 return Err(format_err!("Unknown cooling device: {t:?}"));
235 }
236 };
237 }
238
239 Ok(())
240}
241
242struct FccCoolingOps {
243 proxy: fbattery::ChargerSynchronousProxy,
244 max_charge_level: u32,
245 charge_level: Mutex<u32>,
246}
247
248impl FccCoolingOps {
249 fn new(
250 proxy: fbattery::ChargerSynchronousProxy,
251 max_charge_level: u32,
252 charge_level: u32,
253 ) -> Self {
254 Self { proxy, max_charge_level, charge_level: Mutex::new(charge_level) }
255 }
256}
257
258impl CoolingOps for FccCoolingOps {
259 fn get_max_state(&self) -> u32 {
260 self.max_charge_level
261 }
262
263 fn get_state(&self) -> Result<u32, Errno> {
264 let locked_charge_level = self.charge_level.lock();
265 Ok(*locked_charge_level)
266 }
267
268 fn set_state(&self, state: u32) -> Result<(), Errno> {
269 let mut locked_charge_level = self.charge_level.lock();
270
271 let charge_level = if state > self.max_charge_level {
275 log_warn!(
276 "FCC charge_level of {} exceeds {}; setting to 0",
277 state,
278 self.max_charge_level
279 );
280 0
281 } else {
282 state
283 };
284
285 if charge_level == self.max_charge_level {
288 self.proxy
289 .enable(false, zx::MonotonicInstant::INFINITE)
290 .map_err(|e| errno!(EIO, e))?
291 .map_err(|e| errno!(EIO, e))?;
292 } else if *locked_charge_level == self.max_charge_level {
293 self.proxy
294 .enable(true, zx::MonotonicInstant::INFINITE)
295 .map_err(|e| errno!(EIO, e))?
296 .map_err(|e| errno!(EIO, e))?;
297 }
298
299 *locked_charge_level = charge_level;
300 Ok(())
301 }
302}
303
304fn register_fcc_device(
305 locked: &mut Locked<Unlocked>,
306 kernel: &Kernel,
307 registrar: &mut CoolingDeviceRegistrar,
308 param: &str,
309) -> Result<(), Error> {
310 let proxy = connect_to_battery_charger().context("Failed to connect to battery Charger")?;
311 let max_charge_level: u32 = param.parse().context("Invalid max_charge_level")?;
312 let ops = FccCoolingOps::new(proxy, max_charge_level, 0);
313
314 registrar.register(locked, kernel, "fcc".to_string(), ops);
315 Ok(())
316}
317
318fn connect_to_battery_charger() -> Result<fbattery::ChargerSynchronousProxy, Error> {
319 let mut dir = std::fs::read_dir(BATTERY_CHARGER_SERVICE_DIRECTORY)
323 .context("Failed to read ChargerService directory")?;
324 let entry = dir
325 .next()
326 .ok_or_else(|| anyhow::format_err!("Missing ChargerService instance"))?
327 .context("Unable to read ChargerService instance")?;
328 let path = entry
329 .path()
330 .join("device")
331 .into_os_string()
332 .into_string()
333 .map_err(|_| anyhow::format_err!("Failed to get device path"))?;
334
335 let (client_end, server_end) = zx::Channel::create();
336 fdio::service_connect(&path, server_end)?;
337 Ok(fbattery::ChargerSynchronousProxy::from_channel(client_end))
338}