# MS-RTOS IO 子系统

本章将介绍 MS-RTOS IO 子系统的基础知识,文件系统、设备驱动、网络子系统开发都需要用到 IO 子系统的数据类型和接口。

# IO 子系统相关数据类型

类型 描述
ms_io_name_node_t 命名节点类型
ms_io_name_node_callback_t 命名节点遍历回调类型
ms_io_driver_ops_t 设备驱动操作类型
ms_io_drv_type_t 设备驱动的类型
ms_io_driver_t 设备驱动类型
ms_io_device_t 设备类型
ms_io_fs_ops_t 文件系统操作类型
ms_io_fs_type_t 文件系统的类型
ms_io_fs_t 文件系统类型
ms_io_file_t IO 系统打开的一个文件实例类型
ms_io_file_type_t 文件实例的类型
ms_io_mnt_t 挂载点类型
ms_io_job_t IO 工作类型
ms_io_job_opt_t IO 工作选项
ms_io_job_status_t IO 工作运行状态

# ms_io_name_node_t

命名节点类型定义如下:

typedef struct {
    ms_list_head_t  node; // 链表节点
    const char     *name; // 名字
} ms_io_name_node_t;

# ms_io_name_node_callback_t

命名节点遍历回调函数类型定义如下:

typedef void (*ms_io_name_node_callback_t)(ms_io_name_node_t *nnode, ms_ptr_t arg);

# ms_io_driver_ops_t

设备驱动操作类型定义如下:

typedef struct {
    // 设备驱动的类型
    ms_io_drv_type_t type;

    // 打开设备
    int        (*open)(ms_ptr_t ctx, ms_io_file_t *file, int oflag, ms_mode_t mode);
    // 关闭设备
    int        (*close)(ms_ptr_t ctx, ms_io_file_t *file);
    // 读设备
    ms_ssize_t (*read)(ms_ptr_t ctx, ms_io_file_t *file, ms_ptr_t buf, ms_size_t len);
    // 写设备
    ms_ssize_t (*write)(ms_ptr_t ctx, ms_io_file_t *file, ms_const_ptr_t buf, ms_size_t len);
    // 控制设备
    int        (*ioctl)(ms_ptr_t ctx, ms_io_file_t *file, int cmd, ms_ptr_t arg);
    // 控制文件
    int        (*fcntl)(ms_ptr_t ctx, ms_io_file_t *file, int cmd, int arg);
    // 获得设备状态
    int        (*fstat)(ms_ptr_t ctx, ms_io_file_t *file, ms_stat_t *buf);
    // 判断是不是一个 TTY 设备
    int        (*isatty)(ms_ptr_t ctx, ms_io_file_t *file);
    // 同步文件系统 CACHE
    int        (*fsync)(ms_ptr_t ctx, ms_io_file_t *file);
    // 同步文件数据 CACHE
    int        (*fdatasync)(ms_ptr_t ctx, ms_io_file_t *file);
    // 截断文件长度
    int        (*ftruncate)(ms_ptr_t ctx, ms_io_file_t *file, ms_off_t len);
    // 调整文件读写指针
    ms_off_t   (*lseek)(ms_ptr_t ctx, ms_io_file_t *file, ms_off_t offset, int whence);
    // 等待文件事件
    int        (*poll)(ms_ptr_t ctx, ms_io_file_t *file, ms_pollfd_t *fds, ms_bool_t setup);
    // 删除设备
    int        (*unlink)(ms_ptr_t ctx);

    /*
     * Block device only:
     */
    // 读块
    ms_ssize_t (*readblk )(ms_ptr_t ctx, ms_io_file_t *file,
                           ms_size_t blk_no, ms_size_t blk_cnt, ms_ptr_t buf);
    // 写块
    ms_ssize_t (*writeblk)(ms_ptr_t ctx, ms_io_file_t *file,
                           ms_size_t blk_no, ms_size_t blk_cnt, ms_const_ptr_t buf);

    /*
     * NAND Flash device only:
     */
    // 读 chunk
    int        (*readchunk )(ms_ptr_t ctx, ms_io_file_t *file,
                             ms_size_t chunk_no, ms_ptr_t data, ms_size_t data_len,
                             ms_ptr_t oob, ms_size_t oob_len, ms_uint8_t *ecc_result);
    // 写 chunk
    int        (*writechunk)(ms_ptr_t ctx, ms_io_file_t *file,
                             ms_size_t chunk_no, ms_const_ptr_t data, ms_size_t data_len,
                             ms_const_ptr_t oob, ms_size_t oob_len);


     * Power management
     */
#if MS_CFG_KERN_PM_EN > 0
    // 挂起设备
    ms_err_t   (*suspend)(ms_ptr_t ctx, ms_pm_sleep_mode_t sleep_mode);
    // 恢复设备
    void       (*resume)(ms_ptr_t ctx, ms_pm_sleep_mode_t sleep_mode);
    // 调整工作频率
    void       (*adjust_freq)(ms_ptr_t ctx, ms_pm_run_mode_t run_mode);
#endif
} const ms_io_driver_ops_t;

