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 fn ensure_dir(&self, path: &[&FsStr]) -> Arc<SimpleDirectory> {
102 let fs = self.fs();
103 let mut dir = self.root.clone();
104 for component in path {
105 dir = dir.subdir(fs, component, 0o755);
106 }
107 dir
108 }
109
110 fn edit_dir(&self, path: &[&FsStr], callback: impl FnOnce(&SimpleDirectoryMutator)) {
111 let dir = self.ensure_dir(path);
112 let mutator = SimpleDirectoryMutator::new(self.fs().clone(), dir);
113 callback(&mutator);
114 }
115
116 pub fn get_or_create_bus(&self, name: &FsStr) -> Bus {
120 let name = name.to_owned();
121 let dir = self.ensure_dir(&[b"devices".into(), name.as_ref()]);
122 let collection = self.ensure_dir(&[b"bus".into(), name.as_ref(), b"devices".into()]);
123 Bus::new(name, dir, Some(collection))
124 }
125
126 pub fn get_or_create_class(&self, name: &FsStr, bus: Bus) -> Class {
130 let name = name.to_owned();
131 let dir = bus.dir.subdir(self.fs(), name.as_ref(), 0o755);
132 let collection = self.ensure_dir(&[b"class".into(), name.as_ref()]);
133 Class::new(name, dir, bus, collection)
134 }
135
136 pub fn class_with_dir(
137 &self,
138 name: &FsStr,
139 bus: Bus,
140 build_collection: impl FnOnce(&SimpleDirectoryMutator),
141 ) -> Class {
142 let class = self.get_or_create_class(name, bus);
143 let mutator = SimpleDirectoryMutator::new(self.fs().clone(), class.collection.clone());
144 build_collection(&mutator);
145 class
146 }
147
148 fn block(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
149 self.edit_dir(&[b"block".into()], callback);
150 }
151
152 fn dev_block(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
153 self.edit_dir(&[b"dev".into(), b"block".into()], callback);
154 }
155
156 fn dev_char(&self, callback: impl FnOnce(&SimpleDirectoryMutator)) {
157 self.edit_dir(&[b"dev".into(), b"char".into()], callback);
158 }
159
160 pub(super) fn create_device(
169 &self,
170 name: &FsStr,
171 metadata: Option<DeviceMetadata>,
172 class: Class,
173 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
174 ) -> Device {
175 let device = Device::new(name.to_owned(), class, metadata);
176 device.class.dir.edit(self.fs(), |dir| {
177 dir.subdir2(name, 0o755, |dir| {
178 build_directory(&device, dir);
179 });
180 });
181 self.add(&device);
182 device
183 }
184
185 fn add(&self, device: &Device) {
186 let class = &device.class;
187 let name = device.name.as_ref();
188
189 let up_device = device.path_from_depth(1);
190 let up_up_device = device.path_from_depth(2);
191
192 class.collection.edit(self.fs(), |dir| {
194 dir.symlink(name, up_up_device.as_ref());
195 });
196
197 if let Some(metadata) = &device.metadata {
198 let device_number = FsString::from(metadata.device_type.to_string());
199 match metadata.mode {
200 DeviceMode::Block => {
201 self.block(|dir| dir.symlink(name, up_device.as_ref()));
202 self.dev_block(|dir| {
203 dir.symlink(device_number.as_ref(), up_up_device.as_ref());
204 });
205 }
206 DeviceMode::Char => {
207 self.dev_char(|dir| {
208 dir.symlink(device_number.as_ref(), up_up_device.as_ref());
209 });
210 }
211 }
212 }
213
214 if let Some(bus_collection) = &class.bus.collection {
215 bus_collection.edit(self.fs(), |dir| {
216 dir.symlink(name, device.path_from_depth(3).as_ref());
217 });
218 }
219 }
220
221 pub(super) fn remove(&self, device: &Device) {
228 let name = device.name.as_ref();
229 if let Some(bus_collection) = &device.class.bus.collection {
231 bus_collection.remove(name);
232 }
233 if let Some(metadata) = &device.metadata {
234 let device_number: FsString = metadata.device_type.to_string().into();
235 match metadata.mode {
236 DeviceMode::Block => {
237 self.dev_block(|dir| dir.remove(device_number.as_ref()));
238 self.block(|dir| dir.remove(name));
239 }
240 DeviceMode::Char => {
241 self.dev_char(|dir| dir.remove(device_number.as_ref()));
242 }
243 }
244 }
245 device.class.collection.remove(name);
246 device.class.dir.remove(name);
248 }
249}
250
251impl Default for KObjectStore {
252 fn default() -> Self {
253 Self { root: SimpleDirectory::new(), fs: OnceLock::new() }
254 }
255}