当前位置:首页>Linux>Linux 设备驱动 -- hy46xx触摸屏驱动

Linux 设备驱动 -- hy46xx触摸屏驱动

  • 2026-09-06 01:45:24
Linux 设备驱动 -- hy46xx触摸屏驱动

hy46xx Touch IC

hy46xx是HYCON科技一款触摸IC。

上电时序:

通信接口:

  • 使用IIC通信

中断方式:

  • 当INT引脚产生下降沿的时候,触摸数据就绪,这样就可以在中断中读取
  • 如果使用线程轮询方式获取触摸数据,则可以通过判断INT引脚是否为低电平来判断触摸数据是否就绪

两种实现驱动方式:

  • 按照IIC设备驱动一般框架驱动芯片获取触摸坐标,这种方式的缺点:不兼容旧的或别人的触摸相关的应用程序
  • 按照内核input输入子系统框架来实现触摸驱动

MT(Multi-touch)多点触摸协议

内核中MT协议相关文档:Documentation\input\multi-touch-protocol.rst

老旧版本的linux内核不支持MT协议,如2.x 版本 linux 内核的话可能找不到 MT 协议

MT协议数以input子系统的一部分。

凡是触摸屏驱动若是按照input子系统框架来实现触摸都要按照MT协议来

MT协议被分为两种:

  • Type A,用于触摸点不能被区分或追踪,需上报原始数据
  • Type B,用于具备硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot (也就是触摸点ID)更新某一个触摸点的信息,既然是多点触摸协议,触摸点也必须具备ID才能区分是哪个触摸点

hy46xx 便是一款支持多点触摸的的Touch IC,从手册上可得知,其最高可支持11点触摸

现今多数Touch IC都支持多点触摸,遇到的Touch IC基本都是使用I2C接口

内核定义的MT相关的事件: include\uapi\linux\input-event-codes.h

#define ABS_MT_SLOT        0x2f    /* MT slot being modified */#define ABS_MT_TOUCH_MAJOR    0x30    /* Major axis of touching ellipse */#define ABS_MT_TOUCH_MINOR    0x31    /* Minor axis (omit if circular) */#define ABS_MT_WIDTH_MAJOR    0x32    /* Major axis of approaching ellipse */#define ABS_MT_WIDTH_MINOR    0x33    /* Minor axis (omit if circular) */#define ABS_MT_ORIENTATION    0x34    /* Ellipse orientation */#define ABS_MT_POSITION_X    0x35    /* Center X touch position */#define ABS_MT_POSITION_Y    0x36    /* Center Y touch position */#define ABS_MT_TOOL_TYPE    0x37    /* Type of touching device */#define ABS_MT_BLOB_ID        0x38    /* Group a set of packets as a blob */#define ABS_MT_TRACKING_ID    0x39    /* Unique ID of initiated contact */#define ABS_MT_PRESSURE        0x3a    /* Pressure on contact area */#define ABS_MT_DISTANCE        0x3b    /* Contact hover distance */#define ABS_MT_TOOL_X        0x3c    /* Center X tool position */#define ABS_MT_TOOL_Y        0x3d    /* Center Y tool position */

常用MT事件:

  • ABS_MT_SLOT, 上报触摸点ID
  • ABS_MT_POSITION_X,上报触摸X坐标
  • ABS_MT_POSITION_Y,上报触摸Y坐标
  • ABS_MT_TRACKING_ID,对于Type B类设备,需要该事件来区分触摸点
  • ABS_MT_TOOL_TYPE 事件用于上报触摸工具类型
    • MT_TOOL_FINGER(手指)
    • MT_TOOL_PEN(笔)
    • MT_TOOL_PALM(手掌)

Type A Touch Device 上报触摸数据流程 :

