Touchscreen开发实例

本实例提供Touchscreen驱动开发示例,并简要对具体关键点进行开发说明。

加载驱动

基于HDF驱动模型,加载启动Touchscreen驱动,代码形式如下,具体原理可参考HDF驱动开发指南


1. /* 根据实际需求,实现TouchDispatch */
2. int32_t TouchDispatch(struct HdfDeviceObject *device, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
3. {
4. (void)device;
5. (void)cmd;
6. if (data == NULL || reply == NULL) {
7. HDF_LOGE("%s: param is null", __func__);
8. return HDF_FAILURE;
9. }
10. return HDF_SUCCESS;
11. }

13. /* 根据业务实际需求,实现TouchEntryOpen */
14. int32_t Gt911TouchDriverOpen(struct HdfDeviceObject *object)
15. {
16. if (object == NULL) {
17. HDF_LOGE("%s: param is null", __func__);
18. return HDF_ERR_INVALID_PARAM;
19. }
20. static struct IRemoteService service = {
21. .object = {0},
22. .Dispatch = TouchDispatch,
23. };
24. object->service = &service;
25. return HDF_SUCCESS;
26. }

28. /* Touch驱动的总入口Init函数 */
29. int Gt911TouchDriverInit(struct HdfDeviceObject *object)
30. {
31. /* 具体实现参考下面“执行初始化”示例代码 */
32. return HDF_SUCCESS;
33. }
34. /* HDF驱动入口数据结构 */
35. struct HdfDriverEntry g_gt5p5TouchDevEntry = {
36. .moduleVersion = 1,
37. .moduleName = "HDF_TOUCHSCREEN",
38. .Bind = Gt911TouchDriverOpen,
39. .Init = Gt911TouchDriverInit,
40. };

42. HDF_INIT(g_gt5p5TouchDevEntry);

执行初始化

如下初始化流程包含常用的步骤,实际业务开发时,可根据具体需求增删及修改如下初始化中的相关步骤,具体示例如下。


1. int TouchEntryInit(struct HdfDeviceObject *object)
2. {
3. (void)object;
4. /* 创建全局数据结构体,用于存储器件驱动相关信息 */
5. g_coreData = (TouchCoreData *)OsalMemAlloc(sizeof(TouchCoreData));
6. if (g_coreData == NULL) {
7. HDF_LOGE("%s: malloc failed", __func__);
8. return HDF_ERR_MALLOC_FAIL;
9. }

11. if (memset_s(g_coreData, sizeof(TouchCoreData), 0, sizeof(TouchCoreData)) != EOK) {
12. HDF_LOGE("%s: memset_s fail", __func__);
13. return;
14. }
15. /* 初始化全局数据结构体,将器件驱动相关的配置信息,进行解析赋值 */
16. TouchConfigInit(g_coreData);
17. /* 设置GPIO相关的属性及状态 */
18. if (TouchSetupGpio(g_coreData)) {
19. goto ERR_EXIT;
20. }
21. /* 设置并获取I2C BUS操作句柄 */
22. if (TouchSetupI2c(g_coreData)) {
23. goto ERR_EXIT;
24. }
25. /* 创建Task用于监听处理中断业务 */
26. if (TouchIrqTaskInit(g_coreData)) {
27. goto ERR_EXIT;
28. }
29. /* 进行电源初始化配置及操作 */
30. if (TouchPowerInit(g_coreData)) {
31. goto ERR_EXIT;
32. }
33. /* 创建input设备文件 */
34. (void)mkdir("/dev/input", DEFAULT_DIR_MODE);
35. if (register_driver(TOUCH_DEVICE, &g_touchDevOps, TOUCH_DEVICE_MODE, NULL)) {
36. HDF_LOGE("%s: register touch dev failed", __func__);
37. goto ERR_EXIT;
38. }
39. HDF_LOGE("%s: exit succ", __func__);
40. return HDF_SUCCESS;

42. ERR_EXIT:
43. if (g_coreData->i2cClient.i2cHandle != NULL) {
44. DeviceHandleDestroy(g_coreData->i2cClient.i2cHandle);
45. g_coreData->i2cClient.i2cHandle = NULL;
46. }
47. OsalMemFree(g_coreData);
48. g_coreData = NULL;
49. return HDF_FAILURE;
50. }

配置基础参数

如下示例中,主要配置了i2c的从地址及总线号、屏幕的报点范围、input设备类型、GPIO管脚号等。具体开发过程,需要根据实际使用的单板及器件进行配置,以下为示例。


1. static void TouchConfigInit(TouchCoreData *cd)
2. {
3. /* init waitqueue for poll */
4. __init_waitqueue_head(&cd->pollWait);

6. /* 配置i2c从地址、总线号、报点范围 */
7. cd->i2cClient.i2cCfg.addr = DRIVER_CHIP_I2C_ADDR;
8. cd->i2cClient.i2cCfg.busNum = I2C_BUS_NUM;
9. cd->inputCfg.solutionX = TOUCH_SOLUTION_X;
10. cd->inputCfg.solutionY = TOUCH_SOLUTION_Y;

12. /* 配置input设备类型,本例为Touch驱动 */
13. cd->inputDevType = INDEV_TYPE_TOUCH;

15. /* 配置reset、irq的gpio号,以及irq的中断触发方式 */
16. cd->rstGpioNum = RST_GPIO_OFFSET;
17. cd->intGpioNum = INT_GPIO_OFFSET;
18. cd->irqFlag = OSAL_IRQF_TRIGGER_FALLING;
19. }

配置及使用IO管脚

如下为reset和irq管脚的初始化配置,统一使用PAL接口实现对GPIO的操作,具体可参考PLATFORM提供的GPIO接口使用指导


1. static int TouchSetupGpio(TouchCoreData *cd)
2. {
3. /* 配置int为输入上拉 */
4. writel(INT_REG_CFG, IO_DEVICE_ADDR(INR_REG_ADDR));
5. /* 设置int为输入方向 */
6. int ret = GpioSetDir(cd->intGpioNum, GPIO_DIR_IN);
7. if (ret != HDF_SUCCESS) {
8. HDF_LOGE("set int to input dir failed, ret %d", ret);
9. return HDF_FAILURE;
10. }
11. /* 设置reset为输出方向 */
12. ret = GpioSetDir(cd->rstGpioNum, GPIO_DIR_OUT);
13. if (ret != HDF_SUCCESS) {
14. HDF_LOGE("set reset to output dir failed, ret %d", ret);
15. return HDF_FAILURE;
16. }
17. /* 拉高reset */
18. ret = GpioWrite(cd->rstGpioNum, GPIO_VAL_HIGH);
19. if (ret != HDF_SUCCESS) {
20. HDF_LOGE("pull up reset gpio failed, ret %d", ret);
21. return HDF_FAILURE;
22. }
23. OsalMSleep(RESET_HIGH_DELAY);
24. /* 拉低reset */
25. ret = GpioWrite(cd->rstGpioNum, GPIO_VAL_LOW);
26. if (ret != HDF_SUCCESS) {
27. HDF_LOGE("pull down reset gpio failed, ret %d", ret);
28. return HDF_FAILURE;
29. }
30. OsalMSleep(RESET_LOW_DELAY);
31. /* 再次拉高reset */
32. ret = GpioWrite(cd->rstGpioNum, GPIO_VAL_HIGH);
33. if (ret != HDF_SUCCESS) {
34. HDF_LOGE("pull up reset gpio again failed, ret %d", ret);
35. return HDF_FAILURE;
36. }
37. OsalMSleep(RESET_HIGH_DELAY);
38. HDF_LOGI("%s: succ\n", __func__);
39. return HDF_SUCCESS;
40. }

配置I2C的IO管脚复用,以及其操作句柄的获取,可参考PLATFORM提供的I2C接口使用指导


1. static int TouchSetupI2c(TouchCoreData *cd)
2. {
3. /* config I2C reuse I2C7 */
4. writel(I2C_REG_CFG, IO_DEVICE_ADDR(I2C7_DATA_REG_ADDR));
5. writel(I2C_REG_CFG, IO_DEVICE_ADDR(I2C7_CLK_REG_ADDR));
6. /* get i2c handle */
7. cd->i2cClient.i2cHandle = I2cOpen(cd->i2cClient.i2cCfg.busNum);
8. if (cd->i2cClient.i2cHandle == NULL) {
9. HDF_LOGE("open i2c failed");
10. return HDF_FAILURE;
11. }
12. HDF_LOGI("%s: exit succ", __func__);
13. return HDF_SUCCESS;
14. }

创建中断处理TASK

创建用于获取及处理报点数据的Task


1. static int TouchIrqTaskInit(TouchCoreData *cd)
2. {
3. /* 初始化消息事件 */
4. int ret = LOS_EventInit(&g_touchEventIrq);
5. if (ret != HDF_SUCCESS) {
6. HDF_LOGE("LOS_EventInit failed, ret = %d", ret);
7. return HDF_FAILURE;
8. }

10. /* 注册中断 */
11. ret = GpioSetIrq(cd->intGpioNum, cd->irqFlag, IrqHandle, cd);
12. if (ret != 0) {
13. HDF_LOGE("register irq failed, ret %d", ret);
14. return ret;
15. }
16. /* 使能中断 */
17. ret = GpioEnableIrq(cd->intGpioNum);
18. if (ret != HDF_SUCCESS) {
19. HDF_LOGE("enable irq failed, ret %d", ret);
20. return HDF_FAILURE;
21. }
22. /* 创建中断处理Task,其负责input event数据的读取和解析 */
23. TSK_INIT_PARAM_S handleEventTask = {0};
24. UINT32 handleEventTaskID;
25. handleEventTask.pfnTaskEntry = (TSK_ENTRY_FUNC)TouchHandleEvent;
26. handleEventTask.uwStackSize  = TASK_SIZE;
27. handleEventTask.pcName       = "HdfTouchEventHandler";
28. handleEventTask.usTaskPrio   = TASK_PRIO_LEVEL_TWO;
29. handleEventTask.uwResved     = LOS_TASK_STATUS_DETACHED;
30. if (LOS_TaskCreate(&handleEventTaskID, &handleEventTask) != HDF_SUCCESS) {
31. HDF_LOGE("%s: LOS_TaskCreate fail, HdfTouchEventHandler", __func__);
32. return HDF_FAILURE;
33. }
34. HDF_LOGI("%s: exit succ", __func__);
35. return HDF_SUCCESS;
36. }

中断响应函数


1. int32_t IrqHandle(uint16_t irqGpio, void *data)
2. {
3. HDF_LOGD("%s: irq is triggered, irqGpio = %d", __func__, irqGpio);
4. (void)data;
5. /* 关闭中断响应 */
6. int ret = GpioDisableIrq(irqGpio);
7. if (ret != HDF_SUCCESS) {
8. HDF_LOGE("disable irq failed, ret %d", ret);
9. }
10. (void)LOS_EventWrite(&g_touchEventIrq, EVENT_SYNC);
11. return HDF_SUCCESS;
12. }

Task处理函数


1. static void TouchHandleEvent(void)
2. {
3. InputEventData event;
4. TouchCoreData *cd = GetCoreData();
5. (void)memset_s(&event, sizeof(InputEventData), 0, sizeof(InputEventData));

7. while (true) {
8. /* 读取同步事件 */
9. int ret = LOS_EventRead(&g_touchEventIrq, EVENT_SYNC, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
10. if (ret != EVENT_SYNC) {
11. OsalMSleep(TASK_SLEEP_MS);
12. } else {
13. /* 报点事件的读取及解析 */
14. if (EventHandler(cd, &event) == HDF_SUCCESS) {
15. TouchWakeupPoll();
16. }
17. }
18. /* 使能中断 */
19. ret = GpioEnableIrq(cd->intGpioNum);
20. if (ret != HDF_SUCCESS) {
21. HDF_LOGE("enable irq failed, ret %d", ret);
22. }

24. if (cd->shouldStop) {
25. HDF_LOGE("%s: the event task should be stoped", __func__);
26. break;
27. }
28. }
29. }

创建及操作设备文件

设备文件的创建及其操作接口,本处仅举例Ioctl的使用


1. /* 创建设备文件 */
2. register_driver(TOUCH_DEVICE, &g_touchDevOps, TOUCH_DEVICE_MODE, NULL);

4. /* 文件操作ops */
5. static const struct file_operations_vfs g_touchDevOps = {
6. .open = TouchOpen,
7. .close = TouchClose,
8. .read = NULL,
9. .write = NULL,
10. .seek = NULL,
11. .ioctl = TouchIoctl,
12. .mmap = NULL,
13. #ifndef CONFIG_DISABLE_POLL
14. .poll = TouchPoll,
15. #endif
16. .unlink = NULL,
17. };

19. /* Ioctl的操作方式 */
20. static int TouchIoctl(FAR struct file *filep, int cmd, unsigned long arg)
21. {
22. int ret;
23. if (filep == NULL) {
24. HDF_LOGE("%s: param is null", __func__);
25. return HDF_ERR_INVALID_PARAM;
26. }
27. switch (cmd) {
28. case INPUT_IOCTL_GET_EVENT_DATA:
29. ret = IoctlReadInputEvent(arg);
30. break;
31. case INPUT_IOCTL_GET_DEVICE_TYPE:
32. ret = IoctlGetDeviceType(arg);
33. break;
34. case INPUT_IOCTL_GET_CHIP_INFO:
35. ret = IoctlGetChipInfo(arg);
36. break;
37. default:
38. ret = 0;
39. HDF_LOGE("%s: cmd unknown, cmd = 0x%x", __func__, cmd);
40. break;
41. }
42. return ret;
43. }

主要数据结构


1. /* 触摸事件 */
2. typedef enum {
3. EVENT_DOWN,
4. EVENT_UP,
5. EVENT_CONTACT,
6. } EventType;

8. /* I2C配置信息 */
9. typedef struct {
10. unsigned short busNum;
11. unsigned short addr;
12. } I2cConfig;

14. /* I2C客户端信息 */
15. typedef struct {
16. struct DevHandle *i2cHandle;
17. I2cConfig i2cCfg;
18. } InputI2cClient;

20. /* 输入事件数据结构体 */
21. typedef struct {
22. int x;
23. int y;
24. int z;
25. int definedEvent;
26. int fingerID;
27. int pointNum;
28. struct timeval timeStamp;
29. bool moreDataFlag;
30. } InputEventData;

32. /* 器件驱动核心数据结构体 */
33. typedef struct {
34. unsigned int inputDevType;
35. wait_queue_head_t pollWait;
36. bool readFinishFlag;
37. bool shouldStop;
38. struct InputConfig inputCfg;
39. InputI2cClient i2cClient;
40. int intGpioNum;
41. int rstGpioNum;
42. unsigned int irqFlag;
43. unsigned int powerStatus;
44. char chipInfo[CHIP_INFO_LEN];
45. char vendorName[VENDOR_NAME_LEN];
46. char chipName[CHIP_NAME_LEN];
47. } TouchCoreData;