요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
====================
How FunctionFS works
====================
Overview
========
From kernel point of view it is just a composite function with some
unique behaviour. It may be added to an USB configuration only after
the user space driver has registered by writing descriptors and
strings (the user space program has to provide the same information
that kernel level composite functions provide when they are added to
the configuration).
This in particular means that the composite initialisation functions
may not be in init section (ie. may not use the __init tag).
From user space point of view it is a file system which when
mounted provides an "ep0" file. User space driver need to
write descriptors and strings to that file. It does not need
to worry about endpoints, interfaces or strings numbers but
simply provide descriptors such as if the function was the
only one (endpoints and strings numbers starting from one and
interface numbers starting from zero). The FunctionFS changes
them as needed also handling situation when numbers differ in
different configurations.
For more information about FunctionFS descriptors see :doc:`functionfs-desc`
When descriptors and strings are written "ep#" files appear
(one for each declared endpoint) which handle communication on
a single endpoint. Again, FunctionFS takes care of the real
numbers and changing of the configuration (which means that
"ep1" file may be really mapped to (say) endpoint 3 (and when
configuration changes to (say) endpoint 2)). "ep0" is used
for receiving events and handling setup requests.
When all files are closed the function disables itself.
What I also want to mention is that the FunctionFS is designed in such
a way that it is possible to mount it several times so in the end
a gadget could use several FunctionFS functions. The idea is that
each FunctionFS instance is identified by the device name used
when mounting.
One can imagine a gadget that has an Ethernet, MTP and HID interfaces
where the last two are implemented via FunctionFS. On user space
level it would look like this::
$ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid
$ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp
$ ( cd /dev/ffs-mtp && mtp-daemon ) &
$ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid
$ ( cd /dev/ffs-hid && hid-daemon ) &
On kernel level the gadget checks ffs_data->dev_name to identify
whether its FunctionFS is designed for MTP ("mtp") or HID ("hid").
If no "functions" module parameters is supplied, the driver accepts
just one function with any name.
When "functions" module parameter is supplied, only functions
with listed names are accepted. In particular, if the "functions"
parameter's value is just a one-element list, then the behaviour
is similar to when there is no "functions" at all; however,
only a function with the specified name is accepted.
The gadget is registered only after all the declared function
filesystems have been mounted and USB descriptors of all functions
have been written to their ep0's.
Conversely, the gadget is unregistered after the first USB function
closes its endpoints.
DMABUF interface
================
FunctionFS additionally supports a DMABUF based interface, where the
userspace can attach DMABUF objects (externally created) to an endpoint,
and subsequently use them for data transfers.
A userspace application can then use this interface to share DMABUF
objects between several interfaces, allowing it to transfer data in a
zero-copy fashion, for instance between IIO and the USB stack.
As part of this interface, three new IOCTLs have been added. These three
IOCTLs have to be performed on a data endpoint (ie. not ep0). They are:
``FUNCTIONFS_DMABUF_ATTACH(int)``
Attach the DMABUF object, identified by its file descriptor, to the
data endpoint. Returns zero on success, and a negative errno value
on error.
``FUNCTIONFS_DMABUF_DETACH(int)``
Detach the given DMABUF object, identified by its file descriptor,
from the data endpoint. Returns zero on success, and a negative
errno value on error. Note that closing the endpoint's file
descriptor will automatically detach all attached DMABUFs.
``FUNCTIONFS_DMABUF_TRANSFER(struct usb_ffs_dmabuf_transfer_req *)``
Enqueue the previously attached DMABUF to the transfer queue.
The argument is a structure that packs the DMABUF's file descriptor,
the size in bytes to transfer (which should generally correspond to
the size of the DMABUF), and a 'flags' field which is unused
for now. Returns zero on success, and a negative errno value on
error.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
제목
1-4이 문서는 FunctionFS가 kernel과 user space 양쪽에서 어떻게 동작하는지 설명합니다.
====================
How FunctionFS works
====================
Kernel 관점의 composite function
5-17Kernel에서 FunctionFS는 고유한 동작을 가진 composite function입니다. User-space driver가 descriptor와 string을 기록해 등록한 뒤에만 USB configuration에 추가할 수 있습니다.
User-space program은 kernel-level composite function이 configuration에 추가될 때 제공하는 것과 같은 정보를 제공해야 합니다.
이러한 지연 등록 때문에 composite initialization function은 init section에 둘 수 없으며 `__init` tag를 사용해서는 안 됩니다.
User space가 descriptor를 제공한 뒤 composite configuration에 결합됩니다.
Overview
========
From kernel point of view it is just a composite function with some
unique behaviour. It may be added to an USB configuration only after
the user space driver has registered by writing descriptors and
strings (the user space program has to provide the same information
that kernel level composite functions provide when they are added to
the configuration).
This in particular means that the composite initialisation functions
may not be in init section (ie. may not use the __init tag).
User space의 ep0와 번호 추상화
18-29User space에서 FunctionFS는 mount하면 `ep0` file을 제공하는 file system입니다. User-space driver는 descriptor와 string을 이 file에 기록합니다.
Driver는 endpoint, interface, string의 실제 번호를 관리하지 않습니다. Function이 하나뿐인 것처럼 endpoint와 string 번호는 1부터, interface 번호는 0부터 시작해 descriptor를 제공합니다.
FunctionFS가 configuration별 번호 차이까지 포함해 필요한 번호를 실제 값으로 바꿉니다. Descriptor 형식의 자세한 내용은 `functionfs-desc` 문서를 참고합니다.
User space가 쓰는 논리 번호와 FunctionFS의 실제 mapping 책임입니다.
From user space point of view it is a file system which when
mounted provides an "ep0" file. User space driver need to
write descriptors and strings to that file. It does not need
to worry about endpoints, interfaces or strings numbers but
simply provide descriptors such as if the function was the
only one (endpoints and strings numbers starting from one and
interface numbers starting from zero). The FunctionFS changes
them as needed also handling situation when numbers differ in
different configurations.
For more information about FunctionFS descriptors see :doc:`functionfs-desc`
ep# file, event, setup request, 비활성화
30-39Descriptor와 string을 쓰면 선언한 endpoint마다 하나씩 `ep#` file이 나타나며 각 file은 단일 endpoint 통신을 처리합니다.
FunctionFS가 실제 endpoint 번호와 configuration 변경을 처리하므로 논리 `ep1`은 한 configuration에서 endpoint 3, 다른 configuration에서 endpoint 2에 mapping될 수 있습니다.
`ep0`는 event 수신과 setup request 처리에 사용됩니다. 모든 file을 닫으면 function이 스스로 비활성화됩니다.
When descriptors and strings are written "ep#" files appear
(one for each declared endpoint) which handle communication on
a single endpoint. Again, FunctionFS takes care of the real
numbers and changing of the configuration (which means that
"ep1" file may be really mapped to (say) endpoint 3 (and when
configuration changes to (say) endpoint 2)). "ep0" is used
for receiving events and handling setup requests.
When all files are closed the function disables itself.
여러 FunctionFS instance
40-45FunctionFS는 여러 번 mount할 수 있도록 설계되어 하나의 gadget에서 여러 FunctionFS function을 사용할 수 있습니다.
각 instance는 mount할 때 사용한 device name으로 식별됩니다.
What I also want to mention is that the FunctionFS is designed in such
a way that it is possible to mount it several times so in the end
a gadget could use several FunctionFS functions. The idea is that
each FunctionFS instance is identified by the device name used
when mounting.
MTP와 HID 다중 instance 예제
46-58예제 gadget은 Ethernet, MTP, HID interface를 가지며 MTP와 HID를 FunctionFS로 구현합니다. `g_ffs.ko`에 `functions=mtp,hid`를 주고 `mtp`, `hid` 이름으로 각각 mount한 뒤 별도의 daemon을 실행합니다.
Kernel에서는 `ffs_data->dev_name`을 확인해 해당 FunctionFS가 MTP용 `mtp`인지 HID용 `hid`인지 식별합니다.
Device name이 user-space mount와 kernel function을 연결합니다.
One can imagine a gadget that has an Ethernet, MTP and HID interfaces
where the last two are implemented via FunctionFS. On user space
level it would look like this::
$ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid
$ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp
$ ( cd /dev/ffs-mtp && mtp-daemon ) &
$ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid
$ ( cd /dev/ffs-hid && hid-daemon ) &
On kernel level the gadget checks ffs_data->dev_name to identify
whether its FunctionFS is designed for MTP ("mtp") or HID ("hid").
functions module parameter
59-67`functions` module parameter를 주지 않으면 driver는 이름과 관계없이 function 하나만 허용합니다.
Parameter를 주면 목록에 적힌 이름의 function만 허용합니다. 목록이 한 항목뿐이면 하나만 허용한다는 점은 parameter가 없을 때와 비슷하지만, 지정한 이름만 받아들인다는 차이가 있습니다.
Parameter 유무와 목록 길이에 따른 function 승인 규칙입니다.
If no "functions" module parameters is supplied, the driver accepts
just one function with any name.
When "functions" module parameter is supplied, only functions
with listed names are accepted. In particular, if the "functions"
parameter's value is just a one-element list, then the behaviour
is similar to when there is no "functions" at all; however,
only a function with the specified name is accepted.
Gadget 등록과 해제 시점
68-74선언한 모든 function filesystem이 mount되고 모든 function의 USB descriptor가 각 `ep0`에 기록된 뒤에만 gadget이 등록됩니다.
반대로 USB function 하나라도 endpoint를 닫으면 gadget이 등록 해제됩니다.
모든 function의 준비가 등록 조건이고 첫 endpoint close가 해제 조건입니다.
The gadget is registered only after all the declared function
filesystems have been mounted and USB descriptors of all functions
have been written to their ep0's.
Conversely, the gadget is unregistered after the first USB function
closes its endpoints.
DMABUF와 zero-copy
75-85FunctionFS는 user space가 외부에서 만든 DMABUF object를 endpoint에 attach한 뒤 data transfer에 사용하는 DMABUF interface도 지원합니다.
Application은 여러 interface 사이에서 DMABUF object를 공유할 수 있으며, 예를 들어 IIO와 USB stack 사이에서 zero-copy 방식으로 data를 전송할 수 있습니다.
DMABUF interface
================
FunctionFS additionally supports a DMABUF based interface, where the
userspace can attach DMABUF objects (externally created) to an endpoint,
and subsequently use them for data transfers.
A userspace application can then use this interface to share DMABUF
objects between several interfaces, allowing it to transfer data in a
zero-copy fashion, for instance between IIO and the USB stack.
Data endpoint 전용 IOCTL
86-88DMABUF interface에는 세 IOCTL이 추가됐습니다. 모두 `ep0`가 아닌 data endpoint에서 실행해야 합니다.
Attach, detach, transfer queue 동작과 핵심 argument를 정리합니다.
As part of this interface, three new IOCTLs have been added. These three
IOCTLs have to be performed on a data endpoint (ie. not ep0). They are:
FUNCTIONFS_DMABUF_ATTACH
89-93`FUNCTIONFS_DMABUF_ATTACH(int)`는 file descriptor로 식별한 DMABUF object를 data endpoint에 attach합니다. 성공 시 0, 실패 시 음수 errno를 반환합니다.
``FUNCTIONFS_DMABUF_ATTACH(int)``
Attach the DMABUF object, identified by its file descriptor, to the
data endpoint. Returns zero on success, and a negative errno value
on error.
FUNCTIONFS_DMABUF_DETACH
94-99`FUNCTIONFS_DMABUF_DETACH(int)`는 file descriptor로 식별한 DMABUF를 data endpoint에서 분리합니다. 성공 시 0, 실패 시 음수 errno를 반환합니다.
Endpoint의 file descriptor를 닫으면 attach된 모든 DMABUF가 자동으로 detach됩니다.
``FUNCTIONFS_DMABUF_DETACH(int)``
Detach the given DMABUF object, identified by its file descriptor,
from the data endpoint. Returns zero on success, and a negative
errno value on error. Note that closing the endpoint's file
descriptor will automatically detach all attached DMABUFs.
FUNCTIONFS_DMABUF_TRANSFER
100-106`FUNCTIONFS_DMABUF_TRANSFER(struct usb_ffs_dmabuf_transfer_req *)`는 이전에 attach한 DMABUF를 transfer queue에 넣습니다.
Argument structure는 DMABUF file descriptor, 전송 byte 수, 현재는 사용하지 않는 `flags` field를 담습니다. 전송 크기는 일반적으로 DMABUF 크기와 같아야 하며 성공 시 0, 실패 시 음수 errno를 반환합니다.
``FUNCTIONFS_DMABUF_TRANSFER(struct usb_ffs_dmabuf_transfer_req *)``
Enqueue the previously attached DMABUF to the transfer queue.
The argument is a structure that packs the DMABUF's file descriptor,
the size in bytes to transfer (which should generally correspond to
the size of the DMABUF), and a 'flags' field which is unused
for now. Returns zero on success, and a negative errno value on
error.
요약·해설
functionfs.rst:1-106FunctionFS는 user space가 `ep0`에 descriptor/string을 제공할 때까지 composite gadget 결합을 미루고 실제 endpoint/interface/string 번호를 대신 관리합니다. 여러 mount instance는 device name으로 구분되며, 모든 function 준비 후 gadget이 등록되고 첫 endpoint close 시 해제됩니다. DMABUF IOCTL은 data endpoint에서 zero-copy 전송을 구성합니다.