USB设备无响应

Device No Response 测试介绍

在USB认证中,otgeh_compliance_plan_1_2.pdf 测试文档有一项关于连接超时显示Device No Response的测试。
描述如下:
这里写图片描述

测试步骤如下:
这里写图片描述

这里写图片描述

说白了,就是说连接一个无法识别的USB设备到Embedded Host上,判断其能否在30s内给出“Device No Response”的提示,如果有,那么测试pass,如果没有或者超过30s给出“Device No Response”的提示,那么这个测试项是NG的。


术语:

  • A-UUT:Unit Under Test with a Micro-A plug attached.(待认证的设备)
  • PET:Protocol and Electrical Tester. A test unit which is capable of performing the tests specified in Section 6.(测试治具)
  • SRP:Session Request Protocol (see Section [USBOTG&EHv2.0]).(开始枚举)

内核打印

在做这个测试,USB认证实验室的工程师会专门拿一个特制的USB设备,这个设备是无法正常响应USB Host发起的USB_REQ_GET_DESCRIPTOR命令,会出现超时的情况,以此来判定待测的Embedded Host是否能在30s之内给出“Device No Response”的提示。连接这个特制的USB设备,内核的打印如下:

[   32.809100] usb 2-1: new high-speed USB device number 2 using xxx-ehci
[   36.429085] usb 2-1: device descriptor read/64, error -110
[   40.149029] usb 2-1: device descriptor read/64, error -110
[   40.369041] usb 2-1: new high-speed USB device number 3 using xxx-ehci
[   43.985098] usb 2-1: device descriptor read/64, error -110
[   47.705018] usb 2-1: device descriptor read/64, error -110
[   47.925103] usb 2-1: new high-speed USB device number 4 using xxx-ehci
[   52.949071] usb 2-1: device descriptor read/8, error -110
[   58.073024] usb 2-1: device descriptor read/8, error -110
[   58.293048] usb 2-1: new high-speed USB device number 5 using xxx-ehci
[   63.317040] usb 2-1: device descriptor read/8, error -110
[   68.441045] usb 2-1: device descriptor read/8, error -110
[   68.549040] hub 2-0:1.0: unable to enumerate USB device on port 1

根据内核打印,我们可以知道:
这次枚举总共用时36s,超过了30s的限定时间,所以这个测试项肯定是NG的。


USB Host尝试枚举次数

从上面的内核log来看,总共尝试枚举4次,每次枚举尝试读取2次设备描述符信息,但是读取失败,报告的错误信息是-100,也就是timeout。

枚举过程是在 <kernel_dir>/drivers/usb/core/hub.c 中的hub_port_connect_change() 函数进行的,宏 SET_CONFIG_TRIES 决定枚举的次数,宏 GET_DESCRIPTOR_TRIES 决定获取描述符的次数。

static bool use_both_schemes = 1;
module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(use_both_schemes,
        "try the other device initialization scheme if the "
        "first one fails");

#define PORT_RESET_TRIES    5
#define SET_ADDRESS_TRIES   2
#define GET_DESCRIPTOR_TRIES    2
#define SET_CONFIG_TRIES    (2 * (use_both_schemes + 1))
#define USE_NEW_SCHEME(i)   ((i) / 2 == (int)old_scheme_first)

USB Host尝试获取描述符次数

<kernel_dir>/drivers/usb/core/hub.c 中的hub_port_init()函数会去获取描述符。

/* Reset device, (re)assign address, get device descriptor.
 * Device connection must be stable, no more debouncing needed.
 * Returns device in USB_STATE_ADDRESS, except on error.
 *
 * If this is called for an already-existing device (as part of
 * usb_reset_and_verify_device), the caller must own the device lock.  For a
 * newly detected device that is not accessible through any global
 * pointers, it's not necessary to lock the device.
 */
static int
hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        int retry_counter)
{
//……
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { // 获取描述符
    //……
    retval = usb_get_device_descriptor(udev, 8);
        if (retval < 8) {
            if (retval != -ENODEV)
                dev_err(&udev->dev,
                    "device descriptor read/8, error %d\n",
                    retval);
            if (retval >= 0)
                retval = -EMSGSIZE;
        } else {
            retval = 0;
            break;
        }
//……
}
    //……
}
// <kernel_dir>/drivers/usb/core/message.c

