1use crate::device::kobject::{Bus, Class, Device, DeviceMetadata, UEventAction, UEventContext};
6use crate::device::kobject_store::KObjectStore;
7use crate::fs::devtmpfs::{devtmpfs_create_device, devtmpfs_remove_path};
8use crate::fs::sysfs::build_device_directory;
9use crate::task::{CurrentTask, Kernel, register_delayed_release};
10use crate::vfs::pseudo::simple_directory::SimpleDirectoryMutator;
11use crate::vfs::pseudo::stub_empty_file::StubEmptyFile;
12use crate::vfs::{FileOps, FsStr, FsString, NamespaceNode};
13use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
14use starnix_logging::{bug_ref, log_error};
15use starnix_sync::{DeviceRegistryStateLevel, LockDepGuard, LockDepMutex, MappedLockDepGuard};
16use starnix_types::ownership::{Releasable, ReleaseGuard};
17use starnix_uapi::as_any::AsAny;
18use starnix_uapi::device_id::{DYN_MAJOR_RANGE, DeviceId, MISC_DYNANIC_MINOR_RANGE, MISC_MAJOR};
19use starnix_uapi::error;
20use starnix_uapi::errors::Errno;
21use starnix_uapi::file_mode::mode;
22use starnix_uapi::open_flags::OpenFlags;
23use std::collections::btree_map::{BTreeMap, Entry};
24use std::ops::{Deref, Range};
25use std::sync::Arc;
26
27use dyn_clone::{DynClone, clone_trait_object};
28
29const CHRDEV_MINOR_MAX: u32 = 256;
30const BLKDEV_MINOR_MAX: u32 = 2u32.pow(20);
31
32#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
34pub enum DeviceMode {
35 Char,
37
38 Block,
40}
41
42impl DeviceMode {
43 fn minor_count(&self) -> u32 {
45 match self {
46 Self::Char => CHRDEV_MINOR_MAX,
47 Self::Block => BLKDEV_MINOR_MAX,
48 }
49 }
50
51 pub fn minor_range(&self) -> Range<u32> {
53 0..self.minor_count()
54 }
55}
56
57pub trait DeviceOps: DynClone + Send + Sync + AsAny + 'static {
58 fn open(
63 &self,
64 current_task: &CurrentTask,
65 devt: DeviceId,
66 node: &NamespaceNode,
67 flags: OpenFlags,
68 ) -> Result<Box<dyn FileOps>, Errno>;
69}
70
71clone_trait_object!(DeviceOps);
72
73impl<F> DeviceOps for F
76where
77 F: Clone
78 + Send
79 + Sync
80 + Clone
81 + Fn(&CurrentTask, DeviceId, &NamespaceNode, OpenFlags) -> Result<Box<dyn FileOps>, Errno>
82 + 'static,
83{
84 fn open(
85 &self,
86 current_task: &CurrentTask,
87 id: DeviceId,
88 node: &NamespaceNode,
89 flags: OpenFlags,
90 ) -> Result<Box<dyn FileOps>, Errno> {
91 self(current_task, id, node, flags)
92 }
93}
94
95pub fn simple_device_ops<T: Default + FileOps + 'static>(
97 _current_task: &CurrentTask,
98 _id: DeviceId,
99 _node: &NamespaceNode,
100 _flags: OpenFlags,
101) -> Result<Box<dyn FileOps>, Errno> {
102 Ok(Box::new(T::default()))
103}
104
105pub type DeviceListenerKey = u64;
108
109pub trait DeviceListener: Send + Sync {
111 fn on_device_event(&self, action: UEventAction, device: Device, context: UEventContext);
112}
113
114pub struct DeviceOpsWrapper(Box<dyn DeviceOps>);
115impl ReleaserAction<DeviceOpsWrapper> for DeviceOpsWrapper {
116 fn release(device_ops: ReleaseGuard<DeviceOpsWrapper>) {
117 register_delayed_release(device_ops);
118 }
119}
120impl Deref for DeviceOpsWrapper {
121 type Target = dyn DeviceOps;
122 fn deref(&self) -> &Self::Target {
123 self.0.deref()
124 }
125}
126pub type DeviceReleaser = ObjectReleaser<DeviceOpsWrapper, DeviceOpsWrapper>;
127pub type DeviceHandle = Arc<DeviceReleaser>;
128impl Releasable for DeviceOpsWrapper {
129 type Context<'a> = &'a CurrentTask;
130
131 fn release<'a>(self, _context: &'a CurrentTask) {}
132}
133
134struct DeviceEntry {
136 name: FsString,
140
141 ops: DeviceHandle,
143}
144
145impl DeviceEntry {
146 fn new(name: FsString, ops: impl DeviceOps) -> Self {
147 Self { name, ops: Arc::new(DeviceOpsWrapper(Box::new(ops)).into()) }
148 }
149}
150
151#[derive(Default)]
155struct RegisteredDevices {
156 majors: BTreeMap<u32, DeviceEntry>,
165
166 minors: BTreeMap<DeviceId, DeviceEntry>,
170}
171
172impl RegisteredDevices {
173 fn register_major(&mut self, major: u32, entry: DeviceEntry) -> Result<(), Errno> {
177 if let Entry::Vacant(slot) = self.majors.entry(major) {
178 slot.insert(entry);
179 Ok(())
180 } else {
181 error!(EINVAL)
182 }
183 }
184
185 fn register_minor(&mut self, devt: DeviceId, entry: DeviceEntry) {
189 self.minors.insert(devt, entry);
190 }
191
192 fn unregister_minor(&mut self, devt: DeviceId) {
194 self.minors.remove(&devt);
195 }
196
197 fn get(&self, devt: DeviceId) -> Result<DeviceHandle, Errno> {
204 if let Some(major_device) = self.majors.get(&devt.major()) {
205 Ok(Arc::clone(&major_device.ops))
206 } else if let Some(minor_device) = self.minors.get(&devt) {
207 Ok(Arc::clone(&minor_device.ops))
208 } else {
209 error!(ENODEV)
210 }
211 }
212
213 fn list_major_devices(&self) -> Vec<(u32, FsString)> {
215 self.majors.iter().map(|(major, entry)| (*major, entry.name.clone())).collect()
216 }
217
218 fn list_minor_devices(&self, range: Range<DeviceId>) -> Vec<(DeviceId, FsString)> {
220 self.minors.range(range).map(|(devt, entry)| (devt.clone(), entry.name.clone())).collect()
221 }
222}
223
224pub struct DeviceRegistry {
233 pub objects: KObjectStore,
235
236 state: LockDepMutex<DeviceRegistryState, DeviceRegistryStateLevel>,
238}
239struct DeviceRegistryState {
240 char_devices: RegisteredDevices,
242
243 block_devices: RegisteredDevices,
245
246 misc_chardev_allocator: DeviceIdAllocator,
250
251 dyn_chardev_allocator: DeviceIdAllocator,
255
256 next_anon_minor: u32,
258
259 listeners: BTreeMap<u64, Box<dyn DeviceListener>>,
264
265 next_listener_id: u64,
267
268 next_event_id: u64,
270}
271
272impl DeviceRegistry {
273 fn notify_device(&self, kernel: &Kernel, device: Device) -> Result<(), Errno> {
275 if let Some(metadata) = device.metadata() {
276 devtmpfs_create_device(kernel, metadata.clone())?;
277 self.dispatch_uevent(UEventAction::Add, device);
278 }
279 Ok(())
280 }
281
282 pub fn register_device(
329 &self,
330 kernel: &Kernel,
331 name: &FsStr,
332 metadata: DeviceMetadata,
333 class: Class,
334 dev_ops: impl DeviceOps,
335 ) -> Result<Device, Errno> {
336 self.register_device_with_dir(
337 kernel,
338 name,
339 metadata,
340 None,
341 class,
342 build_device_directory,
343 dev_ops,
344 )
345 }
346
347 pub fn register_device_with_dir(
355 &self,
356 kernel: &Kernel,
357 name: &FsStr,
358 metadata: DeviceMetadata,
359 parent: Option<Device>,
360 class: Class,
361 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
362 dev_ops: impl DeviceOps,
363 ) -> Result<Device, Errno> {
364 let entry = DeviceEntry::new(name.into(), dev_ops);
365 self.devices(metadata.mode).register_minor(metadata.devt, entry);
366 self.add_device(kernel, name, metadata, parent, class, build_directory)
367 }
368
369 pub fn register_misc_device(
377 &self,
378 kernel: &Kernel,
379 name: &FsStr,
380 dev_ops: impl DeviceOps,
381 ) -> Result<Device, Errno> {
382 let devt = self.state.lock().misc_chardev_allocator.allocate()?;
383 let metadata = DeviceMetadata::new(name.into(), devt, DeviceMode::Char);
384 self.register_device(kernel, name, metadata, self.objects.misc_class(), dev_ops)
385 }
386
387 pub fn register_dyn_device(
398 &self,
399 kernel: &Kernel,
400 name: &FsStr,
401 class: Class,
402 dev_ops: impl DeviceOps,
403 ) -> Result<Device, Errno> {
404 self.register_dyn_device_with_dir(kernel, name, class, build_device_directory, dev_ops)
405 }
406
407 pub fn register_dyn_device_with_dir(
411 &self,
412 kernel: &Kernel,
413 name: &FsStr,
414 class: Class,
415 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
416 dev_ops: impl DeviceOps,
417 ) -> Result<Device, Errno> {
418 self.register_dyn_device_with_devname(kernel, name, name, class, build_directory, dev_ops)
419 }
420
421 pub fn register_dyn_device_with_devname(
432 &self,
433 kernel: &Kernel,
434 name: &FsStr,
435 devname: &FsStr,
436 class: Class,
437 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
438 dev_ops: impl DeviceOps,
439 ) -> Result<Device, Errno> {
440 let devt = self.state.lock().dyn_chardev_allocator.allocate()?;
441 let metadata = DeviceMetadata::new(devname.into(), devt, DeviceMode::Char);
442 self.register_device_with_dir(
443 kernel,
444 name,
445 metadata,
446 None,
447 class,
448 build_directory,
449 dev_ops,
450 )
451 }
452
453 pub fn register_silent_dyn_device(
460 &self,
461 name: &FsStr,
462 dev_ops: impl DeviceOps,
463 ) -> Result<DeviceMetadata, Errno> {
464 let devt = self.state.lock().dyn_chardev_allocator.allocate()?;
465 let metadata = DeviceMetadata::new(name.into(), devt, DeviceMode::Char);
466 let entry = DeviceEntry::new(name.into(), dev_ops);
467 self.devices(metadata.mode).register_minor(metadata.devt, entry);
468 Ok(metadata)
469 }
470
471 pub fn add_device(
479 &self,
480 kernel: &Kernel,
481 name: &FsStr,
482 metadata: DeviceMetadata,
483 parent: Option<Device>,
484 class: Class,
485 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
486 ) -> Result<Device, Errno> {
487 self.devices(metadata.mode).get(metadata.devt).expect("device is registered");
488 let device = self.objects.create_device(
489 name,
490 parent,
491 Some(class.into()),
492 Some(metadata),
493 build_directory,
494 );
495
496 self.notify_device(kernel, device.clone())?;
497 Ok(device)
498 }
499
500 pub fn add_net_device(&self, name: &FsStr) -> Device {
513 self.add_numberless_device(
514 name,
515 None,
516 self.objects.net_class(),
517 |device, dir| {
518 build_device_directory(device, dir);
519 dir.entry(
520 "address",
521 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
522 mode!(IFREG, 0o444),
523 );
524 },
525 )
526 }
527
528 pub fn remove_net_device(&self, device: Device) {
532 assert!(device.metadata().is_none());
533 self.objects.remove(&device);
534 }
535
536 pub fn add_subsystemless_device(
544 &self,
545 name: &FsStr,
546 parent: Option<Device>,
547 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
548 ) -> Device {
549 self.objects.create_device(
550 name,
551 parent,
552 None,
553 None,
554 build_directory,
555 )
556 }
557
558 pub fn add_bus_device(
566 &self,
567 name: &FsStr,
568 parent: Option<Device>,
569 bus: Bus,
570 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
571 ) -> Device {
572 self.objects.create_device(
573 name,
574 parent,
575 Some(bus.into()),
576 None,
577 build_directory,
578 )
579 }
580
581 pub fn add_numberless_device(
592 &self,
593 name: &FsStr,
594 parent: Option<Device>,
595 class: Class,
596 build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
597 ) -> Device {
598 self.objects.create_device(
599 name,
600 parent,
601 Some(class.into()),
602 None,
603 build_directory,
604 )
605 }
606
607 pub fn remove_device(&self, current_task: &CurrentTask, device: Device) {
611 if let Some(metadata) = device.metadata() {
612 self.dispatch_uevent(UEventAction::Remove, device.clone());
613
614 if let Err(err) = devtmpfs_remove_path(current_task, metadata.devname.as_ref()) {
615 log_error!("Cannot remove device {:?} ({:?})", device, err);
616 }
617
618 self.devices(metadata.mode).unregister_minor(metadata.devt);
619 }
620
621 self.objects.remove(&device);
622 }
623
624 pub fn list_major_devices(&self, mode: DeviceMode) -> Vec<(u32, FsString)> {
627 self.devices(mode).list_major_devices()
628 }
629
630 pub fn list_minor_devices(
632 &self,
633 mode: DeviceMode,
634 range: Range<DeviceId>,
635 ) -> Vec<(DeviceId, FsString)> {
636 self.devices(mode).list_minor_devices(range)
637 }
638
639 fn devices<'a>(&'a self, mode: DeviceMode) -> MappedLockDepGuard<'a, RegisteredDevices> {
641 LockDepGuard::map(self.state.lock(), |state| match mode {
642 DeviceMode::Char => &mut state.char_devices,
643 DeviceMode::Block => &mut state.block_devices,
644 })
645 }
646
647 pub fn register_major<'a>(
653 &self,
654 name: FsString,
655 mode: DeviceMode,
656 major: u32,
657 dev_ops: impl DeviceOps,
658 ) -> Result<(), Errno> {
659 let entry = DeviceEntry::new(name, dev_ops);
660 self.devices(mode).register_major(major, entry)
661 }
662
663 pub fn next_anonymous_dev_id<'a>(&self) -> DeviceId {
665 let mut state = self.state.lock();
666 let id = DeviceId::new(0, state.next_anon_minor);
667 state.next_anon_minor += 1;
668 id
669 }
670
671 pub fn register_listener<'a>(
675 &self,
676 listener: impl DeviceListener + 'static,
677 ) -> DeviceListenerKey {
678 let mut state = self.state.lock();
679 let key = state.next_listener_id;
680 state.next_listener_id += 1;
681 state.listeners.insert(key, Box::new(listener));
682 key
683 }
684
685 pub fn unregister_listener<'a>(&self, key: &DeviceListenerKey) {
687 self.state.lock().listeners.remove(key);
688 }
689
690 pub fn dispatch_uevent<'a>(&self, action: UEventAction, device: Device) {
692 let mut state = self.state.lock();
693 let event_id = state.next_event_id;
694 state.next_event_id += 1;
695 let context = UEventContext { seqnum: event_id };
696 for listener in state.listeners.values() {
697 listener.on_device_event(action, device.clone(), context);
698 }
699 }
700
701 pub fn open_device(
705 &self,
706 current_task: &CurrentTask,
707 node: &NamespaceNode,
708 flags: OpenFlags,
709 devt: DeviceId,
710 mode: DeviceMode,
711 ) -> Result<Box<dyn FileOps>, Errno> {
712 let dev_ops = self.devices(mode).get(devt)?;
713 dev_ops.open(current_task, devt, node, flags)
714 }
715
716 pub fn get_device(&self, devt: DeviceId, mode: DeviceMode) -> Result<DeviceHandle, Errno> {
717 self.devices(mode).get(devt)
718 }
719}
720
721impl Default for DeviceRegistry {
722 fn default() -> Self {
723 let misc_available = vec![DeviceId::new_range(MISC_MAJOR, MISC_DYNANIC_MINOR_RANGE)];
724 let dyn_available = DYN_MAJOR_RANGE
725 .map(|major| DeviceId::new_range(major, DeviceMode::Char.minor_range()))
726 .rev()
727 .collect();
728 let state = DeviceRegistryState {
729 char_devices: Default::default(),
730 block_devices: Default::default(),
731 misc_chardev_allocator: DeviceIdAllocator::new(misc_available),
732 dyn_chardev_allocator: DeviceIdAllocator::new(dyn_available),
733 next_anon_minor: 1,
734 listeners: Default::default(),
735 next_listener_id: 0,
736 next_event_id: 0,
737 };
738 Self { objects: Default::default(), state: state.into() }
739 }
740}
741
742struct DeviceIdAllocator {
744 freelist: Vec<Range<DeviceId>>,
748}
749
750impl DeviceIdAllocator {
751 fn new(mut available: Vec<Range<DeviceId>>) -> Self {
755 available.reverse();
756 Self { freelist: available }
757 }
758
759 fn allocate(&mut self) -> Result<DeviceId, Errno> {
763 let Some(range) = self.freelist.pop() else {
764 return error!(ENOMEM);
765 };
766 let allocated = range.start;
767 if let Some(next) = allocated.next_minor() {
768 if next < range.end {
769 self.freelist.push(next..range.end);
770 }
771 }
772 Ok(allocated)
773 }
774}
775
776#[cfg(test)]
777mod tests {
778 use super::*;
779 use crate::device::mem::DevNull;
780 use crate::task::DelayedReleaser;
781 use crate::testing::*;
782 use crate::vfs::*;
783 use starnix_uapi::device_id::{INPUT_MAJOR, MEM_MAJOR};
784
785 #[::fuchsia::test]
786 async fn registry_fails_to_add_duplicate_device() {
787 spawn_kernel_and_run(async |_current_task| {
788 let registry = DeviceRegistry::default();
789 registry
790 .register_major(
791 "mem".into(),
792 DeviceMode::Char,
793 MEM_MAJOR,
794 simple_device_ops::<DevNull>,
795 )
796 .expect("registers once");
797 registry
798 .register_major(
799 "random".into(),
800 DeviceMode::Char,
801 123,
802 simple_device_ops::<DevNull>,
803 )
804 .expect("registers unique");
805 registry
806 .register_major(
807 "mem".into(),
808 DeviceMode::Char,
809 MEM_MAJOR,
810 simple_device_ops::<DevNull>,
811 )
812 .expect_err("fail to register duplicate");
813 })
814 .await;
815 }
816
817 #[::fuchsia::test]
818 async fn registry_opens_device() {
819 spawn_kernel_and_run(async |current_task| {
820 let kernel = current_task.kernel();
821 let registry = DeviceRegistry::default();
822 registry
823 .register_major(
824 "mem".into(),
825 DeviceMode::Char,
826 MEM_MAJOR,
827 simple_device_ops::<DevNull>,
828 )
829 .expect("registers unique");
830
831 let fs = create_testfs(&kernel);
832 let node = create_namespace_node_for_testing(&fs, PanickingFsNode);
833
834 assert!(
836 registry
837 .open_device(
838 ¤t_task,
839 &node,
840 OpenFlags::RDONLY,
841 DeviceId::NONE,
842 DeviceMode::Char
843 )
844 .is_err()
845 );
846
847 assert!(
849 registry
850 .open_device(
851 ¤t_task,
852 &node,
853 OpenFlags::RDONLY,
854 DeviceId::NULL,
855 DeviceMode::Block
856 )
857 .is_err()
858 );
859
860 let _ = registry
862 .open_device(
863 ¤t_task,
864 &node,
865 OpenFlags::RDONLY,
866 DeviceId::NULL,
867 DeviceMode::Char,
868 )
869 .expect("opens device");
870 })
871 .await;
872 }
873
874 #[::fuchsia::test]
875 async fn registry_dynamic_misc() {
876 spawn_kernel_and_run(async |current_task| {
877 let kernel = current_task.kernel();
878 fn create_test_device(
879 _current_task: &CurrentTask,
880 _id: DeviceId,
881 _node: &NamespaceNode,
882 _flags: OpenFlags,
883 ) -> Result<Box<dyn FileOps>, Errno> {
884 Ok(Box::new(PanickingFile))
885 }
886
887 let registry = &kernel.device_registry;
888 let device = registry
889 .register_dyn_device(
890 kernel,
891 "test-device".into(),
892 registry.objects.block_class(),
893 create_test_device,
894 )
895 .unwrap();
896 let devt = device.metadata().expect("has metadata").devt;
897 assert!(DYN_MAJOR_RANGE.contains(&devt.major()));
898
899 let fs = create_testfs(&kernel);
900 let node = create_namespace_node_for_testing(&fs, PanickingFsNode);
901 let _ = registry
902 .open_device(¤t_task, &node, OpenFlags::RDONLY, devt, DeviceMode::Char)
903 .expect("opens device");
904 })
905 .await;
906 }
907
908 #[::fuchsia::test]
909 async fn registery_add_class() {
910 spawn_kernel_and_run(async |current_task| {
911 let kernel = current_task.kernel();
912 let registry = &kernel.device_registry;
913 registry
914 .register_major(
915 "input".into(),
916 DeviceMode::Char,
917 INPUT_MAJOR,
918 simple_device_ops::<DevNull>,
919 )
920 .expect("can register input");
921
922 let input_class = registry.objects.get_or_create_class("input".into());
923 registry
924 .add_device(
925 kernel,
926 "mouse".into(),
927 DeviceMetadata::new(
928 "mouse".into(),
929 DeviceId::new(INPUT_MAJOR, 0),
930 DeviceMode::Char,
931 ),
932 None,
933 input_class,
934 build_device_directory,
935 )
936 .expect("add_device");
937
938 assert!(registry.objects.root.lookup("class/input/mouse".into()).is_some());
939 assert!(registry.objects.root.lookup("devices/virtual/input/mouse".into()).is_some());
940 })
941 .await;
942 }
943
944 #[::fuchsia::test]
945 async fn registry_add_bus() {
946 spawn_kernel_and_run(async |current_task| {
947 let kernel = current_task.kernel();
948 let registry = &kernel.device_registry;
949
950 let bus = registry.objects.get_or_create_bus("my-bus".into());
951 let bus_dev = registry.add_bus_device(
952 "my-device".into(),
953 None,
954 bus.clone(),
955 build_device_directory,
956 );
957 assert!(registry.objects.root.lookup("bus/my-bus/devices/my-device".into()).is_some());
958 assert!(registry.objects.root.lookup("devices/my-device".into()).is_some());
959
960 let class = registry.objects.get_or_create_class("my-class".into());
961 let class_dev = registry.add_numberless_device(
962 "my-class-dev".into(),
963 Some(bus_dev.clone()),
964 class,
965 build_device_directory,
966 );
967 assert!(registry.objects.root.lookup("class/my-class/my-class-dev".into()).is_some());
968 assert!(
969 registry
970 .objects
971 .root
972 .lookup("devices/my-device/my-class/my-class-dev".into())
973 .is_some()
974 );
975
976 let sub_class = registry.objects.get_or_create_class("my-subclass".into());
977 let child_class_dev = registry.add_numberless_device(
978 "my-child-class-dev".into(),
979 Some(class_dev.clone()),
980 sub_class,
981 build_device_directory,
982 );
983 assert!(
984 registry
985 .objects
986 .root
987 .lookup("class/my-subclass/my-child-class-dev".into())
988 .is_some()
989 );
990 assert!(
991 registry
992 .objects
993 .root
994 .lookup("devices/my-device/my-class/my-class-dev/my-child-class-dev".into())
995 .is_some()
996 );
997
998 registry.remove_device(¤t_task, child_class_dev);
999 assert!(
1000 registry
1001 .objects
1002 .root
1003 .lookup("class/my-subclass/my-child-class-dev".into())
1004 .is_none()
1005 );
1006 assert!(
1007 registry
1008 .objects
1009 .root
1010 .lookup("devices/my-device/my-class/my-class-dev/my-child-class-dev".into())
1011 .is_none()
1012 );
1013
1014 registry.remove_device(¤t_task, class_dev);
1015 assert!(registry.objects.root.lookup("class/my-class/my-class-dev".into()).is_none());
1016 assert!(
1017 registry
1018 .objects
1019 .root
1020 .lookup("devices/my-device/my-class/my-class-dev".into())
1021 .is_none()
1022 );
1023 assert!(registry.objects.root.lookup("devices/my-device/my-class".into()).is_none());
1024
1025 let bus_dev_check = bus_dev.clone();
1026 registry.remove_device(¤t_task, bus_dev);
1027 assert!(registry.objects.root.lookup("bus/my-bus/devices/my-device".into()).is_none());
1028 assert!(registry.objects.root.lookup("devices/my-device".into()).is_none());
1029 DelayedReleaser::default().apply(¤t_task);
1030 assert!(bus_dev_check.dir().is_none());
1031 })
1032 .await;
1033 }
1034
1035 #[::fuchsia::test]
1036 async fn registry_add_root_and_child_bus_device() {
1037 spawn_kernel_and_run(async |current_task| {
1038 let kernel = current_task.kernel();
1039 let registry = &kernel.device_registry;
1040
1041 let root_dev = registry.add_subsystemless_device(
1042 "my-root".into(),
1043 None,
1044 build_device_directory,
1045 );
1046 assert!(registry.objects.root.lookup("devices/my-root/uevent".into()).is_some());
1047
1048 let bus = registry.objects.get_or_create_bus("my-bus".into());
1049 let child_bus_dev = registry.add_bus_device(
1050 "my-child".into(),
1051 Some(root_dev.clone()),
1052 bus.clone(),
1053 build_device_directory,
1054 );
1055 assert!(
1056 registry.objects.root.lookup("devices/my-root/my-child/uevent".into()).is_some()
1057 );
1058 assert!(registry.objects.root.lookup("bus/my-bus/devices/my-child".into()).is_some());
1059
1060 let grandchild_bus_dev = registry.add_bus_device(
1061 "my-grandchild".into(),
1062 Some(child_bus_dev.clone()),
1063 bus,
1064 build_device_directory,
1065 );
1066 assert!(
1067 registry
1068 .objects
1069 .root
1070 .lookup("devices/my-root/my-child/my-grandchild/uevent".into())
1071 .is_some()
1072 );
1073 assert!(
1074 registry.objects.root.lookup("bus/my-bus/devices/my-grandchild".into()).is_some()
1075 );
1076
1077 registry.remove_device(¤t_task, grandchild_bus_dev);
1078 assert!(
1079 registry
1080 .objects
1081 .root
1082 .lookup("devices/my-root/my-child/my-grandchild".into())
1083 .is_none()
1084 );
1085 assert!(
1086 registry.objects.root.lookup("bus/my-bus/devices/my-grandchild".into()).is_none()
1087 );
1088
1089 registry.remove_device(¤t_task, child_bus_dev);
1090 assert!(registry.objects.root.lookup("devices/my-root/my-child".into()).is_none());
1091 assert!(registry.objects.root.lookup("bus/my-bus/devices/my-child".into()).is_none());
1092
1093 registry.remove_device(¤t_task, root_dev);
1094 assert!(registry.objects.root.lookup("devices/my-root".into()).is_none());
1095 })
1096 .await;
1097 }
1098
1099 #[::fuchsia::test]
1100 async fn registry_remove_device() {
1101 spawn_kernel_and_run(async |current_task| {
1102 let kernel = current_task.kernel();
1103 let registry = &kernel.device_registry;
1104 registry
1105 .register_major(
1106 "input".into(),
1107 DeviceMode::Char,
1108 INPUT_MAJOR,
1109 simple_device_ops::<DevNull>,
1110 )
1111 .expect("can register input");
1112
1113 let input_class = registry.objects.get_or_create_class("input".into());
1114 let mouse_dev = registry
1115 .add_device(
1116 kernel,
1117 "mouse".into(),
1118 DeviceMetadata::new(
1119 "mouse".into(),
1120 DeviceId::new(INPUT_MAJOR, 0),
1121 DeviceMode::Char,
1122 ),
1123 None,
1124 input_class.clone(),
1125 build_device_directory,
1126 )
1127 .expect("add_device");
1128 let keyboard_dev = registry
1129 .add_device(
1130 kernel,
1131 "keyboard".into(),
1132 DeviceMetadata::new(
1133 "keyboard".into(),
1134 DeviceId::new(INPUT_MAJOR, 1),
1135 DeviceMode::Char,
1136 ),
1137 None,
1138 input_class,
1139 build_device_directory,
1140 )
1141 .expect("add_device");
1142
1143 assert!(registry.objects.root.lookup("devices/virtual/input/mouse".into()).is_some());
1144 assert!(
1145 registry.objects.root.lookup("devices/virtual/input/keyboard".into()).is_some()
1146 );
1147 assert!(registry.objects.root.lookup("class/input/mouse".into()).is_some());
1148 assert!(registry.objects.root.lookup("class/input/keyboard".into()).is_some());
1149
1150 registry.remove_device(¤t_task, mouse_dev);
1151
1152 assert!(registry.objects.root.lookup("devices/virtual/input/mouse".into()).is_none());
1153 assert!(registry.objects.root.lookup("devices/virtual/input".into()).is_some());
1154 assert!(registry.objects.root.lookup("class/input/mouse".into()).is_none());
1155
1156 registry.remove_device(¤t_task, keyboard_dev.clone());
1157
1158 assert!(
1159 registry.objects.root.lookup("devices/virtual/input/keyboard".into()).is_none()
1160 );
1161 assert!(registry.objects.root.lookup("devices/virtual/input".into()).is_none());
1162 assert!(registry.objects.root.lookup("class/input/keyboard".into()).is_none());
1163
1164 registry.objects.remove(&keyboard_dev);
1166 assert!(registry.objects.root.lookup("devices/virtual/input".into()).is_none());
1167 })
1168 .await;
1169 }
1170
1171 #[::fuchsia::test]
1172 async fn registry_add_and_remove_numberless_device() {
1173 spawn_kernel_and_run(async |current_task| {
1174 let kernel = current_task.kernel();
1175 let registry = &kernel.device_registry;
1176
1177 let cooling_device = registry.add_numberless_device(
1178 "cooling_device0".into(),
1179 None,
1180 registry.objects.thermal_class(),
1181 build_device_directory,
1182 );
1183
1184 assert!(registry.objects.root.lookup("class/thermal/cooling_device0".into()).is_some());
1185 assert!(
1186 registry
1187 .objects
1188 .root
1189 .lookup("devices/virtual/thermal/cooling_device0".into())
1190 .is_some()
1191 );
1192
1193 registry.remove_device(¤t_task, cooling_device);
1194
1195 assert!(registry.objects.root.lookup("class/thermal/cooling_device0".into()).is_none());
1196 assert!(
1197 registry
1198 .objects
1199 .root
1200 .lookup("devices/virtual/thermal/cooling_device0".into())
1201 .is_none()
1202 );
1203 assert!(registry.objects.root.lookup("devices/virtual/thermal".into()).is_none());
1204 })
1205 .await;
1206 }
1207
1208 #[::fuchsia::test]
1209 async fn registry_add_and_remove_net_device() {
1210 spawn_kernel_and_run(async |current_task| {
1211 let kernel = current_task.kernel();
1212 let registry = &kernel.device_registry;
1213
1214 let wlan0 = registry.add_net_device("wlan0".into());
1215 assert!(registry.objects.root.lookup("class/net/wlan0".into()).is_some());
1216 assert!(
1217 registry.objects.root.lookup("devices/virtual/net/wlan0/address".into()).is_some()
1218 );
1219 assert!(
1220 registry.objects.root.lookup("devices/virtual/net/wlan0/uevent".into()).is_some()
1221 );
1222
1223 registry.remove_net_device(wlan0);
1224 assert!(registry.objects.root.lookup("class/net/wlan0".into()).is_none());
1225 assert!(registry.objects.root.lookup("devices/virtual/net/wlan0".into()).is_none());
1226 })
1227 .await;
1228 }
1229
1230 #[::fuchsia::test]
1231 async fn registry_remove_minor_device() {
1232 spawn_kernel_and_run(async |current_task| {
1233 let kernel = current_task.kernel();
1234 let registry = &kernel.device_registry;
1235
1236 let dev = registry
1237 .register_misc_device(kernel, "test_misc".into(), simple_device_ops::<DevNull>)
1238 .expect("register misc device");
1239 let devt = dev.metadata().expect("metadata").devt;
1240
1241 assert!(registry.get_device(devt, DeviceMode::Char).is_ok());
1242
1243 registry.remove_device(¤t_task, dev);
1244
1245 assert_eq!(registry.get_device(devt, DeviceMode::Char).map(|_| ()), error!(ENODEV));
1246 })
1247 .await;
1248 }
1249}