1use crate::device::kobject::{
6 Bus, Class, Device, DeviceMetadata, DeviceSubsystem, UEventAction, UEventContext,
7};
8use crate::device::kobject_store::KObjectStore;
9use crate::fs::devtmpfs::{devtmpfs_create_device, devtmpfs_remove_path};
10use crate::fs::sysfs::build_device_directory;
11use crate::task::{CurrentTask, Kernel, register_delayed_release};
12use crate::vfs::pseudo::simple_directory::SimpleDirectoryMutator;
13use crate::vfs::pseudo::stub_empty_file::StubEmptyFile;
14use crate::vfs::{FileOps, FsStr, FsString, NamespaceNode};
15use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
16use starnix_logging::{bug_ref, log_error};
17use starnix_sync::{
18 DeviceRegistryListenersLock, DeviceRegistryStateLevel, LockDepGuard, LockDepMutex,
19 MappedLockDepGuard,
20};
21use starnix_types::ownership::{Releasable, ReleaseGuard};
22use starnix_uapi::as_any::AsAny;
23use starnix_uapi::device_id::{DYN_MAJOR_RANGE, DeviceId, MISC_DYNANIC_MINOR_RANGE, MISC_MAJOR};
24use starnix_uapi::error;
25use starnix_uapi::errors::Errno;
26use starnix_uapi::file_mode::mode;
27use starnix_uapi::open_flags::OpenFlags;
28use std::collections::btree_map::{BTreeMap, Entry};
29use std::ops::{Deref, Range};
30use std::sync::Arc;
31
32use dyn_clone::{DynClone, clone_trait_object};
33
34const CHRDEV_MINOR_MAX: u32 = 256;
35const BLKDEV_MINOR_MAX: u32 = 2u32.pow(20);
36
37#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
39pub enum DeviceMode {
40 Char,
42
43 Block,
45}
46
47impl DeviceMode {
48 fn minor_count(&self) -> u32 {
50 match self {
51 Self::Char => CHRDEV_MINOR_MAX,
52 Self::Block => BLKDEV_MINOR_MAX,
53 }
54 }
55
56 pub fn minor_range(&self) -> Range<u32> {
58 0..self.minor_count()
59 }
60}
61
62pub trait DeviceOps: DynClone + Send + Sync + AsAny + 'static {
63 fn open(
68 &self,
69 current_task: &CurrentTask,
70 devt: DeviceId,
71 node: &NamespaceNode,
72 flags: OpenFlags,
73 ) -> Result<Box<dyn FileOps>, Errno>;
74}
75
76clone_trait_object!(DeviceOps);
77
78impl<F> DeviceOps for F
81where
82 F: Clone
83 + Send
84 + Sync
85 + Clone
86 + Fn(&CurrentTask, DeviceId, &NamespaceNode, OpenFlags) -> Result<Box<dyn FileOps>, Errno>
87 + 'static,
88{
89 fn open(
90 &self,
91 current_task: &CurrentTask,
92 id: DeviceId,
93 node: &NamespaceNode,
94 flags: OpenFlags,
95 ) -> Result<Box<dyn FileOps>, Errno> {
96 self(current_task, id, node, flags)
97 }
98}
99
100pub fn simple_device_ops<T: Default + FileOps + 'static>(
102 _current_task: &CurrentTask,
103 _id: DeviceId,
104 _node: &NamespaceNode,
105 _flags: OpenFlags,
106) -> Result<Box<dyn FileOps>, Errno> {
107 Ok(Box::new(T::default()))
108}
109
110pub type DeviceListenerKey = u64;
113
114pub trait DeviceListener: Send + Sync {
121 fn on_device_event(&self, action: UEventAction, device: Device, context: UEventContext);
122}
123
124impl<F> DeviceListener for F
126where
127 F: Fn(UEventAction, Device, UEventContext) + Send + Sync,
128{
129 fn on_device_event(&self, action: UEventAction, device: Device, context: UEventContext) {
130 self(action, device, context);
131 }
132}
133
134pub struct DeviceOpsWrapper(Box<dyn DeviceOps>);
135impl ReleaserAction<DeviceOpsWrapper> for DeviceOpsWrapper {
136 fn release(device_ops: ReleaseGuard<DeviceOpsWrapper>) {
137 register_delayed_release(device_ops);
138 }
139}
140impl Deref for DeviceOpsWrapper {
141 type Target = dyn DeviceOps;
142 fn deref(&self) -> &Self::Target {
143 self.0.deref()
144 }
145}
146pub type DeviceReleaser = ObjectReleaser<DeviceOpsWrapper, DeviceOpsWrapper>;
147pub type DeviceHandle = Arc<DeviceReleaser>;
148impl Releasable for DeviceOpsWrapper {
149 type Context<'a> = &'a CurrentTask;
150
151 fn release<'a>(self, _context: &'a CurrentTask) {}
152}
153
154struct DeviceEntry {
156 name: FsString,
160
161 ops: DeviceHandle,
163}
164
165impl DeviceEntry {
166 fn new(name: FsString, ops: impl DeviceOps) -> Self {
167 Self { name, ops: Arc::new(DeviceOpsWrapper(Box::new(ops)).into()) }
168 }
169}
170
171#[derive(Default)]
175struct RegisteredDevices {
176 majors: BTreeMap<u32, DeviceEntry>,
185
186 minors: BTreeMap<DeviceId, DeviceEntry>,
190}
191
192impl RegisteredDevices {
193 fn register_major(&mut self, major: u32, entry: DeviceEntry) -> Result<(), Errno> {
197 if let Entry::Vacant(slot) = self.majors.entry(major) {
198 slot.insert(entry);
199 Ok(())
200 } else {
201 error!(EINVAL)
202 }
203 }
204
205 fn register_minor(&mut self, devt: DeviceId, entry: DeviceEntry) {
209 self.minors.insert(devt, entry);
210 }
211
212 fn unregister_minor(&mut self, devt: DeviceId) {
214 self.minors.remove(&devt);
215 }
216
217 fn get(&self, devt: DeviceId) -> Result<DeviceHandle, Errno> {
224 if let Some(major_device) = self.majors.get(&devt.major()) {
225 Ok(Arc::clone(&major_device.ops))
226 } else if let Some(minor_device) = self.minors.get(&devt) {
227 Ok(Arc::clone(&minor_device.ops))
228 } else {
229 error!(ENODEV)
230 }
231 }
232
233 fn list_major_devices(&self) -> Vec<(u32, FsString)> {
235 self.majors.iter().map(|(major, entry)| (*major, entry.name.clone())).collect()
236 }
237
238 fn list_minor_devices(&self, range: Range<DeviceId>) -> Vec<(DeviceId, FsString)> {
240 self.minors.range(range).map(|(devt, entry)| (devt.clone(), entry.name.clone())).collect()
241 }
242}
243
244pub struct DeviceRegistry {
253 pub objects: KObjectStore,
255
256 state: LockDepMutex<DeviceRegistryState, DeviceRegistryStateLevel>,
258
259 listeners: LockDepMutex<DeviceRegistryListeners, DeviceRegistryListenersLock>,
261}
262struct DeviceRegistryState {
263 char_devices: RegisteredDevices,
265
266 block_devices: RegisteredDevices,
268
269 misc_chardev_allocator: DeviceIdAllocator,
273
274 dyn_chardev_allocator: DeviceIdAllocator,
278
279 next_anon_minor: u32,
281}
282
283#[derive(Default)]
284struct DeviceRegistryListeners {
285 listeners: BTreeMap<u64, Box<dyn DeviceListener>>,
287
288 next_listener_id: u64,
290
291 next_event_id: u64,
293}
294
295impl DeviceRegistry {
296 pub fn add_device(
344 &self,
345 kernel: &Kernel,
346 name: &FsStr,
347 metadata: DeviceMetadata,
348 class: Class,
349 dev_ops: impl DeviceOps,
350 ) -> Device {
351 self.add_device_with_dir(
352 kernel,
353 name,
354 metadata,
355 None,
356 class,
357 build_device_directory,
358 dev_ops,
359 )
360 }
361
362 pub fn add_device_with_dir(
374 &self,
375 kernel: &Kernel,
376 name: &FsStr,
377 metadata: DeviceMetadata,
378 parent: Option<Device>,
379 subsystem: impl Into<DeviceSubsystem>,
380 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
381 dev_ops: impl DeviceOps,
382 ) -> Device {
383 let entry = DeviceEntry::new(name.into(), dev_ops);
384 self.devices(metadata.mode).register_minor(metadata.devt, entry);
385 self.add_major_device(kernel, name, metadata, parent, subsystem, build_directory)
386 }
387
388 pub fn add_misc_device(
397 &self,
398 kernel: &Kernel,
399 name: &FsStr,
400 dev_ops: impl DeviceOps,
401 ) -> Result<Device, Errno> {
402 let devt = self.state.lock().misc_chardev_allocator.allocate()?;
403 let metadata = DeviceMetadata::new(name.into(), devt, DeviceMode::Char);
404 Ok(self.add_device(kernel, name, metadata, self.objects.misc_class(), dev_ops))
405 }
406
407 pub fn add_dyn_device(
419 &self,
420 kernel: &Kernel,
421 name: &FsStr,
422 class: Class,
423 dev_ops: impl DeviceOps,
424 ) -> Result<Device, Errno> {
425 self.add_dyn_device_with_dir(kernel, name, class, build_device_directory, dev_ops)
426 }
427
428 pub fn add_dyn_device_with_dir(
433 &self,
434 kernel: &Kernel,
435 name: &FsStr,
436 class: Class,
437 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
438 dev_ops: impl DeviceOps,
439 ) -> Result<Device, Errno> {
440 self.add_dyn_device_with_devname(kernel, name, name, class, build_directory, dev_ops)
441 }
442
443 pub fn add_dyn_device_with_devname(
449 &self,
450 kernel: &Kernel,
451 name: &FsStr,
452 devname: &FsStr,
453 class: Class,
454 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
455 dev_ops: impl DeviceOps,
456 ) -> Result<Device, Errno> {
457 let devt = self.state.lock().dyn_chardev_allocator.allocate()?;
458 let metadata = DeviceMetadata::new(devname.into(), devt, DeviceMode::Char);
459 Ok(self.add_device_with_dir(
460 kernel,
461 name,
462 metadata,
463 None,
464 class,
465 build_directory,
466 dev_ops,
467 ))
468 }
469
470 pub fn register_silent_dyn_device(
477 &self,
478 name: &FsStr,
479 dev_ops: impl DeviceOps,
480 ) -> Result<DeviceMetadata, Errno> {
481 let devt = self.state.lock().dyn_chardev_allocator.allocate()?;
482 let metadata = DeviceMetadata::new(name.into(), devt, DeviceMode::Char);
483 let entry = DeviceEntry::new(name.into(), dev_ops);
484 self.devices(metadata.mode).register_minor(metadata.devt, entry);
485 Ok(metadata)
486 }
487
488 pub fn add_major_device(
498 &self,
499 kernel: &Kernel,
500 name: &FsStr,
501 metadata: DeviceMetadata,
502 parent: Option<Device>,
503 subsystem: impl Into<DeviceSubsystem>,
504 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
505 ) -> Device {
506 self.devices(metadata.mode).get(metadata.devt).expect("device is registered");
507 let device = self.objects.create_device(
508 name,
509 parent,
510 Some(subsystem.into()),
511 Some(metadata.clone()),
512 build_directory,
513 );
514
515 if kernel.features.devtmpfs {
516 if let Err(err) = devtmpfs_create_device(kernel, metadata) {
517 log_error!("Cannot create device {:?} in devtmpfs ({:?})", device, err);
518 }
519 }
520 self.dispatch_uevent(UEventAction::Add, device.clone());
521 device
522 }
523
524 pub fn add_net_device(&self, name: &FsStr) -> Device {
541 self.add_numberless_device(
542 name,
543 None,
544 self.objects.net_class(),
545 |device, dir| {
546 build_device_directory(device, dir);
547 dir.entry(
548 "address",
549 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
550 mode!(IFREG, 0o444),
551 );
552 },
553 )
554 }
555
556 fn add_device_without_metadata(
557 &self,
558 name: &FsStr,
559 parent: Option<Device>,
560 subsystem: Option<DeviceSubsystem>,
561 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
562 ) -> Device {
563 let device = self.objects.create_device(
564 name,
565 parent,
566 subsystem,
567 None,
568 build_directory,
569 );
570 self.dispatch_uevent(UEventAction::Add, device.clone());
571 device
572 }
573
574 pub fn add_subsystemless_device(
584 &self,
585 name: &FsStr,
586 parent: Option<Device>,
587 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
588 ) -> Device {
589 self.add_device_without_metadata(name, parent, None, build_directory)
590 }
591
592 pub fn add_bus_device(
601 &self,
602 name: &FsStr,
603 parent: Option<Device>,
604 bus: Bus,
605 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
606 ) -> Device {
607 self.add_device_without_metadata(name, parent, Some(bus.into()), build_directory)
608 }
609
610 pub fn add_numberless_device(
623 &self,
624 name: &FsStr,
625 parent: Option<Device>,
626 class: Class,
627 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
628 ) -> Device {
629 self.add_device_without_metadata(name, parent, Some(class.into()), build_directory)
630 }
631
632 pub fn remove_device(&self, current_task: &CurrentTask, device: Device) {
639 if let Some(metadata) = device.metadata() {
640 if current_task.kernel().features.devtmpfs {
641 if let Err(err) = devtmpfs_remove_path(current_task, metadata.devname.as_ref()) {
642 log_error!("Cannot remove device {:?} ({:?})", device, err);
643 }
644 }
645 }
646
647 self.objects.remove(&device);
648
649 if let Some(metadata) = device.metadata() {
650 let mut state = self.state.lock();
651 match metadata.mode {
652 DeviceMode::Char => {
653 state.char_devices.unregister_minor(metadata.devt);
654 state.misc_chardev_allocator.free(metadata.devt);
655 state.dyn_chardev_allocator.free(metadata.devt);
656 }
657 DeviceMode::Block => {
658 state.block_devices.unregister_minor(metadata.devt);
659 }
660 }
661 }
662
663 self.dispatch_uevent(UEventAction::Remove, device);
664 }
665
666 pub fn list_major_devices(&self, mode: DeviceMode) -> Vec<(u32, FsString)> {
669 self.devices(mode).list_major_devices()
670 }
671
672 pub fn list_minor_devices(
674 &self,
675 mode: DeviceMode,
676 range: Range<DeviceId>,
677 ) -> Vec<(DeviceId, FsString)> {
678 self.devices(mode).list_minor_devices(range)
679 }
680
681 fn devices<'a>(&'a self, mode: DeviceMode) -> MappedLockDepGuard<'a, RegisteredDevices> {
683 LockDepGuard::map(self.state.lock(), |state| match mode {
684 DeviceMode::Char => &mut state.char_devices,
685 DeviceMode::Block => &mut state.block_devices,
686 })
687 }
688
689 pub fn register_major<'a>(
695 &self,
696 name: FsString,
697 mode: DeviceMode,
698 major: u32,
699 dev_ops: impl DeviceOps,
700 ) -> Result<(), Errno> {
701 let entry = DeviceEntry::new(name, dev_ops);
702 self.devices(mode).register_major(major, entry)
703 }
704
705 pub fn next_anonymous_dev_id<'a>(&self) -> DeviceId {
707 let mut state = self.state.lock();
708 let id = DeviceId::new(0, state.next_anon_minor);
709 state.next_anon_minor += 1;
710 id
711 }
712
713 pub fn register_listener<'a>(
715 &self,
716 listener: impl DeviceListener + 'static,
717 ) -> DeviceListenerKey {
718 let mut listeners = self.listeners.lock();
719 let key = listeners.next_listener_id;
720 listeners.next_listener_id += 1;
721 listeners.listeners.insert(key, Box::new(listener));
722 key
723 }
724
725 pub fn unregister_listener<'a>(&self, key: &DeviceListenerKey) {
727 self.listeners.lock().listeners.remove(key);
728 }
729
730 pub fn dispatch_uevent<'a>(&self, action: UEventAction, device: Device) {
733 let mut listeners = self.listeners.lock();
734 let event_id = listeners.next_event_id;
735 listeners.next_event_id += 1;
736 let context = UEventContext { seqnum: event_id };
737 for listener in listeners.listeners.values() {
738 listener.on_device_event(action, device.clone(), context);
739 }
740 }
741
742 pub fn open_device(
746 &self,
747 current_task: &CurrentTask,
748 node: &NamespaceNode,
749 flags: OpenFlags,
750 devt: DeviceId,
751 mode: DeviceMode,
752 ) -> Result<Box<dyn FileOps>, Errno> {
753 let dev_ops = self.devices(mode).get(devt)?;
754 dev_ops.open(current_task, devt, node, flags)
755 }
756
757 pub fn get_device(&self, devt: DeviceId, mode: DeviceMode) -> Result<DeviceHandle, Errno> {
758 self.devices(mode).get(devt)
759 }
760}
761
762impl Default for DeviceRegistry {
763 fn default() -> Self {
764 let misc_available = vec![DeviceId::new_range(MISC_MAJOR, MISC_DYNANIC_MINOR_RANGE)];
765 let dyn_available = DYN_MAJOR_RANGE
766 .map(|major| DeviceId::new_range(major, DeviceMode::Char.minor_range()))
767 .rev()
768 .collect();
769 let state = DeviceRegistryState {
770 char_devices: Default::default(),
771 block_devices: Default::default(),
772 misc_chardev_allocator: DeviceIdAllocator::new(misc_available),
773 dyn_chardev_allocator: DeviceIdAllocator::new(dyn_available),
774 next_anon_minor: 1,
775 };
776 Self { objects: Default::default(), state: state.into(), listeners: Default::default() }
777 }
778}
779
780struct DeviceIdAllocator {
782 ranges: Vec<Range<DeviceId>>,
784
785 freelist: Vec<Range<DeviceId>>,
789}
790
791impl DeviceIdAllocator {
792 fn new(mut available: Vec<Range<DeviceId>>) -> Self {
796 let ranges = available.clone();
797 available.reverse();
798 Self { ranges, freelist: available }
799 }
800
801 fn allocate(&mut self) -> Result<DeviceId, Errno> {
803 let Some(range) = self.freelist.pop() else {
804 return error!(ENOMEM);
805 };
806 let allocated = range.start;
807 if let Some(next) = allocated.next_minor() {
808 if next < range.end {
809 self.freelist.push(next..range.end);
810 }
811 }
812 Ok(allocated)
813 }
814
815 fn free(&mut self, id: DeviceId) {
819 if !self.ranges.iter().any(|range| range.contains(&id)) {
820 return;
821 }
822 let Some(next) = id.next_minor() else {
823 return;
824 };
825 if self.freelist.iter().any(|range| range.start <= id && id < range.end) {
826 return;
827 };
828 let mut new_range = id..next;
831 if let Some(idx) = self.freelist.iter().position(|range| range.end == new_range.start) {
832 let prev = self.freelist.remove(idx);
833 new_range.start = prev.start;
834 }
835 if let Some(idx) = self.freelist.iter().position(|range| range.start == new_range.end) {
836 self.freelist[idx].start = new_range.start;
837 } else {
838 self.freelist.push(new_range);
839 }
840 }
841}
842
843#[cfg(test)]
844mod tests {
845 use super::*;
846 use crate::device::mem::DevNull;
847 use crate::task::{DelayedReleaser, KernelFeatures};
848 use crate::testing::*;
849 use crate::vfs::*;
850 use starnix_uapi::device_id::{INPUT_MAJOR, MEM_MAJOR};
851
852 #[::fuchsia::test]
853 async fn registry_fails_to_add_duplicate_device() {
854 spawn_kernel_and_run(async |_current_task| {
855 let registry = DeviceRegistry::default();
856 registry
857 .register_major(
858 "mem".into(),
859 DeviceMode::Char,
860 MEM_MAJOR,
861 simple_device_ops::<DevNull>,
862 )
863 .expect("registers once");
864 registry
865 .register_major(
866 "random".into(),
867 DeviceMode::Char,
868 123,
869 simple_device_ops::<DevNull>,
870 )
871 .expect("registers unique");
872 registry
873 .register_major(
874 "mem".into(),
875 DeviceMode::Char,
876 MEM_MAJOR,
877 simple_device_ops::<DevNull>,
878 )
879 .expect_err("fail to register duplicate");
880 })
881 .await;
882 }
883
884 #[::fuchsia::test]
885 async fn registry_opens_device() {
886 spawn_kernel_and_run(async |current_task| {
887 let kernel = current_task.kernel();
888 let registry = DeviceRegistry::default();
889 registry
890 .register_major(
891 "mem".into(),
892 DeviceMode::Char,
893 MEM_MAJOR,
894 simple_device_ops::<DevNull>,
895 )
896 .expect("registers unique");
897
898 let fs = create_testfs(&kernel);
899 let node = create_namespace_node_for_testing(&fs, PanickingFsNode);
900
901 assert!(
903 registry
904 .open_device(
905 ¤t_task,
906 &node,
907 OpenFlags::RDONLY,
908 DeviceId::NONE,
909 DeviceMode::Char
910 )
911 .is_err()
912 );
913
914 assert!(
916 registry
917 .open_device(
918 ¤t_task,
919 &node,
920 OpenFlags::RDONLY,
921 DeviceId::NULL,
922 DeviceMode::Block
923 )
924 .is_err()
925 );
926
927 let _ = registry
929 .open_device(
930 ¤t_task,
931 &node,
932 OpenFlags::RDONLY,
933 DeviceId::NULL,
934 DeviceMode::Char,
935 )
936 .expect("opens device");
937 })
938 .await;
939 }
940
941 #[::fuchsia::test]
942 async fn registry_dynamic_misc() {
943 spawn_kernel_and_run(async |current_task| {
944 let kernel = current_task.kernel();
945 fn create_test_device(
946 _current_task: &CurrentTask,
947 _id: DeviceId,
948 _node: &NamespaceNode,
949 _flags: OpenFlags,
950 ) -> Result<Box<dyn FileOps>, Errno> {
951 Ok(Box::new(PanickingFile))
952 }
953
954 let registry = &kernel.device_registry;
955 let device = registry
956 .add_dyn_device(
957 kernel,
958 "test-device".into(),
959 registry.objects.block_class(),
960 create_test_device,
961 )
962 .unwrap();
963 let devt = device.metadata().expect("has metadata").devt;
964 assert!(DYN_MAJOR_RANGE.contains(&devt.major()));
965
966 let fs = create_testfs(&kernel);
967 let node = create_namespace_node_for_testing(&fs, PanickingFsNode);
968 let _ = registry
969 .open_device(¤t_task, &node, OpenFlags::RDONLY, devt, DeviceMode::Char)
970 .expect("opens device");
971 })
972 .await;
973 }
974
975 #[::fuchsia::test]
976 async fn registery_add_class() {
977 spawn_kernel_and_run(async |current_task| {
978 let kernel = current_task.kernel();
979 let registry = &kernel.device_registry;
980 registry
981 .register_major(
982 "input".into(),
983 DeviceMode::Char,
984 INPUT_MAJOR,
985 simple_device_ops::<DevNull>,
986 )
987 .expect("can register input");
988
989 let input_class = registry.objects.get_or_create_class("input".into());
990 registry.add_major_device(
991 kernel,
992 "mouse".into(),
993 DeviceMetadata::new(
994 "mouse".into(),
995 DeviceId::new(INPUT_MAJOR, 0),
996 DeviceMode::Char,
997 ),
998 None,
999 input_class,
1000 build_device_directory,
1001 );
1002
1003 assert!(registry.objects.root.lookup("class/input/mouse".into()).is_some());
1004 assert!(registry.objects.root.lookup("devices/virtual/input/mouse".into()).is_some());
1005 })
1006 .await;
1007 }
1008
1009 #[::fuchsia::test]
1010 async fn registry_add_bus() {
1011 spawn_kernel_and_run(async |current_task| {
1012 let kernel = current_task.kernel();
1013 let registry = &kernel.device_registry;
1014
1015 let bus = registry.objects.get_or_create_bus("my-bus".into());
1016 let bus_dev = registry.add_bus_device(
1017 "my-device".into(),
1018 None,
1019 bus.clone(),
1020 build_device_directory,
1021 );
1022 assert!(registry.objects.root.lookup("bus/my-bus/devices/my-device".into()).is_some());
1023 assert!(registry.objects.root.lookup("devices/my-device".into()).is_some());
1024
1025 let class = registry.objects.get_or_create_class("my-class".into());
1026 let class_dev = registry.add_numberless_device(
1027 "my-class-dev".into(),
1028 Some(bus_dev.clone()),
1029 class,
1030 build_device_directory,
1031 );
1032 assert!(registry.objects.root.lookup("class/my-class/my-class-dev".into()).is_some());
1033 assert!(
1034 registry
1035 .objects
1036 .root
1037 .lookup("devices/my-device/my-class/my-class-dev".into())
1038 .is_some()
1039 );
1040
1041 let sub_class = registry.objects.get_or_create_class("my-subclass".into());
1042 let child_class_dev = registry.add_numberless_device(
1043 "my-child-class-dev".into(),
1044 Some(class_dev.clone()),
1045 sub_class,
1046 build_device_directory,
1047 );
1048 assert!(
1049 registry
1050 .objects
1051 .root
1052 .lookup("class/my-subclass/my-child-class-dev".into())
1053 .is_some()
1054 );
1055 assert!(
1056 registry
1057 .objects
1058 .root
1059 .lookup("devices/my-device/my-class/my-class-dev/my-child-class-dev".into())
1060 .is_some()
1061 );
1062
1063 registry.remove_device(¤t_task, child_class_dev);
1064 assert!(
1065 registry
1066 .objects
1067 .root
1068 .lookup("class/my-subclass/my-child-class-dev".into())
1069 .is_none()
1070 );
1071 assert!(
1072 registry
1073 .objects
1074 .root
1075 .lookup("devices/my-device/my-class/my-class-dev/my-child-class-dev".into())
1076 .is_none()
1077 );
1078
1079 registry.remove_device(¤t_task, class_dev);
1080 assert!(registry.objects.root.lookup("class/my-class/my-class-dev".into()).is_none());
1081 assert!(
1082 registry
1083 .objects
1084 .root
1085 .lookup("devices/my-device/my-class/my-class-dev".into())
1086 .is_none()
1087 );
1088 assert!(registry.objects.root.lookup("devices/my-device/my-class".into()).is_none());
1089
1090 let bus_dev_check = bus_dev.clone();
1091 registry.remove_device(¤t_task, bus_dev);
1092 assert!(registry.objects.root.lookup("bus/my-bus/devices/my-device".into()).is_none());
1093 assert!(registry.objects.root.lookup("devices/my-device".into()).is_none());
1094 DelayedReleaser::default().apply(¤t_task);
1095 assert!(bus_dev_check.dir().is_none());
1096 })
1097 .await;
1098 }
1099
1100 #[::fuchsia::test]
1101 async fn registry_add_root_and_child_bus_device() {
1102 spawn_kernel_and_run(async |current_task| {
1103 let kernel = current_task.kernel();
1104 let registry = &kernel.device_registry;
1105
1106 let root_dev = registry.add_subsystemless_device(
1107 "my-root".into(),
1108 None,
1109 build_device_directory,
1110 );
1111 assert!(registry.objects.root.lookup("devices/my-root/uevent".into()).is_some());
1112
1113 let bus = registry.objects.get_or_create_bus("my-bus".into());
1114 let child_bus_dev = registry.add_bus_device(
1115 "my-child".into(),
1116 Some(root_dev.clone()),
1117 bus.clone(),
1118 build_device_directory,
1119 );
1120 assert!(
1121 registry.objects.root.lookup("devices/my-root/my-child/uevent".into()).is_some()
1122 );
1123 assert!(registry.objects.root.lookup("bus/my-bus/devices/my-child".into()).is_some());
1124
1125 let grandchild_bus_dev = registry.add_bus_device(
1126 "my-grandchild".into(),
1127 Some(child_bus_dev.clone()),
1128 bus,
1129 build_device_directory,
1130 );
1131 assert!(
1132 registry
1133 .objects
1134 .root
1135 .lookup("devices/my-root/my-child/my-grandchild/uevent".into())
1136 .is_some()
1137 );
1138 assert!(
1139 registry.objects.root.lookup("bus/my-bus/devices/my-grandchild".into()).is_some()
1140 );
1141
1142 registry.remove_device(¤t_task, grandchild_bus_dev);
1143 assert!(
1144 registry
1145 .objects
1146 .root
1147 .lookup("devices/my-root/my-child/my-grandchild".into())
1148 .is_none()
1149 );
1150 assert!(
1151 registry.objects.root.lookup("bus/my-bus/devices/my-grandchild".into()).is_none()
1152 );
1153
1154 registry.remove_device(¤t_task, child_bus_dev);
1155 assert!(registry.objects.root.lookup("devices/my-root/my-child".into()).is_none());
1156 assert!(registry.objects.root.lookup("bus/my-bus/devices/my-child".into()).is_none());
1157
1158 registry.remove_device(¤t_task, root_dev);
1159 assert!(registry.objects.root.lookup("devices/my-root".into()).is_none());
1160 })
1161 .await;
1162 }
1163
1164 #[::fuchsia::test]
1165 async fn registry_remove_device() {
1166 spawn_kernel_and_run(async |current_task| {
1167 let kernel = current_task.kernel();
1168 let registry = &kernel.device_registry;
1169 registry
1170 .register_major(
1171 "input".into(),
1172 DeviceMode::Char,
1173 INPUT_MAJOR,
1174 simple_device_ops::<DevNull>,
1175 )
1176 .expect("can register input");
1177
1178 let input_class = registry.objects.get_or_create_class("input".into());
1179 let mouse_dev = registry.add_major_device(
1180 kernel,
1181 "mouse".into(),
1182 DeviceMetadata::new(
1183 "mouse".into(),
1184 DeviceId::new(INPUT_MAJOR, 0),
1185 DeviceMode::Char,
1186 ),
1187 None,
1188 input_class.clone(),
1189 build_device_directory,
1190 );
1191 let keyboard_dev = registry.add_major_device(
1192 kernel,
1193 "keyboard".into(),
1194 DeviceMetadata::new(
1195 "keyboard".into(),
1196 DeviceId::new(INPUT_MAJOR, 1),
1197 DeviceMode::Char,
1198 ),
1199 None,
1200 input_class,
1201 build_device_directory,
1202 );
1203
1204 assert!(registry.objects.root.lookup("devices/virtual/input/mouse".into()).is_some());
1205 assert!(
1206 registry.objects.root.lookup("devices/virtual/input/keyboard".into()).is_some()
1207 );
1208 assert!(registry.objects.root.lookup("class/input/mouse".into()).is_some());
1209 assert!(registry.objects.root.lookup("class/input/keyboard".into()).is_some());
1210
1211 registry.remove_device(¤t_task, mouse_dev);
1212
1213 assert!(registry.objects.root.lookup("devices/virtual/input/mouse".into()).is_none());
1214 assert!(registry.objects.root.lookup("devices/virtual/input".into()).is_some());
1215 assert!(registry.objects.root.lookup("class/input/mouse".into()).is_none());
1216
1217 registry.remove_device(¤t_task, keyboard_dev.clone());
1218
1219 assert!(
1220 registry.objects.root.lookup("devices/virtual/input/keyboard".into()).is_none()
1221 );
1222 assert!(registry.objects.root.lookup("devices/virtual/input".into()).is_none());
1223 assert!(registry.objects.root.lookup("class/input/keyboard".into()).is_none());
1224
1225 registry.objects.remove(&keyboard_dev);
1227 assert!(registry.objects.root.lookup("devices/virtual/input".into()).is_none());
1228 })
1229 .await;
1230 }
1231
1232 #[::fuchsia::test]
1233 async fn registry_add_and_remove_numberless_device() {
1234 spawn_kernel_and_run(async |current_task| {
1235 let kernel = current_task.kernel();
1236 let registry = &kernel.device_registry;
1237
1238 let cooling_device = registry.add_numberless_device(
1239 "cooling_device0".into(),
1240 None,
1241 registry.objects.thermal_class(),
1242 build_device_directory,
1243 );
1244
1245 assert!(registry.objects.root.lookup("class/thermal/cooling_device0".into()).is_some());
1246 assert!(
1247 registry
1248 .objects
1249 .root
1250 .lookup("devices/virtual/thermal/cooling_device0".into())
1251 .is_some()
1252 );
1253
1254 registry.remove_device(¤t_task, cooling_device);
1255
1256 assert!(registry.objects.root.lookup("class/thermal/cooling_device0".into()).is_none());
1257 assert!(
1258 registry
1259 .objects
1260 .root
1261 .lookup("devices/virtual/thermal/cooling_device0".into())
1262 .is_none()
1263 );
1264 assert!(registry.objects.root.lookup("devices/virtual/thermal".into()).is_none());
1265 })
1266 .await;
1267 }
1268
1269 #[::fuchsia::test]
1270 async fn registry_add_and_remove_net_device() {
1271 spawn_kernel_and_run(async |current_task| {
1272 let kernel = current_task.kernel();
1273 let registry = &kernel.device_registry;
1274
1275 let wlan0 = registry.add_net_device("wlan0".into());
1276 assert!(registry.objects.root.lookup("class/net/wlan0".into()).is_some());
1277 assert!(
1278 registry.objects.root.lookup("devices/virtual/net/wlan0/address".into()).is_some()
1279 );
1280 assert!(
1281 registry.objects.root.lookup("devices/virtual/net/wlan0/uevent".into()).is_some()
1282 );
1283
1284 registry.remove_device(¤t_task, wlan0);
1285 assert!(registry.objects.root.lookup("class/net/wlan0".into()).is_none());
1286 assert!(registry.objects.root.lookup("devices/virtual/net/wlan0".into()).is_none());
1287 })
1288 .await;
1289 }
1290
1291 #[::fuchsia::test]
1292 async fn registry_remove_minor_device() {
1293 spawn_kernel_with_features_and_run(
1294 async |current_task| {
1295 let kernel = current_task.kernel();
1296 let registry = &kernel.device_registry;
1297
1298 let dev = registry
1299 .add_misc_device(kernel, "test_misc".into(), simple_device_ops::<DevNull>)
1300 .expect("add misc device");
1301 let devt = dev.metadata().expect("metadata").devt;
1302
1303 assert!(registry.get_device(devt, DeviceMode::Char).is_ok());
1304
1305 registry.remove_device(¤t_task, dev);
1306
1307 assert_eq!(registry.get_device(devt, DeviceMode::Char).map(|_| ()), error!(ENODEV));
1308
1309 let dev2 = registry
1311 .add_misc_device(kernel, "test_misc".into(), simple_device_ops::<DevNull>)
1312 .expect("re-add misc device");
1313 assert_eq!(dev2.metadata().expect("metadata").devt, devt);
1314 registry.remove_device(¤t_task, dev2);
1315 },
1316 KernelFeatures { devtmpfs: true, ..Default::default() },
1317 )
1318 .await;
1319 }
1320
1321 #[::fuchsia::test]
1322 async fn registry_remove_dyn_device_recycles_device_id() {
1323 spawn_kernel_with_features_and_run(
1324 async |current_task| {
1325 let kernel = current_task.kernel();
1326 let registry = &kernel.device_registry;
1327 let class = registry.objects.get_or_create_class("test_dyn_class".into());
1328
1329 let dev1 = registry
1330 .add_dyn_device(
1331 kernel,
1332 "test_dyn_0".into(),
1333 class.clone(),
1334 simple_device_ops::<DevNull>,
1335 )
1336 .expect("add first dyn device");
1337 let dev2 = registry
1338 .add_dyn_device(
1339 kernel,
1340 "test_dyn_1".into(),
1341 class.clone(),
1342 simple_device_ops::<DevNull>,
1343 )
1344 .expect("add second dyn device");
1345 let devt1 = dev1.metadata().expect("metadata").devt;
1346 let devt2 = dev2.metadata().expect("metadata").devt;
1347 assert_ne!(devt1, devt2);
1348
1349 registry.remove_device(¤t_task, dev1);
1351 registry.remove_device(¤t_task, dev2);
1352
1353 let dev1_rebound = registry
1354 .add_dyn_device(
1355 kernel,
1356 "test_dyn_0".into(),
1357 class,
1358 simple_device_ops::<DevNull>,
1359 )
1360 .expect("re-add dyn device");
1361 assert_eq!(dev1_rebound.metadata().expect("metadata").devt, devt1);
1362 registry.remove_device(¤t_task, dev1_rebound);
1363 },
1364 KernelFeatures { devtmpfs: true, ..Default::default() },
1365 )
1366 .await;
1367 }
1368
1369 #[::fuchsia::test]
1370 async fn registry_listener_can_query_registry_and_devtmpfs_collision_does_not_fail_add() {
1371 spawn_kernel_with_features_and_run(
1372 async |current_task| {
1373 let kernel = current_task.kernel();
1374 let registry = &kernel.device_registry;
1375 let observed = Arc::new(starnix_sync::Mutex::new(Vec::new()));
1376 let listener_observed = observed.clone();
1377 let kernel_weak = Arc::downgrade(kernel);
1378 let key = registry.register_listener(
1379 move |action: UEventAction, device: Device, _context: UEventContext| {
1380 let Some(kernel) = kernel_weak.upgrade() else {
1381 return;
1382 };
1383 if let Some(metadata) = device.metadata() {
1384 let is_registered = kernel
1385 .device_registry
1386 .get_device(metadata.devt, metadata.mode)
1387 .is_ok();
1388 listener_observed.lock().push((action, is_registered));
1389 }
1390 },
1391 );
1392
1393 let dev1 = registry
1395 .add_misc_device(kernel, "colliding_dev".into(), simple_device_ops::<DevNull>)
1396 .expect("add first misc device");
1397 let dev2 = registry
1399 .add_misc_device(kernel, "colliding_dev".into(), simple_device_ops::<DevNull>)
1400 .expect("add second misc device despite devtmpfs collision");
1401
1402 registry.remove_device(¤t_task, dev2);
1403 registry.remove_device(¤t_task, dev1);
1404
1405 assert_eq!(
1406 std::mem::take(&mut *observed.lock()),
1407 vec![
1408 (UEventAction::Add, true),
1409 (UEventAction::Add, true),
1410 (UEventAction::Remove, false),
1411 (UEventAction::Remove, false),
1412 ]
1413 );
1414
1415 registry.unregister_listener(&key);
1416 },
1417 KernelFeatures { devtmpfs: true, ..Default::default() },
1418 )
1419 .await;
1420 }
1421
1422 #[::fuchsia::test]
1423 async fn registry_dispatches_uevents_for_bus_and_numberless_devices() {
1424 spawn_kernel_and_run(async |current_task| {
1425 let kernel = current_task.kernel();
1426 let registry = &kernel.device_registry;
1427 let events = Arc::new(starnix_sync::Mutex::new(Vec::new()));
1428 let listener_events = events.clone();
1429 let root = registry.objects.root.clone();
1430 let key = registry.register_listener(
1431 move |action: UEventAction, device: Device, _context: UEventContext| {
1432 let path = device.path_from_depth(0);
1433 match action {
1434 UEventAction::Add => {
1435 assert!(
1436 root.lookup(path.as_ref()).is_some(),
1437 "sysfs entry for {path} must exist when Add uevent is dispatched"
1438 );
1439 }
1440 UEventAction::Remove => {
1441 assert!(
1442 root.lookup(path.as_ref()).is_none(),
1443 "sysfs entry for {path} must be removed before Remove uevent is dispatched"
1444 );
1445 }
1446 _ => {}
1447 }
1448 listener_events.lock().push((
1449 action,
1450 path,
1451 device.subsystem().map(|s| s.name().to_owned()),
1452 ));
1453 },
1454 );
1455
1456 let root_dev = registry.add_subsystemless_device(
1457 "my-root".into(),
1458 None,
1459 build_device_directory,
1460 );
1461 let bus = registry.objects.get_or_create_bus("my-bus".into());
1462 let bus_dev = registry.add_bus_device(
1463 "my-bus-dev".into(),
1464 Some(root_dev.clone()),
1465 bus,
1466 build_device_directory,
1467 );
1468 let class = registry.objects.get_or_create_class("my-class".into());
1469 let class_dev = registry.add_numberless_device(
1470 "my-class-dev".into(),
1471 None,
1472 class,
1473 build_device_directory,
1474 );
1475 let net_dev = registry.add_net_device("wlan0".into());
1476
1477 assert_eq!(
1478 std::mem::take(&mut *events.lock()),
1479 vec![
1480 (UEventAction::Add, "devices/my-root".into(), None),
1481 (
1482 UEventAction::Add,
1483 "devices/my-root/my-bus-dev".into(),
1484 Some("my-bus".into()),
1485 ),
1486 (
1487 UEventAction::Add,
1488 "devices/virtual/my-class/my-class-dev".into(),
1489 Some("my-class".into()),
1490 ),
1491 (UEventAction::Add, "devices/virtual/net/wlan0".into(), Some("net".into())),
1492 ]
1493 );
1494
1495 registry.remove_device(¤t_task, net_dev);
1496 registry.remove_device(¤t_task, class_dev);
1497 registry.remove_device(¤t_task, bus_dev);
1498 registry.remove_device(¤t_task, root_dev);
1499
1500 assert_eq!(
1501 std::mem::take(&mut *events.lock()),
1502 vec![
1503 (UEventAction::Remove, "devices/virtual/net/wlan0".into(), Some("net".into())),
1504 (
1505 UEventAction::Remove,
1506 "devices/virtual/my-class/my-class-dev".into(),
1507 Some("my-class".into()),
1508 ),
1509 (
1510 UEventAction::Remove,
1511 "devices/my-root/my-bus-dev".into(),
1512 Some("my-bus".into()),
1513 ),
1514 (UEventAction::Remove, "devices/my-root".into(), None),
1515 ]
1516 );
1517
1518 registry.unregister_listener(&key);
1519 })
1520 .await;
1521 }
1522
1523 #[::fuchsia::test]
1524 async fn device_edit_dir() {
1525 spawn_kernel_and_run(async |current_task| {
1526 let kernel = current_task.kernel();
1527 let registry = &kernel.device_registry;
1528
1529 let bus = registry.objects.get_or_create_bus("my-bus".into());
1530 let bus_dev = registry.add_bus_device(
1531 "my-device".into(),
1532 None,
1533 bus,
1534 build_device_directory,
1535 );
1536 assert!(registry.objects.root.lookup("devices/my-device/uevent".into()).is_some());
1537 assert!(registry.objects.root.lookup("devices/my-device/extra_attr".into()).is_none());
1538
1539 bus_dev.edit_dir(kernel, |dir| {
1540 dir.entry(
1541 "extra_attr",
1542 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/560216403")),
1543 mode!(IFREG, 0o444),
1544 );
1545 });
1546 assert!(registry.objects.root.lookup("devices/my-device/extra_attr".into()).is_some());
1547
1548 bus_dev.edit_dir(kernel, |dir| {
1549 dir.remove("extra_attr".into());
1550 });
1551 assert!(registry.objects.root.lookup("devices/my-device/extra_attr".into()).is_none());
1552
1553 let bus_dev_check = bus_dev.clone();
1554 registry.remove_device(¤t_task, bus_dev);
1555 DelayedReleaser::default().apply(¤t_task);
1556
1557 bus_dev_check.edit_dir(kernel, |dir| {
1559 dir.entry(
1560 "extra_attr",
1561 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/560216403")),
1562 mode!(IFREG, 0o444),
1563 );
1564 });
1565 assert!(registry.objects.root.lookup("devices/my-device".into()).is_none());
1566 })
1567 .await;
1568 }
1569}