1、 ABS_MT_POSITION_X x[0] ,上报触摸点0的x坐标    调用staticinlinevoidinput_report_abs(struct input_dev *dev, unsignedint code, int value)上报2 、ABS_MT_POSITION_Y y[0] ,上报触摸点0的y坐标3、 SYN_MT_REPORT , 上报该事件,用于隔离区分不同触摸点,因为Type A设备无法区分触摸点,    调用staticinlinevoidinput_mt_sync(struct input_dev *dev)来上报该事件4、 ABS_MT_POSITION_X x[1] ,上报触摸点1的x坐标5 、ABS_MT_POSITION_Y y[1] ,上报触摸点1的y坐标6、 SYN_MT_REPORT ......                       以此类推,上报所有触摸点坐标n、 SYN_REPORT , 最后结束,上报同步事件,    调用staticinlinevoidinput_sync(struct input_dev *dev)来上报staticinlinevoidinput_mt_sync(struct input_dev *dev){    input_event(dev, EV_SYN, SYN_MT_REPORT, 0);}staticinlinevoidinput_report_abs(struct input_dev *dev, unsignedint code, int value){    input_event(dev, EV_ABS, code, value);}staticinlinevoidinput_sync(struct input_dev *dev){    input_event(dev, EV_SYN, SYN_REPORT, 0);}

内核中的一个参考例子:drivers\input\touchscreen\st1232.c

staticirqreturn_tst1232_ts_irq_handler(int irq, void *dev_id){structst1232_ts_data *ts = dev_id;structst1232_ts_finger *finger = ts->finger;structinput_dev *input_dev = ts->input_dev;int count = 0;int i, ret;    ret = st1232_ts_read_data(ts);if (ret < 0)goto end;/* multi touch protocol */for (i = 0; i < MAX_FINGERS; i++) {if (!finger[i].is_valid)continue;        input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);        input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);        input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);        input_mt_sync(input_dev);        count++;    }/* SYN_MT_REPORT only if no contact */if (!count) {        input_mt_sync(input_dev);if (ts->low_latency_req.dev) {            dev_pm_qos_remove_request(&ts->low_latency_req);            ts->low_latency_req.dev = NULL;        }    } elseif (!ts->low_latency_req.dev) {/* First contact, request 100 us latency. */        dev_pm_qos_add_ancestor_request(&ts->client->dev,                        &ts->low_latency_req,                        DEV_PM_QOS_RESUME_LATENCY, 100);    }/* SYN_REPORT */    input_sync(input_dev);end:return IRQ_HANDLED;}

linux内核是一个宝库,只要熟悉框架,对于一般驱动基本都可以参考内核已有的驱动去编写驱动。

Type B Touch Device 上报触摸数据流程 :

1、 ABS_MT_SLOT 0 ,上报 ABS_MT_SLOT 事件,就是触摸点0的ID,调用input_mt_slot上报2、 ABS_MT_TRACKING_ID 45,按照Type B类型设备要求每个slot必须    关联一个TRACKING_ID完成对触摸点的添加、替换或删除,调用input_mt_report_slot_state实现3、 ABS_MT_POSITION_X x[0],上报触摸点0的x坐标, input_report_abs4、 ABS_MT_POSITION_Y y[0],上报触摸点0的y坐标, input_report_abs5、 ABS_MT_SLOT 1 ,上报触摸点1的ABS_MT_SLOT 事件6、 ABS_MT_TRACKING_ID 467、 ABS_MT_POSITION_X x[1] 8、 ABS_MT_POSITION_Y y[1] .....                      // 以此类推上报所有触摸点x、 SYN_REPORT,调用input_sync上报staticinlinevoidinput_mt_slot(struct input_dev *dev, int slot){    input_event(dev, EV_ABS, ABS_MT_SLOT, slot);}staticinlinevoidinput_report_abs(struct input_dev *dev, unsignedint code, int value){    input_event(dev, EV_ABS, code, value);}

Type B Touch Device 触摸数据移除流程 :

1、 ABS_MT_TRACKING_ID -1 ,调用input_mt_report_slot_state实现不需要手动设置值为-1,   将改函数名为active参数设置为false即可2、 SYN_REPORT boolinput_mt_report_slot_state(struct input_dev *dev,unsignedint tool_type, bool active){structinput_mt *mt = dev->mt;structinput_mt_slot *slot;int id;if (!mt)returnfalse;    slot = &mt->slots[mt->slot];    slot->frame = mt->frame;if (!active) {        input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);returnfalse;    }    id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);if (id < 0)        id = input_mt_new_trkid(mt);    input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);    input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);returntrue;}从input_mt_report_slot_state函数实现中可以看到,当active设置为false时,会调用input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1)上报ABS_MT_TRACKING_ID,值为-1

