电子产业一站式赋能平台

PCB联盟网

搜索
查看: 598|回复: 0
收起左侧

品读鸿蒙HDF架构(二)

[复制链接]

2607

主题

2607

帖子

7472

积分

高级会员

Rank: 5Rank: 5

积分
7472
发表于 2020-12-16 11:56:26 | 显示全部楼层 |阅读模式
品读鸿蒙HDF架构(二), 在前一篇文章里,我们阐述了在启动DeviceManager这个核心服务时,是如何生成所有的host配套设施的,下面我们来进一步剖析细节。

我们已经知道,一个Host对应一个DevHostServiceClnt和一个DevHostService,很明显主要行为都包含在后者内部。当后者启动时,会执行到DriverInstallerStartDeviceHost(),该函数又会调用DevHostServiceStartServie(),这些内容在前一篇文章里都说过。

我们不用去想太多调用细节,反正说起来就是要让一个DevHostServiceClnt和一个DevHostService“挂接”(attach)起来,挂接的动作里会进一步在DevHostService里安装设备驱动。这个挂接动作具体对应的函数就是DevmgrServiceClntAttachDeviceHost()。在上一篇文章里,我们没有展开讲这个函数,现在就从它说起。为了便于阅读,我将挂接动作的调用顺序先绘制出来,如下图所示:
1 挂接device Host 我用黄色框表达了DevmgrServiceClntAttachDeviceHost()一步,该函数代码截选如下:

【drivers/hdf/frameworks/core/host/src/Devmgr_service_clnt.c】

  • int DevmgrServiceClntAttachDeviceHost(uint16_t hostid, struct IDevHostService *hostService)
      
  • {
      
  •     struct IDevmgrService *devMgrSvcIf = NULL;
      
  •     . . . . . .
      
  •     devMgrSvcIf = inst->devMgrSvcIf;
      
  •     . . . . . .
      
  •     // 实际调用的是DevmgrServiceAttachDeviceHost()
      
  •     return devMgrSvcIf->AttachDeviceHost(devMgrSvcIf, hostId, hostService);
      
  • }

复制代码 最后一句实际调用的是DevmgrServiceAttachDeviceHost(),代码截选如下:

【drivers/hdf/frameworks/core/manager/src/Devmgr_service.c】

  • static int DevmgrServiceAttachDeviceHost(
      
  •     struct IDevmgrService *inst, uint16_t hostId, struct IDevHostService *hostService)
      
  • {
      
  •     struct DevHostServiceClnt *hostClnt = DevmgrServiceFindDeviceHost(inst, hostId);
      
  •     . . . . . .
      
  •     hostClnt->deviceInfos = HdfAttributeManagerGetDeviceList(hostClnt->hostId, hostClnt->hostName);
      
  •     . . . . . .
      
  •     hostClnt->hostService = hostService;
      
  •     return DevHostServiceClntInstallDriver(hostClnt);
      
  • }

复制代码 首先,遍历DevmgrService的hosts列表,根据hostId找到对应的DevHostServiceClnt对象,并给该DevHostServiceClnt对象的deviceInfos域和hostService域赋值,然后调用重头戏DevHostServiceClntInstallDriver()。 在获取这个host范畴的所有device信息时,也是去查询上一篇文章提到的配置树,树节点的类型为DeviceResourceNode,只不过上一次系统是去查找具有“hdf_manager”属性的节点,而此次是查找名字为hostName的节点,这个节点里包含着若干设备的信息,现在这些设备信息会被组织成一个HdfDeviceInfo链表。最终形成下面图中的结构:
1.1 安装host范畴内的设备驱动
1.1.1 在每个host的DevHostService里添加设备 Attach动作的最后一步就是安装驱动啦,我们看一下这个DevHostServiceClntInstallDriver()函数:

【drivers/hdf/frameworks/core/manager/src/Devhost_service_clnt.c】

  • int DevHostServiceClntInstallDriver(struct DevHostServiceClnt *hostClnt)
      
  • {
      
  •     . . . . . .
      
  •     struct HdfSListIterator it;
      
  •     struct HdfDeviceInfo *deviceInfo = NULL;
      
  •     struct IDevHostService *devHostSvcIf = NULL;
      
  •     . . . . . .
      
  •     devHostSvcIf = (struct IDevHostService *)hostClnt->hostService;
      
  •     . . . . . .
      
  •     HdfSListIteratorInit(&it, hostClnt->deviceInfos);
      
  •     while (HdfSListIteratorHasNext(&it)) {
      
  •         deviceInfo = (struct HdfDeviceInfo *)HdfSListIteratorNext(&it);
      
  •         if ((deviceInfo == NULL) || (deviceInfo->preload != DEVICE_PRELOAD_ENABLE)) {
      
  •             continue;
      
  •         }
      
  •         // 实际调用的是 DevHostServiceAddDevice()
      
  •         ret = devHostSvcIf->AddDevice(devHostSvcIf, deviceInfo);
      
  •         . . . . . .
      
  •     }
      
  •     return HDF_SUCCESS;
      
  • }

