電子產業(yè)一站式賦能平臺

PCB聯(lián)盟網(wǎng)

搜索
查看: 597|回復: 0
收起左側

品讀鴻蒙HDF架構(二)

[復制鏈接]

2607

主題

2607

帖子

7472

積分

高級會員

Rank: 5Rank: 5

積分
7472
跳轉到指定樓層
樓主
發(fā)表于 2020-12-16 11:56:26 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
品讀鴻蒙HDF架構(二), 在前一篇文章里,我們闡述了在啟動DeviceManager這個核心服務時,是如何生成所有的host配套設施的,下面我們來進一步剖析細節(jié)。

我們已經知道,一個Host對應一個DevHostServiceClnt和一個DevHostService,很明顯主要行為都包含在后者內部。當后者啟動時,會執(zhí)行到DriverInstallerStartDeviceHost(),該函數(shù)又會調用DevHostServiceStartServie(),這些內容在前一篇文章里都說過。

我們不用去想太多調用細節(jié),反正說起來就是要讓一個DevHostServiceClnt和一個DevHostService“掛接”(attach)起來,掛接的動作里會進一步在DevHostService里安裝設備驅動。這個掛接動作具體對應的函數(shù)就是DevmgrServiceClntAttachDeviceHost()。在上一篇文章里,我們沒有展開講這個函數(shù),現(xiàn)在就從它說起。為了便于閱讀,我將掛接動作的調用順序先繪制出來,如下圖所示:
1 掛接device Host 我用黃色框表達了DevmgrServiceClntAttachDeviceHost()一步,該函數(shù)代碼截選如下:

【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列表,根據(jù)hostId找到對應的DevHostServiceClnt對象,并給該DevHostServiceClnt對象的deviceInfos域和hostService域賦值,然后調用重頭戲DevHostServiceClntInstallDriver()。 在獲取這個host范疇的所有device信息時,也是去查詢上一篇文章提到的配置樹,樹節(jié)點的類型為DeviceResourceNode,只不過上一次系統(tǒng)是去查找具有“hdf_manager”屬性的節(jié)點,而此次是查找名字為hostName的節(jié)點,這個節(jié)點里包含著若干設備的信息,現(xiàn)在這些設備信息會被組織成一個HdfDeviceInfo鏈表。最終形成下面圖中的結構:
1.1 安裝host范疇內的設備驅動
1.1.1 在每個host的DevHostService里添加設備 Attach動作的最后一步就是安裝驅動啦,我們看一下這個DevHostServiceClntInstallDriver()函數(shù):

【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節(jié)點,如果節(jié)點的preload是“使能”的,就執(zhí)行對應的AddDevice操作,即DevHostServiceAddDevice()函數(shù),其代碼截選如下:

【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;
      
  •     . . . . . .
      
  • }

復制代碼 在這個函數(shù)里,先調用DevHostServiceGetDevice()嘗試從DevHostService的devices列表里查找與deviceId匹配的節(jié)點,如果找不到就創(chuàng)建一個新HdfDevice節(jié)點,并插入該列表。 當然,一開始devices列表是個空列表,此時只會創(chuàng)建新節(jié)點。反正經此一步,我們一般可以拿到一個可用的HdfDevice對象。接著利用驅動加載器加載一個和deviceInfo匹配的HdfDeviceNode節(jié)點。最后還需把得到的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;
      
  • };

復制代碼 可以看到,驅動加載器在創(chuàng)建HdfDeviceNode節(jié)點時,還是有一些工作要做的:

1)得加載相應設備的驅動程序入口,最終體現(xiàn)為HdfDriverEntry;

2)創(chuàng)建一個HdfDeviceNode對象,經過研究,我們可以看到最終創(chuàng)建的其實是HdfDeviceNode的派生類(DeviceNodeExt)對象;

3)把HdfDeviceNode節(jié)點和設備驅動程序綁定起來;


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);
      
  • };

復制代碼 現(xiàn)在我們來解釋一下,HdfDriverLoaderGetDriverEntry()到底在干什么。我們設想,HDF會先加載需要的所有驅動程序,每個驅動程序內部都會構造一個HdfDriverEntry對象,而且會填好那個Bind域,這其實就是在填寫一個回調函數(shù)指針,當然,也只有驅動程序自己知道該填寫哪個函數(shù)指針。

HDF會把加載的所有驅動的HdfDriverEntry對象的起始地址匯總起來,形成一個類似地址數(shù)組的東西,這個數(shù)組的第一項的地址對應上面代碼中的HDF_DRIVER_BEGIN(),最后一項的地址對應HDF_DRIVER_END()(最后一項不填內容)。示意圖如下: 獲取驅動入口時,就是在遍歷這個指針數(shù)組,查詢與moduleName匹配的節(jié)點。


1.1.1.1.2 創(chuàng)建HdfDeviceNode對象

接著嘗試創(chuàng)建HdfDeviceNode對象,此時調用的HdfDeviceNodeNewInstance()函數(shù)如下:

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

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

復制代碼 又需要去查我們熟悉的對象創(chuàng)建表(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;
      
  • }

復制代碼 可以看到,實際創(chuàng)建的是一個DeviceNodeExt對象。DeviceNodeExt繼承于HdfDeviceNode,定義如下:

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

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

復制代碼 其構造函數(shù)如下:

【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域,將函數(shù)指針設為DeviceNodeExtPublishService了。

HdfDriverLoaderLoadNode()會給DeviceNodeExt的driverEntry域、deviceInfo域、deviceObject.property賦值,那么在進行綁定之前,DeviceNodeExt的示意圖大概是這樣的:


1.1.1.1.3綁定驅動入口

接下來要將剛剛創(chuàng)建的DeviceNodeExt節(jié)點和驅動入口綁定起來: driverEntry->Bind(&devNode->deviceObject)

前文我們已經說了,每個程序會實現(xiàn)自己的Bind動作,而HDF只負責回調Bind。注意,回調時HDF需要傳入DeviceNodeExt節(jié)點的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);
      
  • };

復制代碼 現(xiàn)在我們可以基于前文示意圖,繪制一張DeviceNodeExt和驅動程序綁定后的示意圖了,如下圖:
1.1.1.2 掛接HdfDeviceNode

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

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

復制代碼 嘗試把HdfDevice節(jié)點和DeviceNodeExt聯(lián)系起來,這一句其實是調用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節(jié)點在之前已經添加進DevHostService的devices列表了,現(xiàn)在它又和DeviceNodeExt聯(lián)系起來了,再結合前文中的知識,我們可以畫一張大一點兒的關系示意圖了,如下: 至此,相信大家已經基本了解掛接設備host所形成的數(shù)據(jù)結構了,正如上圖所示,每個host都會對應上圖中紅、綠、藍三個范疇。大家不妨自己試著畫畫這張圖,看看還會發(fā)現(xiàn)什么。至于HDF的其他方面,我們可以在其他文章里再探討。

文章轉自:侯亮(悠然紅茶)
回復

使用道具 舉報

發(fā)表回復

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則


聯(lián)系客服 關注微信 下載APP 返回頂部 返回列表