tag:blogger.com,1999:blog-7648765300997881292024-03-13T23:04:02.789-07:00BeagleBoard - USB Sniffer (GSoC 2010)drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.comBlogger21125tag:blogger.com,1999:blog-764876530099788129.post-56547315193615590052010-08-09T03:57:00.000-07:002010-08-09T03:59:11.575-07:00Weekly report - Week 11Pencil down is today, so it's probably my last weekly report...<br /><br />Status:<ul><li>Improved the documentation on my <a href="http://www.elinux.org/BeagleBoard/GSoC/2010_Projects/USBSniffer">wiki page</a>, including a paragraph about a potential problem with bandwidth allocation.</li><li>Got my <a href="http://fpga4u.epfl.ch/">FPGA4U</a> to work.</li><li>No success at getting the TI MSP430 Launchpad to work...</li><li>Attempted to add support for high-bandwidth isochronous endpoints, but it hit yet another bug in the MUSB driver, happening even with DMA disabled...</li></ul>Plans:<ul><li>I may be able to fix the MSP430 problem...</li></ul>Risks:<ul><li>?</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com3tag:blogger.com,1999:blog-764876530099788129.post-12774671287587765442010-08-02T04:22:00.000-07:002010-08-02T04:23:02.219-07:00Weekly report - Week 10Status:<ul><li>Dynamic sizing of MUSB FIFOs: there is a new module parameter, <tt>fifo_config</tt>, that allows to set the FIFO configuration for each endpoint. An example would be: <tt>ep1in:1024,ep3out:32,ep4in:512</tt>. In that case, EP1 IN will have 1024 bytes of buffer, EP3 OUT 32 bytes, etc... Note that FIFO sizes must be powers of 2.</li><li>Modified the <tt>sniff</tt> script to take that into account: it reads the device descriptor, and chooses the closest bigger or equal power of 2 size for the endpoint FIFO.</li><li>Improved the instructions on the wiki, taking into account feedback from Frans.</li></ul>Plans:<ul><li>I just bought a USB 2.0 webcam, that needs high-bandwith isochronous endpoints. Getting that to work will require modifications to the MUSB driver</li></ul>Risks:<ul><li>Lack of time... There is only a week left until the suggested pencil down date...</li><li>Adding high-bandwidth endpoints support to MUSB may be tricky.</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-1825449598109256952010-07-25T21:27:00.000-07:002010-07-25T21:30:24.297-07:00Weekly report - Week 9As expected, it wasn't a very productive week...<br /><br />Status:<ul><li>Tested my MUSB modification when double-buffering is enabled. It seems to cause a lot of packet losses with isochronous transfers, so I'm wondering if my patch is breaking something.</li><li>Added recipes for libpcap 1.1.1 and tcpdump 4.1.1 in OpenEmbedded. Commits: <a href="http://git.openembedded.org/cgit.cgi/openembedded/commit/?id=7b9e14891f7d69b5376041fc15df3d5f13f41855">libpcap</a>, and <a href="http://git.openembedded.org/cgit.cgi/openembedded/commit/?id=d4f0fb310f7d40f7a50f50fb12083fa258aa1eed">tcpdump</a>.</li><li>These versions are able to capture USB traffic in a format that is compatible with wireshark.</li><li>Added an all-in-one capture script: <tt>sniff</tt>. See the script <a href="http://gitorious.org/beagleboard-usbsniffer/helper-scripts/blobs/master/arm/sniff">here</a>, and <a href="http://www.elinux.org/BeagleBoard/GSoC/USBSniffer#Build_and_run_instructions">updated instructions</a>.</li></ul><br />Plans:<ul><li>Investigate the MSP430 Launchpad problem.</li><li>Choose the FIFO size for each of the endpoints from the device descriptors: right now, I have 2 extra FIFO modes, 6, and 7, used respectively for the webcam, and the headset. When that is done, we will have some fully automatic sniffing solution.</li><li>MUSB related: try to find out what is going wrong when double-buffering is enabled, and experiment with high-bandwidth transfers.</li></ul><br />Risks:<ul><li>Lack of time... This week will be the last week I will be able to work full-time on this project.</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com1tag:blogger.com,1999:blog-764876530099788129.post-65543545262046159182010-07-19T03:32:00.000-07:002010-07-19T03:40:43.934-07:00Weekly report - Week 8Status:<ul><li>Managed to fix the bug with short ISO packets in the MUSB driver (see Friday's post).</li><li>Retested the proxy driver with the devices I have. I did some more thorough Bluetooth testing, including file transfers (<a href="http://www.elinux.org/BeagleBoard/GSoC/USBSniffer#Tested_devices">table here</a>).</li></ul>Plans:<ul><li>Test with a few more devices, before leaving Switzerland.</li><li>The MSP430 Launchpad doesn't work with the proxy (it seems a bit fragile, even when connected directly to my PC, I suspect a driver problem): investigate this.</li><li>It would be good to add support for high-bandwidth endpoints in the MUSB driver, and test it with the proxy (I don't own any device requiring this at the moment).</li><li>Test packet capture with libpcap on the BeagleBoard (to get wireshark-compatible capture files).<br /></li></ul>Risks:<br /><ul><li>I'll be on a plane for most of Wednesday and Thursday (and jet-lagged after that...), so don't expect too much out of this week...</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-67091316511857341392010-07-16T05:34:00.000-07:002010-07-16T05:42:27.389-07:00MUSB isochronous transfers fixed (hopefully)So, it took a while, but I think I managed to fix the MUSB bug, the relevant commit is <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commit/b0be3b6cc195ba732189b04f1d43ec843c3e54c9">here</a>.<br /><br />The MUSB DMA supports 2 different transfer modes: mode-0 transfers packets one at a time, requiring CPU intervention to reload the next packet, while mode-1 is able to transfer multiple packets, before triggering an interrupt.<br /><br />For every mode-0 transfer, or for the last mode-1 packet, the packet in the FIFO must be manually flushed, that is, <tt>MUSB_TXCSR_TXPKTRDY</tt> must be set. This was somehow done in <tt>musb_g_tx</tt> (<tt>musb_gadget.c:513</tt>), but incorrectly. Using the procedure described on the <a href="http://elinux.org/BeagleBoard/GSoC/USBSniffer#MUSB_testing_code">wiki</a>, with a packet size of 4 (parameter <tt>-x 4</tt>), I got the following usbmon output:<br /><pre>S Zi:2:120:1 -115:1024:0 1 -18:0:512 512 <<br />C Zi:2:120:1 0:1024:5584:0 1 0:0:512 512 = de010203 de050607 de090a0b de0d0e0f de111213 de151617 de19<br />1a1b de1d1e1f<br />S Zi:2:120:1 -115:1024:5584 1 -18:0:512 512 <<br />C Zi:2:120:1 0:1024:6608:0 1 0:0:4 4 = df010203<br />S Zi:2:120:1 -115:1024:6608 1 -18:0:512 512 <<br />C Zi:2:120:1 0:1024:7632:0 1 0:0:4 4 = df010203<br />S Zi:2:120:1 -115:1024:7632 1 -18:0:512 512 <<br />C Zi:2:120:1 0:1024:464:0 1 0:0:4 4 = df010203<br />S Zi:2:120:1 -115:1024:464 1 -18:0:512 512 <<br />...</pre> The first packet is 512 bytes, which is normal, and then same data was repeated again and again: <tt>df</tt> is supposed to be incremented, that is, the next packets should contain <tt>e0010203</tt>, <tt>e1010203</tt>. I tried commenting out<br /><pre>if (csr & MUSB_TXCSR_TXPKTRDY)<br /> return;</pre> as recommend by Ajay, with the same result...<br /><br />I then realized that the following lines (which, BTW, do not necessarily send a zero packet, they simply ask the MUSB controller to fetch the next packet from the FIFO): <br /><pre>DBG(4, "sending zero pkt\n");<br />musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE<br /> | MUSB_TXCSR_TXPKTRDY);</pre> were clearing all flags from MUSB_TXCSR (including things like <tt>MUSB_TXCSR_ISO</tt> or <tt>>MUSB_TXCSR_DMAEN</tt>). So I replaced these with:<br /><pre>DBG(4, "sending zero pkt\n");<br />musb_writew(epio, MUSB_TXCSR, csr<br /> | MUSB_TXCSR_TXPKTRDY);</pre> where <tt>csr</tt> is the current value of <tt>MUSB_TXCSR</tt>. I'm not sure if some other flags must be cleared, but at least, it works for my test case...<br /><br />And the output looks better:<br /><pre>S Zi:2:125:1 -115:1024:0 1 -18:0:512 512 <<br />C Zi:2:125:1 0:1024:2608:0 1 0:0:512 512 = de010203 de050607 de090a0b de0d0e0f de111213 de151617 de191a1b de1d1e1f<br />S Zi:2:125:1 -115:1024:2608 1 -18:0:512 512 <<br />C Zi:2:125:1 0:1024:3632:0 1 0:0:12 12 = df010203 e0010203 e1010203<br />S Zi:2:125:1 -115:1024:3632 1 -18:0:512 512 <<br />C Zi:2:125:1 0:1024:4656:0 1 0:0:12 12 = e2010203 e3010203 e4010203<br />S Zi:2:125:1 -115:1024:4656 1 -18:0:512 512 <<br />C Zi:2:125:1 0:1024:5680:0 1 0:0:4 4 = e5010203<br />S Zi:2:125:1 -115:1024:5680 1 -18:0:512 512 <<br />C Zi:2:125:1 0:1024:6704:0 1 0:0:4 4 = e6010203<br />...</pre> Except that 3 requests were merged into one packet (twice), which is not supposed to happen, I suppose: If the gadget driver sends a short request to the gadget controller, it probably means that it wants a short packet to be transmitted.<br /><br />In any case, a bigger problem appeared, if the driver sent packets of 5 bytes, instead of 4 bytes:<br /><pre>S Zi:2:009:1 -115:8:0 1 -18:0:512 512 <<br />C Zi:2:009:1 0:8:4568:0 1 0:0:512 512 = de010203 de050607 de090a0b de0d0e0f de111213 de151617 de191a1b de1d1e1f<br />S Zi:2:009:1 -115:8:4568 1 -18:0:512 512 <<br />C Zi:2:009:1 0:8:4576:0 1 0:0:15 15 = df010203 e0010203 e1010203 de0d0e<br />S Zi:2:009:1 -115:8:4576 1 -18:0:512 512 <<br />C Zi:2:009:1 0:8:4584:0 1 0:0:10 10 = e1e20203 e3010203 e301<br />S Zi:2:009:1 -115:8:4584 1 -18:0:512 512 <<br />C Zi:2:009:1 0:8:4592:0 1 0:0:15 15 = e4010203 e5010203 e6010203 e60102<br />S Zi:2:009:1 -115:8:4592 1 -18:0:512 512 <<br />C Zi:2:009:1 0:8:4600:0 1 0:0:5 5 = e7010203 e7<br />S Zi:2:009:1 -115:8:4600 1 -18:0:512 512 <<br />C Zi:2:009:1 0:8:4608:0 1 0:0:5 5 = e8010203 e8<br />...</pre> The second packet data is badly corrupted, it should be df010203 04e00102 0304e101 020304. It seems like the DMA engine is not able to properly write unaligned data to the FIFO.<br /><br />After seeing that problem (added to the fact that requests should not be merged together in the first place), I realized that <tt>MUSB_TXCSR_TXPKTRDY</tt> was probably not set at the right place in the code: it should be set right after the DMA finishes copying the data to the FIFO.<br /><br />This happens in <tt>musbhsdma.c</tt>, function <tt>dma_controller_irq</tt>. And the code was already there, it's just that, for some reasons, it was only enabled for the host mode, and not the peripheral mode (<tt>if (devctl & MUSB_DEVCTL_HM)</tt>, line 533). I enabled that code path, with a fix for DMA mode 0: it is useless to clear <tt>MUSB_TXCSR_DMAMODE</tt> in that case, and <tt>MUSB_TXCSR_DMAENAB</tt> may need to be cleared before clearing <tt>MUSB_TXCSR_DMAMODE</tt>, but the flag needs to be set again, otherwise this confuses the driver...<br /><br />Then, I disabled the code setting <tt>MUSB_TXCSR_TXPKTRDY</tt> in <tt>musb_g_tx</tt>, and replaced it with another piece of code that forces the packet to be sent, by setting <tt>MUSB_TXCSR_FLUSHFIFO</tt>, and, it seems to work!<br /><pre>S Zi:2:016:1 -115:8:0 1 -18:0:512 512 <<br />C Zi:2:016:1 0:8:1328:0 1 0:0:512 512 = de010203 de050607 de090a0b de0d0e0f de111213 de151617 de191a1b de1d1e1f<br />S Zi:2:016:1 -115:8:1328 1 -18:0:512 512 <<br />C Zi:2:016:1 0:8:1336:0 1 0:0:5 5 = df010203 df<br />S Zi:2:016:1 -115:8:1336 1 -18:0:512 512 <<br />C Zi:2:016:1 0:8:1344:0 1 0:0:5 5 = e0010203 e0<br />S Zi:2:016:1 -115:8:1344 1 -18:0:512 512 <<br />C Zi:2:016:1 0:8:1352:0 1 0:0:5 5 = e1010203 e1<br />...</pre><br /><br />Long story short, the webcam works, even with DMA enabled... And <tt>g_ether</tt> still works (i.e., I didn't break everything else)...<br /><br />The latest code is available <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commits/stable-20100716">here</a>: the kernel is now based on a 2.6.34 tree.drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-43681677862443387192010-07-12T03:28:00.000-07:002010-07-12T03:46:05.789-07:00Weekly report - Week 7Status:<ul><li>Switched to a <a href="http://arago-project.org/git/people/sriram/ti-psp-omap.git?p=people/sriram/ti-psp-omap.git;a=shortlog;h=refs/heads/OMAPPSP_03.00.02.07">more recent kernel</a>, based on 2.6.34, to make sure I have the latest bug fixes, as recommended by Ajay.<br /></li><li>I shifted focus towards debugging the MUSB driver, and particularly the code path used when DMA is used. It could be possible to debug the MUSB driver using my proxy driver, connecting the webcam, but the transfer rate and packet sizes are rather unpredictable, making it hard to reproduce problems.<br /></li><li>My first idea was to program a Cypress FX2 to stream isochronous packets, connect the FX2 to the BeagleBoard, with my proxy driver. I tried to find some ready-made test firmwares, without much success: none of these tested isochronous transfers, and most of them were written for the Cypress EZ-USB chip (i.e., a (incompatible) predecessor to the FX2).<br /></li><li>Since the problem lies in the MUSB driver, I don't really need to use my proxy driver. I found a testing gadgetfs driver, which supports isochronous transfers. I could then hack the driver to force it to send short packets, triggering the MUSB bug (some instructions can be found <a href="http://www.elinux.org/BeagleBoard/GSoC/2010_Projects/USBSniffer#MUSB_testing_code">here</a>).</li></ul><br />Plans:<ul><li>Continue debugging the MUSB driver with short isochronous packets. If I cannot find a solution after a few days, I'll report the problem to the linux-usb list.<br /></li><li>High-throughput endpoints are not supported in the MUSB driver, that's something I could try to implement.</li></ul><br />Risks:<ul><li>Debugging the MUSB driver is a bit difficult: since isochronous are delay sensitive, displaying some debugging messages causes packet losses.</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-15295953130383474262010-07-05T02:05:00.000-07:002010-07-05T02:06:57.039-07:00Weekly report - Week 6Status:<br /><ul><li>Mostly worked on the webcam, I got isochronous transfers to work, after identifying a bug in the MUSB driver (related to the DMA controller). See last Friday's post.</li></ul>Plans:<br /><ul><li>Attempt to fix the MUSB driver with isochronous endpoints, disabling the DMA works, but hurts the performance...<br /></li><li>Program a Cypress FX2 with a high-speed, high-bandwidth endpoint (the MUSB does not seems to handle that, so it would be good to fix it as well). Maybe the FX2 can be used for bulk bandwidth tests too.</li></ul>Risks:<br /><ul><li>Lack of available documentation about MUSB.</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com1tag:blogger.com,1999:blog-764876530099788129.post-90020871084853424502010-07-02T15:33:00.000-07:002010-07-02T15:50:40.139-07:00Isochronous transfers - WebcamThese past 2 weeks, I focused on getting a USB webcam to work, and particularly the 2 isochronous endpoints, used for audio and video coming from the webcam. This is a full speed device, and its descriptor is below (I trimmed it a bit):<br /><pre><br />Bus 002 Device 061: ID 046d:08da Logitech, Inc. QuickCam Messanger<br />Device Descriptor:<br /> bLength 18<br /> bDescriptorType 1<br /> bcdUSB 1.10<br /> bDeviceClass 0 (Defined at Interface level)<br /> bDeviceSubClass 0 <br /> bDeviceProtocol 0 <br /> bMaxPacketSize0 8<br /> idVendor 0x046d Logitech, Inc.<br /> idProduct 0x08da QuickCam Messanger<br /> bcdDevice 1.00<br /> iManufacturer 0 <br /> iProduct 0 <br /> iSerial 0 <br /> bNumConfigurations 1<br /> Configuration Descriptor:<br /> bLength 9<br /> bDescriptorType 2<br /> wTotalLength 336<br /> bNumInterfaces 3<br /> bConfigurationValue 1<br /> iConfiguration 0 <br /> bmAttributes 0xa0<br /> (Bus Powered)<br /> Remote Wakeup<br /> MaxPower 100mA<br /> Interface Descriptor:<br /> bLength 9<br /> bDescriptorType 4<br /> bInterfaceNumber 0<br /> bAlternateSetting 0<br /> bNumEndpoints 2<br /> bInterfaceClass 255 Vendor Specific Class<br /> bInterfaceSubClass 255 Vendor Specific Subclass<br /> bInterfaceProtocol 255 Vendor Specific Protocol<br /> iInterface 0 <br /> Endpoint Descriptor:<br /> bLength 7<br /> bDescriptorType 5<br /> bEndpointAddress 0x81 EP 1 IN<br /> bmAttributes 1<br /> Transfer Type Isochronous<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0000 1x 0 bytes<br /> bInterval 1<br /> Endpoint Descriptor:<br /> bLength 7<br /> bDescriptorType 5<br /> bEndpointAddress 0x82 EP 2 IN<br /> bmAttributes 3<br /> Transfer Type Interrupt<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0008 1x 8 bytes<br /> bInterval 10<br /> Interface Descriptor: ...<br /> Interface Descriptor:<br /> bLength 9<br /> bDescriptorType 4<br /> bInterfaceNumber 0<br /> bAlternateSetting 6<br /> bNumEndpoints 2<br /> bInterfaceClass 255 Vendor Specific Class<br /> bInterfaceSubClass 255 Vendor Specific Subclass<br /> bInterfaceProtocol 255 Vendor Specific Protocol<br /> iInterface 0 <br /> Endpoint Descriptor:<br /> bLength 7<br /> bDescriptorType 5<br /> bEndpointAddress 0x81 EP 1 IN<br /> bmAttributes 1<br /> Transfer Type Isochronous<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0300 1x 768 bytes<br /> bInterval 1<br /> Endpoint Descriptor:<br /> bLength 7<br /> bDescriptorType 5<br /> bEndpointAddress 0x82 EP 2 IN<br /> bmAttributes 3<br /> Transfer Type Interrupt<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0008 1x 8 bytes<br /> bInterval 10<br /> Interface Descriptor: ...<br /> Interface Descriptor:<br /> bLength 9<br /> bDescriptorType 4<br /> bInterfaceNumber 1<br /> bAlternateSetting 0<br /> ...<br /> Interface Descriptor:<br /> bLength 9<br /> bDescriptorType 4<br /> bInterfaceNumber 2<br /> bAlternateSetting 0<br /> bNumEndpoints 0<br /> bInterfaceClass 1 Audio<br /> bInterfaceSubClass 2 Streaming<br /> bInterfaceProtocol 0 <br /> iInterface 0 <br /> Interface Descriptor:<br /> bLength 9<br /> bDescriptorType 4<br /> bInterfaceNumber 2<br /> bAlternateSetting 1<br /> bNumEndpoints 1<br /> bInterfaceClass 1 Audio<br /> bInterfaceSubClass 2 Streaming<br /> bInterfaceProtocol 0 <br /> iInterface 0 <br /> AudioStreaming Interface Descriptor: ....<br /> AudioStreaming Interface Descriptor: ....<br /> Endpoint Descriptor:<br /> bLength 9<br /> bDescriptorType 5<br /> bEndpointAddress 0x83 EP 3 IN<br /> bmAttributes 1<br /> Transfer Type Isochronous<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0010 1x 16 bytes<br /> bInterval 1<br /> bRefresh 0<br /> bSynchAddress 0<br /> AudioControl Endpoint Descriptor: ....<br />Device Status: 0x0000<br /> (Bus Powered)<br /></pre><br />Audio comes through <tt>EP3</tt>, and video through <tt>EP1</tt>.<br /><br />The first thing to note is that isochronous endpoints are not allowed to be part of the default configuration for a device, so, to support these transfers, the <tt>SET_INTERFACE</tt> command has to be supported. For example, when a video player is launched, the alternate setting 6 is selected for interface 0, allowing packets of up to 768 bytes on <tt>EP1 IN</tt>.<br /><br />When I tried with audio playback, URBs could not be submitted to the device, with error <tt>-28</tt>, i.e. <tt>ENOSPC</tt>, which has something to do with a problem in USB bandwidth allocation. The kernel configuration <tt>CONFIG_USB_EHCI_TT_NEWSCHED</tt> is meant to help with that kind of problems, and it does, no more <tt>-28</tt> errors, and audio worked. I realised much later that the same problem happens when I connect the webcam to my PC, through the same USB hub I normally use with the BeagleBoard, so this is probably a hub problem. The webcam works fine with another USB hub on my PC, but that USB hub refuses to work with the BeagleBoard, so I need to find a better supported USB hub.<br /><br />The next problem was about the packet size used for <tt>EP1</tt>, 768 bytes is more than the FIFO size (512 bytes) in the default endpoint configurations (<tt>fifo_mode=5</tt>, see <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/blobs/stable-20100702/drivers/usb/musb/musb_core.c">here</a>, <tt>__initdata mode_5_cfg</tt>). I simply created a new configuration, with an EP1 FIFO size of 1024 bytes (<tt>fifo_mode=6</tt>).<br /><br />And then, nothing. When I started a video player, some packets were received properly from the webcam. The proxy driver would then submit a request to the MUSB controller, and, then, the request completion handler was only called for the first request, and never for any subsequent packet. After a few hours of debugging, I found that the MUSB driver sends a zero-length packet after sending a packet smaller than the maximum size (see <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/blobs/stable-20100702/drivers/usb/musb/musb_gadget.c"><tt>musb_gadget.c</tt></a>, around line 520). This may make sense for bulk transfers (and I have doubts...), but not for isochronous transfers. Furthermore, sending that packet seemed to stall the endpoint, and no further requests would be processed. I tried a quick hack (around line 503), and avoid sending a zero-length packet, but transfers were still not working.<br /><br />After seeing the line testing <tt>#ifdef CONFIG_USB_INVENTRA_DMA</tt> around there, I started wondering about that DMA engine, and disabled it (<tt>use_dma=0</tt> parameter to <tt>musb_hdrc</tt>), and the webcam video started to work.<br /><br />Now, the question is, why did it work with audio, but not video? The answer is quite simple, audio packets are always filled: Each packet contains exactly 16 bytes, as can be seen in the following usbmon line:<br /><pre><br />ffff88006e576100 2368995185 C Zi:6:075:3 0:1:831804651:0 1 0:0:16 16 =<br />6aff81ff 65ff6fff 7fff6fff 9dff86ff<br /></pre><br />(The interesting bit is <tt>0:0:16</tt>, the 3rd number indicates that the packet contains 16 bytes. Other packets are similar, just with different payload and timestamps.)<br /><br />However, for the webcam, the packet size is variable:<br /><pre><br />ffff880080052000 2351992862 C Zi:6:075:1 0:1:831787618:0 32 0:0:250<br />0:768:292 0:1536:338 0:2304:362 0:3072:254 6807 = ...<br /></pre><br />Here, the first packet contains 250 bytes, the second one 292, then 338, etc., triggering the MUSB/DMA bug.<br /><br />Finally, you can try the latest version by using the instructions found <a href="http://www.elinux.org/BeagleBoard/GSoC/USBSniffer">here</a>, and the branch <tt>stable-20100702</tt> (<a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commits/stable-20100702">here</a>).drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com1tag:blogger.com,1999:blog-764876530099788129.post-47730142264941686212010-06-27T09:33:00.000-07:002010-06-27T09:39:44.653-07:00Weekly report - Week 5Status:<br /><ul><li>Managed to fix the throughput issue with my USB flash device. I now get 19.11 MB/sec, close to the maximum throughput when the USB device is directly connected to the host.<br>In my previous version, I used only one urb/request pair per endpoint: when data came from the device (through an urb), it was forwarded to the host (as a request), and the driver would only resubmit the urb when the data was properly sent to the host.<br /></li><br /><ul><li>I fixed this by having 8 urb/requests submitted to the USB controller driver, to make sure that there is always some buffer available to write incoming data to. This alone improved the performance to 12.79 MB/sec.</li><li>The second thing I did is to have a larger buffer per urb/request: instead of allocating 512 bytes (i.e. <tt>wMaxPacketSize</tt>) per urb/request, I allocated 4096 bytes. I guess that this reduces the number of interrupts (and the number of times my handlers are called), giving an extra performance gain. This should also be transparent to the host/device, as transfers larger than <tt>wMaxPacketSize</tt> are split into smaller packets of size <tt>wMaxPacketSize</tt> (except the last one). Since our buffer size is a multiple of <tt>wMaxPacketSize</tt>, this should not cause problems.<br /></li></ul><br /><li><tt>SET_INTERFACE</tt> command works (this is a prerequisite for isochronous transfers). This was a bit tricky, as disabling endpoints cannot be done in interrupt context, so I submit a work_struct to do that in process context.</li><li>I started working on isochronous transfers. I got clean audio coming from the microphone integrated in a webcam. The video still does not work, but I am working on it.<br /></li></ul>Plans:<br /><ul><li>Fix isochronous transfers, as the urb buffer is filled in a special way in these cases (I'll write about that next week), my code works by chance with the audio from the webcam.</li><li>Code cleanup, again. Some parts are unstable again, causing oopses and warning, after some of my recent updates.<br /></li><li>Maybe, collect statistics on urb/request usage, to see how many urb/requests are needed for maximum performance.<br /></ul>Risks:<br /><ul><li>From what I see in MUSB, the driver does not support high-bandwidth endpoints (i.e. isochronous transfers with <tt>maxPacketSize</tt> > 1024 bytes), that are used by High-Speed device. The driver may need to be updated.</li><li>Bandwidth allocation: with this proxy model, there is nothing much with can do if bandwidth allocation fails on the BeagleBoard. If the host believes enough bandwidth is available, it will use high-throughput interfaces, and there is nothing that can be done on the BeagleBoard to prevent that, in case there is not enough bandwidth available on the EHCI controller of the BeagleBoard. This causes problems with the video on the USB webcam, but the configuration option <tt>CONFIG_USB_EHCI_TT_NEWSCHED</tt> seems to help, though.</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com4tag:blogger.com,1999:blog-764876530099788129.post-70513444635251481862010-06-20T15:33:00.000-07:002010-06-20T15:35:18.749-07:00Weekly report - Week 4Status:<br /><ul><li> Did some code cleanup, hopefully the code should not crash anymore, and be free of memory leaks. Instructions on how to use my code can be found <a href="http://www.elinux.org/BeagleBoard/GSoC/USBSniffer">here</a>, and you should use <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commits/stable-20100618">this branch of my git tree</a>.</li><li>Documented a bit more the data flow, in the code.</li><li> Tested more systematically with a few different devices. A table of those devices can be found on the <a href="http://www.elinux.org/BeagleBoard/GSoC/USBSniffer">wiki page</a>.</li></ul>Plans:<br /><ul><li> Improve performance with the USB flash device (current speed: 3.77MB/sec, whereas we can get as high as 19.76 MB/sec without proxy).</li><li>Isochronous transfers (see last week).<br /></li></ul>Risks:<br /><ul><li>Risks from last week are still around.<br /></li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-37875089398796268782010-06-13T11:26:00.000-07:002010-06-13T11:29:01.355-07:00Weekly report - Week 3Status:<br /><ul><li>I now have a more general proxy driver, that should work with any device, as long as it does not use any isochronous endpoints, and does not require any change in configuration or interface (i.e., only one <tt>SET_CONFIGURATION</tt> control request is used, and no <tt>SET_INTERFACE)</tt>.</li><li>Managed to get a DVB-T tuner to work properly (mine only uses bulk transfers). There is no noticeable difference between connecting the tuner directly to a PC, or through the BeagleBoard, even though only a single transfer is buffered in the proxy driver.<br /></li></ul>Plans:<br /><ul><li>Code cleanup. There are frequent kernel oops (notably upon module unloading), a few memory leaks I know about, and the code is lacking error checking in many places.</li><li>Some documentation about the data flow in the code (a transfer goes through a few different callbacks, on the gadget and device sides, and it is a bit hard to follow what is happening by looking at the code).</li><li>Isochronous transfers seems to work differently from control/interrupt/bulk transfers. I need to look at that, and implement them (I have a USB webcam and a headset, which would make good test cases). Since isochronous endpoints cannot be part of the default interface of a device, I need to implement <tt>SET_INTERFACE</tt> as well.<br /></li></ul>Risks:<br /><ul><li>Endpoints maximum packet size. With the current FIFO configuration, the MUSB block probably only supports a maximum of 512 bytes per transfer. More would be needed for the webcam to work (768 at max, the standard allowing up to 3072 in High-Speed mode).</li><li>I tried the g_audio gadget, which uses isochronous transfers, but experienced some corruption (the music plays, but with noticeable corruption), I do not know if it is due to the MUSB, or to the g_audio gadget.</li><li>Bandwidth allocation. I picked some functions from the USB core to initialize the USB device and its endpoints correctly, but I may have left some parts aside, one of them being the function that allocates USB bandwidth.</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-23960624757790154132010-06-09T10:28:00.000-07:002010-06-09T10:37:31.938-07:00Bidirectional communication with an ArduinoI now have transparent communication with an Arduino (programming the device work, as well as serial communication with the loaded program). You can find the proxy driver code <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commit/bb3cbd786ad95e0220ce4b96ecdd9dd668c5d441">here</a>, or fetch the whole branch <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commits/backup-20100609">here</a>.<br /><br />Basically, the Arduino appears as a USB->serial converter to the host, with 2 bulk endpoints, with directions IN and OUT (for both directions of the serial transfers):<br /><pre><br />Bus 007 Device 120: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC<br />Device Descriptor:<br /> bLength 18<br /> bDescriptorType 1<br /> bcdUSB 2.00<br /> bDeviceClass 0 (Defined at Interface level)<br /> bDeviceSubClass 0<br /> bDeviceProtocol 0<br /> bMaxPacketSize0 8<br /> idVendor 0x0403 Future Technology Devices International, Ltd<br /> idProduct 0x6001 FT232 USB-Serial (UART) IC<br /> bcdDevice 6.00<br /> iManufacturer 1 FTDI<br /> iProduct 2 FT232R USB UART<br /> iSerial 3 A800evGn<br /> bNumConfigurations 1<br /> Configuration Descriptor:<br /> bLength 9<br /> bDescriptorType 2<br /> wTotalLength 32<br /> bNumInterfaces 1<br /> bConfigurationValue 1<br /> iConfiguration 0<br /> bmAttributes 0xa0<br /> (Bus Powered)<br /> Remote Wakeup<br /> MaxPower 90mA<br /> Interface Descriptor:<br /> bLength 9<br /> bDescriptorType 4<br /> bInterfaceNumber 0<br /> bAlternateSetting 0<br /> bNumEndpoints 2<br /> bInterfaceClass 255 Vendor Specific Class<br /> bInterfaceSubClass 255 Vendor Specific Subclass<br /> bInterfaceProtocol 255 Vendor Specific Protocol<br /> iInterface 2 FT232R USB UART<br /> Endpoint Descriptor:<br /> bLength 7<br /> bDescriptorType 5<br /> bEndpointAddress 0x81 EP 1 IN<br /> bmAttributes 2<br /> Transfer Type Bulk<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0040 1x 64 bytes<br /> bInterval 0<br /> Endpoint Descriptor:<br /> bLength 7<br /> bDescriptorType 5<br /> bEndpointAddress 0x02 EP 2 OUT<br /> bmAttributes 2<br /> Transfer Type Bulk<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0040 1x 64 bytes<br /> bInterval 0<br />Device Status: 0x0000<br /> (Bus Powered)<br /></pre><br />The first endpoint (<tt>EP 1 IN</tt>), for communication from the Arduino to the host, worked almost immediately: apart from the transfer type, this is the same as for HID devices.<br /><br />Getting the second endpoint (<tt>EP 2 OUT</tt>) to be configured properly on the gadget side was a little tricky. In fact, the infrastucture provided in <tt>drivers/usb/gadget/epautoconf.c</tt>, namely the function <tt>usb_ep_autoconfig</tt>, does not allow to choose an endpoint address: This function looks at the list of endpoints provided by the gadget controller driver, and simply selects the first endpoint that supports the request transfer type, direction and maximum packet size (here, Bulk OUT, 64 bytes). In our case, the function selects <tt>EP 1 OUT</tt>, while the host still thinks transfers should be done on <tt>EP 2 OUT</tt>.<br /><br />To get it to work, I had to rewrite <tt>usb_ep_autoconfig</tt> (see <tt>find_gadget_endpoint</tt>), and I was a little horrified to see the way gadget controllers endpoints are advertised: Each endpoint structure has a <tt>char* name</tt> field, which tells the endpoint address, direction, and possibly the supported transfer types. To find EP 2 OUT, the function has to go through all the endpoints, until it finds one whose name is <tt>ep2out</tt>. A bit kludgy, but well, it works, at least for the MUSB controller...<br /><br />Data transfers are handled differently, whether they happens on a IN, or OUT, endpoint. For IN endpoints, we follow the following procedure:<br /> 1. Initialization (see <tt>bridge_endpoint</tt>): We submit an URB (USB request block) to the device, asking for data.<br /> 2. Device callback (see <tt>device_epin_irq</tt>): We got some data. Copy it to a <tt>request</tt> (the gadget equivalent of an URB), and submit it.<br /> 3. Gadget callback (see <tt>gadget_epin_complete</tt>): The request was submitted correctly. Resubmit the URB, so we can receive the next packet.<br /><br />OUT endpoints are handled similarly: Upon initialization, a request is submitted (<tt>bridge_endpoint</tt>), the gadget callback (<tt>gadget_epout_complete</tt>) submits an URB. When the URB completes (<tt>device_epout_irq</tt>), the request is resubmitted.<br /><br />This method, that is, with only one URB/request "flying" at the time, seems to work well for low throughput applications, but buffering may be required for higher throughput.drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-63238556236002686632010-06-06T13:38:00.000-07:002010-06-06T13:43:32.471-07:00Weekly report - Week 2Status:<br /><ul><li>Modified the proxy driver to be more generic: descriptors requests are forwarded to the device, and the descriptors are parsed (and modified if required) on the fly: but still, only interrupt transfers from the device to the host on endpoint 1 are supported.</li><li>Ported my set of patches to the kernel 2.6.35-rc1 (i.e., the latest vanilla tree): a few functions got renamed, but nothing major. I compiled and ran that kernel on the BeagleBoard. I had to tweak some files to get the MUSB block to accept being run in peripheral-only mode (<a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commit/05e36d91aac22b9781f48f3aa01d4ece27193f43">commit</a>), but the MUSB block seems buggy (even with the Ethernet gadget), so I gave up on that. From a discussion on <span style="font-size:85%;"><span style="font-family: courier new;">#beagle</span></span>, it seems like it would be better to use the <span style="font-size:85%;"><span style="font-family: courier new;">linux-omap</span></span> git tree (but I don't know which branch), and apply "some patches" from Angstrom.</li><li>Started working with a new device: the FTDI USB->Serial converter found, for example, on Arduino boards. Device->PC communication uses endpoint 1, in bulk mode, and worked with little modifications of the existing code.<br /></li></ul>Plans:<br /><ul><li>Get PC->Device communication to work with the Arduino, which uses endpoint 2 in bulk mode (to get at least one OUT endpoint working).</li><li>From there, dynamically connect all endpoints advertised in the configuration.<br /></li></ul>Risks/problems:<br /><ul><li>So far I've been targeting kernel 2.6.32 (from <span style="font-size:85%;"><span style="font-family: courier new;">angstrom-linux/beagleboardXM</span></span>), but at some point I would like to target the latest kernel, so I would need to get the MUSB block to work properly with a recent kernel.</li><li>I have encountered strange problems with a keyboard: pressing num/caps lock only takes effect at the next key stroke, I need to investigate this.<br /></li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-69025763831229166692010-06-02T09:05:00.000-07:002010-06-02T09:11:26.929-07:00Towards a more general solution<a href="http://www.google.com/profiles/105984412292232800384#buzz" class="CSS_UPDATES_UCW_USER CSS_UPDATES_UCW_AUTHOR proflink" oid="105984412292232800384"></a>I spent the last few days generalizing my proxy driver, in such a way that most HID devices (mice, keyboards), should now be working. Actually, any device that uses only endpoint 1 in interrupt mode and IN direction should be supported by the current implementation.<br /><br />There are no static descriptors hard-coded in the driver anymore, so <span style="font-size:85%;"><span style="font-family: courier new;">GET_DESCRIPTOR </span></span>requests are intercepted, and the configuration descriptors are parsed and cached (using functions found in the kernel). Also, the descriptors are modified on the fly, to compensate for the fact that the communication between the PC and the BeagleBoard happens in Full Speed, while the BeagleBoard-device communication uses Low Speed.<br /><br />Two fields are dynamically modified:<br /><ul><li><span style="font-size:85%;"><span style="font-family: courier new;">bMaxPacketSize0</span></span> in the device descriptor. It seems like the MUSB driver only support 64 bytes as maximum packet size (which is what is mandated by the High Speed mode), while the mouse uses 8 bytes (the only possible value for Low Speed devices). In theory, Full Speed devices can advertise a maximum packet size between 8 and 64 bytes, but the MUSB driver does not seem to support that.</li><li><span style="font-size:85%;"><span style="font-family: courier new;">bInterval</span></span> in endpoints descriptors. As mentionned before, the meaning of that field varies with the device speed.<br /></li></ul>To get the proxy driver to work, you need to follow these steps:<br /><ul><li>Clone my kernel <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel">git tree</a>. Use the <span style="font-size:85%;"><span style="font-family: courier new;">backup-20100602</span></span> branch.</li><li>Compile the kernel with the default beagleboard configuration (see <a href="http://elinux.org/BeagleBoard#Linux_kernel">here</a>). You just need to add <span style="font-size:85%;"><span style="font-family: courier new;">CONFIG_USB_G_PROXY=m</span></span>. I also disabled MUSB in host and OTG mode, as well as USB suspend, but this may not be necessary.</li><li>Install the new kernel on the board.</li><li>Clone the helper scripts <a href="http://gitorious.org/beagleboard-usbsniffer/helper-scripts">git tree</a>, and copy the content of the arm directory to the BeagleBoard (you need to modify load/setup scripts if you do not have have a copy of <span style="font-family: courier new;font-size:85%;" >musb_hdrc.ko</span> and <span style="font-size:85%;"><span style="font-family: courier new;">g_proxy.ko</span></span> in the same directory).</li><li>Run <span style="font-size:85%;"><span style="font-family: courier new;">./setup</span></span> on the BeagleBoard, this will unload the <span style="font-size:85%;"><span style="font-family: courier new;">g_ether</span></span> gadget driver.</li><li>Plug your USB hub + a HID mouse/keyboard to the BeagleBoard (this can be done earlier).</li><li>Plug your PC to the BeagleBoard USB slave port (this can be done earlier as well).</li><li>Run <span style="font-size:85%;"><span style="font-family: courier new;">./unbind</span></span>: This will unbind the device from the normal Linux driver.</li><li>Run <span style="font-size:85%;"><span style="font-family: courier new;">./load</span></span>: this will (re)load the <span style="font-size:85%;"><span style="font-family: courier new;">g_proxy</span></span> driver.</li><li>Use the mouse/keyboard, it should work.<br /></li></ul>The code is still full of TODO/FIXME, and is rather likely to cause kernel panics.drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-58938318255371141652010-05-31T03:06:00.000-07:002010-05-31T03:08:36.307-07:00Weekly report - Week 1Status:<br /><ul><li> Managed to build Angstrom's console-image, as well as the kernel (outside OpenEmbedded), both work well on the BeagleBoard.</li><li>Wrote a prototype kernel proxy driver, and managed to get USB data to be forwarded properly between a USB mouse and a Linux PC, with the BeagleBoard in between (git tree <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commits/backup-20100527-mouse">here</a>, but no really usable yet).</li><li>Modified the MUSB controller driver to disable high-speed USB if the gadget asks for full-speed (commit <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commit/704235c0ca136280e655cdb6c40bed2471088823">here</a>).<br /></li></ul>Plans:<br /><ul><li>Get the proxy driver more generic, and get completely rid of the static descriptor copy.</li><li>Dynamically connect endpoints, according to the endpoint descriptor.<br /></li></ul>Risks:<br /><ul><li>Differences between low-speed, full-speed, high-speed, for example in the meaning of some descriptor fields (e.g., <span style="font-size:85%;"><span style="font-family: courier new;">bInterval</span></span> for endpoints): since the BeagleBoard MUSB cannot operate in low-speed, this would require some "rewriting" of the descriptors to get the device to work.</li><li>Also, my Linux PC asks for the Device_Qualifier descriptor (a high-speed only descriptor) when connected to the BB, but not when connected directly to the mouse, even though the device is advertised and detected as full-speed.</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-27673334800694537722010-05-27T14:22:00.000-07:002010-05-27T14:33:27.252-07:00A first device works: USB mouseToday I managed to get the following to work: I connect a USB mouse to the host port of my BeagleBoard (via a hub, since the BeagleBoard does not support low-speed USB), and the slave USB port of my BeagleBoard to my PC. Then, I can use that mouse to control the cursor of my PC.<br /><br />For that, I have a "proxy" kernel driver on the BeagleBoard, that is registered both as a USB device driver (on the EHCI side), and as a USB gadget driver (on the MUSB/OTG side).<br /><br />Most USB drivers register at the interface level (that is, as a <span style="font-size:85%;"><span style="font-family:courier new;">struct usb_driver</span></span>), so control only a part of a device (one device could have multiple interfaces, for multiple functions). That is not what we want, so, instead, the proxy driver registers as a <span style="font-size:85%;"><span style="font-family:courier new;">struct usb_device_driver</span></span>, that claims the device at a lower level. Normally, there is only one of such low-level drivers, found in <span style="font-size:85%;"><span style="font-family:courier new;">drivers/usb/core/generic.c</span></span>. This generic driver takes care of all USB devices attached to the system, and looks for interface-level drivers for each of the interfaces of these devices.<br /><br />Since the generic driver claims all new devices (and never releases them), the trick is to unbind the device from the generic driver, so that it can be claimed by our proxy driver. This is done using a command like:<br /><pre>echo 1-2 > /sys/bus/usb/drivers/usb/unbind</pre>Once "unbound", our driver is able to claim it.<br /><br />On the gadget side, there is nothing special: the driver is registered as a <span style="font-size:85%;"><span style="font-family: courier new;">struct usb_gadget_driver</span></span>. Then, we do everything we can to make the PC believe that it is connected directly to a USB mouse. For that purpose, we reply to <span style="font-size:85%;"><span style="font-family: courier new;">GET_DESCRIPTOR</span></span> control requests from the PC with the following device descriptor:<br /><pre>Bus 001 Device 005: ID 046d:c00e Logitech, Inc. M-BJ58/M-BJ69 Optical Wheel Mouse<br />Device Descriptor:<br />bLength 18<br />bDescriptorType 1<br />bcdUSB 2.00<br />bDeviceClass 0 (Defined at Interface level)<br />bDeviceSubClass 0<br />bDeviceProtocol 0<br />bMaxPacketSize0 8<br />idVendor 0x046d Logitech, Inc.<br />idProduct 0xc00e M-BJ58/M-BJ69 Optical Wheel Mouse<br />bcdDevice 11.10<br />iManufacturer 1 Logitech<br />iProduct 2 USB-PS/2 Optical Mouse<br />iSerial 0<br />bNumConfigurations 1<br />Configuration Descriptor:<br /> bLength 9<br /> bDescriptorType 2<br /> wTotalLength 34<br /> bNumInterfaces 1<br /> bConfigurationValue 1<br /> iConfiguration 0<br /> bmAttributes 0xa0<br /> (Bus Powered)<br /> Remote Wakeup<br /> MaxPower 98mA<br /> Interface Descriptor:<br /> bLength 9<br /> bDescriptorType 4<br /> bInterfaceNumber 0<br /> bAlternateSetting 0<br /> bNumEndpoints 1<br /> bInterfaceClass 3 Human Interface Device<br /> bInterfaceSubClass 1 Boot Interface Subclass<br /> bInterfaceProtocol 2 Mouse<br /> iInterface 0<br /> HID Device Descriptor:<br /> bLength 9<br /> bDescriptorType 33<br /> bcdHID 1.10<br /> bCountryCode 0 Not supported<br /> bNumDescriptors 1<br /> bDescriptorType 34 Report<br /> wDescriptorLength 52<br /> Report Descriptors:<br /> ** UNAVAILABLE **<br /> Endpoint Descriptor:<br /> bLength 7<br /> bDescriptorType 5<br /> bEndpointAddress 0x81 EP 1 IN<br /> bmAttributes 3<br /> Transfer Type Interrupt<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0004 1x 4 bytes<br /> bInterval 10<br />Device Status: 0x0000<br />(Bus Powered)<br /></pre>Currently, I have a copy of the descriptor statically defined in the driver, but of course, in the future, this descriptor will have to be read from the device itself.<br /><br />Then, whenever the drivers receives a control request it does not know how to answer (for example, a class-specific HID control request), it forwards the request to the device, waits for the reply, then writes back the reply to the PC.<br /><br />With that, the mouse is fully recognized by the PC, but nothing happens when you move it, because mouse events use interrupt transfers on endpoint 1. That can be fixed by listening for interrupt transfers from the device, and forwarding those to the PC.<br /><br />At that point, the cursor moved, but with some huge latency: clicking was fast, but there was a delay of a few seconds when moving the mouse around... This was due to the following: the mouse is a low-speed USB device, and its endpoint descriptor asks the host to poll it for events every 10 ms (<span style="font-size:85%;"><span style="font-family: courier new;">bInterval = 10</span></span>). However, the MUSB device controller on the BeagleBoard appears as a high-speed device (there is probably a way to force the controller in full-speed mode, but the current driver does not seem to support that), and the definition of the polling interval, for a high-speed device, is <span style="font-size:85%;"><span style="font-family: courier new;">0.125 ms * 2^(bInterval-1)</span></span>. By setting <span style="font-size:85%;"><span style="font-family: courier new;">bInterval</span></span> to 10, the BeagleBoard device controller only got polled every 64 ms, so, when I moved the mouse, this created a lot of events, which got buffered somewhere in the BeagleBoard, until they could be released to the PC.<br /><br />I fixed the problem by modifying the descriptor, and putting <span style="font-size:85%;"><span style="font-family: courier new;">bInterval = 7</span></span>, that is a poll every 8 ms.<br /><br />I can write up some instructions about how to get this setup to work, but I guess this is not so useful if you do not have the same mouse as I have, or a similar enough mouse at least...<br /><br />All the kernel modifications have been pushed in my <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/commits/backup-20100527-mouse">git repository</a>. The proxy driver code, in particular, can be found <a href="http://gitorious.org/beagleboard-usbsniffer/beagleboard-usbsniffer-kernel/blobs/backup-20100527-mouse/drivers/usb/gadget/proxy.c">here</a>, but the code is still far from clean and full of <span style="font-size:85%;"><span style="font-family: courier new;">TODO</span></span>/<span style="font-size:85%;"><span style="font-family: courier new;">FIXME</span></span> tags.drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com1tag:blogger.com,1999:blog-764876530099788129.post-7198030831937511962010-05-25T09:07:00.000-07:002010-05-25T09:52:17.260-07:00Received my BeagleBoard!This morning I received a package from Digikey (thanks to Cathy!), with a BeagleBoard, a 5V power adapter, and a <a href="http://parts.digikey.com/1/parts/1615172-cable-beagle-brd-serial-40-bbc01.html">IDC10-DB9 cable</a>.<br /><br />I connected the BeagleBoard to my PC, using the ICD10-DB9 cable, followed by a USB->RS232 adapter. Then I powered it on, some leds blinked, and, nothing on the terminal... I then tried connecting it to another PC, with a serial port, nothing again.<br /><br />I started wondering if I needed a null-modem cable, so I checked the pinout on the ICD10-DB9 to check if it wasn't one already. And I realised that the pinout was completely non-sensical (ground connected to RX, ring signal connected to TX)... Since the colors on the RS232 wires are not standardized, it looks like the people who built the cable did not realize that the colors changed with their latest supply of cables...<br /><br />It seems like the problem affect quite a few people who ordered the cable recently, so here is how to fix it:<br /><ul><li>Take out all the wires from the ICD10 connector (easy to do with a needle).</li><li>The red and green wires should be together on one pin. Cut the green one.</li><li>Then, connect the red wire (TX, pin 3) on pin 2 of the BeagleBoard (RX).</li><li>The brown one (RX, pin 2), on pin 3 of the BeagleBoard (TX).</li><li>The yellow one (GND, pin 5), on pin 5 of the BeagleBoard.</li><li>Leave the other wires dangling, you don't need them (beware of shorts though, I taped them to avoid problems).<br /></li></ul>A picture of what it looks like in the end:<br /><div style="text-align: center;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh5.ggpht.com/_z9i2JZ7TZXs/S_v-v6rWGjI/AAAAAAAAATA/dnjnqqyEzzw/s640/cable.JPG"><img style="cursor: pointer; width: 381px; height: 274px;" src="http://lh5.ggpht.com/_z9i2JZ7TZXs/S_v-v6rWGjI/AAAAAAAAATA/dnjnqqyEzzw/s640/cable.JPG" alt="" border="0" /></a><br /></div><br />Note that this is only for this batch of cables, and it's always better to check the wiring with a ohmmeter, if you have one (the RS232/DB9 pinout can be found <a href="http://www.zytrax.com/tech/layer_1/cables/tech_rs232.htm#db9">here</a>).drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-90025405781930482942010-05-24T08:55:00.000-07:002010-05-24T09:03:58.110-07:00Weekly report: Week 0First, I should receive my BeagleBoard tomorrow, so I can get up to speed on the project.<br /><br />Status:<br /><ul><li>Tried to build Angstrom (the latest git version), but ran into disk space problems (20+ gigs do not seem to be enough). Since I only need to do kernel development, I can also use demo images, and pre-built toolchains.</li><li>Downloaded the pre-built <a href="http://www.angstrom-distribution.org/toolchains/">toolchain</a> (<span style="font-size:85%;"><span style="font-family:courier new;">angstrom-2010.4-test-20100421-x86_64-linux-armv7a-linux-gnueabi-toolchain-qte-4.6.2.tar.bz2</span></span>).</li><li>Built a Beagleboard kernel based on <a href="http://gitorious.org/angstrom/angstrom-linux/commits/beagleboardXM"><span style="font-size:85%;"><span style="font-family:courier new;">angstrom-linux/beagleboardXM</span></span></a>, using that toolchain.</li><li>Formatted a 1GiB SD-card according to the <a href="http://code.google.com/p/beagleboard/wiki/LinuxBootDiskFormat">guide</a>, and copied the content from the <a href="http://www.angstrom-distribution.org/demo/beagleboard/sd-images/2gb/Angstrom-Beagleboard-demo-image-glibc-ipk-2010.3-beagleboard.sd-image-2GiB.img.bz2">demo image</a> to it. Since my SD-card is only 1GiB, and the image is 2GiB, I "<span style="font-family:courier new;">dd</span>"-ed the first FAT partition (to make sure that files are in the right order), but copied all the files on the ext3 partition.<br /></li></ul>Plans:<br /><ul><li>Try to finish building Angstrom (I freed some disk space, and maybe I messed up somewhere).</li><li>Test the SD-card I formatted.</li><li>Replace the kernel on the SD-card with the one I built.</li><li>Use the newest root filesystem (if I manage to finish building it).</li><li>Test the USB gadget and EHCI controllers with a few different drivers/devices.</li><li>Start working on the proxy driver (i.e., the project itself).<br /></li></ul>Risks:<br /><ul><li>Unable to build Angstrom: nevermind, I can use demo images (at least for now).</li><li>?<br /></li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-5059383081700983532010-05-18T07:50:00.001-07:002010-05-18T07:50:33.542-07:00Device emulationSo, as it seems that hub emulation cannot be done, here is how device emulation would work.<br /><br />We need a kernel driver that lies between the slave (gadget, MUSB) port and the master (EHCI) port. This "proxy" driver will be registered both as a USB device driver, and as a USB gadget driver. It will then "simply" forward USB packets back and forth between the 2 interfaces.<br /><br />First, the sniffed device is connected to the master port of the BeagleBoard. The Linux kernel assign an address to it, reads its descriptors, select a configuration, and tries to find a driver for the new device. Reading the descriptors and assigning the address are probably fine (it needs to be done anyway, and it should be a rather standard operation), but we probably do not want to set a configuration, and clearly do not want any driver to initialize the device.<br /><br />Then, we want to bind the device to our proxy driver (this can be done using<span style="font-family:courier new;"> echo [device] > /sys/bus/usb/drivers/xxx/[un]bind </span>).<br />The proxy driver will then copy the descriptors, and activate the slave port. The host PC enumerates the new device, sets an address to it, and obtains the copied descriptors (and hopefully believes that it is connected to the actual device).<br /><br />Some additional control transfers (i.e. endpoint <span style="font-family:courier new;">0</span>) may happen, such as configuration selection. These need to be forwarded to the real device.<br /><br />To be able to actually use the device, other endpoints (in addition to the mandatory endpoint <span style="font-family:courier new;">0</span>) need to be configured in the gadget driver, and registered on the device side, so that the data can be forwarded. The required endpoints can be obtained from the device descriptor (below, the (very simple) descriptor for a mouse):<br /><pre><br />Bus 006 Device 003: ID 046d:c018 Logitech, Inc. Optical Wheel Mouse<br />Device Descriptor:<br />bLength 18<br />bDescriptorType 1<br />bcdUSB 2.00<br />bDeviceClass 0 (Defined at Interface level)<br />bDeviceSubClass 0<br />bDeviceProtocol 0<br />bMaxPacketSize0 8<br />idVendor 0x046d Logitech, Inc.<br />idProduct 0xc018 Optical Wheel Mouse<br />bcdDevice 43.01<br />iManufacturer 1 Logitech<br />iProduct 2 USB Optical Mouse<br />iSerial 0<br />bNumConfigurations 1<br />Configuration Descriptor:<br />bLength 9<br />bDescriptorType 2<br />wTotalLength 34<br />bNumInterfaces 1<br />bConfigurationValue 1<br />iConfiguration 0<br />bmAttributes 0xa0<br /> (Bus Powered)<br /> Remote Wakeup<br />MaxPower 100mA<br />Interface Descriptor:<br /> bLength 9<br /> bDescriptorType 4<br /> bInterfaceNumber 0<br /> bAlternateSetting 0<br /> bNumEndpoints 1<br /> bInterfaceClass 3 Human Interface Device<br /> bInterfaceSubClass 1 Boot Interface Subclass<br /> bInterfaceProtocol 2 Mouse<br /> iInterface 0<br /> HID Device Descriptor:<br /> bLength 9<br /> bDescriptorType 33<br /> bcdHID 1.11<br /> bCountryCode 0 Not supported<br /> bNumDescriptors 1<br /> bDescriptorType 34 Report<br /> wDescriptorLength 52<br /> Report Descriptors:<br /> ** UNAVAILABLE **<br /> Endpoint Descriptor:<br /> bLength 7<br /> bDescriptorType 5<br /> bEndpointAddress 0x81 EP 1 IN<br /> bmAttributes 3<br /> Transfer Type Interrupt<br /> Synch Type None<br /> Usage Type Data<br /> wMaxPacketSize 0x0005 1x 5 bytes<br /> bInterval 10<br />Device Status: 0x0000<br />(Bus Powered)<br /></pre><br />From that descriptor, we can see that we need to configure the gadget driver to handle outgoing interrupt transfers on endpoint <span style="font-family:courier new;">1</span>, and that we need to listen for interrupt transfers on endpoint <span style="font-family:courier new;">1</span>, coming from the device.<br /><br />My plan for the following weeks:<br /><ul><li>Manually copy the descriptor of a simple device (a mouse/keyboard would do)</li><li>Handle control transfers forwarding</li><li> Connect one endpoint on the slave and master sides (EP 1 IN, interrupt for mouse/keyboard)</li><li> Forward interrupt transfers</li></ul>Some other thoughts:<br /><ul><li> Mice and keyboards are usually Low Speed devices, which is not supported by many gadget controllers (including MUSB), does it hurt if we advertise them as Full Speed devices on the gadget-host link?</li><li> If a device has multiple configurations, an endpoint may have different types and/or directions depending on the configuration, we need to be able to handle that (and intercept <span style="font-family:courier new;">SET_CONFIGURATION</span> requests).</li><li> Some devices change descriptor (and disconnect/reconnect) after a firmware load (e.g., FX2-based devices), we need to find a way to handle that, and reattach to the "new" device automatically.</li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-65082420851593470102010-05-15T06:32:00.000-07:002010-05-15T06:40:51.319-07:00Device vs hub emulationThere are 2 main alternatives to implement the USB sniffer:<br /><ul><li>Device emulation: Emulate the sniffed device itself: That is, pretend that we are the device itself, and forward packets back and forth between the device and the host.</li><li>Hub emulation: Emulate a USB hub. That is, act as if we were a USB hub, with several ports. One (or more) of these ports would be connected to the device to be analysed. Other ports would still be available for other USB gadgets (e.g., Ethernet, serial gadgets).<br /></li></ul>For the hub emulation, I should first try to explain how a USB hub works (or at least, how I understand it works, skipping details):<br />An USB hub is a simple repeater: that is, each packet coming from the host is broadcasted to all the devices connected to it. An USB token packet contains, among other things, an address field. As each device is assigned an unique address, it can safely ignore transfers that are not meant for it. Packets coming from the device are not broadcasted (it would not make any sense), and are simply forwarded back to the host.<br /><br />When a new device is connected to a hub, the hub informs the host. The new device, by default, takes address 0, and the host can then initiate basic communication with it using that address. One of the first thing the host does it to send a <span style="font-family:courier new;">SET_ADDRESS</span> command to the device, the new device will then answer on that new address (and not on address <span style="font-family:courier new;">0</span> anymore).<br /><br />Now, the question is, can we implement this on the BeagleBoard, with the MUSB controller? For this, the MUSB controller needs to be able to listen on all possible USB addresses (similar to a promiscuous mode on an Ethernet controller). Depending on the address, we could then forward the packet to the sniffed device, or on any other virtual gadget device (since we have more processing power than a normal USB hub, we can be more clever and avoid broadcasting the data to every device).<br /><br />From what I see in the <a href="http://gitorious.org/angstrom/angstrom-linux/blobs/beagleboardXM/drivers/usb/musb/musb_gadget_ep0.c">code of the MUSB controller driver</a>, there seems to be only one register containing the USB address to listen on. This register (<span style="font-family:courier new;">F_ADDR</span>) is updated at line 706, after a <span style="font-family:courier new;">SET_ADDRESS</span> command is received from the host:<br /><pre> if (musb->set_address) {<br /> musb->set_address = false;<br /> musb_writeb(mbase, MUSB_FADDR, musb->address);<br /> }<br /></pre>Therefore, it seems like the MUSB controller is only able to listen on a single address, so it looks like it may not be possible to implement a USB hub.drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0tag:blogger.com,1999:blog-764876530099788129.post-24494367323090240192010-05-13T04:30:00.000-07:002010-05-13T04:31:28.892-07:00Project GoalThe goal of this Google Summer of Code 2010 project is to have some hardware USB sniffer on the Beagle Board. The host PC is connected on the slave USB port of the Beagle Board, and the device to be analysed on the host port of the Beagle Board.<br /><br />The goal is to have a completely transparent solution to forward USB packets from the host PC to the device (and back), while logging the data: that is, neither the host PC nor the device must be able to realise that there is a sniffer in the middle, intercepting packets.<br /><br />Software solutions to capture packets already exist (e.g., USB Snoopy on Windows, USB monitor on Linux), but a hardware solution would have the advantage of:<br /><ul><li>Not requiring any software modification</li><li>Supporting proprietary OSes, where you may not have access to the software</li><li>Allowing debugging of a new USB stack: If, let's say, you are developing a new USB stack for your preferred operating system, any software logging solution would obviously be as reliable as the stack you are currently developing, hence the usefulness of a hardware solution.</li><li>Depending on the capabilities of the OTG and EHCI chips, being able to capture USB frames at a lower level, and maybe monitor for transmission errors for example. </li></ul>drinkcathttp://www.blogger.com/profile/08991363247732795423noreply@blogger.com0