[PATCH RESEND v2 13/16] usb/gadget: FunctionFS: convert to new function interface with backward compatibility

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
Acked-by: Michal Nazarewicz <mina86@xxxxxxxxxx>
---
 drivers/usb/gadget/Kconfig     |    3 +
 drivers/usb/gadget/Makefile    |    2 +
 drivers/usb/gadget/f_fs.c      |  568 +++++++++++++++++++++++++---------------
 drivers/usb/gadget/g_ffs.c     |    3 +-
 drivers/usb/gadget/u_fs.h      |  221 ++++++++++++++++
 include/linux/usb/functionfs.h |    5 +-
 6 files changed, 586 insertions(+), 216 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 0d117e2..66444d0 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -539,6 +539,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 fd9fe1f..6bb1155 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -61,6 +61,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 bfbb580..469cb86 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
-	 * 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_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 *,
@@ -365,7 +166,23 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
 
 static struct ffs_dev *ffs_alloc_dev(void);
 static void ffs_free_dev(struct ffs_dev *dev);
-static struct ffs_dev *ffs_find_dev(const char *name);
+
+#ifndef USB_FFS_INCLUDED
+static struct mutex *ffs_dev_lock;
+
+static void *(*ffs_acquire_dev_cb)(const char *name);
+static void (*ffs_release_dev_cb)(struct ffs_data *ffs_data);
+static int (*ffs_ready_cb)(struct ffs_data *ffs_data);
+static void (*ffs_closed_cb)(struct ffs_data *ffs_data);
+
+static bool auto_init_active = true;
+static bool do_auto_init = true;
+static bool do_init_kref = true;
+static struct kref auto_init_ref;
+static DEFINE_MUTEX(auto_init_lock);
+
+static struct module *ffs_owner;
+#endif
 
 /* Misc helper functions ****************************************************/
 
@@ -491,7 +308,11 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
 			ffs->state = FFS_ACTIVE;
 			mutex_unlock(&ffs->mutex);
 
+#ifdef USB_FFS_INCLUDED
 			ret = functionfs_ready_callback(ffs);
+#else
+			ret = ffs_ready_cb(ffs);
+#endif
 			if (unlikely(ret < 0)) {
 				ffs->state = FFS_CLOSING;
 				return ret;
@@ -1222,18 +1043,40 @@ ffs_fs_mount(struct file_system_type *t, int flags,
 		return ERR_PTR(-ENOMEM);
 	}
 
+#ifdef USB_FFS_INCLUDED
 	ffs_dev = functionfs_acquire_dev_callback(dev_name);
 	if (IS_ERR(ffs_dev)) {
 		ffs_data_put(ffs);
 		return ERR_CAST(ffs_dev);
 	}
+#else
+	if (ffs_owner && !try_module_get(ffs_owner)) {
+		ffs_data_put(ffs);
+		return ERR_PTR(-ENODEV);
+	}
+	ffs_dev = ffs_acquire_dev_cb(dev_name);
+	if (IS_ERR(ffs_dev)) {
+		if (ffs_owner)
+			module_put(ffs_owner);
+		ffs_data_put(ffs);
+
+		return ERR_CAST(ffs_dev);
+	}
+#endif
 	ffs->private_data = ffs_dev;
 	data.ffs_data = ffs;
 
 	rv = mount_nodev(t, flags, &data, ffs_sb_fill);
 	if (IS_ERR(rv) && data.ffs_data) {
+#ifdef USB_FFS_INCLUDED
 		functionfs_release_dev_callback(data.ffs_data);
 		ffs_data_put(data.ffs_data);
+#else
+		ffs_release_dev_cb(data.ffs_data);
+		ffs_data_put(data.ffs_data);
+		if (ffs_owner)
+			module_put(ffs_owner);
+#endif
 	}
 	return rv;
 }
@@ -1245,8 +1088,15 @@ ffs_fs_kill_sb(struct super_block *sb)
 
 	kill_litter_super(sb);
 	if (sb->s_fs_info) {
+#ifdef USB_FFS_INCLUDED
 		functionfs_release_dev_callback(sb->s_fs_info);
 		ffs_data_put(sb->s_fs_info);
+#else
+		ffs_release_dev_cb(sb->s_fs_info);
+		ffs_data_put(sb->s_fs_info);
+		if (ffs_owner)
+			module_put(ffs_owner);
+#endif
 	}
 }
 
@@ -1261,12 +1111,22 @@ MODULE_ALIAS_FS("functionfs");
 
 /* Driver's main init/cleanup functions *************************************/
 
