Skip to main content

starnix_core/device/
registry.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::device::kobject::{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::{FileOps, FsStr, FsString, NamespaceNode};
12use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
13use starnix_logging::log_error;
14use starnix_sync::{DeviceRegistryStateLevel, LockDepGuard, LockDepMutex, MappedLockDepGuard};
15use starnix_types::ownership::{Releasable, ReleaseGuard};
16use starnix_uapi::as_any::AsAny;
17use starnix_uapi::device_id::{DYN_MAJOR_RANGE, DeviceId, MISC_DYNANIC_MINOR_RANGE, MISC_MAJOR};
18use starnix_uapi::error;
19use starnix_uapi::errors::Errno;
20use starnix_uapi::open_flags::OpenFlags;
21use std::collections::btree_map::{BTreeMap, Entry};
22use std::ops::{Deref, Range};
23use std::sync::Arc;
24
25use dyn_clone::{DynClone, clone_trait_object};
26
27const CHRDEV_MINOR_MAX: u32 = 256;
28const BLKDEV_MINOR_MAX: u32 = 2u32.pow(20);
29
30/// The mode or category of the device driver.
31#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
32pub enum DeviceMode {
33    /// This device is a character device.
34    Char,
35
36    /// This device is a block device.
37    Block,
38}
39
40impl DeviceMode {
41    /// The number of minor device numbers available for this device mode.
42    fn minor_count(&self) -> u32 {
43        match self {
44            Self::Char => CHRDEV_MINOR_MAX,
45            Self::Block => BLKDEV_MINOR_MAX,
46        }
47    }
48
49    /// The range of minor device numbers available for this device mode.
50    pub fn minor_range(&self) -> Range<u32> {
51        0..self.minor_count()
52    }
53}
54
55pub trait DeviceOps: DynClone + Send + Sync + AsAny + 'static {
56    /// Instantiate a FileOps for this device.
57    ///
58    /// This function is called when userspace opens a file with a `DeviceId`
59    /// assigned to this device.
60    fn open(
61        &self,
62        current_task: &CurrentTask,
63        devt: DeviceId,
64        node: &NamespaceNode,
65        flags: OpenFlags,
66    ) -> Result<Box<dyn FileOps>, Errno>;
67}
68
69clone_trait_object!(DeviceOps);
70
71/// Allows directly using a function or closure as an implementation of DeviceOps, avoiding having
72/// to write a zero-size struct and an impl for it.
73impl<F> DeviceOps for F
74where
75    F: Clone
76        + Send
77        + Sync
78        + Clone
79        + Fn(&CurrentTask, DeviceId, &NamespaceNode, OpenFlags) -> Result<Box<dyn FileOps>, Errno>
80        + 'static,
81{
82    fn open(
83        &self,
84        current_task: &CurrentTask,
85        id: DeviceId,
86        node: &NamespaceNode,
87        flags: OpenFlags,
88    ) -> Result<Box<dyn FileOps>, Errno> {
89        self(current_task, id, node, flags)
90    }
91}
92
93/// A simple `DeviceOps` function for any device that implements `FileOps + Default`.
94pub fn simple_device_ops<T: Default + FileOps + 'static>(
95    _current_task: &CurrentTask,
96    _id: DeviceId,
97    _node: &NamespaceNode,
98    _flags: OpenFlags,
99) -> Result<Box<dyn FileOps>, Errno> {
100    Ok(Box::new(T::default()))
101}
102
103/// Keys returned by the registration method for `DeviceListener`s that allows to unregister a
104/// listener.
105pub type DeviceListenerKey = u64;
106
107/// A listener for uevents on devices.
108pub trait DeviceListener: Send + Sync {
109    fn on_device_event(&self, action: UEventAction, device: Device, context: UEventContext);
110}
111
112pub struct DeviceOpsWrapper(Box<dyn DeviceOps>);
113impl ReleaserAction<DeviceOpsWrapper> for DeviceOpsWrapper {
114    fn release(device_ops: ReleaseGuard<DeviceOpsWrapper>) {
115        register_delayed_release(device_ops);
116    }
117}
118impl Deref for DeviceOpsWrapper {
119    type Target = dyn DeviceOps;
120    fn deref(&self) -> &Self::Target {
121        self.0.deref()
122    }
123}
124pub type DeviceReleaser = ObjectReleaser<DeviceOpsWrapper, DeviceOpsWrapper>;
125pub type DeviceHandle = Arc<DeviceReleaser>;
126impl Releasable for DeviceOpsWrapper {
127    type Context<'a> = &'a CurrentTask;
128
129    fn release<'a>(self, _context: &'a CurrentTask) {}
130}
131
132/// An entry in the `DeviceRegistry`.
133struct DeviceEntry {
134    /// The name of the device.
135    ///
136    /// This name is the same as the name of the KObject for the device.
137    name: FsString,
138
139    /// The ops used to open the device.
140    ops: DeviceHandle,
141}
142
143impl DeviceEntry {
144    fn new(name: FsString, ops: impl DeviceOps) -> Self {
145        Self { name, ops: Arc::new(DeviceOpsWrapper(Box::new(ops)).into()) }
146    }
147}
148
149/// The devices registered for a given `DeviceMode`.
150///
151/// Each `DeviceMode` has its own namespace of registered devices.
152#[derive(Default)]
153struct RegisteredDevices {
154    /// The major devices registered for this device mode.
155    ///
156    /// Typically the devices registered here will add and remove individual devices using the
157    /// `add_device` and `remove_device` functions on `DeviceRegistry`.
158    ///
159    /// A major device registration shadows any minor device registrations for the same major
160    /// device number. We might need to reconsider this choice in the future in order to make
161    /// the /proc/devices file correctly list major devices such as `misc`.
162    majors: BTreeMap<u32, DeviceEntry>,
163
164    /// Individually registered minor devices.
165    ///
166    /// These devices are registered using the `register_device` function on `DeviceRegistry`.
167    minors: BTreeMap<DeviceId, DeviceEntry>,
168}
169
170impl RegisteredDevices {
171    /// Register a major device.
172    ///
173    /// Returns `EINVAL` if the major device is already registered.
174    fn register_major(&mut self, major: u32, entry: DeviceEntry) -> Result<(), Errno> {
175        if let Entry::Vacant(slot) = self.majors.entry(major) {
176            slot.insert(entry);
177            Ok(())
178        } else {
179            error!(EINVAL)
180        }
181    }
182
183    /// Register a minor device.
184    ///
185    /// Overwrites any existing minor device registered with the given `DeviceId`.
186    fn register_minor(&mut self, devt: DeviceId, entry: DeviceEntry) {
187        self.minors.insert(devt, entry);
188    }
189
190    /// Get the ops for a given `DeviceId`.
191    ///
192    /// If there is a major device registered with the major device number of the
193    /// `DeviceId`, the ops for that major device will be returned. Otherwise,
194    /// if there is a minor device registered, the ops for that minor device will be
195    /// returned. Otherwise, returns `ENODEV`.
196    fn get(&self, devt: DeviceId) -> Result<DeviceHandle, Errno> {
197        if let Some(major_device) = self.majors.get(&devt.major()) {
198            Ok(Arc::clone(&major_device.ops))
199        } else if let Some(minor_device) = self.minors.get(&devt) {
200            Ok(Arc::clone(&minor_device.ops))
201        } else {
202            error!(ENODEV)
203        }
204    }
205
206    /// Returns a list of the registered major device numbers and their names.
207    fn list_major_devices(&self) -> Vec<(u32, FsString)> {
208        self.majors.iter().map(|(major, entry)| (*major, entry.name.clone())).collect()
209    }
210
211    /// Returns a list of the registered minor devices and their names.
212    fn list_minor_devices(&self, range: Range<DeviceId>) -> Vec<(DeviceId, FsString)> {
213        self.minors.range(range).map(|(devt, entry)| (devt.clone(), entry.name.clone())).collect()
214    }
215}
216
217/// The registry for devices.
218///
219/// Devices are specified in file systems with major and minor device numbers, together referred to
220/// as a `DeviceId`. When userspace opens one of those files, we look up the `DeviceId` in the
221/// device registry to instantiate a file for that device.
222///
223/// The `DeviceRegistry` also manages the `KObjectStore`, which provides metadata for devices via
224/// the sysfs file system, typically mounted at /sys.
225pub struct DeviceRegistry {
226    /// The KObjects for registered devices.
227    pub objects: KObjectStore,
228
229    /// Mutable state for the device registry.
230    state: LockDepMutex<DeviceRegistryState, DeviceRegistryStateLevel>,
231}
232struct DeviceRegistryState {
233    /// The registered character devices.
234    char_devices: RegisteredDevices,
235
236    /// The registered block devices.
237    block_devices: RegisteredDevices,
238
239    /// Some of the misc devices (devices with the `MISC_MAJOR` major number) are dynamically
240    /// allocated. This allocator keeps track of which device numbers have been allocated to
241    /// such devices.
242    misc_chardev_allocator: DeviceIdAllocator,
243
244    /// A range of large major device numbers are reserved for other dynamically allocated
245    /// devices. This allocator keeps track of which device numbers have been allocated to
246    /// such devices.
247    dyn_chardev_allocator: DeviceIdAllocator,
248
249    /// The next anonymous device number to assign to a file system.
250    next_anon_minor: u32,
251
252    /// Listeners registered to learn about new devices being added to the registry.
253    ///
254    /// These listeners generate uevents for those devices, which populates /dev on some
255    /// systems.
256    listeners: BTreeMap<u64, Box<dyn DeviceListener>>,
257
258    /// The next identifier to use for a listener.
259    next_listener_id: u64,
260
261    /// The next event identifier to use when notifying listeners.
262    next_event_id: u64,
263}
264
265impl DeviceRegistry {
266    /// Notify devfs and listeners that a device has been added to the registry.
267    fn notify_device(&self, kernel: &Kernel, device: Device) -> Result<(), Errno> {
268        if let Some(metadata) = &device.metadata {
269            devtmpfs_create_device(kernel, metadata.clone())?;
270            self.dispatch_uevent(UEventAction::Add, device);
271        }
272        Ok(())
273    }
274
275    /// Register a device with the `DeviceRegistry`.
276    ///
277    /// If you are registering a device that exists in other systems, please check the metadata
278    /// for that device in /sys and make sure you use the same properties when calling this
279    /// function because these value are visible to userspace.
280    ///
281    /// For example, a typical device will appear in sysfs at a path like:
282    ///
283    ///   `/sys/devices/{bus}/{class}/{name}`
284    ///
285    /// Many common classes have convenient accessors on `DeviceRegistry::objects`.
286    ///
287    /// To fill out the `DeviceMetadata`, look at the `uevent` file:
288    ///
289    ///   `/sys/devices/{bus}/{class}/{name}/uevent`
290    ///
291    /// which as the following format:
292    ///
293    /// ```
294    ///   MAJOR={major-number}
295    ///   MINOR={minor-number}
296    ///   DEVNAME={devname}
297    ///   DEVMODE={devmode}
298    /// ```
299    ///
300    /// Often, the `{name}` and the `{devname}` are the same, but if they are not the same,
301    /// please take care to use the correct string in the correct field.
302    ///
303    /// If the `{major-number}` is 10 and the `{minor-number}` is in the range 52..128, please use
304    /// `register_misc_device` instead because these device numbers are dynamically allocated.
305    ///
306    /// If the `{major-number}` is in the range 234..255, please use `register_dyn_device` instead
307    /// because these device are also dynamically allocated.
308    ///
309    /// If you are unsure which device numbers to use, consult devices.txt:
310    ///
311    ///   https://www.kernel.org/doc/Documentation/admin-guide/devices.txt
312    ///
313    /// If you are still unsure, please ask an experienced Starnix contributor rather than make up
314    /// a device number.
315    ///
316    /// For most devices, the `create_device_sysfs_ops` parameter should be
317    /// `DeviceDirectory::new`, but some devices have custom directories in sysfs.
318    ///
319    /// Finally, the `dev_ops` parameter is where you provide the callback for instantiating
320    /// your device.
321    pub fn register_device<'a>(
322        &self,
323        kernel: &Kernel,
324        name: &FsStr,
325        metadata: DeviceMetadata,
326        class: Class,
327        dev_ops: impl DeviceOps,
328    ) -> Result<Device, Errno> {
329        self.register_device_with_dir(
330            kernel,
331            name,
332            metadata,
333            class,
334            build_device_directory,
335            dev_ops,
336        )
337    }
338
339    /// Register a device with a custom directory.
340    ///
341    /// See `register_device` for an explanation of the parameters.
342    pub fn register_device_with_dir<'a>(
343        &self,
344        kernel: &Kernel,
345        name: &FsStr,
346        metadata: DeviceMetadata,
347        class: Class,
348        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
349        dev_ops: impl DeviceOps,
350    ) -> Result<Device, Errno> {
351        let entry = DeviceEntry::new(name.into(), dev_ops);
352        self.devices(metadata.mode).register_minor(metadata.devt, entry);
353        self.add_device(kernel, name, metadata, class, build_directory)
354    }
355
356    /// Register a dynamic device in the `MISC_MAJOR` major device number.
357    ///
358    /// MISC devices (major number 10) with minor numbers in the range 52..128 are dynamically
359    /// assigned. Rather than hardcoding registrations with these device numbers, use this
360    /// function instead to register the device.
361    ///
362    /// See `register_device` for an explanation of the parameters.
363    pub fn register_misc_device<'a>(
364        &self,
365        kernel: &Kernel,
366        name: &FsStr,
367        dev_ops: impl DeviceOps,
368    ) -> Result<Device, Errno> {
369        let devt = self.state.lock().misc_chardev_allocator.allocate()?;
370        let metadata = DeviceMetadata::new(name.into(), devt, DeviceMode::Char);
371        Ok(self.register_device(kernel, name, metadata, self.objects.misc_class(), dev_ops)?)
372    }
373
374    /// Register a dynamic device with major numbers 234..255.
375    ///
376    /// Majors device numbers 234..255 are dynamically assigned. Rather than hardcoding
377    /// registrations with these device numbers, use this function instead to register the device.
378    ///
379    /// Note: We do not currently allocate from this entire range because we have mistakenly
380    /// hardcoded some device registrations from the dynamic range. Once we fix these registrations
381    /// to be dynamic, we should expand to using the full dynamic range.
382    ///
383    /// See `register_device` for an explanation of the parameters.
384    pub fn register_dyn_device<'a>(
385        &self,
386        kernel: &Kernel,
387        name: &FsStr,
388        class: Class,
389        dev_ops: impl DeviceOps,
390    ) -> Result<Device, Errno> {
391        self.register_dyn_device_with_dir(kernel, name, class, build_device_directory, dev_ops)
392    }
393
394    /// Register a dynamic device with a custom directory.
395    ///
396    /// See `register_device` for an explanation of the parameters.
397    pub fn register_dyn_device_with_dir<'a>(
398        &self,
399        kernel: &Kernel,
400        name: &FsStr,
401        class: Class,
402        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
403        dev_ops: impl DeviceOps,
404    ) -> Result<Device, Errno> {
405        self.register_dyn_device_with_devname(kernel, name, name, class, build_directory, dev_ops)
406    }
407
408    /// Register a dynamic device with major numbers 234..255.
409    ///
410    /// Majors device numbers 234..255 are dynamically assigned. Rather than hardcoding
411    /// registrations with these device numbers, use this function instead to register the device.
412    ///
413    /// Note: We do not currently allocate from this entire range because we have mistakenly
414    /// hardcoded some device registrations from the dynamic range. Once we fix these registrations
415    /// to be dynamic, we should expand to using the full dynamic range.
416    ///
417    /// See `register_device` for an explanation of the parameters.
418    pub fn register_dyn_device_with_devname<'a>(
419        &self,
420        kernel: &Kernel,
421        name: &FsStr,
422        devname: &FsStr,
423        class: Class,
424        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
425        dev_ops: impl DeviceOps,
426    ) -> Result<Device, Errno> {
427        let devt = self.state.lock().dyn_chardev_allocator.allocate()?;
428        let metadata = DeviceMetadata::new(devname.into(), devt, DeviceMode::Char);
429        Ok(self.register_device_with_dir(
430            kernel,
431            name,
432            metadata,
433            class,
434            build_directory,
435            dev_ops,
436        )?)
437    }
438
439    /// Register a "silent" dynamic device with major numbers 234..255.
440    ///
441    /// Only use for devices that should not be registered with the KObjectStore/appear in sysfs.
442    /// This is a rare occurrence.
443    ///
444    /// See `register_dyn_device` for an explanation of dyn devices and of the parameters.
445    pub fn register_silent_dyn_device<'a>(
446        &self,
447        name: &FsStr,
448        dev_ops: impl DeviceOps,
449    ) -> Result<DeviceMetadata, Errno> {
450        let devt = self.state.lock().dyn_chardev_allocator.allocate()?;
451        let metadata = DeviceMetadata::new(name.into(), devt, DeviceMode::Char);
452        let entry = DeviceEntry::new(name.into(), dev_ops);
453        self.devices(metadata.mode).register_minor(metadata.devt, entry);
454        Ok(metadata)
455    }
456
457    /// Directly add a device to the KObjectStore.
458    ///
459    /// This function should be used only by device that have registered an entire major device
460    /// number. If you want to add a single minor device, use the `register_device` function
461    /// instead.
462    ///
463    /// See `register_device` for an explanation of the parameters.
464    pub fn add_device<'a>(
465        &self,
466        kernel: &Kernel,
467        name: &FsStr,
468        metadata: DeviceMetadata,
469        class: Class,
470        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
471    ) -> Result<Device, Errno> {
472        self.devices(metadata.mode).get(metadata.devt).expect("device is registered");
473        let device = self.objects.create_device(name, Some(metadata), class, build_directory);
474
475        self.notify_device(kernel, device.clone())?;
476        Ok(device)
477    }
478
479    /// Add a net device to the device registry.
480    ///
481    /// Net devices are different from other devices because they do not have a device number.
482    /// Instead, their `uevent` files have the following format:
483    ///
484    /// ```
485    /// INTERFACE={name}
486    /// IFINDEX={index}
487    /// ```
488    ///
489    /// Currently, we only register the net devices by name and use an empty `uevent` file.
490    pub fn add_net_device(&self, name: &FsStr) -> Device {
491        self.objects.create_device(name, None, self.objects.net_class(), build_device_directory)
492    }
493
494    /// Remove a net device from the device registry.
495    ///
496    /// See `add_net_device` for more details.
497    pub fn remove_net_device(&self, device: Device) {
498        assert!(device.metadata.is_none());
499        self.objects.remove(&device);
500    }
501
502    /// Directly add a device to the KObjectStore that lacks a device number.
503    ///
504    /// This function should be used only by device do not have a major or a minor number. You can
505    /// identify these devices because they appear in sysfs and have an empty `uevent` file.
506    ///
507    /// See `register_device` for an explanation of the parameters.
508    pub fn add_numberless_device(
509        &self,
510        name: &FsStr,
511        class: Class,
512        build_directory: impl FnOnce(&Device, &SimpleDirectoryMutator),
513    ) -> Device {
514        self.objects.create_device(name, None, class, build_directory)
515    }
516
517    /// Remove a device directly added with `add_device`.
518    ///
519    /// This function should be used only by device that have registered an entire major device
520    /// number. Individually registered minor device cannot be removed at this time.
521    pub fn remove_device(&self, current_task: &CurrentTask, device: Device) {
522        if let Some(metadata) = &device.metadata {
523            self.dispatch_uevent(UEventAction::Remove, device.clone());
524
525            if let Err(err) = devtmpfs_remove_path(current_task, metadata.devname.as_ref()) {
526                log_error!("Cannot remove device {:?} ({:?})", device, err);
527            }
528        }
529
530        self.objects.remove(&device);
531    }
532
533    /// Returns a list of the registered major device numbers for the given `DeviceMode` and their
534    /// names.
535    pub fn list_major_devices(&self, mode: DeviceMode) -> Vec<(u32, FsString)> {
536        self.devices(mode).list_major_devices()
537    }
538
539    /// Returns a list of the registered minor devices for the given `DeviceMode` and their names.
540    pub fn list_minor_devices(
541        &self,
542        mode: DeviceMode,
543        range: Range<DeviceId>,
544    ) -> Vec<(DeviceId, FsString)> {
545        self.devices(mode).list_minor_devices(range)
546    }
547
548    /// The `RegisteredDevice` object for the given `DeviceMode`.
549    fn devices<'a>(&'a self, mode: DeviceMode) -> MappedLockDepGuard<'a, RegisteredDevices> {
550        LockDepGuard::map(self.state.lock(), |state| match mode {
551            DeviceMode::Char => &mut state.char_devices,
552            DeviceMode::Block => &mut state.block_devices,
553        })
554    }
555
556    /// Register an entire major device number.
557    ///
558    /// If you register an entire major device, use `add_device` and `remove_device` to manage the
559    /// sysfs entiries for your device rather than trying to register and unregister individual
560    /// minor devices.
561    pub fn register_major<'a>(
562        &self,
563        name: FsString,
564        mode: DeviceMode,
565        major: u32,
566        dev_ops: impl DeviceOps,
567    ) -> Result<(), Errno> {
568        let entry = DeviceEntry::new(name, dev_ops);
569        self.devices(mode).register_major(major, entry)
570    }
571
572    /// Allocate an anonymous device identifier.
573    pub fn next_anonymous_dev_id<'a>(&self) -> DeviceId {
574        let mut state = self.state.lock();
575        let id = DeviceId::new(0, state.next_anon_minor);
576        state.next_anon_minor += 1;
577        id
578    }
579
580    /// Register a new listener for uevents on devices.
581    ///
582    /// Returns a key used to unregister the listener.
583    pub fn register_listener<'a>(
584        &self,
585        listener: impl DeviceListener + 'static,
586    ) -> DeviceListenerKey {
587        let mut state = self.state.lock();
588        let key = state.next_listener_id;
589        state.next_listener_id += 1;
590        state.listeners.insert(key, Box::new(listener));
591        key
592    }
593
594    /// Unregister a listener previously registered through `register_listener`.
595    pub fn unregister_listener<'a>(&self, key: &DeviceListenerKey) {
596        self.state.lock().listeners.remove(key);
597    }
598
599    /// Dispatch an uevent for the given `device`.
600    pub fn dispatch_uevent<'a>(&self, action: UEventAction, device: Device) {
601        let mut state = self.state.lock();
602        let event_id = state.next_event_id;
603        state.next_event_id += 1;
604        let context = UEventContext { seqnum: event_id };
605        for listener in state.listeners.values() {
606            listener.on_device_event(action, device.clone(), context);
607        }
608    }
609
610    /// Instantiate a file for the specified device.
611    ///
612    /// The device will be looked up in the device registry by `DeviceMode` and `DeviceId`.
613    pub fn open_device(
614        &self,
615        current_task: &CurrentTask,
616        node: &NamespaceNode,
617        flags: OpenFlags,
618        devt: DeviceId,
619        mode: DeviceMode,
620    ) -> Result<Box<dyn FileOps>, Errno> {
621        let dev_ops = self.devices(mode).get(devt)?;
622        dev_ops.open(current_task, devt, node, flags)
623    }
624
625    pub fn get_device(&self, devt: DeviceId, mode: DeviceMode) -> Result<DeviceHandle, Errno> {
626        self.devices(mode).get(devt)
627    }
628}
629
630impl Default for DeviceRegistry {
631    fn default() -> Self {
632        let misc_available = vec![DeviceId::new_range(MISC_MAJOR, MISC_DYNANIC_MINOR_RANGE)];
633        let dyn_available = DYN_MAJOR_RANGE
634            .map(|major| DeviceId::new_range(major, DeviceMode::Char.minor_range()))
635            .rev()
636            .collect();
637        let state = DeviceRegistryState {
638            char_devices: Default::default(),
639            block_devices: Default::default(),
640            misc_chardev_allocator: DeviceIdAllocator::new(misc_available),
641            dyn_chardev_allocator: DeviceIdAllocator::new(dyn_available),
642            next_anon_minor: 1,
643            listeners: Default::default(),
644            next_listener_id: 0,
645            next_event_id: 0,
646        };
647        Self { objects: Default::default(), state: state.into() }
648    }
649}
650
651/// An allocator for `DeviceId`
652struct DeviceIdAllocator {
653    /// The available ranges of device types to allocate.
654    ///
655    /// Devices will be allocated from the back of the vector first.
656    freelist: Vec<Range<DeviceId>>,
657}
658
659impl DeviceIdAllocator {
660    /// Create an allocator for the given ranges of device types.
661    ///
662    /// The devices will be allocated from the front of the vector first.
663    fn new(mut available: Vec<Range<DeviceId>>) -> Self {
664        available.reverse();
665        Self { freelist: available }
666    }
667
668    /// Allocate a `DeviceId`.
669    ///
670    /// Once allocated, there is no mechanism for freeing a `DeviceId`.
671    fn allocate(&mut self) -> Result<DeviceId, Errno> {
672        let Some(range) = self.freelist.pop() else {
673            return error!(ENOMEM);
674        };
675        let allocated = range.start;
676        if let Some(next) = allocated.next_minor() {
677            if next < range.end {
678                self.freelist.push(next..range.end);
679            }
680        }
681        Ok(allocated)
682    }
683}
684
685#[cfg(test)]
686mod tests {
687    use super::*;
688    use crate::device::mem::DevNull;
689    use crate::testing::*;
690    use crate::vfs::*;
691    use starnix_uapi::device_id::{INPUT_MAJOR, MEM_MAJOR};
692
693    #[::fuchsia::test]
694    async fn registry_fails_to_add_duplicate_device() {
695        spawn_kernel_and_run(async |_current_task| {
696            let registry = DeviceRegistry::default();
697            registry
698                .register_major(
699                    "mem".into(),
700                    DeviceMode::Char,
701                    MEM_MAJOR,
702                    simple_device_ops::<DevNull>,
703                )
704                .expect("registers once");
705            registry
706                .register_major(
707                    "random".into(),
708                    DeviceMode::Char,
709                    123,
710                    simple_device_ops::<DevNull>,
711                )
712                .expect("registers unique");
713            registry
714                .register_major(
715                    "mem".into(),
716                    DeviceMode::Char,
717                    MEM_MAJOR,
718                    simple_device_ops::<DevNull>,
719                )
720                .expect_err("fail to register duplicate");
721        })
722        .await;
723    }
724
725    #[::fuchsia::test]
726    async fn registry_opens_device() {
727        spawn_kernel_and_run(async |current_task| {
728            let kernel = current_task.kernel();
729            let registry = DeviceRegistry::default();
730            registry
731                .register_major(
732                    "mem".into(),
733                    DeviceMode::Char,
734                    MEM_MAJOR,
735                    simple_device_ops::<DevNull>,
736                )
737                .expect("registers unique");
738
739            let fs = create_testfs(&kernel);
740            let node = create_namespace_node_for_testing(&fs, PanickingFsNode);
741
742            // Fail to open non-existent device.
743            assert!(
744                registry
745                    .open_device(
746                        &current_task,
747                        &node,
748                        OpenFlags::RDONLY,
749                        DeviceId::NONE,
750                        DeviceMode::Char
751                    )
752                    .is_err()
753            );
754
755            // Fail to open in wrong mode.
756            assert!(
757                registry
758                    .open_device(
759                        &current_task,
760                        &node,
761                        OpenFlags::RDONLY,
762                        DeviceId::NULL,
763                        DeviceMode::Block
764                    )
765                    .is_err()
766            );
767
768            // Open in correct mode.
769            let _ = registry
770                .open_device(
771                    &current_task,
772                    &node,
773                    OpenFlags::RDONLY,
774                    DeviceId::NULL,
775                    DeviceMode::Char,
776                )
777                .expect("opens device");
778        })
779        .await;
780    }
781
782    #[::fuchsia::test]
783    async fn registry_dynamic_misc() {
784        spawn_kernel_and_run(async |current_task| {
785            let kernel = current_task.kernel();
786            fn create_test_device(
787                _current_task: &CurrentTask,
788                _id: DeviceId,
789                _node: &NamespaceNode,
790                _flags: OpenFlags,
791            ) -> Result<Box<dyn FileOps>, Errno> {
792                Ok(Box::new(PanickingFile))
793            }
794
795            let registry = &kernel.device_registry;
796            let device = registry
797                .register_dyn_device(
798                    kernel,
799                    "test-device".into(),
800                    registry.objects.virtual_block_class(),
801                    create_test_device,
802                )
803                .unwrap();
804            let devt = device.metadata.expect("has metadata").devt;
805            assert!(DYN_MAJOR_RANGE.contains(&devt.major()));
806
807            let fs = create_testfs(&kernel);
808            let node = create_namespace_node_for_testing(&fs, PanickingFsNode);
809            let _ = registry
810                .open_device(&current_task, &node, OpenFlags::RDONLY, devt, DeviceMode::Char)
811                .expect("opens device");
812        })
813        .await;
814    }
815
816    #[::fuchsia::test]
817    async fn registery_add_class() {
818        spawn_kernel_and_run(async |current_task| {
819            let kernel = current_task.kernel();
820            let registry = &kernel.device_registry;
821            registry
822                .register_major(
823                    "input".into(),
824                    DeviceMode::Char,
825                    INPUT_MAJOR,
826                    simple_device_ops::<DevNull>,
827                )
828                .expect("can register input");
829
830            let input_class = registry
831                .objects
832                .get_or_create_class("input".into(), registry.objects.virtual_bus());
833            registry
834                .add_device(
835                    kernel,
836                    "mouse".into(),
837                    DeviceMetadata::new(
838                        "mouse".into(),
839                        DeviceId::new(INPUT_MAJOR, 0),
840                        DeviceMode::Char,
841                    ),
842                    input_class,
843                    build_device_directory,
844                )
845                .expect("add_device");
846
847            assert!(registry.objects.root.lookup("class/input/mouse".into()).is_some());
848        })
849        .await;
850    }
851
852    #[::fuchsia::test]
853    async fn registry_add_bus() {
854        spawn_kernel_and_run(async |current_task| {
855            let kernel = current_task.kernel();
856            let registry = &kernel.device_registry;
857            registry
858                .register_major(
859                    "input".into(),
860                    DeviceMode::Char,
861                    INPUT_MAJOR,
862                    simple_device_ops::<DevNull>,
863                )
864                .expect("can register input");
865
866            let bus = registry.objects.get_or_create_bus("my-bus".into());
867            let class = registry.objects.get_or_create_class("my-class".into(), bus);
868            registry
869                .add_device(
870                    kernel,
871                    "my-device".into(),
872                    DeviceMetadata::new(
873                        "my-device".into(),
874                        DeviceId::new(INPUT_MAJOR, 0),
875                        DeviceMode::Char,
876                    ),
877                    class,
878                    build_device_directory,
879                )
880                .expect("add_device");
881            assert!(registry.objects.root.lookup("bus/my-bus".into()).is_some());
882            assert!(registry.objects.root.lookup("devices/my-bus/my-class".into()).is_some());
883            assert!(
884                registry.objects.root.lookup("devices/my-bus/my-class/my-device".into()).is_some()
885            );
886        })
887        .await;
888    }
889
890    #[::fuchsia::test]
891    async fn registry_remove_device() {
892        spawn_kernel_and_run(async |current_task| {
893            let kernel = current_task.kernel();
894            let registry = &kernel.device_registry;
895            registry
896                .register_major(
897                    "input".into(),
898                    DeviceMode::Char,
899                    INPUT_MAJOR,
900                    simple_device_ops::<DevNull>,
901                )
902                .expect("can register input");
903
904            let pci_bus = registry.objects.get_or_create_bus("pci".into());
905            let input_class = registry.objects.get_or_create_class("input".into(), pci_bus);
906            let mouse_dev = registry
907                .add_device(
908                    kernel,
909                    "mouse".into(),
910                    DeviceMetadata::new(
911                        "mouse".into(),
912                        DeviceId::new(INPUT_MAJOR, 0),
913                        DeviceMode::Char,
914                    ),
915                    input_class.clone(),
916                    build_device_directory,
917                )
918                .expect("add_device");
919
920            assert!(registry.objects.root.lookup("bus/pci/devices/mouse".into()).is_some());
921            assert!(registry.objects.root.lookup("devices/pci/input/mouse".into()).is_some());
922            assert!(registry.objects.root.lookup("class/input/mouse".into()).is_some());
923
924            registry.remove_device(&current_task, mouse_dev);
925
926            assert!(registry.objects.root.lookup("bus/pci/devices/mouse".into()).is_none());
927            assert!(registry.objects.root.lookup("devices/pci/input/mouse".into()).is_none());
928            assert!(registry.objects.root.lookup("class/input/mouse".into()).is_none());
929        })
930        .await;
931    }
932
933    #[::fuchsia::test]
934    async fn registry_add_and_remove_numberless_device() {
935        spawn_kernel_and_run(async |current_task| {
936            let kernel = current_task.kernel();
937            let registry = &kernel.device_registry;
938
939            let cooling_device = registry.add_numberless_device(
940                "cooling_device0".into(),
941                registry.objects.virtual_thermal_class(),
942                build_device_directory,
943            );
944
945            assert!(registry.objects.root.lookup("class/thermal/cooling_device0".into()).is_some());
946            assert!(
947                registry
948                    .objects
949                    .root
950                    .lookup("devices/virtual/thermal/cooling_device0".into())
951                    .is_some()
952            );
953
954            registry.remove_device(&current_task, cooling_device);
955
956            assert!(registry.objects.root.lookup("class/thermal/cooling_device0".into()).is_none());
957            assert!(
958                registry
959                    .objects
960                    .root
961                    .lookup("devices/virtual/thermal/cooling_device0".into())
962                    .is_none()
963            );
964        })
965        .await;
966    }
967}