【鸿蒙OS开发入门】18 - HDF驱动子系统:加速度计传感器 Driver层驱动代码分析_鸿蒙开发 传感器_"小夜猫&小懒虫&小财迷"的男人的博客-程序员秘密

技术标签: 鸿蒙OS开发  java  华为  harmonyos  


本系列文章汇总:

  1. 【鸿蒙OS开发入门】01 - 搭建Ubuntu虚拟机开发环境
  2. 【鸿蒙OS开发入门】02 - 启动流程代码分析之Uboot 第一阶段:之解压并引导加载u-boot.bin
  3. 【鸿蒙OS开发入门】03 - 启动流程代码分析之Uboot 第二阶段:之board_init初始化
  4. 【鸿蒙OS开发入门】04 - 启动流程代码分析之Uboot 第二阶段:之U_BOOT_CMD原理
  5. 【鸿蒙OS开发入门】05 - 启动流程代码分析之Uboot 第二阶段:之bootm引导加载Kernel OS
  6. 【鸿蒙OS开发入门】06 - 启动流程代码分析之KernelOS:之启动Linux-4.19 Kernel内核
  7. 【鸿蒙OS开发入门】07 - 安装docker环境编译openharmony 2.0代码
  8. 【鸿蒙OS开发入门】08 - 启动流程代码分析之KernelOS:之启动 liteos_a 内核
  9. 【鸿蒙OS开发入门】09 - 启动流程代码分析之KernelOS:之启动Linux-4.19 Kernel内核 中do_basic_setup()所干的大事
  10. 【鸿蒙OS开发入门】10 - 启动流程代码分析之第一个用户态进程:init 进程
  11. 【鸿蒙OS开发入门】11 - 启动流程代码分析之第一个用户态进程:init 进程 之 Services简介
  12. 【鸿蒙OS开发入门】12 - 启动流程代码分析之第一个用户态进程:init 进程 之 pre-init 任务详解
  13. 【鸿蒙OS开发入门】13 - 启动流程代码分析之第一个用户态进程:init 进程 之 init 任务详解
  14. 【鸿蒙OS开发入门】14 - 启动流程代码分析之第一个用户态进程:init 进程 之 post-init 任务详解
  15. 【鸿蒙OS开发入门】15 - 启动流程代码分析之第一个用户态进程:init 进程 之 StartParamService源码分析 及 setparam、getparam代码分析
  16. 【鸿蒙OS开发入门】16 - 重头搭建Ubuntu新环境编译OpenHarmony 3.0 LTS
  17. 【鸿蒙OS开发入门】17 - HDF驱动子系统:hdf_devmgr服务 驱动框架管理模块源码分析
  18. 【鸿蒙OS开发入门】18 - HDF驱动子系统:加速度计传感器 Driver层驱动代码分析


之所以选择加速度计传感器来作为首篇驱动分析,主要是因为官方文档有对它介绍,《SENSOR》,
本文就参考着官方文档,来学习下加速度计传感器的驱动逻辑。

参考官方文档,先来上一张Sensor驱动模型图:
请添加图片描述