hy46xx 触摸驱动实现

1、设备树节点编写

iomuxc节点增加复位引脚的pinctrl节点:pinctrl_tsc_reset

&iomuxc {    pinctrl-names = "default";    pinctrl-0 = <&pinctrl_hog_1>;    ......    pinctrl_tsc_reset: tscresetgrp {        fsl,pins = </* used for tsc reset */            MX6UL_PAD_LCD_RESET__GPIO3_IO04        0x05        >;    };    ......}

在IO复用节点 —— iomuxc节点中增加即可,位置放在那里都没关系

iomuxc_snvs节点增加中断引脚的pinctrl节点:pinctrl_tsc_irq

&iomuxc_snvs {    pinctrl-names = "default_snvs";    ......    pinctrl_tsc_irq: tsc_irq {        fsl,pins = <            MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09        0x4001b8b0        >;    };};

最重要是在根节点下增加hy46xx触摸IC的节点:

hy46xx@0x38 {    compatible = "hy46xx,ts";     /* 设备树和驱动匹配属性 */    pinctrl-0 = <&pinctrl_tsc_reset>;    pinctrl-1 = <&pinctrl_tsc_irq>;    reg = <0x38>;                 /* i2c设备地址 */    status = "okay";/*gpio*/    reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;          irq-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;/*interrupt­*/    interrupt-parent = <&gpio5>;    interrupts = <9 IRQ_TYPE_EDGE_FALLING>;    irq-flags = <2>;        /* 1:rising  2: falling */};

设备树编译:

ares@ubuntu:~/work/ebf_linux_kernel-ebf_4.19.35_imx6ul$ cat make_dtb.sh#!/bin/shmake ARCH=arm -j4 CROSS_COMPILE=arm-linux-gnueabihf- dtbs

将设备树拷贝系统内核目录:

debian@npi:~/nfs_root/driver$ cat cp_dtb_to_linux.sh#!/bin/shsudo cp imx6ull-mmc-npi.dtb /usr/lib/linux-image-4.19.35-carp-imx6/
  • /usr/lib/linux-image-4.19.35-carp-imx6/  ,系统存放设备树的目录

重启系统设备树生效:

sudo reboot

查看设备树是否生效 :

debian@npi:~$ ls /sys/bus/i2c/devices/0-001e  0-00380-005d  0-00681-001a  1-0039  i2c-0  i2c-1

可以看到出现了I2C设备地址为0x38的设备。

2、驱动编写

头文件:

#include<linux/init.h>#include<linux/module.h>#include<linux/fs.h>#include<linux/cdev.h>#include<linux/uaccess.h>#include<linux/types.h>#include<linux/kernel.h>#include<linux/delay.h>#include<linux/ide.h>#include<linux/errno.h>#include<linux/gpio.h>#include<asm/mach/map.h>#include<linux/of.h>#include<linux/of_address.h>#include<linux/of_gpio.h>#include<asm/io.h>#include<linux/device.h>#include<linux/timer.h>#include<linux/jiffies.h>#include<linux/platform_device.h>#include<linux/of_irq.h>#include<linux/wait.h>#include<linux/sched/signal.h>#include<linux/poll.h>#include<linux/atomic.h>#include<linux/i2c.h>#include<linux/input.h>#include<linux/input/mt.h>

宏定义和数据结构:

