1use crate::device::DeviceMode;
6use crate::device::kobject::{Bus, Class, Device, DeviceMetadata, Subsystem};
7use crate::fs::sysfs::{build_device_directory, get_sysfs, register_cpu_devices};
8use crate::task::Kernel;
9use crate::vfs::pseudo::simple_directory::{SimpleDirectory, SimpleDirectoryMutator};
10use crate::vfs::pseudo::stub_bytes_file::StubBytesFile;
11use crate::vfs::pseudo::stub_empty_file::StubEmptyFile;
12use crate::vfs::{FileSystemHandle, FsStr, FsString};
13use starnix_logging::bug_ref;
14use starnix_uapi::file_mode::mode;
15use std::sync::{Arc, OnceLock};
16
17pub struct KObjectStore {
22 pub root: Arc<SimpleDirectory>,
24
25 fs: OnceLock<FileSystemHandle>,
27
28 virtual_device: OnceLock<Device>,
30
31 platform_device: OnceLock<Device>,
33
34 system_device: OnceLock<Device>,
36
37 soc_device: OnceLock<Device>,
39}
40
41impl KObjectStore {
42 pub fn init(&self, kernel: &Kernel) {
43 self.fs.set(get_sysfs(kernel)).unwrap();
44 self.register_initial_devices(kernel);
45 }
46
47 fn register_initial_devices(&self, kernel: &Kernel) {
48 let registry = &kernel.device_registry;
49
50 register_cpu_devices(kernel);
52
53 registry.add_numberless_device(
56 "0:80".into(),
57 None,
58 self.get_or_create_class("bdi".into()),
59 |device, dir| {
60 build_device_directory(device, dir);
61 add_stub_attributes(dir, &["max_ratio", "read_ahead_kb"]);
62 },
63 );
64
65 self.get_or_create_class("powercap".into());
67 self.get_or_create_class("udc".into());
68
69 let platform_bus = self.platform_bus();
73 let soc = self.soc_device();
74
75 let spmi = registry.add_bus_device(
77 "1c40000.qcom,spmi".into(),
78 Some(soc.clone()),
79 platform_bus.clone(),
80 build_device_directory,
81 );
82 let spmi_bus = self.get_or_create_bus("spmi".into());
83 let spmi_0 = registry.add_bus_device(
84 "spmi-0".into(),
85 Some(spmi),
86 spmi_bus.clone(),
87 build_device_directory,
88 );
89 let spmi_0_00 =
90 registry.add_bus_device("0-00".into(), Some(spmi_0), spmi_bus, build_device_directory);
91 let qbg = registry.add_bus_device(
92 "1c40000.qcom,spmi:qcom,pm5100@0:qpnp,qbg@4f00".into(),
93 Some(spmi_0_00),
94 platform_bus.clone(),
95 build_device_directory,
96 );
97 let iio_bus = self.get_or_create_bus("iio".into());
98 registry.add_bus_device("iio:device3".into(), Some(qbg), iio_bus, |device, dir| {
99 build_device_directory(device, dir);
100 add_stub_attributes(dir, &["in_resistance_resistance_id_input"]);
101 });
102
103 let mdss_mdp = registry.add_bus_device(
106 "5e00000.qcom,mdss_mdp".into(),
107 Some(soc),
108 platform_bus,
109 build_device_directory,
110 );
111 let drm_class = self.get_or_create_class("drm".into());
112 let card0 = registry.add_numberless_device(
113 "card0".into(),
114 Some(mdss_mdp.clone()),
115 drm_class.clone(),
116 build_device_directory,
117 );
118 registry.add_numberless_device(
119 "sde-conn-0-DSI-1".into(),
120 Some(card0.clone()),
121 drm_class.clone(),
122 |device, dir| {
123 build_device_directory(device, dir);
124 dir.entry(
125 "display_power_state",
126 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
127 mode!(IFREG, 0o644),
128 );
129 dir.entry(
130 "panel_power_state",
131 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
132 mode!(IFREG, 0o644),
133 );
134 },
135 );
136 registry.add_numberless_device(
137 "card0-DSI-1".into(),
138 Some(card0),
139 drm_class,
140 |device, dir| {
141 build_device_directory(device, dir);
142 dir.subdir("panel", 0o755, |dir| {
143 dir.entry(
144 "panel_name",
145 StubBytesFile::new_node_with_data(
146 bug_ref!("https://fxbug.dev/560212202"),
147 b"Placeholder",
148 ),
149 mode!(IFREG, 0o444),
150 );
151 });
152 },
153 );
154
155 registry.add_numberless_device(
158 "panel0-backlight".into(),
159 Some(mdss_mdp),
160 self.get_or_create_class("backlight".into()),
161 |device, dir| {
162 build_device_directory(device, dir);
163 add_stub_attributes(dir, &["brightness"]);
164 },
165 );
166
167 registry.add_numberless_device(
168 "battery".into(),
169 None,
170 self.get_or_create_class("power_supply".into()),
171 |device, dir| {
172 build_device_directory(device, dir);
173 dir.entry(
174 "capacity",
175 StubBytesFile::new_node_with_data(
176 bug_ref!("https://fxbug.dev/573313995"),
177 b"0",
178 ),
179 mode!(IFREG, 0o644),
180 );
181 },
182 );
183
184 registry.add_subsystemless_device(
185 "goog-chip-info".into(),
186 Some(self.system_device()),
187 |device, dir| {
188 build_device_directory(device, dir);
189 for name in ["device_table", "dvfs_table", "ids_table"] {
190 dir.entry(
191 name,
192 StubBytesFile::new_node_with_data(
193 bug_ref!("https://fxbug.dev/560212202"),
194 b"Placeholder",
195 ),
196 mode!(IFREG, 0o444),
197 );
198 }
199 },
200 );
201
202 let mmc0 = registry.add_numberless_device(
208 "mmc0".into(),
209 None,
210 self.get_or_create_class("mmc_host".into()),
211 build_device_directory,
212 );
213 registry.add_bus_device(
214 "mmc0:0001".into(),
215 Some(mmc0),
216 self.get_or_create_bus("mmc".into()),
217 |device, dir| {
218 build_device_directory(device, dir);
219 add_stub_attributes(
220 dir,
221 &["fwrev", "hwrev", "life_time", "manfid", "pre_eol_info", "serial"],
222 );
223 dir.subdir("block", 0o755, |dir| {
224 dir.subdir("mmcblk0", 0o755, |dir| {
225 add_stub_attributes(dir, &["size"]);
226 });
227 });
228 },
229 );
230
231 registry.add_bus_device(
234 "soc0".into(),
235 None,
236 self.get_or_create_bus("soc".into()),
237 |device, dir| {
238 build_device_directory(device, dir);
239 add_stub_attributes(dir, &["revision", "serial_number"]);
240 },
241 );
242 }
243
244 fn fs(&self) -> &FileSystemHandle {
245 self.fs.get().expect("sysfs should be initialized")
246 }
247
248 pub fn platform_bus(&self) -> Bus {
250 self.get_or_create_bus("platform".into())
251 }
252
253 pub fn virtual_device(&self) -> Device {
255 self.virtual_device
256 .get_or_init(|| {
257 self.create_device(
258 "virtual".into(),
259 None,
260 None,
261 None,
262 |_, _| {},
263 )
264 })
265 .clone()
266 }
267
268 pub fn platform_device(&self) -> Device {
270 self.platform_device
271 .get_or_init(|| {
272 self.create_device(
273 "platform".into(),
274 None,
275 None,
276 None,
277 build_device_directory,
278 )
279 })
280 .clone()
281 }
282
283 pub fn system_device(&self) -> Device {
287 self.system_device
288 .get_or_init(|| {
289 self.create_device(
290 "system".into(),
291 None,
292 None,
293 None,
294 |_, _| {},
295 )
296 })
297 .clone()
298 }
299
300 pub fn soc_device(&self) -> Device {
302 self.soc_device
305 .get_or_init(|| {
306 self.create_device(
307 "soc".into(),
308 Some(self.platform_device()),
309 Some(self.platform_bus().into()),
310 None,
311 build_device_directory,
312 )
313 })
314 .clone()
315 }
316
317 pub fn block_class(&self) -> Class {
319 self.get_or_create_class("block".into())
320 }
321
322 pub fn thermal_class(&self) -> Class {
324 self.get_or_create_class("thermal".into())
325 }
326
327 pub fn graphics_class(&self) -> Class {
329 self.get_or_create_class("graphics".into())
330 }
331
332 pub fn input_class(&self) -> Class {
334 self.get_or_create_class("input".into())
335 }
336
337 pub fn mem_class(&self) -> Class {
339 self.get_or_create_class("mem".into())
340 }
341
342 pub fn net_class(&self) -> Class {
344 self.get_or_create_class("net".into())
345 }
346
347 pub fn misc_class(&self) -> Class {
349 self.get_or_create_class("misc".into())
350 }
351
352 pub fn tty_class(&self) -> Class {
354 self.get_or_create_class("tty".into())
355 }
356
357 pub fn dma_heap_class(&self) -> Class {
359 self.get_or_create_class("dma_heap".into())
360 }
361
362 pub fn starnix_class(&self) -> Class {
370 self.get_or_create_class("starnix".into())
371 }
372
373 pub fn rtc_class(&self) -> Class {
377 self.get_or_create_class("rtc".into())
378 }
379
380 fn ensure_dir(&self, path: &[&FsStr]) -> Arc<SimpleDirectory> {
381 let fs = self.fs();
382 let mut dir = self.root.clone();
383 for component in path {
384 dir = dir.subdir(fs, component, 0o755);
385 }
386 dir
387 }
388
389 fn lookup_dir(&self, path: &[&FsStr]) -> Option<Arc<SimpleDirectory>> {
390 let mut dir = self.root.clone();
391 for component in path {
392 dir = dir.get_dir(component)?;
393 }
394 Some(dir)
395 }
396
397 pub fn get_or_create_bus(&self, name: &FsStr) -> Bus {
401 let name = name.to_owned();
402 let devices = self.ensure_dir(&[b"bus".into(), name.as_ref(), b"devices".into()]);
403 Bus::new(name, devices)
404 }
405
406 pub fn get_or_create_class(&self, name: &FsStr) -> Class {
410 let name = name.to_owned();
411 let devices = self.ensure_dir(&[b"class".into(), name.as_ref()]);
412 Class::new(name, devices)
413 }
414
415 pub fn class_with_dir(
416 &self,
417 name: &FsStr,
418 build_directory: impl FnOnce(&SimpleDirectoryMutator),
419 ) -> Class {
420 let class = self.get_or_create_class(name);
421 class.devices().edit(self.fs(), build_directory);
422 class
423 }
424
425 pub(super) fn create_device(
436 &self,
437 name: &FsStr,
438 parent: Option<Device>,
439 subsystem: Option<Subsystem>,
440 metadata: Option<DeviceMetadata>,
441 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
442 ) -> Device {
443 let parent = match (parent, &subsystem) {
444 (None, Some(Subsystem::Class(_))) => Some(self.virtual_device()),
445 (parent, _) => parent,
446 };
447 let dir = if let Some(glue_dir) =
448 Device::glue_dir_name_for(parent.as_ref(), subsystem.as_ref())
449 {
450 let parent_dir = parent
451 .as_ref()
452 .and_then(Device::dir)
453 .expect("parent device directory exists in sysfs");
454 parent_dir.nested_subdir(self.fs(), glue_dir, 0o755, name, 0o755)
455 } else if let Some(parent) = parent.as_ref() {
456 let parent_dir = parent.dir().expect("parent device directory exists in sysfs");
457 parent_dir.subdir(self.fs(), name, 0o755)
458 } else {
459 self.ensure_dir(&[b"devices".into()]).subdir(self.fs(), name, 0o755)
460 };
461 let device = Device::new(name.to_owned(), parent, subsystem, metadata, dir.clone());
462 dir.edit(self.fs(), |mutator| {
463 build_directory(&device, mutator);
464 });
465 self.add(&device);
466 device
467 }
468
469 fn add(&self, device: &Device) {
470 let name = device.name();
471
472 match device.subsystem() {
474 Some(Subsystem::Bus(bus)) => {
475 bus.devices().edit(self.fs(), |dir| {
476 dir.symlink(name, device.path_from_depth(3).as_ref());
477 });
478 }
479 Some(Subsystem::Class(class)) => {
480 class.devices().edit(self.fs(), |dir| {
481 dir.symlink(name, device.path_from_depth(2).as_ref());
482 });
483 }
484 None => {}
485 }
486
487 if let Some(metadata) = device.metadata() {
488 let device_number = FsString::from(metadata.devt.to_string());
489 let dev_subdir: &FsStr = match metadata.mode {
490 DeviceMode::Block => {
491 self.ensure_dir(&[b"block".into()]).edit(self.fs(), |dir| {
492 dir.symlink(name, device.path_from_depth(1).as_ref());
493 });
494 b"block".into()
495 }
496 DeviceMode::Char => b"char".into(),
497 };
498 self.ensure_dir(&[b"dev".into(), dev_subdir]).edit(self.fs(), |dir| {
499 dir.symlink(device_number.as_ref(), device.path_from_depth(2).as_ref());
500 });
501 }
502 }
503
504 pub(super) fn remove(&self, device: &Device) {
511 let name = device.name();
512 if let Some(metadata) = device.metadata() {
514 let device_number: FsString = metadata.devt.to_string().into();
515 let dev_subdir: &FsStr = match metadata.mode {
516 DeviceMode::Block => {
517 if let Some(block_dir) = self.lookup_dir(&[b"block".into()]) {
518 block_dir.remove(name);
519 }
520 b"block".into()
521 }
522 DeviceMode::Char => b"char".into(),
523 };
524 if let Some(dev_dir) = self.lookup_dir(&[b"dev".into(), dev_subdir]) {
525 dev_dir.remove(device_number.as_ref());
526 }
527 }
528 match device.subsystem() {
529 Some(Subsystem::Bus(bus)) => {
530 bus.devices().remove(name);
531 }
532 Some(Subsystem::Class(class)) => {
533 class.devices().remove(name);
534 }
535 None => {}
536 }
537 if let Some(glue_dir) = device.glue_dir_name() {
539 if let Some(parent_dir) = device.parent().and_then(Device::dir) {
540 parent_dir.remove_from_subdir_if_empty(glue_dir, name);
541 }
542 } else if let Some(parent) = device.parent() {
543 if let Some(parent_dir) = parent.dir() {
544 parent_dir.remove(name);
545 }
546 } else if let Some(devices_dir) = self.lookup_dir(&[b"devices".into()]) {
547 devices_dir.remove(name);
548 }
549 }
550}
551
552impl Default for KObjectStore {
553 fn default() -> Self {
554 Self {
555 root: SimpleDirectory::new(),
556 fs: OnceLock::new(),
557 virtual_device: OnceLock::new(),
558 platform_device: OnceLock::new(),
559 system_device: OnceLock::new(),
560 soc_device: OnceLock::new(),
561 }
562 }
563}
564
565fn add_stub_attributes(dir: &SimpleDirectoryMutator, names: &[&str]) {
570 for name in names {
571 dir.entry(
572 name,
573 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
574 mode!(IFREG, 0o444),
575 );
576 }
577}