linux内核usb触摸屏驱动bug调试- selected device is not a touchscreen I understand

  期给客户调试一块数控板,今天客户带过来一个屏,并且有一个usb的触摸屏芯片接在屏上。屏很快就弄好正常显示。

   触摸屏在内核下找到usb 触摸屏驱动,内核启动后这个usb转的触摸屏也正常找到,注册为event接口事件event0, cat /dev/event0,触摸屏幕有乱码输出,说明usb触摸屏驱动产生中断并且将采集数据上报input子系统了。

   然后用我移植的tslib中有几个校准测试程序,运行,发现出现下面的错误:

   selected device is not a touchscreen I understand

   屏上出现校准界面,但是校准的5个点瞬间连了一遍程序就出错结束了。

   多次尝试都是这个结果,我就插入一个usb的鼠标,识别产生event1,我就讲为tslib运行设置的环境变量中tslib的设备设为event1,再运行校准程序,发现现象跟触摸屏的一样。也就说tslib中应该是有容错处理,会先根据一些条件来判断这个环境变量指定的设备是否是一个真正的触摸屏设备。

  想多无意,还是多看代码,于是在tslib源码中找到上面这句的出处如下:

static int check_fd(struct tslib_input *i)
{
    struct tsdev *ts = i->module.dev;
    int version;
    u_int32_t bit;
    u_int64_t absbit;

    if (! ((ioctl(ts->fd, EVIOCGVERSION, &version) >= 0) &&
        (version == EV_VERSION) &&
        (ioctl(ts->fd, EVIOCGBIT(0, sizeof(bit) * 8), &bit) >= 0) &&
        (bit & (1 << EV_ABS)) &&
        (ioctl(ts->fd, EVIOCGBIT(EV_ABS, sizeof(absbit) * 8), &absbit) >= 0) &&
        (absbit & (1 << ABS_X)) &&
        (absbit & (1 << ABS_Y)) && (absbit & (1 << ABS_PRESSURE)))) {
        fprintf(stderr, "selected device is not a touchscreen I understand\n");
        return -1;
    }   

    if (bit & (1 << EV_SYN))
        i->using_syn = 1;

    return 0;
}

这个check_fd中会根据这些条件来判断是否打印如上错误。

第一个条件是ioctl获取version,内核源码下找到ioctl定义在driver/input/evdev.c中,对应命令EVIOCGVERSION定义值为0x10000 而编译器中input.h中定义值也是0x10000,这个条件没有问题。我看网上关于这个错误大部分问题都是处在这里。可惜我的不是,继续往下。

第二个条件是获取input设备的bit标志,也就是看这个是被是否是一个触摸屏设备。usb设备我之前也没有接触过,但是根据cat /dev/event0,有反应,说明usb部分采集数据是没有问题的,只是上报给input子系统出了问题,所以应该想到的是看一下usb触摸屏驱动注册input设备的部分代码,在usb触摸屏驱动driver/usb/input/usbtouchscreen.c中的probe函数中代码如下:

    input_dev->name = usbtouch->name;
    input_dev->phys = usbtouch->phys;
    usb_to_input_id(udev, &input_dev->id);
    input_dev->cdev.dev = &intf->dev;
    input_dev->private = usbtouch;
    input_dev->open = usbtouch_open;
    input_dev->close = usbtouch_close;

    input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
    input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
    input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
    input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);

if (type->max_press)
    input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
                             type->max_press, 0, 0);
可以看到evbit中设置了EV_ABS标志位。这样第二个条件也满足了。

第三个条件是获取专为触摸屏input设备准备的absbit标志中是否有触摸屏对应的标志位,因为之前写过一个触摸屏驱动,所以知道触摸屏标志位为x y press,也就是坐标以及按压。

在input_set_abs_params实现中是为absbit置各种标志位。并且设置对应标志的范围(min max),但是这个标志比如x y press的范围在后面没有看到使用,我也实验发现min max都写0也没有问题,这个是题外话了。

这里就出现了问题了,usb触摸屏中枚举出来的设备中max_press和min_press都没有设置,为0,所以最后这个设置press标志位的函数就没有调用。

所以我上面出现selected device is not a touchscreen I understand 是因为  absbit & (1 << ABS_PRESSURE)不满足造成的!

我把if判断注释掉,然后重编内核启动,运行tslib测试程序,发现不会出现上面的错误退出了,这个问题算是解决。后来我实验发现input_set_abs_params中设置x y press的min max都没有用到,即使这些都设置为0也没有影响。

校准测试程序正常算是运行,但是我点击屏幕,校准程序并没有检测到我的点击行为,接着就遇到了这个问题。接着研究搞定!


运行tslib测试程序没有检测到点击事件,但是cat /dev/event0时点击屏幕是有东西传给input子系统的,这说明触摸屏中断是正常的。

之间编写另外一个触摸屏驱动的时候点击事件上报坐标数据给input子系统是在触摸屏的中断中做的,因此需要找到这段代码来看一下有没有问题,在usbtouchscreen.c中找到如下代码:

static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
                                 unsigned char *pkt, int len)
{
    struct usbtouch_device_info *type = usbtouch->type;


    if (!type->read_data(usbtouch, pkt))
            return;
    input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);

    if (swap_xy) {
        input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
        input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
    } else {
        input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
        input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
    }

    if (type->max_press)
        input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
    input_sync(usbtouch->input);
}

这段代码是中断中上报数据给input子系统的部分,report key是标志输入事件是否按下和弹起,而对于触摸屏来说上报的数据包括x y press,这段代码中可以看出由于max_press为0,所以中断中一直没有上报press,也就是说usb触摸屏一直上报的是坐标,但是press值一直为0,所以上层程序就会认为没有按压下去。所以没有反应。在中断中加打印,发现从usb读出来的数据press值为0,不管是按下还是弹起,但是touch在按下的时候是1,弹起的时候是0,可以用这个值来上报给input子系统当前的press,函数修改如下:

static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
                                 unsigned char *pkt, int len)
{
    struct usbtouch_device_info *type = usbtouch->type;


    if (!type->read_data(usbtouch, pkt))
            return;
    input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
    //zk modify for usb touchpad
    input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->touch);


    if (swap_xy) {
        input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
        input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
    } else {
        input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
        input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
    }
#if 0
    if (type->max_press)
        input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
#endif
    input_sync(usbtouch->input);
}

重新编译内核,启动,运行tslib的校准测试程序,可以正常点击,并且tslib程序可以检测到触摸屏数据了!成功!!


你可能感兴趣的:(driver,debug,summary)