#define HY_CHIP_ID_REG          0xA9#define HY_TP_RUN_MODE_REG        0x00        /* 0x00 工作模式  0xc0 测试模式 */#define HY_FITLTER_REG          0x8A        /* 滤波器  0-5 */#define HY_PWR_NOISE_REG        0x89        /* 电源噪声 0 off  1 on */#define HY_FW_VERSION_REG       0xA6       #define HY_LIB_VERSION_REG      0xA7    #define HY_PWR_MODE_REG         0xA5        /* 0x03 tp enter sleep  需要 reset pin 拉 low 喚醒 */#define HY_REPORT_SPEED_REG     0x88        /* 报点率设置 0x64 */#define HY_GSTID_REG             0x02           /* 当前检测到的触摸情况 */#define HY_TP1_XH_REG             0X03          /* 第一个触摸点数据地址 */#define HY_TP1_XL_REG             0X04          /* 第一个触摸点数据地址 */#define HY_TP1_YH_REG             0X05          /* 第一个触摸点数据地址 */#define HY_TP1_YL_REG             0X06          /* 第一个触摸点数据地址 */#define HY_TP2_REG                 0X09        /* 第二个触摸点数据地址 */#define HY_TP3_REG                 0X0F        /* 第三个触摸点数据地址 */#define HY_TP4_REG                 0X15        /* 第四个触摸点数据地址 */#define HY_TP5_REG                 0X1B        /* 第五个触摸点数据地址 */#define HY_MAX_SUPPORT_POINTS           5#define HY46XX_HOR_RES    1024#define HY46XX_VER_RES    600#ifndef HY_COUNTOF#define  HY_COUNTOF(a)           (sizeof(a)/sizeof(a[0]))#endif#define  DEV_NAME                   "hy46xx,ts"#define  HY46XX_DTS_COMPATIBLE       "hy46xx,ts"#define  HY46XX_DTS_IRQ_GPIO_NAME     "irq-gpios"#define  HY46XX_DTS_RST_GPIO_NAME     "reset-gpios"enumhy46xx_ts_state {    HY46XX_TS_DOWN    = 0x00,      /* 按下 */    HY46XX_TS_UP      = 0x01,        /* 弹起 */    HY46XX_TS_CONTACT = 0x02,       /* 持续性按下 */    HY46XX_TS_RESERVED = 0x03,  };structtouch_data {short x;short y;uint8_t state;uint8_t id;};structhy46xx_device {int irq; /* 中断号 */int irq_gpio;int rst_gpio;dev_t dev_no; /* 设备号 */structi2c_client *i2c;structinput_dev *inputdev;/* input 结构体 */structtouch_datats_data[HY_MAX_SUPPORT_POINTS];};staticstructhy46xx_device *hy46xx_dev;

熟悉的I2C子系统操作:

staticinthy46xx_write_regs(struct i2c_client *i2c, uint8_t reg, uint8_t *buf, uint8_t len){int ret = 0;uint8_t w_buf[300] = {0};structi2c_msgmsg;    w_buf[0] = reg;memcpy(&w_buf[1], buf, len);    msg.addr = i2c->addr;    msg.buf = w_buf;    msg.flags = 0;               /* I2C direction : write */    msg.len = len + 1;    ret = i2c_transfer(i2c->adapter, &msg, 1);if (ret < 0)return ret;elseif (ret != 1)return -EIO;return0;}staticinthy46xx_write_reg(struct i2c_client *client, uint8_t reg, uint8_t data){return hy46xx_write_regs(client, reg, &data, 1);}staticinthy46xx_read_regs(struct i2c_client *client, uint8_t reg, uint8_t *buf, uint8_t len){structi2c_msgmsgs[2];int ret;    msgs[0].flags = 0;    msgs[0].addr  = client->addr;    msgs[0].len   = 1;    msgs[0].buf   = ®    msgs[1].flags = I2C_M_RD;    msgs[1].addr  = client->addr;    msgs[1].len   = len;    msgs[1].buf   = buf;    ret = i2c_transfer(client->adapter, msgs, 2);if (ret < 0)return ret;elseif (ret != 2)return -EIO;return0;}staticinthy46xx_i2c_read_reg(struct i2c_client *client, uint8_t reg, uint8_t *data){return hy46xx_read_regs(client, reg, data, 1);}staticinthy46xx_read_touch_data(struct hy46xx_device *dev){uint8_t buf[29];uint8_t *ts;int ret;int i;    ret =  hy46xx_read_regs(dev->i2c, HY_TP1_XH_REG, buf, 29);if (ret != 0) return ret;for (i = 0; i < HY_MAX_SUPPORT_POINTS; i++)    {        ts = &buf[i * 6];        dev->ts_data[i].state = (ts[0] & 0xC0) >> 6;        dev->ts_data[i].x = ((ts[0] & 0x0f) << 8) | ts[1];        dev->ts_data[i].y = ((ts[2] & 0x0f) << 8) | ts[3];        dev->ts_data[i].id = (ts[2] & 0xf0) >> 4;                }return0;}/* 设置为坐标模式, 默认也是坐标模式 */staticinthy46xx_set_tp_run_mode(struct hy46xx_device *dev){return hy46xx_write_reg(dev->i2c, HY_TP_RUN_MODE_REG, 0x00);}staticinthy46xx_ts_reset(struct hy46xx_device *dev){if (gpio_is_valid(dev->rst_gpio))   /* 检查 IO 是否有效 */    {        gpio_set_value(dev->rst_gpio, 0);        msleep(5);        gpio_set_value(dev->rst_gpio, 1);        msleep(1000);return0;    }return-1;}

