引言
为了方便查阅,本文汇集了我在学习鸿蒙驱动子系统过程中,曾经遇到过的HDF驱动框架提供的API。 同时,还加入了一些对这些API的个人理解和解读。
另外,大家也可以去阅读这些API的源码或官方文档:
https://device.harmonyos.com/cn/docs/documentation/apiref/core-0000001054718073
一、结构体
1.1 HdfDriverEntry
结构体HdfDriverEntry
可以称为HDF驱动入口结构体
,代表设备驱动的入口。
1、官方文档
https://device.harmonyos.com/cn/docs/documentation/apiref/hdfdriverentry-0000001055198130
2、定义
drivers/framework/include/core/hdf_device_desc.h
struct HdfDriverEntry {
//驱动程序的版本号
int32_t moduleVersion;
//驱动程序的名称,必须与驱动配置文件device_info.hcs中设备节点的moduleName属性保持一致。
const char *moduleName;
//三个函数指针,指向设备驱动的三个入口函数。
int32_t (*Bind)(struct HdfDeviceObject *deviceObject);
int32_t (*Init)(struct HdfDeviceObject *deviceObject);
void (*Release)(struct HdfDeviceObject *deviceObject);
};
在结构体HdfDriverEntry
中,三个函数指针所指向的函数被称为 驱动入口函数 ,由驱动开发者负责编写,被HDF驱动框架调用。
(1)Bind函数
用于向HDF驱动框架告知(注册)驱动程序的驱动服务入口。
函数执行成功时,返回值等于0。
(2)Init函数
主要是用来完成驱动的一些初始化动作,比如:通过HDF提供的接口获取设备的配置信息、初始化设备、订阅驱动提供的服务等等。
函数执行成功时,返回值等于0。
(3)Release函数
用来释放驱动程序所占用资源。
HDF驱动框架在加载驱动的过程中,首先调用Bind
函数,然后再调用Init
函数。当加载驱动的过程中出现异常,或者当驱动被卸载的时候,HDF驱动框架会调用Release
函数释放驱动所占用的资源。
驱动入口函数的参数都是指向结构体HdfDeviceObject
(见1.2节) 的指针。
1.2 HdfDeviceObject
结构体HdfDeviceObject
可以被称为HDF设备对象结构体
,是由HDF生成的,代表一个设备节点。HDF驱动框架通过解析驱动的配置文件,获取到了所有设备节点的配置信息,然后它就会为每个设备节点创建一个这样的结构体,用于存放设备节点的配置信息和驱动服务入口;当HDF调用驱动入口函数(见1.1节)的时候,会把指向这个结构体的指针作为参数传给这些函数。
1、官方文档
https://device.harmonyos.com/cn/docs/documentation/apiref/hdfdeviceobject-0000001054479563
2、定义
drivers/framework/include/core/hdf_device_desc.h
struct HdfDeviceObject {
//指向驱动服务入口结构体的指针
struct IDeviceIoService *service;
//指向设备节点配置信息的指针,
const struct DeviceResourceNode *property;
//设备节点所属的设备类型
DeviceClass deviceClass;
//指向设备节点的私有数据
void *priv;
};
结构体HdfDeviceObject
中有4个成员:
(1)service
指向驱动服务入口结构体IDeviceIoService
(见1.3节)的指针。驱动程序开发者需要在Bind
函数(见1.1节)中通过对这个指针赋值,将驱动对外提供服务的入口告知HDF。
(2)property
指向结构体DeviceResourceNode
(见1.4节)的指针。在这个结构体中存放着HDF已经获取到的设备节点的必选配置信息。
(3)deviceClass
设备节点所属的设备种类,取值类型:枚举类型DeviceClass
(见3.1节)。
(4)priv
指向设备节点的私有数据的指针。
1.3 IDeviceIoService
驱动程序的功能大多是通过对外提供服务的形式呈现出来的。对于任何一个驱动程序,其对外提供服务的入口都必须是 IDeviceIoService
结构体。即使你也可以自定义驱动入口结构体,但自定义的驱动入口结构体的第一个成员必须是IDeviceIoService
结构体。
1、官方文档
https://device.harmonyos.com/cn/docs/documentation/apiref/ideviceioservice-0000001055198134
2、定义
drivers/framework/include/core/hdf_device_desc.h
struct IDeviceIoService {
//驱动服务的ID
struct HdfObject object;
//当用户态的应用程序获取驱动服务的时候,该函数被HDF调用。
int32_t (*Open)(struct HdfDeviceIoClient *client);
//当用户态的应用程序调用应用态Dispatch函数的时候,HDF就会调用这个内核态的Dispatch函数,驱动开发者可以在这个函数中实现驱动提供的服务。
int32_t (*Dispatch)(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply);
//当用户态的应用程序释放驱动服务的时候,该函数被HDF调用。
void (*Release)(struct HdfDeviceIoClient *client);
};
在结构体IDeviceIoService
中有4个成员:
第一个成员object
,用于存放驱动服务的ID,HdfObject
结构体类型(见1.6节),这个结构体中只有一个字段(objectId),这是一个由HDF赋值的32bit的整数。
接下来的三个函数指针指向的函数,都是被HDF调用的,函数的参数也是由HDF传入的,第一个参数都是指向HdfDeviceIoClient
结构体(见1.7节)的指针。驱动程序开发者可以根据实际需要,选择是否编写这三个函数。
(1)Open函数
当在用户态的应用程序中,调用函数HdfIoServiceBind
(见2.9节)获取驱动服务的时候,该函数被HDF调用。
(2)Dispatch函数
用户态的应用程序与内核态的驱动程序之间的交互必须使用Dispatch
函数。这个函数由驱动开发者编写,在应用程序中调用HDF提供的Dispatch接口函数(见1.11节)使用驱动服务的时候被HDF调用。HDF调用这个函数的时候,传进来4个参数:
参数 | 类型 | 描述 |
---|---|---|
client | HdfDeviceIoClient 结构体(见1.7节)指针 | 这个结构体用于存放HDF设备IO服务客户端的信息。 |
cmdId | 整数 | 来自应用程序的命令字。 |
data | 指向HdfSBuf 结构体(见1.8节)的指针 | 指向一个缓冲区,缓冲区用于存放从应用程序接收的数据。 |
reply | 指向HdfSBuf 结构体(见1.8节)的指针 | 指向一个缓冲区,缓冲区用于存放向应用程序回送的数据。 |
(3)Release函数
当在用户态的应用程序中,调用函数HdfIoServiceRecycle
(见2.11节)释放驱动服务的时候,该函数被HDF调用。
1.4 DeviceResourceNode
用于存放设备树中一个设备节点的配置信息,包括设备节点的名称、属性,以及指向这个设备节点的父节点、子节点、兄弟姐妹节点的指针。通过这种结构体,多个设备节点以双向链表的形式构成了设备树。
1、官方文档
https://device.harmonyos.com/cn/docs/documentation/apiref/deviceresourcenode-0000001054598157
2、定义
drivers/framework/include/config/device_resource_if.h
struct DeviceResourceNode {
const char *name; //节点的名称
uint32_t hashValue; //节点的ID
struct DeviceResourceAttr *attrData; //指向节点的属性结构体(见1.5节)
struct DeviceResourceNode *parent; //指向父节点的指针
struct DeviceResourceNode *child; //指向子节点的指针
struct DeviceResourceNode *sibling; //指向兄弟姐妹节点的指针
};
1.5 DeviceResourceAttr
用于存放设备节点的一个属性。设备节点的属性是以单向链表的形式存储的,链表中的每个节点就是一个DeviceResourceAttr
结构体,存放着设备节点的一个属性。
1、官方文档
https://device.harmonyos.com/cn/docs/documentation/apiref/deviceresourceattr-0000001055078135
2、定义
drivers/framework/include/config/device_resource_if.h
struct DeviceResourceAttr {
const char *name; //属性的名称
const char *value; //属性的值
struct DeviceResourceAttr *next; //指向下一个属性的指针
};
1.6 HdfObject
只有一个成员objectId,32bit整数。
1、官方文档
https://device.harmonyos.com/cn/docs/develop/apiref/hdfobject-0000001054918155
2、定义
drivers/framework/include/core/hdf_object.h
struct HdfObject {
int32_t objectId;
};
1.7 HdfDeviceIoClient
这个结构体用于存放HDF设备IO服务客户端的信息。设备驱动程序通过HDF发布服务,相当于“服务器”;应用程序通过HDF请求服务,相当于“客户端”。
1、官方文档
https://device.harmonyos.com/cn/docs/develop/apiref/hdfdeviceioclient-0000001054879532
2、定义
drivers/framework/include/core/hdf_device_desc.h
struct HdfDeviceIoClient {
//指向HDF设备对象结构体的指针
struct HdfDeviceObject *device;
//指向客户端的私有数据
void *priv;
};
1.8 HdfSBuf
HDF驱动框架定义的数据缓冲区。
1、官方文档
https://device.harmonyos.com/cn/docs/develop/apiref/hdfsbuf-0000001055039516
2、定义
drivers/framework/ability/sbuf/src/hdf_sbuf.c
1.9 DeviceResourceIface
这种结构体不需要驱动开发者创建,它是由HDF根据设备配置文件的类型(见3.2节)创建的,里面全是函数指针,指向的函数用于获取设备的各种配置信息,是驱动程序获取设备配置信息的入口。驱动开发者只需要先调用接口函数DeviceResourceGetIfaceInstance
(见2.8节)获取到这个结构体的地址,然后就可以通过调用里面的函数指针所指向的函数获取设备的配置信息了。
1、官方文档
https://device.harmonyos.com/cn/docs/documentation/apiref/deviceresourceiface-0000001054918151
2、定义
drivers/framework/include/config/device_resource_if.h
3、结构体中的函数指针
(1)GetUint32
int32_t (*GetUint32)(const struct DeviceResourceNode *node, const char *attrName, uint32_t *value, uint32_t def)
从一个设备节点(参数node
)读取属性(参数attrName
)的值,并将读到的值保存到指针(参数value
)指向的变量中;如果没有读到指定属性的值,就将参数def
的值保存到指针(参数value
)指向的变量中。
1.10 HdfIoService
这种结构体用于表示一个驱动服务对象,可以理解为驱动程序通过HDF框架暴露给应用程序的接口。
1、官方文档
https://device.harmonyos.com/cn/docs/documentation/apiref/hdfioservice-0000001054598161
2、定义
drivers/framework/include/core/hdf_io_service_if.h:127
这种结构体应该是HDF负责生成、提供给应用程序使用的,其中最重要的成员是指向HdfIoDispatcher
结构体(见1.11节)的指针。在应用程序中,调用函数HdfIoServiceBind
(见2.9节),可根据驱动服务的名称获得指向HdfIoService
结构体的指针。
1.11 HdfIoDispatcher
这个结构体体中只有一个成员:函数指针Dispatch
。
1、官方文档
https://device.harmonyos.com/cn/docs/develop/apiref/hdfiodispatcher-0000001055078139
2、定义
drivers/framework/include/core/hdf_io_service_if.h:115
struct HdfIoDispatcher {
int (*Dispatch)(struct HdfObject *service, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply);
};
这里的指针Dispatch
所指向的函数不需要驱动开发者编写,是由HDF框架提供的,供应用程序调用。在应用程序中调用指针Dispatch
所指向的函数时,需要给它传进去以下4个参数:
参数 | 类型 | 描述 |
---|---|---|
service | 指向HdfObject 结构体(见1.6节)指针 | 这个参数的值是调用函数HdfIoServiceBind (见2.9节)获得的结构体HdfIoService (见1.10节)中第一个成员的地址。 |
cmdId | 整数 | 应用程序发送给驱动程序的命令字。 |
data | 指向HdfSBuf 结构体(见1.8节)的指针 | 指向一个缓冲区,缓冲区用于存放向驱动程序发送的数据。 |
reply | 指向HdfSBuf 结构体(见1.8节)的指针 | 指向一个缓冲区,缓冲区用于存放从驱动程序接收的数据。 |
在应用程序中调用指针Dispatch
所指向的函数时,最终会导致驱动程序中的Dispatch
函数被执行。
1.12 HdfDevEventlistener
驱动事件的监听器。
1、官方文档
https://device.harmonyos.com/cn/docs/develop/apiref/hdfdeveventlistener-0000001055358108
2、定义
drivers/framework/include/core/hdf_io_service_if.h:99
如果在应用程序中要监听驱动程序主动上报的事件并对其进行处理,就要先定义一个这种结构体,然后再调用函数HdfDeviceRegisterEventListener
(见2.10节)对其进行注册。当应用程序监听到驱动程序主动上报的事件时,函数指针onReceive
所指向的回调函数就会被自动执行,用于处理驱动程序主动上报的事件。
函数指针onReceive
的类型OnDevEventReceive
定义如下:
开发者需要在应用程序中编写函数指针onReceive
所指向的回调函数,这个回调函数有4个传入参数:
(1)listener
:指向监听器(HdfDevEventlistener
结构体,见1.12节)的指针。
(2)service
:指向HdfIoService
结构体(见1.10节)的指针。
(3)id
:驱动上报事件的编号。
(4)data:指向从驱动接收到的数据的缓冲区。
1.13 SubscriberCallback
与驱动服务订阅有关的回调结构体。
1、官方文档
https://device.harmonyos.com/cn/docs/documentation/apiref/subscribercallback-0000001055358146
2、定义
drivers/framework/include/core/hdf_device_desc.h:164
结构体SubscriberCallback
有两个成员:
(1)deviceObject
:指向设备对象结构体HdfDeviceObject
(见1.2节)的指针。
(2)OnServiceConnected
:回调函数指针。
int32_t (*OnServiceConnected)(struct HdfDeviceObject *deviceObject, const struct HdfObject *service)
在用函数HdfDeviceSubscribeService
(见2.14节)订阅了驱动服务之后,当驱动被加载完成后,这个指针指向的函数就会被HDF自动调用。HDF调用该函数时传进来两个参数:第一个参数时指向设备对象结构体HdfDeviceObject
(见1.2节)的指针;第2个参数是指向驱动服务入口结构体(见1.3节)的指针。
下一篇: 《HDF驱动框架的API》(2)