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