probe 和 remove函数实现:

staticinthy46xx_driver_probe(struct i2c_client *client, conststruct i2c_device_id *id){int err = 0;structdevice_node *dev_node;    hy46xx_dev = (struct hy46xx_device *)kzalloc(sizeof(struct hy46xx_device), GFP_KERNEL);if (!hy46xx_dev)    {        printk("can't kzalloc hy46xx device\n");return -ENOMEM;    }    dev_node = client->dev.of_node;if (!dev_node)    {        printk("hy46xx ts dts node err\r\n");        err = -EINVAL;goto exit_free_dev;    }    hy46xx_dev->i2c = client;    printk("hy46xx dts irq %d !\r\n", client->irq);    hy46xx_dev->irq_gpio = of_get_named_gpio(dev_node, HY46XX_DTS_IRQ_GPIO_NAME, 0);   /* 获取irq-gpios */if (!gpio_is_valid( hy46xx_dev->irq_gpio)) {        printk("don't get %s %s!\n", DEV_NAME, HY46XX_DTS_IRQ_GPIO_NAME);        err = -EINVAL;goto exit_free_dev;    }    hy46xx_dev->irq = gpio_to_irq( hy46xx_dev->irq_gpio);                              /* 通过gpio得到irq */    hy46xx_dev->rst_gpio = of_get_named_gpio(dev_node, HY46XX_DTS_RST_GPIO_NAME, 0);   /* 获取rst-gpios */if (!gpio_is_valid( hy46xx_dev->rst_gpio)) {        printk("don't get %s %s!\n", DEV_NAME, HY46XX_DTS_RST_GPIO_NAME);        err = -EINVAL;goto exit_free_dev;    }    printk("%s %d, %s %d", HY46XX_DTS_IRQ_GPIO_NAME, hy46xx_dev->irq_gpio, HY46XX_DTS_RST_GPIO_NAME, hy46xx_dev->rst_gpio);#if 0    err = request_irq(hy46xx_dev->irq, hy46xx_ts_isr, RQF_TRIGGER_FALLING, DEV_NAME, NULL);    #else/* 中断线程化 */    err = devm_request_threaded_irq(&client->dev, client->irq, NULL,                                     hy46xx_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,                                     client->name, hy46xx_dev);#endifif (err)    {        printk(KERN_INFO "failed to request irq %d\r\n", hy46xx_dev->irq);goto exit_free_dev;    }    hy46xx_dev->inputdev =  devm_input_allocate_device(&client->dev);;    /* 申请输入设备结构 */if (!hy46xx_dev->inputdev)     {        printk(KERN_ERR "%s: Failed to allocate input device.\n", __func__);        err = -ENOMEM;goto exit_free_irq;    }    hy46xx_dev->inputdev->name = DEV_NAME;    hy46xx_dev->inputdev->id.bustype = BUS_I2C;      /* 触摸屏通信总线类型 */    hy46xx_dev->inputdev->dev.parent = &client->dev;/* Single touch */    input_set_abs_params(hy46xx_dev->inputdev, ABS_X, 0, HY46XX_HOR_RES, 0, 0);    input_set_abs_params(hy46xx_dev->inputdev, ABS_Y, 0, HY46XX_VER_RES, 0, 0);    input_set_abs_params(hy46xx_dev->inputdev, ABS_MT_POSITION_X, 0, HY46XX_HOR_RES, 0, 0);    input_set_abs_params(hy46xx_dev->inputdev, ABS_MT_POSITION_Y, 0, HY46XX_VER_RES, 0, 0);    err = input_mt_init_slots(hy46xx_dev->inputdev, HY_MAX_SUPPORT_POINTS, 0);        /* 初始化触摸屏,5点触摸 */if (err) {        dev_err(&client->dev,"Failed to initialize MT slots: %d", err);goto exit_free_irq;    }    err = input_register_device(hy46xx_dev->inputdev);           /* 注册input_device */if (err)     {        printk(KERN_ERR "%s: Failed to regist key device.\n", __func__);goto exit_free_irq;    }    gpio_direction_input(hy46xx_dev->irq_gpio);    gpio_direction_output(hy46xx_dev->rst_gpio, 0);     hy46xx_ts_reset(hy46xx_dev);     /* 复位 */    hy46xx_set_tp_run_mode(hy46xx_dev);gotoexit;exit_free_irq:                                       free_irq(hy46xx_dev->irq, NULL);             /* 释放中断*/exit_free_dev:    kfree(hy46xx_dev);    hy46xx_dev = NULL;exit:return err;}staticinthy46xx_driver_remove(struct i2c_client *i2c){/* 释放中断*/    free_irq(hy46xx_dev->irq, NULL);    /* 释放内存 */    kfree(hy46xx_dev);    printk(KERN_INFO "%s success\n", DEV_NAME);return0;}

出口入口函数实现:

/* 设备树的匹配列表 */staticstructof_device_iddts_match_table[] = {    {.compatible = HY46XX_DTS_COMPATIBLE}, /* 通过设备树来匹配 */    {},};/* 传统匹配方式 ID 列表 ,即使不使用也要添加,不然probe匹配不成功 */staticconststructi2c_device_idid_table[] = {    {.name = HY46XX_DTS_COMPATIBLE, 0},    {},};staticstructi2c_driverhy46xx_driver = {    .probe = hy46xx_driver_probe,    .remove = hy46xx_driver_remove,    .driver = {        .name = HY46XX_DTS_COMPATIBLE,        .owner = THIS_MODULE,        .of_match_table = dts_match_table, /* 通过设备树匹配 */    },    .id_table = id_table,};module_i2c_driver(hy46xx_driver);

上报触摸数据的关键操作:

staticvoidhy46xx_report_events(struct hy46xx_device *dev){int i;bool touch;for (i = 0; i < HY_MAX_SUPPORT_POINTS; i++)     {        input_mt_slot(dev->inputdev, dev->ts_data[i].id);                  /* ABS_MT_SLOT事件  上报触摸ID  */if (dev->ts_data[i].state == HY46XX_TS_RESERVED) continue;                 touch = dev->ts_data[i].state != HY46XX_TS_UP;                     /* 当触摸按下touch为true,弹起时touch为false */        input_mt_report_slot_state(dev->inputdev, MT_TOOL_FINGER, touch);    /* ABS_MT_TRACKING_ID 事件 */if (touch)                                                                {            input_report_abs(dev->inputdev, ABS_MT_POSITION_X, dev->ts_data[i].x);    /* 上报触摸点的x坐标 */            input_report_abs(dev->inputdev, ABS_MT_POSITION_Y, dev->ts_data[i].y);    /* 上报触摸点的y坐标 */        }    }    input_mt_report_pointer_emulation(dev->inputdev, true);    input_sync(dev->inputdev);                                            }staticirqreturn_thy46xx_ts_isr(int irq, void *dev){structhy46xx_device *hydev = (struct hy46xx_device *)dev;/* 上报触摸点数据 */    hy46xx_read_touch_data(hydev);    hy46xx_report_events(hydev);return IRQ_RETVAL(IRQ_HANDLED);}

hy46xx符合Type B类型的触摸设备时序,故而使用的是Type B类型时序。 在中断处理函数hy46xx_ts_isr中调用hy46xx_read_touch_data读取5点坐标,调用hy46xx_report_events上报事件

3、驱动测试

安装驱动出现错误:

debian@npi:~/nfs_root/driver$ sudo insmod hy46xx_ts_drv.ko[   69.990212] hy46xx_ts_drv: loading out-of-tree module taints kernel.[   70.003587] hy46xx dts irq 210 ![   70.006999] irq-gpios 137, reset-gpios 68[   70.016025] input: hy46xx,ts as /devices/soc0/soc/2100000.aips-bus/21a0000.i2c/i2c-0/0-0038/input/input1

这是因为系统还有个gt9xx的触摸使用了设备树节点定义的资源,所以匹配失败,去掉gt9xx相关的设备节点即可。 我使用的系统触摸设备树节点是使用设备树插件实现的,只要禁用关于gt9xx触摸屏插件即可

debian@npi:~/nfs_root/driver$ sudo nano /boot/uEnv.txt  GNU nano 3.2                     /boot/uEnv.txtdtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-hdmi.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-cam.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-btwifi.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-can1.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-can2.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-dht11.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-ecspi3.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-key.dtbodtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-lcd.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-touch-capac$#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-led.dtbodtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-sound.dtbodtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-uart2.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-uart3.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-mpu6050.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-ds18b20.dtbo#overlay_end

通过#号注释掉dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-touch-capac该项目接着保存重启系统使修改生效。

重新安装驱动模块:

debian@npi:~/nfs_root/driver$ sudo insmod hy46xx_ts_drv.ko[   69.990212] hy46xx_ts_drv: loading out-of-tree module taints kernel.[   70.003587] hy46xx dts irq 210 ![   70.006999] irq-gpios 137, reset-gpios 68[   70.016025] input: hy46xx,ts as /devices/soc0/soc/2100000.aips-bus/21a0000.i2c/i2c-0/0-0038/input/input1

可以看到已经probe成功了

查看输入子系统生成设备节点:

debian@npi:~/nfs_root/driver$ ls /dev/input/ev*/dev/input/event0  /dev/input/event1

/dev/input/event1 就是hy46xx触摸的设备节点

用命令方式测试驱动:

debian@npi:~/nfs_root/driver$ hexdump /dev/input/event1hexdump: /dev/input/event1: Permission denieddebian@npi:~/nfs_root/driver$ sudo hexdump /dev/input/event10000000 c6f9 624962ff 000e 00030039000c 00000000010 c6f9 624962ff 000e 00030035024b00000000020 c6f9 624962ff 000e 00030036010800000000030 c6f9 624962ff 000e 00030000024b00000000040 c6f9 624962ff 000e 00030001010800000000050 c6f9 624962ff 000e 00000000000000000000060 c6f9 62490498000f00030039 ffff ffff

这样测试不太直观,编写测试程序:

#include"stdio.h"#include"unistd.h"#include"sys/types.h"#include"sys/stat.h"#include"sys/ioctl.h"#include"fcntl.h"#include"stdlib.h"#include"string.h"#include<poll.h>#include<sys/select.h>#include<sys/time.h>#include<signal.h>#include<fcntl.h>#include<linux/input.h>#define DEV_NAME "/dev/input/event1"staticstructinput_eventin_event;intmain(int argc, char *argv[]){int fd;int ret = 0;    fd = open(DEV_NAME, O_RDWR);if (fd < 0) {printf("Can't open file %s\r\n", DEV_NAME);return-1;    }while (1)     {        ret = read(fd, &in_event, sizeof(in_event));if (ret == sizeof(in_event))      /* 读取数据成功 */        {switch (in_event.type)             {case EV_KEY:     /* 按键事件类型 */break;/* 其他类型的事件,自行处理 */case EV_REL: break; case EV_ABS: if (in_event.code == ABS_X)                {printf("x %d ", in_event.value);                }if (in_event.code == ABS_Y)                {printf("y %d\r\n", in_event.value);                }break; case EV_MSC: break; case EV_SW: break;             }         }else        { printf("读取数据失败\r\n");         }     }  return0; }

执行sudo ./hy46xx_ts_test进行测试

debian@npi:~/nfs_root/driver$ sudo ./hy46xx_ts_testx 606 y 303x 621 y 464x 744 y 255x 734 y 276x 826 y 428x 972 y 573x 982 y 529

代码:https://gitee.com/guangjieMVP/linux-driver-leanring

最新文章

随机文章