从上面Sensor驱动模型图,从下往上,按我的理解,我们大致可以分为三层:

  1. Hardware: 这一层是实实在在的物理器件,比如加速度计、陀螺仪等。
  2. Platform IF: 这一层主要是提供与物理器件的交互方法,比如I2C、SPI等总线驱动。
  3. Driver:这一层的核心就是各个驱动的struct HdfDriverEntry结构体,在结构体中封装了相关sensor的具体实现逻辑。
  4. HDI 层(Hardware Driver Interface:这一层,主要是对所有sensor操作方法的封装,给上层app提供操作接口。

本文重点分析的就是加速度计传感器的Driver层代码实现。
好,废话不多说,先来看代码吧。



一、如何添加速度计传感器驱动代码(代码、编译、配置)

1、驱动代码实现

# drivers\framework\model\sensor\driver\chipset\accel\accel_bmi160.c

static int32_t ReadBmi160RawData(struct SensorCfgData *data, struct AccelData *rawData, int64_t *timestamp) {
     }
int32_t ReadBmi160Data(struct SensorCfgData *data){
     }
static int32_t InitBmi160(struct SensorCfgData *data){
     }
static int32_t InitAccelPreConfig(void){
     }
static int32_t DispatchBMI160(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply){
     }

int32_t Bmi160BindDriver(struct HdfDeviceObject *device){
     }		// 加速度计传感器绑定函数
int32_t Bmi160InitDriver(struct HdfDeviceObject *device){
     }		// 加速度计传感器初始化函数
void Bmi160ReleaseDriver(struct HdfDeviceObject *device){
     }		// 加速度计传感器资源释放函数

// 注册加速度计传感器入口数据结构体对象
struct HdfDriverEntry g_accelBmi160DevEntry = {
    
    .moduleVersion = 1,							// 加速度计传感器模块版本号
    .moduleName = "HDF_SENSOR_ACCEL_BMI160",	// 加速度计传感器模块名,要与device_info.hcs文件里的加速度计moduleName字段值一样
    .Bind = Bmi160BindDriver,					// 加速度计传感器绑定函数
    .Init = Bmi160InitDriver,					// 加速度计传感器初始化函数
    .Release = Bmi160ReleaseDriver,				// 加速度计传感器资源释放函数
};

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

2、驱动编译配置

2.1 linux 编译宏控配置

如果内核跑的是linux,那宏控配置主要是在Kconfig中:

# drivers\adapter\khdf\linux\model\sensor\Kconfig

config DRIVERS_HDF_SENSOR_ACCEL
    bool "Enable HDF accel sensor driver"
    default n
    depends on DRIVERS_HDF_SENSOR
    help
      Answer Y to enable HDF accel sensor driver.
config DRIVERS_HDF_SENSOR_ACCEL_BMI160
    bool "Enable HDF accel sensor driver"
    default n
    depends on DRIVERS_HDF_SENSOR_ACCEL
    help
      Answer Y to enable HDF accel bmi160 sensor driver.

Makefile来控制相应的编译规则:

# drivers\adapter\khdf\linux\model\sensor\Makefile

SENSOR_ROOT_DIR = ../../../../../framework/model/sensor/driver

obj-$(CONFIG_DRIVERS_HDF_SENSOR) += \
               $(SENSOR_ROOT_DIR)/common/src/sensor_config_controller.o \
               $(SENSOR_ROOT_DIR)/common/src/sensor_config_parser.o \
               $(SENSOR_ROOT_DIR)/common/src/sensor_device_manager.o \
               $(SENSOR_ROOT_DIR)/common/src/sensor_platform_if.o 
               
obj-$(CONFIG_DRIVERS_HDF_SENSOR_ACCEL) += $(SENSOR_ROOT_DIR)/accel/sensor_accel_driver.o

obj-$(CONFIG_DRIVERS_HDF_SENSOR_ACCEL_BMI160) += $(SENSOR_ROOT_DIR)/chipset/accel/accel_bmi160.o

2.2 liteos 编译宏控配置

如果内核跑的是liteos,则是由BUILD.gn、makefile、Kconfig共同控制:

# drivers\adapter\khdf\liteos\model\sensor\BUILD.gn

import("//drivers/adapter/khdf/liteos/hdf.gni")

module_switch = defined(LOSCFG_DRIVERS_HDF_SENSOR)
module_name = "hdf_sensor_driver"
hdf_driver(module_name) {
    
  FRAMEWORKS_SENSOR_ROOT = "$HDF_FRAMEWORKS_PATH/model/sensor/driver"
  sources = [
    "$FRAMEWORKS_SENSOR_ROOT/common/src/sensor_config_controller.c",
    "$FRAMEWORKS_SENSOR_ROOT/common/src/sensor_config_parser.c",
    "$FRAMEWORKS_SENSOR_ROOT/common/src/sensor_device_manager.c",
    "$FRAMEWORKS_SENSOR_ROOT/common/src/sensor_platform_if.c",
  ]

  if (defined(LOSCFG_DRIVERS_HDF_SENSOR_ACCEL)) {
    
    sources += [ "$FRAMEWORKS_SENSOR_ROOT/accel/sensor_accel_driver.c" ]
  }
  if (defined(LOSCFG_DRIVERS_HDF_SENSOR_ACCEL_BMI160)) {
    
    sources += [ "$FRAMEWORKS_SENSOR_ROOT/chipset/accel/accel_bmi160.c" ]
  }

  include_dirs = [
    "$FRAMEWORKS_SENSOR_ROOT/include",
    "$FRAMEWORKS_SENSOR_ROOT/common/include",
    "$FRAMEWORKS_SENSOR_ROOT/accel",
    "$FRAMEWORKS_SENSOR_ROOT/chipset/accel",
  ]
}

Makefile 内容如下:

# drivers\adapter\khdf\liteos\model\sensor\Makefile

include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk
MODULE_NAME := hdf_sensor_driver

FRAMEWORKS_SENSOR_ROOT = $(LITEOSTOPDIR)/../../drivers/framework/model/sensor/driver

LOCAL_INCLUDE := $(FRAMEWORKS_SENSOR_ROOT)/include \
                 $(FRAMEWORKS_SENSOR_ROOT)/common/include \
                 $(FRAMEWORKS_SENSOR_ROOT)/accel 

LOCAL_SRCS += $(FRAMEWORKS_SENSOR_ROOT)/common/src/sensor_config_controller.c \
              $(FRAMEWORKS_SENSOR_ROOT)/common/src/sensor_config_parser.c \
              $(FRAMEWORKS_SENSOR_ROOT)/common/src/sensor_device_manager.c \
              $(FRAMEWORKS_SENSOR_ROOT)/common/src/sensor_platform_if.c

ifeq ($(LOSCFG_DRIVERS_HDF_SENSOR_ACCEL), y)
LOCAL_SRCS += $(FRAMEWORKS_SENSOR_ROOT)/accel/sensor_accel_driver.c \
              $(FRAMEWORKS_SENSOR_ROOT)/chipset/accel/accel_bmi160.c
endif

include $(HDF_DRIVER)

Kconfig内容如下:

# drivers\adapter\khdf\liteos\model\sensor\Kconfig

config DRIVERS_HDF_SENSOR
    bool "Enable HDF sensor driver"
    default n
    depends on DRIVERS_HDF
    help
      Answer Y to enable HDF sensor driver.

config DRIVERS_HDF_SENSOR_ACCEL
    bool "Enable HDF accel sensor driver"
    default n
    depends on DRIVERS_HDF_SENSOR
    help
      Answer Y to enable HDF accel sensor driver.
config DRIVERS_HDF_SENSOR_ACCEL_BMI160
    bool "Enable HDF accel sensor driver"
    default n
    depends on DRIVERS_HDF_SENSOR_ACCEL
    help
      Answer Y to enable HDF accel bmi160 sensor driver.

分析到这,我发现其实Makefile 和BUILD.gn的内容其实差不多,这就很奇怪了,为啥要配两份?


3、设备配置描述

Hi3516DV300 为例,这个平台的 device_info.hcsvendor/hisilicon/Hi3516DV300/hdf_config/khdf/device_info/目录下:

# vendor/hisilicon/Hi3516DV300/hdf_config/khdf/device_info/device_info.hcs
 root {
    
    device_info {
    
        match_attr = "hdf_manager";
        template host {
    
            hostName = "";
            priority = 100;
            template device {
    
                template deviceNode {
    
                    policy = 0;
                    priority = 100;
                    preload = 0;
                    permission = 0664;
                    moduleName = "";
                    serviceName = "";
                    deviceMatchAttr = "";
                }
            }
        }
        platform :: host {
    
            hostName = "platform_host";
            priority = 50;
            device_gpio :: device {
    
                device0 :: deviceNode {
    
                    policy = 0;
                    priority = 10;
                    permission = 0644;
                    moduleName = "linux_gpio_adapter";
                    deviceMatchAttr = "linux_gpio_adapter";
                }
            }
    		device_i2c :: device {
    
                device0 :: deviceNode {
    
                    policy = 2;
                    priority = 50;
                    permission = 0644;
                    moduleName = "HDF_PLATFORM_I2C_MANAGER";
                    serviceName = "HDF_PLATFORM_I2C_MANAGER";
                    deviceMatchAttr = "hdf_platform_i2c_manager";
                }
                device1 :: deviceNode {
    
                    policy = 0;
                    priority = 55;
                    permission = 0644;
                    moduleName = "linux_i2c_adapter";
                    deviceMatchAttr = "linux_i2c_adapter";
                }
            }
  		}
  		display :: host {
    
            hostName = "display_host";
        }
        input :: host {
    
            hostName = "input_host";
            priority = 100;
        }
        network :: host {
    
            hostName = "network_host";
		}
		sensor :: host {
    
            hostName = "sensor_host";
            device_sensor_manager :: device {
    
                device0 :: deviceNode {
    
                    policy = 2;
                    priority = 100;
                    preload = 0;
                    permission = 0664;
                    moduleName = "HDF_SENSOR_MGR_AP";
                    serviceName = "hdf_sensor_manager_ap";
                }
            }
            device_sensor_accel :: device {
    
                device0 :: deviceNode {
    
                    policy = 1;
                    priority = 110;
                    preload = 2;
                    permission = 0664;
                    moduleName = "HDF_SENSOR_ACCEL";
                    serviceName = "hdf_sensor_accel";
                    deviceMatchAttr = "hdf_sensor_accel_driver";
                }
            }
            device_sensor_bmi160 :: device {
    
                device0 :: deviceNode {
    
                    policy = 1;
                    priority = 120;
                    preload = 2;
                    permission = 0664;
                    moduleName = "HDF_SENSOR_ACCEL_BMI160";
                    serviceName = "hdf_accel_bmi160";
                    deviceMatchAttr = "hdf_sensor_accel_bmi160_driver";
                }
            }
  		}
  		usb_pnp_linux :: host {
    
            hostName = "usb_pnp_linux_host";
            device_usb_pnp_linux :: device {
    
            }
        }
		audio :: host {
    
            hostName = "audio_host";
            priority = 60;
		}
		vibrator :: host {
    
            hostName = "vibrator_host";
		}
		dsoftbus :: host {
    
            hostName = "dsoftbus_host";
		}

可以看到,配置方面,相对还是比较简单的。

看到这里,其实您可以返回上一篇文章继续看了: 《【鸿蒙OS开发入门】17 - HDF驱动子系统:hdf_devmgr服务 驱动框架管理模块源码分析



二、加速度计传感器Driver层代码逻辑分析

在前面《【鸿蒙OS开发入门】17 - HDF驱动子系统:hdf_devmgr服务 驱动框架管理模块源码分析》 中,
我们分析到 DevHostServiceAddDevice()函数,它就是整个驱动的总入口:

主要工作如下:

  1. 获取 driverLoader 入口
  2. 获取 HdfDevice 结构体,其中定义了hostId/deviceIdAttach/Detach方法
  3. 调用LoadNode() ,加载设备驱动
  4. 调用device->super.Attach() 方法开始探测驱动,实际调用的是.Init方法
# drivers\framework\core\host\src\devhost_service.c
int DevHostServiceAddDevice(struct IDevHostService *inst, const struct HdfDeviceInfo *deviceInfo)
{
    
    int ret = HDF_FAILURE;
    struct HdfDevice *device = NULL;
    struct HdfDeviceNode *devNode = NULL;
    struct DevHostService *hostService = CONTAINER_OF(inst, struct DevHostService, super);
    // 1. 获取 driverLoader 入口
    struct IDriverLoader *driverLoader = HdfDriverLoaderGetInstance();		
    ================>
	    static struct HdfDriverLoader driverLoader;
	    HdfDriverLoaderConstruct(&driverLoader);
	    --------------->
	    +	 struct IDriverLoader *driverLoaderIf = (struct IDriverLoader *)inst;
	    +    driverLoaderIf->LoadNode = HdfDriverLoaderLoadNode;
	    +    driverLoaderIf->UnLoadNode = HdfDriverLoaderUnLoadNode;
	    +    driverLoaderIf->GetDriverEntry = HdfDriverLoaderGetDriverEntry;
	    <---------------
	    return (struct HdfObject *)&driverLoader;
    <================

	// 2. 获取 HdfDevice 结构体,其中定义了hostId/deviceId 和 Attach/Detach方法
    device = DevHostServiceGetDevice(hostService, deviceInfo->deviceId);
    ------------->
    +	device = HdfDeviceNewInstance();
   	+	========>	return (struct HdfDevice *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVICE);
    +	+	struct HdfDevice *device = (struct HdfDevice *)OsalMemCalloc(sizeof(struct HdfDevice));
    +	+	HdfDeviceConstruct(device);
    +	+	--------->
    +	+	+	device->super.Attach = HdfDeviceAttach;		// 最终调用驱动的 .Init
    +	+	+	DListHeadInit(&device->devNodes);
    +	+	<---------
    +	<========
    +	device->hostId = inst->hostId;
    +   device->deviceId = deviceId;
    +   DListInsertHead(&device->node, &inst->devices);
    <------------
    if (device == NULL || device->super.Attach == NULL) {
    
        ret = HDF_DEV_ERR_NO_DEVICE;
        goto error;
    }
	// 3. 调用LoadNode() ,加载设备驱动
    devNode = driverLoader->LoadNode(driverLoader, deviceInfo);

	// 4. 调用device->super.Attach() 方法开始探测驱动,实际调用的是.Init方法
    devNode->hostService = hostService;
    ret = device->super.Attach(&device->super, devNode);

    return HDF_SUCCESS;
}

我们本文就以ACCEL_BMI160 为例来分析下调用流程:



2.1 driverLoader->LoadNode()方法: HdfDriverLoaderLoadNode() 加载驱动 bind() 方法

主要工作如下:

  1. 获取驱动函数结构体struct HdfDriverEntry g_accelBmi160DevEntry,其中包含了bmi160bindinit方法
// 注册加速度计传感器入口数据结构体对象
struct HdfDriverEntry g_accelBmi160DevEntry = {
    
    .moduleVersion = 1,							// 加速度计传感器模块版本号
    .moduleName = "HDF_SENSOR_ACCEL_BMI160",	// 加速度计传感器模块名,要与device_info.hcs文件里的加速度计moduleName字段值一样
    .Bind = Bmi160BindDriver,					// 加速度计传感器绑定函数
    .Init = Bmi160InitDriver,					// 加速度计传感器初始化函数
    .Release = Bmi160ReleaseDriver,				// 加速度计传感器资源释放函数
};
  1. 初始化驱动相关的设备节点,调用HDF_OBJECT_ID_DEVICE_SERVICE所对应的函数DeviceNodeExtCreate()
  2. 配置Bmi160devNode结构体,绑定driverEntry
  3. 调用驱动的 bind 方法开始绑定驱动
# drivers\framework\core\host\src\hdf_driver_loader.c
struct HdfDeviceNode *HdfDriverLoaderLoadNode(struct IDriverLoader *loader, const struct HdfDeviceInfo *deviceInfo)
{
    
    struct HdfDriverEntry *driverEntry = NULL;
    struct HdfDeviceNode *devNode = NULL;
	// 1. 获取驱动函数结构体struct HdfDriverEntry g_accelBmi160DevEntry
    driverEntry = loader->GetDriverEntry(deviceInfo);
    
	// 2. 初始化驱动相关的设备节点,调用HDF_OBJECT_ID_DEVICE_SERVICE所对应的函数DeviceNodeExtCreate()
    devNode = HdfDeviceNodeNewInstance();
    ================>	return (struct HdfDeviceNode *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVICE_SERVICE);
    +	struct DeviceNodeExt *instance = (struct DeviceNodeExt *)OsalMemCalloc(sizeof(struct DeviceNodeExt));
    +	DeviceNodeExtConstruct(instance);
    +	------------>
    +	-	struct IDeviceNode *nodeIf = &devNode->super;
    +	-	HdfDeviceNodeConstruct(&inst->super);
    +	-	==========>
	+   -   	HdfDeviceObjectConstruct(&devNode->deviceObject);
	+   -   	-------->
	+   -   	+	deviceObject->property = NULL;
	+	-   	+   deviceObject->service = NULL;
	+	-   	+   deviceObject->deviceClass = DEVICE_CLASS_DEFAULT;
	+	-   	<--------
	+   -   	devNode->token = HdfDeviceTokenNewInstance();
	+   -   	nodeIf->LaunchNode = HdfDeviceLaunchNode;			// 调用sensor init方法,初始化sensor
	+   -   	nodeIf->PublishService = HdfDeviceNodePublishPublicService;
	+ 	-	<==========
    +	-	nodeIf->PublishService = DeviceNodeExtPublishService;
    +	<------------
    +   instance->ioService = NULL;
    <================
    
    // 3. 配置Bmi160的 devNode结构体,绑定driverEntry
    devNode->driverEntry = driverEntry;
    devNode->deviceInfo = deviceInfo;		// device list
    devNode->deviceObject.property = HcsGetNodeByMatchAttr(HdfGetRootNode(), deviceInfo->deviceMatchAttr);
    devNode->deviceObject.priv = (void *)(deviceInfo->private);
    
	// 4. 调用驱动的 bind 方法开始绑定驱动
    driverEntry->Bind(&devNode->deviceObject);
    return devNode;
}

2.2 driverEntry->Bind()方法: Bmi160BindDriver() 分配并初始化驱动结构体g_bmi160DrvData

  1. 分配并初始化struct Bmi160DrvData 内存
  2. 将设备节点的HdfDeviceObject结构体与驱动结构体Bmi160DrvData绑定在一起
  3. 配置全局驱动结构体指针g_bmi160DrvData
# drivers\framework\model\sensor\driver\chipset\accel\accel_bmi160.c
int32_t Bmi160BindDriver(struct HdfDeviceObject *device)
{
    
	// 1. 分配并初始经`struct Bmi160DrvData` 内存
    struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)OsalMemCalloc(sizeof(*drvData));
	
	// 2. 将设备节点的HdfDeviceObject结构体与驱动结构体Bmi160DrvData绑定在一起
    drvData->ioService.Dispatch = DispatchBMI160;
    drvData->device = device;
    device->service = &drvData->ioService;
	// 3. 配置全局驱动结构体指针g_bmi160DrvData 
    g_bmi160DrvData = drvData;

    return HDF_SUCCESS;
}

2.3 device->super.Attach()方法: HdfDeviceAttach() 开始加载驱动.Init 方法探测驱动设备

# drivers\framework\core\host\src\hdf_device.c
static int HdfDeviceAttach(struct IHdfDevice *devInst, struct HdfDeviceNode *devNode)
{
    
    struct HdfDevice *device = (struct HdfDevice *)devInst;
    struct IDeviceNode *nodeIf = (struct IDeviceNode *)devNode;
    
    DListInsertTail(&devNode->entry, &device->devNodes);
    return nodeIf->LaunchNode(devNode, devInst);
}

HdfDeviceAttach() 中主要是调用了DeviceNodeLaunchNode()方法,
它是在前面初始化驱动相关的设备节点时配置的,代码为:nodeIf->LaunchNode = HdfDeviceLaunchNode;
我们来看看HdfDeviceLaunchNode() 函数:

  1. 调用驱动 .Init() 方法探测并初始化驱动设备
  2. 注册device node 对应的service
  3. 将驱动添加进device node service中, 对应的函数为 DevmgrServiceAttachDevice()
# drivers\framework\core\host\src\hdf_device_node.c
int HdfDeviceLaunchNode(struct HdfDeviceNode *devNode, struct IHdfDevice *devInst)
{
    
    struct HdfDevice *device = (struct HdfDevice *)devInst;	   // HdfDevice 结构体,其中定义了hostId/deviceId和Attach/Detach方法
    struct HdfDriverEntry *driverEntry = devNode->driverEntry; // 驱动函数结构体
    const struct HdfDeviceInfo *deviceInfo = devNode->deviceInfo;	// 设备device list结构体
    struct IHdfDeviceToken *deviceToken = NULL;
	
	// 1. 调用驱动 .Init() 方法探测并初始化驱动设备
    int ret = driverEntry->Init(&devNode->deviceObject);
    // 2. 注册device node 对应的service
    ret = HdfDeviceNodePublishService(devNode, deviceInfo, devInst);
    ------------>
    -	struct IDeviceNode *nodeIf = &devNode->super;
    -	status = nodeIf->PublishService(devNode, deviceInfo->svcName);		// 调用的是 HdfDeviceNodePublishPublicService() 方法
    -	===========>
    -	+	return DevSvcManagerClntAddService(svcName, &devNode->deviceObject);
    -	+	--------->
    -	+		struct DevSvcManagerClnt *devSvcMgrClnt = DevSvcManagerClntGetInstance();
    -	+		struct IDevSvcManager *serviceManager = devSvcMgrClnt->devSvcMgrIf;
    -	+		return serviceManager->AddService(serviceManager, svcName, service);
    -	+	<---------
    -	<===========
    <------------
	// 3. 将驱动添加进device node service中, 对应的函数为 DevmgrServiceAttachDevice()
    deviceToken = devNode->token;
    ret = DevmgrServiceClntAttachDevice(deviceInfo, deviceToken);
    ------------>
    	struct DevmgrServiceClnt *inst = DevmgrServiceClntGetInstance();
    	devMgrSvcIf = inst->devMgrSvcIf;
    	return devMgrSvcIf->AttachDevice(devMgrSvcIf, deviceInfo, deviceToken);		
    <------------

    return ret;
}

2.4 driverEntry->Init方法:

此时,终于进入我们驱动的正题了,开始探测并初始化驱动设备。

# drivers\framework\model\sensor\driver\chipset\accel\accel_bmi160.c
int32_t Bmi160InitDriver(struct HdfDeviceObject *device)
{
    
    int32_t ret;
    struct AccelOpsCall ops;
    struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)device->service;
	// 初始化I2C6的控制寄存器:PIN肢配置为I2C模式和配置I2C时钟
    ret = InitAccelPreConfig();
	// 
    drvData->sensorCfg = AccelCreateCfgData(device->property);
    ------------>
    	GetSensorBaseConfigData(node, drvData->accelCfg);
    	DetectSensorDevice(drvData->accelCfg);
    	drvData->detectFlag = true;
    	InitAccelAfterDetected(drvData->accelCfg);
    <------------

    ops.Init = NULL;
    ops.ReadData = ReadBmi160Data;	// 配置 sensor 读取寄存器的方法
    ret = AccelRegisterChipOps(&ops);
    ------------->
    	drvData->ops.Init = ops->Init;
    	drvData->ops.ReadData = ops->ReadData;		// 配置加速度计传感器寄存器读取方法
    <-------------
    
    ret = InitBmi160(drvData->sensorCfg);
    ------------->
    	ret = SetSensorRegCfgArray(&data->busCfg, data->regCfgGroup[SENSOR_INIT_GROUP]);
	<-------------
	
    return HDF_SUCCESS;
}



文档参考:
SENSOR
驱动开发
配置管理

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Ciellee/article/details/122176126

智能推荐

HDU3764(Cyclic Nacklace)_;w the endhdu_Splaying的博客-程序员秘密

Cyclic NacklaceProblem DescriptionCC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last

dockers镜像的制作_李氏程序员的博客-程序员秘密

[[email protected] ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEcentos latest 75835a67d134 3 month...

深度学习崛起十年:“开挂”的OpenAI革新者_OneFlow深度学习框架的博客-程序员秘密

作为一个AI前沿领域的探索者,纵览其职业生涯,Sutskever的每一次转向似乎都能恰到好处地挖到黄金。

sql 优化 5大步骤+10个案例,堪称SQL优化万能公式_Young丶的博客-程序员秘密

一、前言在应用开发的早期,数据量少,开发人员开发功能时更重视功能上的实现,随着生产数据的增长,很多SQL语句开始暴露出性能问题,对生产的影响也越来越大,有时可能这些有问题的SQL就是整个系统性能的瓶颈。二、SQL优化一般步骤1、通过慢查日志等定位那些执行效率较低的SQL语句2、explain 分析SQL的执行计划需要重点关注type、rows、filtered、extra。type由上至下,效率越来越高。ALL 全表扫描;index 索引全扫描;range 索引范围扫描,常用语&lt;,

ArrayList的底层原理-扩容_VanHua的博客-程序员秘密

ArrayList的底层数据结构就是一个数组,数组元素的类型为Object类型,对ArrayList的所有操作底层都是基于数组的ArrayList的扩容机制ArrayList的扩容主要发生在向ArrayList集合中添加元素的时候。由add()方法的分析可知添加前必须确保集合的容量能够放下添加的元素。主要经历了以下几个阶段:第一,在add()方法中调用ensureCapacityIntern...

ScrollView用法_Aaronns的博客-程序员秘密

理论部分1、ScrollView和HorizontalScrollView是为控件或者布局添加滚动条2、上述两个控件只能有一个孩子,但是它并不是传统意义上的容器3、上述两个控件可以互相嵌套4、滚动条的位置现在的实验结果是:可以由layout_width和layout_height设定5、ScrollView用于设置垂直滚动条,HorizontalScrollView用于设置水平滚动条:需要注意的是,

随便推点

Independence Day_broadury的博客-程序员秘密

《独立日》总是这么能鼓舞人,特别是总统对飞行员演讲的时候,我一遍一遍的听着,似乎总是听不够……The President:Good morning. In less than an hour, aircraft from here will join others from around the world. And you will be launching the larges...

Bootstrap-select 使用问题_加了白糖的老干妈的博客-程序员秘密

Bootstrap-selectBootstrap-selectbootstrap-select 搜索,动态加载数据bootstrap-select js设置选中Bootstrap-select 官方APIbootstrap-select 搜索,动态加载数据1.开启搜索&amp;lt;!-- data-live-search=&quot;true&quot; --&amp;gt; ...

DUI总结_weixin_30650039的博客-程序员秘密

DUI好处在于可以很方便的构建高效,绚丽的,非常易于扩展的界面。从而很好的将界面和逻辑分离,同时易于实现各种超炫的界面效果如换色,换肤,透明等。DUI使用的是GDI+核心.DirectUI可以理解为一个轻量级的WPF,可以让C++做出C#般绚丽的界面。DUI核心的大体结构图如下:分为几个大部分:1.控件2.容器3.UI构建解析器(XML解析)...

windows mysql的坑:ERROR 2003 (HY000): Can’t connect to MySQL server on ‘localhost’ (10061)_秃如其来的秃头的博客-程序员秘密

windows中mysql5.7的坑:ERROR 2003 (HY000): Can’t connect to MySQL server on ‘localhost’ (10061)不知道是 windows 自动更新导致的问题还是什么**一、**打开解压的文件夹C:\MySQL Server 5.7(这只是打个比方,各位看官按照自己的目录去找) ,发现里面有my-default.ini配置文件...

最长非递减子序列LIS(动态规划法,一维)_iOPEN.Yang的博客-程序员秘密

//动态规划法//LIS(时间复杂度为n平方)#include <iostream>#include <cstring>#define N 1000using namespace std;int LIS(int A[], int length){ int d[N]; for(int i=1;i<N;i++) d[i]=1; d[0]=0; for(int i=

2021下半年软考中项案例分析试题四答案及解析_软考中项csdn_逸尘谈PM的博客-程序员秘密

计算机软件资格考试是由国家人力资源和社会保障部、工业和信息化部领导下的国家级考试,其目的是科学、公正地对全国计算机与软件专业技术人员进行职业资格、专业技术资格认定和专业技术水平测试。关于2021下半年软考中项案例分析试题四答案及解析,慧翔天地在这里给大家简单介绍一下。  试题四  阅读下列说明,回各问题1至问题3,将解答填入各题纸的对应栏内。  [说明]  A公司承接了某金融行业用户(甲方)信息系统建设项目,服务内容涉及咨询、开发、集成、运维等。公司任命技术经验丰富的张伟担任项目经理,张伟协

推荐文章

热门文章

相关标签