/**
 * usb_get_descriptor - issues a generic GET_DESCRIPTOR request
 * @dev: the device whose descriptor is being retrieved
 * @type: the descriptor type (USB_DT_*)
 * @index: the number of the descriptor
 * @buf: where to put the descriptor
 * @size: how big is "buf"?
 * Context: !in_interrupt ()
 *
 * Gets a USB descriptor.  Convenience functions exist to simplify
 * getting some types of descriptors.  Use
 * usb_get_string() or usb_string() for USB_DT_STRING.
 * Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG)
 * are part of the device structure.
 * In addition to a number of USB-standard descriptors, some
 * devices also use class-specific or vendor-specific descriptors.
 *
 * This call is synchronous, and may not be used in an interrupt context.
 *
 * Return: The number of bytes received on success, or else the status code
 * returned by the underlying usb_control_msg() call.
 */
int usb_get_descriptor(struct usb_device *dev, unsigned char type,
               unsigned char index, void *buf, int size)
{
    int i;
    int result;

    memset(buf, 0, size);   /* Make sure we parse really received data */

    for (i = 0; i < 3; ++i) {
        /* retry on length 0 or error; some devices are flakey */
        result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
                (type << 8) + index, 0, buf, size,
                USB_CTRL_GET_TIMEOUT);
        if (result <= 0 && result != -ETIMEDOUT)
            continue;
        if (result > 1 && ((u8 *)buf)[1] != type) {
            result = -ENODATA;
            continue;
        }
        break;
    }
    return result;
}

/*
 * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
 * @dev: the device whose device descriptor is being updated
 * @size: how much of the descriptor to read
 * Context: !in_interrupt ()
 *
 * Updates the copy of the device descriptor stored in the device structure,
 * which dedicates space for this purpose.
 *
 * Not exported, only for use by the core.  If drivers really want to read
 * the device descriptor directly, they can call usb_get_descriptor() with
 * type = USB_DT_DEVICE and index = 0.
 *
 * This call is synchronous, and may not be used in an interrupt context.
 *
 * Return: The number of bytes received on success, or else the status code
 * returned by the underlying usb_control_msg() call.
 */
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
{
    struct usb_device_descriptor *desc;
    int ret;

    if (size > sizeof(*desc))
        return -EINVAL;
    desc = kmalloc(sizeof(*desc), GFP_NOIO);
    if (!desc)
        return -ENOMEM;

    ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
    if (ret >= 0)
        memcpy(&dev->descriptor, desc, size);
    kfree(desc);
    return ret;
}

usb_get_descriptor() 函数中通过 usb_control_msg() 发送获取设备描述符命令 USB_REQ_GET_DESCRIPTOR,设定timeout时间为USB_CTRL_GET_TIMEOUT(5s),如果发生timeout,返回-ETIMEDOUT的错误。

// <kernel_dir>/include/linux/usb.h

/*
 * timeouts, in milliseconds, used for sending/receiving control messages
 * they typically complete within a few frames (msec) after they're issued
 * USB identifies 5 second timeouts, maybe more in a few cases, and a few
 * slow devices (like some MGE Ellipse UPSes) actually push that limit.
 */
#define USB_CTRL_GET_TIMEOUT    5000
#define USB_CTRL_SET_TIMEOUT    5000

这里的timeout跟每次尝试获取描述符的间隔时间差不多一致。


解决NG项

根据上述的分析,为了在30s之内检测到设备无响应,我们可以尝试减小
SET_CONFIG_TRIESGET_DESCRIPTOR_TRIESUSB_CTRL_GET_TIMEOUT 这三个参数。保证在规定的时间内检测到设备无响应。


模拟USB设备无响应

为了模拟出USB设备无响应的问题,可以拿一条Android手机充电线,剪掉Micro A的那口,留下Type A的公头。将暴露出来的D+(绿色)信号与VCC和GND构成一个5V的上拉。做出来的“USB设备”插入USB Host中就会枚举失败,出现设备无响应的提示。对应的内核打印如下:

[ 1552.533095] usb 2-1: new full-speed USB device number 2 using xxx-ehci
[ 1552.745029] usb 2-1: device descriptor read/64, error -71
[ 1553.061115] usb 2-1: device descriptor read/64, error -71
[ 1553.281032] usb 2-1: new full-speed USB device number 3 using xxx-ehci
[ 1553.493081] usb 2-1: device descriptor read/64, error -71
[ 1553.809078] usb 2-1: device descriptor read/64, error -71
[ 1554.029027] usb 2-1: new full-speed USB device number 4 using xxx-ehci
[ 1554.504983] usb 2-1: device not accepting address 4, error -71
[ 1554.621111] usb 2-1: new full-speed USB device number 5 using xxx-ehci
[ 1555.096976] usb 2-1: device not accepting address 5, error -71
[ 1555.103295] hub 2-0:1.0: unable to enumerate USB device on port 1

