input设备适配HDF框架并和用户态程序交互
# input设备适配HDF框架并和用户态程序交互 # HDF(OpenHarmony Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。 input设备适配HDF框架 以rk3568中 gt911_5p5 触摸屏为例说明inpu
# input设备适配HDF框架并和用户态程序交互 #
HDF(OpenHarmony Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
input设备适配HDF框架
以rk3568中 gt911_5p5 触摸屏为例说明input设备适配hdf框架步骤:
1、添加驱动配置文件
1.1 配置设备驱动描述信息【必须】
配置文件路径:
./vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs
在该文件的input::host{}中添加对应的设备描述:
input :: host {
hostName = "input_host";
priority = 100;
//公共驱动:HDF_INPUT_MANAGER
device_input_manager :: device {
...
}
//公共驱动:HDF_TOUCH
device_hdf_touch :: device {
...
}
//适配gt911_5p5触摸屏驱动描述信息
device_touch_chip :: device {//设备节点
device0 :: deviceNode {//驱动的DeviceNode节点。
policy = 0;//驱动服务发布的策略
priority = 130;//驱动启动优先级(0-200),值越大优先级越低,
preload = 0;//驱动按需加载字段,0:默认加载,1:当系统支持快速启动的时候,则在系统完成之后再加载这一类驱动 2:默认不加载,支持后续动态加载
permission = 0660;//驱动创建设备节点权限
moduleName = "HDF_TOUCH_GT911";//驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
serviceName = "hdf_touch_gt911_service";//驱动对外发布服务的名称,必须唯一
deviceMatchAttr = "zsj_gt911_5p5";//驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等。
}
}
//公共驱动:HDF_HID
device_hdf_hid :: device {
...
}
//公共驱动:HDF_INFRARED
device_hdf_infrared :: device {
...
}
}
1.2 配置设备私有描述信息:【可选】
如果驱动配置有deviceMatchAttr参数,需添加一个私有配置文件:
路径:./vendor/hihope/rk3568/hdf_config/khdf/device_info/input_config.hcs
root {
input_config {
touchConfig {
touch0 {
//公共驱动:HDF_TOUCH 私有配置信息
boardConfig {
match_attr = "touch_device1";
inputAttr {
/* 0:touch 1:key 2:keyboard 3:mouse 4:button 5:crown 6:encoder */
inputType = 0;
solutionX = 720;
solutionY = 1280;
devName = "main_touch";
}
//部分公共touch私有配置信息跟随触摸器件修改
// Hi3516DV300-Runhe gt911--5p5 & 4p0 start
busConfig {
// 0:i2c 1:spi
busType = 0;
busNum = 1;
clkGpio = 86;
dataGpio = 87;
i2cClkIomux = [0x114f0048, 0x403];
i2cDataIomux = [0x114f004c, 0x403];
}
pinConfig {
rstGpio = 14;
intGpio = 13;
rstRegCfg = [0x112f0094, 0x400];
intRegCfg = [0x112f0098, 0x400];
}
// Hi3516DV300-Runhe gt911--5p5 & 4p0 end
powerConfig {
/* 0:unused 1:ldo 2:gpio 3:pmic */
vccType = 2;
vccNum = 20; // gpio20
vccValue = 1800;
vciType = 1;
vciNum = 12; // ldo12
vciValue = 3300;
}
featureConfig {
capacitanceTest = 0;
gestureMode = 0;
gloverMOde = 0;
coverMode = 0;
chargerMode = 0;
knuckleMode = 0;
}
}
chipConfig {
//适配gt911_5p5触摸屏私有驱动描述信息:zsj_gt911_5p5
chip0 :: touchChip {
match_attr = "zsj_gt911_5p5";
chipInfo = "ZIDN45100"; // 4-ProjectName, 2-TP IC, 3-TP Module
chipVersion = 0; //parse point by TypeA
chipName = "gt911";
vendorName = "zsj";
/* 0:i2c 1:spi*/
busType = 0;
deviceAddr = 0x5D;
/* 0:None 1:Rising 2:Failing 4:High-level 8:Low-level */
irqFlag = 2;
maxSpeed = 400;
chipVersion = 0; //parse Coord TypeA
powerSequence {
/* [type, status, dir , delay]
<type> 0:none 1:vcc-1.8v 2:vci-3.3v 3:reset 4:int
<status> 0:off or low 1:on or high 2:no ops
<dir> 0:input 1:output 2:no ops
<delay> meanings delay xms, 20: delay 20ms
*/
powerOnSeq = [4, 0, 1, 5,
3, 0, 1, 10,
3, 1, 1, 60,
4, 2, 0, 50];
suspendSeq = [3, 0, 2, 10];
resumeSeq = [3, 1, 2, 10];
powerOffSeq = [3, 0, 2, 10,
1, 0, 2, 20];
}
}
}
}
}
...
}
1.3 将配置文件添加到板级配置:
将上面两个配置文件添加到板级配置入口文件hdf.hcs中
路径:./vendor/hihope/rk3568/hdf_config/khdf/hdf.hcs
#include "input/input_config.hcs"
#include "device_info/device_info.hcs"
2、驱动开发
2.1 开发驱动配置解析函数 【可选】####
路径:./drivers/hdf_core/framework/model/input/driver/input_config_parser.c
该函数主要将 hcs 文件中各字段含义进行解析,如果现有函数不满足hcs文件添加信息的解析,可以仿照现有函数添加新的解析方法
//公共驱动:HDF_TOUCH 私有配置信息 解析
int32_t ParseTouchBoardConfig(const struct DeviceResourceNode *node, TouchBoardCfg *config)
{
...
}
//gt911_5p5触摸屏私有驱动描述信息 解析
int32_t ParseTouchChipConfig(const struct DeviceResourceNode *node, TouchChipCfg *config)
{
...
}
2.2 驱动实现
对于touch 类型的设备,公共驱动框架已实现。
路径为:/drivers/hdf_core/framework/model/input/driver/touchscreen/hdf_touch.c
适配gt911_5p5触摸屏需要完成器件层驱动初始化、释放资源、注册驱动至HDF框架及触摸屏器件差异化接口适配
路径:/drivers/hdf_core/framework/model/input/driver/touchscreen/touch_gt911.c
具体实现函数如下:
2.2.1 注册到HDF框架
//驱动注册到HDF框架函数
struct HdfDriverEntry g_touchGoodixChipEntry = {
.moduleVersion = 1,
.moduleName = "HDF_TOUCH_GT911", // /驱动名称,该字段的值必须和驱动信息配置文件中moduleName的值一致
.Init = HdfGoodixChipInit,
.Release = HdfGoodixChipRelease,
};
HDF_INIT(g_touchGoodixChipEntry);
2.2.2 器件层驱动初始化
//器件层驱动初始化
static int32_t HdfGoodixChipInit(struct HdfDeviceObject *device)
{
TouchChipCfg *chipCfg = NULL;
ChipDevice *chipDev = NULL;
HDF_LOGI("%s: enter", __func__);
if (device == NULL) {
return HDF_ERR_INVALID_PARAM;
}
/* 器件配置结构体内存申请、配置信息解析及挂载 */
chipCfg = ChipConfigInstance(device);
if (chipCfg == NULL) {
return HDF_ERR_MALLOC_FAIL;
}
/* 器件实例化 */
chipDev = ChipDeviceInstance();
if (chipDev == NULL) {
goto EXIT;
}
/* 器件信息挂载及器件私有操作挂载 */
chipDev->chipCfg = chipCfg;
chipDev->ops = &g_gt911ChipOps;
chipDev->chipName = chipCfg->chipName;
chipDev->vendorName = chipCfg->vendorName;
device->priv = (void *)chipDev;
/* 注册器件驱动至平台驱动 */
if (RegisterTouchChipDevice(chipDev) != HDF_SUCCESS) {
goto EXIT1;
}
HDF_LOGI("%s: exit succ, chipName = %s", __func__, chipCfg->chipName);
return HDF_SUCCESS;
EXIT1:
OsalMemFree(chipDev);
EXIT:
FreeChipConfig(chipCfg);
return HDF_FAILURE;
}
2.2.3 器件层驱动释放资源
static void HdfGoodixChipRelease(struct HdfDeviceObject *device)
{
if (device == NULL || device->priv == NULL) {
HDF_LOGE("%s: param is null", __func__);
return;
}
HDF_LOGI("%s: goodix chip is release", __func__);
}
2.2.4 器件层驱动数据上报
正常流程需要实现HdfGoodixChipBind 函数用于,触摸屏和外部进行数据同行,但是公共驱动层HDF_TOUCH已经用HdfTouchDriverBind函数实现,器件不用重新实现,可以直接使用。
路径:/drivers/hdf_core/framework/model/input/driver/hdf_touch.c
static int32_t HdfTouchDriverBind(struct HdfDeviceObject *device)
{
if (device == NULL) {
HDF_LOGE("%s: param is null", func);
return HDF_ERR_INVALID_PARAM;
}
static struct IDeviceIoService touchService = {
.Dispatch = HdfTouchDispatch,
};
device->service = &touchService;
return HDF_SUCCESS;
}
2.2.4 触摸屏器件差异化接口适配
触摸屏器件差异化接口适配
// gt911差异化接口适配
static struct TouchChipOps g_gt911ChipOps = {// 器件IC接口
.Init = ChipInit,// 初始化
.Detect = ChipDetect,// 器件检测
.Resume = ChipResume,// 唤醒
.Suspend = ChipSuspend,// 休眠
.DataHandle = ChipDataHandle,// 器件数据读取
.UpdateFirmware = UpdateFirmware,// 固件升级
.SetAbility = SetAbility,
};
static int32_t ChipInit(ChipDevice *device)
{
return HDF_SUCCESS;
}
static int32_t ChipResume(ChipDevice *device)
{
return HDF_SUCCESS;
}
static int32_t ChipSuspend(ChipDevice *device)
{
return HDF_SUCCESS;
}
static int32_t ChipDetect(ChipDevice *device)
{
...
}
static int32_t ChipDataHandle(ChipDevice *device)
{
...
}
static int32_t UpdateFirmware(ChipDevice *device)
{
...
}
static void SetAbility(ChipDevice *device)
{
...
}
3、驱动编译配置
3.1、为内核增加对应的config参数
路径:.\drivers\hdf_core\adapter\khdf\linux\model\input\Kconfig
在Kconfig文件中添加 DRIVERS_HDF_TP_5P5_GT911 参数:
config DRIVERS_HDF_TP_5P5_GT911
bool "Enable HDF tp 5P5 GT911 driver"
default n
depends on DRIVERS_HDF_INPUT
help
Answer Y to enable HDF TP 5P5 GT911 driver.
3.2、编译文件Makefile中添加驱动配置
路径:.\drivers\hdf_core\adapter\khdf\linux\model\input\Makefile
在Makefile文件中添加 DRIVERS_HDF_TP_5P5_GT911 编译配置:
obj-$(CONFIG_DRIVERS_HDF_TP_5P5_GT911) += \
$(INPUT_ROOT_DIR)/touchscreen/touch_gt911.o
3.3、在rk3568内核参数中增加DRIVERS_HDF_TP_5P5_GT911参数
路径:.\kernel\linux/config/linux-5.10/arch/arm64/configs/rk3568_standard_defconfig
在rk3568_standard_defconfig文件中添加 DRIVERS_HDF_TP_5P5_GT911 = y 参数:
CONFIG_DRIVERS_HDF_INPUT=y
CONFIG_DRIVERS_HDF_TP_5P5_GT911=y
基于HDF框架编写用户态程序和驱动交互
当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现.
消息机制的功能主要有以下两种:
1.用户态应用发送消息到驱动。
2.用户态应用接收驱动主动上报事件。
1.1、用户态应用发送消息到驱动
static int SendEvent(struct HdfIoService *serv, char *eventData)
{
int ret = 0;
struct HdfSBuf *data = HdfSBufObtainDefaultSize();
if (data == NULL) {
HDF_LOGE("fail to obtain sbuf data");
return 1;
}
struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
if (reply == NULL) {
HDF_LOGE("fail to obtain sbuf reply");
ret = HDF_DEV_ERR_NO_MEMORY;
goto out;
}
if (!HdfSbufWriteString(data, eventData)) {
HDF_LOGE("fail to write sbuf");
ret = HDF_FAILURE;
goto out;
}
ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply);
if (ret != HDF_SUCCESS) {
HDF_LOGE("fail to send service call");
goto out;
}
int replyData = 0;
if (!HdfSbufReadInt32(reply, &replyData)) {
HDF_LOGE("fail to get service call reply");
ret = HDF_ERR_INVALID_OBJECT;
goto out;
}
HDF_LOGE("Get reply is: %d", replyData);
out:
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
1.2、用户态应用接收驱动主动上报事件
1.2.1、用户态编写驱动上报消息的处理函数
static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data)
{
OsalTimespec time;
OsalGetTime(&time);
HDF_LOGE("%s received event at %llu.%llu", (char *)priv, time.sec, time.usec);
const char *string = HdfSbufReadString(data);
if (string == NULL) {
HDF_LOGE("fail to read string in event data");
return -1;
}
HDF_LOGE("%s: dev event received: %d %s", (char *)priv, id, string);
return 0;
}
1.2.2、用户态编写驱动上报消息的处理函数
int RegisterListen()
{
struct HdfIoService *serv = HdfIoServiceBind("sample_driver", 0);
if (serv == NULL) {
HDF_LOGE("fail to get service");
return -1;
}
static struct HdfDevEventlistener listener = {
.callBack = OnDevEventReceived,
.priv ="Service0"
};
if (HdfDeviceRegisterEventListener(serv, &listener) != 0) {
HDF_LOGE("fail to register event listener");
return -1;
}
HdfDeviceUnregisterEventListener(serv, &listener);
HdfIoServiceRecycle(serv);
return 0;
}
1.3、完整交互用例
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"
#define HDF_LOG_TAG "sample_test"
#define SAMPLE_SERVICE_NAME "sample_service"
#define SAMPLE_WRITE_READ 123
int g_replyFlag = 0;
//驱动回调函数,通过接口注册到驱动用于驱动上报事件
static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data)
{
......
}
static int SendEvent(struct HdfIoService *serv, char *eventData)
{
......
}
int main()
{
char *sendData = "default event info";
//绑定驱动服务
struct HdfIoService *serv = HdfIoServiceBind(SAMPLE_SERVICE_NAME, 0);
if (serv == NULL) {
HDF_LOGE("fail to get service %s", SAMPLE_SERVICE_NAME);
return HDF_FAILURE;
}
static struct HdfDevEventlistener listener = {
.callBack = OnDevEventReceived,
.priv ="Service0"
};
//注册驱动回调函数
if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) {
HDF_LOGE("fail to register event listener");
return HDF_FAILURE;
}
//给驱动发送消息
if (SendEvent(serv, sendData)) {
HDF_LOGE("fail to send event");
return HDF_FAILURE;
}
/* wait for event receive event finishing */
while (g_replyFlag == 0) {
sleep(1);
}
//注销驱动回调函数
if (HdfDeviceUnregisterEventListener(serv, &listener)) {
HDF_LOGE("fail to unregister listener");
return HDF_FAILURE;
}
//释放资源
HdfIoServiceRecycle(serv);
return HDF_SUCCESS;
}
更多推荐
所有评论(0)