USB: f_fs: the FunctionFS driver
The FunctionFS is a USB composite function that can be used with the composite framework to create an USB gadget. >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). >From user space point of view it is a file system which when mounted provide 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 core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. 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. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
28824b18ac
Коммит
ddf8abd259
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,199 @@
|
|||
#ifndef __LINUX_FUNCTIONFS_H__
|
||||
#define __LINUX_FUNCTIONFS_H__ 1
|
||||
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
|
||||
enum {
|
||||
FUNCTIONFS_DESCRIPTORS_MAGIC = 1,
|
||||
FUNCTIONFS_STRINGS_MAGIC = 2
|
||||
};
|
||||
|
||||
|
||||
#ifndef __KERNEL__
|
||||
|
||||
/* Descriptor of an non-audio endpoint */
|
||||
struct usb_endpoint_descriptor_no_audio {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
|
||||
__u8 bEndpointAddress;
|
||||
__u8 bmAttributes;
|
||||
__le16 wMaxPacketSize;
|
||||
__u8 bInterval;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/*
|
||||
* All numbers must be in little endian order.
|
||||
*/
|
||||
|
||||
struct usb_functionfs_descs_head {
|
||||
__le32 magic;
|
||||
__le32 length;
|
||||
__le32 fs_count;
|
||||
__le32 hs_count;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Descriptors format:
|
||||
*
|
||||
* | off | name | type | description |
|
||||
* |-----+-----------+--------------+--------------------------------------|
|
||||
* | 0 | magic | LE32 | FUNCTIONFS_{FS,HS}_DESCRIPTORS_MAGIC |
|
||||
* | 4 | lenght | LE32 | length of the whole data chunk |
|
||||
* | 8 | fs_count | LE32 | number of full-speed descriptors |
|
||||
* | 12 | hs_count | LE32 | number of high-speed descriptors |
|
||||
* | 16 | fs_descrs | Descriptor[] | list of full-speed descriptors |
|
||||
* | | hs_descrs | Descriptor[] | list of high-speed descriptors |
|
||||
*
|
||||
* descs are just valid USB descriptors and have the following format:
|
||||
*
|
||||
* | off | name | type | description |
|
||||
* |-----+-----------------+------+--------------------------|
|
||||
* | 0 | bLength | U8 | length of the descriptor |
|
||||
* | 1 | bDescriptorType | U8 | descriptor type |
|
||||
* | 2 | payload | | descriptor's payload |
|
||||
*/
|
||||
|
||||
struct usb_functionfs_strings_head {
|
||||
__le32 magic;
|
||||
__le32 length;
|
||||
__le32 str_count;
|
||||
__le32 lang_count;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Strings format:
|
||||
*
|
||||
* | off | name | type | description |
|
||||
* |-----+------------+-----------------------+----------------------------|
|
||||
* | 0 | magic | LE32 | FUNCTIONFS_STRINGS_MAGIC |
|
||||
* | 4 | length | LE32 | length of the data chunk |
|
||||
* | 8 | str_count | LE32 | number of strings |
|
||||
* | 12 | lang_count | LE32 | number of languages |
|
||||
* | 16 | stringtab | StringTab[lang_count] | table of strings per lang |
|
||||
*
|
||||
* For each language there is one stringtab entry (ie. there are lang_count
|
||||
* stringtab entires). Each StringTab has following format:
|
||||
*
|
||||
* | off | name | type | description |
|
||||
* |-----+---------+-------------------+------------------------------------|
|
||||
* | 0 | lang | LE16 | language code |
|
||||
* | 2 | strings | String[str_count] | array of strings in given language |
|
||||
*
|
||||
* For each string ther is one strings entry (ie. there are str_count
|
||||
* string entries). Each String is a NUL terminated string encoded in
|
||||
* UTF-8.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Events are delivered on the ep0 file descriptor, when the user mode driver
|
||||
* reads from this file descriptor after writing the descriptors. Don't
|
||||
* stop polling this descriptor.
|
||||
*/
|
||||
|
||||
enum usb_functionfs_event_type {
|
||||
FUNCTIONFS_BIND,
|
||||
FUNCTIONFS_UNBIND,
|
||||
|
||||
FUNCTIONFS_ENABLE,
|
||||
FUNCTIONFS_DISABLE,
|
||||
|
||||
FUNCTIONFS_SETUP,
|
||||
|
||||
FUNCTIONFS_SUSPEND,
|
||||
FUNCTIONFS_RESUME
|
||||
};
|
||||
|
||||
/* NOTE: this structure must stay the same size and layout on
|
||||
* both 32-bit and 64-bit kernels.
|
||||
*/
|
||||
struct usb_functionfs_event {
|
||||
union {
|
||||
/* SETUP: packet; DATA phase i/o precedes next event
|
||||
*(setup.bmRequestType & USB_DIR_IN) flags direction */
|
||||
struct usb_ctrlrequest setup;
|
||||
} __attribute__((packed)) u;
|
||||
|
||||
/* enum usb_functionfs_event_type */
|
||||
__u8 type;
|
||||
__u8 _pad[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* Endpoint ioctls */
|
||||
/* The same as in gadgetfs */
|
||||
|
||||
/* IN transfers may be reported to the gadget driver as complete
|
||||
* when the fifo is loaded, before the host reads the data;
|
||||
* OUT transfers may be reported to the host's "client" driver as
|
||||
* complete when they're sitting in the FIFO unread.
|
||||
* THIS returns how many bytes are "unclaimed" in the endpoint fifo
|
||||
* (needed for precise fault handling, when the hardware allows it)
|
||||
*/
|
||||
#define FUNCTIONFS_FIFO_STATUS _IO('g', 1)
|
||||
|
||||
/* discards any unclaimed data in the fifo. */
|
||||
#define FUNCTIONFS_FIFO_FLUSH _IO('g', 2)
|
||||
|
||||
/* resets endpoint halt+toggle; used to implement set_interface.
|
||||
* some hardware (like pxa2xx) can't support this.
|
||||
*/
|
||||
#define FUNCTIONFS_CLEAR_HALT _IO('g', 3)
|
||||
|
||||
/* Specific for functionfs */
|
||||
|
||||
/*
|
||||
* Returns reverse mapping of an interface. Called on EP0. If there
|
||||
* is no such interface returns -EDOM. If function is not active
|
||||
* returns -ENODEV.
|
||||
*/
|
||||
#define FUNCTIONFS_INTERFACE_REVMAP _IO('g', 128)
|
||||
|
||||
/*
|
||||
* Returns real bEndpointAddress of an endpoint. If function is not
|
||||
* active returns -ENODEV.
|
||||
*/
|
||||
#define FUNCTIONFS_ENDPOINT_REVMAP _IO('g', 129)
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct ffs_data;
|
||||
struct usb_composite_dev;
|
||||
struct usb_configuration;
|
||||
|
||||
|
||||
static int functionfs_init(void) __attribute__((warn_unused_result));
|
||||
static void functionfs_cleanup(void);
|
||||
|
||||
static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
|
||||
__attribute__((warn_unused_result, nonnull));
|
||||
static void functionfs_unbind(struct ffs_data *ffs)
|
||||
__attribute__((nonnull));
|
||||
|
||||
static int functionfs_add(struct usb_composite_dev *cdev,
|
||||
struct usb_configuration *c,
|
||||
struct ffs_data *ffs)
|
||||
__attribute__((warn_unused_result, nonnull));
|
||||
|
||||
|
||||
static int functionfs_ready_callback(struct ffs_data *ffs)
|
||||
__attribute__((warn_unused_result, nonnull));
|
||||
static void functionfs_closed_callback(struct ffs_data *ffs)
|
||||
__attribute__((nonnull));
|
||||
static int functionfs_check_dev_callback(const char *dev_name)
|
||||
__attribute__((warn_unused_result, nonnull));
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче