鸿蒙驱动实战

本文首发于: LHM’s notes欢迎关注我的新博客

用户态代码
#include <stdio.h>
#include "los_sample.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"

enum rw {
	regrd,
	regwd,
};

int main(int argc, char **argv)
{
    printf("\n************************************************\n");
    printf("\n\t\t lhm's test --> fist drv!\n");
    printf("\n***********************************************\n\n");

	struct HdfIoService *serv = HdfIoServiceBind("sample_service", 0);
	if (serv == NULL) {
		printf("fail to get service %s\n", "sample_service");
		return HDF_FAILURE;
	} else {
		printf("get service %s\n", "sample_service");
	}

	// 分配两个消息交互需要的hdfbuf
	struct HdfSBuf *data = HdfSBufObtainDefaultSize();
	if (data == NULL) {
		printf("fail to obtain sbuf data\n");
		return -1;
	}
	struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
	if (data == NULL) {
		printf("fail to obtain sbuf reply\n");
		return -1;
	}

	//向data中写入寄存器数据 32位
	if (HdfSbufWriteUint32(data, (int)0x45) == false) {
		printf("fail to write sbuf\n");
		return -1;
	}
	// 调用dispatch
	int ret = serv->dispatcher->Dispatch(&serv->object, regwd, data, reply);
	if (ret != HDF_SUCCESS) {
		printf("app fail to write\n");
		return -1;
	}

	ret = serv->dispatcher->Dispatch(&serv->object, regrd, data, reply);
	if (ret != HDF_SUCCESS) {
		printf("app fail to read\n");
		return -1;
	}

	int regdata = 0;
	if (HdfSbufReadUint32(reply, (unsigned int*)&regdata) == false) {
		printf("app fail to read ss\n");
		return -1;
	}
	printf("reg data: 0x%x\n", regdata);
    return 0;
}
驱动文件

vendor/huawei/hdf下新建文件夹,内部新增驱动文件

#include "hdf_device_desc.h"  // HDF框架对驱动开放相关能力接口的头文件
#include "hdf_log.h"          // HDF 框架提供的日志接口头文件

#define HDF_LOG_TAG sample_driver   // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签

int reg = 0;

enum rw {
	regrd,
	regwd,
};

int func_regrd(void) {
	return reg;
}

void func_regwd(int regdata) {
	reg = regdata;
}

// 驱动服务结构的定义
struct ISampleDriverService {
    struct IDeviceIoService ioService;  //服务结构的首个成员必须是IDeviceIoService类型的成员
	// 下面可以自定义驱动的服务接口
	int (*ServiceRd)(void);
	void (*ServiceWd)(int);
};  

int32_t SampleDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply) {
	int tmp = 0;
	const struct ISampleDriverService *sampleService =
		(const struct ISampleDriverService*)DevSvcManagerClntGetService("sample_service");

	if (cmdCode == regrd) {
		tmp = sampleService->ServiceRd();
		if (HdfSbufWriteUint32(reply, tmp) == false) {
			HDF_LOGE("fail to write sbuf");
		} else {
			HDF_LOGI(" write sbuf success");
		}
	} else if (cmdCode == regwd) {
		if (HdfSbufReadUint32(data, (unsigned int*)&tmp) == false) {
			HDF_LOGE("DRV fail to READ sbuf");
		} else {
			sampleService->ServiceWd(tmp);
			HDF_LOGI(" READ sbuf success");
		}
	}
	return 0;
}

//驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
{
	// deviceObject为hdf框架每一个驱动创建设备对象 用来保存设备相关的私有数据和服务接口
	if (deviceObject == NULL) {
		HDF_LOGE("deviceObject is null");
		return -1;
	}
	static struct ISampleDriverService mySampleDriver = {
		.ioService.Dispatch = SampleDriverDispatch,
		.ServiceRd = func_regrd,
		.ServiceWd = func_regwd,
	};
	deviceObject->service = &mySampleDriver.ioService;

    HDF_LOGD("Sample driver bind success");
    return 0;
}

// 驱动自身业务初始的接口
int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGD("Sample driver Init success");
    return 0;
}

// 驱动资源释放的接口
void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGD("Sample driver release success");
    return;
}

// 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量
struct HdfDriverEntry g_sampleDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "sample_driver",
    .Bind = HdfSampleDriverBind,
    .Init = HdfSampleDriverInit,
    .Release = HdfSampleDriverRelease,
};

// 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
HDF_INIT(g_sampleDriverEntry);
配置文件

目录:vendor/hisi/hi35xx/hi3518ev300/config/device_info/device_info/device_info.hcs

添加方式有两种,第一种是新建一个sample_host节点

