| 1 | ====================
|
| 2 | How FunctionFS works
|
| 3 | ====================
|
| 4 |
|
| 5 | Overview
|
| 6 | ========
|
| 7 |
|
| 8 | From kernel point of view it is just a composite function with some
|
| 9 | unique behaviour. It may be added to an USB configuration only after
|
| 10 | the user space driver has registered by writing descriptors and
|
| 11 | strings (the user space program has to provide the same information
|
| 12 | that kernel level composite functions provide when they are added to
|
| 13 | the configuration).
|
| 14 |
|
| 15 | This in particular means that the composite initialisation functions
|
| 16 | may not be in init section (ie. may not use the __init tag).
|
| 17 |
|
| 18 | From user space point of view it is a file system which when
|
| 19 | mounted provides an "ep0" file. User space driver need to
|
| 20 | write descriptors and strings to that file. It does not need
|
| 21 | to worry about endpoints, interfaces or strings numbers but
|
| 22 | simply provide descriptors such as if the function was the
|
| 23 | only one (endpoints and strings numbers starting from one and
|
| 24 | interface numbers starting from zero). The FunctionFS changes
|
| 25 | them as needed also handling situation when numbers differ in
|
| 26 | different configurations.
|
| 27 |
|
| 28 | For more information about FunctionFS descriptors see :doc:`functionfs-desc`
|
| 29 |
|
| 30 | When descriptors and strings are written "ep#" files appear
|
| 31 | (one for each declared endpoint) which handle communication on
|
| 32 | a single endpoint. Again, FunctionFS takes care of the real
|
| 33 | numbers and changing of the configuration (which means that
|
| 34 | "ep1" file may be really mapped to (say) endpoint 3 (and when
|
| 35 | configuration changes to (say) endpoint 2)). "ep0" is used
|
| 36 | for receiving events and handling setup requests.
|
| 37 |
|
| 38 | When all files are closed the function disables itself.
|
| 39 |
|
| 40 | What I also want to mention is that the FunctionFS is designed in such
|
| 41 | a way that it is possible to mount it several times so in the end
|
| 42 | a gadget could use several FunctionFS functions. The idea is that
|
| 43 | each FunctionFS instance is identified by the device name used
|
| 44 | when mounting.
|
| 45 |
|
| 46 | One can imagine a gadget that has an Ethernet, MTP and HID interfaces
|
| 47 | where the last two are implemented via FunctionFS. On user space
|
| 48 | level it would look like this::
|
| 49 |
|
| 50 | $ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid
|
| 51 | $ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp
|
| 52 | $ ( cd /dev/ffs-mtp && mtp-daemon ) &
|
| 53 | $ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid
|
| 54 | $ ( cd /dev/ffs-hid && hid-daemon ) &
|
| 55 |
|
| 56 | On kernel level the gadget checks ffs_data->dev_name to identify
|
| 57 | whether its FunctionFS is designed for MTP ("mtp") or HID ("hid").
|
| 58 |
|
| 59 | If no "functions" module parameters is supplied, the driver accepts
|
| 60 | just one function with any name.
|
| 61 |
|
| 62 | When "functions" module parameter is supplied, only functions
|
| 63 | with listed names are accepted. In particular, if the "functions"
|
| 64 | parameter's value is just a one-element list, then the behaviour
|
| 65 | is similar to when there is no "functions" at all; however,
|
| 66 | only a function with the specified name is accepted.
|
| 67 |
|
| 68 | The gadget is registered only after all the declared function
|
| 69 | filesystems have been mounted and USB descriptors of all functions
|
| 70 | have been written to their ep0's.
|
| 71 |
|
| 72 | Conversely, the gadget is unregistered after the first USB function
|
| 73 | closes its endpoints.
|
| 74 |
|
| 75 | Endpoint IOCTLs
|
| 76 | ===============
|
| 77 |
|
| 78 | FunctionFS supports additional IOCTLs that can be performed on data endpoints
|
| 79 | (ie. not ep0). For a full list of these IOCTLs, please refer to the documentation
|
| 80 | in ``include/uapi/linux/usb/functionfs.h``.
|
| 81 |
|
| 82 | One such IOCTL is:
|
| 83 |
|
| 84 | ``FUNCTIONFS_ENDPOINT_ENABLE_ZLP(__u32 *)``
|
| 85 | Enable or disable automatic zero-length packet (ZLP) appending for the
|
| 86 | endpoint. The argument is a pointer to a __u32: 0 to disable, non-zero to
|
| 87 | enable. When enabled, the kernel will automatically append a ZLP at the end
|
| 88 | of a transfer if the payload length is an exact multiple of the endpoint's
|
| 89 | max packet size. This is useful for compatibility with legacy protocols
|
| 90 | which require automatic ZLP appending to data written from userspace. This
|
| 91 | IOCTL can only be used on IN endpoints. It can be called at any time after
|
| 92 | the FunctionFS instance is active, even before the host has connected or
|
| 93 | enabled the endpoint. Returns zero on success, or a negative errno value on
|
| 94 | error:
|
| 95 |
|
| 96 | * ``-ENODEV``: The FunctionFS instance is not active.
|
| 97 | * ``-EINVAL``: The endpoint is not an IN endpoint.
|
| 98 | * ``-EFAULT``: Invalid user space pointer for the argument.
|
| 99 |
|
| 100 | RW Proxy Endpoints
|
| 101 | ==================
|
| 102 |
|
| 103 | If the ``FUNCTIONFS_RW_PROXY_EPS`` flag is passed in the descriptor header
|
| 104 | (requires ``FUNCTIONFS_DESCRIPTORS_MAGIC_V2``), FunctionFS will provision a
|
| 105 | bidirectional rw_proxy file descriptor (e.g., "ep1_rw") alongside each pair
|
| 106 | of IN and OUT endpoints. The rw_proxy file aliases the underlying hardware
|
| 107 | endpoints, allowing userspace to use a single file descriptor for both reading
|
| 108 | (OUT) and writing (IN).
|
| 109 |
|
| 110 | This flag requires the total number of hardware endpoints to be an even number.
|
| 111 | FunctionFS will automatically walk the provided endpoints and group them into
|
| 112 | adjacent pairs (e.g., ep1 and ep2 form the first pair, ep3 and ep4 form the
|
| 113 | second pair). Each pair must consist of exactly one IN endpoint and one OUT
|
| 114 | endpoint.
|
| 115 |
|
| 116 | For each valid pair, a rw_proxy file is created and named after the first
|
| 117 | endpoint in the pair with a "_rw" suffix. For example, if ep1 and ep2 are
|
| 118 | paired, a rw_proxy file named "ep1_rw" is created. If ep3 and ep4 are paired,
|
| 119 | "ep3_rw" is created.
|
| 120 |
|
| 121 | If the ``FUNCTIONFS_VIRTUAL_ADDR`` flag is also enabled, the endpoints will be
|
| 122 | named using their physical endpoint address in hexadecimal instead of their
|
| 123 | index. RW proxy files will inherit this naming convention. For example, if the
|
| 124 | first endpoint of a pair maps to address 0x02, the rw_proxy file will be
|
| 125 | named "ep02_rw".
|
| 126 |
|
| 127 | When this flag is enabled, userspace has the choice of performing data transfers
|
| 128 | via the single rw_proxy file descriptor or the two base file descriptors. The
|
| 129 | rw_proxy file descriptor acts as a pure VFS alias that proxies all operations
|
| 130 | directly to the underlying base file descriptors.
|
| 131 |
|
| 132 | Because it is a pure proxy, there are no data races or buffer corruptions if
|
| 133 | userspace uses both the rw_proxy endpoint and the base endpoints concurrently.
|
| 134 | The native mutexes of the base endpoints perfectly serialize all concurrent
|
| 135 | transfers. However, userspace should generally pick one method and stick to it
|
| 136 | to avoid interleaving its own data stream.
|
| 137 |
|
| 138 | - **IOCTLs (Clear Halt, etc.):** RW proxy endpoints do not support IOCTLs and
|
| 139 | will return ``-ENOTTY``. To clear a host-initiated halt, userspace must issue
|
| 140 | the ``FUNCTIONFS_CLEAR_HALT`` ioctl directly on the corresponding base
|
| 141 | endpoint file descriptor.
|
| 142 | - **Intentional Stalls:** The traditional mechanism for intentionally halting an
|
| 143 | endpoint by issuing a reverse-direction data operation (e.g., attempting to
|
| 144 | read from an IN endpoint) continues to work, but it must be issued on the
|
| 145 | base endpoint. RW proxy endpoints cannot be used to trigger a stall because
|
| 146 | they are fully bidirectional.
|
| 147 |
|
| 148 | Note that DMABUF data transfers (``FUNCTIONFS_DMABUF_TRANSFER``) are unsupported
|
| 149 | via the rw_proxy endpoint because it does not support IOCTLs. If DMABUF
|
| 150 | transfers are required, users must use the standard base endpoints.
|
| 151 | DMABUF interface
|
| 152 | ================
|
| 153 |
|
| 154 | FunctionFS additionally supports a DMABUF based interface, where the
|
| 155 | userspace can attach DMABUF objects (externally created) to an endpoint,
|
| 156 | and subsequently use them for data transfers.
|
| 157 |
|
| 158 | Note: The DMABUF interface is unsupported on rw_proxy endpoints. See
|
| 159 | the RW Proxy Endpoints section for details on using DMABUF alongside
|
| 160 | the ``FUNCTIONFS_RW_PROXY_EPS`` flag.
|
| 161 |
|
| 162 | A userspace application can then use this interface to share DMABUF
|
| 163 | objects between several interfaces, allowing it to transfer data in a
|
| 164 | zero-copy fashion, for instance between IIO and the USB stack.
|
| 165 |
|
| 166 | As part of this interface, three new IOCTLs have been added. These three
|
| 167 | IOCTLs have to be performed on a data endpoint (ie. not ep0). They are:
|
| 168 |
|
| 169 | ``FUNCTIONFS_DMABUF_ATTACH(int)``
|
| 170 | Attach the DMABUF object, identified by its file descriptor, to the
|
| 171 | data endpoint. Returns zero on success, and a negative errno value
|
| 172 | on error.
|
| 173 |
|
| 174 | ``FUNCTIONFS_DMABUF_DETACH(int)``
|
| 175 | Detach the given DMABUF object, identified by its file descriptor,
|
| 176 | from the data endpoint. Returns zero on success, and a negative
|
| 177 | errno value on error. Note that closing the endpoint's file
|
| 178 | descriptor will automatically detach all attached DMABUFs.
|
| 179 |
|
| 180 | ``FUNCTIONFS_DMABUF_TRANSFER(struct usb_ffs_dmabuf_transfer_req *)``
|
| 181 | Enqueue the previously attached DMABUF to the transfer queue.
|
| 182 | The argument is a structure that packs the DMABUF's file descriptor,
|
| 183 | the size in bytes to transfer (which should generally correspond to
|
| 184 | the size of the DMABUF), and a 'flags' field which is unused
|
| 185 | for now. Returns zero on success, and a negative errno value on
|
| 186 | error.
|