cdc_acm 드라이버를 사용하여 USB 포트에서 예기치 않은 문자를 보내는 데 문제가 있습니다. 더욱 혼란스러운 점은 코드가 Ubuntu 12.04(3.2 커널)에서는 제대로 실행되지만 Centos 6(3.6 커널)에서는 실패한다는 것입니다(이 질문의 주제).
USB 장치는 Bluegiga BLED112 Bluetooth Smart Adapter입니다. 내장된 마이크로 컨트롤러는 USB 인터페이스에서 예상치 못한 입력이 발생하면 언제든지 재설정됩니다.
테스트 코드는 포트를 열고 4바이트(안녕하세요 메시지)를 쓰고 읽기 응답을 기대합니다. 예기치 않은 문자로 인해 장치가 재설정되어 허브가 장치를 삭제하고 다시 열거하게 되므로 읽기가 완료되지 않습니다.
문제를 해결하기 위해 다음을 수행했습니다.
- cdc_acm 드라이버의 소스 코드를 다운로드합니다. 무슨 일이 일어나고 있는지 추적하기 위해 여러 개의 printk 디버그 메시지와 stack_dump를 추가했습니다.
- 나는 "재고" cdc_acm을 rmmod하고 내 계측 모듈을 insmod했습니다. 모든 장치 열거가 작동하고 올바른 드라이버가 연결되었습니다.
- 코드는 Ubuntu 12.04/Linux 3.2용이므로 3.2 cdc_acm 코드를 가져와 CentOS 6/Linux 3.6 플랫폼에서 모듈을 컴파일했습니다. 3.6 모듈 대신 3.2 모듈을 사용해도 차이가 없습니다. 3.6 모듈로 되돌아갔습니다.
- usbmon을 사용하여 디버그 파일 시스템을 열고 USB 트래픽을 관찰합니다. USB 인터페이스에서 추가 문자가 전송되는 것을 볼 수 있습니다.
- 무슨 일이 일어나고 있는지 확인하기 위해 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 및 syslog를 다시 컴파일하면 이것이 인식되지만(이상한 8) 기능에는 변화가 없음을 알 수 있습니다.
NetowrkManager도 Modem Manager도 실행되고 있지 않지만 어딘가에서 일부 모뎀 제어 기능이 실행되고 있는 것으로 의심됩니다. 어디인지는 모르겠습니다.
다음은 주석이 달린 디버그 로그입니다(MDV는 내가 cdc_acm에 추가한 printks 앞에 붙습니다).
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
이것은 애플리케이션 00 00 00 01에서 보낸 4바이트입니다.
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
답변1
더 많은 커널 추적을 추가한 후 발견했습니다.
localhost kernel: [<c12c6757>] process_echoes+0x117/0x2c0
localhost kernel: [<c12c8409>] n_tty_receive_char+0x379/0x770
localhost kernel: [<c121fce4>] ? rb_erase+0xb4/0x120
localhost kernel: [<c12c89f6>] n_tty_receive_buf+0x1f6/0x380
localhost kernel: [<c14d62cb>] ? __schedule+0x39b/0x6d0
tty 하위 시스템 에코 및 삭제 문자가 표시됩니다. 이러한 문자가 문제를 일으키고 있습니다. 다음 코드는 tty 라인 규칙을 제거하고 이제 작동합니다.
struct termios usb_termio; // set the USB to raw mode
memset(&usb_termio, 0, sizeof(usb_termio)); // clear the structure
cfmakeraw(&usb_termio);
if (tcsetattr(BLED_fd, TCSANOW, &usb_termio)< 0) {
perror("tcsetattr usb");
return(1);
}
Stack Overflow의 @Sergey Vlasov는 USB 메시지 추적을 분석하고 다른 경로에서도 동일한 결론에 도달했습니다. 그의 설명은 usbmon 출력을 더 잘 이해하는 데 도움이 되었습니다. https://stackoverflow.com/questions/14866899/linux-cdc-acm-device-unexpected-characters-sent-to-device