starnix_uapi/
device_type.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 std::fmt;
6use std::ops::Range;
7
8pub const MEM_MAJOR: u32 = 1;
9pub const TTY_MAJOR: u32 = 4;
10pub const TTY_ALT_MAJOR: u32 = 5;
11pub const LOOP_MAJOR: u32 = 7;
12pub const MISC_MAJOR: u32 = 10;
13pub const INPUT_MAJOR: u32 = 13;
14pub const FB_MAJOR: u32 = 29;
15
16// These minor device numbers in the MISC major device appear to be dynamically allocated.
17// The lower bound is taken from observing /proc/misc an Android device. The upper bound is
18// taken from the value of /dev/beep in devices.txt.
19pub const MISC_DYNANIC_MINOR_RANGE: Range<u32> = 52..128;
20
21// TODO: The range for dynamic character devices actually goes all the way to 254, but we
22// still have a few hardcoded devices registered at high numbers. We can expand this range
23// to 254 once we dynamically allocate those devices.
24pub const DYN_MAJOR_RANGE: Range<u32> = 234..252;
25
26// Unclear if this device number is assigned dynamically, but this value is what abarth observed
27// once for /dev/block/zram0.
28pub const ZRAM_MAJOR: u32 = 252;
29
30// This value is observed from dmsetup.
31pub const DEVICE_MAPPER_MAJOR: u32 = 254;
32
33pub const BLOCK_EXTENDED_MAJOR: u32 = 259;
34
35#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
36pub struct DeviceType(u64);
37
38impl DeviceType {
39    pub const NONE: DeviceType = DeviceType(0);
40
41    // MEM
42    pub const NULL: DeviceType = DeviceType::new(MEM_MAJOR, 3);
43    pub const ZERO: DeviceType = DeviceType::new(MEM_MAJOR, 5);
44    pub const FULL: DeviceType = DeviceType::new(MEM_MAJOR, 7);
45    pub const RANDOM: DeviceType = DeviceType::new(MEM_MAJOR, 8);
46    pub const URANDOM: DeviceType = DeviceType::new(MEM_MAJOR, 9);
47    pub const KMSG: DeviceType = DeviceType::new(MEM_MAJOR, 11);
48
49    // TTY_ALT
50    pub const TTY: DeviceType = DeviceType::new(TTY_ALT_MAJOR, 0);
51    pub const PTMX: DeviceType = DeviceType::new(TTY_ALT_MAJOR, 2);
52
53    // MISC
54    pub const HW_RANDOM: DeviceType = DeviceType::new(MISC_MAJOR, 183);
55    pub const UINPUT: DeviceType = DeviceType::new(MISC_MAJOR, 223);
56    pub const FUSE: DeviceType = DeviceType::new(MISC_MAJOR, 229);
57    pub const DEVICE_MAPPER: DeviceType = DeviceType::new(MISC_MAJOR, 236);
58    pub const LOOP_CONTROL: DeviceType = DeviceType::new(MISC_MAJOR, 237);
59
60    // Frame buffer
61    pub const FB0: DeviceType = DeviceType::new(FB_MAJOR, 0);
62
63    // TUN
64    pub const TUN: DeviceType = DeviceType::new(MISC_MAJOR, 200);
65
66    pub const fn new(major: u32, minor: u32) -> DeviceType {
67        // This encoding is part of the Linux UAPI. The encoded value is
68        // returned to userspace in the stat struct.
69        // See <https://man7.org/linux/man-pages/man3/makedev.3.html>.
70        DeviceType(
71            (((major & 0xfffff000) as u64) << 32)
72                | (((major & 0xfff) as u64) << 8)
73                | (((minor & 0xffffff00) as u64) << 12)
74                | ((minor & 0xff) as u64),
75        )
76    }
77
78    pub const fn new_range(major: u32, minor: Range<u32>) -> Range<DeviceType> {
79        Self::new(major, minor.start)..Self::new(major, minor.end)
80    }
81
82    pub const fn from_bits(dev: u64) -> DeviceType {
83        DeviceType(dev)
84    }
85
86    pub const fn bits(&self) -> u64 {
87        self.0
88    }
89
90    pub fn next_minor(&self) -> Option<DeviceType> {
91        self.minor().checked_add(1).map(|minor| DeviceType::new(self.major(), minor))
92    }
93
94    pub const fn major(&self) -> u32 {
95        ((self.0 >> 32 & 0xfffff000) | ((self.0 >> 8) & 0xfff)) as u32
96    }
97
98    pub const fn minor(&self) -> u32 {
99        ((self.0 >> 12 & 0xffffff00) | (self.0 & 0xff)) as u32
100    }
101}
102
103impl fmt::Display for DeviceType {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
105        write!(f, "{}:{}", self.major(), self.minor())
106    }
107}
108
109impl std::cmp::PartialOrd for DeviceType {
110    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
111        Some(self.cmp(other))
112    }
113}
114
115impl std::cmp::Ord for DeviceType {
116    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
117        (self.major(), self.minor()).cmp(&(other.major(), other.minor()))
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    #[::fuchsia::test]
126    fn test_device_type() {
127        let dev = DeviceType::new(21, 17);
128        assert_eq!(dev.major(), 21);
129        assert_eq!(dev.minor(), 17);
130
131        let dev = DeviceType::new(0x83af83fe, 0xf98ecba1);
132        assert_eq!(dev.major(), 0x83af83fe);
133        assert_eq!(dev.minor(), 0xf98ecba1);
134    }
135}