linux USB触屏无响应驱动出现EPIPE错误

Linux触屏驱动EPIPE错误解决方案
本文介绍了一种在Linux环境下,针对egalax USB触屏设备遇到的EPIPE错误的解决方案。通过修改内核驱动代码,实现在出现EPIPE错误时上报特殊值,触发上层应用程序重启,有效解决了触屏无响应的问题。

#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;
}

目前测试未在出现问题。

<think>嗯,用户这次提出了一个非常具体的驱动调试需求,而且明确指向了XR22800这款USB转网口芯片。结合之前的引用内容看,用户似乎正在构建一个嵌入式Linux系统(提到了rootfilesystem的初始化),现在遇到特定外设驱动的问题。用户可能正在调试定制硬件或工控设备,情绪上比较着急——毕竟系统构建到驱动调试阶段突然卡住会很恼火。ta能准确给出芯片型号,说明有一定技术背景,但可能对Linux内核驱动层不熟悉。深层需求应该是想快速定位是驱动问题还是硬件问题。这个XR22800芯片确实比较冷门,我回忆一下相关知识:它是芯睿(Synopsys)的USB3.0转千兆以太网控制器,常用于嵌入式设备。Linux内核从4.4版本开始提供xr_usb_ether驱动,但调试资料极少。需要分四个层面帮用户排查:首先是硬件确认,避免踩物理层坑;其次内核配置,这个驱动需要同时启用USB网络支持、通用phy驱动等依赖模块;然后是关键调试手段,比如利用usbmon抓USB协议层交互;最后是供应商兜底方案,毕竟这种专用芯片往往需要原厂提供调试工具。特别注意要提醒用户检查phy初始化的波形问题,很多类似案例都是复位时序不符合PHY芯片要求导致的。上次有个树莓派项目就是因为XR22800的reset-gpio配置错误,导致LPSPI模式始终无法建立链路。考虑到用户环境是自建rootfs,还要确认ta是否已加载firmware(虽然xr驱动通常不需要额外固件)。调试模块卸载风险也要强调,避免系统崩溃。</think> 针对Linux系统中XR22800 USB转网口驱动的调试,以下是详细步骤和相关建议: --- ### **调试步骤** 1. **确认驱动加载状态** ```bash lsmod | grep xr_usb_ether # 检查驱动是否加载 dmesg | grep -i xr22800 # 查看内核日志的硬件识别记录 ``` - 若未加载: ```bash sudo modprobe xr_usb_ether # 手动加载驱动 ``` 2. **检查硬件识别** - 使用`lsusb`命令搜索硬件ID: ```bash lsusb | grep 0x8081:0x2280 # XR22800的典型硬件ID ``` - 若设备未列出,可能是硬件故障或USB端口供电问题。 3. **网络接口诊断** - 检查接口命名(通常为`ethX`或`enpXsX`): ```bash ip link show # 查看所有网络接口 ``` - 启用接口并测试连接: ```bash sudo ip link set dev ethX up sudo dhclient ethX # 获取IP地址 ping 8.8.8.8 # 测试网络连通性 ``` 4. **底层通信抓包** 使用`usbmon`捕获USB通信: ```bash sudo modprobe usbmon sudo wireshark-gtk # 在Wireshark中选择usbmon接口抓包 ``` - **关键过滤**: ``` usb.transfer_type == URB_BULK and usb.device == "XR22800" ``` 5. **驱动调试日志** 动态启用内核调试信息: ```bash echo 'module xr_usb_ether +p' | sudo tee /sys/kernel/debug/dynamic_debug/control dmesg -w # 实时监控驱动行为 ``` - 重点观察: - 硬件初始化流程(`probe`函数) - 数据传输错误(`urb status -EPIPE/-ENOENT`) - PHY协商状态(`phy_start`) 6. **排查硬件问题** - **电压测试**:用万用表测量VBUS电压(需稳定5V±0.25V)。 - **信号质量**:高频示波器检查USB D+/D-眼图(jitter需<5% UI)。 - **ESD防护**:检查接口TVS二极管是否击穿(阻抗应>1MΩ)。 --- ### **常见故障解决方案** | 现象 | 可能原因 | 解决措施 | |---------------------|--------------------------|--------------------------------------------------------------------------| | `dmesg`报错`-110` | 硬件通信超时 | 缩短USB线缆(<1米),增强屏蔽或更换接口 | | `ip link`显示`NO-CARRIER` | PHY协商失败 | 强制网口模式:`ethtool -s ethX speed 100 duplex full autoneg off` | | 数据包CRC错误 | EMI干扰或驱动Bug | 更新内核至最新LTS版,硬件增加磁环滤波 | --- ### **高级调试工具** 1. **驱动符号调试** 安装内核调试符号包,使用`gdb`附加内核: ```bash sudo gdb vmlinux /proc/kcore (gdb) p *xr_private_device # 查看设备结构体状态 ``` 2. **硬件热复位** 强制硬件重置: ```bash echo 1 | sudo tee /sys/bus/usb/devices/1-5/reset # 路径根据实际usb树修改 ``` --- ### **厂商支持** 1. **更新固件/驱动** 联系芯片厂商获取: - 最新驱动补丁(常见于`support@xrchip.com`) - PHY初始化配置文件(`xr22800_phy_init.bin`) 2. **原理图审查** 检查设计要点: - USB阻抗控制(90Ω差分) - REFCLK精度(≤50ppm) - 电源去耦(每个VDD需100nF+10uF电容) --- ### **参考文档** - [XR22800 Datasheet](https://www.xrchip.com/products/XR22800) - 第8章硬件设计规范 - [Linux USB Network Guide](https://docs.kernel.org/usb/usb-net.html) - 官方驱动开发文档 - [Kernel USBmon FAQ](https://www.kernel.org/doc/html/latest/usb/usbmon.html) - 抓包技术细节
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值