This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x MUSB in Host Mode, USB 2.0 High Speed Hub (STT), USB Full-Speed Quad-USB-to-UART Bridge (CP2108) Communcation Freeze

Other Parts Discussed in Thread: AM3505

Hello,

the USB communication hangs when we communicate to different UART interfaces of the Quad USB-to-UART Bridge CP2108. The Problem does not appear when we connect the cp2108 directly to the am335x musb host.


This is our hardware setup:

We assume there is a Problem of the MUSB Host with the Transaction Translator handling.

To produce the failure we run:

# echo text > /dev/ttyUSB0  /* this works */

# echo text > /dev/ttyUSB1  /* data is sent but uart disable control transfer returns timeout */

# echo text > /dev/ttyUSB1  /* no communication to cp2108 is possible */

Output of usb monitor of the Linux Kernel (tested versions 4.1.3 mainline and 3.14.26 from ti have the same behavior):

cc8e9e80 3739443171 S Co:2:003:0 s 41 00 0001 0002 0000 0
cc8e9e80 3739443410 C Co:2:003:0 0 0
cc8e9e80 3739444542 S Ci:2:003:0 s c1 1d 0000 0002 0004 4 <
cc8e9e80 3739444743 C Ci:2:003:0 0 4 = 00c20100
cc8e9e80 3739444971 S Ci:2:003:0 s c1 04 0000 0002 0002 2 <
cc8e9e80 3739445118 C Ci:2:003:0 0 2 = 0800
cc8e9e80 3739445328 S Co:2:003:0 s 41 03 0808 0002 0000 0
cc8e9e80 3739445443 C Co:2:003:0 -32 0
cc8e9e80 3739445653 S Co:2:003:0 s 41 03 0800 0002 0000 0
cc8e9e80 3739445768 C Co:2:003:0 0 0
cc8e9e80 3739445971 S Ci:2:003:0 s c1 14 0000 0002 0010 16 <
cc8e9e80 3739446211 C Ci:2:003:0 0 16 = 00000000 00000000 00000000 00000000
cc8e9e80 3739447071 S Co:2:003:0 s 41 1e 0000 0002 0004 4 = 00c20100
cc8e9e80 3739447289 C Co:2:003:0 0 4 >
ce541e80 3739447954 S Bi:2:003:3 -115 256 <
ce541e00 3739448009 S Bi:2:003:3 -115 256 <
ce06cb80 3739448052 S Co:2:003:0 s 41 07 0303 0002 0000 0
ce06cb80 3739448267 C Co:2:003:0 0 0
ce410280 3739449384 S Bo:2:003:3 -115 4 = 74657374
ce410280 3739449558 C Bo:2:003:3 0 4 >
ce410280 3739449584 S Bo:2:003:3 -115 2 = 0d0a
ce410280 3739449654 C Bo:2:003:3 0 2 >
ce06cb80 3739449803 S Co:2:003:0 s 41 07 0300 0002 0000 0
ce06cb80 3739449988 C Co:2:003:0 0 0
ce541e80 3739451587 C Bi:2:003:3 -2 0
ce541e00 3739452809 C Bi:2:003:3 -2 0
cc8e9e80 3739452884 S Co:2:003:0 s 41 00 0000 0002 0000 0
cc8e9e80 3739453034 C Co:2:003:0 0 0



cc8e9080 3750701430 S Co:2:003:0 s 41 00 0001 0001 0000 0
cc8e9080 3750701717 C Co:2:003:0 0 0
cc8e9080 3750702145 S Ci:2:003:0 s c1 1d 0000 0001 0004 4 <
cc8e9080 3750702328 C Ci:2:003:0 0 4 = 00c20100
cc8e9080 3750702548 S Ci:2:003:0 s c1 04 0000 0001 0002 2 <
cc8e9080 3750702714 C Ci:2:003:0 0 2 = 0800
cc8e9080 3750702905 S Co:2:003:0 s 41 03 0808 0001 0000 0
cc8e9080 3750703014 C Co:2:003:0 -32 0
cc8e9080 3750703236 S Co:2:003:0 s 41 03 0800 0001 0000 0
cc8e9080 3750703355 C Co:2:003:0 0 0
cc8e9080 3750703555 S Ci:2:003:0 s c1 14 0000 0001 0010 16 <
cc8e9080 3750703720 C Ci:2:003:0 0 16 = 00000000 00000000 00000000 00000000
cc8e9080 3750703924 S Co:2:003:0 s 41 1e 0000 0001 0004 4 = 00c20100
cc8e9080 3750704078 C Co:2:003:0 0 4 >
ce410780 3750704265 S Bi:2:003:2 -115 256 <
ce541c80 3750704316 S Bi:2:003:2 -115 256 <
cc8e9700 3750704352 S Co:2:003:0 s 41 07 0303 0001 0000 0
cc8e9700 3750704537 C Co:2:003:0 0 0
ce410b00 3750706417 S Bo:2:003:2 -115 4 = 74657374
ce410b00 3750707633 C Bo:2:003:2 0 4 >
ce410b00 3750707700 S Bo:2:003:2 -115 2 = 0d0a
ce410b00 3750707784 C Bo:2:003:2 0 2 >
cc8e9700 3750709321 S Co:2:003:0 s 41 07 0300 0001 0000 0
cc8e9700 3750710469 C Co:2:003:0 0 0
ce410780 3750712694 C Bi:2:003:2 -2 0
ce541c80 3750712791 C Bi:2:003:2 -2 0

cc8e9080 3750714296 S Co:2:003:0 s 41 00 0000 0001 0000 0
cc8e9080 3755712258 C Co:2:003:0 -2 0

When we replace the AM335x MUSB with a AM3505 USB Host (EHCI) everything works as expected. USB Monitor looks like this:

cf3453c0 2211057373 S Co:1:004:0 s 41 00 0001 0002 0000 0
cf3453c0 2211057647 C Co:1:004:0 0 0
cf3453c0 2211057769 S Ci:1:004:0 s c1 1d 0000 0002 0004 4 <
cf3453c0 2211058013 C Ci:1:004:0 0 4 = 00c20100
cf3453c0 2211058654 S Ci:1:004:0 s c1 04 0000 0002 0002 2 <
cf3453c0 2211059020 C Ci:1:004:0 0 2 = 0800
cf3453c0 2211059387 S Ci:1:004:0 s c1 14 0000 0002 0010 16 <
cf3453c0 2211059661 C Ci:1:004:0 0 16 = 00000000 00000000 00000000 00000000
cf3453c0 2211059722 S Co:1:004:0 s 41 1e 0000 0002 0004 4 = 00c20100
cf3453c0 2211059875 C Co:1:004:0 0 4 >
cf039e40 2211060211 S Bi:1:004:3 -115 256 <
cf3453c0 2211060272 S Co:1:004:0 s 41 07 0303 0002 0000 0
cf3453c0 2211060394 C Co:1:004:0 0 0
cf0252c0 2211060791 S Bo:1:004:3 -115 4 = 74657374
cf025340 2211060852 S Bo:1:004:3 -115 2 = 0d0a
cf0252c0 2211061035 C Bo:1:004:3 0 4 >
cf025340 2211061065 C Bo:1:004:3 0 2 >
cf3453c0 2211061187 S Co:1:004:0 s 41 07 0300 0002 0000 0
cf3453c0 2211061401 C Co:1:004:0 0 0
cf039e40 2211062042 C Bi:1:004:3 -2 0
cf3453c0 2211062072 S Co:1:004:0 s 41 00 0000 0002 0000 0
cf345440 2211062133 S Co:1:003:0 s 23 08 9043 0001 0000 0
cf3453c0 2211062255 C Co:1:004:0 0 0
cf345440 2211062500 C Co:1:003:0 0 0


cf345a40 2222885437 S Co:1:004:0 s 41 00 0001 0001 0000 0
cf345a40 2222885711 C Co:1:004:0 0 0
cf345a40 2222885803 S Ci:1:004:0 s c1 1d 0000 0001 0004 4 <
cf345a40 2222886047 C Ci:1:004:0 0 4 = 00c20100
cf345a40 2222886108 S Ci:1:004:0 s c1 04 0000 0001 0002 2 <
cf345a40 2222886322 C Ci:1:004:0 0 2 = 0800
cf345a40 2222886352 S Ci:1:004:0 s c1 14 0000 0001 0010 16 <
cf345a40 2222886566 C Ci:1:004:0 0 16 = 00000000 00000000 00000000 00000000
cf345a40 2222886596 S Co:1:004:0 s 41 1e 0000 0001 0004 4 = 00c20100
cf345a40 2222886810 C Co:1:004:0 0 4 >
cf0251c0 2222886840 S Bi:1:004:2 -115 256 <
cf345a40 2222886901 S Co:1:004:0 s 41 07 0303 0001 0000 0
cf345a40 2222887054 C Co:1:004:0 0 0
cf025dc0 2222887268 S Bo:1:004:2 -115 4 = 74657374
cf0253c0 2222887298 S Bo:1:004:2 -115 2 = 0d0a
cf025dc0 2222887420 C Bo:1:004:2 0 4 >
cf0253c0 2222887451 C Bo:1:004:2 0 2 >
cf345a40 2222888641 S Co:1:004:0 s 41 07 0300 0001 0000 0
cf345a40 2222888824 C Co:1:004:0 0 0
cf0251c0 2222888977 C Bi:1:004:2 -2 0
cf345a40 2222889190 S Co:1:004:0 s 41 00 0000 0001 0000 0
cf345a40 2222889434 C Co:1:004:0 0 0
cf345a40 2222890502 S Co:1:003:0 s 23 08 9042 0001 0000 0
cf345a40 2222890960 C Co:1:003:0 0 0

The additional request we see belong to the transcation translator. The AM335x seems to have a problem with the transaction translator handling. This problem is not listed in the AM335x errata document.

It does not make any difference if i choose DMA or PIO in the kernel config.

The problem seems to be very similar to this:

Any help is appreciated!!

Thanks!