复制代码 其实就是遍历一下该host范畴内的所有HdfDeviceInfo节点,如果节点的preload是“使能”的,就执行对应的AddDevice操作,即DevHostServiceAddDevice()函数,其代码截选如下:

【drivers/hdf/frameworks/core/host/src/Devhost_service.c】

  • static int DevHostServiceAddDevice(struct IDevHostService *inst, const struct HdfDeviceInfo *deviceInfo)
      
  • {
      
  •     int ret = HDF_FAILURE;
      
  •     struct HdfDevice *device = NULL;
      
  •     struct HdfDeviceNode *devNode = NULL;
      
  •     struct DevHostService *hostService = (struct DevHostService *)inst;
      
  •     struct IDriverLoader *driverLoader =  HdfDriverLoaderGetInstance();
      
  •     . . . . . .
      
  •     device = DevHostServiceGetDevice(hostService, deviceInfo->deviceId);
      
  •     . . . . . .
      
  •     // 实际调用的是 HdfDriverLoaderLoadNode()
      
  •     devNode = driverLoader->LoadNode(driverLoader, deviceInfo);
      
  •     . . . . . .
      
  •     devNode->hostService = hostService;
      
  •     // 实际调用的是 HdfDeviceAttach()
      
  •     ret = device->super.Attach(&device->super, devNode);
      
  •     . . . . . .
      
  •     return HDF_SUCCESS;
      
  •     . . . . . .
      
  • }

复制代码 在这个函数里,先调用DevHostServiceGetDevice()尝试从DevHostService的devices列表里查找与deviceId匹配的节点,如果找不到就创建一个新HdfDevice节点,并插入该列表。 当然,一开始devices列表是个空列表,此时只会创建新节点。反正经此一步,我们一般可以拿到一个可用的HdfDevice对象。接着利用驱动加载器加载一个和deviceInfo匹配的HdfDeviceNode节点。最后还需把得到的HdfDevice和HdfDeviceNode挂接起来。


1.1.1.1 加载HdfDeviceNode 加载HdfDeviceNode的动作实际上是HdfDriverLoaderLoadNode(),代码截选如下:

【drivers/hdf/frameworks/core/host/src/Hdf_driver_loader.c】

  • static struct HdfDeviceNode *HdfDriverLoaderLoadNode(
      
  •     struct IDriverLoader *loader, const struct HdfDeviceInfo *deviceInfo)
      
  • {
      
  •     struct HdfDriverEntry *driverEntry = NULL;
      
  •     struct HdfDeviceNode *devNode = NULL;
      
  •     . . . . . .
      
  •     // 实际调用的是 HdfDriverLoaderGetDriverEntry()
      
  •     driverEntry = loader->GetDriverEntry(deviceInfo);
      
  •     . . . . . .
      
  •     devNode = HdfDeviceNodeNewInstance();
      
  •     . . . . . .
      
  •     devNode->driverEntry = driverEntry;
      
  •     devNode->deviceInfo = deviceInfo;
      
  •     devNode->deviceObject.property = HcsGetNodeByMatchAttr(HcsGetRootNode(), deviceInfo->deviceMatchAttr);
      
  •     . . . . . .
      
  •     if ((deviceInfo->policy == SERVICE_POLICY_PUBLIC) ||
      
  •         (deviceInfo->policy == SERVICE_POLICY_CAPACITY)) {
      
  •         . . . . . .
      
  •         if (driverEntry->Bind(&devNode->deviceObject) != 0) {
      
  •             HDF_LOGE(“bind driver faiLED“);
      
  •             HdfDeviceNodeFreeInstance(devNode);
      
  •             return NULL;
      
  •         }
      
  •     }
      
  •     return devNode;
      
  • }

复制代码 HdfDeviceNode的定义如下:

