HDF驅動框架探路(三):基于3516配置一套可以打通的HDF驅動程序
老規(guī)矩還是將最終希望跑出來的效果放出來。如下:

前言
大家如果有讀過第二篇文章的話,可能發(fā)現(xiàn)了在該文中內核態(tài)的驅動程序是直接引用了源碼中已經存在的一個HDF驅動模塊。所以本文的就是著重解決這個問題,也就是自己去配置一個HDF驅動模塊。
本文是基于3516的小型系統(tǒng)去驗證的。
本文框架圖

觀察上圖,其實本文是將上文的流程進一步細化,上文中的驅動程序細分成了三個部分,分別是:HCS文件配置、內核態(tài)代碼、liteos_a配置編譯進內核。這三個部分合起來就是自己搭建HDF驅動程序的步驟。
1. HDF配置
這里的HDF配置是按照源碼中已經存在的sample_driver模塊來的
打開文件vendor/hisilicon/hispark_taurus/hdf_config/hdf_test/hdf_test_manager/device_info.hcs,然后加入下述代碼中的device2。
- device1 :: deviceNode {
- policy = 2;
- priority = 10;
- preload = 0;
- permission = 0644;
- moduleName = "sample_driver";
- serviceName = "sample_service";
- }
- device2 :: deviceNode { // DeviceNode of the sample driver
- policy = 2; // Driver service release policy. For details, see section Driver Service Management.
- priority= 10; // Driver startup priority (0-200). A larger value indicates a lower priority. The default value 100 is recommended. If the priorities are the same, the device loading sequence is random.
- preload = 0; // On-demand loading of the driver. For details, see "NOTE" at the end of this section.
- permission = 0664; // Permission for the driver to create device nodes.
- moduleName = "talkweb_driver"; // Driver name. The value of this field must be the same as the value of moduleName in the driver entry structure.
- serviceName = "talkweb_service"; // Name of the service released by the driver. The name must be unique.
- }
- }
- device_platform_test :: device {
- platform_test:: deviceNode {
- policy = 1;
- priority = 150;
- preload = 0;
- permission = 0644;
- moduleName = "PLATFORM_TEST_DRIVER";
- serviceName = "PLATFORM_TEST";
- deviceMatchAttr = "platform_test";
- }
- }
2. liteos_a編譯配置
該步驟的作用是將第三步中的驅動程序編譯進入內核。
2.1 在BUILD.gn文件中配置
打開drivers/adapter/khdf/liteos/test/BUILD.gn文件
- --- a/khdf/liteos/test/BUILD.gn
- +++ b/khdf/liteos/test/BUILD.gn
- @@ -37,6 +37,7 @@ hdf_driver(module_name) {
- sources = [
- "$HDF_TEST_FRAMWORK_ROOT/common/hdf_main_test.c",
- "$HDF_TEST_FRAMWORK_ROOT/manager/sample_driver_test.c",
- + "$HDF_TEST_FRAMWORK_ROOT/talkwebtest/talkweb.c",
- "$HDF_TEST_FRAMWORK_ROOT/osal/osal_all_test.c",
- "$HDF_TEST_FRAMWORK_ROOT/osal/osal_file_test.c",
- "$HDF_TEST_FRAMWORK_ROOT/osal/osal_get_case_test.c",
2.2 在Makefile中進行添加配置
drivers/adapter/khdf/liteos/test/Makefile
- --- a/khdf/liteos/test/Makefile
- +++ b/khdf/liteos/test/Makefile
- @@ -34,6 +34,7 @@ HDF_TEST_FRAMWORK_ROOT = $(LITEOSTOPDIR)/../../drivers/framework/test/unittest
- LOCAL_SRCS := $(HDF_TEST_FRAMWORK_ROOT)/common/hdf_main_test.c \
- $(HDF_TEST_FRAMWORK_ROOT)/manager/sample_driver_test.c \
- + $(HDF_TEST_FRAMWORK_ROOT)/talkwebtest/talkweb.c \
- $(HDF_TEST_FRAMWORK_ROOT)/osal/osal_test_entry.c \
- $(HDF_TEST_FRAMWORK_ROOT)/osal/osal_all_test.c \
- $(HDF_TEST_FRAMWORK_ROOT)/osal/osal_file_test.c \
3. 驅動程序
進入drivers/framework/test/unittest目錄下,新建talkwebtest目錄
3.1 在上述目錄下新建talkweb.h文件,將下述代碼放入
- #ifndef HDF_SAMPLE_DRIVER_H
- #define HDF_SAMPLE_DRIVER_H
- #include "hdf_object.h"
- #define SAMPLE_SERVICE "sample_service"
- typedef enum {
- SAMPLE_DRIVER_REGISTER_DEVICE = 0,
- SAMPLE_DRIVER_UNREGISTER_DEVICE,
- SAMPLE_DRIVER_SENDEVENT_SINGLE_DEVICE,
- SAMPLE_DRIVER_SENDEVENT_BROADCAST_DEVICE,
- SAMPLE_DRIVER_PM_STATE_INJECT,
- } SAMPLE_DRIVER_CMDID;
- struct HdfDeviceObject *GetDeviceObject(void);
- #endif // HDF_MAIN_TEST_H
3.2 在上述目錄下新建talkweb.c文件,將下述代碼放入
- /*
- * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
- *
- * HDF is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- * See the LICENSE file in the root of this repository for complete details.
- */
- #include "talkweb.h"
- #include "devsvc_manager_clnt.h"
- #include "devmgr_service.h"
- #include "hdf_log.h"
- #include "hdf_device_desc.h"
- #include "hdf_pm.h"
- #include "device_resource_if.h"
- #include "osal_io.h"
- #include "osal_mem.h"
- #include "gpio_if.h"
- #include "osal_irq.h"
- #include "osal_time.h"
- //#define HDF_LOG_TAG led_driver // 打印日志所包含的標簽,如果不定義則用默認> 定義的HDF_TAG標簽
- #define LED_WRITE_READ 88
- #define HDF_LOG_TAG sample_driver_test
- #ifndef INT32_MAX
- #define INT32_MAX 0x7fffffff
- #endif
- void HdftalkwebDriverRelease(struct HdfDeviceObject *deviceObject)
- {
- (void)deviceObject;
- return;
- }
- int32_t talkwebDriverRegisterDevice(struct HdfSBuf *data)
- {
- const char *moduleName = NULL;
- const char *serviceName = NULL;
- struct HdfDeviceObject *devObj = NULL;
- if (data == NULL) {
- return HDF_FAILURE;
- }
- moduleName = HdfSbufReadString(data);
- if (moduleName == NULL) {
- return HDF_FAILURE;
- }
- serviceName = HdfSbufReadString(data);
- if (serviceName == NULL) {
- return HDF_FAILURE;
- }
- devObj = HdfRegisterDevice(moduleName, serviceName, NULL);
- if (devObj == NULL) {
- return HDF_FAILURE;
- }
- return HDF_SUCCESS;
- }
- int32_t talkwebDriverUnregisterDevice(struct HdfSBuf *data)
- {
- const char *moduleName = NULL;
- const char *serviceName = NULL;
- if (data == NULL) {
- return HDF_FAILURE;
- }
- moduleName = HdfSbufReadString(data);
- if (moduleName == NULL) {
- return HDF_FAILURE;
- }
- serviceName = HdfSbufReadString(data);
- if (serviceName == NULL) {
- return HDF_FAILURE;
- }
- HdfUnregisterDevice(moduleName, serviceName);
- return HDF_SUCCESS;
- }
- int32_t talkwebDriverSendEvent(struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, bool broadcast)
- {
- return broadcast ? HdfDeviceSendEvent(client->device, id, data) : HdfDeviceSendEventToClient(client, id, data);
- }
- int32_t talkwebDriverPowerStateInject(uint32_t powerState)
- {
- int ret;
- struct IDevmgrService *devmgrService = DevmgrServiceGetInstance();
- if (devmgrService == NULL || devmgrService->PowerStateChange == NULL) {
- return HDF_ERR_INVALID_OBJECT;
- }
- ret = devmgrService->PowerStateChange(devmgrService, powerState);
- HDF_LOGI("%s: inject power state(%d) done, ret = %d", __func__, powerState, ret);
- return ret;
- }
- static int32_t CtlLED(int mode)
- {
- int32_t ret;
- uint16_t valRead;
- /* LED的GPIO管腳號 */
- uint16_t gpio = 5 * 8 + 1; // 紅外補光燈
- // uint16_t gpio = 2 * 8 + 3; // 綠色指示燈
- // uint16_t gpio = 3 * 8 + 4; // 紅色指示燈
- /* 將GPIO管腳配置為輸出 */
- ret = GpioSetDir(gpio, GPIO_DIR_OUT);
- if (ret != 0)
- {
- HDF_LOGE("GpioSerDir: failed, ret %d\n", ret);
- return ret;
- }
- if (mode == -1)
- {
- // 翻轉輸出口
- (void)GpioRead(gpio, &valRead);
- ret = GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW);
- }
- else
- {
- ret = GpioWrite(gpio, mode);
- }
- if (ret != 0)
- {
- HDF_LOGE("GpioWrite: failed, ret %d\n", ret);
- return ret;
- }
- return ret;
- }
- int32_t talkwebDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
- {
- HDF_LOGD("%s::qzk-enter", __func__);
- uint32_t powerState = 0;
- int32_t ret = HDF_SUCCESS;
- if (reply == NULL || client == NULL) {
- return HDF_FAILURE;
- }
- int32_t result = HDF_FAILURE;
- switch (cmdId) {
- case LED_WRITE_READ:
- const char *recv = HdfSbufReadString(data);
- if (recv != NULL)
- {
- //HDF_LOGI("recv: %s", recv);
- result = CtlLED(-1);
- // CtlLED(GPIO_VAL_HIGH);
- if (!HdfSbufWriteInt32(reply, result)){
- //HDF_LOGE("replay is fail");
- }
- return HdfDeviceSendEvent(client->device, cmdId, data);
- }
- break;
- case SAMPLE_DRIVER_REGISTER_DEVICE: {
- ret = talkwebDriverRegisterDevice(data);
- HdfSbufWriteInt32(reply, ret);
- break;
- }
- case SAMPLE_DRIVER_UNREGISTER_DEVICE:
- ret = talkwebDriverUnregisterDevice(data);
- HdfSbufWriteInt32(reply, ret);
- break;
- case SAMPLE_DRIVER_SENDEVENT_SINGLE_DEVICE:
- ret = talkwebDriverSendEvent(client, cmdId, data, false);
- HdfSbufWriteInt32(reply, INT32_MAX);
- break;
- case SAMPLE_DRIVER_SENDEVENT_BROADCAST_DEVICE:
- ret = talkwebDriverSendEvent(client, cmdId, data, true);
- HdfSbufWriteInt32(reply, INT32_MAX);
- break;
- case SAMPLE_DRIVER_PM_STATE_INJECT:
- HdfSbufReadUint32(data, &powerState);
- return talkwebDriverPowerStateInject(powerState);
- default:
- break;
- }
- return ret;
- }
- int HdftalkwebDriverBind(struct HdfDeviceObject *deviceObject)
- {
- static struct IDeviceIoService testService = {
- .Dispatch = talkwebDriverDispatch,
- .Open = NULL,
- .Release = NULL,
- };
- HDF_LOGD("%s::enter", __func__);
- if (deviceObject == NULL) {
- return HDF_FAILURE;
- }
- deviceObject->service = &testService;
- return HDF_SUCCESS;
- }
- int HdftalkwebDozeResume(struct HdfDeviceObject *deviceObject)
- {
- HDF_LOGI("%s:called", __func__);
- return HDF_SUCCESS;
- }
- int HdftalkwebDozeSuspend(struct HdfDeviceObject *deviceObject)
- {
- HDF_LOGI("%s:called", __func__);
- return HDF_SUCCESS;
- }
- int HdftalkwebResume(struct HdfDeviceObject *deviceObject)
- {
- HDF_LOGI("%s:called", __func__);
- return HDF_SUCCESS;
- }
- int HdftalkwebSuspend(struct HdfDeviceObject *deviceObject)
- {
- HDF_LOGI("%s:called", __func__);
- return HDF_SUCCESS;
- }
- struct talkwebDriverPmListener {
- struct IPowerEventListener powerListener;
- void *p;
- };
- int HdftalkwebDriverInit(struct HdfDeviceObject *deviceObject)
- {
- static struct talkwebDriverPmListener pmListener = {0};
- int ret;
- HDF_LOGI("%s::enter!", __func__);
- if (deviceObject == NULL) {
- HDF_LOGE("%s::ptr is null!", __func__);
- return HDF_FAILURE;
- }
- HDF_LOGD("%s:Init success", __func__);
- pmListener.powerListener.DozeResume = HdftalkwebDozeResume;
- pmListener.powerListener.DozeSuspend = HdftalkwebDozeSuspend;
- pmListener.powerListener.Resume = HdftalkwebResume;
- pmListener.powerListener.Suspend = HdftalkwebSuspend;
- ret = HdfPmRegisterPowerListener(deviceObject, &pmListener.powerListener);
- HDF_LOGI("%s:register power listener, ret = %d", __func__, ret);
- return HDF_SUCCESS;
- }
- struct HdfDriverEntry g_talkwebDriverEntry = {
- .moduleVersion = 1,
- .moduleName = "talkweb_driver",
- .Bind = HdftalkwebDriverBind,
- .Init = HdftalkwebDriverInit,
- .Release = HdftalkwebDriverRelease,
- };
- HDF_INIT(g_talkwebDriverEntry);
4. 應用態(tài)程序
這里的應用態(tài)程序的代碼和編譯方法,直接可以采用上文的就可以。
這里只需要修改SAMPLE_SERVICE_NAME這個宏。
- #define SAMPLE_SERVICE_NAME "talkweb_service"