 All right. Good morning. Thanks for coming. My name is Andrzej Piotrasiewicz. I work for a collaborator. And today you will hear about modern USB gadgets with custom USB functions and its integration with system D. I guess in this room there are at least some people who own this kind of a Linux machine. And from time to time you connect it to a PC to for example transfer your pictures. And then your machine acts as a USB device. While you most probably consider yourselves users of such devices today I will show you how you can actually become creators of similar USB devices. To illustrate the covered topics I will show you a live demo. So by the end of this presentation you will understand how to create USB gadgets and integrate the creation with system D if needed. Of course you need to follow some rules. The set of available components for creating your gadgets is limited but I will tell you what to do if you want your custom USB function. You need to use some tools and want your gadget creation integrated with system D if it happens to be running on your device. You can treat this slide as a roadmap of today's presentation which will take about 25 minutes and then a short demo will follow. So in USB there are two distinct roles. A host and a device. Today our focus is on a device. Speaking precisely on a device implemented as a machine running Linux. Such a machine must be equipped with a piece of hardware called UDC, a USB device controller. You can also come across the term OTG on the go device which can act either as a host or a device but for the purpose of this talk we will be using the term UDC. Such a machine can be called a gadget. Before we move on to composing such gadgets let's learn about some rules about composing them. Knowing about USB endpoints is important to you because ultimately all USB communication happens through endpoints of which there are four kinds. Control, bulk, interrupt and isochronos. You can compare USB endpoints to ports in TCP IP transmission. So in a host there can be a number of ports open each providing a different service. Similarly in a USB device there can be a number of endpoints each providing a different flavor of data connectivity. Control endpoints are for transmitting control information such as the selection of the target endpoint to the device. USB is a serial bus after all so before any transfer the controlling logic must specify the target endpoint of the next transfer. Bulk endpoints are for transmitting potentially large amounts of data with data correctness guarantee but without timing guarantees. Interrupt endpoints are for transmitting information about asynchronous events and they provide both data correctness and timing guarantees. The name is misleading though because in USB all the bus activity is controlled and decided by the host which pulls the device at regular intervals in interrupt transmission. Isochronos endpoints are for transmitting potentially large amounts of data without correctness guarantee but with timing guarantee and are primarily useful for multimedia streams where an occasional loss of a data frame doesn't hurt as much as varying latency does. Sometimes you might need more than one or more than one kind of endpoint which brings the next topic an interface of a USB device. Why am I telling you about interfaces? Because later on we will refer many times to those interfaces implementations. An interface of a USB device is a collection of endpoints meant for a particular purpose. For example a mass storage device contains two bulk endpoints, one for each transmission direction. While an MTP device contains two bulk endpoints, one for each transmission direction and an interrupt endpoint for transmitting information about events to the host. In the Linux kernel we refer to implementations of those interfaces as USB functions. The Linux kernel provides about 20 different functions and in fact a device can provide more than one such an interface at a time so let's see how this is organized. A configuration of a USB device is a collection of one or more interfaces. The standard allows more than one configuration in a device but in practice multiple configurations are rarely seen. So to recap this time in a top-down fashion. USB device logical view is a collection of configurations each of which is a collection of interfaces, each of which is a collection of endpoints. Now let's see what to do if we want a USB function not provided by the Linux kernel. There is a special USB function which you can use as a component of your gadgets. It is called function FS and as its name implies apart from being a USB function it is also a file system. A pseudofil system to be precise. And it is used to delegate actual USB function implementation to user space. When an instance of function FS is made available and mounted it contains only a single file called EP0. Its name is an allusion to the endpoint 0 all USB devices must provide. The user space must then write to this EP0 file binary description of interfaces, endpoints and strings provided by the Eurocustom USB function. Strings are human readable descriptions of your function and they can be presented to the user. After that the kernel instantiates appropriate interfaces, endpoints and strings. And from that moment on a user space program can read, write or poll the EP files to implement your own custom USB function by transferring data to and from the host using regular file operations. Now let's get back to the question of composing a gadget from available components be it kernel provided or user space implemented. The traditional way of composing USB gadgets was to write a kernel module for each combination of configurations and functions. You need to know that even if we limit ourselves to only one configuration. And we choose any number of available kernel provided functions. And we only use one instance, a single instance of each chosen function. We end up with quite a large number of theoretical possibilities. Even though many of them make little sense, that still makes it impractical to provide all precomposed configurations. And that is why since about the end of 2012 you have the option to compose your gadget at runtime using a dedicated interface. And so now that you know about logical structure of USB gadgets, let's see how to use the dedicated interface. The interface chosen by the community to manipulate USB gadgets is ConfigFS. ConfigFS is another pseudo file system. Internally it is similar to CISFS, but while CISFS is primarily a window through which you can see the internal state of the system. ConfigFS is meant for creating and destroying kernel objects whose lifetime is decided by the user, that is by you. So let's see, we use simple shell commands to manipulate our gadgets. So let's see an example Ethernet over USB gadgets created with the ConfigFS interface. Don't worry we will go through it step by step. So even though simple shell commands are used, you need to know where to look for ConfigFS, what to look for, what kind of things to create and what parameters to specify. An example here indicated in reds, we specify USB device IDs. We create some strings, we create a configuration and a function. We associate a function to a configuration and then make the gadgets available. To ease this process you can use an open source tool called GT, a gadget tool. It allows creating your gadgets from command line step by step or by reading declarative config files called gadget schemes. Let's see such a scheme file for the equivalent of Ethernet over USB gadgets we've just seen. The scheme file is shown in two columns. Thanks to such a scheme file all we care about is what we want created rather than how to poke around ConfigFS. For example, here we declare USB device IDs, we declare strings, we declare the functions we want in our gadgets, we declare our configurations and we declare the association of a function to a configuration. Even though the already covered topics are enough to easily create your USB gadget, for example with GT, now you can have your gadget creation integrated with SystemD. SystemD has been with us for a while and is becoming a de facto standard in many systems. The components of a system are described with so-called units, for example service units, mount units, target units, socket units and so on. These can be managed in a uniform way. SystemD also tracks dependencies between the units and thanks to that it offers high parallelization. Combined with lazy initialization which should result in shorter booting times of our machines. The lazy initialization is possible because many clients are interested only in being past open file descriptors and they don't care about the process behind those descriptors. We will come back to this concept when talking about FunctionFS in the context of SystemD. Now let's discuss the recent additions to SystemD. You need to know that in the beginning of this year two small but important additions were upstreamed in SystemD, from version 243 I guess. The first one is a USB gadget target. It is a target other units can depend on, for example to create your USB gadgets with GT using a gadget scheme. The other one is a UDF rule which fires when a UDC chip becomes available in our Linux machine acting as a USB gadget. The combination of these two with a service unit creates our USB gadgets at UDC's appearance. So let's see such an example service unit. This service unit composes the equivalent of the Ethernet of over USB gadgets we've seen before. It requires configFS, the lines indicated in right. And upon start it uses GT to load and activate our Ethernet over USB gadgets. It must not inherit default dependencies, otherwise a dependency cycle is formed. And it does have an install section, thanks to which you as a system administrator, you still remember that we are talking about USB gadgets implemented as machines running Linux, don't you? So you as a system administrator of such a machine can then use system CTL to enable or disable your gadget creation at UDC's appearance. In fact, you can make the gadget name, again indicated in red, a template parameter, and then have many gadgets to choose from for enabling or disabling using just a single template unit. If you are interested only in functions provided by the Linux kernel, this kind of a service unit is all you need. However, if you want your own USB function implemented on top of function FS, we need some more, and this case is a little bit more complicated. We need a gadget scheme as before. We also need a service unit. This service unit is almost the same as in the previous case. The difference is that we cannot activate and load and activate the gadget at the same time, because activating it at this stage would fail, as the user space demon has not been started yet. So the only difference is the minus O switch to GT load, which does just that, load without activating. This service unit must be enabled as before, and we won't be analyzing its contents again. Since we use function FS, we need a mount unit to have it mounted. And we can use a socket unit to lazily start our demon, and with a socket unit always comes its associated service unit. Before we move on to analyzing the unit's contents, let's see the gadget scheme we will be using. It is very similar to the Ethernet over USB scheme we've seen before. The difference is, the most important difference is that we use FFS as function type instead of ECM. FFS for function FS. The instance name, here MTP, is very important, because later on this will become the name of a device when mounting this function FS instance. Speaking of mounting, we need a mount unit. By definition any mount unit cannot be templatized, this one is no exception. This particular mount unit automates mounting a device called MTP, remember function FS instance name, under run ffs underscore MTP mount point. There is no install section in this unit. It will be activated based only on dependencies after our first service unit, but before the socket unit. So let's see the socket unit. This socket unit is the most important unit from the point of view of activating our user space implemented USB function. It pulls in the mount unit as a dependency, and it does have its install section, which means it has to be system CTL enabled. It must not inherit default dependencies, otherwise a dependency cycle is formed, and it listens for traffic under our function FS mount point, and if some traffic happens, it starts our service unit. So let's see the service unit. Oh, but after the service unit fully starts, it uses GT to finally enable our gadget. Remember that in the first service unit, we only loaded the gadget without activating it. So once the second service unit fully starts, we can then enable the gadget, because the user space demon has already been started. And now the last service unit. This service unit is where you finally reference your USB function implementation, user space implementation of your USB function. So it specifies the demon binary to be launched, and the USB function descriptors and USB function strings for function FS. These are binary blobs, whose format is specified in include UAPI Linux USB function FS.h. They are written to the EP0 file by system D, and the demon binary is launched when it is actually needed. You might have noticed that you need binary blobs containing USB descriptors and strings, and I have something for you. There is a pull request pending, which adds support for creating such descriptors and string blobs with gadget tool. You may find it interesting when creating your own USB functions on top of function FS, because it allows creating the set blobs based on declarative config files. At this moment there are limitations, though, of what kind of descriptors can be created this way. But for basic use cases this extension is already a useful tool. And now is ready more time. You will see a USB gadget composed upon UDC's appearance. It will consist of a single instance of function FS, and the user space implemented USB function will be an MTP responder, called CMTP responder. It is available on GitHub. I will run the demo on this Android U2 board, but any board with UDC available can be used. The physical setup is pretty straightforward. The UART of the board is connected to my laptop with UART to USB converter, and the board's micro USB port is connected to the laptop as well, and that latter connection will be the connection our USB device uses. So here's the console of the board. The board has already booted. Now let's see the ingredients of our gadgets. So the first thing that triggers the whole process is the UDAF rule. So let's see it. On this development board I'm using a Dibian release, which uses system D's release, which predates the addition of the rule and the gadget target. That's why I'm using administrator directories for the files. So let's go to HCUDAF rules D, and let's see the rule. So the rule is exactly the same as in the slides. So basically when UDC appears, it's tagged with system D, and our USB gadget target is referenced. Now let's see the target itself. It's also exactly the same as it was in the slides, a typo, once again. Okay, nothing special, just a target, other units can depend on. Now the first service unit, which loads the gadget without activating it. It's a template unit, exactly the same as in the slides. So the exact start entry in the service section is where we specify the command to be run. So we run gadget tool to load our gadget without activating it. We will be using ffs underscore mtp as the template parameter. The mount units. So we mount our function fs instance in run ffs underscore mtp, so we are looking for a mount unit called run ffs underscore mtp, and it is exactly the same as in the slides. And then our socket unit, it pulls in the mount unit as a dependency, and then our last service unit, which references the demon binder and the string descriptors and the descriptor blobs and the USB function descriptor blobs. Ok, so now let me enable the first service unit and the socket unit, and now I will reboot the board and the gadget should appear. So let's see. The kernel is booting. SystemD has taken over, and in a while we should see, there we go. Ok, we have our, sorry, we have our gadget. It's empty. Let's create a directory, maybe some documents, some more directories. Let's copy a picture to this device. Ok, there we go. It's me attending a conference called Linux Vacation Eastern Europe in the woods near Grodno Belarus. Ok, let's copy the picture back to the desktop. Yeah, so it's the same picture. So there you go, an open source implementation of an MTP device. Ok, so to summarize. Now you know about logical structure of USB gadgets. You know how to compose your gadgets with open source tools. You know how to implement your own custom USB function. And you know how to integrate all that with SystemD. And that concludes my presentation. Are there any questions? Yes. Who did the implementation of the MTP daemon, that SystemD was starting to actually handle the... Can you repeat the beginning of the question? Who wrote the MTP daemon that starts, that handles... Ok, so it's licensed under Apache license. It was originally written by Samsung as part of Tizen. And I stripped it off all Tizen dependencies. I made it available as a standalone MTP implementation. Thank you. Any more questions? Do you have any vision or any ideas how a support for multiple UDC could be implemented? For multiple UDCs. Because now it seems that the target for SystemD it is started whenever a UDC appears. Right. The UDF rule fires whenever any UDC becomes available. Can we start a SystemD target multiple times? Well, I think in that case we might want to further customize our rule to be more specific so that it fires when the UDC wants becomes available. Yeah, yeah. That's a good discussion, actually, because... Yeah. This one of the purposes of this talk to look for maybe better alternatives. Yeah, so thanks for this question. I don't have any good ideas how to solve that, but it's something which came to my mind during your talk. Yeah, yeah. Thanks. No questions. Thank you for your attention.