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 std::sync::{Arc, OnceLock};
12
13pub struct KObjectStore {
18 pub root: Arc<SimpleDirectory>,
20
21 fs: OnceLock<FileSystemHandle>,
23}
24
25impl KObjectStore {
26 pub fn init(&self, kernel: &Kernel) {
27 self.fs.set(get_sysfs(kernel)).unwrap();
28 }
29
30 fn fs(&self) -> &FileSystemHandle {
31 self.fs.get().expect("sysfs should be initialized")
32 }
33
34 pub fn virtual_bus(&self) -> Bus {
36 let name: FsString = b"virtual".into();
37 let dir = self.ensure_dir(&[b"devices".into(), name.as_ref()]);
38 Bus::new(name, dir, None)
39 }
40
41 pub fn virtual_block_class(&self) -> Class {
43 self.get_or_create_class("block".into(), self.virtual_bus())
44 }
45
46 pub fn virtual_thermal_class(&self) -> Class {
48 self.get_or_create_class("thermal".into(), self.virtual_bus())
49 }
50
51 pub fn graphics_class(&self) -> Class {
53 self.get_or_create_class("graphics".into(), self.virtual_bus())
54 }
55
56 pub fn input_class(&self) -> Class {
58 self.get_or_create_class("input".into(), self.virtual_bus())
59 }
60
61 pub fn mem_class(&self) -> Class {
63 self.get_or_create_class("mem".into(), self.virtual_bus())
64 }
65
66 pub fn net_class(&self) -> Class {
68 self.get_or_create_class("net".into(), self.virtual_bus())
69 }
70
71 pub fn misc_class(&self) -> Class {
73 self.get_or_create_class("misc".into(), self.virtual_bus())
74 }
75
76 pub fn tty_class(&self) -> Class {
78 self.get_or_create_class("tty".into(), self.virtual_bus())
79 }
80
81 pub fn dma_heap_class(&self) -> Class {
83 self.get_or_create_class("dma_heap".into(), self.virtual_bus())
84 }
85
86 pub fn starnix_class(&self) -> Class {
94 self.get_or_create_class("starnix".into(), self.virtual_bus())
95 }
96
97 pub fn rtc_class(&self) -> Class {
101 self.get_or_create_class("rtc".into(), self.virtual_bus())
102 }
103
104 fn ensure_dir(&self, path: &[&FsStr]) -> Arc<SimpleDirectory> {
105 let fs = self.fs();
106 let mut dir = self.root.clone();
107 for component in path {
108 dir = dir.subdir(fs, component, 0o755);
109 }
110 dir
111 }
112
113 fn edit_dir(&self, path: &[&FsStr], callback: impl FnOnce(&SimpleDirectoryMutator)) {
114 let dir = self.ensure_dir(path);
115 let mutator = SimpleDirectoryMutator::new(self.fs().clone(), dir);
116 callback(&mutator);
117 }
118
119 pub fn get_or_create_bus(&self, name: &FsStr) -> Bus {
123 let name = name.to_owned();
124 let dir = self.ensure_dir(&[b"devices".into(), name.as_ref()]);
125 let collection = self.ensure_dir(&[b"bus".into(), name.as_ref(), b"devices".into()]);
126 Bus::new(name, dir, Some(collection))
127 }
128
129 pub fn get_or_create_class(&self, name: &FsStr, bus: Bus) -> Class {
133 let name = name.to_owned();
134 let dir = bus.dir.subdir(self.fs(), name.as_ref(), 0o755);
135 let collection = self.ensure_dir(&[b"class".into(), name.as_ref()]);
136 Class::new(name, dir, bus, collection)
137 }
138
139 pub fn class_with_dir(
140 &self,
141 name: &FsStr,
142 bus: Bus,
143 build_collection: impl FnOnce(&SimpleDirectoryMutator),
144 ) -> Class {
145 let class = self.get_or_create_class(name, bus);
146 let mutator = SimpleDirectoryMutator::new(self.fs().clone(), class.collection.clone());
147 build_collection(&mutator);
148 class
149 }
150
151 fn block(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
152 self.edit_dir(&[b"block".into()], callback);
153 }
154
155 fn dev_block(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
156 self.edit_dir(&[b"dev".into(), b"block".into()], callback);
157 }
158
159 fn dev_char(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
160 self.edit_dir(&[b"dev".into(), b"char".into()], callback);
161 }
162
163 pub(super) fn create_device(
172 &self,
173 name: &FsStr,
174 metadata: Option<DeviceMetadata>,
175 class: Class,
176 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
177 ) -> Device {
178 let device = Device::new(name.to_owned(), class, metadata);
179 device.class.dir.edit(self.fs(), |dir| {
180 dir.subdir2(name, 0o755, |dir| {
181 build_directory(&device, dir);
182 });
183 });
184 self.add(&device);
185 device
186 }
187
188 fn add(&self, device: &Device) {
189 let class = &device.class;
190 let name = device.name.as_ref();
191
192 let up_device = device.path_from_depth(1);
193 let up_up_device = device.path_from_depth(2);
194
195 class.collection.edit(self.fs(), |dir| {
197 dir.symlink(name, up_up_device.as_ref());
198 });
199
200 if let Some(metadata) = &device.metadata {
201 let device_number = FsString::from(metadata.devt.to_string());
202 match metadata.mode {
203 DeviceMode::Block => {
204 self.block(|dir| dir.symlink(name, up_device.as_ref()));
205 self.dev_block(|dir| {
206 dir.symlink(device_number.as_ref(), up_up_device.as_ref());
207 });
208 }
209 DeviceMode::Char => {
210 self.dev_char(|dir| {
211 dir.symlink(device_number.as_ref(), up_up_device.as_ref());
212 });
213 }
214 }
215 }
216
217 if let Some(bus_collection) = &class.bus.collection {
218 bus_collection.edit(self.fs(), |dir| {
219 dir.symlink(name, device.path_from_depth(3).as_ref());
220 });
221 }
222 }
223
224 pub(super) fn remove(&self, device: &Device) {
231 let name = device.name.as_ref();
232 if let Some(bus_collection) = &device.class.bus.collection {
234 bus_collection.remove(name);
235 }
236 if let Some(metadata) = &device.metadata {
237 let device_number: FsString = metadata.devt.to_string().into();
238 match metadata.mode {
239 DeviceMode::Block => {
240 self.dev_block(|dir| dir.remove(device_number.as_ref()));
241 self.block(|dir| dir.remove(name));
242 }
243 DeviceMode::Char => {
244 self.dev_char(|dir| dir.remove(device_number.as_ref()));
245 }
246 }
247 }
248 device.class.collection.remove(name);
249 device.class.dir.remove(name);
251 }
252}
253
254impl Default for KObjectStore {
255 fn default() -> Self {
256 Self { root: SimpleDirectory::new(), fs: OnceLock::new() }
257 }
258}