#linux触屏无响应驱动出现EPIPE错误
使用的触屏设备是egalax通过USB接入的,使用的驱动是 kernel\linux-3.10.y\drivers\input\touchscreen\usbtouchscreen.c。出现问题时触屏没有反应,hexdump /dev/input/event0也没有输出,但是重启QT程序后正常。问题很难复现,复现后也获取不到多少有用信息,后来直接将触屏USB输入输出线短路复现此问题。后续发现触屏无反应时出现EPIPE错误:
static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
struct device *dev = &usbtouch->interface->dev;
int retval;
switch (urb->status) {
case 0:
/* success */
break;
case -ETIME:
/* this urb is timing out */
dev_dbg(dev,
"%s - urb timed out - was the device unplugged?\n",
__func__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
case -EPIPE:
/* this urb is terminated, clean up */
dev_dbg(dev, "%s - urb shutting down with status: %d\n",
__func__, urb->status);
return;
default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, urb->status);
goto exit;
}
usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
exit:
usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
__func__, retval);
}
添加一些打印后发现,结束QT程序后,再打开QT程序,驱动会重新open设备。没有找到比较好的办法,于是在驱动层出现EPIPE错误的时候,向上层上报一个特殊值,应用层监控/dev/input/event0,检测到特殊值时,重启QT程序,修改usbtouchscreen.c如下:
static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
struct device *dev = &usbtouch->interface->dev;
int retval;
dev_err(&usbtouch->interface->dev,"XXXXXXXX file:%s func:%s IN status:%d",__FILE__,__func__,urb->status);
switch (urb->status) {
case 0:
/* success */
break;
case -ETIME:
/* this urb is timing out */
dev_dbg(dev,
"%s - urb timed out - was the device unplugged?\n",
__func__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dev_dbg(dev, "%s - urb shutting down with status: %d\n",
__func__, urb->status);
return;
case -EPIPE://出现EPIPE错误,上报一个特殊值
dev_err(&usbtouch->interface->dev,"XXXXXXXXXXXXXXXXXXXXXXXXX EPIPE ERROR file:%s func:%s EPIPE status:%d",__FILE__,__func__,urb->status);
usbtouch->touch = 1;
usbtouch->x = 20480;
usbtouch->y = 20480;
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);
}
input_sync(usbtouch->input);
goto exit;
default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, urb->status);
goto exit;
}
usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
exit:
usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
__func__, retval);
}
监控程序:
#include <stdio.h>
#include <linux/input.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
bool openFile(int & fdTouch){
fdTouch = open("/dev/input/event0", O_RDWR);
if(fdTouch <= 0){
printf("Can not /dev/input/event0\n");
return false;
}
printf("Open /dev/input/event0 success\n");
return true;
}
int main(int argc, char **argv)
{
int fdTouch = -1;
char buf[128] = {0};
while(1) {
if(fdTouch <= 0){
openFile(fdTouch);
}
if(fdTouch > 0){
int len = read(fdTouch, buf, sizeof(buf));
if (len > 0){
for(int pos = 0;len >= pos + 16;pos += 16){
//hexdump /dev/input/event0 出现EPIPE错误时上报的特殊值
//2be9 5ba7 a6d4 0005 0003 0000 5000 0000
//2be9 5ba7 a6d4 0005 0003 0001 5000 0000
if(3 == buf[pos + 8] && 0 == buf[pos + 9] && (0 == buf[pos + 10] || 1 == buf[pos + 10]) && 0 == buf[pos + 11] && 0 == buf[pos + 12] && 80 == buf[pos + 13] && 0 == buf[pos + 14] && 0 == buf[pos + 15]){
printf("Read driver define value ,need kill ui and client.\n");
close(fdTouch);
fdTouch = -1;
sleep(2);
printf("Close fdTouch in read driver define value\n");
int loop = 0;
while (true) {
openFile(fdTouch);
if(fdTouch > 0){ //等到能正常打开/dev/input/event0时重启QT程序
printf("Retry open /dev/input/event0 SUCCESS close fdTouch times:%d\n",loop);
close(fdTouch);
fdTouch = -1;
sleep(1);
break;
}
fdTouch = -1;
++loop;
printf("Retry open /dev/input/event0 times:%d\n",loop);
usleep(500 * 1000);
}
system("killall -kill qtPrograme");//杀死QT程序,进程监控程序会重启它的
break;
}
}
}
else if(len < 0){
close(fdTouch);
fdTouch = -1;
printf("Close fdTouch \n");
}
}
usleep(200 * 1000);
}
close(fdTouch);
return 0;
}
目前测试未在出现问题。