【drivers/hdf/frameworks/core/host/include/Hdf_device_node.h】

  • struct HdfDeviceNode {
      
  •     struct IDeviceNode super;
      
  •     struct HdfSListNode entry;
      
  •     struct PowerStateToken *powerToken;
      
  •     struct DevHostService *hostService;
      
  •     struct HdfDeviceObject deviceObject;
      
  •     struct IHdfDeviceToken *token;
      
  •     struct HdfDriverEntry *driverEntry;
      
  •     const struct HdfDeviceInfo *deviceInfo;
      
  • };

复制代码 可以看到,驱动加载器在创建HdfDeviceNode节点时,还是有一些工作要做的:

1)得加载相应设备的驱动程序入口,最终体现为HdfDriverEntry;

2)创建一个HdfDeviceNode对象,经过研究,我们可以看到最终创建的其实是HdfDeviceNode的派生类(DeviceNodeExt)对象;

3)把HdfDeviceNode节点和设备驱动程序绑定起来;


1.1.1.1.1 获取驱动入口

驱动加载器获取HdfDriverEntry的实际动作是HdfDriverLoaderGetDriverEntry():

【drivers/hdf/lite/manager/src/Lite_driver_loader.c】

  • struct HdfDriverEntry *HdfDriverLoaderGetDriverEntry(const struct HdfDeviceInfo *deviceInfo)
      
  • {
      
  •     int count = (int) (((uint8_t *)(HDF_DRIVER_END()) - (uint8_t *)(HDF_DRIVER_BEGIN())) / sizeof(size_t));
      
  •     size_t *addrBegin = (size_t*)(HDF_DRIVER_BEGIN());
      
  •     if ((deviceInfo == NULL) || (deviceInfo->moduleName == NULL) || (deviceInfo->svcName == NULL)) {
      
  •         HDF_LOGE(“Hdf get device entry failed, input deviceInfo is NULL!“);
      
  •         return NULL;
      
  •     }
      

  •   
  •     for (int i = 0; i < count; i++) {
      
  •         struct HdfDriverEntry *driverEntry = (struct HdfDriverEntry *)(*addrBegin);
      
  •         if (strcmp(deviceInfo->moduleName, driverEntry->moduleName) == 0) {
      
  •             return driverEntry;
      
  •         }
      
  •         addrBegin++;
      
  •     }
      
  •     HDF_LOGE(“Hdf get %s device entry failed!“, deviceInfo->svcName);
      
  •     return NULL;
      
  • }

复制代码 其中,HdfDriverEntry的定义如下:

【drivers/hdf/frameworks/include/core/Hdf_device_desc.h】

  • struct HdfDriverEntry {
      
  •     int32_t moduleVersion;
      
  •     const char *moduleName;
      
  •     int32_t (*Bind)(struct HdfDeviceObject *deviceObject);
      
  •     int32_t (*Init)(struct HdfDeviceObject *deviceObject);
      
  •     void (*Release)(struct HdfDeviceObject *deviceObject);
      
  • };

复制代码 现在我们来解释一下,HdfDriverLoaderGetDriverEntry()到底在干什么。我们设想,HDF会先加载需要的所有驱动程序,每个驱动程序内部都会构造一个HdfDriverEntry对象,而且会填好那个Bind域,这其实就是在填写一个回调函数指针,当然,也只有驱动程序自己知道该填写哪个函数指针。

HDF会把加载的所有驱动的HdfDriverEntry对象的起始地址汇总起来,形成一个类似地址数组的东西,这个数组的第一项的地址对应上面代码中的HDF_DRIVER_BEGIN(),最后一项的地址对应HDF_DRIVER_END()(最后一项不填内容)。示意图如下: 获取驱动入口时,就是在遍历这个指针数组,查询与moduleName匹配的节点。


1.1.1.1.2 创建HdfDeviceNode对象

接着尝试创建HdfDeviceNode对象,此时调用的HdfDeviceNodeNewInstance()函数如下:

【drivers/hdf/frameworks/core/host/src/Hdf_device_node.c】

  • struct HdfDeviceNode *HdfDeviceNodeNewInstance()
      
  • {
      
  •     return (struct HdfDeviceNode *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVICE_SERVICE);
      
  • }

复制代码 又需要去查我们熟悉的对象创建表(g_liteObjectCreators),最终查到会调用DeviceNodeExtCreate():

【drivers/hdf/lite/manager/src/Hdf_device_node_ext.c】

  • struct HdfObject *DeviceNodeExtCreate()
      
  • {
      
  •     struct DeviceNodeExt *instance =
      
  •         (struct DeviceNodeExt *)OsalMemcalloc(sizeof(struct DeviceNodeExt));
      
  •     if (instance != NULL) {
      
  •         DeviceNodeExtConstruct(instance);
      
  •         instance->ioService = NULL;
      
  •     }
      
  •     return (struct HdfObject *)instance;
      
  • }