这里的出错不是-110(Connection timed out),而是-71(Protocol error),也能能快的检测到USB设备无响应的问题。


参考资料

关于USB设备的Kernel中的枚举过程,可以参照Linux kernel U盘识别流程

关于常见的Linux返回错误,可以参照Linux 驱动常见错误返回值

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: USB设备远程共享是指通过网络连接的方式,将USB设备连接到一台计算机上,然后让其他计算机也能够通过网络使用该USB设备的功能。这种方式可以使多台计算机同时使用同一个USB设备,方便了用户的操作。 USB设备远程共享的原理是在连接USB设备的计算机上安装一个USB设备服务器软件,该软件会将USB设备转换成网络数据包进行传输。其他要使用该USB设备的计算机需要安装USB设备客户端软件,通过网络连接到USB设备服务器,然后就可以像连接本地USB设备一样使用远程共享的USB设备了。 远程共享USB设备的好处是可以实现多台计算机之间资源共享,节省了用户的成本和空间。例如,在一家公司的办公室中,只需要一台打印机,并通过USB设备远程共享让所有员工的电脑都能够使用这台打印机,就能够满足工作的需求,而不需要给每个员工都配备一台打印机。 USB设备远程共享也有一些限制,首先是网络的速度和稳定性,如果网络不稳定或者速度很慢,使用远程共享的USB设备可能会变得卡顿或者无法使用。其次,一些特殊的USB设备可能不支持远程共享功能,需要根据具体的USB设备来判断是否可以进行远程共享。 总的来说,USB设备远程共享是一种便利的技术,可以使多台计算机共享一个USB设备,提高了办公效率和资源利用率。但是在使用过程中,还需要考虑网络的稳定性和设备的兼容性等问题。 ### 回答2: USB设备远程共享是指通过网络将USB设备连接到远程计算机并共享该设备的功能。这种功能通常用在远程办公、远程控制和远程协作等场景中。 USB设备远程共享的实现需要使用特定的软件或硬件设备,其中最常见的方式是使用USB设备服务器。USB设备服务器是一种可以将USB设备连接到网络的设备,它会将USB接口转为网络接口,使得USB设备可以通过网络与远程计算机进行通信。 通过USB设备服务器,用户可以在本地计算机上安装相应的驱动程序和共享软件,然后将USB设备连接到USB设备服务器。通过网络,远程计算机可以访问共享软件,并将其识别为远程设备,从而实现对USB设备的远程共享和控制。 USB设备远程共享的优势在于可以实现远程设备的共享和使用,不再局限于物理连接。这对于需要在远程环境中使用USB设备的用户来说非常方便。例如,在远程会议中,用户可以将摄像头、麦克风等USB设备连接到USB设备服务器并共享给远程参会人员,从而实现更好的远程协作体验。此外,也可以通过远程共享USB设备来远程访问文件、打印文档等操作,提高工作效率。 需要注意的是,USB设备远程共享需要保证网络的稳定性和带宽的充足性,以确保远程设备的实时响应和流畅使用。此外,也要注意安全性问题,避免远程设备被未授权的用户滥用或侵犯隐私。因此,在进行USB设备远程共享时,需要选择可靠的软件和设备,并采取相应的安全措施来保护用户的数据和隐私。 ### 回答3: USB设备远程共享是指通过网络将USB设备连接到一台远程计算机上,使得远程计算机可以访问和使用USB设备。 实现USB设备远程共享的一种方法是使用虚拟化技术。虚拟化技术可以创建一个虚拟的USB设备接口,将USB设备的信号传输通过网络发送给远程计算机,远程计算机接收到信号后就可以像本地USB设备一样使用该设备USB设备远程共享的好处包括: 1. 方便共享:可以将一台USB设备共享给多台计算机使用,提高设备的利用率。 2. 节省成本:无需购买额外的USB设备,节省了硬件成本。 3. 提高灵活性:用户可以在任何地点通过网络访问和使用USB设备,无需受到地理位置限制。 4. 增强安全性:可以对USB设备进行权限管理和监控,有效防止数据泄漏和设备滥用的风险。 至于实现USB设备远程共享的具体方法,可以使用专门的USB设备共享软件或者使用远程桌面协议。这些软件和协议可以将本地USB设备映射到远程计算机上,并提供相应的控制和访问权限。 总之,USB设备远程共享是一种方便实用的技术,可以提高USB设备的利用率和灵活性,同时也增强了数据安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值