-static int functionfs_init(void)
+int functionfs_init(struct module *owner)
 {
 	int ret;
 
 	ENTER();
 
+#ifndef USB_FFS_INCLUDED
+	if (!ffs_acquire_dev_cb || !ffs_release_dev_cb ||
+	    !ffs_ready_cb || !ffs_closed_cb) {
+		ret = -ENODEV;
+		pr_err("filesystem callbacks not set (%d)\n", ret);
+		return ret;
+	}
+	ffs_owner = owner;
+#endif
+
 	ret = register_filesystem(&ffs_fs_type);
 	if (likely(!ret))
 		pr_info("file system registered\n");
@@ -1275,14 +1135,27 @@ static int functionfs_init(void)
 
 	return ret;
 }
+#ifndef USB_FFS_INCLUDED
+EXPORT_SYMBOL(functionfs_init);
+#endif
 
-static void functionfs_cleanup(void)
+void functionfs_cleanup(void)
 {
+#ifndef USB_FFS_INCLUDED
+	ffs_owner = NULL;
+	do_auto_init = true;
+	auto_init_active = true;
+#endif
+
 	ENTER();
 
 	pr_info("unloading\n");
+
 	unregister_filesystem(&ffs_fs_type);
 }
+#ifndef USB_FFS_INCLUDED
+EXPORT_SYMBOL(functionfs_cleanup);
+#endif
 
 
 /* ffs_data and ffs_function construction and destruction code **************/
@@ -1358,7 +1231,11 @@ static void ffs_data_clear(struct ffs_data *ffs)
 	ENTER();
 
 	if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags))
+#ifdef USB_FFS_INCLUDED
 		functionfs_closed_callback(ffs);
+#else
+		ffs_closed_cb(ffs);
+#endif
 
 	BUG_ON(ffs->gadget);
 
@@ -1494,6 +1371,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)
@@ -1511,7 +1390,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;
@@ -1556,10 +1435,11 @@ static void ffs_func_free(struct ffs_function *func)
 	 * only one free is required.  Descriptors are also allocated
 	 * in the same chunk.
 	 */
-
 	kfree(func);
 }
 
+#endif
+
 static void ffs_func_eps_disable(struct ffs_function *func)
 {
 	struct ffs_ep *ep         = func->eps;
@@ -2222,8 +2102,65 @@ 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)
+static inline void mutex_lock_if_nonnull(struct mutex *mutex)
+{
+	if (mutex)
+		mutex_lock(mutex);
+}
+
+#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_dev_lock)
+		mutex_lock(ffs_dev_lock);
+	ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
+	if (ffs_dev_lock)
+		mutex_unlock(ffs_dev_lock);
+	if (ret)
+		return ERR_PTR(ret);
+
+	func->conf = c;
+	func->gadget = c->cdev->gadget;
+
+	func->ffs = ffs_opts->dev->ffs_data;
+	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 = ffs_opts->dev->ffs_data->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;
@@ -2323,10 +2260,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);
@@ -2344,6 +2296,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)
 {
@@ -2494,7 +2448,7 @@ static void ffs_free_dev(struct ffs_dev *dev)
 	kfree(dev);
 }
 
-static struct ffs_dev *ffs_find_dev(const char *name)
+struct ffs_dev *ffs_find_dev(const char *name)
 {
 	struct ffs_dev *dev;
 
@@ -2504,6 +2458,186 @@ static struct ffs_dev *ffs_find_dev(const char *name)
 
 	return NULL;
 }
