123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * u_fs.h
- *
- * Utility definitions for the FunctionFS
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
- */
- #ifndef U_FFS_H
- #define U_FFS_H
- #include <linux/usb/composite.h>
- #include <linux/list.h>
- #include <linux/mutex.h>
- #include <linux/workqueue.h>
- #include <linux/refcount.h>
- #ifdef VERBOSE_DEBUG
- #ifndef pr_vdebug
- # define pr_vdebug pr_debug
- #endif /* pr_vdebug */
- # define ffs_dump_mem(prefix, ptr, len) \
- print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
- #else
- #ifndef pr_vdebug
- # define pr_vdebug(...) do { } while (0)
- #endif /* pr_vdebug */
- # define ffs_dump_mem(prefix, ptr, len) do { } while (0)
- #endif /* VERBOSE_DEBUG */
- #define ENTER() pr_vdebug("%s()\n", __func__)
- struct f_fs_opts;
- struct ffs_dev {
- struct ffs_data *ffs_data;
- struct f_fs_opts *opts;
- struct list_head entry;
- char name[41];
- bool mounted;
- bool desc_ready;
- bool single;
- int (*ffs_ready_callback)(struct ffs_data *ffs);
- void (*ffs_closed_callback)(struct ffs_data *ffs);
- void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
- void (*ffs_release_dev_callback)(struct ffs_dev *dev);
- };
- extern struct mutex ffs_lock;
- static inline void ffs_dev_lock(void)
- {
- mutex_lock(&ffs_lock);
- }
- static inline void ffs_dev_unlock(void)
- {
- mutex_unlock(&ffs_lock);
- }
- int ffs_name_dev(struct ffs_dev *dev, const char *name);
- int ffs_single_dev(struct ffs_dev *dev);
- struct ffs_epfile;
- struct ffs_function;
- enum ffs_state {
- /*
- * Waiting for descriptors and strings.
- *
- * In this state no open(2), read(2) or write(2) on epfiles
- * may succeed (which should not be the problem as there
- * should be no such files opened in the first place).
- */
- FFS_READ_DESCRIPTORS,
- FFS_READ_STRINGS,
- /*
- * We've got descriptors and strings. We are or have called
- * functionfs_ready_callback(). functionfs_bind() may have
- * been called but we don't know.
- *
- * This is the only state in which operations on epfiles may
- * succeed.
- */
- FFS_ACTIVE,
- /*
- * Function is visible to host, but it's not functional. All
- * setup requests are stalled and transfers on another endpoints
- * are refused. All epfiles, except ep0, are deleted so there
- * is no way to perform any operations on them.
- *
- * This state is set after closing all functionfs files, when
- * mount parameter "no_disconnect=1" has been set. Function will
- * remain in deactivated state until filesystem is umounted or
- * ep0 is opened again. In the second case functionfs state will
- * be reset, and it will be ready for descriptors and strings
- * writing.
- *
- * This is useful only when functionfs is composed to gadget
- * with another function which can perform some critical
- * operations, and it's strongly desired to have this operations
- * completed, even after functionfs files closure.
- */
- FFS_DEACTIVATED,
- /*
- * All endpoints have been closed. This state is also set if
- * we encounter an unrecoverable error. The only
- * unrecoverable error is situation when after reading strings
- * from user space we fail to initialise epfiles or
- * functionfs_ready_callback() returns with error (<0).
- *
- * In this state no open(2), read(2) or write(2) (both on ep0
- * as well as epfile) may succeed (at this point epfiles are
- * unlinked and all closed so this is not a problem; ep0 is
- * also closed but ep0 file exists and so open(2) on ep0 must
- * fail).
- */
- FFS_CLOSING
- };
- enum ffs_setup_state {
- /* There is no setup request pending. */
- FFS_NO_SETUP,
- /*
- * User has read events and there was a setup request event
- * there. The next read/write on ep0 will handle the
- * request.
- */
- FFS_SETUP_PENDING,
- /*
- * There was event pending but before user space handled it
- * some other event was introduced which canceled existing
- * setup. If this state is set read/write on ep0 return
- * -EIDRM. This state is only set when adding event.
- */
- FFS_SETUP_CANCELLED
- };
- struct ffs_data {
- struct usb_gadget *gadget;
- /*
- * Protect access read/write operations, only one read/write
- * at a time. As a consequence protects ep0req and company.
- * While setup request is being processed (queued) this is
- * held.
- */
- struct mutex mutex;
- /*
- * Protect access to endpoint related structures (basically
- * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
- * endpoint zero.
- */
- spinlock_t eps_lock;
- /*
- * XXX REVISIT do we need our own request? Since we are not
- * handling setup requests immediately user space may be so
- * slow that another setup will be sent to the gadget but this
- * time not to us but another function and then there could be
- * a race. Is that the case? Or maybe we can use cdev->req
- * after all, maybe we just need some spinlock for that?
- */
- struct usb_request *ep0req; /* P: mutex */
- struct completion ep0req_completion; /* P: mutex */
- /* reference counter */
- refcount_t ref;
- /* how many files are opened (EP0 and others) */
- atomic_t opened;
- /* EP0 state */
- enum ffs_state state;
- /*
- * Possible transitions:
- * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock
- * happens only in ep0 read which is P: mutex
- * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock
- * happens only in ep0 i/o which is P: mutex
- * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELLED -- P: ev.waitq.lock
- * + FFS_SETUP_CANCELLED -> FFS_NO_SETUP -- cmpxchg
- *
- * This field should never be accessed directly and instead
- * ffs_setup_state_clear_cancelled function should be used.
- */
- enum ffs_setup_state setup_state;
- /* Events & such. */
- struct {
- u8 types[4];
- unsigned short count;
- /* XXX REVISIT need to update it in some places, or do we? */
- unsigned short can_stall;
- struct usb_ctrlrequest setup;
- wait_queue_head_t waitq;
- } ev; /* the whole structure, P: ev.waitq.lock */
- /* Flags */
- unsigned long flags;
- #define FFS_FL_CALL_CLOSED_CALLBACK 0
- #define FFS_FL_BOUND 1
- /* For waking up blocked threads when function is enabled. */
- wait_queue_head_t wait;
- /* Active function */
- struct ffs_function *func;
- /*
- * Device name, write once when file system is mounted.
- * Intended for user to read if she wants.
- */
- const char *dev_name;
- /* Private data for our user (ie. gadget). Managed by user. */
- void *private_data;
- /* filled by __ffs_data_got_descs() */
- /*
- * raw_descs is what you kfree, real_descs points inside of raw_descs,
- * where full speed, high speed and super speed descriptors start.
- * real_descs_length is the length of all those descriptors.
- */
- const void *raw_descs_data;
- const void *raw_descs;
- unsigned raw_descs_length;
- unsigned fs_descs_count;
- unsigned hs_descs_count;
- unsigned ss_descs_count;
- unsigned ms_os_descs_count;
- unsigned ms_os_descs_ext_prop_count;
- unsigned ms_os_descs_ext_prop_name_len;
- unsigned ms_os_descs_ext_prop_data_len;
- void *ms_os_descs_ext_prop_avail;
- void *ms_os_descs_ext_prop_name_avail;
- void *ms_os_descs_ext_prop_data_avail;
- unsigned user_flags;
- #define FFS_MAX_EPS_COUNT 31
- u8 eps_addrmap[FFS_MAX_EPS_COUNT];
- unsigned short strings_count;
- unsigned short interfaces_count;
- unsigned short eps_count;
- unsigned short _pad1;
- /* filled by __ffs_data_got_strings() */
- /* ids in stringtabs are set in functionfs_bind() */
- const void *raw_strings;
- struct usb_gadget_strings **stringtabs;
- /*
- * File system's super block, write once when file system is
- * mounted.
- */
- struct super_block *sb;
- /* File permissions, written once when fs is mounted */
- struct ffs_file_perms {
- umode_t mode;
- kuid_t uid;
- kgid_t gid;
- } file_perms;
- struct eventfd_ctx *ffs_eventfd;
- struct workqueue_struct *io_completion_wq;
- bool no_disconnect;
- struct work_struct reset_work;
- /*
- * The endpoint files, filled by ffs_epfiles_create(),
- * destroyed by ffs_epfiles_destroy().
- */
- struct ffs_epfile *epfiles;
- };
- struct f_fs_opts {
- struct usb_function_instance func_inst;
- struct ffs_dev *dev;
- unsigned refcnt;
- bool no_configfs;
- };
- static inline struct f_fs_opts *to_f_fs_opts(struct usb_function_instance *fi)
- {
- return container_of(fi, struct f_fs_opts, func_inst);
- }
- #endif /* U_FFS_H */
|