Skip to main content

starnix_core/device/
block.rs

1// Copyright 2026 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::DeviceMode;
6use crate::device::kobject::DeviceMetadata;
7use crate::fs::sysfs::{BlockDeviceInfo, build_block_device_directory};
8use crate::task::CurrentTask;
9use crate::vfs::{FileOps, FsString, NamespaceNode};
10use starnix_logging::track_stub;
11use starnix_sync::{FileOpsCore, Locked, Unlocked};
12use starnix_uapi::device_type::DeviceType;
13use starnix_uapi::errors::Errno;
14use starnix_uapi::open_flags::OpenFlags;
15use starnix_uapi::user_address::ArchSpecific;
16use starnix_uapi::{errno, uapi};
17use std::sync::Arc;
18
19pub fn canonicalize_ioctl_request(current_task: &CurrentTask, request: u32) -> u32 {
20    if current_task.is_arch32() {
21        match request {
22            uapi::arch32::BLKGETSIZE64 => uapi::BLKGETSIZE64,
23            _ => request,
24        }
25    } else {
26        request
27    }
28}
29
30pub struct MmcBlockDevice;
31
32impl BlockDeviceInfo for MmcBlockDevice {
33    fn size(&self) -> Result<usize, Errno> {
34        track_stub!(TODO("https://fxbug.dev/488067251"), "mmcblk query size");
35        Err(errno!(ENOTSUP))
36    }
37}
38
39fn open_mmc_block_device(
40    _locked: &mut Locked<FileOpsCore>,
41    _current_task: &CurrentTask,
42    _id: DeviceType,
43    _node: &NamespaceNode,
44    _flags: OpenFlags,
45) -> Result<Box<dyn FileOps>, Errno> {
46    track_stub!(TODO("https://fxbug.dev/488067251"), "mmcblk open device");
47    Err(errno!(ENOTSUP))
48}
49
50/// Adds an mmc block device at /dev/block/mmcblk0. The current implementation is just a stub that
51/// exports the typical sysfs layout for block devices, but cannot be read from or written to.
52pub fn add_mmc_block_device(
53    locked: &mut Locked<Unlocked>,
54    current_task: &CurrentTask,
55) -> Result<Arc<MmcBlockDevice>, Errno> {
56    let name = FsString::from("mmcblk0");
57    let kernel = current_task.kernel();
58    let class = kernel.device_registry.objects.virtual_block_class();
59    let device = Arc::new(MmcBlockDevice);
60    let device_weak = Arc::downgrade(&device);
61    kernel.device_registry.register_device_with_dir(
62        locked,
63        current_task,
64        name.as_ref(),
65        DeviceMetadata::new(name.clone(), DeviceType::MMCBLK0, DeviceMode::Block),
66        class,
67        |device, dir| build_block_device_directory(device, device_weak, dir),
68        open_mmc_block_device,
69    )?;
70    Ok(device)
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use crate::testing::{anon_test_file, spawn_kernel_and_run};
77    use crate::vfs::VecOutputBuffer;
78    use starnix_uapi::open_flags::OpenFlags;
79
80    #[::fuchsia::test]
81    async fn test_mmc_block_device() {
82        spawn_kernel_and_run(async |locked, current_task| {
83            let _device = add_mmc_block_device(locked, &current_task).unwrap();
84            let class = current_task.kernel().device_registry.objects.virtual_block_class();
85            // The device should have a typical sysfs layout for block devices.
86            assert!(class.dir.lookup(b"mmcblk0/holders".into()).is_some());
87            // We should be able to open the size node of the stub device, but reading it will fail
88            // since right now it is just a stub implementation.
89            let size_node = class.dir.lookup(b"mmcblk0/size".into()).unwrap();
90            let file_ops =
91                size_node.create_file_ops(locked, &current_task, OpenFlags::RDONLY).unwrap();
92            let file = anon_test_file(locked, &current_task, file_ops, OpenFlags::RDONLY);
93            let mut buf = VecOutputBuffer::new(10);
94            assert_eq!(file.read(locked, &current_task, &mut buf).unwrap_err(), errno!(ENOTSUP));
95        })
96        .await;
97    }
98}