Add Doxygen pages for RT-Thread device-model drivers: platform/OFW, DM core (bus, dm, power), clk/regulator/reset/power-domain, PCI/PIC, Phye, DMA/hwcache, block/SCSI/ATA/NVMe/UFS/SDIO, SCMI, RPMsg, mailbox, NVMem, NUMA, syscon, thermal, input/LED/IIO/graphic, and related power/charger/supply docs. Expand device-driver INDEX.md with ~90 @subpage entries so all new pages appear in the driver chapter navigation. Update existing UART/SPI/RTC/pin/framework/dtc pages: UART docs moved from serial/ to uart/ (uart + uart_dm + uart_earlycon); SPI and RTC gain DM companion pages; pin links to pin_dm; framework points at DM topics. Focus on registration/probe flow and in-tree APIs; no standalone VirtIO subsystem page (transport code still incomplete). Test plan: build Doxygen for documentation/ and verify device-driver INDEX links resolve without missing @ref/@subpage warnings. Signed-off-by: GuEe-GUI <2991707448@qq.com>
11 KiB
@page page_device_blk Block layer (blk)
Block storage subsystem
The blk layer turns a single physical storage backend into one or more RT-Thread block devices that applications and DFS can open, read/write by sector, and control with standard IOCTLs. Hardware drivers implement struct rt_blk_disk_ops on an embedded struct rt_blk_disk; the core registers the disk, scans partition tables, and creates child volumes (struct rt_blk_device) such as sda1 or mmcsd0p1.
Header: components/drivers/include/drivers/blk.h. IOCTLs and geometry: components/drivers/include/drivers/classes/block.h. Core: components/drivers/block/blk.c, blk_dev.c, blk_partition.c.
Architecture
[NVMe / SDIO / SCSI SD / … driver]
│ rt_blk_disk_ops (read/write/getgeome/…)
▼
struct rt_blk_disk ← rt_hw_blk_disk_register()
│ rt_blk_disk_probe_partition() (inside register)
▼
struct rt_blk_device × N ← disk_add_blk_dev() / blk_dev.c
│ rt_device_read/write (sector-relative)
▼
DFS / applications / POSIX devio
| Layer | Struct | Document |
|---|---|---|
| Physical disk | struct rt_blk_disk |
@ref page_device_disk |
| Partition table | (on-disk metadata) | @ref page_device_partitions |
| Volume (partition) | struct rt_blk_device |
This page — application-facing nodes |
Both disk and volume nodes use RT_Device_Class_Block. Applications normally open volumes (sda1), not the raw disk device, unless probing created a single full-disk volume with partno == 0.
Kconfig
| Option | Role |
|---|---|
RT_USING_BLK |
Master switch for components/drivers/block/ |
RT_BLK_PARTITION_EFI |
GPT / protective MBR parser (partitions/efi.c) |
RT_BLK_PARTITION_DFS |
Legacy DFS superblock layout on sector 0 (partitions/dfs.c, needs RT_USING_DFS) |
rt_hw_blk_disk_register always calls rt_blk_disk_probe_partition; partition scan errors are ignored (register still succeeds).
Access block devices (applications)
Same usage model as other char/block devices: find → open → read/write → control → close. Sector index is 0-based within the opened device (for a partition device, sector 0 is the start of that partition).
Find device
rt_device_t rt_device_find(const char *name);
| Parameter | Description |
|---|---|
name |
Volume name, e.g. sda0, sda1, mmcsd0, nvme0n1 (from DM naming — see @ref page_device_disk) |
| Return | Device handle, or RT_NULL if not found |
#define BLK_DEV_NAME "sda1"
rt_device_t blk = rt_device_find(BLK_DEV_NAME);
Open / close
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag);
rt_err_t rt_device_close(rt_device_t dev);
oflag |
Notes |
|---|---|
RT_DEVICE_OFLAG_RDONLY |
Always valid |
RT_DEVICE_OFLAG_WRONLY |
Fails on disk/volume if backend is read-only (ops->write == NULL sets read_only) |
Opening a partition device (rt_blk_device) internally opens the parent disk (blk_dev_open → rt_device_open(&blk->disk->parent)).
Read / write (sectors)
rt_ssize_t rt_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_ssize_t rt_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
For block class devices, pos is the starting sector number, size is sector count (not bytes).
| Parameter | Partition volume | Whole disk |
|---|---|---|
pos |
0 … sector_count - 1 (relative to partition) |
0 … disk capacity − 1 |
size |
Sectors to transfer | Same |
| Return | Sectors actually transferred, or negative error | Same |
#define SECTOR_SIZE 512
rt_uint8_t buf[SECTOR_SIZE];
if (rt_device_read(blk, 0, buf, 1) == 1)
{
/* one sector at LBA 0 of this partition */
}
Control (IOCTL)
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *args);
Standard commands (classes/block.h)
| Command | args type |
Partition volume | Raw disk |
|---|---|---|---|
RT_DEVICE_CTRL_BLK_GETGEOME |
struct rt_device_blk_geometry * |
sector_count = partition size; bytes_per_sector from disk |
Full disk geometry |
RT_DEVICE_CTRL_BLK_SYNC |
ignored | Flushes parent disk | ops->sync under lock |
RT_DEVICE_CTRL_BLK_ERASE |
ignored | Only if disk->partitions <= 1; else -RT_EIO |
May remove all partitions then ops->erase |
RT_DEVICE_CTRL_BLK_AUTOREFRESH |
rt_bool_t * / pointer treated as enable flag |
Delegates to disk if single partition | ops->autorefresh |
RT_DEVICE_CTRL_BLK_PARTITION |
struct dfs_partition * |
Copies blk->partition |
-RT_EINVAL on disk node |
DFS helpers (blk_dfs.h)
| Command | Role |
|---|---|
RT_DEVICE_CTRL_BLK_SSIZEGET |
Fills *(rt_off_t *)args with bytes per sector |
RT_DEVICE_CTRL_ALL_BLK_SSIZEGET |
Total byte size = sectors × bytes_per_sector (used by DFS v2 POSIX layer) |
Vendor-specific IOCTLs pass through disk->ops->control(disk, blk, cmd, args) on the volume path; on the disk path blk is NULL.
Geometry structure
struct rt_device_blk_geometry {
rt_uint64_t sector_count;
rt_uint32_t bytes_per_sector;
rt_uint32_t block_size; /* erase block size for flash-style media */
};
Partition volumes (rt_blk_device)
Defined in blk.h when DFS headers are available.
| Field | Meaning |
|---|---|
disk |
Parent rt_blk_disk |
sector_start / sector_count |
Slice on the physical disk (LBA range) |
partno |
Index used in device name (%sp%d / %s%d) |
partition |
struct dfs_partition for DFS mount; partition.lock → disk->usr_lock |
list |
Node on disk->part_nodes |
blk_dev.c forwarding
| Operation | Behavior |
|---|---|
| read/write | Translates to disk->parent at sector_start + pos |
| GETGEOME | Disk geometry with sector_count replaced by partition length |
| SYNC | rt_device_control(&disk->parent, SYNC) |
| ERASE / AUTOREFRESH | Allowed only when disk->partitions <= 1 |
Device naming (DM)
disk_add_blk_dev (blk_dev.c):
- If disk name’s last character is
'a'–'z'(e.g.sda): volume namesdap1(%sp%d). - Otherwise (e.g.
mmcsd0,nvme0n1):mmcsd0p1,nvme0n1p2(%s%d).
Each volume gets its own rt_dm_ida_alloc(disk->ida) slot under the same master_id as the disk.
DFS integration
When RT_USING_DFS and RT_USING_POSIX_DEVIO (and DFS v2 as implemented in-tree), blk_dfs.c registers file operations that:
- On open:
GETGEOME+ALL_BLK_SSIZEGETfor file size. - On read/write: byte-oriented I/O with unaligned head/tail sector handling via a bounce sector buffer.
- ioctl: forwards to
rt_device_control.
Mount the volume device name (not the disk) with the appropriate filesystem driver after partition probe.
Drivers already using blk
These drivers embed struct rt_blk_disk, set ops, ida, and call rt_hw_blk_disk_register when media is present:
| Driver | File | Typical name | Notable rt_blk_disk fields |
|---|---|---|---|
| NVMe | nvme/nvme.c |
nvme0n1, … |
parallel_io = RT_TRUE, per-namespace disk, max_partitions = RT_BLK_PARTITION_MAX |
| SDIO/MMC | sdio/dev_block.c |
host name / mmcsd0p* |
removable, max_partitions = RT_MMCSD_MAX_PARTITION, sets geometry before register |
| SCSI disk | scsi/scsi_sd.c |
sda, sdb, … |
parallel_io from host, READ CAPACITY 10/16, sd_ida |
| SCSI CD-ROM | scsi/scsi_cdrom.c |
optical media | Read-only style backend |
AHCI/SATA path: ata/ahci.c exposes SCSI devices; SD card goes through scsi_sd or MMC dev_block, then blk.
Minimal driver pattern
static const struct rt_blk_disk_ops my_blk_ops = {
.read = my_read,
.write = my_write,
.getgeome = my_getgeome,
.sync = my_sync,
};
static struct rt_dm_ida my_ida = RT_DM_IDA_INIT(MY_DISK);
void my_disk_register(struct my_hw *hw)
{
struct rt_blk_disk *disk = &hw->blk;
disk->ops = &my_blk_ops;
disk->ida = &my_ida;
disk->parallel_io = RT_FALSE; /* or RT_TRUE if ops are reentrant */
rt_dm_dev_set_name(&disk->parent.parent, "sda"); /* example */
rt_hw_blk_disk_register(disk); /* also runs partition probe */
}
Details: @ref page_device_disk.
Locks and concurrency
| Mechanism | Scope |
|---|---|
disk->usr_lock (semaphore) |
Serializes disk read/write/sync when parallel_io == 0 |
disk->lock (spinlock) |
Partition list, unregister, erase path |
parallel_io == 1 |
Disk read/write skip usr_lock — backend must be safe for concurrent I/O |
Partition volume I/O still goes through the disk node and follows the disk’s parallel_io / lock rules.
Typical bring-up sequence
- Allocate
struct rt_blk_disk(often embedded in driver private data). - Implement
rt_blk_disk_ops; setida, name, flags (read_only,removable,parallel_io,max_partitions). rt_hw_blk_disk_register(disk)— partition probe runs automatically.- Application or init code
rt_device_find("sda1"), mount DFS, or run filesystem code. rt_hw_blk_disk_unregister(disk)after unmount — syncs, removes all volumes, checksref_count.
To re-scan partitions after media change, unregister, update geometry, register again (or call rt_blk_disk_probe_partition only if disk->partitions == 0).
Driver / BSP quick notes
| Topic | Guidance |
|---|---|
| Name before register | First character of disk->parent.parent.name must be non-NUL |
ida |
Mandatory with RT_USING_DM; disk and each volume consume IDA slots |
| Probe errors | Ignored at register — check disk->partitions or open volumes explicitly |
max_partitions |
Set RT_BLK_PARTITION_NONE to skip table parsing |
| Read-only | Omit write in ops — core forces read_only |
| Unmount first | unregister returns -RT_EBUSY if ref_count > 0 |
| Erase | Disk erase IOCTL removes all partition devices first |
See also
- @ref page_device_disk —
rt_blk_disk/rt_blk_disk_ops/ register API - @ref page_device_partitions — GPT/EFI and DFS parsers
- @ref page_device_ata — AHCI → SCSI → blk path
- @ref page_device_nvme
- @ref page_device_sdio
- @ref page_device_scsi
components/drivers/block/blk.ccomponents/drivers/block/blk_dev.ccomponents/drivers/block/blk_partition.c