其中 ms_io_drv_type_t 驱动类型有以下几种:

类型 描述
MS_IO_DRV_TYPE_CHR 字符设备驱动
MS_IO_DRV_TYPE_BLK 块设备驱动
MS_IO_DRV_TYPE_SOCK socket 设备驱动
MS_IO_DRV_TYPE_FIFO FIFO 设备驱动

# ms_io_driver_t

设备驱动类型定义如下:

typedef struct ms_io_driver {
    ms_io_name_node_t       nnode; // 名字节点
    ms_io_driver_ops_t     *ops;   // 设备驱动操作
} ms_io_driver_t;

# ms_io_device_t

设备类型定义如下:

typedef struct ms_io_device {
    ms_io_name_node_t       nnode;   // 名字节点
#if MS_CFG_KERN_PM_EN > 0
    ms_list_head_t          pm_node; // 电源管理节点
#endif
    ms_io_driver_t         *drv;     // 驱动指针
    ms_ptr_t                ctx;     // 设备上下文
    ms_atomic_t             ref;     // 引用计数
} ms_io_device_t;

# ms_io_fs_ops_t

文件系统操作类型定义如下:

typedef struct ms_io_fs_ops {
    // 文件系统的类型
    ms_io_fs_type_t type;

    /*
     * File system interfaces
     */
    // 挂载
    int          (*mount)(ms_io_mnt_t *mnt, ms_io_device_t *dev, const char *dev_name, ms_const_ptr_t param);
    // 卸载
    int          (*unmount)(ms_io_mnt_t *mnt, ms_const_ptr_t param);
    // 格式化
    int          (*mkfs)(ms_io_mnt_t *mnt, ms_const_ptr_t param);

    // 创建符号链接
    int          (*link)(ms_io_mnt_t *mnt, const char *path1, const char *path2);
    // 删除文件
    int          (*unlink)(ms_io_mnt_t *mnt, const char *path);
    // 创建目录
    int          (*mkdir)(ms_io_mnt_t *mnt, const char *path, ms_mode_t mode);
    // 删除目录
    int          (*rmdir)(ms_io_mnt_t *mnt, const char *path);
    // 文件重命名、移动
    int          (*rename)(ms_io_mnt_t *mnt, const char *old, const char *_new);
    // 同步
    int          (*sync)(ms_io_mnt_t *mnt);
    // 截断文件长度
    int          (*truncate)(ms_io_mnt_t *mnt, const char *path, ms_off_t len);

    // 获得文件状态
    int          (*stat)(ms_io_mnt_t *mnt, const char *path, ms_stat_t *buf);
    // 获得文件状态
    int          (*lstat)(ms_io_mnt_t *mnt, const char *path, ms_stat_t *buf);
    // 获得文件系统状态
    int          (*statvfs)(ms_io_mnt_t *mnt, ms_statvfs_t *buf);

    /*
     * File interfaces
     */
    // 打开文件
    int          (*open)(ms_io_mnt_t *mnt, ms_io_file_t *file, const char *path, int oflag, ms_mode_t mode);
    // 关闭文件
    int          (*close)(ms_io_mnt_t *mnt, ms_io_file_t *file);
    // 读文件
    ms_ssize_t   (*read)(ms_io_mnt_t *mnt, ms_io_file_t *file, ms_ptr_t buf, ms_size_t len);
    // 写文件
    ms_ssize_t   (*write)(ms_io_mnt_t *mnt, ms_io_file_t *file, ms_const_ptr_t buf, ms_size_t len);
    // IO 控制
    int          (*ioctl)(ms_io_mnt_t *mnt, ms_io_file_t *file, int cmd, ms_ptr_t arg);
    // 控制文件
    int          (*fcntl)(ms_io_mnt_t *mnt, ms_io_file_t *file, int cmd, int arg);
    // 获得文件状态
    int          (*fstat)(ms_io_mnt_t *mnt, ms_io_file_t *file, ms_stat_t *buf);
    // 判断是不是一个 TTY 设备
    int          (*isatty)(ms_io_mnt_t *mnt, ms_io_file_t *file);
    // 同步文件系统缓冲
    int          (*fsync)(ms_io_mnt_t *mnt, ms_io_file_t *file);
    // 同步文件系统数据缓冲
    int          (*fdatasync)(ms_io_mnt_t *mnt, ms_io_file_t *file);
    // 截断文件长度
    int          (*ftruncate)(ms_io_mnt_t *mnt, ms_io_file_t *file, ms_off_t len);
    // 调整文件读写指针
    ms_off_t     (*lseek)(ms_io_mnt_t *mnt, ms_io_file_t *file, ms_off_t offset, int whence);
    // 等待文件事件
    int          (*poll)(ms_io_mnt_t *mnt, ms_io_file_t *file, ms_pollfd_t *fds, ms_bool_t setup);

    /*
     * Directory interfaces
     */
    // 打开目录
    int          (*opendir)(ms_io_mnt_t *mnt, ms_io_file_t *file, const char *path);
    // 读目录项
    int          (*readdir_r)(ms_io_mnt_t *mnt, ms_io_file_t *file, ms_dirent_t *entry, ms_dirent_t **result);
    // 重置目录流读指针
    int          (*rewinddir)(ms_io_mnt_t *mnt, ms_io_file_t *file);
    // 调整目录流读指针
    int          (*seekdir)(ms_io_mnt_t *mnt, ms_io_file_t *file, long loc);
    // 获得目录流读指针
    long         (*telldir)(ms_io_mnt_t *mnt, ms_io_file_t *file);
    // 关闭目录
    int          (*closedir)(ms_io_mnt_t *mnt, ms_io_file_t *file);
} const ms_io_fs_ops_t;

