#include <linux/blkdev.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence.h>
#include <linux/dma-resv.h>
#include <linux/pagemap.h>
#include <linux/export.h>
#include <linux/fs_parser.h>
#include <linux/hid.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/sched/signal.h>
#include <linux/uio.h>
#include <linux/vmalloc.h>
#include <linux/unaligned.h>
#include <linux/usb/ccid.h>
#include <linux/usb/composite.h>
#include <linux/usb/functionfs.h>
#include <linux/usb/func_utils.h>
#include <linux/aio.h>
#include <linux/kthread.h>
#include <linux/poll.h>
#include <linux/eventfd.h>
#include "u_fs.h"
#include "u_os_desc.h"
#include "configfs.h"
#define FUNCTIONFS_MAGIC …
#define MAX_ALT_SETTINGS …
#define DMABUF_ENQUEUE_TIMEOUT_MS …
MODULE_IMPORT_NS(…);
static void ffs_data_get(struct ffs_data *ffs);
static void ffs_data_put(struct ffs_data *ffs);
static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
__attribute__((malloc));
static void ffs_data_opened(struct ffs_data *ffs);
static void ffs_data_closed(struct ffs_data *ffs);
static int __must_check
__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
static int __must_check
__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
struct ffs_ep;
struct ffs_function { … };
static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
{ … }
static inline enum ffs_setup_state
ffs_setup_state_clear_cancelled(struct ffs_data *ffs)
{ … }
static void ffs_func_eps_disable(struct ffs_function *func);
static int __must_check ffs_func_eps_enable(struct ffs_function *func);
static int ffs_func_bind(struct usb_configuration *,
struct usb_function *);
static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
static int ffs_func_get_alt(struct usb_function *f, unsigned int intf);
static void ffs_func_disable(struct usb_function *);
static int ffs_func_setup(struct usb_function *,
const struct usb_ctrlrequest *);
static bool ffs_func_req_match(struct usb_function *,
const struct usb_ctrlrequest *,
bool config0);
static void ffs_func_suspend(struct usb_function *);
static void ffs_func_resume(struct usb_function *);
static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
struct ffs_ep { … };
struct ffs_dmabuf_priv { … };
struct ffs_dma_fence { … };
struct ffs_epfile { … };
struct ffs_buffer { … };
struct ffs_io_data { … };
struct ffs_desc_helper { … };
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
static struct dentry *
ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
const struct file_operations *fops);
DEFINE_MUTEX(…) …;
EXPORT_SYMBOL_GPL(…);
static struct ffs_dev *_ffs_find_dev(const char *name);
static struct ffs_dev *_ffs_alloc_dev(void);
static void _ffs_free_dev(struct ffs_dev *dev);
static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
static void ffs_release_dev(struct ffs_dev *ffs_dev);
static int ffs_ready(struct ffs_data *ffs);
static void ffs_closed(struct ffs_data *ffs);
static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
__attribute__((warn_unused_result, nonnull));
static char *ffs_prepare_buffer(const char __user *buf, size_t len)
__attribute__((warn_unused_result, nonnull));
static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
{ … }
static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
__releases(&ffs->ev.waitq.lock)
{ … }
static int __ffs_ep0_stall(struct ffs_data *ffs)
{ … }
static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
size_t len, loff_t *ptr)
{ … }
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
__releases(&ffs->ev.waitq.lock)
{ … }
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
size_t len, loff_t *ptr)
{ … }
static int ffs_ep0_open(struct inode *inode, struct file *file)
{ … }
static int ffs_ep0_release(struct inode *inode, struct file *file)
{ … }
static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
{ … }
static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait)
{ … }
static const struct file_operations ffs_ep0_operations = …;
static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{ … }
static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
{ … }
static void *ffs_build_sg_list(struct sg_table *sgt, size_t sz)
{ … }
static inline void *ffs_alloc_buffer(struct ffs_io_data *io_data,
size_t data_len)
{ … }
static inline void ffs_free_buffer(struct ffs_io_data *io_data)
{ … }
static void ffs_user_copy_worker(struct work_struct *work)
{ … }
static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
struct usb_request *req)
{ … }
static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
{ … }
static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile,
struct iov_iter *iter)
{ … }
static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
void *data, int data_len,
struct iov_iter *iter)
{ … }
static struct ffs_ep *ffs_epfile_wait_ep(struct file *file)
{ … }
static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
{ … }
static int
ffs_epfile_open(struct inode *inode, struct file *file)
{ … }
static int ffs_aio_cancel(struct kiocb *kiocb)
{ … }
static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
{ … }
static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
{ … }
static void ffs_dmabuf_release(struct kref *ref)
{ … }
static void ffs_dmabuf_get(struct dma_buf_attachment *attach)
{ … }
static void ffs_dmabuf_put(struct dma_buf_attachment *attach)
{ … }
static int
ffs_epfile_release(struct inode *inode, struct file *file)
{ … }
static void ffs_dmabuf_cleanup(struct work_struct *work)
{ … }
static void ffs_dmabuf_signal_done(struct ffs_dma_fence *dma_fence, int ret)
{ … }
static void ffs_epfile_dmabuf_io_complete(struct usb_ep *ep,
struct usb_request *req)
{ … }
static const char *ffs_dmabuf_get_driver_name(struct dma_fence *fence)
{ … }
static const char *ffs_dmabuf_get_timeline_name(struct dma_fence *fence)
{ … }
static void ffs_dmabuf_fence_release(struct dma_fence *fence)
{ … }
static const struct dma_fence_ops ffs_dmabuf_fence_ops = …;
static int ffs_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock)
{ … }
static struct dma_buf_attachment *
ffs_dmabuf_find_attachment(struct ffs_epfile *epfile, struct dma_buf *dmabuf)
{ … }
static int ffs_dmabuf_attach(struct file *file, int fd)
{ … }
static int ffs_dmabuf_detach(struct file *file, int fd)
{ … }
static int ffs_dmabuf_transfer(struct file *file,
const struct usb_ffs_dmabuf_transfer_req *req)
{ … }
static long ffs_epfile_ioctl(struct file *file, unsigned code,
unsigned long value)
{ … }
static const struct file_operations ffs_epfile_operations = …;
static struct inode *__must_check
ffs_sb_make_inode(struct super_block *sb, void *data,
const struct file_operations *fops,
const struct inode_operations *iops,
struct ffs_file_perms *perms)
{ … }
static struct dentry *ffs_sb_create_file(struct super_block *sb,
const char *name, void *data,
const struct file_operations *fops)
{ … }
static const struct super_operations ffs_sb_operations = …;
struct ffs_sb_fill_data { … };
static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
{ … }
enum { … };
static const struct fs_parameter_spec ffs_fs_fs_parameters[] = …;
static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
{ … }
static int ffs_fs_get_tree(struct fs_context *fc)
{ … }
static void ffs_fs_free_fc(struct fs_context *fc)
{ … }
static const struct fs_context_operations ffs_fs_context_ops = …;
static int ffs_fs_init_fs_context(struct fs_context *fc)
{ … }
static void
ffs_fs_kill_sb(struct super_block *sb)
{ … }
static struct file_system_type ffs_fs_type = …;
MODULE_ALIAS_FS(…) …;
static int functionfs_init(void)
{ … }
static void functionfs_cleanup(void)
{ … }
static void ffs_data_clear(struct ffs_data *ffs);
static void ffs_data_reset(struct ffs_data *ffs);
static void ffs_data_get(struct ffs_data *ffs)
{ … }
static void ffs_data_opened(struct ffs_data *ffs)
{ … }
static void ffs_data_put(struct ffs_data *ffs)
{ … }
static void ffs_data_closed(struct ffs_data *ffs)
{ … }
static struct ffs_data *ffs_data_new(const char *dev_name)
{ … }
static void ffs_data_clear(struct ffs_data *ffs)
{ … }
static void ffs_data_reset(struct ffs_data *ffs)
{ … }
static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
{ … }
static void functionfs_unbind(struct ffs_data *ffs)
{ … }
static int ffs_epfiles_create(struct ffs_data *ffs)
{ … }
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
{ … }
static void ffs_func_eps_disable(struct ffs_function *func)
{ … }
static int ffs_func_eps_enable(struct ffs_function *func)
{ … }
enum ffs_entity_type { … };
enum ffs_os_desc_type { … };
ffs_entity_callback;
ffs_os_desc_callback;
static int __must_check ffs_do_single_desc(char *data, unsigned len,
ffs_entity_callback entity,
void *priv, int *current_class, int *current_subclass)
{ … }
static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
ffs_entity_callback entity, void *priv)
{ … }
static int __ffs_data_do_entity(enum ffs_entity_type type,
u8 *valuep, struct usb_descriptor_header *desc,
void *priv)
{ … }
static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
struct usb_os_desc_header *desc)
{ … }
static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
enum ffs_os_desc_type type,
u16 feature_count,
ffs_os_desc_callback entity,
void *priv,
struct usb_os_desc_header *h)
{ … }
static int __must_check ffs_do_os_descs(unsigned count,
char *data, unsigned len,
ffs_os_desc_callback entity, void *priv)
{ … }
static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
struct usb_os_desc_header *h, void *data,
unsigned len, void *priv)
{ … }
static int __ffs_data_got_descs(struct ffs_data *ffs,
char *const _data, size_t len)
{ … }
static int __ffs_data_got_strings(struct ffs_data *ffs,
char *const _data, size_t len)
{ … }
static void __ffs_event_add(struct ffs_data *ffs,
enum usb_functionfs_event_type type)
{ … }
static void ffs_event_add(struct ffs_data *ffs,
enum usb_functionfs_event_type type)
{ … }
static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
{ … }
static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
struct usb_descriptor_header *desc,
void *priv)
{ … }
static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
struct usb_descriptor_header *desc,
void *priv)
{ … }
static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
struct usb_os_desc_header *h, void *data,
unsigned len, void *priv)
{ … }
static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
struct usb_configuration *c)
{ … }
static int _ffs_func_bind(struct usb_configuration *c,
struct usb_function *f)
{ … }
static int ffs_func_bind(struct usb_configuration *c,
struct usb_function *f)
{ … }
static void ffs_reset_work(struct work_struct *work)
{ … }
static int ffs_func_get_alt(struct usb_function *f,
unsigned int interface)
{ … }
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{ … }
static void ffs_func_disable(struct usb_function *f)
{ … }
static int ffs_func_setup(struct usb_function *f,
const struct usb_ctrlrequest *creq)
{ … }
static bool ffs_func_req_match(struct usb_function *f,
const struct usb_ctrlrequest *creq,
bool config0)
{ … }
static void ffs_func_suspend(struct usb_function *f)
{ … }
static void ffs_func_resume(struct usb_function *f)
{ … }
static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
{ … }
static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
{ … }
static LIST_HEAD(ffs_devices);
static struct ffs_dev *_ffs_do_find_dev(const char *name)
{ … }
static struct ffs_dev *_ffs_get_single_dev(void)
{ … }
static struct ffs_dev *_ffs_find_dev(const char *name)
{ … }
static inline struct f_fs_opts *to_ffs_opts(struct config_item *item)
{ … }
static ssize_t f_fs_opts_ready_show(struct config_item *item, char *page)
{ … }
CONFIGFS_ATTR_RO(…);
static struct configfs_attribute *ffs_attrs[] = …;
static void ffs_attr_release(struct config_item *item)
{ … }
static struct configfs_item_operations ffs_item_ops = …;
static const struct config_item_type ffs_func_type = …;
static void ffs_free_inst(struct usb_function_instance *f)
{ … }
static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
{ … }
static struct usb_function_instance *ffs_alloc_inst(void)
{ … }
static void ffs_free(struct usb_function *f)
{ … }
static void ffs_func_unbind(struct usb_configuration *c,
struct usb_function *f)
{ … }
static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
{ … }
static struct ffs_dev *_ffs_alloc_dev(void)
{ … }
int ffs_name_dev(struct ffs_dev *dev, const char *name)
{ … }
EXPORT_SYMBOL_GPL(…);
int ffs_single_dev(struct ffs_dev *dev)
{ … }
EXPORT_SYMBOL_GPL(…);
static void _ffs_free_dev(struct ffs_dev *dev)
{ … }
static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
{ … }
static void ffs_release_dev(struct ffs_dev *ffs_dev)
{ … }
static int ffs_ready(struct ffs_data *ffs)
{ … }
static void ffs_closed(struct ffs_data *ffs)
{ … }
static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
{ … }
static char *ffs_prepare_buffer(const char __user *buf, size_t len)
{ … }
DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
MODULE_DESCRIPTION(…) …;
MODULE_LICENSE(…) …;
MODULE_AUTHOR(…) …;