sample_host :: host{
    hostName = "host0";  // host名称,host节点是用来存放某一类驱动的容器
    priority = 100; //值越大 优先级越低
}

第二种是在host节点下面,新增一个device节点

device_sample :: device {
    device0 :: deviceNode {
        policy = 2;  // 2->内核态 和用户态都发布服务
        priority = 100;
        permission = 0644;
        moduleName = "sample_driver";
        serviceName = "sample_service";
        deviceMatchAttr = "sample_driver";
    }
}

私有配置文件信息

目录:vendor/hisi/hi35xx/hi3518ev300/config/

新建test 目录,新增sample_config.hcs

root{
    sample_version = 1;
    author = "lhm";
    module = "sample_driver";
    serviceName = "sample_service";
    match_attr = "sample_config";   //该字段的值必须和device_info.hcs中deviceMatchAttr值一致
}

私有配置写好后,需要加载到板级配置入口文件vendor/hisi/hi35xx/hi3518ev300/config/hdf.hcs

驱动编译配置项

驱动代码的编译必须使用HDF框架提供的Makefile模板进行编译

1/首先是Kconfig, 路径与驱动文件同级

config DRIVERS_HDF_PLATFORM_UART_SAMPLE
    bool "Enable HDF platform lhm sample driver"
    default n
    depends on DRIVERS_HDF_PLATFORM
    help
      Answer Y to enable HDF platform uart sample driver.

2/然后在test目录下新增Makefile文件

include $(LITEOSTOPDIR)/config.mk
include $(LITEOSTOPDIR)/../../drivers/hdf/lite/lite.mk

MODULE_NAME := sample_driver
LOCAL_CFLAGS += $(HDF_INCLUDE)
LOCAL_SRCS += sample_driver.c
LOCAL_HCS_SRCS+=test/sample_config.hcs
LOCAL_CFLAGS += -fstack-protector-strong

include $(HDF_DRIVER)

3/将新增Kconfig文件添加到test文件夹同级目录下的Kconfig文件中

目录:vendor/huawei/hdf/Kconfig

修改:

source "../../vendor/hisi/hi35xx/platform/Kconfig"
source "../../vendor/huawei/hdf/wifi/driver/Kconfig"
source "../../vendor/huawei/hdf/input/driver/Kconfig"
source "../../vendor/huawei/hdf/display/driver/Kconfig"
source "../../vendor/huawei/hdf/test/Kconfig"

4/修改vendor/huawei/hdf/hdf_vendor.mk文件

LITEOS_BASELIB += -lsample_driver
LIB_SUBDIRS += $(VENDOR_HDF_DRIVERS_ROOT)/test

遇到的问题

首先在官网指导最后面,有这样一句话
harmony_docs
在这里插入图片描述
然后按这个说明将这个deps替代原来那个;这个位置其实依赖的是共享so; 原来代码是不需要任何依赖,但是里面写了个:hello_word 估计是个模板。

在这里插入图片描述
需要注意的是,间距调整不能用table键,不然会报如下错误:

ERROR at //applications/sample/camera/app/BUILD.gn:41:1: Invalid token.
        "//drivers/hdf/lite/manager:hdf_core",
^
You got a tab character in here. Tabs are evil. Convert to spaces.

修改成空格后,接着编译,报错找不到头文件。

helloworld.c:22:10: fatal error: 'hdf_sbuf.h' file not found

找了下头文件的位置:

[root@iZ8vb7hcv48qpdyb1zrnfjZ sourceCode]# find -name hdf_sbuf.h ./drivers/hdf/frameworks/ability/sbuf/include/hdf_sbuf.h

将头文件目录添加到BUILD.gn中,再次编译,报错hdf_sbuf.h中include的一个头文件找不到,说明头文件目录还没有添加全,继续全局搜索,添加头文件目录

最后添加目录如下:

 include_dirs = [
        "include",
        "//drivers/hdf/frameworks/ability/sbuf/include",
        "//drivers/hdf/frameworks/utils/include",
        "//drivers/hdf/frameworks/include/core",
        "//drivers/hdf/frameworks/include/utils",
    ]

此时编译,不会出现头文件找不到的目录,出现另一个错误

ld.lld: error: undefined symbol: HdfIoServiceBind
>>> referenced by ld-temp.o
>>>               lto.tmp:(main)

在这里插入图片描述

重新梳理了下流程,这个感觉是没有正确依赖so; 官网最后的声明也确实强调要新增两个库的依赖,那会不会是这两行deps 放的位置不对呢? 在看了其他文件夹中BUILD.gn的写法后,修改尝试下(将deps上移)
在这里插入图片描述
放到feature后,这个问题就迈过去了;

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值