IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> zephyr的驱动模型及其实现 -> 正文阅读

[C++知识库]zephyr的驱动模型及其实现

一、概述

  • zephyr内核支持很多种驱动,但是在zephyr应用中所支持的驱动,则是在zephyr应用编译时通过CONFIG配置来选择的。以此来达到控制生成文件大小、内核功能、驱动裁剪的效果。
  • 与Linux设备驱动不同,zephyr上对于不同类型的设备,定义了不同类型的驱动接口(或称:系统调用),这些接口都定义在include文件夹内的头文件中,如:./zephyr/include/driver/iic.c
  • 虽然不同类型的设备驱动接口不同,但是其基本模型是一样的,本文仅分析基本模型,并实现一个较为完整的驱动。

zephyr如今的代码已经更新到V2.6,在驱动中包含了大量的设备树的使用,为更好地分析原理,我们采用V1.14版本的代码来学习。后续有机会在单独学习一下zephyr中设备树的使用。

二、相关文件:

/zephyr/include/device.h
/zephyr/kernel/device.c

三、zephyr驱动的基本要素

先说重点,一个zephyr的驱动,需要包含以下五个基本元素:

  • 两个重要的内核对象结构体,struct device, struct device_config
  • 一个设备申明与定义的宏,DEVICE_AND_API_INIT
  • 两个重要的设备相关的结构体,struct xxx_device_config,struct xxx_device_data
  • 一个设备初始化接口,int (*init)(struct device *device)
  • 一个设备接口的结构体及其成员函数的实现,struct xxx_driver_api?

四、重要的数据结构之一
? ? 对于一个驱动设备来说,一方面需要能够被内核管理,另一方面又需要保留一些设备特有信息,因此在zephyr提供了几个重要的数据结构来满足二者的需求。

/**device.h 所有驱动通用,zephyr内核对象,用于管理所有的设备,**/
struct device
/**device.h 所有驱动通用,zephyr内核对象,属于struct device的成员**/
struct device_config

????????这两个对象是zephyr的内核对象,结构体的定义在device.h文件中。可以使用宏:DEVICE_AND_API_INIT来定义,也是应用代码通过系统调用来访问设备驱动的关键对象。其定义如下:

/** Version:V1.14, directory:/zephyr/include/device.h **/
struct device_config {
    const char *name;    /*驱动名称*/
    int (*init)(struct device *device);    /*设备初始化接口*/
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
    int (*device_pm_control)(struct device *device, u32_t command,
                             void *context, device_pm_cb cb, void *arg);
    struct device_pm *pm;
#endif
    const void *config_info;    /*驱动设备私有配置,struct  xxx_device_config*/
};

struct device {
    struct device_config *config;    /** **/
    const void *driver_api;        /** 驱动的api接口,共有代码**/
    void *driver_data;             /** 驱动设备的私有数据 struct xxx_device_data**/
#if defined(__x86_64) && __SIZEOF_POINTER__ == 4
    /* The x32 ABI hits an edge case.  This is a 12 byte struct,
    * but the x86_64 linker will pack them only in units of 8
    * bytes, leading to alignment problems when iterating over
    * the link-time array.
    */
    void *padding;
#endif
};

? ? ? ? 从这两个结构体的成员可以看出:驱动基本元素中的三个都被包含在里面,从而可以实现对驱动设备私有数据的访问;而对于内核管理驱动设备,则可以通过宏来体现。
五、基本元素之——重要的宏

? ? ? ? 先来看一下宏的定义。通过该宏定义了两个结构体变量,并向其中填充了驱动api、以及驱动设备的data、cfg_info。宏定义中的其他传参的作用,详见注释。

/** Version:zephyrV1.14,  Directory:/zephyr/include/device.h  **/
/**
*    @param dev_name    input,设备名,一般没啥作用;
            drv_name    input,重要参数,设备的驱动名,用于在device_get_binding中查找设备
            init_fn     input,设备的初始化接口,在内核启动的驱动设备初始化阶段被调用
            data        input,其实就是struct xxx_device_data 类型的变量
            cfg_info    input,其实就是struct xxx_device_config 类型的变量
            level       input,重要参数,与prio一起确定设备的初始化顺序
            prio        input,重要参数,与level一起驱动设备的初始化顺序
            api         input,stuct xxx_driver_api,提供系统调用的接口
**/
#define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info,  \
                            level, prio, api)                             \
        static struct device_config _CONCAT(__config_, dev_name) __used   \
        __attribute__((__section__(".devconfig.init"))) = {               \
                .name = drv_name, .init = (init_fn),                      \
                .config_info = (cfg_info)                                 \
        };                                                                \
        static struct device _CONCAT(__device_, dev_name) __used          \
        __attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \
                .config = &_CONCAT(__config_, dev_name),                  \
                .driver_api = api,                                        \
                .driver_data = data                                       \
        }

? ? ? ? 再来看一下struct device类型的变量定义。通过__attribut__ 设置了变量 __device_dev_name在编译后所属的段为(".init_" #level STRINGIFY(prio)),这是一个与level&prio相关的段,在zephyr应用完成编译之后,会根据level & prio 参数将所有的驱动设备汇聚在一起。

????????在zephyr运行时,会将所有的device变量拷贝到内存中,并根据level & prio参数完成设备的初始化(详见:zephyr如何运行到main)。

static struct device _CONCAT(__device_, dev_name) __used ? ? ? ? ?\
__attribute__((__section__(".init_" #level STRINGIFY(prio)))) = {? ?........ }

zephyr的驱动设备是通过struct device结构体来管理的。在内核启动过程中,驱动设备会根据 DEVICE_AND_API_INIT 宏中所传规定的level & prio 参数在内核启动的不同阶段(详见:zephyr如何运行到main)完成初始化。

/** 不同类型设备驱动特有对象,用于保存驱动设备中特有的一些不可更改的重要数据,如IRQ号**/
strcut xxx_device_config
/**驱动特有对象,用于保存驱动设备中一些可供用户访问、修改的参数,如波特率等。**/
struct xxx_device_data

/**驱动特有对象,用于向应用层提供的接口**/
struct xxx_driver_api

五、zephyr驱动的实现

? ? ? ? 从前文可以看到,要实现一个zephyr的驱动,并实例化相应的驱动设备,需要调用DEVICE_AND_API_INIT宏来定义device、device_config类型的变量。为了定义变量则需要定义变量所需的一些成员变量。这些成员变量与驱动类型有关,下面以IIC驱动来简单的分析一下驱动的实现。

未完待续。。。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-05 10:37:43  更:2021-09-05 10:38:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 20:32:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计