其中 ms_io_fs_type_t 文件系统类型有以下几种:

类型 描述
MS_IO_FS_TYPE_ROOTFS 根文件系统
MS_IO_FS_TYPE_DEVFS 设备文件系统
MS_IO_FS_TYPE_DISKFS 磁盘文件系统

# ms_io_fs_t

文件系统类型定义如下:

typedef struct ms_io_fs {
    ms_io_name_node_t       nnode; // 命名节点
    ms_io_fs_ops_t         *ops;   // 文件系统操作
} ms_io_fs_t;

# ms_io_mnt_t

挂载点类型定义如下:

typedef struct ms_io_mnt {
    ms_io_name_node_t       nnode;             // 命名节点
    ms_io_fs_t             *fs;                // 文件系统指针
    ms_ptr_t                ctx;               // 挂载点上下文
    ms_io_device_t         *dev;               // 块设备指针
    ms_uint32_t             ref;               // 引用计数
    ms_bool_t               umount_req;        // 是否有卸载请求
    ms_const_ptr_t          umount_param;      // 文件系统 `unmount` 参数
    ms_callback_t           on_unmount;        // 卸载时回调函数
    ms_ptr_t                on_unmount_arg;    // 卸载时回调函数参数
} ms_io_mnt_t;

# ms_io_file_t