Ludwig

  • Hi,

    I will forward this to the USB experts. Meanwhile you can check this wiki: http://processors.wiki.ti.com/index.php/Sitara_Linux_MUSB_Issues

  • I am looking forward to here from your USB experts soon.

    I am already familiar with "processors.wiki.ti.com/.../Sitara_Linux_MUSB_Issues". I`ve test with mainline 4.1.3 so there should be every patch applied you mention on this page.

    Best Regards,
    Ludwig
  • From one of our driver experts:


    We need the results from 'dmesg' with all debugging options from musb enabled. Basically, for mainline, they need to enable dynamic printk
    (CONFIG_DYNAMIC_DEBUG), increase the size of the log buffer (CONFIG_LOG_BUF_SHIFT=19) and enable debugging messages on the musb
    driver:

    # echo 'module musb_hdrc +p' > /sys/kernel/debug/dynamic_debug/control
    # echo 'module musb_dsps +p' > /sys/kernel/debug/dynamic_debug/control
    # echo 'module usbcore +p' > /sys/kernel/debug/dynamic_debug/control

    then:

    # dmesg -c > /dev/null

    then run test case, and after failure:

    # dmesg > musb-debug-output.txt

    Please forward that file. His usbmon logs show a broken pipe error, but I don't think that should be there. EPIPE is returned on STALL conditions.
    More interesting is the "No Such File Or Directory" (ENOENT) error. Were they trying to access a file that didn't exist ?

  • here is the output of dmesg:

    musb-debug-output.txt
    [  101.887000] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  103.886795] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  105.886951] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  107.886939] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  109.886949] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  110.444324] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb cc3e3180 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  110.444442] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3180 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  110.444544] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  110.444614] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  110.444993] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.445074] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.445152] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3480, count 0, urb cc3e3180, stage 1
    [  110.445215] musb-hdrc musb-hdrc.1.auto: start no-DATA
    [  110.445276] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  110.445440] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.445510] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.445583] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3480, count 0, urb cc3e3180, stage 4
    [  110.445704] musb-hdrc musb-hdrc.1.auto: complete cc3e3180 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  110.446529] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb cc3e3180 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  110.454946] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3180 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  110.455063] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  110.455131] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  110.455447] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.455527] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.455604] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3480, count 0, urb cc3e3180, stage 1
    [  110.455668] musb-hdrc musb-hdrc.1.auto: start IN-DATA
    [  110.455830] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.455900] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.455972] musb-hdrc musb-hdrc.1.auto: <== csr0 0001, qh cc3e3480, count 4, urb cc3e3180, stage 2
    [  110.456044] musb-hdrc musb-hdrc.1.auto: RX ep0 fifo d0956c20 count 4 buf cc014740
    [  110.456108] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0842
    [  110.456378] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.456451] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.456525] musb-hdrc musb-hdrc.1.auto: <== csr0 0800, qh cc3e3480, count 0, urb cc3e3180, stage 4
    [  110.456845] musb-hdrc musb-hdrc.1.auto: complete cc3e3180 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0in, 4/4
    [  110.459451] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb cc3e3180 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  110.459548] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3180 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  110.459630] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  110.459697] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  110.460002] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.460079] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.460154] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3480, count 0, urb cc3e3180, stage 1
    [  110.460216] musb-hdrc musb-hdrc.1.auto: start IN-DATA
    [  110.460375] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.460446] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.460519] musb-hdrc musb-hdrc.1.auto: <== csr0 0001, qh cc3e3480, count 2, urb cc3e3180, stage 2
    [  110.460589] musb-hdrc musb-hdrc.1.auto: RX ep0 fifo d0956c20 count 2 buf cc014740
    [  110.460652] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0842
    [  110.460801] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.460870] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.460941] musb-hdrc musb-hdrc.1.auto: <== csr0 0800, qh cc3e3480, count 0, urb cc3e3180, stage 4
    [  110.461039] musb-hdrc musb-hdrc.1.auto: complete cc3e3180 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0in, 2/2
    [  110.461577] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb cc3e3180 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  110.461665] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3180 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  110.461742] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  110.461807] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  110.462080] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.462153] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.462227] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3480, count 0, urb cc3e3180, stage 1
    [  110.462287] musb-hdrc musb-hdrc.1.auto: start IN-DATA
    [  110.462444] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.462514] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.462587] musb-hdrc musb-hdrc.1.auto: <== csr0 0001, qh cc3e3480, count 16, urb cc3e3180, stage 2
    [  110.462657] musb-hdrc musb-hdrc.1.auto: RX ep0 fifo d0956c20 count 16 buf cc014740
    [  110.462721] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0842
    [  110.462869] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.462938] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.463010] musb-hdrc musb-hdrc.1.auto: <== csr0 0800, qh cc3e3480, count 0, urb cc3e3180, stage 4
    [  110.463103] musb-hdrc musb-hdrc.1.auto: complete cc3e3180 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0in, 16/16
    [  110.463634] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb cc3e3180 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  110.463719] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3180 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  110.463796] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  110.463861] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  110.464130] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.464204] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.464278] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3480, count 0, urb cc3e3180, stage 1
    [  110.464339] musb-hdrc musb-hdrc.1.auto: start OUT-DATA
    [  110.464404] musb-hdrc musb-hdrc.1.auto: Sending 4 bytes to ep0 fifo cc014740
    [  110.464471] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 4 buf cc014740
    [  110.464627] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.464697] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.464769] musb-hdrc musb-hdrc.1.auto: <== csr0 0000, qh cc3e3480, count 0, urb cc3e3180, stage 3
    [  110.464831] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  110.464979] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.465048] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.465120] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3480, count 0, urb cc3e3180, stage 4
    [  110.465209] musb-hdrc musb-hdrc.1.auto: complete cc3e3180 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 4/4
    [  110.465726] musb-hdrc musb-hdrc.1.auto: qh cc3e3180 periodic slot 11
    [  110.465812] musb-hdrc musb-hdrc.1.auto: qh cc3e3180 urb ce70c780 dev3 ep1in-bulk, hw_ep 11, ce703800/256
    [  110.465889] musb-hdrc musb-hdrc.1.auto: <-- hw11 urb ce70c780 spd2 dev3 ep1in h_addr02 h_port04 bytes 256
    [  110.465964] musb-hdrc musb-hdrc.1.auto: RXCSR11 := 0020
    [  110.466159] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3480 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  110.466240] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3480 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  110.466328] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  110.466393] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  110.468569] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.468657] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.468735] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3b00, count 0, urb cc3e3480, stage 1
    [  110.468796] musb-hdrc musb-hdrc.1.auto: start no-DATA
    [  110.468856] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  110.469043] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.469113] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.469186] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3b00, count 0, urb cc3e3480, stage 4
    [  110.469287] musb-hdrc musb-hdrc.1.auto: complete cc3e3480 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  110.498081] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 periodic slot 10
    [  110.498192] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb ce70c880 dev3 ep1out-bulk, hw_ep 10, ce703b00/4
    [  110.498273] musb-hdrc musb-hdrc.1.auto: --> hw10 urb ce70c880 spd2 dev3 ep1out h_addr02 h_port04 bytes 4
    [  110.498361] musb-hdrc musb-hdrc.1.auto: TX ep10 fifo d0956c48 count 4 buf ce703b00
    [  110.500596] musb-hdrc musb-hdrc.1.auto: Start TX10 pio
    [  110.500892] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(400)
    [  110.500970] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0400 rx0000
    [  110.501041] musb-hdrc musb-hdrc.1.auto: OUT/TX10 end, csr 2100
    [  110.501165] musb-hdrc musb-hdrc.1.auto: complete ce70c880 usb_serial_generic_write_bulk_callback+0x0/0x17c (0), dev3 ep1out, 4/4
    [  110.502031] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 periodic slot 10
    [  110.502118] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb ce70c880 dev3 ep1out-bulk, hw_ep 10, ce703b00/2
    [  110.502197] musb-hdrc musb-hdrc.1.auto: --> hw10 urb ce70c880 spd2 dev3 ep1out h_addr02 h_port04 bytes 2
    [  110.502276] musb-hdrc musb-hdrc.1.auto: TX ep10 fifo d0956c48 count 2 buf ce703b00
    [  110.502342] musb-hdrc musb-hdrc.1.auto: Start TX10 pio
    [  110.502673] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(400)
    [  110.502746] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0400 rx0000
    [  110.502813] musb-hdrc musb-hdrc.1.auto: OUT/TX10 end, csr 2000
    [  110.502910] musb-hdrc musb-hdrc.1.auto: complete ce70c880 usb_serial_generic_write_bulk_callback+0x0/0x17c (0), dev3 ep1out, 2/2
    [  110.506530] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3480 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  110.507101] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3480 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  110.507204] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  110.507272] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  110.507552] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.507629] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.507706] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3b00, count 0, urb cc3e3480, stage 1
    [  110.507768] musb-hdrc musb-hdrc.1.auto: start no-DATA
    [  110.507830] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  110.507992] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.508062] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.508135] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3b00, count 0, urb cc3e3480, stage 4
    [  110.508243] musb-hdrc musb-hdrc.1.auto: complete cc3e3480 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  110.508644] musb-hdrc musb-hdrc.1.auto: urb=ce70c780, dev3 ep1in
    [  110.508766] musb-hdrc musb-hdrc.1.auto: complete ce70c780 usb_serial_generic_read_bulk_callback+0x0/0x1cc (0), dev3 ep1in, 0/256
    [  110.509150] musb-hdrc musb-hdrc.1.auto: ... next ep11 RX urb ce70c680
    [  110.509236] musb-hdrc musb-hdrc.1.auto: qh cc3e3180 urb ce70c680 dev3 ep1in-bulk, hw_ep 11, ce703900/256
    [  110.509314] musb-hdrc musb-hdrc.1.auto: <-- hw11 urb ce70c680 spd2 dev3 ep1in h_addr02 h_port04 bytes 256
    [  110.509383] musb-hdrc musb-hdrc.1.auto: RXCSR11 := 0020
    [  110.509481] musb-hdrc musb-hdrc.1.auto: urb=ce70c680, dev3 ep1in
    [  110.509583] musb-hdrc musb-hdrc.1.auto: complete ce70c680 usb_serial_generic_read_bulk_callback+0x0/0x1cc (0), dev3 ep1in, 0/256
    [  110.510054] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb cc3e3180 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  110.510141] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3180 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  110.510231] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  110.510296] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  110.510570] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.510643] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.510716] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3480, count 0, urb cc3e3180, stage 1
    [  110.510776] musb-hdrc musb-hdrc.1.auto: start no-DATA
    [  110.510836] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  110.510992] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  110.511062] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  110.511134] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3480, count 0, urb cc3e3180, stage 4
    [  110.511227] musb-hdrc musb-hdrc.1.auto: complete cc3e3180 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  111.886945] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  112.950506] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3200 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  112.950629] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3200 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  112.950732] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  112.950802] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  112.951187] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.951269] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.951347] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3b00, count 0, urb cc3e3200, stage 1
    [  112.951411] musb-hdrc musb-hdrc.1.auto: start no-DATA
    [  112.951472] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  112.951645] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.951716] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.951789] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3b00, count 0, urb cc3e3200, stage 4
    [  112.951909] musb-hdrc musb-hdrc.1.auto: complete cc3e3200 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  112.952878] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3200 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  112.952968] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3200 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  112.953058] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  112.953124] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  112.953421] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.953495] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.953570] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3b00, count 0, urb cc3e3200, stage 1
    [  112.953633] musb-hdrc musb-hdrc.1.auto: start IN-DATA
    [  112.953805] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.953876] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.953949] musb-hdrc musb-hdrc.1.auto: <== csr0 0001, qh cc3e3b00, count 4, urb cc3e3200, stage 2
    [  112.954020] musb-hdrc musb-hdrc.1.auto: RX ep0 fifo d0956c20 count 4 buf cc0148c0
    [  112.954084] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0842
    [  112.954234] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.954304] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.954377] musb-hdrc musb-hdrc.1.auto: <== csr0 0800, qh cc3e3b00, count 0, urb cc3e3200, stage 4
    [  112.954472] musb-hdrc musb-hdrc.1.auto: complete cc3e3200 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0in, 4/4
    [  112.955008] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3200 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  112.955094] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3200 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  112.955171] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  112.955236] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  112.955505] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.955578] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.955650] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3b00, count 0, urb cc3e3200, stage 1
    [  112.955711] musb-hdrc musb-hdrc.1.auto: start IN-DATA
    [  112.955868] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.955938] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.956010] musb-hdrc musb-hdrc.1.auto: <== csr0 0001, qh cc3e3b00, count 2, urb cc3e3200, stage 2
    [  112.956082] musb-hdrc musb-hdrc.1.auto: RX ep0 fifo d0956c20 count 2 buf cc0148c0
    [  112.956146] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0842
    [  112.956292] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.956362] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.956433] musb-hdrc musb-hdrc.1.auto: <== csr0 0800, qh cc3e3b00, count 0, urb cc3e3200, stage 4
    [  112.956524] musb-hdrc musb-hdrc.1.auto: complete cc3e3200 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0in, 2/2
    [  112.964591] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3200 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  112.964696] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3200 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  112.964778] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  112.964846] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  112.965151] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.965227] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.965301] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3b00, count 0, urb cc3e3200, stage 1
    [  112.965363] musb-hdrc musb-hdrc.1.auto: start IN-DATA
    [  112.965734] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.965805] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.965878] musb-hdrc musb-hdrc.1.auto: <== csr0 0001, qh cc3e3b00, count 16, urb cc3e3200, stage 2
    [  112.965949] musb-hdrc musb-hdrc.1.auto: RX ep0 fifo d0956c20 count 16 buf cc0148c0
    [  112.966014] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0842
    [  112.966167] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.966236] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.966307] musb-hdrc musb-hdrc.1.auto: <== csr0 0800, qh cc3e3b00, count 0, urb cc3e3200, stage 4
    [  112.966413] musb-hdrc musb-hdrc.1.auto: complete cc3e3200 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0in, 16/16
    [  112.971551] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3200 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  112.971647] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3200 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  112.971730] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  112.971796] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  112.972110] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.972186] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.972261] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3b00, count 0, urb cc3e3200, stage 1
    [  112.972324] musb-hdrc musb-hdrc.1.auto: start OUT-DATA
    [  112.972388] musb-hdrc musb-hdrc.1.auto: Sending 4 bytes to ep0 fifo cc0148c0
    [  112.972455] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 4 buf cc0148c0
    [  112.972618] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.972688] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.972761] musb-hdrc musb-hdrc.1.auto: <== csr0 0000, qh cc3e3b00, count 0, urb cc3e3200, stage 3
    [  112.972824] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  112.972974] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.973045] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.973119] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3b00, count 0, urb cc3e3200, stage 4
    [  112.973218] musb-hdrc musb-hdrc.1.auto: complete cc3e3200 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 4/4
    [  112.977531] musb-hdrc musb-hdrc.1.auto: qh cc3e3200 periodic slot 11
    [  112.977626] musb-hdrc musb-hdrc.1.auto: qh cc3e3200 urb ce70ca80 dev3 ep2in-bulk, hw_ep 11, ce703a00/256
    [  112.977704] musb-hdrc musb-hdrc.1.auto: <-- hw11 urb ce70ca80 spd2 dev3 ep2in h_addr02 h_port04 bytes 256
    [  112.977779] musb-hdrc musb-hdrc.1.auto: RXCSR11 := 0020
    [  112.977986] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb cc3e3b00 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  112.978067] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3b00 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  112.978158] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  112.978224] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  112.978563] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.978639] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.978711] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3480, count 0, urb cc3e3b00, stage 1
    [  112.978913] musb-hdrc musb-hdrc.1.auto: start no-DATA
    [  112.978974] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  112.979137] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.979205] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.979276] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3480, count 0, urb cc3e3b00, stage 4
    [  112.979377] musb-hdrc musb-hdrc.1.auto: complete cc3e3b00 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  112.980621] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 periodic slot 10
    [  112.980714] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb ce70cb80 dev3 ep2out-bulk, hw_ep 10, ce703f00/4
    [  112.980793] musb-hdrc musb-hdrc.1.auto: --> hw10 urb ce70cb80 spd2 dev3 ep2out h_addr02 h_port04 bytes 4
    [  112.980873] musb-hdrc musb-hdrc.1.auto: TX ep10 fifo d0956c48 count 4 buf ce703f00
    [  112.980939] musb-hdrc musb-hdrc.1.auto: Start TX10 pio
    [  112.981267] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(400)
    [  112.981470] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0400 rx0000
    [  112.981543] musb-hdrc musb-hdrc.1.auto: OUT/TX10 end, csr 2100
    [  112.981653] musb-hdrc musb-hdrc.1.auto: complete ce70cb80 usb_serial_generic_write_bulk_callback+0x0/0x17c (0), dev3 ep2out, 4/4
    [  112.983141] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 periodic slot 10
    [  112.983233] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb ce70cb80 dev3 ep2out-bulk, hw_ep 10, ce703f00/2
    [  112.983309] musb-hdrc musb-hdrc.1.auto: --> hw10 urb ce70cb80 spd2 dev3 ep2out h_addr02 h_port04 bytes 2
    [  112.983390] musb-hdrc musb-hdrc.1.auto: TX ep10 fifo d0956c48 count 2 buf ce703f00
    [  112.983455] musb-hdrc musb-hdrc.1.auto: Start TX10 pio
    [  112.983816] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(400)
    [  112.983890] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0400 rx0000
    [  112.983958] musb-hdrc musb-hdrc.1.auto: OUT/TX10 end, csr 2000
    [  112.984054] musb-hdrc musb-hdrc.1.auto: complete ce70cb80 usb_serial_generic_write_bulk_callback+0x0/0x17c (0), dev3 ep2out, 2/2
    [  112.987636] musb-hdrc musb-hdrc.1.auto: qh cc3e3480 urb cc3e3b00 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  112.987734] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3b00 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  112.987827] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  112.987892] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  112.988211] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.988285] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.988359] musb-hdrc musb-hdrc.1.auto: <== csr0 0200, qh cc3e3480, count 0, urb cc3e3b00, stage 1
    [  112.988420] musb-hdrc musb-hdrc.1.auto: start no-DATA
    [  112.988481] musb-hdrc musb-hdrc.1.auto: ep0 STATUS, csr 0860
    [  112.988737] musb-hdrc musb-hdrc.1.auto: usbintr (0) epintr(1)
    [  112.988808] musb-hdrc musb-hdrc.1.auto: ** IRQ host usb0000 tx0001 rx0000
    [  112.988882] musb-hdrc musb-hdrc.1.auto: <== csr0 0841, qh cc3e3480, count 0, urb cc3e3b00, stage 4
    [  112.988986] musb-hdrc musb-hdrc.1.auto: complete cc3e3b00 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  112.990858] musb-hdrc musb-hdrc.1.auto: urb=ce70ca80, dev3 ep2in
    [  112.990994] musb-hdrc musb-hdrc.1.auto: complete ce70ca80 usb_serial_generic_read_bulk_callback+0x0/0x1cc (0), dev3 ep2in, 0/256
    [  112.995444] musb-hdrc musb-hdrc.1.auto: ... next ep11 RX urb ce70cb00
    [  112.995544] musb-hdrc musb-hdrc.1.auto: qh cc3e3200 urb ce70cb00 dev3 ep2in-bulk, hw_ep 11, ce703e00/256
    [  112.995624] musb-hdrc musb-hdrc.1.auto: <-- hw11 urb ce70cb00 spd2 dev3 ep2in h_addr02 h_port04 bytes 256
    [  112.995694] musb-hdrc musb-hdrc.1.auto: RXCSR11 := 0020
    [  112.995795] musb-hdrc musb-hdrc.1.auto: urb=ce70cb00, dev3 ep2in
    [  112.995908] musb-hdrc musb-hdrc.1.auto: complete ce70cb00 usb_serial_generic_read_bulk_callback+0x0/0x1cc (0), dev3 ep2in, 0/256
    [  112.999119] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3200 dev3 ep0out, hw_ep 0, cc0147c0/8
    [  112.999212] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3200 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  112.999306] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc0147c0
    [  112.999373] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  113.886955] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  115.886948] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  117.886937] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  117.997283] musb-hdrc musb-hdrc.1.auto: urb=cc3e3200, dev3 ep0out
    [  117.997462] musb-hdrc musb-hdrc.1.auto: complete cc3e3200 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  117.997929] usb 2-1.4: bash timed out on ep0out len=0/0
    [  117.998041] cp210x ttyUSB1: cp210x_set_config - Unable to send request, request=0x0 size=2 result=-110
    [  119.886947] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  120.308024] musb-hdrc musb-hdrc.1.auto: qh cc3e3b00 urb cc3e3200 dev3 ep0out, hw_ep 0, cc014840/8
    [  120.308139] musb-hdrc musb-hdrc.1.auto: --> hw0 urb cc3e3200 spd2 dev3 ep0out h_addr02 h_port04 bytes 8
    [  120.308229] musb-hdrc musb-hdrc.1.auto: TX ep0 fifo d0956c20 count 8 buf cc014840
    [  120.308299] musb-hdrc musb-hdrc.1.auto: Start TX0 pio
    [  121.887080] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  123.886948] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  125.307497] musb-hdrc musb-hdrc.1.auto: urb=cc3e3200, dev3 ep0out
    [  125.307688] musb-hdrc musb-hdrc.1.auto: complete cc3e3200 usb_api_blocking_completion+0x0/0x2c (0), dev3 ep0out, 0/0
    [  125.313533] usb 2-1.4: bash timed out on ep0out len=0/0
    [  125.313664] cp210x ttyUSB1: cp210x_set_config - Unable to send request, request=0x0 size=2 result=-110
    [  125.331296] cp210x ttyUSB1: cp210x_open - Unable to enable UART
    [  125.886956] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  127.886949] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    [  129.886951] musb-hdrc musb-hdrc.0.auto: Poll devctl 88 (b_idle)
    

  • Hello,

    was it possible for you to have a look a the debug output?

    Any new information?

    Thank You.

    Ludwig
  • From the debug output, it appears that the driver has indeed locked up.

    We are working to repro the issue here, but it may take several days to complete the testing. An answer will be posted here when available.

  • We were unable to repro the issue here using a different hub (we don't have the Cypress). Would it be possible to try a different hub on your side and see if the issue persists?

  • Hello,

    I am a colleague of Ludwig.

    Today we have tested it with different hubs and the result was not always the same. We repro the same problems with hama hub which has Genesys Logic hub controller integrated. But we also found one hub which works correctly (terminus technology inc hub controller). So we are sure, that the problem does not only exist with Cypress Hub.
    Which hardware do you use for testing? Do you have done the tests with different hubs? Do you use the silicon Labs evaluation board for your tests?

    Best regards,
    Andreas
  • We've tested two hubs, but aren't sure of the actual silicon vendors as the reseller (Pluggable) has re-programmed the VID/PID via EEPROM.

    We will try with more hubs. Also, I've ordered the Cypress eval board for testing this issue, I'll update this thread with results.
  • Hello Dave,

    do you already use the SiliconLabs Evaluation-Kit "CP2108EK" as well?

    Regards, Robert
  • -RG- said:
    Hello Dave,

    do you already use the SiliconLabs Evaluation-Kit "CP2108EK" as well?

    Regards, Robert

    It's on order. We used 4x UART devices in our previous testing.

  • Hello Dave,

    now we have done some tests with the following HW: Beaglebone Black + hama hub (Genesys Logic hub controller) + SiliconLabs Evaluation-Kit "CP2108EK"

    On beaglebone black we are using standard image "bone-debian-7.8-lxde-4gb-armhf-2015-03-01-4gb.img" with 3.8.13 Kernel. The problem here is exactly the same like on our hardware and kernel.

    Here you can see the log file:

    Starting kernel ...

     

    Uncompressing Linux... done, booting the kernel.

    [    0.372805] omap2_mbox_probe: platform not supported

    [    0.527769] tps65217-bl tps65217-bl: no platform data provided

    [    0.591101] bone-capemgr bone_capemgr.9: slot #0: No cape found

    [    0.628206] bone-capemgr bone_capemgr.9: slot #1: No cape found

    [    0.665315] bone-capemgr bone_capemgr.9: slot #2: No cape found

    [    0.702424] bone-capemgr bone_capemgr.9: slot #3: No cape found

    [    0.718218] bone-capemgr bone_capemgr.9: slot #6: BB-BONELT-HDMIN conflict P8.45 (#5:BB-BONELT-HDMI)

    [    0.727844] bone-capemgr bone_capemgr.9: slot #6: Failed verification

    [    0.734591] bone-capemgr bone_capemgr.9: loader: failed to load slot-6 BB-BONELT-HDMIN:00A0 (prio 2)

    [    0.751007] omap_hsmmc mmc.5: of_parse_phandle_with_args of 'reset' failed

    [    0.814043] pinctrl-single 44e10800.pinmux: pin 44e10854 already requested by 44e10800.pinmux; cannot claim for gpio-leds.8

    [    0.825725] pinctrl-single 44e10800.pinmux: pin-21 (gpio-leds.8) status -22

    [    0.833028] pinctrl-single 44e10800.pinmux: could not request pin 21 on device pinctrl-single

    Loading, please wait...

    systemd-fsck[224]: rootfs: clean, 84849/230608 files, 482416/922368 blocks

     

    Debian GNU/Linux 7 beaglebone ttyO0

     

    BeagleBoard.org Debian Image 2015-03-01

     

    Support/FAQ: http://elinux.org/Beagleboard:BeagleBoneBlack_Debian

     

    default username:password is [debian:temppwd]

     

    The IP Address for usb0 is: 192.168.7.2

    beaglebone login: root

    Last login: Sun Mar  1 20:55:31 UTC 2015 on ttyO0

    Linux beaglebone 3.8.13-bone70 #1 SMP Fri Jan 23 02:15:42 UTC 2015 armv7l

     

    The programs included with the Debian GNU/Linux system are free software;

    the exact distribution terms for each program are described in the

    individual files in /usr/share/doc/*/copyright.

     

    Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent

    permitted by applicable law.

    root@beaglebone:~#

    root@beaglebone:~# lsusb -tv

    /:  Bus 02.Port 1: Dev 1, class="root_hub", Driver=musb-hdrc/1p, 480M

    /:  Bus 01.Port 1: Dev 1, class="root_hub", Driver=musb-hdrc/1p, 480M

        |__ Port 1: Dev 2, If 0, class="hub", Driver=hub/4p, 480M

            |__ Port 4: Dev 3, If 0, class="hub", Driver=hub/4p, 480M

                |__ Port 3: Dev 4, If 0, class="vend"., Driver=cp210x, 12M

                |__ Port 3: Dev 4, If 1, class="vend"., Driver=cp210x, 12M

                |__ Port 3: Dev 4, If 2, class="vend"., Driver=cp210x, 12M

                |__ Port 3: Dev 4, If 3, class="vend"., Driver=cp210x, 12M

    root@beaglebone:~# u[   32.199854] libphy: PHY 4a101000.mdio:01 not found

    [   32.204955] net eth0: phy 4a101000.mdio:01 not found on slave 1

    name -a

    Linux beaglebone 3.8.13-bone70 #1 SMP Fri Jan 23 02:15:42 UTC 2015 armv7l GNU/Linux

    root@beaglebone:~# echo Hallo >/dev/ttyUSB0

    root@beaglebone:~# echo Hallo >/dev/ttyUSB0

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB0

    [   76.335485] cp210x ttyUSB0: cp210x_open - Unable to enable UART

    -bash: /dev/ttyUSB0: Input/output error

    root@beaglebone:~#

    Best regards,

    Andreas

  • Hello,

    now we have also done some tests with FTDI USB to serial devices. We are using beaglebone black with "bone-debian-7.8-lxde-4gb-armhf-2015-03-01-4gb.img" image for our tests. On the USB Host port we have connected 4port USB Hub μPD720114 from Renesas and four FTDI 1222-C devices are connected to the hub.

    With this configuration we have roughly the same problems. Below you can see the log files:

    root@beaglebone:~# echo Hallo >/dev/ttyUSB0

    root@beaglebone:~# echo Hallo >/dev/ttyUSB0

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~#

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB3

    root@beaglebone:~# echo Hallo >/dev/ttyUSB3

    root@beaglebone:~# echo Hallo >/dev/ttyUSB3

    root@beaglebone:~# echo Hallo >/dev/ttyUSB3

    root@beaglebone:~# echo Hallo >/dev/ttyUSB3

    root@beaglebone:~# echo Hallo >/dev/ttyUSB4

    root@beaglebone:~# echo Hallo >/dev/ttyUSB0

    root@beaglebone:~# echo Hallo >/dev/ttyUSB1

    root@beaglebone:~# echo Hallo >/dev/ttyUSB2

    root@beaglebone:~# echo Hallo >/dev/ttyUSB3

    [   73.751584] ftdi_sio ttyUSB3: ftdi_set_termios FAILED to set databits/stopbits/parity

    [   74.761257] ftdi_sio ttyUSB3: ftdi_set_termios urb failed to set baudrate

    [   84.769085] ftdi_sio ttyUSB3: urb failed to clear flow control

    root@beaglebone:~#

    Best regards,

    Andreas

  • Hello,

    do you have any news for us? We are quite in time pressure and need an solution...

    Best regards,

    Andreas

  • Andreas,

    We are able to duplicate the issue with cp2108 on both AM335x board and PC, so it seems to be cp2108 specific. It is still under debugging. We will keep you posted.

  • Hello,

    cp2108 is working with AM35x and i.MX6 without any problems. Only AM335x has the described problems.

    Best regards,

    Andreas

  • Andreas,

    I am not sure about iMX6, but AM35x has an EHCI controller (unless you used the otg port), while AM335x has a MUSB controller. We also replicated the issue on an PC, even on AM437x, which has xHCI.

    It seems the issue is related to timing - how fast to send data to the uart port. But at this moment it is not clear to us that what causes the issue. It is still under investigation.

  • Hello Bin Liu,

    were you able to get some results with your investigations?

    Do you have a workaround?

    Best regards,
    Ludwig
  • Hi Ludwig,

    We are still debugging this issue and the root cause is still unclear yet. We don't have a workaround yet.

  • Ludwig,

    I just found the following kernel commit gives me an issue with USB hub. Can you please revert this patch to see if it has any effect on this issue you reported?

    My coworker took away the CP2108 from me to debug this issue, so I am unable to validate it in your use case on my end at this moment.

    dd97dc6 usb: musb: musb_host: Enable HCD_BH flag to handle urb return in bottom half
  • Hi,

    I did test it but it was the same behavior then before.


    Just to be clear, i did test the following:

    --- a/drivers/usb/musb/musb_host.c
    +++ b/drivers/usb/musb/musb_host.c
    @@ -2613,7 +2613,7 @@ static const struct hc_driver musb_hc_driver = {
            .description            = "musb-hcd",
            .product_desc           = "MUSB HDRC host driver",
            .hcd_priv_size          = sizeof(struct musb *),
    -       .flags                  = HCD_USB2 | HCD_MEMORY | HCD_BH,
    +       .flags                  = HCD_USB2 | HCD_MEMORY, /* | HCD_BH,*/
     
            /* not using irq handler or reset hooks from usbcore, since
             * those must be shared with peripheral code for OTG configs

    Best regards,

    Ludwig

  • Hello Bin Liu,


    were you able to make some progress on the issue?

    Thank You!

    Best regards,

    Ludwig

  • Hello Bin Liu,

    i did some further investigations  and did a test with the "MUSB_POWER_HSENAB" flag disabled after reading the thread because they mentioned not to have the problem with a USB 1.0 hub. The am335x and USB Hub connection is limited to full-speed with this setting.

     

    --- a/drivers/usb/musb/musb_core.c

    +++ b/drivers/usb/musb/musb_core.c

    @@ -1022,7 +1022,7 @@ void musb_start(struct musb *musb)

           /* put into basic highspeed mode and start session */

           musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE

    -                       | MUSB_POWER_HSENAB

    +                       /* | MUSB_POWER_HSENAB  */

                           /* ENSUSPEND wedges tusb */

                           /* | MUSB_POWER_ENSUSPEND */

                      );

    The issue does not appear with this configuration. But we do need the high-speed in our project.

    Best regards,

    Ludwig

  • Ludwig,

    We were able to replicate the issue with CP2108 on AM335x board, AM437x board, and PC, with or without a hub. What we found was that at the failure point CP2108 just decides to stop responding to host's IN tokens, so we believe the problem is on CP2108, not AM335x.

    Is it possible to use both MUSB controllers on your board? If so, you can configure one controller to full-speed only to work with CP2108, then use another controller for other high-speed devices.
  • Hello Bin Liu,

    thank you very much for your answers and your investigations. I am already in contact with the cp2108 silicon vendor.

    We are using one USB port in device mode and the second one in host mode. We need this to be solved ...

    Best regards,

    Ludwig

  • Hello Bin and Ludwig,

    I have following setup musb <-> GL850 HUB <-> FT2232C. During a test, that consists of baudrate changes and data transmission, I get tons of:

    ftdi_sio ttyUSB8: ftdi_set_termios FAILED to set databits/stopbits/parity
    ftdi_sio ttyUSB8: ftdi_set_termios urb failed to set baudrate
    ftdi_sio ttyUSB8: urb failed to clear flow control

    As in Ludwig's case I don't experiences issues with connecting this chip to musb directly. I've run the same test on a x86 for some hours and there were no errors.

    Using FT4232H i.e. high-speed device makes no problems.

    Kernels used from 3.2 till 4.2.

    Regards,
    Yegor

  • Hello Bin,

    with the silabs support we discovered that there have to be two errors.

    The first one is in the cp2108 (or driver cp210x). The silabs support provided a new cp210x driver which did solve the problem on PC with USB XHCI ports and maybe some other situations.

    The second error must be caused by the am335x musb (i think now). I found this in the musb_host.c:

            /* Enable bulk RX/TX NAK timeout scheme when bulk requests are
             * multiplexed. This scheme does not work in high speed to full
             * speed scenario as NAK interrupts are not coming from a
             * full speed device connected to a high speed device.
             * NAK timeout interval is 8 (128 uframe or 16ms) for HS and
             * 4 (8 frame or 8ms) for FS device.
             */

    Could this cause the problem?

    I appended the latest driver cp210x.c which I have got from silabs to this post.

    8345.CP210x.c
    /*
     * Silicon Laboratories CP210x USB to RS232 serial adaptor driver
     *
     * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
     *
     *	This program is free software; you can redistribute it and/or
     *	modify it under the terms of the GNU General Public License version
     *	2 as published by the Free Software Foundation.
     *
     * Support to set flow control line levels using TIOCMGET and TIOCMSET
     * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
     * control thanks to Munir Nassar nassarmu@real-time.com
     *
     */
    
    #include <linux/kernel.h>
    #include <linux/errno.h>
    #include <linux/slab.h>
    #include <linux/tty.h>
    #include <linux/tty_flip.h>
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/usb.h>
    #include <linux/uaccess.h>
    #include <linux/usb/serial.h>
    
    #define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
    
    /*
     * Function Prototypes
     */
    static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
    static void cp210x_close(struct usb_serial_port *);
    static int cp210x_ioctl(struct tty_struct *tty, unsigned int cmd,
    	unsigned long arg);
    static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
    static void cp210x_get_termios_port(struct usb_serial_port *port,
    	unsigned int *cflagp, unsigned int *baudp);
    static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
    							struct ktermios *);
    static bool cp210x_tx_empty(struct usb_serial_port *);
    static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
    							struct ktermios*);
    static int cp210x_tiocmget(struct tty_struct *);
    static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
    static int cp210x_tiocmset_port(struct usb_serial_port *port,
    		unsigned int, unsigned int);
    static void cp210x_break_ctl(struct tty_struct *, int);
    static int cp210x_startup(struct usb_serial *);
    static void cp210x_release(struct usb_serial *);
    static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
    
    static const struct usb_device_id id_table[] = {
    	{ USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
    	{ USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
    	{ USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
    	{ USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
    	{ USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
    	{ USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
    	{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
    	{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
    	{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
    	{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
    	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
    	{ USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
    	{ USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
    	{ USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */
    	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
    	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
    	{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
    	{ USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */
    	{ USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */
    	{ USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */
    	{ USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
    	{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
    	{ USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */
    	{ USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */
    	{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
    	{ USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
    	{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
    	{ USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */
    	{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
    	{ USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */
    	{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
    	{ USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
    	{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
    	{ USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
    	{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
    	{ USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
    	{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
    	{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
    	{ USB_DEVICE(0x2405, 0x0003) }, /* West Mountain Radio RIGblaster Advantage */
    	{ USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */
    	{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
    	{ USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */
    	{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
    	{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
    	{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
    	{ USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */
    	{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
    	{ USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
    	{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
    	{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
    	{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
    	{ USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
    	{ USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
    	{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
    	{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
    	{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
    	{ USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
    	{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
    	{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
    	{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
    	{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
    	{ USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
    	{ USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
    	{ USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
    	{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
    	{ USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
    	{ USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
    	{ USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
    	{ USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
    	{ USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
    	{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
    	{ USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
    	{ USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
    	{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
    	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
    	{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
    	{ USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */
    	{ USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
    	{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
    	{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
    	{ USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
    	{ USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
    	{ USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
    	{ USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
    	{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
    	{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
    	{ USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
    	{ USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */
    	{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
    	{ USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */
    	{ USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
    	{ USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
    	{ USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
    	{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
    	{ USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
    	{ USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
    	{ USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
    	{ USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
    	{ USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */
    	{ USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */
    	{ USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
    	{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
    	{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
    	{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
    	{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
    	{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
    	{ USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
    	{ USB_DEVICE(0x1FB9, 0x0100) }, /* Lake Shore Model 121 Current Source */
    	{ USB_DEVICE(0x1FB9, 0x0200) }, /* Lake Shore Model 218A Temperature Monitor */
    	{ USB_DEVICE(0x1FB9, 0x0201) }, /* Lake Shore Model 219 Temperature Monitor */
    	{ USB_DEVICE(0x1FB9, 0x0202) }, /* Lake Shore Model 233 Temperature Transmitter */
    	{ USB_DEVICE(0x1FB9, 0x0203) }, /* Lake Shore Model 235 Temperature Transmitter */
    	{ USB_DEVICE(0x1FB9, 0x0300) }, /* Lake Shore Model 335 Temperature Controller */
    	{ USB_DEVICE(0x1FB9, 0x0301) }, /* Lake Shore Model 336 Temperature Controller */
    	{ USB_DEVICE(0x1FB9, 0x0302) }, /* Lake Shore Model 350 Temperature Controller */
    	{ USB_DEVICE(0x1FB9, 0x0303) }, /* Lake Shore Model 371 AC Bridge */
    	{ USB_DEVICE(0x1FB9, 0x0400) }, /* Lake Shore Model 411 Handheld Gaussmeter */
    	{ USB_DEVICE(0x1FB9, 0x0401) }, /* Lake Shore Model 425 Gaussmeter */
    	{ USB_DEVICE(0x1FB9, 0x0402) }, /* Lake Shore Model 455A Gaussmeter */
    	{ USB_DEVICE(0x1FB9, 0x0403) }, /* Lake Shore Model 475A Gaussmeter */
    	{ USB_DEVICE(0x1FB9, 0x0404) }, /* Lake Shore Model 465 Three Axis Gaussmeter */
    	{ USB_DEVICE(0x1FB9, 0x0600) }, /* Lake Shore Model 625A Superconducting MPS */
    	{ USB_DEVICE(0x1FB9, 0x0601) }, /* Lake Shore Model 642A Magnet Power Supply */
    	{ USB_DEVICE(0x1FB9, 0x0602) }, /* Lake Shore Model 648 Magnet Power Supply */
    	{ USB_DEVICE(0x1FB9, 0x0700) }, /* Lake Shore Model 737 VSM Controller */
    	{ USB_DEVICE(0x1FB9, 0x0701) }, /* Lake Shore Model 776 Hall Matrix */
    	{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
    	{ USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
    	{ USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
    	{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
    	{ } /* Terminating Entry */
    };
    
    MODULE_DEVICE_TABLE(usb, id_table);
    
    struct cp210x_port_private {
    	__u8			bInterfaceNumber;
    	__u8			bPartNumber;
    	bool            Swap_GET_LINE_CTL; /* CP2108 returns swapped bytes due to a bug */
    };
    
    static struct usb_serial_driver cp210x_device = {
    	.driver = {
    		.owner =	THIS_MODULE,
    		.name =		"cp210x",
    	},
    	.id_table		= id_table,
    	.num_ports		= 1,
    	.bulk_in_size		= 256,
    	.bulk_out_size		= 256,
    	.open			= cp210x_open,
    	.close			= cp210x_close,
    	.ioctl			= cp210x_ioctl,
    	.break_ctl		= cp210x_break_ctl,
    	.set_termios		= cp210x_set_termios,
    	.tx_empty       = cp210x_tx_empty,
    	.tiocmget		= cp210x_tiocmget,
    	.tiocmset		= cp210x_tiocmset,
    	.attach			= cp210x_startup,
    	.release		= cp210x_release,
    	.dtr_rts		= cp210x_dtr_rts
    };
    
    /* Part number definitions */
    #define CP2101_PARTNUM		0x01
    #define CP2102_PARTNUM		0x02
    #define CP2103_PARTNUM		0x03
    #define CP2104_PARTNUM		0x04
    #define CP2105_PARTNUM		0x05
    #define CP2108_PARTNUM		0x08
    
    /* IOCTLs */
    #define IOCTL_GPIOGET		0x8000
    #define IOCTL_GPIOSET		0x8001
    
    static struct usb_serial_driver * const serial_drivers[] = {
    	&cp210x_device, NULL
    };
    
    /* Config request types */
    #define REQTYPE_HOST_TO_INTERFACE	0x41
    #define REQTYPE_INTERFACE_TO_HOST	0xc1
    #define REQTYPE_HOST_TO_DEVICE	0x40
    #define REQTYPE_DEVICE_TO_HOST	0xc0
    
    /* Config request codes */
    #define CP210X_IFC_ENABLE	0x00
    #define CP210X_SET_BAUDDIV	0x01
    #define CP210X_GET_BAUDDIV	0x02
    #define CP210X_SET_LINE_CTL	0x03
    #define CP210X_GET_LINE_CTL	0x04
    #define CP210X_SET_BREAK	0x05
    #define CP210X_IMM_CHAR		0x06
    #define CP210X_SET_MHS		0x07
    #define CP210X_GET_MDMSTS	0x08
    #define CP210X_SET_XON		0x09
    #define CP210X_SET_XOFF		0x0A
    #define CP210X_SET_EVENTMASK	0x0B
    #define CP210X_GET_EVENTMASK	0x0C
    #define CP210X_SET_CHAR		0x0D
    #define CP210X_GET_CHARS	0x0E
    #define CP210X_GET_PROPS	0x0F
    #define CP210X_GET_COMM_STATUS	0x10
    #define CP210X_RESET		0x11
    #define CP210X_PURGE		0x12
    #define CP210X_SET_FLOW		0x13
    #define CP210X_GET_FLOW		0x14
    #define CP210X_EMBED_EVENTS	0x15
    #define CP210X_GET_EVENTSTATE	0x16
    #define CP210X_SET_CHARS	0x19
    #define CP210X_GET_BAUDRATE	0x1D
    #define CP210X_SET_BAUDRATE	0x1E
    #define CP210X_VENDOR_SPECIFIC	0xFF
    
    /* CP210X_IFC_ENABLE */
    #define UART_ENABLE		0x0001
    #define UART_DISABLE		0x0000
    
    /* CP210X_VENDOR_SPECIFIC */
    #define CP210X_WRITE_LATCH	0x37E1
    #define CP210X_READ_LATCH	0x00C2
    #define CP210X_GET_PARTNUM	0x370B
    
    /* CP210X_(SET|GET)_BAUDDIV */
    #define BAUD_RATE_GEN_FREQ	0x384000
    
    /* CP210X_(SET|GET)_LINE_CTL */
    #define BITS_DATA_MASK		0X0f00
    #define BITS_DATA_5		0X0500
    #define BITS_DATA_6		0X0600
    #define BITS_DATA_7		0X0700
    #define BITS_DATA_8		0X0800
    #define BITS_DATA_9		0X0900
    
    #define BITS_PARITY_MASK	0x00f0
    #define BITS_PARITY_NONE	0x0000
    #define BITS_PARITY_ODD		0x0010
    #define BITS_PARITY_EVEN	0x0020
    #define BITS_PARITY_MARK	0x0030
    #define BITS_PARITY_SPACE	0x0040
    
    #define BITS_STOP_MASK		0x000f
    #define BITS_STOP_1		0x0000
    #define BITS_STOP_1_5		0x0001
    #define BITS_STOP_2		0x0002
    
    /* CP210X_SET_BREAK */
    #define BREAK_ON		0x0001
    #define BREAK_OFF		0x0000
    
    /* CP210X_(SET_MHS|GET_MDMSTS) */
    #define CONTROL_DTR		0x0001
    #define CONTROL_RTS		0x0002
    #define CONTROL_CTS		0x0010
    #define CONTROL_DSR		0x0020
    #define CONTROL_RING		0x0040
    #define CONTROL_DCD		0x0080
    #define CONTROL_WRITE_DTR	0x0100
    #define CONTROL_WRITE_RTS	0x0200
    
    // Data returned by CP210X_GET_COMM_STATUS --
    // same as SERIAL_STATUS in ntddser.h plus one byte
    // The h/w doc says it's 0x0013 bytes
    
    struct CP210X_COMM_STATUS {
    	u32     ulErrors;
    	u32     ulHoldReasons;
    	u32     ulAmountInInQueue;
    	u32     ulAmountInOutQueue;
    	u8      bEofReceived;
    	u8      bWaitForImmediate;
    	u8      bReserved;
    };
    
    /*
     * cp210x_get_config
     * Reads from the CP210x configuration registers
     * 'size' is specified in bytes.
     * 'data' is a pointer to a pre-allocated array of integers large
     * enough to hold 'size' bytes (with 4 bytes to each integer)
     */
    static int cp210x_get_config(struct usb_serial_port *port, u8 requestType,
    		u8 request, int value, unsigned int *data, int size)
    {
    	struct usb_serial *serial = port->serial;
    	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
    	__le32 *buf;
    	int result, i, length;
    
    	/* Number of integers required to contain the array */
    	length = (((size - 1) | 3) + 1) / 4;
    
    	buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
    	if (!buf) {
    		dev_err(&port->dev, "%s - out of memory.\n", __func__);
    		return -ENOMEM;
    	}
    
    	/* Issue the request, attempting to read 'size' bytes */
    	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
    				request, requestType, value,
    				port_priv->bInterfaceNumber, buf, size, USB_CTRL_GET_TIMEOUT);
    
    	/* Convert data into an array of integers */
    	for (i = 0; i < length; i++)
    		data[i] = le32_to_cpu(buf[i]);
    
    	kfree(buf);
    
    	if (result != size) {
    		dev_dbg(&port->dev, "%s - Unable to send config request, request=0x%x size=%d result=%d\n",
    			__func__, request, size, result);
    		if (result > 0)
    			result = -EPROTO;
    
    		return result;
    	}
    
    	return 0;
    }
    
    /*
     * cp210x_set_config
     * Writes to the CP210x configuration registers
     * Values less than 16 bits wide are sent directly
     * 'size' is specified in bytes.
     */
    static int cp210x_set_config(struct usb_serial_port *port, u8 requestType,
    		u8 request, int value, unsigned int *data, int size)
    {
    	struct usb_serial *serial = port->serial;
    	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
    	__le32 *buf = NULL;
    	int result, i, length = 0;
    
    	if (size)
    	{
    		/* Number of integers required to contain the array */
    		length = (((size - 1) | 3) + 1) / 4;
    
    		buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
    		if (!buf) {
    			dev_err(&port->dev, "%s - out of memory.\n", __func__);
    			return -ENOMEM;
    		}
    
    		/* Array of integers into bytes */
    		for (i = 0; i < length; i++)
    			buf[i] = cpu_to_le32(data[i]);
    	}
    
    	result = usb_control_msg(serial->dev,
    			usb_sndctrlpipe(serial->dev, 0),
    			request, requestType, value,
    			port_priv->bInterfaceNumber, buf, size, USB_CTRL_SET_TIMEOUT);
    
    	if (buf)
    		kfree(buf);
    
    	if (result != size) {
    		dev_dbg(&port->dev, "%s - Unable to send request, request=0x%x size=%d result=%d\n",
    			__func__, request, size, result);
    		if (result > 0)
    			result = -EPROTO;
    
    		return result;
    	}
    
    	return 0;
    }
    
    static bool cp210x_tx_empty(struct usb_serial_port *port)
    {
    	int err;
    
    	/* Looks like get_config may write beyond end of buffer if it's not multiple of 4; pad it to 0x14 bytes */
    	struct CP210X_COMM_STATUS_CONTAINER {
    		struct CP210X_COMM_STATUS  sts;
    		u8                         pad_to_0x14_bytes;
    	} comm_sts_cont;
    
    	err = cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    			CP210X_GET_COMM_STATUS, 0, (unsigned int *) &comm_sts_cont, 0x13);
    
    	if (!err) {
    		if (comm_sts_cont.sts.ulAmountInOutQueue)
    			return false;
    	}
    	return true;
    }
    
    /*
     * cp210x_quantise_baudrate
     * Quantises the baud rate as per AN205 Table 1
     */
    static unsigned int cp210x_quantise_baudrate(unsigned int baud)
    {
    	if (baud <= 300)
    		baud = 300;
    	else if (baud <= 600)      baud = 600;
    	else if (baud <= 1200)     baud = 1200;
    	else if (baud <= 1800)     baud = 1800;
    	else if (baud <= 2400)     baud = 2400;
    	else if (baud <= 4000)     baud = 4000;
    	else if (baud <= 4803)     baud = 4800;
    	else if (baud <= 7207)     baud = 7200;
    	else if (baud <= 9612)     baud = 9600;
    	else if (baud <= 14428)    baud = 14400;
    	else if (baud <= 16062)    baud = 16000;
    	else if (baud <= 19250)    baud = 19200;
    	else if (baud <= 28912)    baud = 28800;
    	else if (baud <= 38601)    baud = 38400;
    	else if (baud <= 51558)    baud = 51200;
    	else if (baud <= 56280)    baud = 56000;
    	else if (baud <= 58053)    baud = 57600;
    	else if (baud <= 64111)    baud = 64000;
    	else if (baud <= 77608)    baud = 76800;
    	else if (baud <= 117028)   baud = 115200;
    	else if (baud <= 129347)   baud = 128000;
    	else if (baud <= 156868)   baud = 153600;
    	else if (baud <= 237832)   baud = 230400;
    	else if (baud <= 254234)   baud = 250000;
    	else if (baud <= 273066)   baud = 256000;
    	else if (baud <= 491520)   baud = 460800;
    	else if (baud <= 567138)   baud = 500000;
    	else if (baud <= 670254)   baud = 576000;
    	else if (baud < 1000000)
    		baud = 921600;
    	else if (baud > 2000000)
    		baud = 2000000;
    	return baud;
    }
    
    static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
    {
    	int err;
    
    	err = cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    			CP210X_IFC_ENABLE, UART_ENABLE, NULL, 0);
    	if (err) {
    		dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);
    		return err;
    	}
    
    	/* Configure the termios structure */
    	cp210x_get_termios(tty, port);
    
    	/* The baud rate must be initialised on cp2104 */
    	if (tty)
    		cp210x_change_speed(tty, port, NULL);
    
    	return usb_serial_generic_open(tty, port);
    }
    
    static void cp210x_close(struct usb_serial_port *port)
    {
    	usb_serial_generic_close(port);
    	cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    		CP210X_IFC_ENABLE, UART_DISABLE, NULL, 0);
    }
    
    static int cp210x_ioctl(struct tty_struct *tty,
    	unsigned int cmd, unsigned long arg)
    {
    	struct usb_serial_port *port = tty->driver_data;
    	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
    	int result = 0;
    	unsigned long latch_buf = 0;
    
    	switch (cmd) {
    
    	case IOCTL_GPIOGET:
    		if ((port_priv->bPartNumber == CP2103_PARTNUM) ||
    			(port_priv->bPartNumber == CP2104_PARTNUM)) {
    			result = cp210x_get_config(port,
    					REQTYPE_DEVICE_TO_HOST,
    					CP210X_VENDOR_SPECIFIC,
    					CP210X_READ_LATCH,
    					(unsigned int*)&latch_buf, 1);
    			if (result != 0)
    				return result;
    			if (copy_to_user((unsigned int*)arg, &latch_buf, 1))
         				return -EFAULT;
    			return 0;
    		}
    		else if (port_priv->bPartNumber == CP2105_PARTNUM) {
    			result = cp210x_get_config(port,
    					REQTYPE_INTERFACE_TO_HOST,
    					CP210X_VENDOR_SPECIFIC,
    					CP210X_READ_LATCH,
    					(unsigned int*)&latch_buf, 1);
    			if (result != 0)
    				return result;
    			if (copy_to_user((unsigned int*)arg, &latch_buf, 1))
         				return -EFAULT;
    			return 0;
    		}
    		else if (port_priv->bPartNumber == CP2108_PARTNUM) {
    			result = cp210x_get_config(port,
    					REQTYPE_DEVICE_TO_HOST,
    					CP210X_VENDOR_SPECIFIC,
    					CP210X_READ_LATCH,
    					(unsigned int*)&latch_buf, 2);
    			if (result != 0)
    				return result;
    			if (copy_to_user((unsigned int*)arg, &latch_buf, 2))
         				return -EFAULT;
    			return 0;
    		}
    		else {
    			return -ENOTSUPP;
    		}
    		break;
    
    	case IOCTL_GPIOSET:
    		if ((port_priv->bPartNumber == CP2103_PARTNUM) ||
    			(port_priv->bPartNumber == CP2104_PARTNUM)) {
    			if (copy_from_user(&latch_buf, (unsigned int*)arg, 2))
         				return -EFAULT;
    			result = usb_control_msg(port->serial->dev,
    					usb_sndctrlpipe(port->serial->dev, 0),
    					CP210X_VENDOR_SPECIFIC,
    					REQTYPE_HOST_TO_DEVICE,
    					CP210X_WRITE_LATCH,
    					latch_buf,
    					NULL, 0, USB_CTRL_SET_TIMEOUT);
    			if (result != 0)
    				return result;
    			return 0;
    		}
    		else if (port_priv->bPartNumber == CP2105_PARTNUM) {
    			if (copy_from_user(&latch_buf, (unsigned int*)arg, 2))
         				return -EFAULT;
    			return cp210x_set_config(port, 
    					REQTYPE_HOST_TO_INTERFACE,
    					CP210X_VENDOR_SPECIFIC,
    					CP210X_WRITE_LATCH,
    					(unsigned int*)&latch_buf, 2);
    		}
    		else if (port_priv->bPartNumber == CP2108_PARTNUM) {
    			if (copy_from_user(&latch_buf, (unsigned int*)arg, 4))
         				return -EFAULT;
    			return cp210x_set_config(port, REQTYPE_HOST_TO_DEVICE,
    					CP210X_VENDOR_SPECIFIC,
    					CP210X_WRITE_LATCH,
    					(unsigned int*)&latch_buf, 4);
    		}
    		else {
    			return -ENOTSUPP;
    		}
    		break;
    
    	default:
    		break;
    	}
    
    	return -ENOIOCTLCMD;
    }
    
    /*
     * cp210x_get_termios
     * Reads the baud rate, data bits, parity, stop bits and flow control mode
     * from the device, corrects any unsupported values, and configures the
     * termios structure to reflect the state of the device
     */
    static void cp210x_get_termios(struct tty_struct *tty,
    	struct usb_serial_port *port)
    {
    	unsigned int baud;
    
    	if (tty) {
    		cp210x_get_termios_port(tty->driver_data,
    			&tty->termios.c_cflag, &baud);
    		tty_encode_baud_rate(tty, baud, baud);
    	} else {
    		unsigned int cflag;
    		cflag = 0;
    		cp210x_get_termios_port(port, &cflag, &baud);
    	}
    }
    
    static void cp210x_maybe_swap_LINE_CTL(struct usb_serial_port *port, u16 *pval)
    {
    	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
    
    	if (port_priv->Swap_GET_LINE_CTL)
    		*pval = ((*pval & 0xff) >> 8) | (*pval << 8);
    }
    
    /*
     * cp210x_get_termios_port
     * This is the heart of cp210x_get_termios which always uses a &usb_serial_port.
     */
    static void cp210x_get_termios_port(struct usb_serial_port *port,
    	unsigned int *cflagp, unsigned int *baudp)
    {
    	struct device *dev = &port->dev;
    	unsigned int cflag, modem_ctl[4];
    	unsigned int baud;
    	unsigned int bits;
    
    	cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    			CP210X_GET_BAUDRATE, 0, &baud, 4);
    
    	dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud);
    	*baudp = baud;
    
    	cflag = *cflagp;
    
    	cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    			CP210X_GET_LINE_CTL, 0, &bits, 2);
    	cp210x_maybe_swap_LINE_CTL( port, (u16*) &bits);
    
    	cflag &= ~CSIZE;
    	switch (bits & BITS_DATA_MASK) {
    	case BITS_DATA_5:
    		dev_dbg(dev, "%s - data bits = 5\n", __func__);
    		cflag |= CS5;
    		break;
    	case BITS_DATA_6:
    		dev_dbg(dev, "%s - data bits = 6\n", __func__);
    		cflag |= CS6;
    		break;
    	case BITS_DATA_7:
    		dev_dbg(dev, "%s - data bits = 7\n", __func__);
    		cflag |= CS7;
    		break;
    	case BITS_DATA_8:
    		dev_dbg(dev, "%s - data bits = 8\n", __func__);
    		cflag |= CS8;
    		break;
    	case BITS_DATA_9:
    		dev_dbg(dev, "%s - data bits = 9 (not supported, using 8 data bits)\n", __func__);
    		cflag |= CS8;
    		bits &= ~BITS_DATA_MASK;
    		bits |= BITS_DATA_8;
    		cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_LINE_CTL, bits, NULL, 0);
    		break;
    	default:
    		dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__);
    		cflag |= CS8;
    		bits &= ~BITS_DATA_MASK;
    		bits |= BITS_DATA_8;
    		cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_LINE_CTL, bits, NULL, 0);
    		break;
    	}
    
    	switch (bits & BITS_PARITY_MASK) {
    	case BITS_PARITY_NONE:
    		dev_dbg(dev, "%s - parity = NONE\n", __func__);
    		cflag &= ~PARENB;
    		break;
    	case BITS_PARITY_ODD:
    		dev_dbg(dev, "%s - parity = ODD\n", __func__);
    		cflag |= (PARENB|PARODD);
    		break;
    	case BITS_PARITY_EVEN:
    		dev_dbg(dev, "%s - parity = EVEN\n", __func__);
    		cflag &= ~PARODD;
    		cflag |= PARENB;
    		break;
    	case BITS_PARITY_MARK:
    		dev_dbg(dev, "%s - parity = MARK\n", __func__);
    		cflag |= (PARENB|PARODD|CMSPAR);
    		break;
    	case BITS_PARITY_SPACE:
    		dev_dbg(dev, "%s - parity = SPACE\n", __func__);
    		cflag &= ~PARODD;
    		cflag |= (PARENB|CMSPAR);
    		break;
    	default:
    		dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__);
    		cflag &= ~PARENB;
    		bits &= ~BITS_PARITY_MASK;
    		cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_LINE_CTL, bits, NULL, 0);
    		break;
    	}
    
    	cflag &= ~CSTOPB;
    	switch (bits & BITS_STOP_MASK) {
    	case BITS_STOP_1:
    		dev_dbg(dev, "%s - stop bits = 1\n", __func__);
    		break;
    	case BITS_STOP_1_5:
    		dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__);
    		bits &= ~BITS_STOP_MASK;
    		cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_LINE_CTL, bits, NULL, 0);
    		break;
    	case BITS_STOP_2:
    		dev_dbg(dev, "%s - stop bits = 2\n", __func__);
    		cflag |= CSTOPB;
    		break;
    	default:
    		dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__);
    		bits &= ~BITS_STOP_MASK;
    		cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_LINE_CTL, bits, NULL, 0);
    		break;
    	}
    
    	cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    			CP210X_GET_FLOW, 0, modem_ctl, 16);
    	if (modem_ctl[0] & 0x0008) {
    		dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
    		cflag |= CRTSCTS;
    	} else {
    		dev_dbg(dev, "%s - flow control = NONE\n", __func__);
    		cflag &= ~CRTSCTS;
    	}
    
    	*cflagp = cflag;
    }
    
    /*
     * CP2101 supports the following baud rates:
     *
     *	300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
     *	38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
     *
     * CP2102 and CP2103 support the following additional rates:
     *
     *	4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
     *	576000
     *
     * The device will map a requested rate to a supported one, but the result
     * of requests for rates greater than 1053257 is undefined (see AN205).
     *
     * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
     * respectively, with an error less than 1%. The actual rates are determined
     * by
     *
     *	div = round(freq / (2 x prescale x request))
     *	actual = freq / (2 x prescale x div)
     *
     * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
     * or 1 otherwise.
     * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
     * otherwise.
     */
    static void cp210x_change_speed(struct tty_struct *tty,
    		struct usb_serial_port *port, struct ktermios *old_termios)
    {
    	u32 baud;
    
    	baud = tty->termios.c_ospeed;
    
    	/* This maps the requested rate to a rate valid on cp2102 or cp2103,
    	 * or to an arbitrary rate in [1M,2M].
    	 *
    	 * NOTE: B0 is not implemented.
    	 */
    	baud = cp210x_quantise_baudrate(baud);
    
    	dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud);
    	if (cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    			CP210X_SET_BAUDRATE, 0, &baud, sizeof(baud))) {
    		dev_warn(&port->dev, "failed to set baud rate to %u\n", baud);
    		if (old_termios)
    			baud = old_termios->c_ospeed;
    		else
    			baud = 9600;
    	}
    
    	tty_encode_baud_rate(tty, baud, baud);
    }
    
    static void cp210x_set_termios(struct tty_struct *tty,
    		struct usb_serial_port *port, struct ktermios *old_termios)
    {
    	struct device *dev = &port->dev;
    	unsigned int cflag, old_cflag;
    	unsigned int bits;
    	unsigned int modem_ctl[4];
    
    	cflag = tty->termios.c_cflag;
    	old_cflag = old_termios->c_cflag;
    
    	if (tty->termios.c_ospeed != old_termios->c_ospeed)
    		cp210x_change_speed(tty, port, old_termios);
    
    	/* If the number of data bits is to be updated */
    	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
    		cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    				CP210X_GET_LINE_CTL, 0, &bits, 2);
    		cp210x_maybe_swap_LINE_CTL( port, (u16*)  &bits);
    		bits &= ~BITS_DATA_MASK;
    		switch (cflag & CSIZE) {
    		case CS5:
    			bits |= BITS_DATA_5;
    			dev_dbg(dev, "%s - data bits = 5\n", __func__);
    			break;
    		case CS6:
    			bits |= BITS_DATA_6;
    			dev_dbg(dev, "%s - data bits = 6\n", __func__);
    			break;
    		case CS7:
    			bits |= BITS_DATA_7;
    			dev_dbg(dev, "%s - data bits = 7\n", __func__);
    			break;
    		case CS8:
    			bits |= BITS_DATA_8;
    			dev_dbg(dev, "%s - data bits = 8\n", __func__);
    			break;
    		/*case CS9:
    			bits |= BITS_DATA_9;
    			dev_dbg(dev, "%s - data bits = 9\n", __func__);
    			break;*/
    		default:
    			dev_dbg(dev, "cp210x driver does not support the number of bits requested, using 8 bit mode\n");
    			bits |= BITS_DATA_8;
    			break;
    		}
    		if (cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_LINE_CTL, bits, NULL, 0))
    			dev_dbg(dev, "Number of data bits requested not supported by device\n");
    	}
    
    	if ((cflag     & (PARENB|PARODD|CMSPAR)) !=
    	    (old_cflag & (PARENB|PARODD|CMSPAR))) {
    		cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    				CP210X_GET_LINE_CTL, 0, &bits, 2);
    		cp210x_maybe_swap_LINE_CTL( port, (u16*) &bits);
    		bits &= ~BITS_PARITY_MASK;
    		if (cflag & PARENB) {
    			if (cflag & CMSPAR) {
    				if (cflag & PARODD) {
    					bits |= BITS_PARITY_MARK;
    					dev_dbg(dev, "%s - parity = MARK\n", __func__);
    				} else {
    					bits |= BITS_PARITY_SPACE;
    					dev_dbg(dev, "%s - parity = SPACE\n", __func__);
    				}
    			} else {
    				if (cflag & PARODD) {
    					bits |= BITS_PARITY_ODD;
    					dev_dbg(dev, "%s - parity = ODD\n", __func__);
    				} else {
    					bits |= BITS_PARITY_EVEN;
    					dev_dbg(dev, "%s - parity = EVEN\n", __func__);
    				}
    			}
    		}
    		if (cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_LINE_CTL, bits, NULL, 0))
    			dev_dbg(dev, "Parity mode not supported by device\n");
    	}
    
    	if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
    		cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    				CP210X_GET_LINE_CTL, 0, &bits, 2);
    		cp210x_maybe_swap_LINE_CTL( port, (u16*) &bits);
    		bits &= ~BITS_STOP_MASK;
    		if (cflag & CSTOPB) {
    			bits |= BITS_STOP_2;
    			dev_dbg(dev, "%s - stop bits = 2\n", __func__);
    		} else {
    			bits |= BITS_STOP_1;
    			dev_dbg(dev, "%s - stop bits = 1\n", __func__);
    		}
    		if (cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_LINE_CTL, bits, NULL, 0))
    			dev_dbg(dev, "Number of stop bits requested not supported by device\n");
    	}
    
    	if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
    		cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    				CP210X_GET_FLOW, 0, modem_ctl, 16);
    		dev_dbg(dev, "%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n",
    			__func__, modem_ctl[0], modem_ctl[1],
    			modem_ctl[2], modem_ctl[3]);
    
    		if (cflag & CRTSCTS) {
    			modem_ctl[0] &= ~0x7B;
    			modem_ctl[0] |= 0x09;
    			modem_ctl[1] = 0x80;
    			dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
    		} else {
    			modem_ctl[0] &= ~0x7B;
    			modem_ctl[0] |= 0x01;
    			modem_ctl[1] |= 0x40;
    			dev_dbg(dev, "%s - flow control = NONE\n", __func__);
    		}
    
    		dev_dbg(dev, "%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n",
    			__func__, modem_ctl[0], modem_ctl[1],
    			modem_ctl[2], modem_ctl[3]);
    		cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_FLOW, 0, modem_ctl, 16);
    	}
    
    }
    
    static int cp210x_tiocmset(struct tty_struct *tty,
    		unsigned int set, unsigned int clear)
    {
    	struct usb_serial_port *port = tty->driver_data;
    	return cp210x_tiocmset_port(port, set, clear);
    }
    
    static int cp210x_tiocmset_port(struct usb_serial_port *port,
    		unsigned int set, unsigned int clear)
    {
    	unsigned int control = 0;
    
    	if (set & TIOCM_RTS) {
    		control |= CONTROL_RTS;
    		control |= CONTROL_WRITE_RTS;
    	}
    	if (set & TIOCM_DTR) {
    		control |= CONTROL_DTR;
    		control |= CONTROL_WRITE_DTR;
    	}
    	if (clear & TIOCM_RTS) {
    		control &= ~CONTROL_RTS;
    		control |= CONTROL_WRITE_RTS;
    	}
    	if (clear & TIOCM_DTR) {
    		control &= ~CONTROL_DTR;
    		control |= CONTROL_WRITE_DTR;
    	}
    
    	dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control);
    
    	return cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    				CP210X_SET_MHS, control, NULL, 0);
    }
    
    static void cp210x_dtr_rts(struct usb_serial_port *p, int on)
    {
    	if (on)
    		cp210x_tiocmset_port(p, TIOCM_DTR|TIOCM_RTS, 0);
    	else
    		cp210x_tiocmset_port(p, 0, TIOCM_DTR|TIOCM_RTS);
    }
    
    static int cp210x_tiocmget(struct tty_struct *tty)
    {
    	struct usb_serial_port *port = tty->driver_data;
    	unsigned int control;
    	int result;
    
    	cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    			CP210X_GET_MDMSTS, 0, &control, 1);
    
    	result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
    		|((control & CONTROL_RTS) ? TIOCM_RTS : 0)
    		|((control & CONTROL_CTS) ? TIOCM_CTS : 0)
    		|((control & CONTROL_DSR) ? TIOCM_DSR : 0)
    		|((control & CONTROL_RING)? TIOCM_RI  : 0)
    		|((control & CONTROL_DCD) ? TIOCM_CD  : 0);
    
    	dev_dbg(&port->dev, "%s - control = 0x%.2x\n", __func__, control);
    
    	return result;
    }
    
    static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
    {
    	struct usb_serial_port *port = tty->driver_data;
    	unsigned int state;
    
    	if (break_state == 0)
    		state = BREAK_OFF;
    	else
    		state = BREAK_ON;
    	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
    		state == BREAK_OFF ? "off" : "on");
    	cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    			CP210X_SET_BREAK, state, NULL, 0);
    }
    
    static int cp210x_startup(struct usb_serial *serial)
    {
    	struct usb_host_interface *cur_altsetting;
    	struct cp210x_port_private *port_priv;
    	int i;
    	unsigned int partNum;
    
    	for (i = 0; i < serial->num_ports; i++) {
    		unsigned int line_ctl;
    		int err;
    
    		port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
    		if (!port_priv)
    			return -ENOMEM;
    
    		cur_altsetting = serial->interface->cur_altsetting;
    		port_priv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber;
    
    		usb_set_serial_port_data(serial->port[i], port_priv);
    
    		/* Get the 1-byte part number of the cp210x device */
    		err = cp210x_get_config(serial->port[i],
    			REQTYPE_DEVICE_TO_HOST, CP210X_VENDOR_SPECIFIC,
    			CP210X_GET_PARTNUM, &partNum, 1);
    		if (err)
    			return err;
    		port_priv->bPartNumber = partNum & 0xFF;
    
    		/* Detect CP2108 bug and activate workaround.
    		 * Write a known good value 0x800, read it back.
    		 * If it comes back swapped the bug is detected.
    		 */
    		port_priv->Swap_GET_LINE_CTL = false;
    
    		err = cp210x_set_config(serial->port[i], REQTYPE_HOST_TO_INTERFACE,
    			CP210X_SET_LINE_CTL, 0x800, NULL, 0);
    		if (err)
    			return err;
    		err = cp210x_get_config(serial->port[i], REQTYPE_INTERFACE_TO_HOST,
    			CP210X_GET_LINE_CTL, 0, &line_ctl, 2);
    		if (err)
    			return err;
    		if ((line_ctl & 0xffff) == 8) {
    			port_priv->Swap_GET_LINE_CTL = true;
    			dev_err(&serial->port[i]->dev, "%s Swap_GET_LINE_CTL ON\n", __func__);
    		}
    	}
    	return 0;
    }
    
    static void cp210x_release(struct usb_serial *serial)
    {
    	struct cp210x_port_private *port_priv;
    	int i;
    
    	for (i = 0; i < serial->num_ports; i++) {
    		port_priv = usb_get_serial_port_data(serial->port[i]);
    		kfree(port_priv);
    	}
    }
    
    module_usb_serial_driver(serial_drivers, id_table);
    
    MODULE_DESCRIPTION(DRIVER_DESC);
    MODULE_LICENSE("GPL");
    

    Information from the silabs support team after a look at my capture of the usb communication between am335x and the hub (download the capture data here: ):

    I see some strange things (see listing below). Looks like the host doesn't frame some Control Transfer data correctly - the USB analyzer doesn't recognize it as Control Transfer. It does this 2 times, gets an error, then sends the same data correctly and succeeds. Then later it gets a NAK twice for cr,lf and then succeeds on the third try.

    Maybe the first malformed packet confused the hub and it stopped functioning correctly?

    I think it can be beneficial to take 2 USB traces simultaneously - host-hub and hub-cp2108, so we can see how the hub is passing packets.

    Index dev:EP
    ...
    3604 3:1 Hallo - ok
    3615 3:1 cr. lf - ok
    ...
    4080 3:1 Hallo - ok
    4091 3:1 cr. lf - ok
    ...
    4639 3:0 - NAK - malformed packet? Contains the same CP210X_GET_COMM_STATUS data as CT below
    4644 3:0 - NAK - malformed packet? Contains the same CP210X_GET_COMM_STATUS data as CT below
    4677 3:0 CT ok

    4730 - 3:2 OUT cr/lf - NAK
    4735 - 3:2 OUT cr/lf - NAK
    4756 - 3:2 OUT cr/lf - ok

    I append a capture of the usb communication between hub and the cp2108, too. (Appended to this post.)

    bbb_4.1.5_silabdrv_hub2cp2108.tdc.zip

    You can view this with the Total Phase Data Center.

    I did the following while capturing the USB traffic:

    # echo Hallo >/dev/ttyUSB0
    # echo Hallo >/dev/ttyUSB0
    # echo Hallo >/dev/ttyUSB1
    # echo Hallo >/dev/ttyUSB0

    Please have a look at it.


    Thank you!

    Best regards,

    Ludwig

  • Hello Yegor,

    maybe it is possible for you to have a look at my latest post. It could be the solution for FT2232C connected with a HS USB hub to am335x musb, too.

    Best regards,
    Ludwig
  • Hello Ludwig,

    AFAIK you've discovered two issues. One could be fixed in drivers/usb/serial/cp210x.c directly, but the remaining one has still something to do with MUSB subsystem. Btw. file 8345.CP210x.c doesn't  help much as one needs to know the exact commit in order to see the fix.

    The solution would be, if MUSB is fixed for our case. Right or am I missing some solution from your previous post?

    Regards,

    Yegor

  • Hello Yegor,

    Ludwig is back again in office on Monday. He will report next week.

    Thanks and best regards,

    Andreas

  • Hi Yegor,


    the driver 8345.CP210x.c is not based on the mainline kernel sources. I append you a diff to the previous version which is available on the silabs website so you can see what was done.

    cp210x_silabs.diff
    --- /home/lzenz/workspace/dhcom/am335x/kernel/cp210x.c
    +++ /home/lzenz/cp210x.diff
    @@ -38,6 +38,7 @@
     	unsigned int *cflagp, unsigned int *baudp);
     static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
     							struct ktermios *);
    +static bool cp210x_tx_empty(struct usb_serial_port *);
     static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
     							struct ktermios*);
     static int cp210x_tiocmget(struct tty_struct *);
    @@ -188,6 +189,7 @@
     struct cp210x_port_private {
     	__u8			bInterfaceNumber;
     	__u8			bPartNumber;
    +	bool            Swap_GET_LINE_CTL; /* CP2108 returns swapped bytes due to a bug */
     };
     
     static struct usb_serial_driver cp210x_device = {
    @@ -204,6 +206,7 @@
     	.ioctl			= cp210x_ioctl,
     	.break_ctl		= cp210x_break_ctl,
     	.set_termios		= cp210x_set_termios,
    +	.tx_empty       = cp210x_tx_empty,
     	.tiocmget		= cp210x_tiocmget,
     	.tiocmset		= cp210x_tiocmset,
     	.attach			= cp210x_startup,
    @@ -308,6 +311,20 @@
     #define CONTROL_WRITE_DTR	0x0100
     #define CONTROL_WRITE_RTS	0x0200
     
    +// Data returned by CP210X_GET_COMM_STATUS --
    +// same as SERIAL_STATUS in ntddser.h plus one byte
    +// The h/w doc says it's 0x0013 bytes
    +
    +struct CP210X_COMM_STATUS {
    +	u32     ulErrors;
    +	u32     ulHoldReasons;
    +	u32     ulAmountInInQueue;
    +	u32     ulAmountInOutQueue;
    +	u8      bEofReceived;
    +	u8      bWaitForImmediate;
    +	u8      bReserved;
    +};
    +
     /*
      * cp210x_get_config
      * Reads from the CP210x configuration registers
    @@ -403,6 +420,26 @@
     	}
     
     	return 0;
    +}
    +
    +static bool cp210x_tx_empty(struct usb_serial_port *port)
    +{
    +	int err;
    +
    +	/* Looks like get_config may write beyond end of buffer if it's not multiple of 4; pad it to 0x14 bytes */
    +	struct CP210X_COMM_STATUS_CONTAINER {
    +		struct CP210X_COMM_STATUS  sts;
    +		u8                         pad_to_0x14_bytes;
    +	} comm_sts_cont;
    +
    +	err = cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
    +			CP210X_GET_COMM_STATUS, 0, (unsigned int *) &comm_sts_cont, 0x13);
    +
    +	if (!err) {
    +		if (comm_sts_cont.sts.ulAmountInOutQueue)
    +			return false;
    +	}
    +	return true;
     }
     
     /*
    @@ -449,13 +486,13 @@
     
     static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
     {
    -	int result;
    -
    -	result = cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
    +	int err;
    +
    +	err = cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE,
     			CP210X_IFC_ENABLE, UART_ENABLE, NULL, 0);
    -	if (result) {
    +	if (err) {
     		dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);
    -		return result;
    +		return err;
     	}
     
     	/* Configure the termios structure */
    @@ -595,6 +632,14 @@
     	}
     }
     
    +static void cp210x_maybe_swap_LINE_CTL(struct usb_serial_port *port, u16 *pval)
    +{
    +	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
    +
    +	if (port_priv->Swap_GET_LINE_CTL)
    +		*pval = ((*pval & 0xff) >> 8) | (*pval << 8);
    +}
    +
     /*
      * cp210x_get_termios_port
      * This is the heart of cp210x_get_termios which always uses a &usb_serial_port.
    @@ -617,6 +662,8 @@
     
     	cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
     			CP210X_GET_LINE_CTL, 0, &bits, 2);
    +	cp210x_maybe_swap_LINE_CTL( port, (u16*) &bits);
    +
     	cflag &= ~CSIZE;
     	switch (bits & BITS_DATA_MASK) {
     	case BITS_DATA_5:
    @@ -792,6 +839,7 @@
     	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
     		cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
     				CP210X_GET_LINE_CTL, 0, &bits, 2);
    +		cp210x_maybe_swap_LINE_CTL( port, (u16*)  &bits);
     		bits &= ~BITS_DATA_MASK;
     		switch (cflag & CSIZE) {
     		case CS5:
    @@ -828,6 +876,7 @@
     	    (old_cflag & (PARENB|PARODD|CMSPAR))) {
     		cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
     				CP210X_GET_LINE_CTL, 0, &bits, 2);
    +		cp210x_maybe_swap_LINE_CTL( port, (u16*) &bits);
     		bits &= ~BITS_PARITY_MASK;
     		if (cflag & PARENB) {
     			if (cflag & CMSPAR) {
    @@ -856,6 +905,7 @@
     	if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
     		cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST,
     				CP210X_GET_LINE_CTL, 0, &bits, 2);
    +		cp210x_maybe_swap_LINE_CTL( port, (u16*) &bits);
     		bits &= ~BITS_STOP_MASK;
     		if (cflag & CSTOPB) {
     			bits |= BITS_STOP_2;
    @@ -984,6 +1034,9 @@
     	unsigned int partNum;
     
     	for (i = 0; i < serial->num_ports; i++) {
    +		unsigned int line_ctl;
    +		int err;
    +
     		port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
     		if (!port_priv)
     			return -ENOMEM;
    @@ -994,12 +1047,32 @@
     		usb_set_serial_port_data(serial->port[i], port_priv);
     
     		/* Get the 1-byte part number of the cp210x device */
    -		cp210x_get_config(serial->port[i],
    +		err = cp210x_get_config(serial->port[i],
     			REQTYPE_DEVICE_TO_HOST, CP210X_VENDOR_SPECIFIC,
     			CP210X_GET_PARTNUM, &partNum, 1);
    +		if (err)
    +			return err;
     		port_priv->bPartNumber = partNum & 0xFF;
    -	}
    -
    +
    +		/* Detect CP2108 bug and activate workaround.
    +		 * Write a known good value 0x800, read it back.
    +		 * If it comes back swapped the bug is detected.
    +		 */
    +		port_priv->Swap_GET_LINE_CTL = false;
    +
    +		err = cp210x_set_config(serial->port[i], REQTYPE_HOST_TO_INTERFACE,
    +			CP210X_SET_LINE_CTL, 0x800, NULL, 0);
    +		if (err)
    +			return err;
    +		err = cp210x_get_config(serial->port[i], REQTYPE_INTERFACE_TO_HOST,
    +			CP210X_GET_LINE_CTL, 0, &line_ctl, 2);
    +		if (err)
    +			return err;
    +		if ((line_ctl & 0xffff) == 8) {
    +			port_priv->Swap_GET_LINE_CTL = true;
    +			dev_err(&serial->port[i]->dev, "%s Swap_GET_LINE_CTL ON\n", __func__);
    +		}
    +	}
     	return 0;
     }
     
    


    Yes, i think that the solution would be to fix the MUSB.

    I am not that familiar with USB to do it myself. So i do need support from TI or somebody else on this issue.

    Best regards,

    Ludwig

  • I noticed the following two new patches on linux-usb mailing list today, but don't have time to test them out yet. Would you mind it give it a try?

    [PATCH] USB: serial: cp210x: Adding tx_empty() to avoid cp2108 failure

    [PATCH] USB: serial: cp210x: Workaround for cp2108 failure due to GET_LINE_CTL bug

  • Hello Bin,

    these are the same fixes which i got from silabs. (see the diff i posted for yegor) They fix the bug 1 (see above) and another problem which repairs some configuration control transfers (not handled in this thread).

    They do not repair the problem 2 with MUSB for which i made a suggestion some comments before:

    Please have a look at it.


    Best regards,

    Ludwig

  • Hello Bin,


    are the any news on this issue? Do you need some further information.

    What do you think about my assumption of the error-cause?

    Best regards,

    Ludwig

  • Hello,

    was someone able to have a look at the latest informations. Any news?

    Best regards,

    Ludwig

  • Ludwig,

    I am actively working on this issue. Currently I am seeking for help from our USB hub expert to understand what could cause the hub to NAK the SSplit of SETUP packets. I will update once I have progress.
  • Hello Bin,


    can you give an update on the issue?


    Thank you very much!


    Best regards,

    Ludwig

  • Ludwig,

    We are able to replicate the issue with a TI hub, and getting help from the hub team.

    We ordered the sync cable for USB protocol analyzers so that we can capture the USB bus traces simultaneously before and after the hub. Right now we are waiting for the cable shipment, which is slow.

  • Hello Bin,


    did you get the required cable? Can you provide some information about your progress?


    We are running out of time. It is very important for us to get as many information as possible as soon as possible. Do you think the problem can be fixed by software?


    Best regards,

    Ludwig

  • Ludwig,

    We received the cable on last Thursday. It was back-ordered. We have been reviewing the bus traces and other factors, but haven't found any thing which could lead to the hub lockup yet. The process will be slow as most folks are out this week for US holidays.

    Until the root cause is identified, we cannot tell if the issue is fixable or not.
  • Hello Bin,


    we're still interested on a solution. Were you able to do some further investigations?

    Best regards,

    Ludwig

  • Ludwig,
    We have examined the issue at length and do not find anything on the interface that explains the behavior. There are no errors or protocol violations and no differences between "good" and "bad" hub transactions.

    From the protocol analyzer trace we can see that the hub itself will simply stop passing downstream transactions to the UART device and then continually NAK any attempt from the Host to communicate with (or recover) the downstream device. The hub port itself seems to be broken. As you mentioned, this issue doesn't occur without a hub.

    At this point we would recommend you contact the hub vendor for their assistance with the issue.
  • Hello,

    thank you for your efforts. Since TI is a hub vendor we don't want to get in contact with a third vendor. So the solution/reason remains in the dark for now.

    In our current project we use a different hardware setup.

    For future projects, it would still be interesting to have a solution to this problem.

    Best regards,

    Ludwig