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>
8.0 KiB
@page page_device_disk Physical disk (rt_blk_disk)
Disk device (driver writer guide)
struct rt_blk_disk is the physical backing store: one contiguous LBA space implemented by your driver’s rt_blk_disk_ops. The blk core wraps it as an rt_device, then creates volume children — see @ref page_device_blk and @ref page_device_partitions.
Implementation: components/drivers/block/blk.c. Header: components/drivers/include/drivers/blk.h.
Same documentation pattern as documentation/6.components/device-driver/ata/ata.md: fill structures before rt_hw_blk_disk_register, implement ops, then let the core attach partitions and DFS-facing devices.
struct rt_blk_disk (before rt_hw_blk_disk_register)
struct rt_blk_disk
{
struct rt_device parent;
const struct rt_blk_disk_ops *ops;
#ifdef RT_USING_DM
struct rt_dm_ida *ida;
#endif
rt_uint32_t read_only:1;
rt_uint32_t parallel_io:1;
rt_uint32_t removable:1;
rt_uint32_t __magic;
rt_uint32_t partitions;
rt_int32_t max_partitions;
rt_list_t part_nodes;
struct rt_spinlock lock;
struct rt_semaphore usr_lock;
};
| Member | Owner | Rule / meaning |
|---|---|---|
parent |
Caller | Embedded rt_device. Name must be set before register (first char of parent.parent.name ≠ \0). |
ops |
Caller | Required; see struct rt_blk_disk_ops below. |
ida |
Caller (RT_USING_DM) |
Non-NULL; shared with all volume children for rt_dm_ida_alloc. |
read_only |
Caller / core | If ops->write == NULL, core sets read_only = RT_TRUE. |
parallel_io |
Caller | RT_TRUE: disk read/write skip usr_lock (NVMe uses this). |
removable |
Caller | Hint for removable media (e.g. SDIO sets from host). |
max_partitions |
Caller | Cap for parsers; RT_BLK_PARTITION_NONE disables probing. RT_BLK_PARTITION_MAX = unlimited. |
partitions |
Core | Count of registered rt_blk_device nodes. |
part_nodes |
Core | List of struct rt_blk_device. |
lock |
Core | Spinlock for list / unregister / erase. |
usr_lock |
Core | Semaphore (prio) serializing I/O when not parallel_io. |
__magic |
Core | Set to RT_BLK_DISK_MAGIC at register. |
struct rt_blk_disk_ops
struct rt_blk_disk_ops
{
rt_ssize_t (*read)(struct rt_blk_disk *disk, rt_off_t sector, void *buffer,
rt_size_t sector_count);
rt_ssize_t (*write)(struct rt_blk_disk *disk, rt_off_t sector, const void *buffer,
rt_size_t sector_count);
rt_err_t (*getgeome)(struct rt_blk_disk *disk, struct rt_device_blk_geometry *geometry);
rt_err_t (*sync)(struct rt_blk_disk *disk);
rt_err_t (*erase)(struct rt_blk_disk *disk);
rt_err_t (*autorefresh)(struct rt_blk_disk *disk, rt_bool_t is_auto);
rt_err_t (*control)(struct rt_blk_disk *disk, struct rt_blk_device *blk, int cmd, void *args);
};
| Callback | Required? | Contract |
|---|---|---|
read |
Yes (practical) | sector, sector_count in 512-byte sectors unless getgeome says otherwise. Return sectors read or < 0 error. |
write |
Optional | NULL → disk read-only. Same addressing as read. |
getgeome |
Yes (practical) | Fill sector_count, bytes_per_sector, block_size. Used by partition code and DFS. |
sync |
Optional | Flush caches; called on unregister and RT_DEVICE_CTRL_BLK_SYNC. |
erase |
Optional | Whole-device erase; disk IOCTL may remove partitions first. |
autorefresh |
Optional | RT_DEVICE_CTRL_BLK_AUTOREFRESH (e.g. SD auto refresh). |
control |
Optional | Vendor IOCTLs; blk is NULL on raw disk, non-NULL on volume forwarding. |
Sector addressing expectations
- Arguments are LBA sector indices on the whole disk, not bytes.
getgeome()->bytes_per_sectormust match whatread/writeuse.getgeome()->sector_countis full device capacity in sectors.- If
parallel_io,read/writemay overlap — use driver-internal locking or queue depth as needed.
rt_hw_blk_disk_register (core sequence)
rt_err_t rt_hw_blk_disk_register(struct rt_blk_disk *disk)
| Step | Action |
|---|---|
| 1 | Validate disk, ops, name, ida (DM). |
| 2 | rt_dm_ida_alloc(disk->ida) for the disk device id. |
| 3 | Init usr_lock, part_nodes, lock. |
| 4 | Hook blk_ops or blk_parallel_ops on parent. |
| 5 | If !ops->write → read_only = 1. |
| 6 | device_set_blk_fops, rt_device_register with RD/WR flags. |
| 7 | rt_blk_disk_probe_partition(disk) — errors ignored. |
Return: register error only; partition failure does not fail register.
Disk rt_device ops (internal)
| Op | parallel_io == 0 |
parallel_io == 1 |
|---|---|---|
| read/write | Under usr_lock |
Direct ops->read/write |
| control | blk_control → ops |
Same |
RT_DEVICE_CTRL_BLK_PARTITION on the disk node returns -RT_EINVAL (use volume devices).
rt_hw_blk_disk_unregister
| Step | Action |
|---|---|
| 1 | ref_count > 0 → -RT_EBUSY |
| 2 | ops->sync if present |
| 3 | blk_remove_all — unregister every rt_blk_device |
| 4 | rt_dm_ida_free for disk id, rt_device_unregister |
Unmount DFS / close handles before unregister.
Helper APIs
| API | Role |
|---|---|
rt_blk_disk_probe_partition(disk) |
Re-run parsers if partitions == 0; see @ref page_device_partitions |
rt_blk_disk_get_capacity(disk) |
getgeome → sector_count |
rt_blk_disk_get_logical_block_size(disk) |
getgeome → bytes_per_sector |
In-tree integration examples
NVMe (nvme/nvme.c)
Per namespace:
rt_dm_dev_set_name(&ndev->parent.parent, "%sn%u", nvme->name, nsid)parallel_io = RT_TRUE,ops = &nvme_blk_ops,ida = &nvme_idamax_partitions = RT_BLK_PARTITION_MAXrt_hw_blk_disk_register(&ndev->parent)after identify
SDIO / MMC (sdio/dev_block.c)
- Geometry from card CSD:
sector_count,bytes_per_sector,block_size mmcsd_set_blksizebefore registerremovable,max_partitions = RT_MMCSD_MAX_PARTITION- Name from
host->name→ volumeshostp1style
SCSI SD (scsi/scsi_sd.c)
- READ CAPACITY (10/16) → geometry
rt_dm_dev_set_name(..., "sd%c%c", letter_name(sd_id))— names likesdaparallel_iofrom SCSI hostida = &scsi_sd_ida
SCSI CD-ROM (scsi/scsi_cdrom.c)
Same blk registration pattern; typically read-only media (write omitted or read-only flag).
DM naming checklist
RT_DM_IDA_INITper disk family (e.g.scsi_sd_ida,nvme_ida,sdio_ida).- Set
disk->idabefore register. - Disk name via
rt_dm_dev_set_name(&disk->parent.parent, ...). - Volumes are named automatically at probe — do not register
rt_blk_deviceyourself unless you bypassblk_put_partition.
Driver cautions
| Topic | Guidance |
|---|---|
| DMA / buffers | Bounce in ops if callers pass non-DMA-safe pointers |
| Capacity change | Unregister, update geometry, register again |
| Hotplug | Remove card → rt_hw_blk_disk_unregister; insert → register fresh |
| GPT + DFS | Enable both Kconfig parsers; EFI runs first in partition_list[] |
| Custom IOCTL | Implement control(disk, blk, cmd, args); forward unknown cmds from blk_control default case |
See also
- @ref page_device_blk — application API and volume layer
- @ref page_device_partitions
components/drivers/block/blk.ccomponents/drivers/include/drivers/blk.h