ms_io_file_t 为 IO 系统打开的一个文件实例类型:

typedef struct ms_io_file {
    ms_list_head_t          node;             // 命名节点
    ms_io_mnt_t            *mnt;              // 挂载点指针
    ms_ptr_t                ctx;              // 上下文
    union {
       ms_bool_t            bool_info;
       ms_uint8_t           uint8_info;
       ms_uint16_t          uint16_info;
       ms_uint32_t          uint32_info;
       ms_addr_t            addr_info;
       ms_ptr_t             ptr_info;
       ms_atomic_t          atomic_info;
    } u;                                      // 用于记录不同的类型的信息
    int                     flags;            // 标志
    ms_uint32_t             ref;              // 引用计数
    ms_io_file_type_t       type;             // 类型
    ms_bool_t               close_req;        // 是否有关闭请求
} ms_io_file_t;

其中 ms_io_file_type_t 文件实例类型有以下几种:

类型 描述
MS_IO_FILE_TYPE_FREE 空闲
MS_IO_FILE_TYPE_FILE 普通文件
MS_IO_FILE_TYPE_SOCK socket
MS_IO_FILE_TYPE_FIFO fifo
MS_IO_FILE_TYPE_DIR 目录

# ms_io_job_t

ms_io_job_t 为 IO 工作类型:

typedef struct ms_io_job {
    ms_list_head_t       node;
    const char          *name;
    ms_callback_t        callback;
    ms_ptr_t             arg;
    ms_tick_t            remain;
    ms_tick_t            period;
    ms_io_job_opt_t      opt;
    ms_io_job_status_t   status;
    ms_bool_t            valid;
} ms_io_job_t;

其中 ms_io_job_opt_t IO 工作选项类型有以下几种:

类型 描述
MS_IO_JOB_OPT_ONE_SHOT 单次工作
MS_IO_JOB_OPT_PERIODIC 周期性工作

其中 ms_io_job_status_t IO 工作状态类型有以下几种:

类型 描述
MS_IO_JOB_STATUS_UNUSED 未使用的
MS_IO_JOB_STATUS_STOP 停止
MS_IO_JOB_STATUS_RUNNING 正在运行

# IO 子系统相关宏

定义 说明
MS_IO_NAME_BUF_SIZE 名字缓冲区大小
MS_IO_PATH_BUF_SIZE 路径缓冲区大小
MS_IO_PATH_BUF_ALLOC(pathbuf) 路径缓冲区分配
MS_IO_PATH_BUF_FREE(pathbuf) 路径缓冲区释放
MS_IO_PATH_IS_ROOT(path) 判断路径是不是根目录
MS_IO_DEF_POLLFD_SLOT_SIZE 默认的 poll fd slot 大小
MS_IO_LOCK() IO 子系统上锁
MS_IO_UNLOCK() IO 子系统解锁
_MS_IO(x, y) 普通 ioctl 命令
_MS_IOR(x, y, t) 读数据的 ioctl 命令
_MS_IOW(x, y, t) 写数据的 ioctl 命令
_MS_IORW(x, y, t) 读写数据的 ioctl 命令

驱动程序的头文件可以使用类似如下的宏定义来定义设备支持的 ioctl 命令:

#define MS_UART_CMD_SET_PARAM           _MS_IOW('u', 'a', ms_uart_param_t)
#define MS_UART_CMD_GET_PARAM           _MS_IOR('u', 'a', ms_uart_param_t)

