Andrzej Pietrasiewicz | 581791f | 2012-05-14 15:51:52 +0200 | [diff] [blame] | 1 | *How FunctionFS works* |
| 2 | |
| 3 | From kernel point of view it is just a composite function with some |
| 4 | unique behaviour. It may be added to an USB configuration only after |
| 5 | the user space driver has registered by writing descriptors and |
| 6 | strings (the user space program has to provide the same information |
| 7 | that kernel level composite functions provide when they are added to |
| 8 | the configuration). |
| 9 | |
| 10 | This in particular means that the composite initialisation functions |
| 11 | may not be in init section (ie. may not use the __init tag). |
| 12 | |
| 13 | From user space point of view it is a file system which when |
| 14 | mounted provides an "ep0" file. User space driver need to |
| 15 | write descriptors and strings to that file. It does not need |
| 16 | to worry about endpoints, interfaces or strings numbers but |
| 17 | simply provide descriptors such as if the function was the |
| 18 | only one (endpoints and strings numbers starting from one and |
| 19 | interface numbers starting from zero). The FunctionFS changes |
| 20 | them as needed also handling situation when numbers differ in |
| 21 | different configurations. |
| 22 | |
| 23 | When descriptors and strings are written "ep#" files appear |
| 24 | (one for each declared endpoint) which handle communication on |
| 25 | a single endpoint. Again, FunctionFS takes care of the real |
| 26 | numbers and changing of the configuration (which means that |
| 27 | "ep1" file may be really mapped to (say) endpoint 3 (and when |
| 28 | configuration changes to (say) endpoint 2)). "ep0" is used |
| 29 | for receiving events and handling setup requests. |
| 30 | |
| 31 | When all files are closed the function disables itself. |
| 32 | |
| 33 | What I also want to mention is that the FunctionFS is designed in such |
| 34 | a way that it is possible to mount it several times so in the end |
| 35 | a gadget could use several FunctionFS functions. The idea is that |
| 36 | each FunctionFS instance is identified by the device name used |
| 37 | when mounting. |
| 38 | |
| 39 | One can imagine a gadget that has an Ethernet, MTP and HID interfaces |
| 40 | where the last two are implemented via FunctionFS. On user space |
| 41 | level it would look like this: |
| 42 | |
| 43 | $ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid |
| 44 | $ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp |
| 45 | $ ( cd /dev/ffs-mtp && mtp-daemon ) & |
| 46 | $ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid |
| 47 | $ ( cd /dev/ffs-hid && hid-daemon ) & |
| 48 | |
| 49 | On kernel level the gadget checks ffs_data->dev_name to identify |
| 50 | whether it's FunctionFS designed for MTP ("mtp") or HID ("hid"). |
| 51 | |
| 52 | If no "functions" module parameters is supplied, the driver accepts |
| 53 | just one function with any name. |
| 54 | |
| 55 | When "functions" module parameter is supplied, only functions |
| 56 | with listed names are accepted. In particular, if the "functions" |
| 57 | parameter's value is just a one-element list, then the behaviour |
| 58 | is similar to when there is no "functions" at all; however, |
| 59 | only a function with the specified name is accepted. |
| 60 | |
| 61 | The gadget is registered only after all the declared function |
| 62 | filesystems have been mounted and USB descriptors of all functions |
| 63 | have been written to their ep0's. |
| 64 | |
| 65 | Conversely, the gadget is unregistered after the first USB function |
| 66 | closes its endpoints. |
| 67 | |