• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Touchscreen
2
3
4## 概述
5
6### 功能简介
7
8Touchscreen驱动用于驱动触摸屏使其正常工作,该驱动主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定Input相关配置、下载及更新固件等操作。
9
10在HDF(Hardware Driver Foundation)[驱动管理框架](../driver/driver-hdf-development.md)的基础上,Input驱动模型通过调用OSAL接口层和Platform接口层提供的基础接口进行开发,涉及的接口包括bus通信接口、操作系统原生接口(memory、lock、thread、timer等)。由于OSAL接口和Platform接口屏蔽了芯片平台的差异,所以基于Input驱动模型实现的Touchscreen驱动可以进行跨平台、跨OS迁移,从而实现驱动的一次开发、多端部署。
11
12### 运作机制
13
14Input模型整体的框架如图1所示。Input驱动模型基于HDF驱动框架、Platform接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Device Interface)层,通过Input-HDI层对外提供硬件能力,即上层Input Service可以通过HDI接口层获取相应的驱动能力,进而操控Touchscreen等输入设备。
15
16**图1** 基于HDF驱动框架的Input驱动模型
17
18![image](figures/基于HDF驱动框架的input驱动模型.png "基于HDF驱动框架的input驱动模型")
19
20Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。器件产生的数据借助平台数据通道能力从内核传递到用户态,驱动模型通过配置文件适配不同器件及硬件平台,提高开发者对器件驱动的开发效率。如下为模型各部分的说明:
21
22- Input设备管理:为各类输入设备驱动提供Input设备的注册、注销接口,同时对Input设备列表进行统一管理。
23- Input平台驱动:指各类Input设备的公共抽象驱动(例如触摸屏的公共驱动),该部分主要负责对板级硬件进行初始化、硬件中断处理、向manager注册Input设备等。
24- Input器件驱动:指各器件厂家的差异化驱动,开发者可以通过适配平台驱动预留的差异化接口进行器件驱动开发,实现器件驱动开发量最小化。
25- Input数据通道:提供一套通用的数据上报通道,各类别的Input设备驱动均可用此通道上报Input事件。
26- Input配置解析:负责对Input设备的板级配置及器件私有配置进行解析及管理。
27
28
29## 开发指导
30
31### 场景介绍
32
33Input模块主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定Input相关配置、下载及更新固件等操作。
34
35### 接口说明
36
37#### 硬件接口
38
39Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简单分为如下三类:
40
41- 电源接口
42
43- IO控制接口
44
45- 通信接口
46
47**图2** Touchscreen器件常用管脚
48
49![image](figures/Touchscreen器件常用管脚.png "Touchscreen器件常用管脚")
50
51对于上图所示的三类接口,简要说明如下:
52
531. **电源接口**
54
55   - LDO_1P8:1.8V数字电路
56   - LDO_3P3:3.3V模拟电路
57
58     通常情况下,Touchscreen驱动IC和LCD驱动IC是相互分离的,这种情况下,Touchscreen驱动IC一般同时需要1.8V和3.3V两路供电。随着芯片的演进,业内已有将Touchscreen驱动IC和LCD驱动IC集成在一颗IC中的案例,对Touchscreen而言,只需要关注1.8V供电即可,其内部需要的3.3V电源,会在驱动IC内部从LCD的VSP电源(典型值5.5V)中分出来。
59
602. **IO控制接口**
61
62   - Reset:reset管脚,用于在系统休眠、唤醒时,由主机侧对驱动IC进行复位操作。
63   - INT:中断管脚,需要在驱动初始化时,配置为输入上拉状态。在驱动IC检测到外部触摸信号后,通过操作中断管脚来触发中断,器件驱动则会在中断处理函数中进行报点数据读取等操作。
64
653. **通信接口**
66
67   - I2C:由于Touchscreen的报点数据量相对较少,所以一般选用I2C方式传输数据。I2C的具体协议及对应操作接口,可以参考Platform接口层中的[I2C使用指南](../driver/driver-platform-i2c-des.md#概述)。
68   - SPI:在需要传递的数据不止包含报点坐标,还包含基础容值的情况下,由于需要传递的数据量较大,所以部分厂商会选用SPI通信方式。SPI的具体协议及对应操作接口,可以参考Platform接口层中的[SPI使用指南](../driver/driver-platform-spi-des.md#概述)。
69
70#### 软件接口
71
72Input HDF驱动提供给系统服务Input Service调用的HDI驱动能力接口,按照业务范围可以分为三大模块:Input设备管理模块、Input数据上报模块、Input业务控制模块,具体的接口如下表所示,包括:输入设备打开及关闭接口、注册设备监听的回调接口、设备信息查询接口、电源状态控制接口等。
73
74- input_manager.h
75
76  | 接口名称                                                                               | 功能描述           |
77  | ------------------------------------------------------------------------------------- | -------------------|
78  | int32_t (*OpenInputDevice)(uint32_t devIndex);                                        | 打开Input设备       |
79  | int32_t (*CloseInputDevice)(uint32_t devIndex);                                       | 关闭Input设备       |
80  | int32_t (*GetInputDevice)(uint32_t devIndex, DeviceInfo **devInfo);                   | 获取指定ID的设备信息 |
81  | int32_t (*GetInputDeviceList)(uint32_t *devNum, DeviceInfo **devList, uint32_t size); | 获取所有设备列表信息 |
82
83- input_reporter.h
84
85  | 接口名称                                                                             | 功能描述            |
86  | ----------------------------------------------------------------------------------- | ------------------ |
87  | int32_t (*RegisterReportCallback)(uint32_t devIndex, InputReportEventCb *callback); | 注册Input设备的回调 |
88  | int32_t (*UnregisterReportCallback)(uint32_t devIndex);                             | 注销Input设备的回调 |
89  | void (*ReportEventPkgCallback)(const EventPackage **pkgs, uint32_t count);          | 上报数据的回调函数   |
90
91- input_controller.h
92
93  | 接口名称                                                                                             | 功能描述       |
94  | --------------------------------------------------------------------------------------------------- |--------------- |
95  | int32_t (*SetPowerStatus)(uint32_t devIndex, uint32_t status);                                      | 设置电源状态    |
96  | int32_t (*GetPowerStatus)(uint32_t devIndex, uint32_t *status);                                     | 获取电源状态    |
97  | int32_t (*GetDeviceType)(uint32_t devIndex, uint32_t *deviceType);                                  | 获取设备类型    |
98  | int32_t (*GetChipInfo)(uint32_t devIndex, char *chipInfo, uint32_t length);                         | 获取器件编码信息 |
99  | int32_t (*GetVendorName)(uint32_t devIndex, char *vendorName, uint32_t length);                     | 获取模组厂商名   |
100  | int32_t (*GetChipName)(uint32_t devIndex, char *chipName, uint32_t length);                         | 获取芯片厂商名   |
101  | int32_t (*SetGestureMode)(uint32_t devIndex, uint32_t gestureMode);                                 | 设置手势模式     |
102  | int32_t (*RunCapacitanceTest)(uint32_t devIndex, uint32_t testType, char *result, uint32_t length); | 执行容值自检测试 |
103  | int32_t (*RunExtraCommand)(uint32_t devIndex, InputExtraCmd *cmd);                                  | 执行拓展指令     |
104
105更多接口请参考[Input驱动仓](https://gitee.com/openharmony/drivers_peripheral/tree/master/input)106
107### 开发步骤
108
109以Touchscreen器件驱动为例,Input驱动模型的完整加载流程可以分为六步:
110
1111. 设备描述配置:由开发者参考已有模板进行设备描述配置,配置的信息包括驱动加载顺序、板级硬件信息、器件私有数据信息等。
112
1132. 加载Input设备管理驱动:由HDF驱动加载Input设备管理驱动,完成设备manager的创建并对其初始化。
114
1153. 加载平台驱动:平台驱动由HDF框架加载,主要完成板级配置解析及硬件初始化,并提供器件注册接口。
116
1174. 加载器件驱动:器件驱动也由HDF框架加载,完成器件设备的实例化,包括器件私有配置解析和平台预留的差异化接口适配。
118
1195. 器件设备向平台驱动注册:将实例化的器件设备注册到平台驱动,实现设备和驱动的绑定,并完成中断注册、上下电等器件初始化工作。
120
1216. Input设备注册:在器件初始化完成后,实例化Input设备,并将其注册到Input manager进行管理。
122
123
124根据Input驱动模型的加载流程可知,Touchscreen器件驱动的开发过程主要包含以下三个步骤:
125
1261. 设备描述配置:目前Input驱动基于HDF驱动框架编写,驱动的加载启动由HDF驱动管理框架统一处理。首先需要在对应的配置文件中,将驱动信息注册进去,如是否加载、加载优先级,此后HDF驱动框架会逐一启动注册过的驱动模块。驱动的相关配置请参考[HDF驱动框架配置指导](../driver/driver-hdf-development.md#驱动开发步骤)。
127
1282. 板级配置及Touchscreen器件私有配置:配置对应的IO管脚功能,例如对单板上为Touchscreen设计预留的I2C Pin脚,需设置对应的寄存器,使其选择I2C的通信功能。
129
1303. 实现器件差异化适配接口:根据硬件单板设计的通信接口,使用Platform接口层提供的管脚操作接口配置对应的复位管脚、中断管脚以及电源操作,对于GPIO的操作,可参考[GPIO操作接口指导](../driver/driver-platform-gpio-des.md#概述)。
131
132
133### 开发实例
134
135下面以RK3568开发板的Input模块为例,说明Touchscreen器件的适配和接口使用方法。
136
1371. 设备描述配置
138
139   如下配置主要包含Input驱动模型各模块层级信息,配置文件路径为drivers/adapter/khdf/linux/hcs/device_info/device_info.hcs。具体原理可参考[HDF驱动开发指南](../driver/driver-hdf-development.md),HDF框架依据该配置信息实现对Input模型各模块的依次加载等。
140
141   ```c
142   input :: host {
143       hostName = "input_host";
144       priority = 100;
145       device_input_manager :: device {
146           device0 :: deviceNode {
147               policy = 2;        // 向外发布服务
148               priority = 100;    // 加载优先级,在input模块内,manager模块优先级应为最高
149               preload = 0;       // 加载该驱动,0:加载;1:不加载
150               permission = 0660;
151               moduleName = "HDF_INPUT_MANAGER";
152               serviceName = "input_dev_manager";
153               deviceMatchAttr = "";
154           }
155       }
156       device_hdf_touch :: device {
157           device0 :: deviceNode {
158               policy = 2;
159               priority = 120;
160               preload = 0;
161               permission = 0660;
162               moduleName = "HDF_TOUCH";
163               serviceName = "event1";
164               deviceMatchAttr = "touch_device1";
165           }
166       }
167
168       device_touch_chip :: device {
169           device0 :: deviceNode {
170               policy = 0;
171               priority = 130;
172               preload = 0;
173               permission = 0660;
174               moduleName = "HDF_TOUCH_SAMPLE";
175               serviceName = "hdf_touch_sample_service";
176               deviceMatchAttr = "zsj_sample_5p5";
177           }
178       }
179   }
180   ```
181
1822. 板级配置及器件私有配置
183
184   如下配置包含板级硬件配置及器件私有数据配置,配置文件路径为drivers/adapter/khdf/linux/hcs/input/input_config.hcs。实际业务开发时,可根据具体需求增删及修改如下配置文件信息。
185
186   ```c
187   root {
188       input_config {
189           touchConfig {
190               touch0 {
191                   boardConfig {
192                       match_attr = "touch_device1";
193                       inputAttr {
194                           inputType = 0;           // 0代表触摸屏
195                           solutionX = 480;
196                           solutionY = 960;
197                           devName = "main_touch";  // 设备名称
198                       }
199                       busConfig {
200                           busType = 0;             // 0代表I2C
201                           busNum = 6;
202                           clkGpio = 86;
203                           dataGpio = 87;
204                           i2cClkIomux = [0x114f0048, 0x403];  // i2c_clk对应pin的寄存器配置
205                           i2cDataIomux = [0x114f004c, 0x403]; // i2c_data对应pin的寄存器配置
206                       }
207                       pinConfig {
208                           rstGpio = 3;
209                           intGpio = 4;
210                           rstRegCfg = [0x112f0094, 0x400];  // reset对应pin的寄存器配置
211                           intRegCfg = [0x112f0098, 0x400];  // interrupt对应pin的寄存器配置
212                       }
213                       powerConfig {
214                           vccType = 2;       // 1代表LDO、2代表GPIO、3代表PMIC
215                           vccNum = 20;       // GPIO号为20
216                           vccValue = 1800;   // 电压幅值为1800mV
217                           vciType = 1;
218                           vciNum = 12;
219                           vciValue = 3300;
220                       }
221                       featureConfig {
222                           capacitanceTest = 0;
223                           gestureMode = 0;
224                           gloverMOde = 0;
225                           coverMode = 0;
226                           chargerMode = 0;
227                           knuckleMode = 0;
228                       }
229                   }
230                   chipConfig {
231                       template touchChip {
232                           match_attr = "";
233                           chipName = "sample";
234                           vendorName = "zsj";
235                           chipInfo = "AAAA11222";  // 1~4字符代表产品名,5~6字符代表IC型号,7~9字符代表模型型号
236                           busType = 0;
237                           deviceAddr = 0x5D;
238                           irqFlag = 2;             // 1代表上升沿触发,2代表下降沿触发,4代表高电平触发,8代表低电平触发
239                           maxSpeed = 400;
240                           chipVersion = 0;
241                           powerSequence {
242                               /* 上电时序的配置含义说明:
243                                 [类型, 状态, 方向 , 延时]
244                                 <type> 0代表空,1代表vcc电源(1.8V),2代表VCI电源(3.3V),3代表复位管脚,4代表中断管脚
245                                 <status> 0代表下电或拉低,1代表上电或拉高,2代表无操作
246                                 <dir> 0代表输入方向,1代表输出方向,2代表无操作
247                                 <delay> 代表延时多少毫秒, 例如20代表延时20ms
248                               */
249                               powerOnSeq = [4, 0, 1, 0,
250                                           3, 0, 1, 10,
251                                           3, 1, 2, 60,
252                                           4, 2, 0, 0];
253                               suspendSeq = [3, 0, 2, 10];
254                               resumeSeq = [3, 1, 2, 10];
255                               powerOffSeq = [3, 0, 2, 10,
256                                             1, 0, 2, 20];
257                           }
258                       }
259                       chip0 :: touchChip {
260                           match_attr = "zsj_sample_5p5";
261                           chipInfo = "ZIDN45100";
262                           chipVersion = 0;
263                       }
264                   }
265               }
266           }
267       }
268   }
269   ```
270
2713. 添加器件驱动
272
273   在器件驱动中,主要实现了平台预留的差异化接口,以器件数据获取及解析进行示例说明,代码路径为drivers/framework/model/input/driver/touchscreen/touch_gt911.c。具体开发过程,需要根据实际使用的单板及器件进行适配。
274
275   ```c
276   /* 将从器件中读取到的报点数据解析为坐标 */
277   static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, uint8_t pointNum)
278   {
279       int32_t resX = device->driver->boardCfg->attr.resolutionX;
280       int32_t resY = device->driver->boardCfg->attr.resolutionY;
281
282       for (int32_t i = 0; i < pointNum; i++) {
283           frame->fingers[i].y = (buf[GT_POINT_SIZE * i + GT_X_LOW] & ONE_BYTE_MASK) |
284                                 ((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);
285           frame->fingers[i].x = (buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) |
286                                 ((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);
287           frame->fingers[i].valid = true;
288       }
289   }
290   /* 从器件中获取报点数据 */
291   static int32_t ChipDataHandle(ChipDevice *device)
292   {
293       int32_t ret;
294       uint8_t touchStatus = 0;
295       uint8_t pointNum;
296       uint8_t buf[GT_POINT_SIZE * MAX_SUPPORT_POINT] = {0};
297       InputI2cClient *i2cClient = &device->driver->i2cClient;
298       uint8_t reg[GT_ADDR_LEN] = {0};
299       FrameData *frame = &device->driver->frameData;
300       reg[0] = (GT_BUF_STATE_ADDR >> ONE_BYTE_OFFSET) & ONE_BYTE_MASK;
301       reg[1] = GT_BUF_STATE_ADDR & ONE_BYTE_MASK;
302       ret = InputI2cRead(i2cClient, reg, GT_ADDR_LEN, &touchStatus, 1);
303       if (ret < 0 || touchStatus == GT_EVENT_INVALID) {
304           return HDF_FAILURE;
305       }
306       OsalMutexLock(&device->driver->mutex);
307       (void)memset_s(frame, sizeof(FrameData), 0, sizeof(FrameData));
308       if (touchStatus == GT_EVENT_UP) {
309           frame->realPointNum = 0;
310           frame->definedEvent = TOUCH_UP;
311           goto exit;
312       }
313       reg[0] = (GT_X_LOW_BYTE_BASE >> ONE_BYTE_OFFSET) & ONE_BYTE_MASK;
314       reg[1] = GT_X_LOW_BYTE_BASE & ONE_BYTE_MASK;
315       pointNum = touchStatus & GT_FINGER_NUM_MASK;
316       if (pointNum <= 0 || pointNum > MAX_SUPPORT_POINT) {
317           HDF_LOGE("%s: pointNum is invalid, %d", __func__, pointNum);
318           (void)ChipCleanBuffer(i2cClient);
319           OsalMutexUnlock(&device->driver->mutex);
320           return HDF_FAILURE;
321       }
322       frame->realPointNum = pointNum;
323       frame->definedEvent = TOUCH_DOWN;
324       /* 从寄存器中读取报点值 */
325       (void)InputI2cRead(i2cClient, reg, GT_ADDR_LEN, buf, GT_POINT_SIZE * pointNum);
326       /* 解析报点值 */
327       ParsePointData(device, frame, buf, pointNum);
328   exit:
329       OsalMutexUnlock(&device->driver->mutex);
330       if (ChipCleanBuffer(i2cClient) != HDF_SUCCESS) {
331           return HDF_FAILURE;
332       }
333       return HDF_SUCCESS;
334   }
335
336   static struct TouchChipOps g_sampleChipOps = {
337       .Init = ChipInit,
338       .Detect = ChipDetect,
339       .Resume = ChipResume,
340       .Suspend = ChipSuspend,
341       .DataHandle = ChipDataHandle,
342   };
343
344   static TouchChipCfg *ChipConfigInstance(struct HdfDeviceObject *device)
345   {
346       TouchChipCfg *chipCfg = (TouchChipCfg *)OsalMemAlloc(sizeof(TouchChipCfg));
347       if (chipCfg == NULL) {
348           HDF_LOGE("%s: instance chip config failed", __func__);
349           return NULL;
350       }
351       (void)memset_s(chipCfg, sizeof(TouchChipCfg), 0, sizeof(TouchChipCfg));
352       /* 解析器件私有配置 */
353       if (ParseTouchChipConfig(device->property, chipCfg) != HDF_SUCCESS) {
354           HDF_LOGE("%s: parse chip config failed", __func__);
355           OsalMemFree(chipCfg);
356           chipCfg = NULL;
357       }
358       return chipCfg;
359   }
360
361   static ChipDevice *ChipDeviceInstance(void)
362   {
363       ChipDevice *chipDev = (ChipDevice *)OsalMemAlloc(sizeof(ChipDevice));
364       if (chipDev == NULL) {
365           HDF_LOGE("%s: instance chip device failed", __func__);
366           return NULL;
367       }
368       (void)memset_s(chipDev, sizeof(ChipDevice), 0, sizeof(ChipDevice));
369       return chipDev;
370   }
371
372   static void FreeChipConfig(TouchChipCfg *config)
373   {
374       if (config->pwrSeq.pwrOn.buf != NULL) {
375           OsalMemFree(config->pwrSeq.pwrOn.buf);
376       }
377       if (config->pwrSeq.pwrOff.buf != NULL) {
378           OsalMemFree(config->pwrSeq.pwrOff.buf);
379       }
380       OsalMemFree(config);
381   }
382
383   static int32_t HdfSampleChipInit(struct HdfDeviceObject *device)
384   {
385       TouchChipCfg *chipCfg = NULL;
386       ChipDevice *chipDev = NULL;
387       HDF_LOGE("%s: enter", __func__);
388       if (device == NULL) {
389           return HDF_ERR_INVALID_PARAM;
390       }
391       /* 器件私有配置解析 */
392       chipCfg = ChipConfigInstance(device);
393       if (chipCfg == NULL) {
394           return HDF_ERR_MALLOC_FAIL;
395       }
396       /* 器件设备实例化 */
397       chipDev = ChipDeviceInstance();
398       if (chipDev == NULL) {
399           goto freeCfg;
400       }
401       chipDev->chipCfg = chipCfg;
402       chipDev->ops = &g_sampleChipOps;
403       chipDev->chipName = chipCfg->chipName;
404       chipDev->vendorName = chipCfg->vendorName;
405
406     /* 器件设备注册到平台驱动 */
407       if (RegisterChipDevice(chipDev) != HDF_SUCCESS) {
408           goto freeDev;
409       }
410       HDF_LOGI("%s: exit succ, chipName = %s", __func__, chipCfg->chipName);
411       return HDF_SUCCESS;
412
413   freeDev:
414       OsalMemFree(chipDev);
415   freeCfg:
416       FreeChipConfig(chipCfg);
417       return HDF_FAILURE;
418   }
419
420   struct HdfDriverEntry g_touchSampleChipEntry = {
421       .moduleVersion = 1,
422       .moduleName = "HDF_TOUCH_SAMPLE",
423       .Init = HdfSampleChipInit,
424   };
425
426   HDF_INIT(g_touchSampleChipEntry);
427   ```
428
4294. 调用Input HDI接口
430
431   下面通过示例代码说明上层输入系统服务调用Input HDI的步骤。
432
433   ```c
434   #include "input_manager.h"
435   #define DEV_INDEX 1
436
437   IInputInterface *g_inputInterface;
438   InputReportEventCb g_callback;
439
440   /* 定义数据上报的回调函数 */
441   static void ReportEventPkgCallback(const EventPackage **pkgs, uint32_t count)
442   {
443       if (pkgs == NULL || count > MAX_PKG_NUM) {
444           return;
445       }
446       for (uint32_t i = 0; i < count; i++) {
447           HDF_LOGI("%s: pkgs[%d] = 0x%x, 0x%x, %d", __func__, i, pkgs[i]->type, pkgs[i]->code, pkgs[i]->value);
448       }
449   }
450
451   int InputServiceSample(void)
452   {
453       uint32_t devType = INIT_DEFAULT_VALUE;
454
455       /* 获取Input驱动能力接口 */
456       int ret = GetInputInterface(&g_inputInterface);
457       if (ret != INPUT_SUCCESS) {
458           HDF_LOGE("%s: get input interfaces failed, ret = %d", __func__, ret);
459           return ret;
460       }
461
462       INPUT_CHECK_NULL_POINTER(g_inputInterface, INPUT_NULL_PTR);
463       INPUT_CHECK_NULL_POINTER(g_inputInterface->iInputManager, INPUT_NULL_PTR);
464       /* 打开特定的Input设备 */
465       ret = g_inputInterface->iInputManager->OpenInputDevice(DEV_INDEX);
466       if (ret) {
467           HDF_LOGE("%s: open input device failed, ret = %d", __func__, ret);
468         return ret;
469       }
470
471       INPUT_CHECK_NULL_POINTER(g_inputInterface->iInputController, INPUT_NULL_PTR);
472       /* 获取对应Input设备的类型 */
473       ret = g_inputInterface->iInputController->GetDeviceType(DEV_INDEX, &devType);
474       if (ret) {
475           HDF_LOGE("%s: get device type failed, ret: %d", __FUNCTION__, ret);
476           return ret;
477       }
478       HDF_LOGI("%s: device1's type is %u\n", __FUNCTION__, devType);
479
480       /* 给特定的Input设备注册数据上报回调函数 */
481       g_callback.ReportEventPkgCallback = ReportEventPkgCallback;
482       INPUT_CHECK_NULL_POINTER(g_inputInterface->iInputReporter, INPUT_NULL_PTR);
483       ret  = g_inputInterface->iInputReporter->RegisterReportCallback(DEV_INDEX, &g_callback);
484       if (ret) {
485           HDF_LOGE("%s: register callback failed, ret: %d", __FUNCTION__, ret);
486         return ret;
487       }
488       HDF_LOGI("%s: wait 10s for testing, pls touch the panel now", __FUNCTION__);
489       OsalMSleep(KEEP_ALIVE_TIME_MS);
490
491       /* 注销特定Input设备上的回调函数 */
492       ret = g_inputInterface->iInputReporter->UnregisterReportCallback(DEV_INDEX);
493       if (ret) {
494           HDF_LOGE("%s: unregister callback failed, ret: %d", __FUNCTION__, ret);
495           return ret;
496       }
497
498       /* 关闭特定的Input设备 */
499       ret = g_inputInterface->iInputManager->CloseInputDevice(DEV_INDEX);
500       if (ret) {
501           HDF_LOGE("%s: close device failed, ret: %d", __FUNCTION__, ret);
502         return ret;
503       }
504       return 0;
505   }
506   ```
507