Linux GT9147 多点触摸

前言

正点原子的源码提供的驱动 GT9147只支持单点,说是没有硬件检测触摸点按下和抬起,但其实芯片是有提供的,只不过不太明确。我改进了一点点代码,就可以支持多点触摸,供大家学习。

原理

中断来之后,先读点个数N,然后根据点数读取N个寄存器,寄存器信息包括:id+X+Y.
比如此时
touchnum=3
id=1, X=100, Y=100
id=2, X=200, Y=200
id=3, X=300, Y=300
下一次上报
touchnum=2
id=2, X=200, Y=200
id=3, X=300, Y=300
那就可以知道点1松开了。

代码

这份修订是已经可以通过tslib一个叫tstest_mt那个啥的工具测过了。准确无误。

struct point_info {
    int id;
    int x;
    int y;
};

struct gt9147_dev {
    int irq_pin;
    int reset_pin;
    void *priv;
    struct input_dev *input;
    struct i2c_client *client;
    int touch_num;
    struct point_info p[MAX_SUPPORT_POINTS];
    struct work_struct work;
};

const short touch_id_arr[MAX_SUPPORT_POINTS] = {
    GT_TP1_REG, GT_TP2_REG, GT_TP3_REG, GT_TP4_REG, GT_TP5_REG
};

static int gt9147_report(struct gt9147_dev *dev)
{
    static int last_touchnum = 0;
    static int last_point_id[MAX_SUPPORT_POINTS] = {0};
    int i, j;
    int idx;
    /* report true state */
    for (i = 0; i < dev->touch_num; i++) {
        input_mt_slot(dev->input, dev->p[i].id);
        input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, true);
        input_report_abs(dev->input, ABS_MT_POSITION_X, dev->p[i].x);
        input_report_abs(dev->input, ABS_MT_POSITION_Y, dev->p[i].y);
    }

    /* sync false state */
    if (last_touchnum > dev->touch_num) {
#if 0
        printk("last[%d]: ", last_touchnum);
        for(idx = 0; idx < last_touchnum; idx++)
            printk("%d ", last_point_id[idx]);
        printk("now[%d]: ", dev->touch_num);
        for(idx = 0; idx < dev->touch_num; idx++)
            printk("%d ", dev->p[idx].id);
        printk("\n");
#endif
        for (i = 0; i < dev->touch_num; i++) {
            for (j = 0; j < last_touchnum; j++) {
                if (last_point_id[j] == dev->p[i].id)
                    last_point_id[j] = -1;
            }
        }
        /* to report release point */
        for (j = 0; j < last_touchnum; j++) {
            if (last_point_id[j] != -1) {
#if 0
                printk("release id: %d\n", last_point_id[j]);
#endif
                input_mt_slot(dev->input, last_point_id[j]);
                input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, false);
            }
        }
    }
    /* last point */
    if (last_touchnum == 1 && dev->touch_num == 0){	
    } else {
        input_mt_report_pointer_emulation(dev->input, true);
        input_sync(dev->input);
    }
    
    /* update last data */
    last_touchnum = dev->touch_num;
    memset(last_point_id, 0, sizeof(int) * MAX_SUPPORT_POINTS);
    for (i = 0; i < dev->touch_num; i++) 
        last_point_id[i] = dev->p[i].id;

    return 0;
}

static irqreturn_t gt9147_irq_handler(int irq, void *dev_id)
{
    int ret;
    uint8_t data;
    struct gt9147_dev *dev = dev_id;
    int i;
    uint8_t touch_data[5];

    ret = gt9147_read_regs(dev, GT_GSTID_REG, &data, 1);
    if (!data) {
        goto failed;
    }
    
    dev->touch_num = data & 0x0f;
    // printk("Current touch num=%d\n", dev->touch_num);
    dev->touch_num = (dev->touch_num > MAX_SUPPORT_POINTS ? \
                MAX_SUPPORT_POINTS : dev->touch_num);
    for (i = 0; i < dev->touch_num; i++) {
        gt9147_read_regs(dev, touch_id_arr[i], touch_data, 5);
        dev->p[i].id = touch_data[0] & 0x0F;
        dev->p[i].x = touch_data[1] | (touch_data[2] << 8);
        dev->p[i].y = touch_data[3] | (touch_data[4] << 8);
        // printk("[%d]: id %d x: %d y: %d\n", i, id, x, y);
    }
    gt9147_report(dev);
    /* Clear reg */
    data = 0;
    gt9147_write_regs(dev, GT_GSTID_REG, &data, 1);

failed:
    return IRQ_HANDLED;
}

大概逻辑是 中断来了之后读取所有按下的点和个数,然后放到 gt9147_report函数处理,gt9147_report函数是重点,但也简单:

  1. 上报所有按下点的状态
  2. 如果上次记录的点个数大于当前点个数,就说明有按键释放了.
    根据上次保存的点id数组,寻找当前释放的点,然后上报释放点。
  3. 注意的是,如果是最后一个点释放,不用上报SYN事件了。
  4. 保存此次点个数和ID,用于第2步。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值