鴻蒙的驅(qū)動子系統(tǒng)-4-驅(qū)動配置文件的分析
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
前文《小型系統(tǒng)驅(qū)動示例程序的編譯和驗證》提到,以UART驅(qū)動實例程序為例,可將示驅(qū)動程序分為三部分:
1. 設備樹的描述文件及驅(qū)動的配置描述文件(.hcs)
2. 驅(qū)動程序的內(nèi)核空間部分的實現(xiàn)和編譯腳本
3. 驅(qū)動程序的用戶空間部分的實現(xiàn)和編譯腳本
本文將基于Hi3516平臺詳細分析第一部分驅(qū)動的配置文件的相關(guān)要點。
在項目根目錄執(zhí)行: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這些關(guān)系不大的先去掉,剩下的整理成表格如下:

PartA灰色部分由 //drivers/adapter/khdf/liteos/hdf_lite.mk 文件內(nèi)對 HAVE_VENDOR_CONFIG 的判斷決定了不編譯它,又由 LOSCFG_DRIVERS_HDF_TEST 決定編譯入口在 PartB/hdf_test/Makefile,而不是PartB/Makefile。
PartB/PartC的藍色部分,可以由開發(fā)者自行配置是否編譯,PartB/hdf_test 不編譯的話,那編譯入口就是PartB/Makefile。
更詳細的編譯路徑分析,見前文《驅(qū)動相關(guān)模塊的編譯》。
上表的文件可分為三類:
【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框架加載驅(qū)動所需要的基本信息,基于HDF框架開發(fā)的驅(qū)動,必須要在device_info.hcs文件中添加對應的設備描述。
官方文檔已經(jīng)對該文件結(jié)構(gòu)已經(jīng)有很詳細的解釋了:
- root {
- device_info {
- match_attr = "hdf_manager";
- template host { // host模板,繼承該模板的節(jié)點(如下sample_host)如果使用模板中的默認值,則節(jié)點字段可以缺省
- //......
- }
- sample_host :: host{
- hostName = "host0"; // host名稱,host節(jié)點是用來存放某一類驅(qū)動的容器
- priority = 100; // host啟動優(yōu)先級(0-200),值越大優(yōu)先級越低,建議默認配100,優(yōu)先級相同則不保證host的加載順序
- device_sample :: device { // sample設備節(jié)點
- device0 :: deviceNode { // sample驅(qū)動的DeviceNode節(jié)點
- policy = 1; // policy字段是驅(qū)動服務發(fā)布的策略,在驅(qū)動服務管理章節(jié)有詳細介紹
- priority = 100; // 驅(qū)動啟動優(yōu)先級(0-200),值越大優(yōu)先級越低,建議默認配100,優(yōu)先級相同則不保證device的加載順序
- preload = 0; // 驅(qū)動按需加載字段,在本章節(jié)最后的說明有詳細介紹
- permission = 0664; // 驅(qū)動創(chuàng)建設備節(jié)點權(quán)限
- moduleName = "sample_driver"; // 驅(qū)動名稱,該字段的值必須和驅(qū)動入口結(jié)構(gòu)的moduleName值一致
- serviceName = "sample_service"; // 驅(qū)動對外發(fā)布服務的名稱,必須唯一
- deviceMatchAttr = "sample_config"; // 驅(qū)動私有數(shù)據(jù)匹配的關(guān)鍵字,必須和驅(qū)動私有數(shù)據(jù)配置表中的match_attr值相等
- }
- }
- }
- }
- }
這里僅增加我自己的一些粗淺理解:
host + hostName:一個host,就是同一類設備驅(qū)動的容器。如下面的平臺類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 : 某一類具體設備的某些具體的設備節(jié)點,如I2C總線上掛著設備0,設備1,它們分別有各自的驅(qū)動配置
- device_i2c :: device {
- device0 :: deviceNode {
- ......
- }
- device1 :: deviceNode {
- ......
- }
- }
- device_uart :: device {
- device0 :: deviceNode {
- ......
- }
- device1 :: deviceNode {
- ......
- }
- }
接下來就是具體的deviceNode的各個字段了,以前文提到的uart驅(qū)動示例程序的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:驅(qū)動服務發(fā)布的策略,官方文檔《驅(qū)動服務管理》章節(jié)有非常詳細的解釋。
- priority :驅(qū)動啟動優(yōu)先級(0-200),值越大優(yōu)先級越低: 0~ 49板級驅(qū)動,50~149設備驅(qū)動,150~200 接口拔插類設備驅(qū)動
- preload :驅(qū)動加載方式,支持按需加載和按序加載兩種方式,官方文檔《驅(qū)動開發(fā)》章節(jié)也有非常詳細的解釋。
- permission :驅(qū)動創(chuàng)建設備節(jié)點權(quán)限,默認是0666
- moduleName = "UART_SAMPLE":驅(qū)動名稱,該字段的值必須和驅(qū)動入口結(jié)構(gòu)的moduleName值一致。
本文開頭的“2. 驅(qū)動程序的內(nèi)核空間部分的實現(xiàn)和編譯腳本”中的內(nèi)核實現(xiàn)部分代碼中的驅(qū)動入口結(jié)構(gòu) 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":驅(qū)動對外發(fā)布服務的名稱,必須唯一,這是調(diào)用者找到驅(qū)動服務的憑證,要完全匹配才能找到并使用對應的驅(qū)動服務。
本文開頭的“3. 驅(qū)動程序的用戶空間部分的實現(xiàn)和編譯腳本”中的實現(xiàn)部分代碼://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":驅(qū)動私有數(shù)據(jù)匹配的關(guān)鍵字,必須和驅(qū)動私有數(shù)據(jù)配置表中的match_attr值相等
這是 device_info.hcs 設備信息與下面的 xxx_config.hcs 中設備專屬資源描述掛鉤的憑證,device_info.hcs是設備樹的樹干和樹枝,xxx_config.hcs 內(nèi)的節(jié)點就是一片片樹葉,deviceMatchAttr 就是樹枝和葉片之間的葉柄。
【3-3】xxx_config.hcs:這是對特定設備專屬資源的分別描述,不同類別的設備,各自使用的資源肯定也不同,會有自己的特定描述信息。
例如,//vendor/huawei/hdf/sample/config/uart/uart_config.hcs 文件對該設備節(jié)點的描述,上面的 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 的其他字段則是對這個設備節(jié)點的一些資源的初始化/默認配置了。
這些配置在 HdfDeviceObject 結(jié)構(gòu)體中,通過 property 指向的樹形結(jié)構(gòu)來保存:
- /** 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)中調(diào)用 AttachUartDevice() 再調(diào)用GetUartDeviceResource()來讀取property樹形結(jié)構(gòu),從中解析出相關(guān)字段和值,保存在 struct UartDevice *uartDevice 結(jié)構(gòu)體中,以供調(diào)用:
- 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;
- };
其他類型的設備節(jié)點專屬資源,有各自定義的API和相關(guān)結(jié)構(gòu)體做類似的事情。
對驅(qū)動配置文件的更多詳情,還是請去官方文檔仔細研讀,比如驅(qū)動服務的管理、消息機制的管理和HCS的語法等等。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)