创建SOC驱动构建入口
#文件device/vendor_name/soc_name/drivers/lite.mk
SOC_DRIVER_ROOT := $(LITEOSTOPDIR)/../../device/$(SOC_VENDOR_NAME)/$(SOC_NAME)/drivers/
# 判断如果打开了GPIO的内核编译开关
ifeq ($(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO), y)
# 构建完成要链接一个叫hdf_gpio的对象
LITEOS_BASELIB += -lhdf_gpio
# 增加构建目录gpio
LIB_SUBDIRS += $(SOC_DRIVER_ROOT)/gpio
endif
# 后续其他驱动在此基础上追加
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
创建GPIO构建入口
include $(LITEOSTOPDIR)/config.mk
include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk
# 指定输出对象的名称,注意要与SOC驱动构建入口里的LITEOS_BASELIB 保持一致
MODULE_NAME := hdf_gpio
# 增加HDF框架的INCLUDE
LOCAL_CFLAGS += $(HDF_INCLUDE)
# 要编译的文件
LOCAL_SRCS += soc_name_gpio.c
# 编译参数
LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror -fsigned-char -fno-strict-aliasing -fno-common
include $(HDF_DRIVER)
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
配置产品加载驱动
产品的所有设备信息被定义在源码文件//vendor/vendor_name/product_name/config/device_info/device_info.hcs
中。
平台驱动请添加到platform的host中。
说明: moduleName要与驱动定义中的相同。
root {
...
platform :: host {
device_gpio :: device {
device0 :: deviceNode {
policy = 0;
priority = 10;
permission = 0644;
moduleName = "SOC_NAME_gpio_driver";
}
}
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
平台驱动移植
在这一步,我们会在源码目录//device/vendor_name/soc_name/drivers
目录下创建平台驱动,如果你要移植的SOC的厂商还没有创建仓库的话,请联系 sig_devboard 创建。
建议的目录结构:
device
├── vendor_name
│ ├── drivers
│ │ │ ├── common
│ │ │ ├── Kconfig # 厂商驱动内核菜单入口
│ │ │ └── lite.mk # 构建的入口
│ ├── soc_name
│ │ ├── drivers
│ │ │ ├── dmac
│ │ │ ├── gpio
│ │ │ ├── i2c
│ │ │ ├── LICENSE
│ │ │ ├── mipi_dsi
│ │ │ ├── mmc
│ │ │ ├── pwm
│ │ │ ├── README.md # docs 如果需要的话
│ │ │ ├── README_zh.md
│ │ │ ├── rtc
│ │ │ ├── spi
│ │ │ ├── uart
│ │ │ └── watchdog
│ ├── board_name
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
HDF为所有的平台驱动都创建了驱动模型,移植平台驱动的主要工作是向模型注入实例。 这些模型你可以在源码目录//drivers/hdf_core/framework/support/platform/include
中找到定义。
本节我们会以GPIO为例,讲解如何移植平台驱动,移植过程包含以下步骤:
创建GPIO驱动
在源码目录//device/vendor_name/soc_name/drivers/gpio
中创建文件soc_name_gpio.c
。内容模板如下:
#include "gpio_core.h"
// 定义GPIO结构体,如果需要的话
struct SocNameGpioCntlr {
struct GpioCntlr cntlr; // 这是HDF GPIO驱动框架需要的结构体
int myData; // 以下是当前驱动自身需要的
};
// Bind 方法在HDF驱动中主要用户对外发布服务,这里我们不需要,直接返回成功即可
static int32_t GpioBind(struct HdfDeviceObject *device)
{
(void)device;
return HDF_SUCCESS;
}
// Init方法时驱动初始化的入口,我们需要在Init方法中完成模型实例的注册
static int32_t GpioInit(struct HdfDeviceObject *device)
{
SocNameGpioCntlr *impl = CreateGpio(); // 你的创建代码
ret = GpioCntlrAdd(&impl->cntlr); // 注册GPIO模型实例
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: err add controller:%d", __func__, ret);
return ret;
}
return HDF_SUCCESS;
}
// Release方法会在驱动卸载时被调用,这里主要完成资源回收
static void GpioRelease(struct HdfDeviceObject *device)
{
// GpioCntlrFromDevice 方法能从抽象的设备对象中获得init方法注册进去的模型实例。
struct GpioCntlr *cntlr = GpioCntlrFromDevice(device);
//资源释放...
}
struct HdfDriverEntry g_gpioDriverEntry = {
.moduleVersion = 1,
.Bind = GpioBind,
.Init = GpioInit,
.Release = GpioRelease,
.moduleName = "SOC_NAME_gpio_driver", // 这个名字我们稍后会在配置文件中用到,用来加载驱动。
};
HDF_INIT(g_gpioDriverEntry); // 注册一个GPIO的驱动入口
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
创建厂商驱动构建入口
如前所述device/vendor_name/drivers/lite.mk
是厂商驱动的构建的入口。我们需要从这个入口开始,进行构建。
#文件device/vendor_name/drivers/lite.mk
SOC_VENDOR_NAME := $(subst $/",,$(LOSCFG_DEVICE_COMPANY))
SOC_NAME := $(subst $/",,$(LOSCFG_PLATFORM))
BOARD_NAME := $(subst $/",,$(LOSCFG_PRODUCT_NAME))
# 指定SOC进行构建
LIB_SUBDIRS += $(LITEOSTOPDIR)/../../device/$(SOC_VENDOR_NAME)/$(SOC_NAME)/drivers/
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
创建SOC驱动构建入口
#文件device/vendor_name/soc_name/drivers/lite.mk
SOC_DRIVER_ROOT := $(LITEOSTOPDIR)/../../device/$(SOC_VENDOR_NAME)/$(SOC_NAME)/drivers/
# 判断如果打开了GPIO的内核编译开关
ifeq ($(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO), y)
# 构建完成要链接一个叫hdf_gpio的对象
LITEOS_BASELIB += -lhdf_gpio
# 增加构建目录gpio
LIB_SUBDIRS += $(SOC_DRIVER_ROOT)/gpio
endif
# 后续其他驱动在此基础上追加
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
创建GPIO构建入口
include $(LITEOSTOPDIR)/config.mk
include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk
# 指定输出对象的名称,注意要与SOC驱动构建入口里的LITEOS_BASELIB 保持一致
MODULE_NAME := hdf_gpio
# 增加HDF框架的INCLUDE
LOCAL_CFLAGS += $(HDF_INCLUDE)
# 要编译的文件
LOCAL_SRCS += soc_name_gpio.c
# 编译参数
LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror -fsigned-char -fno-strict-aliasing -fno-common
include $(HDF_DRIVER)
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
配置产品加载驱动
产品的所有设备信息被定义在源码文件//vendor/vendor_name/product_name/config/device_info/device_info.hcs
中。
平台驱动请添加到platform的host中。
说明: moduleName要与驱动定义中的相同。
root {
...
platform :: host {
device_gpio :: device {
device0 :: deviceNode {
policy = 0;
priority = 10;
permission = 0644;
moduleName = "SOC_NAME_gpio_driver";
}
}
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
器件驱动移植
LCD驱动移植
移植LCD驱动的主要工作是编写一个驱动,在驱动中生成模型的实例,并完成注册。
这些LCD的驱动被放置在源码目录//drivers/hdf_core/framework/model/display/driver/panel
中。
创建Panel驱动
创建HDF驱动,在驱动初始化中调用RegisterPanel接口注册模型实例。如:
int32_t LCDxxEntryInit(struct HdfDeviceObject *object)
{
struct PanelData *panel = CreateYourPanel();
// 注册模型实例
if (RegisterPanel(panel) != HDF_SUCCESS) {
HDF_LOGE("%s: RegisterPanel failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
struct HdfDriverEntry g_xxxxDevEntry = {
.moduleVersion = 1,
.moduleName = "LCD_XXXX",
.Init = LCDxxEntryInit,
};
HDF_INIT(g_xxxxDevEntry);
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
配置加载panel驱动
产品的所有设备信息被定义在源码文件//vendor/vendor_name/product_name/config/device_info/device_info.hcs
中。修改该文件,在display的host中,名为device_lcd的device中增加配置。
注意: moduleName 要与panel驱动中的moduleName相同。
root {
...
display :: host {
device_lcd :: device {
deviceN :: deviceNode {
policy = 0;
priority = 100;
preload = 2;
moduleName = "LCD_XXXX";
}
}
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
TP驱动移植
本节描述如何移植触摸屏驱动。触摸屏的器件驱动被放置在源码目录//drivers/hdf_core/framework/model/input/driver/touchscreen
中。 移植触摸屏驱动主要工作是向系统注册ChipDevice模型实例。
详细的驱动开发指导,请参考 TOUCHSCREEN开发指导。
创建触摸屏器件驱动
在上述touchscreen目录中创建名为touch_ic_name.c
的文件。编写如下内容
#include "hdf_touch.h"
static int32_t HdfXXXXChipInit(struct HdfDeviceObject *device)
{
ChipDevice *tpImpl = CreateXXXXTpImpl();
if(RegisterChipDevice(tpImpl) != HDF_SUCCESS) { // 注册ChipDevice模型
ReleaseXXXXTpImpl(tpImpl);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
struct HdfDriverEntry g_touchXXXXChipEntry = {
.moduleVersion = 1,
.moduleName = "HDF_TOUCH_XXXX", // 注意这里的moduleName要与后续的配置完全一致
.Init = HdfXXXXChipInit,
};
HDF_INIT(g_touchXXXXChipEntry);
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
其中ChipDevice中要实现如下方法:
class="table-box">方法 实现说明 int32_t (*Init)(ChipDevice *device) 实现器件初始化 int32_t (*Detect)(ChipDevice *device) 实现器件探测 int32_t (*Suspend)(ChipDevice *device) 实现器件休眠 int32_t (*Resume)(ChipDevice *device) 实现器件唤醒 int32_t (*DataHandle)(ChipDevice *device) 需要实现从器件读取数据,将触摸点数据填写入device->driver->frameData中 int32_t (*UpdateFirmware)(ChipDevice *device) 实现固件升级
配置产品,加载器件驱动
产品的所有设备信息被定义在源码文件//vendor/vendor_name/product_name/config/device_info/device_info.hcs
中。修改该文件,在名为input的host中,名为device_touch_chip的device中增加配置。
说明: moduleName 要与触摸屏驱动中的moduleName相同。
deviceN :: deviceNode {
policy = 0;
priority = 130;
preload = 0;
permission = 0660;
moduleName = "HDF_TOUCH_XXXX";
deviceMatchAttr = "touch_XXXX_configs";
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
WLAN驱动移植
WLAN驱动分为两部分,一部分负责管理WLAN设备,另一个部分负责处理WLAN流量。
图1 OpenHarmony WLAN结构示意图
如图1,左半部分负责管理WLAN设备,右半部分负责WLAN流量。HDF WLAN分别为这两部分做了抽象,驱动的移植过程可以看做分别实现这两部分所需接口。这些接口有:
class="table-box">接口 定义头文件 接口说明 HdfChipDriverFactory drivers\hdf_core\framework\include\wifi\hdf_wlan_chipdriver_manager.h ChipDriver的Factory,用于支持一个芯片多个WLAN端口 HdfChipDriver drivers\hdf_core\framework\include\wifi\wifi_module.h 每个WLAN端口对应一个HdfChipDriver,用来管理一个特定端口 NetDeviceInterFace drivers\hdf_core\framework\include\wifi\net_device.h 与协议栈之间的接口,如发送数据、设置网络接口状态等
说明: 详细的接口开发指导,请参考WLAN开发。
具体的移植步骤如下:
创建HDF WLAN芯片驱动
在目录/device/vendor_name/peripheral/wifi/chip_name/
创建文件hdf_wlan_chip_name.c
。内容模板如下:
static int32_t HdfWlanXXXChipDriverInit(struct HdfDeviceObject *device) {
static struct HdfChipDriverFactory factory = CreateChipDriverFactory(); // 需要移植者实现的方法
struct HdfChipDriverManager *driverMgr = HdfWlanGetChipDriverMgr();
if (driverMgr->RegChipDriver(&factory) != HDF_SUCCESS) { // 注册驱动工厂
HDF_LOGE("%s fail: driverMgr is NULL!", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
struct HdfDriverEntry g_hdfXXXChipEntry = {
.moduleVersion = 1,
.Init = HdfWlanXXXChipDriverInit,
.Release = HdfWlanXXXChipRelease,
.moduleName = "HDF_WIFI_CHIP_XXX" // 注意:这个名字要与配置一致
};
HDF_INIT(g_hdfXXXChipEntry);
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
在上述代码的CreateChipDriverFactory方法中,需要创建一个HdfChipDriverFactory类型的对象。该对象提供如下方法:
class="table-box">接口 说明 const char *driverName 当前driverName int32_t (*InitChip)(struct HdfWlanDevice *device) 初始化芯片 int32_t (*DeinitChip)(struct HdfWlanDevice *device) 去初始化芯片 void (*ReleaseFactory)(struct HdfChipDriverFactory *factory) 释放HdfChipDriverFactory对象 struct HdfChipDriver *(*Build)(struct HdfWlanDevice *device, uint8_t ifIndex) 创建一个HdfChipDriver;输入参数中,device是设备信息,ifIndex是当前创建的接口在这个芯片中的序号 void (*Release)(struct HdfChipDriver *chipDriver) 释放chipDriver uint8_t (*GetMaxIFCount)(struct HdfChipDriverFactory *factory) 获取当前芯片支持的最大接口数
其中Build方法负责创建一个管理指定网络接口的对象HdfChipDriver。该对象需要提供方法:
class="table-box">接口 说明 int32_t (*init)(struct HdfChipDriver *chipDriver, NetDevice *netDev) 初始化当前网络接口,这里需要向netDev提供接口NetDeviceInterFace int32_t (*deinit)(struct HdfChipDriver *chipDriver, NetDevice *netDev) 去初始化当前网络接口 struct HdfMac80211BaseOps *ops WLAN基础能力接口集 struct HdfMac80211STAOps *staOps 支持STA模式所需的接口集 struct HdfMac80211APOps *apOps 支持AP模式所需要的接口集
编写配置文件描述驱动支持的芯片
在产品配置目录下创建芯片的配置文件,保存至源码路径//vendor/vendor_name/product_name/config/wifi/wlan_chip_chip_name.hcs
该文件模板如下:
root {
wlan_config {
chip_name :& chipList {
chip_name :: chipInst {
match_attr = "hdf_wlan_chips_chip_name"; /* 这是配置匹配属性,用于提供驱动的配置根 */
driverName = "driverName"; /* 需要与HdfChipDriverFactory中的driverName相同*/
sdio {
vendorId = 0xXXXX; /* your vendor id */
deviceId = [0xXXXX]; /*your supported devices */
}
}
}
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明:
路径和文件中的vendor_name、product_name、chip_name请替换成实际名称。
vendorId 和 deviceId需要根据实际芯片的识别码进行填写。
编写配置文件,加载驱动
产品的所有设备信息被定义在源码文件//vendor/vendor_name/product_name/config/device_info/device_info.hcs
中。修改该文件,在名为network的host中,名为device_wlan_chips的device中增加配置。模板如下:
deviceN :: deviceNode {
policy = 0;
preload = 2;
moduleName = "HDF_WLAN_CHIPS";
deviceMatchAttr = "hdf_wlan_chips_chip_name";
serviceName = "driverName";
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明: moduleName 要与HDF WLAN 芯片驱动中的moduleName相同。
修改Kconfig文件,让移植的WLAN模组出现再内核配置中
在device/vendor_name/drivers/Kconfig
中增加配置菜单,模板如下
config DRIVERS_HDF_WIFI_chip_name
bool "Enable chip_name Host driver"
default n
depends on DRIVERS_HDF_WLAN help
Answer Y to enable chip_name Host driver.
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明: 请替换模板中的chip_name为实际的芯片名称。
修改构建脚本,让驱动参与内核构建
在源码文件//device/vendor_name/drivers/lite.mk
末尾追加如下内容。
ifeq ($(LOSCFG_DRIVERS_HDF_WIFI_chip_name), y)
# 构建完成要链接一个叫hdf_wlan_chipdriver_chip_name的对象,建议按这个命名,防止冲突
LITEOS_BASELIB += -lhdf_wlan_chipdriver_chip_name
# 增加构建目录gpio
LIB_SUBDIRS += ../peripheral/wifi/chip_name
endif
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明: 请替换模板中的chip_name为实际的芯片名称。
如果大家想更加深入的学习 OpenHarmony(鸿蒙南向) 开发的全栈内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:
搭建开发环境 Windows 开发环境的搭建 Ubuntu 开发环境搭建 Linux 与 Windows 之间的文件共享 ……
构建子系统 启动流程 子系统 分布式任务调度子系统 分布式通信子系统 驱动子系统 ……
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙: 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05
data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/maniuT/article/details/140832440","extend1":"pc","ab":"new"}">>
评论记录:
回复评论: