starnix_core/device/
kobject_store.rs1use crate::device::DeviceMode;
6use crate::device::kobject::{Bus, Class, Device, DeviceMetadata};
7use crate::fs::sysfs::get_sysfs;
8use crate::task::Kernel;
9use crate::vfs::pseudo::simple_directory::{SimpleDirectory, SimpleDirectoryMutator};
10use crate::vfs::{FileSystemHandle, FsStr, FsString};
11use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked};
12use std::sync::{Arc, OnceLock};
13
14pub struct KObjectStore {
19 pub root: Arc<SimpleDirectory>,
21
22 fs: OnceLock<FileSystemHandle>,
24}
25
26impl KObjectStore {
27 pub fn init<L>(&self, locked: &mut Locked<L>, kernel: &Kernel)
28 where
29 L: LockEqualOrBefore<FileOpsCore>,
30 {
31 self.fs.set(get_sysfs(locked, kernel)).unwrap();
32 }
33
34 fn fs(&self) -> &FileSystemHandle {
35 self.fs.get().expect("sysfs should be initialized")
36 }
37
38 pub fn virtual_bus(&self) -> Bus {
40 let name: FsString = b"virtual".into();
41 let dir = self.ensure_dir(&[b"devices".into(), name.as_ref()]);
42 Bus::new(name, dir, None)
43 }
44
45 pub fn virtual_block_class(&self) -> Class {
47 self.get_or_create_class("block".into(), self.virtual_bus())
48 }
49
50 pub fn virtual_thermal_class(&self) -> Class {
52 self.get_or_create_class("thermal".into(), self.virtual_bus())
53 }
54
55 pub fn graphics_class(&self) -> Class {
57 self.get_or_create_class("graphics".into(), self.virtual_bus())
58 }
59
60 pub fn input_class(&self) -> Class {
62 self.get_or_create_class("input".into(), self.virtual_bus())
63 }
64
65 pub fn mem_class(&self) -> Class {
67 self.get_or_create_class("mem".into(), self.virtual_bus())
68 }
69
70 pub fn net_class(&self) -> Class {
72 self.get_or_create_class("net".into(), self.virtual_bus())
73 }
74
75 pub fn misc_class(&self) -> Class {
77 self.get_or_create_class("misc".into(), self.virtual_bus())
78 }
79
80 pub fn tty_class(&self) -> Class {
82 self.get_or_create_class("tty".into(), self.virtual_bus())
83 }
84
85 pub fn dma_heap_class(&self) -> Class {
87 self.get_or_create_class("dma_heap".into(), self.virtual_bus())
88 }
89
90 pub fn starnix_class(&self) -> Class {
98 self.get_or_create_class("starnix".into(), self.virtual_bus())
99 }
100
101 pub fn rtc_class(&self) -> Class {
105 self.get_or_create_class("rtc".into(), self.virtual_bus())
106 }
107
108 fn ensure_dir(&self, path: &[&FsStr]) -> Arc<SimpleDirectory> {
109 let fs = self.fs();
110 let mut dir = self.root.clone();
111 for component in path {
112 dir = dir.subdir(fs, component, 0o755);
113 }
114 dir
115 }
116
117 fn edit_dir(&self, path: &[&FsStr], callback: impl FnOnce(&SimpleDirectoryMutator)) {
118 let dir = self.ensure_dir(path);
119 let mutator = SimpleDirectoryMutator::new(self.fs().clone(), dir);
120 callback(&mutator);
121 }
122
123 pub fn get_or_create_bus(&self, name: &FsStr) -> Bus {
127 let name = name.to_owned();
128 let dir = self.ensure_dir(&[b"devices".into(), name.as_ref()]);
129 let collection = self.ensure_dir(&[b"bus".into(), name.as_ref(), b"devices".into()]);
130 Bus::new(name, dir, Some(collection))
131 }
132
133 pub fn get_or_create_class(&self, name: &FsStr, bus: Bus) -> Class {
137 let name = name.to_owned();
138 let dir = bus.dir.subdir(self.fs(), name.as_ref(), 0o755);
139 let collection = self.ensure_dir(&[b"class".into(), name.as_ref()]);
140 Class::new(name, dir, bus, collection)
141 }
142
143 pub fn class_with_dir(
144 &self,
145 name: &FsStr,
146 bus: Bus,
147 build_collection: impl FnOnce(&SimpleDirectoryMutator),
148 ) -> Class {
149 let class = self.get_or_create_class(name, bus);
150 let mutator = SimpleDirectoryMutator::new(self.fs().clone(), class.collection.clone());
151 build_collection(&mutator);
152 class
153 }
154
155 fn block(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
156 self.edit_dir(&[b"block".into()], callback);
157 }
158
159 fn dev_block(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
160 self.edit_dir(&[b"dev".into(), b"block".into()], callback);
161 }
162
163 fn dev_char(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
164 self.edit_dir(&[b"dev".into(), b"char".into()], callback);
165 }
166
167 pub(super) fn create_device(
176 &self,
177 name: &FsStr,
178 metadata: Option<DeviceMetadata>,
179 class: Class,
180 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
181 ) -> Device {
182 let device = Device::new(name.to_owned(), class, metadata);
183 device.class.dir.edit(self.fs(), |dir| {
184 dir.subdir2(name, 0o755, |dir| {
185 build_directory(&device, dir);
186 });
187 });
188 self.add(&device);
189 device
190 }
191
192 fn add(&self, device: &Device) {
193 let class = &device.class;
194 let name = device.name.as_ref();
195
196 let up_device = device.path_from_depth(1);
197 let up_up_device = device.path_from_depth(2);
198
199 class.collection.edit(self.fs(), |dir| {
201 dir.symlink(name, up_up_device.as_ref());
202 });
203
204 if let Some(metadata) = &device.metadata {
205 let device_number = FsString::from(metadata.device_type.to_string());
206 match metadata.mode {
207 DeviceMode::Block => {
208 self.block(|dir| dir.symlink(name, up_device.as_ref()));
209 self.dev_block(|dir| {
210 dir.symlink(device_number.as_ref(), up_up_device.as_ref());
211 });
212 }
213 DeviceMode::Char => {
214 self.dev_char(|dir| {
215 dir.symlink(device_number.as_ref(), up_up_device.as_ref());
216 });
217 }
218 }
219 }
220
221 if let Some(bus_collection) = &class.bus.collection {
222 bus_collection.edit(self.fs(), |dir| {
223 dir.symlink(name, device.path_from_depth(3).as_ref());
224 });
225 }
226 }
227
228 pub(super) fn remove(&self, device: &Device) {
235 let name = device.name.as_ref();
236 if let Some(bus_collection) = &device.class.bus.collection {
238 bus_collection.remove(name);
239 }
240 if let Some(metadata) = &device.metadata {
241 let device_number: FsString = metadata.device_type.to_string().into();
242 match metadata.mode {
243 DeviceMode::Block => {
244 self.dev_block(|dir| dir.remove(device_number.as_ref()));
245 self.block(|dir| dir.remove(name));
246 }
247 DeviceMode::Char => {
248 self.dev_char(|dir| dir.remove(device_number.as_ref()));
249 }
250 }
251 }
252 device.class.collection.remove(name);
253 device.class.dir.remove(name);
255 }
256}
257
258impl Default for KObjectStore {
259 fn default() -> Self {
260 Self { root: SimpleDirectory::new(), fs: OnceLock::new() }
261 }
262}