我无法通过cdc_acm驱动程序在USB端口上发送意外字符。更令人困惑的是,代码在Ubuntu 12.04(3.2内核)上可以正常运行,但在Centos 6(3.6内核)上无法运行(此问题的主题)

USB设备是Bluegiga BLED112蓝牙智能加密狗。它的嵌入式微 Controller 会随时在其USB接口(interface)上的意外输入中进行重置。

测试代码打开端口,写入4个字节(问候消息),并期望读取响应。读取永远不会完成,因为意外的字符会导致设备重置,从而导致集线器掉落设备并重新枚举。

要进行故障排除,这是我所做的:

  • 下载了cdc_acm驱动程序的源代码。添加了一堆printk调试消息和stack_dumps来跟踪正在发生的事情。
  • 我rmmod了“库存” cdc_acm并安装了我的检测模块。所有设备枚举工作,连接了正确的驱动程序等。
  • 由于该代码可在Ubuntu 12.04/Linux 3.2上运行,因此我抓取了3.2 cdc_acm代码并在Centos 6/Linux 3.6平台上编译了该模块。使用那个3.2模块而不是3.6模块并没有什么不同。我恢复到3.6模块。
  • 使用usbmon打开调试文件系统,并观察USB流量。我可以看到USB接口(interface)上发送了额外的字符。
  • 要观察正在发生的情况,在cdc_acm模块中的printk之上,我合并了usb mon(cat/sys/kernel/debug/usb/usbmon/3u | logger)的输出和测试应用程序的输出(scan_example/dev/ttyACM0 | logger -s),所以我只有一条与时间相关的调试线索流。
  • 在USB端点上发送的虚假字符是x5E x40 x5E x40 x5E x40 x5E x40 x41(以ASCII表示为^ @ ^ @ ^ @ ^ @ A),看起来像是在探测或试图引起调制解调器的注意。在应用程序的write()导致将4个hello字节发送到端点后,立即发送字符。
  • 因为cdc_acm设备应该是调制解调器,所以我试图通过将其添加到cdc_acm.c中的usb_device_id acm_ids []来关闭调制解调器控制。
    /* bluegiga BLED112*/
    { USB_DEVICE(0x2458, 0x0001),
    .driver_info = NOT_A_MODEM,
    },
    
  • 重新编译并进行了insmod'd,并且系统日志显示此错误已被识别(古怪为8),但功能未发生变化。

  • NetowrkManager和modem-manager都没有运行,但是我仍然怀疑某个地方正在执行某种调制解调器控制功能,我只是不知道在哪里。

    这是带注释的调试日志(MDV在我添加到cdc_acm的那些printk的前面加上前缀)
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_bulk
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_done
    

    这是应用程序发送的4个字节00 00 00 01
    Feb 13 18:14:32 localhost cpcenter: df046a80 3672670191 C Bi:3:006:4 0 4 = 00000001
    Feb 13 18:14:32 localhost cpcenter: 1360797272.669690 write: data2: len=0 contains:
    

    ...这些附加字符意外出现5e 40 5e 40 5e 40 ....
    Feb 13 18:14:32 localhost cpcenter: df046a80 3672670232 S Bi:3:006:4 -115 128 <
    Feb 13 18:14:32 localhost cpcenter: f3cc5740 3672670297 S Bo:3:006:4 -115 1 = 5e
    Feb 13 18:14:32 localhost cpcenter: df2e1300 3672670332 S Bo:3:006:4 -115 1 = 40
    Feb 13 18:14:32 localhost cpcenter: f3cc5740 3672670347 C Bo:3:006:4 0 1 >
    Feb 13 18:14:32 localhost cpcenter: f3cc5740 3672670392 S Bo:3:006:4 -115 1 = 5e
    Feb 13 18:14:32 localhost cpcenter: df2e1180 3672670426 S Bo:3:006:4 -115 1 = 40
    Feb 13 18:14:32 localhost cpcenter: df2e1c00 3672670461 S Bo:3:006:4 -115 1 = 5e
    Feb 13 18:14:32 localhost cpcenter: df2e1840 3672670496 S Bo:3:006:4 -115 1 = 40
    Feb 13 18:14:32 localhost cpcenter: df2e1300 3672670591 C Bo:3:006:4 0 1 >
    

    在这一点上,我们自发断开连接。
    Feb 13 18:14:32 localhost kernel: usb 3-1: USB disconnect, device number 6
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_bulk
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_done
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm read_bulk_callback
    Feb 13 18:14:32 localhost kernel: MDV 1 acm_read_bulk_callback - urb 1, len 0
    Feb 13 18:14:32 localhost kernel: MDV 3 acm_read_bulk_callback - non-zero urb status: -71
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_bulk
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_done
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm read_bulk_callback
    Feb 13 18:14:32 localhost kernel: MDV 1 acm_read_bulk_callback - urb 1, len 0
    Feb 13 18:14:32 localhost kernel: MDV 3 acm_read_bulk_callback - non-zero urb status: -71
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_bulk
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_done
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm read_bulk_callback
    Feb 13 18:14:32 localhost kernel: MDV 1 acm_read_bulk_callback - urb 2, len 0
    Feb 13 18:14:32 localhost cpcenter: df2e1d80 3672670629 S Bo:3:006:4 -115 1 = 5e
    Feb 13 18:14:32 localhost kernel: MDV 3 acm_read_bulk_callback - non-zero urb status: -71
    Feb 13 18:14:32 localhost cpcenter: df2e1300 3672670677 S Bo:3:006:4 -115 1 = 41
    Feb 13 18:14:32 localhost cpcenter: f3cc5740 3672670802 C Bo:3:006:4 0 1 >
    Feb 13 18:14:32 localhost cpcenter: df2e1180 3672671019 C Bo:3:006:4 0 1 >
    Feb 13 18:14:32 localhost cpcenter: df2e1c00 3672671237 C Bo:3:006:4 0 1 >
    Feb 13 18:14:32 localhost cpcenter: dfbf8c00 3672673193 C Ii:3:001:1 0:2048 1 = 02
    Feb 13 18:14:32 localhost cpcenter: dfbf8c00 3672673207 S Ii:3:001:1 -115:2048 4 <
    Feb 13 18:14:32 localhost cpcenter: f3c26c00 3672673221 S Ci:3:001:0 s a3 00 0000 0001 0004 4 <
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_disconnect
    Feb 13 18:14:32 localhost kernel: Pid: 29, comm: khubd Tainted: G           O 3.5.3-1.el6.elrepo.i686 #1
    

    断开连接时的堆栈跟踪
    Feb 13 18:14:32 localhost kernel: Call Trace:
    Feb 13 18:14:32 localhost kernel: [<f82dabc5>] acm_disconnect+0x35/0x1f0 [cdc_acm]
    Feb 13 18:14:32 localhost kernel: [<c13835db>] usb_unbind_interface+0x4b/0x180
    Feb 13 18:14:32 localhost cpcenter: f3c26c00 3672673239 C Ci:3:001:0 0 4 = 00010100
    Feb 13 18:14:32 localhost kernel: [<c1318bfb>] __device_release_driver+0x5b/0xb0
    Feb 13 18:14:32 localhost kernel: [<c1318d05>] device_release_driver+0x25/0x40
    Feb 13 18:14:32 localhost kernel: [<c1317f0c>] bus_remove_device+0xcc/0x130
    Feb 13 18:14:32 localhost kernel: [<c131612f>] ? device_remove_attrs+0x2f/0x90
    Feb 13 18:14:32 localhost kernel: [<c1316275>] device_del+0xe5/0x180
    Feb 13 18:14:32 localhost kernel: [<c1380326>] usb_disable_device+0x96/0x240    Feb 13 18:14:32 localhost kernel: [<c1379f91>] usb_disconnect+0x91/0x130
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_bulk
    Feb 13 18:14:32 localhost kernel: [<c137a2c0>] hub_port_connect_change+0xb0/0xa60
    Feb 13 18:14:32 localhost kernel: [<c1380f4e>] ? usb_control_msg+0xce/0xe0
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm acm_write_done
    Feb 13 18:14:32 localhost kernel: [<c137b296>] hub_events+0x536/0x810
    Feb 13 18:14:32 localhost cpcenter: f3c26c00 3672673243 S Co:3:001:0 s 23 01 0010 0001 0000 0
    Feb 13 18:14:32 localhost cpcenter: f3c26c00 3672673250 C Co:3:001:0 0 0
    Feb 13 18:14:32 localhost kernel: [<c1065bdf>] ? finish_wait+0x4f/0x70
    Feb 13 18:14:32 localhost kernel: [<c137b5aa>] hub_thread+0x3a/0x1d0
    Feb 13 18:14:32 localhost cpcenter: df2e1840 3672673260 C Bo:3:006:4 -71 0
    Feb 13 18:14:32 localhost kernel: [<c1065a70>] ? wake_up_bit+0x30/0x30
    Feb 13 18:14:32 localhost kernel: [<c137b570>] ? hub_events+0x810/0x810
    Feb 13 18:14:32 localhost kernel: [<c106564c>] kthread+0x7c/0x90
    Feb 13 18:14:32 localhost cpcenter: f3c16c80 3672673292 C Bi:3:006:4 -71 0
    Feb 13 18:14:32 localhost cpcenter: df2e1d80 3672673453 C Bo:3:006:4 -71 0
    Feb 13 18:14:32 localhost cpcenter: f3c16d40 3672673553 C Bi:3:006:4 -71 0
    Feb 13 18:14:32 localhost kernel: [<c10655d0>] ? kthread_freezable_should_stop+0x60/0x60
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm read_bulk_callback
    Feb 13 18:14:32 localhost kernel: [<c14dedbe>] kernel_thread_helper+0x6/0x10
    Feb 13 18:14:32 localhost kernel: MDV 1 acm_read_bulk_callback - urb 3, len 0
    Feb 13 18:14:32 localhost kernel: MDV:cdc-acm stop_data_traffic
    Feb 13 18:14:32 localhost cpcenter: f3d19500 3672674474 C Ii:3:006:2 -108:64 0
    Feb 13 18:14:32 localhost kernel: MDV 2 acm_read_bulk_callback - disconnected
    Feb 13 18:14:32 localhost cpcenter: df2e1300 3672674636 C Bo:3:006:4 -71 0
    Feb 13 18:14:32 localhost cpcenter: f3c16140 3672674753 C Bi:3:006:4 -71 0
    

    最佳答案

    发送到您的设备的^@^@^@^A字符串是内核中的终端子系统响应来自设备的传入字节而执行回显的结果。

    您的日志中的这一行:

    Feb 13 18:14:32 localhost cpcenter: df046a80 3672670191 C Bi:3:006:4 0 4 = 00000001
    

    实际上意味着您的设备向计算机发送了4个字节(Bi表示“批量端点,输入”)。默认情况下,所有终端设备都启用了回显功能,因此内核将这些字节回显给设备,但是由于这些字节在控制字符范围内,因此它们以转义形式^@^@^@^A进行回显。这些回显的字节也将在单独的1字节写调用中发送,这对应于后续日志中的1字节批量输出URB。

    您需要修复测试程序,以便在尝试与设备通信之前关闭回显和其他tty处理。如果您的测试程序是C/C++,则cfmakeraw()函数可用于此目的。

    该程序可能在Ubuntu中运行,只是因为其他一些程序碰巧在测试程序之前触摸了端口,并更改了端口设置以关闭回显。

    关于Linux cdc_acm设备-发送给设备的意外字符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14866899/

    10-14 16:16
    查看更多