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