#define MS_UART_CMD_SET_R_TIMEOUT       _MS_IOW('u', 't', ms_uint32_t)
#define MS_UART_CMD_GET_R_TIMEOUT       _MS_IOR('u', 't', ms_uint32_t)

#define MS_UART_CMD_FLUSH_RX            _MS_IO('u', 'f')
#define MS_UART_CMD_DRAIN_TX            _MS_IO('u', 'd')

# IO 子系统相关函数

命名节点相关函数:

// 注册命名节点到链表
ms_err_t ms_io_name_node_register(ms_list_head_t *list, ms_io_name_node_t *nnode);

// 卸载命名节点
ms_err_t ms_io_name_node_unregister(ms_list_head_t *list, ms_io_name_node_t *nnode);

// 获得第 n 个命名节点
ms_io_name_node_t *ms_io_name_node_get_by_index(ms_list_head_t *list, ms_uint32_t index);

// 检查指定名字的命名节点
ms_io_name_node_t *ms_io_name_node_find(ms_list_head_t *list, const char *name);

// 遍历命名节点
ms_err_t ms_io_name_node_traverse(ms_list_head_t *list, ms_io_name_node_callback_t callback, ms_ptr_t arg);

设备相关函数:

// 注册设备
ms_err_t ms_io_device_register(ms_io_device_t *dev, const char *dev_path, const char *drv_name, ms_ptr_t ctx);

// 卸载设备
ms_err_t ms_io_device_unregister(ms_io_device_t *dev);

// 文件转设备指针
#define MS_IO_FILE_TO_DEV(file)         ((ms_io_device_t *)((file)->ctx))

// 通过文件获得设备引用计数指针
#define MS_IO_DEV_REF(file)             (&(MS_IO_FILE_TO_DEV(file)->ref))

驱动相关函数:

// 注册驱动
ms_err_t ms_io_driver_register(ms_io_driver_t *drv);

文件系统相关函数:

// 注册文件系统
ms_err_t ms_io_fs_register(ms_io_fs_t *fs);

// 加入挂载点路径
const char *ms_io_path_add_mnt(const char *path);

// 文件模式转文件类型
ms_uint8_t ms_io_mode_to_type(ms_mode_t mode);

poll 相关函数:

// 设置 poll
int ms_io_poll_setup(ms_pollfd_t *fds, ms_nfds_t nfds, ms_handle_t semcid);

// 拆除 poll
int ms_io_poll_teardown(ms_pollfd_t *fds, ms_nfds_t nfds, int *count);

// poll 通知 helper
int ms_io_poll_notify_helper(ms_pollfd_t **slots, ms_nfds_t nslot, ms_pollevent_t event);

// poll helper
int ms_io_poll_helper(ms_pollfd_t *fds, ms_pollfd_t **slots, ms_nfds_t nslot, ms_bool_t setup, ms_ptr_t ctx,
                      ms_io_poll_func_t readable_check, ms_io_poll_func_t writable_check, ms_io_poll_func_t except_check);

IO 工作相关函数:

IO 工作一般用于检查 SD 是否插拨、网线是否插拨、传感器数据采集等,这些类型的工作可能并不需要很强的实时性,以亚秒级或秒级周期性工作,所有 IO 工作都工作在一个 IO 工作线程,所以 IO 工作处理完后应该退出以让其它的 IO 工作能按时运行。

// 初始化 IO 工作
ms_err_t ms_io_job_init(ms_io_job_t *iojob, const char *name, ms_callback_t callback, ms_ptr_t arg);

// 启动 IO 工作
ms_err_t ms_io_job_start(ms_io_job_t *iojob, ms_tick_t delay, ms_tick_t period, ms_io_job_opt_t opt);

// 停止 IO 工作
ms_err_t ms_io_job_stop(ms_io_job_t *iojob);