我們闡述了在啟動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的其他方面,我們可以在其他文章里再探討。
編輯:hfy
-
函數
+關注
關注
3文章
4333瀏覽量
62687 -
設備驅動
+關注
關注
0文章
68瀏覽量
10897 -
鴻蒙系統
+關注
關注
183文章
2636瀏覽量
66393
發布評論請先 登錄
相關推薦
評論