复制代码 可以看到,实际创建的是一个DeviceNodeExt对象。DeviceNodeExt继承于HdfDeviceNode,定义如下:

【drivers/hdf/lite/include/manager/Hdf_device_node_ext.h】

  • struct DeviceNodeExt {
      
  •     struct HdfDeviceNode super;
      
  •     struct HdfIoService *ioService;
      
  • };

复制代码 其构造函数如下:

【drivers/hdf/lite/manager/src/Hdf_device_node_ext.c】

  • static void DeviceNodeExtConstruct(struct DeviceNodeExt *inst)
      
  • {
      
  •     struct IDeviceNode *nodeIf = (struct IDeviceNode *)inst;
      
  •     if (nodeIf != NULL) {
      
  •         HdfDeviceNodeConstruct(&inst->super);
      
  •         nodeIf->PublishService = DeviceNodeExtPublishService;
      
  •     }
      
  • }

复制代码 注意,它修改了继承来的PublishService域,将函数指针设为DeviceNodeExtPublishService了。

HdfDriverLoaderLoadNode()会给DeviceNodeExt的driverEntry域、deviceInfo域、deviceObject.property赋值,那么在进行绑定之前,DeviceNodeExt的示意图大概是这样的:


1.1.1.1.3绑定驱动入口

接下来要将刚刚创建的DeviceNodeExt节点和驱动入口绑定起来: driverEntry->Bind(&devNode->deviceObject)

前文我们已经说了,每个程序会实现自己的Bind动作,而HDF只负责回调Bind。注意,回调时HDF需要传入DeviceNodeExt节点的deviceObject部分的指针,因为需要驱动程序填写其中的域。当然,我们从上图中可以看到,deviceObject部分只剩下service域(IDeviceIoService*)需要填写。那么很明显,一个驱动程序要能被HDF使用,那么它就得包含一个IDeviceIoService对象。IDeviceIoService的定义如下:

【drivers/hdf/frameworks/include/core/Hdf_device_desc.h】

  • struct IDeviceIoService {
      
  •     struct HdfObject object;
      
  •     int32_t (*Open)(struct HdfDeviceIoClient *client);
      
  •     int32_t (*Dispatch)(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply);
      
  •     void (*Release)(struct HdfDeviceIoClient *client);
      
  • };

复制代码 现在我们可以基于前文示意图,绘制一张DeviceNodeExt和驱动程序绑定后的示意图了,如下图:
1.1.1.2 挂接HdfDeviceNode

DevHostServiceAddDevice()在加载好DeviceNodeExt之后,调用了一句Attach:

  • ret = device->super.Attach(&device->super, devNode);

复制代码 尝试把HdfDevice节点和DeviceNodeExt联系起来,这一句其实是调用HdfDeviceAttach(),相关代码如下:

【drivers/hdf/frameworks/core/host/include/Hdf_device.h】

  • struct IHdfDevice {
      
  •     struct HdfObject object;
      
  •     int (*Attach)(struct IHdfDevice *, struct HdfDeviceNode *);
      
  • };
      

  •   
  • struct HdfDevice {
      
  •     struct IHdfDevice super;
      
  •     struct HdfSListNode node;
      
  •     struct HdfSList services;
      
  •     uint16_t deviceId;
      
  •     uint16_t hostId;
      
  • };

复制代码 【drivers/hdf/frameworks/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;
      
  •     . . . . . .
      
  •     HdfSListAdd(&device->services, &devNode->entry);
      
  •     // 实际调用的是 HdfDeviceLaunchNode()
      
  •     return nodeIf->LaunchNode(devNode, devInst);
      
  • }

复制代码 代码里先将DeviceNodeExt添加进HdfDevice的services列表里,然后调用了HdfDeviceLaunchNode()。

我们前文已经说过,HdfDevice节点在之前已经添加进DevHostService的devices列表了,现在它又和DeviceNodeExt联系起来了,再结合前文中的知识,我们可以画一张大一点儿的关系示意图了,如下: 至此,相信大家已经基本了解挂接设备host所形成的数据结构了,正如上图所示,每个host都会对应上图中红、绿、蓝三个范畴。大家不妨自己试着画画这张图,看看还会发现什么。至于HDF的其他方面,我们可以在其他文章里再探讨。

文章转自:侯亮(悠然红茶)
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表