diff options
Diffstat (limited to 'patches.tizen/1172-usb-gadget-FunctionFS-convert-to-new-function-interf.patch')
-rw-r--r-- | patches.tizen/1172-usb-gadget-FunctionFS-convert-to-new-function-interf.patch | 865 |
1 files changed, 865 insertions, 0 deletions
diff --git a/patches.tizen/1172-usb-gadget-FunctionFS-convert-to-new-function-interf.patch b/patches.tizen/1172-usb-gadget-FunctionFS-convert-to-new-function-interf.patch new file mode 100644 index 00000000000..b0b189e288c --- /dev/null +++ b/patches.tizen/1172-usb-gadget-FunctionFS-convert-to-new-function-interf.patch @@ -0,0 +1,865 @@ +From d37c6c402606925ac4ab7dcac0b8809f7d0c7ef1 Mon Sep 17 00:00:00 2001 +From: Andrzej Pietrasiewicz <andrzej.p@samsung.com> +Date: Tue, 3 Dec 2013 15:15:33 +0100 +Subject: [PATCH 1172/1302] usb: gadget: FunctionFS: convert to new function + interface with backward compatibility + +This is required in order to integrate configfs support. +f_fs needs to be a separately compiled module and so it needs to use the new +interface. + +Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> +Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> +Signed-off-by: Felipe Balbi <balbi@ti.com> +Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> +--- + drivers/usb/gadget/Kconfig | 3 + + drivers/usb/gadget/Makefile | 2 + + drivers/usb/gadget/f_fs.c | 422 +++++++++++++++++++++-------------------- + drivers/usb/gadget/g_ffs.c | 1 + + drivers/usb/gadget/u_fs.h | 214 +++++++++++++++++++++ + include/linux/usb/functionfs.h | 2 + + 6 files changed, 435 insertions(+), 209 deletions(-) + +diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig +index 0ba106c..3407f56 100644 +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -537,6 +537,9 @@ config USB_F_RNDIS + config USB_F_MASS_STORAGE + tristate + ++config USB_F_FS ++ tristate ++ + choice + tristate "USB Gadget Drivers" + default USB_ETH +diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile +index 47646b6..85bfe98 100644 +--- a/drivers/usb/gadget/Makefile ++++ b/drivers/usb/gadget/Makefile +@@ -60,6 +60,8 @@ usb_f_rndis-y := f_rndis.o rndis.o + obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o + usb_f_mass_storage-y := f_mass_storage.o storage_common.o + obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o ++usb_f_fs-y := f_fs.o ++obj-$(CONFIG_USB_F_FS) += usb_f_fs.o + + # + # USB gadget drivers +diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c +index f2188ad..1a5ffa5 100644 +--- a/drivers/usb/gadget/f_fs.c ++++ b/drivers/usb/gadget/f_fs.c +@@ -22,6 +22,7 @@ + #include <linux/pagemap.h> + #include <linux/export.h> + #include <linux/hid.h> ++#include <linux/module.h> + #include <asm/unaligned.h> + + #include <linux/usb/composite.h> +@@ -57,210 +58,6 @@ + #define vla_ptr(ptr, groupname, name) \ + ((void *) ((char *)ptr + groupname##_##name##__offset)) + +-/* Debugging ****************************************************************/ +- +-#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__) +- +- +-/* The data structure and setup file ****************************************/ +- +-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 +- * ffs_ready(). 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, +- +- /* +- * 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 +- * ffs_ready() 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_CANCELED +-}; +- +- +- +-struct ffs_epfile; +-struct ffs_function; +- +-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 */ +- int ep0req_status; /* P: mutex */ +- +- /* reference counter */ +- atomic_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_CANCELED -- P: ev.waitq.lock +- * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg +- */ +- enum ffs_setup_state setup_state; +- +-#define FFS_SETUP_STATE(ffs) \ +- ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \ +- FFS_SETUP_CANCELED, FFS_NO_SETUP)) +- +- /* 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 +- +- /* 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() */ +- /* +- * Real descriptors are 16 bytes after raw_descs (so you need +- * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the +- * first full speed descriptor). raw_descs_length and +- * raw_fs_descs_length do not have those 16 bytes added. +- */ +- const void *raw_descs; +- unsigned raw_descs_length; +- unsigned raw_fs_descs_length; +- unsigned fs_descs_count; +- unsigned hs_descs_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; +- +- /* +- * The endpoint files, filled by ffs_epfiles_create(), +- * destroyed by ffs_epfiles_destroy(). +- */ +- struct ffs_epfile *epfiles; +-}; +- + /* Reference counter handling */ + static void ffs_data_get(struct ffs_data *ffs); + static void ffs_data_put(struct ffs_data *ffs); +@@ -300,15 +97,19 @@ static struct ffs_function *ffs_func_from_usb(struct usb_function *f) + return container_of(f, struct ffs_function, function); + } + ++#ifdef USB_FFS_INCLUDED + static void ffs_func_free(struct ffs_function *func); ++#endif + + 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 void ffs_func_unbind(struct usb_configuration *, ++#ifdef USB_FFS_INCLUDED ++static void old_ffs_func_unbind(struct usb_configuration *, + struct usb_function *); ++#endif + static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); + static void ffs_func_disable(struct usb_function *); + static int ffs_func_setup(struct usb_function *, +@@ -364,6 +165,9 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data, + /* Devices management *******************************************************/ + + DEFINE_MUTEX(ffs_lock); ++#ifndef USB_FFS_INCLUDED ++EXPORT_SYMBOL(ffs_lock); ++#endif + + static struct ffs_dev *ffs_find_dev(const char *name); + static void *ffs_acquire_dev(const char *dev_name); +@@ -1499,6 +1303,8 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) + kfree(epfiles); + } + ++#ifdef USB_FFS_INCLUDED ++ + static int functionfs_bind_config(struct usb_composite_dev *cdev, + struct usb_configuration *c, + struct ffs_data *ffs) +@@ -1516,7 +1322,7 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev, + func->function.strings = ffs->stringtabs; + + func->function.bind = ffs_func_bind; +- func->function.unbind = ffs_func_unbind; ++ func->function.unbind = old_ffs_func_unbind; + func->function.set_alt = ffs_func_set_alt; + func->function.disable = ffs_func_disable; + func->function.setup = ffs_func_setup; +@@ -1565,6 +1371,8 @@ static void ffs_func_free(struct ffs_function *func) + kfree(func); + } + ++#endif ++ + static void ffs_func_eps_disable(struct ffs_function *func) + { + struct ffs_ep *ep = func->eps; +@@ -2227,8 +2035,59 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, + return 0; + } + +-static int ffs_func_bind(struct usb_configuration *c, +- struct usb_function *f) ++#ifndef USB_FFS_INCLUDED ++static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, ++ struct usb_configuration *c) ++{ ++ struct ffs_function *func = ffs_func_from_usb(f); ++ struct f_fs_opts *ffs_opts = ++ container_of(f->fi, struct f_fs_opts, func_inst); ++ int ret; ++ ++ ENTER(); ++ ++ /* ++ * Legacy gadget triggers binding in functionfs_ready_callback, ++ * which already uses locking; taking the same lock here would ++ * cause a deadlock. ++ * ++ * Configfs-enabled gadgets however do need ffs_dev_lock. ++ */ ++ if (!ffs_opts->no_configfs) ++ ffs_dev_lock(); ++ ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV; ++ func->ffs = ffs_opts->dev->ffs_data; ++ if (!ffs_opts->no_configfs) ++ ffs_dev_unlock(); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ func->conf = c; ++ func->gadget = c->cdev->gadget; ++ ++ ffs_data_get(func->ffs); ++ ++ /* ++ * in drivers/usb/gadget/configfs.c:configfs_composite_bind() ++ * configurations are bound in sequence with list_for_each_entry, ++ * in each configuration its functions are bound in sequence ++ * with list_for_each_entry, so we assume no race condition ++ * with regard to ffs_opts->bound access ++ */ ++ if (!ffs_opts->refcnt) { ++ ret = functionfs_bind(func->ffs, c->cdev); ++ if (ret) ++ return ERR_PTR(ret); ++ } ++ ffs_opts->refcnt++; ++ func->function.strings = func->ffs->stringtabs; ++ ++ return ffs_opts; ++} ++#endif ++ ++static int _ffs_func_bind(struct usb_configuration *c, ++ struct usb_function *f) + { + struct ffs_function *func = ffs_func_from_usb(f); + struct ffs_data *ffs = func->ffs; +@@ -2328,10 +2187,25 @@ error: + return ret; + } + ++static int ffs_func_bind(struct usb_configuration *c, ++ struct usb_function *f) ++{ ++#ifndef USB_FFS_INCLUDED ++ struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); ++ ++ if (IS_ERR(ffs_opts)) ++ return PTR_ERR(ffs_opts); ++#endif ++ ++ return _ffs_func_bind(c, f); ++} ++ + + /* Other USB function hooks *************************************************/ + +-static void ffs_func_unbind(struct usb_configuration *c, ++#ifdef USB_FFS_INCLUDED ++ ++static void old_ffs_func_unbind(struct usb_configuration *c, + struct usb_function *f) + { + struct ffs_function *func = ffs_func_from_usb(f); +@@ -2349,6 +2223,8 @@ static void ffs_func_unbind(struct usb_configuration *c, + ffs_func_free(func); + } + ++#endif ++ + static int ffs_func_set_alt(struct usb_function *f, + unsigned interface, unsigned alt) + { +@@ -2523,6 +2399,116 @@ static struct ffs_dev *ffs_find_dev(const char *name) + return _ffs_find_dev(name); + } + ++/* Function registration interface ******************************************/ ++ ++#ifndef USB_FFS_INCLUDED ++ ++static void ffs_free_inst(struct usb_function_instance *f) ++{ ++ struct f_fs_opts *opts; ++ ++ opts = to_f_fs_opts(f); ++ ffs_dev_lock(); ++ ffs_free_dev(opts->dev); ++ ffs_dev_unlock(); ++ kfree(opts); ++} ++ ++static struct usb_function_instance *ffs_alloc_inst(void) ++{ ++ struct f_fs_opts *opts; ++ struct ffs_dev *dev; ++ ++ opts = kzalloc(sizeof(*opts), GFP_KERNEL); ++ if (!opts) ++ return ERR_PTR(-ENOMEM); ++ ++ opts->func_inst.free_func_inst = ffs_free_inst; ++ ffs_dev_lock(); ++ dev = ffs_alloc_dev(); ++ ffs_dev_unlock(); ++ if (IS_ERR(dev)) { ++ kfree(opts); ++ return ERR_CAST(dev); ++ } ++ opts->dev = dev; ++ ++ return &opts->func_inst; ++} ++ ++static void ffs_free(struct usb_function *f) ++{ ++ kfree(ffs_func_from_usb(f)); ++} ++ ++static void ffs_func_unbind(struct usb_configuration *c, ++ struct usb_function *f) ++{ ++ struct ffs_function *func = ffs_func_from_usb(f); ++ struct ffs_data *ffs = func->ffs; ++ struct f_fs_opts *opts = ++ container_of(f->fi, struct f_fs_opts, func_inst); ++ struct ffs_ep *ep = func->eps; ++ unsigned count = ffs->eps_count; ++ unsigned long flags; ++ ++ ENTER(); ++ if (ffs->func == func) { ++ ffs_func_eps_disable(func); ++ ffs->func = NULL; ++ } ++ ++ if (!--opts->refcnt) ++ functionfs_unbind(ffs); ++ ++ /* cleanup after autoconfig */ ++ spin_lock_irqsave(&func->ffs->eps_lock, flags); ++ do { ++ if (ep->ep && ep->req) ++ usb_ep_free_request(ep->ep, ep->req); ++ ep->req = NULL; ++ ++ep; ++ } while (--count); ++ spin_unlock_irqrestore(&func->ffs->eps_lock, flags); ++ kfree(func->eps); ++ func->eps = NULL; ++ /* ++ * eps, descriptors and interfaces_nums are allocated in the ++ * same chunk so only one free is required. ++ */ ++ func->function.fs_descriptors = NULL; ++ func->function.hs_descriptors = NULL; ++ func->interfaces_nums = NULL; ++ ++ ffs_event_add(ffs, FUNCTIONFS_UNBIND); ++} ++ ++static struct usb_function *ffs_alloc(struct usb_function_instance *fi) ++{ ++ struct ffs_function *func; ++ ++ ENTER(); ++ ++ func = kzalloc(sizeof(*func), GFP_KERNEL); ++ if (unlikely(!func)) ++ return ERR_PTR(-ENOMEM); ++ ++ func->function.name = "Function FS Gadget"; ++ ++ func->function.bind = ffs_func_bind; ++ func->function.unbind = ffs_func_unbind; ++ func->function.set_alt = ffs_func_set_alt; ++ func->function.disable = ffs_func_disable; ++ func->function.setup = ffs_func_setup; ++ func->function.suspend = ffs_func_suspend; ++ func->function.resume = ffs_func_resume; ++ func->function.free_func = ffs_free; ++ ++ return &func->function; ++} ++ ++#endif ++ + /* + * ffs_lock must be taken by the caller of this function + */ +@@ -2581,6 +2567,9 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) + + return ret; + } ++#ifndef USB_FFS_INCLUDED ++EXPORT_SYMBOL(ffs_name_dev); ++#endif + + int ffs_single_dev(struct ffs_dev *dev) + { +@@ -2597,6 +2586,9 @@ int ffs_single_dev(struct ffs_dev *dev) + ffs_dev_unlock(); + return ret; + } ++#ifndef USB_FFS_INCLUDED ++EXPORT_SYMBOL(ffs_single_dev); ++#endif + + /* + * ffs_lock must be taken by the caller of this function +@@ -2621,6 +2613,9 @@ static void *ffs_acquire_dev(const char *dev_name) + ffs_dev = ERR_PTR(-ENODEV); + else if (ffs_dev->mounted) + ffs_dev = ERR_PTR(-EBUSY); ++ else if (ffs_dev->ffs_acquire_dev_callback && ++ ffs_dev->ffs_acquire_dev_callback(ffs_dev)) ++ ffs_dev = ERR_PTR(-ENODEV); + else + ffs_dev->mounted = true; + +@@ -2638,6 +2633,9 @@ static void ffs_release_dev(struct ffs_data *ffs_data) + ffs_dev = ffs_data->private_data; + if (ffs_dev) + ffs_dev->mounted = false; ++ ++ if (ffs_dev->ffs_release_dev_callback) ++ ffs_dev->ffs_release_dev_callback(ffs_dev); + + ffs_dev_unlock(); + } +@@ -2720,3 +2718,9 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len) + + return data; + } ++ ++#ifndef USB_FFS_INCLUDED ++DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Michal Nazarewicz"); ++#endif +diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c +index 074df0d..ffde36f 100644 +--- a/drivers/usb/gadget/g_ffs.c ++++ b/drivers/usb/gadget/g_ffs.c +@@ -54,6 +54,7 @@ static struct usb_function *f_rndis; + # endif + #endif + ++#define USB_FFS_INCLUDED + #include "f_fs.c" + + #define DRIVER_NAME "g_ffs" +diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h +index 2d00f9d..d60a9dd 100644 +--- a/drivers/usb/gadget/u_fs.h ++++ b/drivers/usb/gadget/u_fs.h +@@ -20,6 +20,22 @@ + #include <linux/list.h> + #include <linux/mutex.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 ffs_dev { + const char *name; + bool mounted; +@@ -30,6 +46,8 @@ struct ffs_dev { + + 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; +@@ -49,4 +67,200 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name); + int ffs_single_dev(struct ffs_dev *dev); + void ffs_free_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, ++ ++ /* ++ * 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_CANCELED ++}; ++ ++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 */ ++ int ep0req_status; /* P: mutex */ ++ ++ /* reference counter */ ++ atomic_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_CANCELED -- P: ev.waitq.lock ++ * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg ++ */ ++ enum ffs_setup_state setup_state; ++ ++#define FFS_SETUP_STATE(ffs) \ ++ ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \ ++ FFS_SETUP_CANCELED, FFS_NO_SETUP)) ++ ++ /* 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 ++ ++ /* 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() */ ++ /* ++ * Real descriptors are 16 bytes after raw_descs (so you need ++ * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the ++ * first full speed descriptor). raw_descs_length and ++ * raw_fs_descs_length do not have those 16 bytes added. ++ */ ++ const void *raw_descs; ++ unsigned raw_descs_length; ++ unsigned raw_fs_descs_length; ++ unsigned fs_descs_count; ++ unsigned hs_descs_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; ++ ++ /* ++ * The endpoint files, filled by ffs_epfiles_create(), ++ * destroyed by ffs_epfiles_destroy(). ++ */ ++ struct ffs_epfile *epfiles; ++}; ++ ++ ++#ifndef USB_FFS_INCLUDED ++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 ++ + #endif /* U_FFS_H */ +diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h +index 9c1e926..3448efb 100644 +--- a/include/linux/usb/functionfs.h ++++ b/include/linux/usb/functionfs.h +@@ -3,6 +3,7 @@ + + #include <uapi/linux/usb/functionfs.h> + ++#ifdef USB_FFS_INCLUDED + + struct ffs_data; + struct usb_composite_dev; +@@ -20,3 +21,4 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev, + + + #endif ++#endif +-- +1.8.3.2 + |