+#ifndef USB_FFS_INCLUDED
+EXPORT_SYMBOL(ffs_find_dev);
+
+bool ffs_set_auto_init(bool flag)
+{
+	bool tmp;
+
+	mutex_lock(&auto_init_lock);
+	tmp = auto_init_active;
+	auto_init_active = flag;
+	mutex_unlock(&auto_init_lock);
+
+	return tmp;
+}
+EXPORT_SYMBOL(ffs_set_auto_init);
+
+void ffs_set_acquire_dev_cb(void *(*cb)(const char *name))
+{
+	ffs_acquire_dev_cb = cb;
+}
+EXPORT_SYMBOL(ffs_set_acquire_dev_cb);
+
+void ffs_set_release_dev_cb(void (*cb)(struct ffs_data *ffs_data))
+{
+	ffs_release_dev_cb = cb;
+}
+EXPORT_SYMBOL(ffs_set_release_dev_cb);
+
+void ffs_set_ready_cb(int (*cb)(struct ffs_data *ffs_data))
+{
+	ffs_ready_cb = cb;
+}
+EXPORT_SYMBOL(ffs_set_ready_cb);
+
+void ffs_set_closed_cb(void (*cb)(struct ffs_data *ffs_data))
+{
+	ffs_closed_cb = cb;
+}
+EXPORT_SYMBOL(ffs_set_closed_cb);
+#endif
+
+
+/* Function registration interface ******************************************/
+
+#ifndef USB_FFS_INCLUDED
+
+static void do_cleanup(struct kref *ref)
+{
+	if (auto_init_active)
+		functionfs_cleanup();
+
+	do_init_kref = true;
+}
+
+static void ffs_free_inst(struct usb_function_instance *f)
+{
+	struct f_fs_opts *opts;
+
+	opts = to_f_fs_opts(f);
+	ffs_free_dev(opts->dev);
+	kfree(opts);
+	mutex_lock(&auto_init_lock);
+	kref_put(&auto_init_ref, do_cleanup);
+	mutex_unlock(&auto_init_lock);
+}
+
+static struct usb_function_instance *ffs_alloc_inst(void)
+{
+	struct f_fs_opts *opts;
+	struct ffs_dev *dev;
+	int ret = 0;
+
+	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	if (!opts)
+		return ERR_PTR(-ENOMEM);
+
+	opts->func_inst.free_func_inst = ffs_free_inst;
+	dev = ffs_alloc_dev();
+	if (IS_ERR(dev)) {
+		ret = PTR_ERR(dev);
+		goto error;
+	}
+	opts->dev = dev;
+
+	mutex_lock(&auto_init_lock);
+	if (auto_init_active && do_auto_init) {
+		kref_init(&auto_init_ref);
+		ret = functionfs_init(NULL);
+		if (!ret)
+			do_init_kref = do_auto_init = false;
+	} else {
+		if (do_init_kref) {
+			kref_init(&auto_init_ref);
+			do_init_kref = false;
+		} else {
+			kref_get(&auto_init_ref);
+		}
+	}
+	mutex_unlock(&auto_init_lock);
+
+	if (!ret)
+		return &opts->func_inst;
+error:
+	ffs_free_dev(opts->dev);
+	kfree(opts);
+	return ERR_PTR(ret);
+}
+
+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
 
 
 /* Misc helper functions ****************************************************/
@@ -2536,3 +2670,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 48b0940..caf0035 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"
@@ -204,7 +205,7 @@ static int __init gfs_init(void)
 
 	missing_funcs = func_num;
 
-	return functionfs_init();
+	return functionfs_init(NULL);
 no_dev:
 	while (--i >= 0)
 		ffs_free_dev(ffs_tab[i]);
diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h
index 12f6970..478a7ae 100644
--- a/drivers/usb/gadget/u_fs.h
+++ b/drivers/usb/gadget/u_fs.h
@@ -19,6 +19,22 @@
 #include <linux/usb/composite.h>
 #include <linux/list.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;
@@ -27,4 +43,209 @@ struct ffs_dev {
 	struct list_head entry;
 };
 
+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;
+};
+
+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);
+}
+
+void ffs_set_acquire_dev_cb(void *(*cb)(const char *name));
+void ffs_set_release_dev_cb(void (*cb)(struct ffs_data *ffs_data));
+void ffs_set_ready_cb(int (*cb)(struct ffs_data *ffs_data));
+void ffs_set_closed_cb(void (*cb)(struct ffs_data *ffs_data));
+
+int functionfs_init(struct module *owner);
+void functionfs_cleanup(void);
+struct ffs_dev *ffs_find_dev(const char *name);
+bool ffs_set_auto_init(bool flag);
+#endif
+
 #endif /* U_FFS_H */
diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h
index 65d0a88..5a1374a 100644
--- a/include/linux/usb/functionfs.h
+++ b/include/linux/usb/functionfs.h
@@ -3,13 +3,15 @@
 
 #include <uapi/linux/usb/functionfs.h>
 
+#ifdef USB_FFS_INCLUDED
 
 struct ffs_data;
 struct usb_composite_dev;
 struct usb_configuration;
 
 
-static int  functionfs_init(void) __attribute__((warn_unused_result));
+static int  functionfs_init(struct module *owner)
+	__attribute__((warn_unused_result));
 static void functionfs_cleanup(void);
 
 static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
@@ -32,5 +34,6 @@ static void *functionfs_acquire_dev_callback(const char *dev_name)
 static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
 	__attribute__((nonnull));
 
+#endif
 
 #endif
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux