鸿蒙的驱动子系统-4-驱动配置文件的分析 原创 精华

发布于 2021-8-25 14:32
浏览
2收藏

鸿蒙的驱动子系统-4-驱动配置文件的分析

liangkz 2021.08.25

 

前文《小型系统驱动示例程序的编译和验证》提到,以UART驱动实例程序为例,可将示驱动程序分为三部分:

1. 设备树的描述文件及驱动的配置描述文件(.hcs)

2. 驱动程序的内核空间部分的实现和编译脚本

3. 驱动程序的用户空间部分的实现和编译脚本

本文将基于Hi3516平台详细分析第一部分驱动的配置文件的相关要点。

 

在项目根目录执行:find ./ -name *.hcs

      ./device/hisilicon/hispark_aries/sdk_liteos/config/hdf.hcs
      ......
      ./device/hisilicon/hispark_aries/sdk_liteos/config/watchdog/watchdog_config.hcs

./device/hisilicon/hispark_taurus/sdk_liteos/config/hdf.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/sdio/sdio_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/input/input_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/spi/spi_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/emmc/emmc_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/device_info/device_info.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/gpio/gpio_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/rtc/rtc_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/i2c/i2c_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/lcd/lcd_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/uart/uart_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/wifi/wlan_platform.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/wifi/wlan_chip_hi3881.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/usb/usb_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/watchdog/watchdog_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/pwm/pwm_config.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/dmac/dmac_config.hcs

      ./device/qemu/arm_virt/config/hdf.hcs
      ......
      ./device/qemu/arm_virt/config/cfiflash/cfi_config.hcs
./vendor/huawei/hdf/sample/config/spi/spi_config.hcs
./vendor/huawei/hdf/sample/config/device_info/device_info.hcs
./vendor/huawei/hdf/sample/config/gpio/gpio_config.hcs
./vendor/huawei/hdf/sample/config/uart/uart_config.hcs

      ./vendor/hisilicon/hispark_aries/config/hdf.hcs
      ......
      ./vendor/hisilicon/hispark_aries/config/wifi/wlan_chip_hi3881.hcs

./vendor/hisilicon/hispark_taurus/config/hdf.hcs
./vendor/hisilicon/hispark_taurus/config/input/input_config.hcs
./vendor/hisilicon/hispark_taurus/config/device_info/device_info.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/emmc_test_config.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/sdio_test_config.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/pwm_test_config.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/hdf_test_manager/device_info.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/hdf_test.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/gpio_test_config.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/spi_test_config.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/uart_test_config.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/i2c_test_config.hcs
./vendor/hisilicon/hispark_taurus/config/hdf_test/hdf_config_test.hcs
./vendor/hisilicon/hispark_taurus/config/lcd/lcd_config.hcs
./vendor/hisilicon/hispark_taurus/config/sensor/sensor_config.hcs
./vendor/hisilicon/hispark_taurus/config/sensor/accel/bmi160_config.hcs
./vendor/hisilicon/hispark_taurus/config/sensor/accel/accel_config.hcs
./vendor/hisilicon/hispark_taurus/config/wifi/wlan_platform.hcs
./vendor/hisilicon/hispark_taurus/config/wifi/wlan_chip_hi3881.hcs

      ./drivers/adapter/khdf/liteos/test/tools/hc-gen/test/unittest/02_empty_root_ei/case.hcs

      ......
      ./drivers/adapter/khdf/liteos/test/tools/hc-gen/test/unittest/30_include_order/base2.hcs

把hispark_aries、qemu/arm_virt、test/unittest这些关系不大的先去掉,剩下的整理成表格如下:

鸿蒙的驱动子系统-4-驱动配置文件的分析-开源基础软件社区

PartA灰色部分由 //drivers/adapter/khdf/liteos/hdf_lite.mk 文件内对 HAVE_VENDOR_CONFIG 的判断决定了不编译它,又由 LOSCFG_DRIVERS_HDF_TEST 决定编译入口在 PartB/hdf_test/Makefile,而不是PartB/Makefile。

PartB/PartC的蓝色部分,可以由开发者自行配置是否编译,PartB/hdf_test 不编译的话,那编译入口就是PartB/Makefile。

更详细的编译路径分析,见前文《驱动相关模块的编译》。

 

上表的文件可分为三类:

【3-1】Makefile:编译 hcs文件的入口。简单,下面不再详细分析。

LITEOSTOPDIR = //kernel/liteos_a/ 

HDF_DRIVER = //adapter/khdf/liteos/hdf_driver.mk   【定义在//drivers/adapter/khdf/liteos/lite.mk:61】

【3-2】device_info.hcs:这是整个平台所有设备信息的配置汇总,设备信息可以分布在不同路径下的若干个device_info.hcs文件中,最终会被hc-gen整合在一起。

        device_info.hcs 包含了HDF框架加载驱动所需要的基本信息,基于HDF框架开发的驱动,必须要在device_info.hcs文件中添加对应的设备描述。

        官方文档已经对该文件结构已经有很详细的解释了:

root {
    device_info {
        match_attr = "hdf_manager";
        template host {            // host模板,继承该模板的节点(如下sample_host)如果使用模板中的默认值,则节点字段可以缺省
        //......
        }

        sample_host :: host{
            hostName = "host0";              // host名称,host节点是用来存放某一类驱动的容器
            priority = 100;                  // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序
            device_sample :: device {        // sample设备节点
                device0 :: deviceNode {      // sample驱动的DeviceNode节点
                    policy = 1;              // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍
                    priority = 100;          // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序
                    preload = 0;             // 驱动按需加载字段,在本章节最后的说明有详细介绍
                    permission = 0664;       // 驱动创建设备节点权限
                    moduleName = "sample_driver";   // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
                    serviceName = "sample_service";    // 驱动对外发布服务的名称,必须唯一
                    deviceMatchAttr = "sample_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
                }
            }
        }
    }
}

这里仅增加我自己的一些粗浅理解:

  • host + hostName:一个host,就是同一类设备驱动的容器。如下面的平台类host,就包含了常见的i2c/gpio/uart/sdio等等,

        platform :: host {

            hostName = "platform_host";

            ........

        }

     还有外设类的host,包括了dipsplay类、input类、network类等等:

 //vendor/hisilicon/hispark_taurus/config/device_info/device_info.hcs 
 Line 19:          platform :: host {
 Line 204:         display :: host {
 Line 245:         input :: host {
 Line 337:         network :: host {
 Line 360:         sensor :: host {
 Line 384:         storage :: host {
 Line 387:         media :: host {

  • device:  具备相同属性的某一类具体的设备,比如I2C设备、uart设备,
  • deviceNode :  某一类具体设备的某些具体的设备节点,如I2C总线上挂着设备0,设备1,它们分别有各自的驱动配置

                device_i2c :: device {
                    device0 :: deviceNode {
                        ......
                    }
                    device1 :: deviceNode {
                        ......
                    }
                }
                device_uart :: device {
                    device0 :: deviceNode {
                        ......
                    }
                    device1 :: deviceNode {

                        ......
                    }

                }

接下来就是具体的deviceNode的各个字段了,以前文提到的uart驱动示例程序的deviceNode为例,配置见 //vendor/huawei/hdf/sample/config/device_info/device_info.hcs

                device5 :: deviceNode {
                    policy = 2;
                    priority = 10;
                    permission = 0660;
                    moduleName = "UART_SAMPLE";                   //uart_sample_driver
                    serviceName = "HDF_PLATFORM_UART_5";  //uart_sample_service
                    deviceMatchAttr = "sample_uart_5";              //uart_sample_config
                }

  • policy:驱动服务发布的策略,官方文档《驱动服务管理》章节有非常详细的解释。
  • priority :驱动启动优先级(0-200),值越大优先级越低: 0~ 49板级驱动,50~149设备驱动,150~200 接口拔插类设备驱动 
  • preload :驱动加载方式,支持按需加载和按序加载两种方式,官方文档《驱动开发》章节也有非常详细的解释。
  • permission :驱动创建设备节点权限,默认是0666
  • moduleName = "UART_SAMPLE":驱动名称,该字段的值必须和驱动入口结构的moduleName值一致。

     本文开头的“2. 驱动程序的内核空间部分的实现和编译脚本”中的内核实现部分代码中的驱动入口结构 g_sampleUartDriverEntry,代码见 //vendor/huawei/hdf/sample/platform/uart/src/uart_sample.c 文件:

struct HdfDriverEntry g_sampleUartDriverEntry = {
    .moduleVersion = 1,
    .moduleName    = "UART_SAMPLE",      //uart_sample_driver
    .Bind    = SampleUartDriverBind,
    .Init    = SampleUartDriverInit,
    .Release = SampleUartDriverRelease,
};

HDF_INIT(g_sampleUartDriverEntry);

  • serviceName = "HDF_PLATFORM_UART_5":驱动对外发布服务的名称,必须唯一,这是调用者找到驱动服务的凭证,要完全匹配才能找到并使用对应的驱动服务。

     本文开头的“3. 驱动程序的用户空间部分的实现和编译脚本”中的实现部分代码://vendor/huawei/hdf/sample/platform/uart/dispatch/uart_if.c 中

#define UART_DEV_SERVICE_NAME_PREFIX "HDF_PLATFORM_UART_%d"           //uart_sample_service

struct DevHandle *UartOpen(uint32_t port)    //sample code,port=5
{
    ......
    ret = snprintf_s(serviceName, MAX_DEV_NAME_SIZE + 1,

                             MAX_DEV_NAME_SIZE, UART_DEV_SERVICE_NAME_PREFIX, port);
    ......
}

  • deviceMatchAttr = "sample_uart_5":驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等

     这是 device_info.hcs 设备信息与下面的 xxx_config.hcs 中设备专属资源描述挂钩的凭证,device_info.hcs是设备树的树干和树枝,xxx_config.hcs 内的节点就是一片片树叶,deviceMatchAttr 就是树枝和叶片之间的叶柄。

 

【3-3】xxx_config.hcs:这是对特定设备专属资源的分别描述,不同类别的设备,各自使用的资源肯定也不同,会有自己的特定描述信息。

     例如,//vendor/huawei/hdf/sample/config/uart/uart_config.hcs 文件对该设备节点的描述,上面的 deviceMatchAttr 必须与这里的 match_attr 匹配。

        uart_sample {
            num = 5;
            base = 0x120a0000;  
            irqNum = 38;
            baudrate = 115200;
            uartClk = 24000000; 
            wlen = 0x60;       
            parity = 0;
            stopBit = 0;
            match_attr = "sample_uart_5";    //uart_sample_config
        }

uart_sample 的其他字段则是对这个设备节点的一些资源的初始化/默认配置了。

这些配置在 HdfDeviceObject 结构体中,通过 property 指向的树形结构来保存:

    /** Pointer to the property of the device, which is read by the HDF from the configuration file and
    transmitted to the driver. */
    const struct DeviceResourceNode *property;

在 SampleUartDriverInit(struct HdfDeviceObject *device)中调用 AttachUartDevice() 再调用GetUartDeviceResource()来读取property树形结构,从中解析出相关字段和值,保存在 struct UartDevice *uartDevice 结构体中,以供调用:

struct UartResource {
    uint32_t num;        /* UART port num */
    uint32_t base;       /* UART PL011 base address */
    uint32_t irqNum;     /* UART PL011 IRQ num */
    uint32_t baudrate;   /* Default baudrate */
    uint32_t wlen;       /* Default word length */
    uint32_t parity;     /* Default parity */
    uint32_t stopBit;    /* Default stop bits */
    uint32_t uartClk;    /* UART clock */
    unsigned long physBase;
};

struct UartDevice {
    struct IDeviceIoService ioService;
    struct UartResource resource;
    enum UartDeviceState state;     /* UART State */
    uint32_t uartClk;               /* UART clock */
    uint32_t baudrate;              /* Baudrate */
    struct BufferFifo rxFifo;
};

其他类型的设备节点专属资源,有各自定义的API和相关结构体做类似的事情。

 

对驱动配置文件的更多详情,还是请去官方文档仔细研读,比如驱动服务的管理、消息机制的管理和HCS的语法等等。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-8-25 23:42:22修改
4
收藏 2
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