文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

OpenHarmony HDF Input驱动模型分析与使用

2024-12-14 00:39

关注

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

概述

输入设备是用户与计算机系统进行人机交互的主要装置之一,是用户与计算机或者其他设备通信的桥梁。常见的输入设备有键盘、鼠标、游戏杆、触摸屏等。本文档将介绍如何使用 Hi3516DV300 开发板完成基于 HDF_Input 模型的触摸屏(Touch Screen)器件驱动开发,从而使开发者快速入门。

硬件资源简介

Touch 设备与主机通讯一般采用 I2C 总线完成数据的交互,为了提高触屏数据的实时性,触屏 IC 都会提供中断支持。当有触屏事件发生时,会触发主机中断管脚完成一次中断响应。中断处理函数中主机通过 I2C 总线读取触屏 IC 寄存器完成一次数据采集。

Hi3516DV300 开发板套件所提供的触摸屏器件 IC 为 GT911,该器件采用标准 I2C 与主机通信,通过 6pin 软排线与主板连接。6pin 分布以及实物连接图如下图所示:


Input模型简介

Input模型概览


Input 驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。器件产生的数据借助平台数据通道能力从内核传递到用户态,驱动模型通过配置文件适配不同器件及硬件平台,提高开发者的器件驱动开发效率。如下部分为模型各部分的说明:

(1)input 设备管理:为各类输入设备驱动提供 input 设备的注册、注销接口,同时统一管理 input 设备列表;

(2)input 平台驱动:指各类 input 设备的公共抽象驱动(例如触摸屏的公共驱动),负责对板级硬件进行初始化、硬件中断处理、向 manager 注册 input 设备等;

(3)input 器件驱动:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化;

(4)input 数据通道:提供一套通用的数据上报通道,各类别的 input 设备驱动均可用此通道上报 input 事件;

(5)input 配置解析:负责对 input 设备的板级配置及器件私有配置进行解析及管理。

Input模型工作流程解析

为了让开发者更清晰的了解 Input 模型工作流程,本节将对 input 模型加载的关键流程代码进行说明。

本章节为 Input 模型工作流程说明,开发者无需进行开发。

私有配置信息解析

示例代码路径:

  1. ./drivers/framework/model/input/driver/input_config_parser.c 

 根据 OSAL 提供的配置解析函数,可以将 hcs 文件中各字段含义进行解析,具体请参考 input_config_parser.c 中各函数的实现。如果提供的模板不能满足需求,在 hcs 文件中添加相应信息后,需要根据添加的字段开发相应的解析函数。

  1. static int32_t ParseAttr(struct DeviceResourceIface *parser, const struct DeviceResourceNode *attrNode, BoardAttrCfg *attr) 
  2. int32_t ret; 
  3. // 获取inputType字段信息,保存在BoardAttrCfg结构体中 
  4.     ret = parser->GetUint8(attrNode, "inputType", &attr->devType, 0);      
  5.     CHECK_PARSER_RET(ret, "GetUint8"); 
  6.     ... 
  7.     return HDF_SUCCESS; 

管理驱动层初始化及注册驱动至HDF框架

示例代码路径:

  1. ./drivers/framework/model/input/driver/hdf_input_device_manager.c 
  2. static int32_t HdfInputManagerInit(struct HdfDeviceObject *device) 
  3. {  
  4.  
  5.     g_inputManager = InputManagerInstance(); 
  6.     ... 
  7. struct HdfDriverEntry g_hdfInputEntry = { 
  8.     .moduleVersion = 1, 
  9.     .moduleName = "HDF_INPUT_MANAGER"
  10.     .Bind = HdfInputManagerBind, 
  11.     .Init = HdfInputManagerInit, 
  12.     .Release = HdfInputManagerRelease, 
  13. }; 
  14. HDF_INIT(g_hdfInputEntry);        //驱动注册入口 

公共驱动层初始化及注册驱动至HDF框架

示例代码路径:

  1. ./drivers/framework/model/input/driver/hdf_touch.c 
  2. static int32_t HdfTouchDriverProbe(struct HdfDeviceObject *device) 
  3.    ... 
  4.      
  5.     boardCfg = BoardConfigInstance(device); 
  6.     ... 
  7.      
  8.     touchDriver = TouchDriverInstance(); 
  9.     ... 
  10.      
  11.     ret = TouchDriverInit(touchDriver, boardCfg); 
  12.     if (ret == HDF_SUCCESS) { 
  13.         ... 
  14.         
  15.         AddTouchDriver(touchDriver); 
  16.         ... 
  17.     } 
  18.     ... 
  19. struct HdfDriverEntry g_hdfTouchEntry = { 
  20.     .moduleVersion = 1, 
  21.     .moduleName = "HDF_TOUCH"
  22.     .Bind = HdfTouchDriverBind, 
  23.     .Init = HdfTouchDriverProbe, 
  24.     .Release = HdfTouchDriverRelease, 
  25. }; 
  26.                                 
  27. HDF_INIT(g_hdfTouchEntry);       //驱动注册入口 

器件驱动层初始化及注册驱动至HDF框架

具体请参考适配器件私有驱动器件层驱动初始化及注册驱动至 HDF 框架部分。

具体调用逻辑串联函数

Input 模型管理层驱动 init 函数初始化了设备管理链表,公共驱动层初始化函数完成了相关结构体的内存申请。器件驱动相关信息通过 RegisterChipDevice 函数对公共驱动层相关结构体进行信息填充,同时完成了相关硬件信息的初始化(如中断注册等),绑定设备与驱动组成 inputDev 通过 RegisterInputDevice 函数向驱动管理层进行注册,在 RegisterInputDevice 函数中主要实现了将 inputDev 向设备管理链表的添加等功能。如下所示为两个函数的实现部分:

函数具体实现代码位置

  1. ./drivers/framework/model/input/driver/hdf_touch.c 
  2. int32_t RegisterChipDevice(ChipDevice *chipDev) 
  3. … 
  4.  
  5.     DeviceBindDriver(chipDev); 
  6. … 
  7.  
  8. ChipDriverInit(chipDev); 
  9. … 
  10.      
  11. inputDev = InputDeviceInstance(chipDev); 
  12.     … 
  13.      
  14. RegisterInputDevice(inputDev); 
  15. … 

 函数具体实现代码位置

  1. ./drivers/framework/model/input/driver/hdf_input_device_manager.c 
  2. int32_t RegisterInputDevice(InputDevice *inputDev) 
  3. … 
  4.      
  5.     ret = AllocDeviceID(inputDev); 
  6. … 
  7.  
  8.     CreateDeviceNode(inputDev); 
  9.      
  10.     AllocPackageBuffer(inputDev); 
  11.      
  12.     AddInputDevice(inputDev); 
  13.     ··· 

TouchScreen器件驱动开发

基于 Input 模型适配一款触摸屏 IC 需要完成的具体工作见下。

配置设备描述信息

驱动注册到 HDF 框架所需要的设备驱动描述信息,如驱动是否加载以及加载次序等。

配置文件路径:

  1. ./drivers/adapter/khdf/linux/hcs/device_info/device_info.hcs 

device_info.hcs 中的信息主要提供给 HDF 框架使用,包含了 Input 模型各层驱动注册到 HDF 框架所必需的信息,开发者无特殊场景需求无需改动。各驱动层私有配置信息通过“deviceMatchAttr”字段与 input_config.hcs 中的“match_attr”相关内容进行匹配。

配置文件中与 input 模块相关的内容如下所示

  1. input :: host { 
  2. hostName = "input_host"
  3. priority = 100; 
  4. device_input_manager :: device {       // Input管理层设备描述信息 
  5. device0 :: deviceNode { 
  6. policy = 2;                      // 向内核用户态均发布服务 
  7. priority = 100;                   // input管理层驱动优先级默认为100 
  8. preload = 0;                     // 加载该驱动 
  9. permission = 0660;               // 驱动创建设备节点权限 
  10. moduleName = "HDF_INPUT_MANAGER"; // 与驱动入口moduleName匹配 
  11. serviceName = "hdf_input_host";  // HDF框架生成的节点名 
  12. deviceMatchAttr = "";         // manager目前不需要私有配置,因此为空 
  13. device_hdf_touch :: device {              // Input公共驱动层设备描述信息 
  14. device0 :: deviceNode { 
  15.         policy = 2;                     // 向内核用户态均发布服务 
  16.         priority = 120;                 // input公共驱动优先级默认为120 
  17.         preload = 0;                   // 加载该驱动 
  18.         permission = 0660;             // 驱动创建设备节点权限 
  19.         moduleName = "HDF_TOUCH";   // 与驱动入口的moduleName匹配 
  20.         serviceName = "hdf_input_event1";  // HDF框架生成的节点名 
  21.         deviceMatchAttr = "touch_device1";  // 与 “match_attr”字段一致 
  22.     } 
  23. device_touch_chip :: device {              // Input器件驱动层信息 
  24.     device0 :: deviceNode { 
  25.         policy = 0;                    // 向内核用户态均不发布服务 
  26.         priority = 130;                 // input器件驱动优先级默认为130 
  27.         preload = 0;                   // 加载该驱动 
  28.         permission = 0660;             // 驱动创建设备节点权限 
  29.         moduleName = "HDF_TOUCH_GT911";   // 与moduleName匹配 
  30.         serviceName = "hdf_touch_gt911_service"; // HDF框架节点名 
  31.         deviceMatchAttr = "zsj_gt911_5p5"; // 与“match_attr”字段一致 
  32.     } 

 该配置文件中需要重点关注的字段有:

“priority”决定驱动加载顺序;

“preload”决定驱动是否加载;

“moduleName ”需要与驱动注册入口处的“moduleName ”字段保持一致;

“serviceName ”HDF 框架依据该字段创建节点名;

“deviceMatchAttr ”需要与私有配置信息中的“match_attr”字段保持一致。

通过配置设备描述信息,使得 HDF 框架通过 moduleName 与注册至驱动入口的代码相匹配,保证了驱动的正常加载,通过 priority 字段保证了各驱动的加载顺序。

配置Touchscreen器件信息

器件私有信息包括上下电时序等,平台硬件信息包括器件连接主板的 GPIO 端口信息等。

配置文件路径:

  1. ./drivers/adapter/khdf/linux/hcs/input/input_config.hcs 

input_config.hcs 中的信息由驱动代码进行读取解析,主要由公共驱动层的私有配置信息及器件驱动层的私有配置信息组成。文件中的配置包含板级硬件信息及器件私有配置信息,实际业务开发时,可根据具体需求增删及修改对应内容。

  1.  pinConfig { 
  2.               rstGpio = 3;      // 复位管脚连接主机芯片的3号管脚 
  3.               intGpio = 4;     // 中断管脚连接主机芯片的4号管脚 
  4.               rstRegCfg = [0x112f0094, 0x400];   // 复位管脚配置信息 
  5.               intRegCfg = [0x112f0098, 0x400];  // 中断管脚配置信息 
  6.           } 
  7.           powerConfig { 
  8.                
  9.               vccType = 2;             // GPIO供电 
  10.               vccNum = 20;            // gpio20 
  11.               vccValue = 1800;         // 电压幅值为1800mV 
  12.               vciType = 1;             // LDO供电 
  13.               vciNum = 12;            // ldo12 
  14.               vciValue = 3300;         // 电压幅值为3300mV  
  15.           } 
  16. featureConfig { 
  17.               capacitanceTest = 0;      // 容值测试 
  18.               gestureMode = 0;        // 手势模式 
  19.               gloverMode = 0;         // 手套模式 
  20.               coverMode = 0;          // 皮套模式 
  21.               chargerMode = 0;        // 充电模式 
  22.               knuckleMode = 0;        // 指关节模式 
  23.           } 
  24.       } 
  25.       chipConfig {                    // 器件私有信息配置 
  26.           template touchChip {        // 模板 
  27.               match_attr = ""
  28.               chipName = "gt911";    // 触摸屏IC型号 
  29.               vendorName = "zsj";    // 供应商 
  30.               chipInfo = "AAAA11222";     
  31.   
  32.               busType = 0;            // 0代表I2C,1代表SPI 
  33.               deviceAddr = 0x5D;      // 器件IC通信地址 
  34.  
  35.               irqFlag = 2;                
  36.               maxSpeed = 400;        // 最大通信速率为400Hz 
  37.               chipVersion = 0;         // 触摸屏IC版本号 
  38. powerSequence { 
  39.  
  40. powerOnSeq = [4, 0, 1, 0,    // 中断管脚配置为输出,且进行拉低 
  41.              3, 0, 1, 10,   // 复位管脚配置为输出,且进行拉低,延时10ms 
  42.              3, 1, 2, 60,   // 复位管脚无操作,且进行拉高,延时60ms 
  43.              4, 2, 0, 0];   // 中断管脚配置为输入 
  44. suspendSeq = [3, 0, 2, 10];   // 复位管脚无操作,且进行拉低,延时10ms 
  45. resumeSeq = [3, 1, 2, 10];    // 复位管脚无操作,且进行拉高,延时10ms 
  46. powerOffSeq = [3, 0, 2, 10,   // 复位管脚无操作,且进行拉低,延时10ms 
  47.              1, 0, 2, 20];   // 电源正极管脚无操作,且进行拉低,延时20ms 
  48. chip0 :: touchChip { 
  49.  
  50.           match_attr = "zsj_gt911_5p5";    
  51.              
  52.           chipInfo = "ZIDN45100";     
  53.                
  54.           chipVersion = 0;            
  55.                 } 
  56.             } 
  57.         } 
  58.     } 

示例中“touchConfig”包含了“touch0”,"touch0"包含了“boardConfig”与“chipConfig”;“boardConfig”字段包含了 Hi3516DV300 板级硬件信息,“chipConfig”包含了触摸屏器件的私有信息,如果需要替换触摸屏器件,重新配置“chipConfig”对应的字段信息即可。同时产品可以配置多款触摸屏,示例中用“touch0”代表了套件中默认的触摸屏的硬件接口以及器件的配置信息,如产品需要配置副屏,可在与“touch0”并列的位置配置“touch1”的信息。

适配器件私有驱动

Input 模型对 Input 设备开发流程进行了抽象,开发者只需要适配器件驱动层,无需改动管理驱动层以及公共驱动层。

Input 模型由三层驱动组成,开发者适配一款全新触摸屏驱动只需要适配器件驱动层即可,重点实现差异化接口,本小节以代码示例的形式展示开发者需要重点完成的工作。

触摸屏器件差异化接口适配

示例代码路径

  1. ./drivers/framework/model/input/driver/touchscreen/touch_gt911.c 
  2. static struct TouchChipOps g_gt911ChipOps = {     // 器件IC接口 
  3. .Init = ChipInit,                         // 初始化 
  4. .Detect = ChipDetect,                   // 器件检测 
  5. .Resume = ChipResume,                 // 唤醒 
  6. .Suspend = ChipSuspend,                // 休眠 
  7. .DataHandle = ChipDataHandle,           // 器件数据读取 
  8. .UpdateFirmware = UpdateFirmware,      // 固件升级 
  9. }; 
  10.  
  11. static int32_t ChipDataHandle(ChipDevice *device) 
  12. ... 
  13.  
  14. reg[0] = (GT_BUF_STATE_ADDR >> ONE_BYTE_OFFSET) & ONE_BYTE_MASK;  
  15. reg[1] = GT_BUF_STATE_ADDR & ONE_BYTE_MASK; 
  16. ret = InputI2cRead(i2cClient, reg, GT_ADDR_LEN, &touchStatus, 1); 
  17. if (ret < 0 || touchStatus == GT_EVENT_INVALID) { 
  18. return HDF_FAILURE; 
  19. ... 
  20.  
  21. reg[0] = (GT_X_LOW_BYTE_BASE >> ONE_BYTE_OFFSET) & ONE_BYTE_MASK; 
  22. reg[1] = GT_X_LOW_BYTE_BASE & ONE_BYTE_MASK; 
  23. pointNum = touchStatus & GT_FINGER_NUM_MASK; 
  24. if (pointNum == 0 || pointNum > MAX_SUPPORT_POINT) { 
  25. HDF_LOGE("%s: pointNum is invalid, %u", __func__, pointNum); 
  26.  (void)ChipCleanBuffer(i2cClient); 
  27. OsalMutexUnlock(&device->driver->mutex); 
  28. return HDF_FAILURE; 
  29. frame->realPointNum = pointNum; 
  30. frame->definedEvent = TOUCH_DOWN; 
  31. (void)InputI2cRead(i2cClient, reg, GT_ADDR_LEN, buf, GT_POINT_SIZE * pointNum); 
  32.  
  33. ParsePointData(device, frame, buf, pointNum); 
  34. ... 
  35.  
  36. static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, uint8_t pointNum) 
  37.     ... 
  38.  
  39. for (i = 0; i < pointNum; i++) { 
  40. frame->fingers[i].trackId = buf[GT_POINT_SIZE * i + GT_TRACK_ID]; 
  41. frame->fingers[i].y = (buf[GT_POINT_SIZE * i + GT_X_LOW] & ONE_BYTE_MASK) | ((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET); 
  42.         frame->fingers[i].x = (buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) | ((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET); 
  43.  
  44.   HDF_LOGD("%s: x = %d, y = %d", __func__, frame->fingers[i].x, 
  45. frame->fingers[i].y); 

器件层驱动初始化及注册驱动至HDF框架

示例代码路径

  1. ./drivers/framework/model/input/driver/touchscreen/touch_gt911.c 
  2. static int32_t HdfGoodixChipInit(struct HdfDeviceObject *device) 
  3.     ... 
  4.  
  5.     chipCfg = ChipConfigInstance(device); 
  6.     ... 
  7.  
  8.     chipDev = ChipDeviceInstance(); 
  9.     ... 
  10.      
  11.     chipDev->chipCfg = chipCfg; 
  12.     chipDev->ops = &g_gt911ChipOps; 
  13.     ... 
  14.      
  15.     RegisterChipDevice(chipDev); 
  16.     ... 
  17. struct HdfDriverEntry g_touchGoodixChipEntry = { 
  18. .moduleVersion = 1, 
  19.  
  20. .moduleName = "HDF_TOUCH_GT911",    
  21. .Init = HdfGoodixChipInit,           // 器件驱动初始化函数 
  22. }; 
  23. HDF_INIT(g_touchGoodixChipEntry);      // 注册器件驱动至HDF框架 

器件私有驱动层主要实现了各器件厂商差异较大的部分,如器件休眠唤醒、数据解析以及固件升级等。

编译入口添加

编辑 Makefile 文件,添加本示例中的内容:

文件路径:

  1. ./drivers/adapter/khdf/linux/model/input/Makefile 

添加内容如下:

  1. obj-$(CONFIG_DRIVERS_HDF_TP_5P5_GT911) += \ 
  2. $(INPUT_ROOT_DIR)/touchscreen/touch_gt911.o 

其中 touch_gt911.o 为本示例中追加的内容

至此,基于 HDF 框架及 Input 模型的触摸屏驱动适配完成。

总结

本文梳理了 HDF_Input 模型工作流程,重点介绍了器件驱动适配,以 Hi3516dv300 开发板触屏为例进行了详细的代码说明,希望通过本文档您能初步掌握基于 HDF 框架的 Input 设备的开发步骤与流程。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