Andrzej Pietrasiewicz
June 24, 2019
Reading time:
In this article, I promised to tell you how to use dummy_hcd, which consists of a software-emulated host controller and a UDC chip. In other words, this means you can play with USB gadgets even if you don't have the appropriate hardware, because your PC can act as both a USB host and a USB device.
Of course we also need some gadget to run, so why don't we use cmtp-responder? You might also want to read about USB gadgets here and here. The description will be Debian-based, so for other systems you need to adjust it accordingly.
We will need a bunch of packages:
gcc |
# we need a compiler to compile anything |
g++ |
# to satisfy cmake the easy way, but otherwise not used) |
libconfig-dev |
# libusbgx and gt need libconfig |
cmake |
# gt and cmtp-responder use cmake to generate Makefiles |
git |
# we will be cloning from git.kernel.org and github.com |
autoconf |
# libusbgx needs it |
libtool |
# libusbgx needs it |
asciidoc-base (for a2x) |
# gt builds its manpage with it |
libncurses-dev |
# compiling the kernel |
flex |
|
bison |
|
build-essential |
|
fakeroot |
|
libelf-dev |
|
libssl-dev |
|
bc |
|
libglib2.0-dev |
# gt needs it |
libsystemd-dev |
# gt needs it |
usbutils |
# for lsusb |
Run this:
apt-get install gcc g++ libconfig-dev cmake git autoconf libtool asciidoc-base libncurses-dev flex bison build-essential fakeroot libelf-dev libssl-dev bc libglib2.0-dev libsystemd-dev usbutils apt-get clean
Once complete, you can then install libusbgx and gt.
libusbgx:
git clone https://github.com/libusbgx/libusbgx.git cd libusbgx autoreconf -i ./configure --prefix=/usr make make install # as root
gt:
git clone https://github.com/kopasiak/gt.git cd gt/source cmake -DCMAKE_INSTALL_PREFIX= . make make install # as root
Unfortunately, the default kernel has neither ConfigFS nor dummy_hcd support turned on. Let's fix it!
Ensure the following options are set in the kernel config:
CONFIG_CONFIGFS_FS=y # ConfigFS support CONFIG_USB=y # USB support CONFIG_USB_GADGET=y # USB gadget framework CONFIG_USB_DUMMY_HCD=y # dummy_hcd, our emulated USB host and device CONFIG_USB_CONFIGFS=y # composing USB gadgets with ConfigFS CONFIG_USB_CONFIGFS_F_FS=y # make FunctionFS a component for creating USB gadgets with ConfigFS
Compile and install the kernel your favorite way.
Thanks to the fact that we enabled the relevant bits of the kernel, we should have dummy_hcd up and running now. To confirm, do this:
ls -l /sys/class/udc
dummy_udc.0 should be there. If it is not, verify that all the previous steps have succeeded.
gt udc
This should also show dummy_udc.0.
Once dummy_udc.0 is there, your PC is ready to emulate USB gadget hardware!
We have chosen to enable ConfigFS support. As recent Debian releases come by default with systemd, your ConfigFS should be automatically mounted by /lib/systemd/system/sys-kernel-coonfig.mount
unit under /sys/kernel/config
.
Thanks to the enabled USB gadget, and the presence of our virtual UDC, /sys/kernel/config
should now contain usb_gadget
directory. From this moment on gadgets can be composed, for example with the gt.
We will create an MTP device with cmtp-responder. When it runs, if you chose to install graphical desktop environment, you will be able to click on its icon and use it as if it were, for example, the storage space of a connected smartphone.
The instructions for cmtp-responder are here, but I provide a quick summary for you below:
git clone https://github.com/cmtp-responder/cmtp-responder.git cd cmtp-responder cmake -DBUILD_DESCRIPTORS=ON . make make install # as root
All the below as root:
mkdir /etc/gt/templates cp systemd/mtp-ffs.scheme /etc/gt/templates cp systemd/*.socket /etc/systemd/system cp systemd/*.service /etc/systemd/system cp systemd/*.mount /etc/systemd/system systemctl enable usb-gadget.service systemctl enable run-ffs_mtp.mount systemctl enable ffs.socket
Create /etc/systemd/system/usb-gadget.target
if you don't have it in /lib/systemd/system
:
[Unit] Description=Harware activated USB gadget
And create /etc/udev/rules.d/99-systemd.rules
with the below contents if your /lib/udev/rules.d/99-systemd.rules
does not contain the following line:
SUBSYSTEM=="udc", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="usb-gadget.target"
After reboot your cmtp-responder should activate automatically. You can verify its existence with lsusb
(run as root):
Bus 001 Device 002: ID 1d6b:0100 Linux Foundation PTP Gadget Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1d6b Linux Foundation idProduct 0x0100 PTP Gadget bcdDevice 5.01 iManufacturer 1 Collabora iProduct 2 MTP Gadget iSerial 3 000000001 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 39 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 2mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 6 Imaging bInterfaceSubClass 1 Still Image Capture bInterfaceProtocol 1 Picture Transfer Protocol (PIMA 15470) iInterface 4 Collabora MTP Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 6 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered)
This screenshot illustrates copying a larger file to our MTP gadget.
The backing storage is /media/card
, and can be configured at compile time in include/mtp_config_h (MTP_EXTERNAL_PATH_CHAR)
.
Happy playing with cmtp-responder!
In the next installment, I will tell you how to run it on real ARM hardware, so stay tuned.
19/12/2024
In the world of deep learning optimization, two powerful tools stand out: torch.compile, PyTorch’s just-in-time (JIT) compiler, and NVIDIA’s…
08/10/2024
Having multiple developers work on pre-merge testing distributes the process and ensures that every contribution is rigorously tested before…
15/08/2024
After rigorous debugging, a new unit testing framework was added to the backend compiler for NVK. This is a walkthrough of the steps taken…
01/08/2024
We're reflecting on the steps taken as we continually seek to improve Linux kernel integration. This will include more detail about the…
27/06/2024
With each board running a mainline-first Linux software stack and tested in a CI loop with the LAVA test framework, the Farm showcased Collabora's…
26/06/2024
WirePlumber 0.5 arrived recently with many new and essential features including the Smart Filter Policy, enabling audio filters to automatically…
Comments (19)
Metehan:
Aug 17, 2019 at 03:06 AM
Hello,
Thank you for great share!
What is the Debian version and Kernel version for this?
Reply to this comment
Reply to this comment
Andrzej Pietrasiewicz:
Aug 26, 2019 at 09:23 PM
I used kernel v5.1 and the then up-to-date debian stable netinst, which must have been "stretch" at the moment of writing.
Reply to this comment
Reply to this comment
Rektide:
Nov 03, 2019 at 10:44 PM
Nice article! Thanks. Gadgets are great!
If you are maybe taking suggestions, perhaps do usb-ip next? :)
Reply to this comment
Reply to this comment
maya:
Mar 23, 2020 at 04:29 PM
Hi!
I have all listen kernel configurations enabled. However, run-ffs_mtp.mount gives me error about unknown filesystem 'functionfs'
What can I do about it?
Thanks for this project! I hope I get it to work
Reply to this comment
Reply to this comment
Andrzej Pietrasiewicz:
Mar 24, 2020 at 11:48 AM
Ensure you have CONFIG_USB_CONFIGFS_F_FS=y, that you accidentally haven't changed any relevant options to "m" (i.e. ensure all the needed bits are compiled-in) and that you are actually running the kernel you compiled (and not e.g. your distribution kernel).
Reply to this comment
Reply to this comment
maya:
Mar 24, 2020 at 12:50 PM
There was actually two problems I had. First, gt was failing silently so I didn't first know there was a problem with it until I got suspicious that it doesn't give me any errors no matter what I do with it. Then I found an issue on github about it and it was because of a misplaced gt.conf file.
Second problem seems to be that the mounting happens too early? I can see from dmesg that it fails because functionfs filesystem is not recognized. But after boot, I can manually systemctl start it and the socket unit and then everything works. I used the exact same files as in your last october speech I found on youtube. If you know right away what it could be, let me know :) But I'm happy already that it works! Thanks alot!
Reply to this comment
Reply to this comment
Tim Rehren:
May 21, 2020 at 09:25 PM
Im Stuck at here :
root@raspberrypi:/gt/source# make
[ 19%] Built target base
[ 34%] Built target config
[ 50%] Built target function
[ 65%] Built target gadget
[ 73%] Built target settings
[ 88%] Built target udc
[ 96%] Built target gt
[100%] Generating gt.1.gz
a2x: ERROR: "xmllint" --nonet --noout --valid "/gt/source/manpages/gt.1.xml" returned non-zero exit s tatus 4
make[2]: *** [manpages/CMakeFiles/manpage.dir/build.make:61: manpages/gt.1.gz] Error 1
make[1]: *** [CMakeFiles/Makefile2:463: manpages/CMakeFiles/manpage.dir/all] Error 2
make: *** [Makefile:130: all] Error 2
Reply to this comment
Reply to this comment
Andrzej Pietrasiewicz:
May 22, 2020 at 11:55 AM
On Debian and Debian-based systems you need libxml2-utils and asciidoc-base installed to have xmllint and a2x.
Reply to this comment
Reply to this comment
Brooke Basile:
Jul 24, 2020 at 09:12 PM
Hi!
Thank you for the guide.
I'm having an issue with gt-- I've installed libusbgx and it seems to be working fine based on the directions from the github, but running make on gt fails with:
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.2")
-- Checking for modules 'libusbgx>=0.2.0;libconfig'
-- No package 'libusbgx' found
CMake Error at /usr/share/cmake/Modules/FindPkgConfig.cmake:497 (message):
A required package was not found
Call Stack (most recent call first):
/usr/share/cmake/Modules/FindPkgConfig.cmake:681 (_pkg_check_modules_internal)
CMakeLists.txt:36 (pkg_check_modules)
How can I fix this?
Reply to this comment
Reply to this comment
Andrzej Pietrasiewicz:
Aug 04, 2020 at 09:57 AM
By default libusbgx installs itself in /usr/local/{include|lib}. You might want to change it, depending on your preferences and whether you compile natively or cross-compile. Make sure it is installed in a path that is searched by cmake/pkg-config and/or pass appropriate variable to cmake to point it to the right location.
Reply to this comment
Reply to this comment
Brooke Basile:
Aug 05, 2020 at 07:58 PM
Ah, I gotcha. I did try playing with the location a bit but couldn't get it to work-- I guess I will just have to keep fiddling with it until I can get it going.
Thank you!
Reply to this comment
Reply to this comment
maya:
Feb 01, 2021 at 08:48 AM
Hi! When I connect my device to Windows, in the properties I have
Model name: DUMMY MODEL
Firmware version: devv_DUMMY_VERSION
Serial number: DUMMY_SERIAL
I have set manufacturer, product, and serialnumber in the gadget scheme. On Linux with lsusb, I see them, but on desktop I still see DUMMY MODEL in the path.
Do I need to change the hardcoded values?
Reply to this comment
Reply to this comment
Andrzej Pietrasiewicz:
Feb 02, 2021 at 09:58 AM
Hi, I assume you have built cmtp-responder for a physical device and are connecting it to either Linux or Windows host and observing different names depending on the PC host OS.
USB gadget scheme affects USB gadget strings. That's what you see with `lsusb` when querying your device with a Linux host. In Windows if you dig deep enough for device properties you will see those as well.
MTP, being a superset of PTP, offers a "PTP get device info" command, which returns whatever is compiled into cmtp-responder. Apparently Windows does not show the USB strings on the desktop, but offers the result of this command instead. You can customize the default "DUMMY" values in `include/util/mtp_util.h` (`MODEL`, `DEVICE_VERSION`, `SERIAL`).
Reply to this comment
Reply to this comment
LittleJohn:
Feb 22, 2021 at 11:41 AM
Hi, I was wondering if, since this tutorial is for a Debian OS, it was possible to use this for a Raspberry Pi on Raspbian. Since Raspbian is Debian-based, I assume it would work.
Reply to this comment
Reply to this comment
Andrzej Pietrasiewicz:
Feb 22, 2021 at 03:12 PM
It absolutely should, no problem. But perhaps not the way you imagine: this description is for running a software-emulated UDC and a USB gadget on top of it. If you follow this description on an RPi it will dutifully _emulate_ a UDC in software. So, even if you run it on e.g. Pi Zero which does have a hardware UDC (which is connected to the micro USB socket, not merely existing inside the SoC), you won't make it access the real hardware, it will still be a pure software emulation without any communication with your physical USB bus. If, however, you mean running the cmtp-responder on top of hardware UDC found in e.g. RPi Zero (to have your Pi Zero act as a physical USB gadget) rather than on top of dummy hcd, then yes, it is certainly possible. Actually, I'm going to blog about it soon, so stay tuned!
Reply to this comment
Reply to this comment
Ashvin Makawana:
Feb 22, 2022 at 09:36 AM
Hi
I have used usb ip with physical usb device earlier, now want to use usb ip with dummy hcd driver.
so, it would be possible if i could use dummy hcd device with usb ip?
As right now i am unable to test due to some hardware dependency.
can you help to share your opinion if possible?
Thanks
Reply to this comment
Reply to this comment
Andrzej Pietrasiewicz:
Feb 22, 2022 at 02:12 PM
Can you be more specific? What does it mean that you used USB IP with a physical device? What was the physical device used for? Did you use a USB gadget as your network interface to provide network connectivity for USB IP to work? Or did you use USB IP and connect to a remote USB gadget? What is that you want to achieve?
Reply to this comment
Reply to this comment
sam:
Feb 12, 2023 at 04:16 PM
root@raspberrypi:/home/pi/gt/source# cmake -DCMAKE_INSTALL_PREFIX= .
-- The C compiler identification is GNU 6.3.0
-- The CXX compiler identification is GNU 6.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29")
-- Checking for modules 'libusbgx>=0.2.0;libconfig'
-- Found libusbgx, version 0.2.0
-- Found libconfig, version 1.5
CMake Warning at CMakeLists.txt:61 (find_package):
By not providing "Findbash-completion.cmake" in CMAKE_MODULE_PATH this
project has asked CMake to find a package configuration file provided by
"bash-completion", but CMake did not find one.
Could not find a package configuration file provided by "bash-completion"
with any of the following names:
bash-completionConfig.cmake
bash-completion-config.cmake
Add the installation prefix of "bash-completion" to CMAKE_PREFIX_PATH or
set "bash-completion_DIR" to a directory containing one of the above files.
If "bash-completion" provides a separate development package or SDK, be
sure it has been installed.
CMake Error at CMakeLists.txt:68 (INSTALL):
install TARGETS given no RUNTIME DESTINATION for executable target "gt".
-- Configuring incomplete, errors occurred!
See also "/home/pi/gt/source/CMakeFiles/CMakeOutput.log".
root@raspberrypi:/home/pi/gt/source#
Why this build fails ?
Reply to this comment
Reply to this comment
Andrzej Pietrasiewicz:
Feb 13, 2023 at 03:59 PM
Your question is more of a general nature of using CMake in the context of gt rather than USB gadget-specific, so your best option is to contact gt developers instead.
That said, gt supports some bash completion (e.g. presenting you with possible continuations of the text you start typing when you press TAB), which means it depends on it. Your system is most likely missing this package, which may or may not be called "bash-completion". Try installing it using the tool appropriate for your system/distribution and likely your problem will be solved.
Reply to this comment
Reply to this comment
Add a Comment