xref: /openbmc/linux/drivers/usb/gadget/function/f_fs.c (revision b3591f67)
100a2430fSAndrzej Pietrasiewicz /*
200a2430fSAndrzej Pietrasiewicz  * f_fs.c -- user mode file system API for USB composite function controllers
300a2430fSAndrzej Pietrasiewicz  *
400a2430fSAndrzej Pietrasiewicz  * Copyright (C) 2010 Samsung Electronics
500a2430fSAndrzej Pietrasiewicz  * Author: Michal Nazarewicz <mina86@mina86.com>
600a2430fSAndrzej Pietrasiewicz  *
700a2430fSAndrzej Pietrasiewicz  * Based on inode.c (GadgetFS) which was:
800a2430fSAndrzej Pietrasiewicz  * Copyright (C) 2003-2004 David Brownell
900a2430fSAndrzej Pietrasiewicz  * Copyright (C) 2003 Agilent Technologies
1000a2430fSAndrzej Pietrasiewicz  *
1100a2430fSAndrzej Pietrasiewicz  * This program is free software; you can redistribute it and/or modify
1200a2430fSAndrzej Pietrasiewicz  * it under the terms of the GNU General Public License as published by
1300a2430fSAndrzej Pietrasiewicz  * the Free Software Foundation; either version 2 of the License, or
1400a2430fSAndrzej Pietrasiewicz  * (at your option) any later version.
1500a2430fSAndrzej Pietrasiewicz  */
1600a2430fSAndrzej Pietrasiewicz 
1700a2430fSAndrzej Pietrasiewicz 
1800a2430fSAndrzej Pietrasiewicz /* #define DEBUG */
1900a2430fSAndrzej Pietrasiewicz /* #define VERBOSE_DEBUG */
2000a2430fSAndrzej Pietrasiewicz 
2100a2430fSAndrzej Pietrasiewicz #include <linux/blkdev.h>
2200a2430fSAndrzej Pietrasiewicz #include <linux/pagemap.h>
2300a2430fSAndrzej Pietrasiewicz #include <linux/export.h>
2400a2430fSAndrzej Pietrasiewicz #include <linux/hid.h>
2500a2430fSAndrzej Pietrasiewicz #include <linux/module.h>
26e2e40f2cSChristoph Hellwig #include <linux/uio.h>
2700a2430fSAndrzej Pietrasiewicz #include <asm/unaligned.h>
2800a2430fSAndrzej Pietrasiewicz 
2900a2430fSAndrzej Pietrasiewicz #include <linux/usb/composite.h>
3000a2430fSAndrzej Pietrasiewicz #include <linux/usb/functionfs.h>
3100a2430fSAndrzej Pietrasiewicz 
3200a2430fSAndrzej Pietrasiewicz #include <linux/aio.h>
3300a2430fSAndrzej Pietrasiewicz #include <linux/mmu_context.h>
3400a2430fSAndrzej Pietrasiewicz #include <linux/poll.h>
355e33f6fdSRobert Baldyga #include <linux/eventfd.h>
3600a2430fSAndrzej Pietrasiewicz 
3700a2430fSAndrzej Pietrasiewicz #include "u_fs.h"
3800a2430fSAndrzej Pietrasiewicz #include "u_f.h"
3900a2430fSAndrzej Pietrasiewicz #include "u_os_desc.h"
4000a2430fSAndrzej Pietrasiewicz #include "configfs.h"
4100a2430fSAndrzej Pietrasiewicz 
4200a2430fSAndrzej Pietrasiewicz #define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */
4300a2430fSAndrzej Pietrasiewicz 
4400a2430fSAndrzej Pietrasiewicz /* Reference counter handling */
4500a2430fSAndrzej Pietrasiewicz static void ffs_data_get(struct ffs_data *ffs);
4600a2430fSAndrzej Pietrasiewicz static void ffs_data_put(struct ffs_data *ffs);
4700a2430fSAndrzej Pietrasiewicz /* Creates new ffs_data object. */
4800a2430fSAndrzej Pietrasiewicz static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc));
4900a2430fSAndrzej Pietrasiewicz 
5000a2430fSAndrzej Pietrasiewicz /* Opened counter handling. */
5100a2430fSAndrzej Pietrasiewicz static void ffs_data_opened(struct ffs_data *ffs);
5200a2430fSAndrzej Pietrasiewicz static void ffs_data_closed(struct ffs_data *ffs);
5300a2430fSAndrzej Pietrasiewicz 
5400a2430fSAndrzej Pietrasiewicz /* Called with ffs->mutex held; take over ownership of data. */
5500a2430fSAndrzej Pietrasiewicz static int __must_check
5600a2430fSAndrzej Pietrasiewicz __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
5700a2430fSAndrzej Pietrasiewicz static int __must_check
5800a2430fSAndrzej Pietrasiewicz __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
5900a2430fSAndrzej Pietrasiewicz 
6000a2430fSAndrzej Pietrasiewicz 
6100a2430fSAndrzej Pietrasiewicz /* The function structure ***************************************************/
6200a2430fSAndrzej Pietrasiewicz 
6300a2430fSAndrzej Pietrasiewicz struct ffs_ep;
6400a2430fSAndrzej Pietrasiewicz 
6500a2430fSAndrzej Pietrasiewicz struct ffs_function {
6600a2430fSAndrzej Pietrasiewicz 	struct usb_configuration	*conf;
6700a2430fSAndrzej Pietrasiewicz 	struct usb_gadget		*gadget;
6800a2430fSAndrzej Pietrasiewicz 	struct ffs_data			*ffs;
6900a2430fSAndrzej Pietrasiewicz 
7000a2430fSAndrzej Pietrasiewicz 	struct ffs_ep			*eps;
7100a2430fSAndrzej Pietrasiewicz 	u8				eps_revmap[16];
7200a2430fSAndrzej Pietrasiewicz 	short				*interfaces_nums;
7300a2430fSAndrzej Pietrasiewicz 
7400a2430fSAndrzej Pietrasiewicz 	struct usb_function		function;
7500a2430fSAndrzej Pietrasiewicz };
7600a2430fSAndrzej Pietrasiewicz 
7700a2430fSAndrzej Pietrasiewicz 
7800a2430fSAndrzej Pietrasiewicz static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
7900a2430fSAndrzej Pietrasiewicz {
8000a2430fSAndrzej Pietrasiewicz 	return container_of(f, struct ffs_function, function);
8100a2430fSAndrzej Pietrasiewicz }
8200a2430fSAndrzej Pietrasiewicz 
8300a2430fSAndrzej Pietrasiewicz 
8400a2430fSAndrzej Pietrasiewicz static inline enum ffs_setup_state
8500a2430fSAndrzej Pietrasiewicz ffs_setup_state_clear_cancelled(struct ffs_data *ffs)
8600a2430fSAndrzej Pietrasiewicz {
8700a2430fSAndrzej Pietrasiewicz 	return (enum ffs_setup_state)
8800a2430fSAndrzej Pietrasiewicz 		cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP);
8900a2430fSAndrzej Pietrasiewicz }
9000a2430fSAndrzej Pietrasiewicz 
9100a2430fSAndrzej Pietrasiewicz 
9200a2430fSAndrzej Pietrasiewicz static void ffs_func_eps_disable(struct ffs_function *func);
9300a2430fSAndrzej Pietrasiewicz static int __must_check ffs_func_eps_enable(struct ffs_function *func);
9400a2430fSAndrzej Pietrasiewicz 
9500a2430fSAndrzej Pietrasiewicz static int ffs_func_bind(struct usb_configuration *,
9600a2430fSAndrzej Pietrasiewicz 			 struct usb_function *);
9700a2430fSAndrzej Pietrasiewicz static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
9800a2430fSAndrzej Pietrasiewicz static void ffs_func_disable(struct usb_function *);
9900a2430fSAndrzej Pietrasiewicz static int ffs_func_setup(struct usb_function *,
10000a2430fSAndrzej Pietrasiewicz 			  const struct usb_ctrlrequest *);
10100a2430fSAndrzej Pietrasiewicz static void ffs_func_suspend(struct usb_function *);
10200a2430fSAndrzej Pietrasiewicz static void ffs_func_resume(struct usb_function *);
10300a2430fSAndrzej Pietrasiewicz 
10400a2430fSAndrzej Pietrasiewicz 
10500a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
10600a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
10700a2430fSAndrzej Pietrasiewicz 
10800a2430fSAndrzej Pietrasiewicz 
10900a2430fSAndrzej Pietrasiewicz /* The endpoints structures *************************************************/
11000a2430fSAndrzej Pietrasiewicz 
11100a2430fSAndrzej Pietrasiewicz struct ffs_ep {
11200a2430fSAndrzej Pietrasiewicz 	struct usb_ep			*ep;	/* P: ffs->eps_lock */
11300a2430fSAndrzej Pietrasiewicz 	struct usb_request		*req;	/* P: epfile->mutex */
11400a2430fSAndrzej Pietrasiewicz 
11500a2430fSAndrzej Pietrasiewicz 	/* [0]: full speed, [1]: high speed, [2]: super speed */
11600a2430fSAndrzej Pietrasiewicz 	struct usb_endpoint_descriptor	*descs[3];
11700a2430fSAndrzej Pietrasiewicz 
11800a2430fSAndrzej Pietrasiewicz 	u8				num;
11900a2430fSAndrzej Pietrasiewicz 
12000a2430fSAndrzej Pietrasiewicz 	int				status;	/* P: epfile->mutex */
12100a2430fSAndrzej Pietrasiewicz };
12200a2430fSAndrzej Pietrasiewicz 
12300a2430fSAndrzej Pietrasiewicz struct ffs_epfile {
12400a2430fSAndrzej Pietrasiewicz 	/* Protects ep->ep and ep->req. */
12500a2430fSAndrzej Pietrasiewicz 	struct mutex			mutex;
12600a2430fSAndrzej Pietrasiewicz 	wait_queue_head_t		wait;
12700a2430fSAndrzej Pietrasiewicz 
12800a2430fSAndrzej Pietrasiewicz 	struct ffs_data			*ffs;
12900a2430fSAndrzej Pietrasiewicz 	struct ffs_ep			*ep;	/* P: ffs->eps_lock */
13000a2430fSAndrzej Pietrasiewicz 
13100a2430fSAndrzej Pietrasiewicz 	struct dentry			*dentry;
13200a2430fSAndrzej Pietrasiewicz 
13300a2430fSAndrzej Pietrasiewicz 	char				name[5];
13400a2430fSAndrzej Pietrasiewicz 
13500a2430fSAndrzej Pietrasiewicz 	unsigned char			in;	/* P: ffs->eps_lock */
13600a2430fSAndrzej Pietrasiewicz 	unsigned char			isoc;	/* P: ffs->eps_lock */
13700a2430fSAndrzej Pietrasiewicz 
13800a2430fSAndrzej Pietrasiewicz 	unsigned char			_pad;
13900a2430fSAndrzej Pietrasiewicz };
14000a2430fSAndrzej Pietrasiewicz 
14100a2430fSAndrzej Pietrasiewicz /*  ffs_io_data structure ***************************************************/
14200a2430fSAndrzej Pietrasiewicz 
14300a2430fSAndrzej Pietrasiewicz struct ffs_io_data {
14400a2430fSAndrzej Pietrasiewicz 	bool aio;
14500a2430fSAndrzej Pietrasiewicz 	bool read;
14600a2430fSAndrzej Pietrasiewicz 
14700a2430fSAndrzej Pietrasiewicz 	struct kiocb *kiocb;
148c993c39bSAl Viro 	struct iov_iter data;
149c993c39bSAl Viro 	const void *to_free;
150c993c39bSAl Viro 	char *buf;
15100a2430fSAndrzej Pietrasiewicz 
15200a2430fSAndrzej Pietrasiewicz 	struct mm_struct *mm;
15300a2430fSAndrzej Pietrasiewicz 	struct work_struct work;
15400a2430fSAndrzej Pietrasiewicz 
15500a2430fSAndrzej Pietrasiewicz 	struct usb_ep *ep;
15600a2430fSAndrzej Pietrasiewicz 	struct usb_request *req;
1575e33f6fdSRobert Baldyga 
1585e33f6fdSRobert Baldyga 	struct ffs_data *ffs;
15900a2430fSAndrzej Pietrasiewicz };
16000a2430fSAndrzej Pietrasiewicz 
1616d5c1c77SRobert Baldyga struct ffs_desc_helper {
1626d5c1c77SRobert Baldyga 	struct ffs_data *ffs;
1636d5c1c77SRobert Baldyga 	unsigned interfaces_count;
1646d5c1c77SRobert Baldyga 	unsigned eps_count;
1656d5c1c77SRobert Baldyga };
1666d5c1c77SRobert Baldyga 
16700a2430fSAndrzej Pietrasiewicz static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);
16800a2430fSAndrzej Pietrasiewicz static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
16900a2430fSAndrzej Pietrasiewicz 
1701bb27cacSAl Viro static struct dentry *
17100a2430fSAndrzej Pietrasiewicz ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
1721bb27cacSAl Viro 		   const struct file_operations *fops);
17300a2430fSAndrzej Pietrasiewicz 
17400a2430fSAndrzej Pietrasiewicz /* Devices management *******************************************************/
17500a2430fSAndrzej Pietrasiewicz 
17600a2430fSAndrzej Pietrasiewicz DEFINE_MUTEX(ffs_lock);
17700a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_lock);
17800a2430fSAndrzej Pietrasiewicz 
17900a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_find_dev(const char *name);
18000a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_alloc_dev(void);
18100a2430fSAndrzej Pietrasiewicz static int _ffs_name_dev(struct ffs_dev *dev, const char *name);
18200a2430fSAndrzej Pietrasiewicz static void _ffs_free_dev(struct ffs_dev *dev);
18300a2430fSAndrzej Pietrasiewicz static void *ffs_acquire_dev(const char *dev_name);
18400a2430fSAndrzej Pietrasiewicz static void ffs_release_dev(struct ffs_data *ffs_data);
18500a2430fSAndrzej Pietrasiewicz static int ffs_ready(struct ffs_data *ffs);
18600a2430fSAndrzej Pietrasiewicz static void ffs_closed(struct ffs_data *ffs);
18700a2430fSAndrzej Pietrasiewicz 
18800a2430fSAndrzej Pietrasiewicz /* Misc helper functions ****************************************************/
18900a2430fSAndrzej Pietrasiewicz 
19000a2430fSAndrzej Pietrasiewicz static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
19100a2430fSAndrzej Pietrasiewicz 	__attribute__((warn_unused_result, nonnull));
19200a2430fSAndrzej Pietrasiewicz static char *ffs_prepare_buffer(const char __user *buf, size_t len)
19300a2430fSAndrzej Pietrasiewicz 	__attribute__((warn_unused_result, nonnull));
19400a2430fSAndrzej Pietrasiewicz 
19500a2430fSAndrzej Pietrasiewicz 
19600a2430fSAndrzej Pietrasiewicz /* Control file aka ep0 *****************************************************/
19700a2430fSAndrzej Pietrasiewicz 
19800a2430fSAndrzej Pietrasiewicz static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
19900a2430fSAndrzej Pietrasiewicz {
20000a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = req->context;
20100a2430fSAndrzej Pietrasiewicz 
20200a2430fSAndrzej Pietrasiewicz 	complete_all(&ffs->ep0req_completion);
20300a2430fSAndrzej Pietrasiewicz }
20400a2430fSAndrzej Pietrasiewicz 
20500a2430fSAndrzej Pietrasiewicz static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
20600a2430fSAndrzej Pietrasiewicz {
20700a2430fSAndrzej Pietrasiewicz 	struct usb_request *req = ffs->ep0req;
20800a2430fSAndrzej Pietrasiewicz 	int ret;
20900a2430fSAndrzej Pietrasiewicz 
21000a2430fSAndrzej Pietrasiewicz 	req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
21100a2430fSAndrzej Pietrasiewicz 
21200a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&ffs->ev.waitq.lock);
21300a2430fSAndrzej Pietrasiewicz 
21400a2430fSAndrzej Pietrasiewicz 	req->buf      = data;
21500a2430fSAndrzej Pietrasiewicz 	req->length   = len;
21600a2430fSAndrzej Pietrasiewicz 
21700a2430fSAndrzej Pietrasiewicz 	/*
21800a2430fSAndrzej Pietrasiewicz 	 * UDC layer requires to provide a buffer even for ZLP, but should
21900a2430fSAndrzej Pietrasiewicz 	 * not use it at all. Let's provide some poisoned pointer to catch
22000a2430fSAndrzej Pietrasiewicz 	 * possible bug in the driver.
22100a2430fSAndrzej Pietrasiewicz 	 */
22200a2430fSAndrzej Pietrasiewicz 	if (req->buf == NULL)
22300a2430fSAndrzej Pietrasiewicz 		req->buf = (void *)0xDEADBABE;
22400a2430fSAndrzej Pietrasiewicz 
22500a2430fSAndrzej Pietrasiewicz 	reinit_completion(&ffs->ep0req_completion);
22600a2430fSAndrzej Pietrasiewicz 
22700a2430fSAndrzej Pietrasiewicz 	ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
22800a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret < 0))
22900a2430fSAndrzej Pietrasiewicz 		return ret;
23000a2430fSAndrzej Pietrasiewicz 
23100a2430fSAndrzej Pietrasiewicz 	ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
23200a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret)) {
23300a2430fSAndrzej Pietrasiewicz 		usb_ep_dequeue(ffs->gadget->ep0, req);
23400a2430fSAndrzej Pietrasiewicz 		return -EINTR;
23500a2430fSAndrzej Pietrasiewicz 	}
23600a2430fSAndrzej Pietrasiewicz 
23700a2430fSAndrzej Pietrasiewicz 	ffs->setup_state = FFS_NO_SETUP;
23800a2430fSAndrzej Pietrasiewicz 	return req->status ? req->status : req->actual;
23900a2430fSAndrzej Pietrasiewicz }
24000a2430fSAndrzej Pietrasiewicz 
24100a2430fSAndrzej Pietrasiewicz static int __ffs_ep0_stall(struct ffs_data *ffs)
24200a2430fSAndrzej Pietrasiewicz {
24300a2430fSAndrzej Pietrasiewicz 	if (ffs->ev.can_stall) {
24400a2430fSAndrzej Pietrasiewicz 		pr_vdebug("ep0 stall\n");
24500a2430fSAndrzej Pietrasiewicz 		usb_ep_set_halt(ffs->gadget->ep0);
24600a2430fSAndrzej Pietrasiewicz 		ffs->setup_state = FFS_NO_SETUP;
24700a2430fSAndrzej Pietrasiewicz 		return -EL2HLT;
24800a2430fSAndrzej Pietrasiewicz 	} else {
24900a2430fSAndrzej Pietrasiewicz 		pr_debug("bogus ep0 stall!\n");
25000a2430fSAndrzej Pietrasiewicz 		return -ESRCH;
25100a2430fSAndrzej Pietrasiewicz 	}
25200a2430fSAndrzej Pietrasiewicz }
25300a2430fSAndrzej Pietrasiewicz 
25400a2430fSAndrzej Pietrasiewicz static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
25500a2430fSAndrzej Pietrasiewicz 			     size_t len, loff_t *ptr)
25600a2430fSAndrzej Pietrasiewicz {
25700a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
25800a2430fSAndrzej Pietrasiewicz 	ssize_t ret;
25900a2430fSAndrzej Pietrasiewicz 	char *data;
26000a2430fSAndrzej Pietrasiewicz 
26100a2430fSAndrzej Pietrasiewicz 	ENTER();
26200a2430fSAndrzej Pietrasiewicz 
26300a2430fSAndrzej Pietrasiewicz 	/* Fast check if setup was canceled */
26400a2430fSAndrzej Pietrasiewicz 	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
26500a2430fSAndrzej Pietrasiewicz 		return -EIDRM;
26600a2430fSAndrzej Pietrasiewicz 
26700a2430fSAndrzej Pietrasiewicz 	/* Acquire mutex */
26800a2430fSAndrzej Pietrasiewicz 	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
26900a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret < 0))
27000a2430fSAndrzej Pietrasiewicz 		return ret;
27100a2430fSAndrzej Pietrasiewicz 
27200a2430fSAndrzej Pietrasiewicz 	/* Check state */
27300a2430fSAndrzej Pietrasiewicz 	switch (ffs->state) {
27400a2430fSAndrzej Pietrasiewicz 	case FFS_READ_DESCRIPTORS:
27500a2430fSAndrzej Pietrasiewicz 	case FFS_READ_STRINGS:
27600a2430fSAndrzej Pietrasiewicz 		/* Copy data */
27700a2430fSAndrzej Pietrasiewicz 		if (unlikely(len < 16)) {
27800a2430fSAndrzej Pietrasiewicz 			ret = -EINVAL;
27900a2430fSAndrzej Pietrasiewicz 			break;
28000a2430fSAndrzej Pietrasiewicz 		}
28100a2430fSAndrzej Pietrasiewicz 
28200a2430fSAndrzej Pietrasiewicz 		data = ffs_prepare_buffer(buf, len);
28300a2430fSAndrzej Pietrasiewicz 		if (IS_ERR(data)) {
28400a2430fSAndrzej Pietrasiewicz 			ret = PTR_ERR(data);
28500a2430fSAndrzej Pietrasiewicz 			break;
28600a2430fSAndrzej Pietrasiewicz 		}
28700a2430fSAndrzej Pietrasiewicz 
28800a2430fSAndrzej Pietrasiewicz 		/* Handle data */
28900a2430fSAndrzej Pietrasiewicz 		if (ffs->state == FFS_READ_DESCRIPTORS) {
29000a2430fSAndrzej Pietrasiewicz 			pr_info("read descriptors\n");
29100a2430fSAndrzej Pietrasiewicz 			ret = __ffs_data_got_descs(ffs, data, len);
29200a2430fSAndrzej Pietrasiewicz 			if (unlikely(ret < 0))
29300a2430fSAndrzej Pietrasiewicz 				break;
29400a2430fSAndrzej Pietrasiewicz 
29500a2430fSAndrzej Pietrasiewicz 			ffs->state = FFS_READ_STRINGS;
29600a2430fSAndrzej Pietrasiewicz 			ret = len;
29700a2430fSAndrzej Pietrasiewicz 		} else {
29800a2430fSAndrzej Pietrasiewicz 			pr_info("read strings\n");
29900a2430fSAndrzej Pietrasiewicz 			ret = __ffs_data_got_strings(ffs, data, len);
30000a2430fSAndrzej Pietrasiewicz 			if (unlikely(ret < 0))
30100a2430fSAndrzej Pietrasiewicz 				break;
30200a2430fSAndrzej Pietrasiewicz 
30300a2430fSAndrzej Pietrasiewicz 			ret = ffs_epfiles_create(ffs);
30400a2430fSAndrzej Pietrasiewicz 			if (unlikely(ret)) {
30500a2430fSAndrzej Pietrasiewicz 				ffs->state = FFS_CLOSING;
30600a2430fSAndrzej Pietrasiewicz 				break;
30700a2430fSAndrzej Pietrasiewicz 			}
30800a2430fSAndrzej Pietrasiewicz 
30900a2430fSAndrzej Pietrasiewicz 			ffs->state = FFS_ACTIVE;
31000a2430fSAndrzej Pietrasiewicz 			mutex_unlock(&ffs->mutex);
31100a2430fSAndrzej Pietrasiewicz 
31200a2430fSAndrzej Pietrasiewicz 			ret = ffs_ready(ffs);
31300a2430fSAndrzej Pietrasiewicz 			if (unlikely(ret < 0)) {
31400a2430fSAndrzej Pietrasiewicz 				ffs->state = FFS_CLOSING;
31500a2430fSAndrzej Pietrasiewicz 				return ret;
31600a2430fSAndrzej Pietrasiewicz 			}
31700a2430fSAndrzej Pietrasiewicz 
31800a2430fSAndrzej Pietrasiewicz 			return len;
31900a2430fSAndrzej Pietrasiewicz 		}
32000a2430fSAndrzej Pietrasiewicz 		break;
32100a2430fSAndrzej Pietrasiewicz 
32200a2430fSAndrzej Pietrasiewicz 	case FFS_ACTIVE:
32300a2430fSAndrzej Pietrasiewicz 		data = NULL;
32400a2430fSAndrzej Pietrasiewicz 		/*
32500a2430fSAndrzej Pietrasiewicz 		 * We're called from user space, we can use _irq
32600a2430fSAndrzej Pietrasiewicz 		 * rather then _irqsave
32700a2430fSAndrzej Pietrasiewicz 		 */
32800a2430fSAndrzej Pietrasiewicz 		spin_lock_irq(&ffs->ev.waitq.lock);
32900a2430fSAndrzej Pietrasiewicz 		switch (ffs_setup_state_clear_cancelled(ffs)) {
33000a2430fSAndrzej Pietrasiewicz 		case FFS_SETUP_CANCELLED:
33100a2430fSAndrzej Pietrasiewicz 			ret = -EIDRM;
33200a2430fSAndrzej Pietrasiewicz 			goto done_spin;
33300a2430fSAndrzej Pietrasiewicz 
33400a2430fSAndrzej Pietrasiewicz 		case FFS_NO_SETUP:
33500a2430fSAndrzej Pietrasiewicz 			ret = -ESRCH;
33600a2430fSAndrzej Pietrasiewicz 			goto done_spin;
33700a2430fSAndrzej Pietrasiewicz 
33800a2430fSAndrzej Pietrasiewicz 		case FFS_SETUP_PENDING:
33900a2430fSAndrzej Pietrasiewicz 			break;
34000a2430fSAndrzej Pietrasiewicz 		}
34100a2430fSAndrzej Pietrasiewicz 
34200a2430fSAndrzej Pietrasiewicz 		/* FFS_SETUP_PENDING */
34300a2430fSAndrzej Pietrasiewicz 		if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
34400a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&ffs->ev.waitq.lock);
34500a2430fSAndrzej Pietrasiewicz 			ret = __ffs_ep0_stall(ffs);
34600a2430fSAndrzej Pietrasiewicz 			break;
34700a2430fSAndrzej Pietrasiewicz 		}
34800a2430fSAndrzej Pietrasiewicz 
34900a2430fSAndrzej Pietrasiewicz 		/* FFS_SETUP_PENDING and not stall */
35000a2430fSAndrzej Pietrasiewicz 		len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
35100a2430fSAndrzej Pietrasiewicz 
35200a2430fSAndrzej Pietrasiewicz 		spin_unlock_irq(&ffs->ev.waitq.lock);
35300a2430fSAndrzej Pietrasiewicz 
35400a2430fSAndrzej Pietrasiewicz 		data = ffs_prepare_buffer(buf, len);
35500a2430fSAndrzej Pietrasiewicz 		if (IS_ERR(data)) {
35600a2430fSAndrzej Pietrasiewicz 			ret = PTR_ERR(data);
35700a2430fSAndrzej Pietrasiewicz 			break;
35800a2430fSAndrzej Pietrasiewicz 		}
35900a2430fSAndrzej Pietrasiewicz 
36000a2430fSAndrzej Pietrasiewicz 		spin_lock_irq(&ffs->ev.waitq.lock);
36100a2430fSAndrzej Pietrasiewicz 
36200a2430fSAndrzej Pietrasiewicz 		/*
36300a2430fSAndrzej Pietrasiewicz 		 * We are guaranteed to be still in FFS_ACTIVE state
36400a2430fSAndrzej Pietrasiewicz 		 * but the state of setup could have changed from
36500a2430fSAndrzej Pietrasiewicz 		 * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need
36600a2430fSAndrzej Pietrasiewicz 		 * to check for that.  If that happened we copied data
36700a2430fSAndrzej Pietrasiewicz 		 * from user space in vain but it's unlikely.
36800a2430fSAndrzej Pietrasiewicz 		 *
36900a2430fSAndrzej Pietrasiewicz 		 * For sure we are not in FFS_NO_SETUP since this is
37000a2430fSAndrzej Pietrasiewicz 		 * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
37100a2430fSAndrzej Pietrasiewicz 		 * transition can be performed and it's protected by
37200a2430fSAndrzej Pietrasiewicz 		 * mutex.
37300a2430fSAndrzej Pietrasiewicz 		 */
37400a2430fSAndrzej Pietrasiewicz 		if (ffs_setup_state_clear_cancelled(ffs) ==
37500a2430fSAndrzej Pietrasiewicz 		    FFS_SETUP_CANCELLED) {
37600a2430fSAndrzej Pietrasiewicz 			ret = -EIDRM;
37700a2430fSAndrzej Pietrasiewicz done_spin:
37800a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&ffs->ev.waitq.lock);
37900a2430fSAndrzej Pietrasiewicz 		} else {
38000a2430fSAndrzej Pietrasiewicz 			/* unlocks spinlock */
38100a2430fSAndrzej Pietrasiewicz 			ret = __ffs_ep0_queue_wait(ffs, data, len);
38200a2430fSAndrzej Pietrasiewicz 		}
38300a2430fSAndrzej Pietrasiewicz 		kfree(data);
38400a2430fSAndrzej Pietrasiewicz 		break;
38500a2430fSAndrzej Pietrasiewicz 
38600a2430fSAndrzej Pietrasiewicz 	default:
38700a2430fSAndrzej Pietrasiewicz 		ret = -EBADFD;
38800a2430fSAndrzej Pietrasiewicz 		break;
38900a2430fSAndrzej Pietrasiewicz 	}
39000a2430fSAndrzej Pietrasiewicz 
39100a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&ffs->mutex);
39200a2430fSAndrzej Pietrasiewicz 	return ret;
39300a2430fSAndrzej Pietrasiewicz }
39400a2430fSAndrzej Pietrasiewicz 
39567913bbdSMichal Nazarewicz /* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
39600a2430fSAndrzej Pietrasiewicz static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
39700a2430fSAndrzej Pietrasiewicz 				     size_t n)
39800a2430fSAndrzej Pietrasiewicz {
39900a2430fSAndrzej Pietrasiewicz 	/*
40067913bbdSMichal Nazarewicz 	 * n cannot be bigger than ffs->ev.count, which cannot be bigger than
40167913bbdSMichal Nazarewicz 	 * size of ffs->ev.types array (which is four) so that's how much space
40267913bbdSMichal Nazarewicz 	 * we reserve.
40300a2430fSAndrzej Pietrasiewicz 	 */
40467913bbdSMichal Nazarewicz 	struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
40567913bbdSMichal Nazarewicz 	const size_t size = n * sizeof *events;
40600a2430fSAndrzej Pietrasiewicz 	unsigned i = 0;
40700a2430fSAndrzej Pietrasiewicz 
40867913bbdSMichal Nazarewicz 	memset(events, 0, size);
40900a2430fSAndrzej Pietrasiewicz 
41000a2430fSAndrzej Pietrasiewicz 	do {
41100a2430fSAndrzej Pietrasiewicz 		events[i].type = ffs->ev.types[i];
41200a2430fSAndrzej Pietrasiewicz 		if (events[i].type == FUNCTIONFS_SETUP) {
41300a2430fSAndrzej Pietrasiewicz 			events[i].u.setup = ffs->ev.setup;
41400a2430fSAndrzej Pietrasiewicz 			ffs->setup_state = FFS_SETUP_PENDING;
41500a2430fSAndrzej Pietrasiewicz 		}
41600a2430fSAndrzej Pietrasiewicz 	} while (++i < n);
41700a2430fSAndrzej Pietrasiewicz 
41800a2430fSAndrzej Pietrasiewicz 	ffs->ev.count -= n;
41967913bbdSMichal Nazarewicz 	if (ffs->ev.count)
42000a2430fSAndrzej Pietrasiewicz 		memmove(ffs->ev.types, ffs->ev.types + n,
42100a2430fSAndrzej Pietrasiewicz 			ffs->ev.count * sizeof *ffs->ev.types);
42200a2430fSAndrzej Pietrasiewicz 
42300a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&ffs->ev.waitq.lock);
42400a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&ffs->mutex);
42500a2430fSAndrzej Pietrasiewicz 
4267fe9a937SDaniel Walter 	return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size;
42700a2430fSAndrzej Pietrasiewicz }
42800a2430fSAndrzej Pietrasiewicz 
42900a2430fSAndrzej Pietrasiewicz static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
43000a2430fSAndrzej Pietrasiewicz 			    size_t len, loff_t *ptr)
43100a2430fSAndrzej Pietrasiewicz {
43200a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
43300a2430fSAndrzej Pietrasiewicz 	char *data = NULL;
43400a2430fSAndrzej Pietrasiewicz 	size_t n;
43500a2430fSAndrzej Pietrasiewicz 	int ret;
43600a2430fSAndrzej Pietrasiewicz 
43700a2430fSAndrzej Pietrasiewicz 	ENTER();
43800a2430fSAndrzej Pietrasiewicz 
43900a2430fSAndrzej Pietrasiewicz 	/* Fast check if setup was canceled */
44000a2430fSAndrzej Pietrasiewicz 	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
44100a2430fSAndrzej Pietrasiewicz 		return -EIDRM;
44200a2430fSAndrzej Pietrasiewicz 
44300a2430fSAndrzej Pietrasiewicz 	/* Acquire mutex */
44400a2430fSAndrzej Pietrasiewicz 	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
44500a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret < 0))
44600a2430fSAndrzej Pietrasiewicz 		return ret;
44700a2430fSAndrzej Pietrasiewicz 
44800a2430fSAndrzej Pietrasiewicz 	/* Check state */
44900a2430fSAndrzej Pietrasiewicz 	if (ffs->state != FFS_ACTIVE) {
45000a2430fSAndrzej Pietrasiewicz 		ret = -EBADFD;
45100a2430fSAndrzej Pietrasiewicz 		goto done_mutex;
45200a2430fSAndrzej Pietrasiewicz 	}
45300a2430fSAndrzej Pietrasiewicz 
45400a2430fSAndrzej Pietrasiewicz 	/*
45500a2430fSAndrzej Pietrasiewicz 	 * We're called from user space, we can use _irq rather then
45600a2430fSAndrzej Pietrasiewicz 	 * _irqsave
45700a2430fSAndrzej Pietrasiewicz 	 */
45800a2430fSAndrzej Pietrasiewicz 	spin_lock_irq(&ffs->ev.waitq.lock);
45900a2430fSAndrzej Pietrasiewicz 
46000a2430fSAndrzej Pietrasiewicz 	switch (ffs_setup_state_clear_cancelled(ffs)) {
46100a2430fSAndrzej Pietrasiewicz 	case FFS_SETUP_CANCELLED:
46200a2430fSAndrzej Pietrasiewicz 		ret = -EIDRM;
46300a2430fSAndrzej Pietrasiewicz 		break;
46400a2430fSAndrzej Pietrasiewicz 
46500a2430fSAndrzej Pietrasiewicz 	case FFS_NO_SETUP:
46600a2430fSAndrzej Pietrasiewicz 		n = len / sizeof(struct usb_functionfs_event);
46700a2430fSAndrzej Pietrasiewicz 		if (unlikely(!n)) {
46800a2430fSAndrzej Pietrasiewicz 			ret = -EINVAL;
46900a2430fSAndrzej Pietrasiewicz 			break;
47000a2430fSAndrzej Pietrasiewicz 		}
47100a2430fSAndrzej Pietrasiewicz 
47200a2430fSAndrzej Pietrasiewicz 		if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
47300a2430fSAndrzej Pietrasiewicz 			ret = -EAGAIN;
47400a2430fSAndrzej Pietrasiewicz 			break;
47500a2430fSAndrzej Pietrasiewicz 		}
47600a2430fSAndrzej Pietrasiewicz 
47700a2430fSAndrzej Pietrasiewicz 		if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
47800a2430fSAndrzej Pietrasiewicz 							ffs->ev.count)) {
47900a2430fSAndrzej Pietrasiewicz 			ret = -EINTR;
48000a2430fSAndrzej Pietrasiewicz 			break;
48100a2430fSAndrzej Pietrasiewicz 		}
48200a2430fSAndrzej Pietrasiewicz 
48300a2430fSAndrzej Pietrasiewicz 		return __ffs_ep0_read_events(ffs, buf,
48400a2430fSAndrzej Pietrasiewicz 					     min(n, (size_t)ffs->ev.count));
48500a2430fSAndrzej Pietrasiewicz 
48600a2430fSAndrzej Pietrasiewicz 	case FFS_SETUP_PENDING:
48700a2430fSAndrzej Pietrasiewicz 		if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
48800a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&ffs->ev.waitq.lock);
48900a2430fSAndrzej Pietrasiewicz 			ret = __ffs_ep0_stall(ffs);
49000a2430fSAndrzej Pietrasiewicz 			goto done_mutex;
49100a2430fSAndrzej Pietrasiewicz 		}
49200a2430fSAndrzej Pietrasiewicz 
49300a2430fSAndrzej Pietrasiewicz 		len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
49400a2430fSAndrzej Pietrasiewicz 
49500a2430fSAndrzej Pietrasiewicz 		spin_unlock_irq(&ffs->ev.waitq.lock);
49600a2430fSAndrzej Pietrasiewicz 
49700a2430fSAndrzej Pietrasiewicz 		if (likely(len)) {
49800a2430fSAndrzej Pietrasiewicz 			data = kmalloc(len, GFP_KERNEL);
49900a2430fSAndrzej Pietrasiewicz 			if (unlikely(!data)) {
50000a2430fSAndrzej Pietrasiewicz 				ret = -ENOMEM;
50100a2430fSAndrzej Pietrasiewicz 				goto done_mutex;
50200a2430fSAndrzej Pietrasiewicz 			}
50300a2430fSAndrzej Pietrasiewicz 		}
50400a2430fSAndrzej Pietrasiewicz 
50500a2430fSAndrzej Pietrasiewicz 		spin_lock_irq(&ffs->ev.waitq.lock);
50600a2430fSAndrzej Pietrasiewicz 
50700a2430fSAndrzej Pietrasiewicz 		/* See ffs_ep0_write() */
50800a2430fSAndrzej Pietrasiewicz 		if (ffs_setup_state_clear_cancelled(ffs) ==
50900a2430fSAndrzej Pietrasiewicz 		    FFS_SETUP_CANCELLED) {
51000a2430fSAndrzej Pietrasiewicz 			ret = -EIDRM;
51100a2430fSAndrzej Pietrasiewicz 			break;
51200a2430fSAndrzej Pietrasiewicz 		}
51300a2430fSAndrzej Pietrasiewicz 
51400a2430fSAndrzej Pietrasiewicz 		/* unlocks spinlock */
51500a2430fSAndrzej Pietrasiewicz 		ret = __ffs_ep0_queue_wait(ffs, data, len);
5167fe9a937SDaniel Walter 		if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len)))
51700a2430fSAndrzej Pietrasiewicz 			ret = -EFAULT;
51800a2430fSAndrzej Pietrasiewicz 		goto done_mutex;
51900a2430fSAndrzej Pietrasiewicz 
52000a2430fSAndrzej Pietrasiewicz 	default:
52100a2430fSAndrzej Pietrasiewicz 		ret = -EBADFD;
52200a2430fSAndrzej Pietrasiewicz 		break;
52300a2430fSAndrzej Pietrasiewicz 	}
52400a2430fSAndrzej Pietrasiewicz 
52500a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&ffs->ev.waitq.lock);
52600a2430fSAndrzej Pietrasiewicz done_mutex:
52700a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&ffs->mutex);
52800a2430fSAndrzej Pietrasiewicz 	kfree(data);
52900a2430fSAndrzej Pietrasiewicz 	return ret;
53000a2430fSAndrzej Pietrasiewicz }
53100a2430fSAndrzej Pietrasiewicz 
53200a2430fSAndrzej Pietrasiewicz static int ffs_ep0_open(struct inode *inode, struct file *file)
53300a2430fSAndrzej Pietrasiewicz {
53400a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = inode->i_private;
53500a2430fSAndrzej Pietrasiewicz 
53600a2430fSAndrzej Pietrasiewicz 	ENTER();
53700a2430fSAndrzej Pietrasiewicz 
53800a2430fSAndrzej Pietrasiewicz 	if (unlikely(ffs->state == FFS_CLOSING))
53900a2430fSAndrzej Pietrasiewicz 		return -EBUSY;
54000a2430fSAndrzej Pietrasiewicz 
54100a2430fSAndrzej Pietrasiewicz 	file->private_data = ffs;
54200a2430fSAndrzej Pietrasiewicz 	ffs_data_opened(ffs);
54300a2430fSAndrzej Pietrasiewicz 
54400a2430fSAndrzej Pietrasiewicz 	return 0;
54500a2430fSAndrzej Pietrasiewicz }
54600a2430fSAndrzej Pietrasiewicz 
54700a2430fSAndrzej Pietrasiewicz static int ffs_ep0_release(struct inode *inode, struct file *file)
54800a2430fSAndrzej Pietrasiewicz {
54900a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
55000a2430fSAndrzej Pietrasiewicz 
55100a2430fSAndrzej Pietrasiewicz 	ENTER();
55200a2430fSAndrzej Pietrasiewicz 
55300a2430fSAndrzej Pietrasiewicz 	ffs_data_closed(ffs);
55400a2430fSAndrzej Pietrasiewicz 
55500a2430fSAndrzej Pietrasiewicz 	return 0;
55600a2430fSAndrzej Pietrasiewicz }
55700a2430fSAndrzej Pietrasiewicz 
55800a2430fSAndrzej Pietrasiewicz static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
55900a2430fSAndrzej Pietrasiewicz {
56000a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
56100a2430fSAndrzej Pietrasiewicz 	struct usb_gadget *gadget = ffs->gadget;
56200a2430fSAndrzej Pietrasiewicz 	long ret;
56300a2430fSAndrzej Pietrasiewicz 
56400a2430fSAndrzej Pietrasiewicz 	ENTER();
56500a2430fSAndrzej Pietrasiewicz 
56600a2430fSAndrzej Pietrasiewicz 	if (code == FUNCTIONFS_INTERFACE_REVMAP) {
56700a2430fSAndrzej Pietrasiewicz 		struct ffs_function *func = ffs->func;
56800a2430fSAndrzej Pietrasiewicz 		ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
56900a2430fSAndrzej Pietrasiewicz 	} else if (gadget && gadget->ops->ioctl) {
57000a2430fSAndrzej Pietrasiewicz 		ret = gadget->ops->ioctl(gadget, code, value);
57100a2430fSAndrzej Pietrasiewicz 	} else {
57200a2430fSAndrzej Pietrasiewicz 		ret = -ENOTTY;
57300a2430fSAndrzej Pietrasiewicz 	}
57400a2430fSAndrzej Pietrasiewicz 
57500a2430fSAndrzej Pietrasiewicz 	return ret;
57600a2430fSAndrzej Pietrasiewicz }
57700a2430fSAndrzej Pietrasiewicz 
57800a2430fSAndrzej Pietrasiewicz static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait)
57900a2430fSAndrzej Pietrasiewicz {
58000a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
58100a2430fSAndrzej Pietrasiewicz 	unsigned int mask = POLLWRNORM;
58200a2430fSAndrzej Pietrasiewicz 	int ret;
58300a2430fSAndrzej Pietrasiewicz 
58400a2430fSAndrzej Pietrasiewicz 	poll_wait(file, &ffs->ev.waitq, wait);
58500a2430fSAndrzej Pietrasiewicz 
58600a2430fSAndrzej Pietrasiewicz 	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
58700a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret < 0))
58800a2430fSAndrzej Pietrasiewicz 		return mask;
58900a2430fSAndrzej Pietrasiewicz 
59000a2430fSAndrzej Pietrasiewicz 	switch (ffs->state) {
59100a2430fSAndrzej Pietrasiewicz 	case FFS_READ_DESCRIPTORS:
59200a2430fSAndrzej Pietrasiewicz 	case FFS_READ_STRINGS:
59300a2430fSAndrzej Pietrasiewicz 		mask |= POLLOUT;
59400a2430fSAndrzej Pietrasiewicz 		break;
59500a2430fSAndrzej Pietrasiewicz 
59600a2430fSAndrzej Pietrasiewicz 	case FFS_ACTIVE:
59700a2430fSAndrzej Pietrasiewicz 		switch (ffs->setup_state) {
59800a2430fSAndrzej Pietrasiewicz 		case FFS_NO_SETUP:
59900a2430fSAndrzej Pietrasiewicz 			if (ffs->ev.count)
60000a2430fSAndrzej Pietrasiewicz 				mask |= POLLIN;
60100a2430fSAndrzej Pietrasiewicz 			break;
60200a2430fSAndrzej Pietrasiewicz 
60300a2430fSAndrzej Pietrasiewicz 		case FFS_SETUP_PENDING:
60400a2430fSAndrzej Pietrasiewicz 		case FFS_SETUP_CANCELLED:
60500a2430fSAndrzej Pietrasiewicz 			mask |= (POLLIN | POLLOUT);
60600a2430fSAndrzej Pietrasiewicz 			break;
60700a2430fSAndrzej Pietrasiewicz 		}
60800a2430fSAndrzej Pietrasiewicz 	case FFS_CLOSING:
60900a2430fSAndrzej Pietrasiewicz 		break;
61018d6b32fSRobert Baldyga 	case FFS_DEACTIVATED:
61118d6b32fSRobert Baldyga 		break;
61200a2430fSAndrzej Pietrasiewicz 	}
61300a2430fSAndrzej Pietrasiewicz 
61400a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&ffs->mutex);
61500a2430fSAndrzej Pietrasiewicz 
61600a2430fSAndrzej Pietrasiewicz 	return mask;
61700a2430fSAndrzej Pietrasiewicz }
61800a2430fSAndrzej Pietrasiewicz 
61900a2430fSAndrzej Pietrasiewicz static const struct file_operations ffs_ep0_operations = {
62000a2430fSAndrzej Pietrasiewicz 	.llseek =	no_llseek,
62100a2430fSAndrzej Pietrasiewicz 
62200a2430fSAndrzej Pietrasiewicz 	.open =		ffs_ep0_open,
62300a2430fSAndrzej Pietrasiewicz 	.write =	ffs_ep0_write,
62400a2430fSAndrzej Pietrasiewicz 	.read =		ffs_ep0_read,
62500a2430fSAndrzej Pietrasiewicz 	.release =	ffs_ep0_release,
62600a2430fSAndrzej Pietrasiewicz 	.unlocked_ioctl =	ffs_ep0_ioctl,
62700a2430fSAndrzej Pietrasiewicz 	.poll =		ffs_ep0_poll,
62800a2430fSAndrzej Pietrasiewicz };
62900a2430fSAndrzej Pietrasiewicz 
63000a2430fSAndrzej Pietrasiewicz 
63100a2430fSAndrzej Pietrasiewicz /* "Normal" endpoints operations ********************************************/
63200a2430fSAndrzej Pietrasiewicz 
63300a2430fSAndrzej Pietrasiewicz static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
63400a2430fSAndrzej Pietrasiewicz {
63500a2430fSAndrzej Pietrasiewicz 	ENTER();
63600a2430fSAndrzej Pietrasiewicz 	if (likely(req->context)) {
63700a2430fSAndrzej Pietrasiewicz 		struct ffs_ep *ep = _ep->driver_data;
63800a2430fSAndrzej Pietrasiewicz 		ep->status = req->status ? req->status : req->actual;
63900a2430fSAndrzej Pietrasiewicz 		complete(req->context);
64000a2430fSAndrzej Pietrasiewicz 	}
64100a2430fSAndrzej Pietrasiewicz }
64200a2430fSAndrzej Pietrasiewicz 
64300a2430fSAndrzej Pietrasiewicz static void ffs_user_copy_worker(struct work_struct *work)
64400a2430fSAndrzej Pietrasiewicz {
64500a2430fSAndrzej Pietrasiewicz 	struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
64600a2430fSAndrzej Pietrasiewicz 						   work);
64700a2430fSAndrzej Pietrasiewicz 	int ret = io_data->req->status ? io_data->req->status :
64800a2430fSAndrzej Pietrasiewicz 					 io_data->req->actual;
64900a2430fSAndrzej Pietrasiewicz 
65000a2430fSAndrzej Pietrasiewicz 	if (io_data->read && ret > 0) {
65100a2430fSAndrzej Pietrasiewicz 		use_mm(io_data->mm);
652c993c39bSAl Viro 		ret = copy_to_iter(io_data->buf, ret, &io_data->data);
653c993c39bSAl Viro 		if (iov_iter_count(&io_data->data))
65400a2430fSAndrzej Pietrasiewicz 			ret = -EFAULT;
65500a2430fSAndrzej Pietrasiewicz 		unuse_mm(io_data->mm);
65600a2430fSAndrzej Pietrasiewicz 	}
65700a2430fSAndrzej Pietrasiewicz 
65804b2fa9fSChristoph Hellwig 	io_data->kiocb->ki_complete(io_data->kiocb, ret, ret);
65900a2430fSAndrzej Pietrasiewicz 
66004b2fa9fSChristoph Hellwig 	if (io_data->ffs->ffs_eventfd &&
66104b2fa9fSChristoph Hellwig 	    !(io_data->kiocb->ki_flags & IOCB_EVENTFD))
6625e33f6fdSRobert Baldyga 		eventfd_signal(io_data->ffs->ffs_eventfd, 1);
6635e33f6fdSRobert Baldyga 
66400a2430fSAndrzej Pietrasiewicz 	usb_ep_free_request(io_data->ep, io_data->req);
66500a2430fSAndrzej Pietrasiewicz 
66600a2430fSAndrzej Pietrasiewicz 	io_data->kiocb->private = NULL;
66700a2430fSAndrzej Pietrasiewicz 	if (io_data->read)
668c993c39bSAl Viro 		kfree(io_data->to_free);
66900a2430fSAndrzej Pietrasiewicz 	kfree(io_data->buf);
67000a2430fSAndrzej Pietrasiewicz 	kfree(io_data);
67100a2430fSAndrzej Pietrasiewicz }
67200a2430fSAndrzej Pietrasiewicz 
67300a2430fSAndrzej Pietrasiewicz static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
67400a2430fSAndrzej Pietrasiewicz 					 struct usb_request *req)
67500a2430fSAndrzej Pietrasiewicz {
67600a2430fSAndrzej Pietrasiewicz 	struct ffs_io_data *io_data = req->context;
67700a2430fSAndrzej Pietrasiewicz 
67800a2430fSAndrzej Pietrasiewicz 	ENTER();
67900a2430fSAndrzej Pietrasiewicz 
68000a2430fSAndrzej Pietrasiewicz 	INIT_WORK(&io_data->work, ffs_user_copy_worker);
68100a2430fSAndrzej Pietrasiewicz 	schedule_work(&io_data->work);
68200a2430fSAndrzej Pietrasiewicz }
68300a2430fSAndrzej Pietrasiewicz 
68400a2430fSAndrzej Pietrasiewicz static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
68500a2430fSAndrzej Pietrasiewicz {
68600a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = file->private_data;
68700a2430fSAndrzej Pietrasiewicz 	struct ffs_ep *ep;
68800a2430fSAndrzej Pietrasiewicz 	char *data = NULL;
689c0d31b3cSDavid Cohen 	ssize_t ret, data_len = -EINVAL;
69000a2430fSAndrzej Pietrasiewicz 	int halt;
69100a2430fSAndrzej Pietrasiewicz 
69200a2430fSAndrzej Pietrasiewicz 	/* Are we still active? */
693b3591f67SMichal Nazarewicz 	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
694b3591f67SMichal Nazarewicz 		return -ENODEV;
69500a2430fSAndrzej Pietrasiewicz 
69600a2430fSAndrzej Pietrasiewicz 	/* Wait for endpoint to be enabled */
69700a2430fSAndrzej Pietrasiewicz 	ep = epfile->ep;
69800a2430fSAndrzej Pietrasiewicz 	if (!ep) {
699b3591f67SMichal Nazarewicz 		if (file->f_flags & O_NONBLOCK)
700b3591f67SMichal Nazarewicz 			return -EAGAIN;
70100a2430fSAndrzej Pietrasiewicz 
70200a2430fSAndrzej Pietrasiewicz 		ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep));
703b3591f67SMichal Nazarewicz 		if (ret)
704b3591f67SMichal Nazarewicz 			return -EINTR;
70500a2430fSAndrzej Pietrasiewicz 	}
70600a2430fSAndrzej Pietrasiewicz 
70700a2430fSAndrzej Pietrasiewicz 	/* Do we halt? */
70800a2430fSAndrzej Pietrasiewicz 	halt = (!io_data->read == !epfile->in);
709b3591f67SMichal Nazarewicz 	if (halt && epfile->isoc)
710b3591f67SMichal Nazarewicz 		return -EINVAL;
71100a2430fSAndrzej Pietrasiewicz 
71200a2430fSAndrzej Pietrasiewicz 	/* Allocate & copy */
71300a2430fSAndrzej Pietrasiewicz 	if (!halt) {
71400a2430fSAndrzej Pietrasiewicz 		/*
71500a2430fSAndrzej Pietrasiewicz 		 * if we _do_ wait above, the epfile->ffs->gadget might be NULL
71600a2430fSAndrzej Pietrasiewicz 		 * before the waiting completes, so do not assign to 'gadget' earlier
71700a2430fSAndrzej Pietrasiewicz 		 */
71800a2430fSAndrzej Pietrasiewicz 		struct usb_gadget *gadget = epfile->ffs->gadget;
719c993c39bSAl Viro 		size_t copied;
72000a2430fSAndrzej Pietrasiewicz 
72100a2430fSAndrzej Pietrasiewicz 		spin_lock_irq(&epfile->ffs->eps_lock);
72200a2430fSAndrzej Pietrasiewicz 		/* In the meantime, endpoint got disabled or changed. */
72300a2430fSAndrzej Pietrasiewicz 		if (epfile->ep != ep) {
72400a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&epfile->ffs->eps_lock);
72500a2430fSAndrzej Pietrasiewicz 			return -ESHUTDOWN;
72600a2430fSAndrzej Pietrasiewicz 		}
727c993c39bSAl Viro 		data_len = iov_iter_count(&io_data->data);
72800a2430fSAndrzej Pietrasiewicz 		/*
72900a2430fSAndrzej Pietrasiewicz 		 * Controller may require buffer size to be aligned to
73000a2430fSAndrzej Pietrasiewicz 		 * maxpacketsize of an out endpoint.
73100a2430fSAndrzej Pietrasiewicz 		 */
732c993c39bSAl Viro 		if (io_data->read)
733c993c39bSAl Viro 			data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
73400a2430fSAndrzej Pietrasiewicz 		spin_unlock_irq(&epfile->ffs->eps_lock);
73500a2430fSAndrzej Pietrasiewicz 
73600a2430fSAndrzej Pietrasiewicz 		data = kmalloc(data_len, GFP_KERNEL);
73700a2430fSAndrzej Pietrasiewicz 		if (unlikely(!data))
73800a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
739c993c39bSAl Viro 		if (!io_data->read) {
740c993c39bSAl Viro 			copied = copy_from_iter(data, data_len, &io_data->data);
741c993c39bSAl Viro 			if (copied != data_len) {
74200a2430fSAndrzej Pietrasiewicz 				ret = -EFAULT;
74300a2430fSAndrzej Pietrasiewicz 				goto error;
74400a2430fSAndrzej Pietrasiewicz 			}
74500a2430fSAndrzej Pietrasiewicz 		}
74600a2430fSAndrzej Pietrasiewicz 	}
74700a2430fSAndrzej Pietrasiewicz 
74800a2430fSAndrzej Pietrasiewicz 	/* We will be using request */
74900a2430fSAndrzej Pietrasiewicz 	ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
75000a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret))
75100a2430fSAndrzej Pietrasiewicz 		goto error;
75200a2430fSAndrzej Pietrasiewicz 
75300a2430fSAndrzej Pietrasiewicz 	spin_lock_irq(&epfile->ffs->eps_lock);
75400a2430fSAndrzej Pietrasiewicz 
75500a2430fSAndrzej Pietrasiewicz 	if (epfile->ep != ep) {
75600a2430fSAndrzej Pietrasiewicz 		/* In the meantime, endpoint got disabled or changed. */
75700a2430fSAndrzej Pietrasiewicz 		ret = -ESHUTDOWN;
7583de4e205SMichal Nazarewicz 		goto error_lock;
75900a2430fSAndrzej Pietrasiewicz 	} else if (halt) {
76000a2430fSAndrzej Pietrasiewicz 		/* Halt */
76100a2430fSAndrzej Pietrasiewicz 		if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
76200a2430fSAndrzej Pietrasiewicz 			usb_ep_set_halt(ep->ep);
76300a2430fSAndrzej Pietrasiewicz 		spin_unlock_irq(&epfile->ffs->eps_lock);
76400a2430fSAndrzej Pietrasiewicz 		ret = -EBADMSG;
76500a2430fSAndrzej Pietrasiewicz 	} else {
76600a2430fSAndrzej Pietrasiewicz 		/* Fire the request */
76700a2430fSAndrzej Pietrasiewicz 		struct usb_request *req;
76800a2430fSAndrzej Pietrasiewicz 
769c0d31b3cSDavid Cohen 		/*
770c0d31b3cSDavid Cohen 		 * Sanity Check: even though data_len can't be used
771c0d31b3cSDavid Cohen 		 * uninitialized at the time I write this comment, some
772c0d31b3cSDavid Cohen 		 * compilers complain about this situation.
773c0d31b3cSDavid Cohen 		 * In order to keep the code clean from warnings, data_len is
774c0d31b3cSDavid Cohen 		 * being initialized to -EINVAL during its declaration, which
775c0d31b3cSDavid Cohen 		 * means we can't rely on compiler anymore to warn no future
776c0d31b3cSDavid Cohen 		 * changes won't result in data_len being used uninitialized.
777c0d31b3cSDavid Cohen 		 * For such reason, we're adding this redundant sanity check
778c0d31b3cSDavid Cohen 		 * here.
779c0d31b3cSDavid Cohen 		 */
780c0d31b3cSDavid Cohen 		if (unlikely(data_len == -EINVAL)) {
781c0d31b3cSDavid Cohen 			WARN(1, "%s: data_len == -EINVAL\n", __func__);
782c0d31b3cSDavid Cohen 			ret = -EINVAL;
783c0d31b3cSDavid Cohen 			goto error_lock;
784c0d31b3cSDavid Cohen 		}
785c0d31b3cSDavid Cohen 
78600a2430fSAndrzej Pietrasiewicz 		if (io_data->aio) {
78700a2430fSAndrzej Pietrasiewicz 			req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
7883163c79eSMichal Nazarewicz 			if (unlikely(!req)) {
7893163c79eSMichal Nazarewicz 				ret = -ENOMEM;
79000a2430fSAndrzej Pietrasiewicz 				goto error_lock;
7913163c79eSMichal Nazarewicz 			}
79200a2430fSAndrzej Pietrasiewicz 
79300a2430fSAndrzej Pietrasiewicz 			req->buf      = data;
794c0d31b3cSDavid Cohen 			req->length   = data_len;
79500a2430fSAndrzej Pietrasiewicz 
79600a2430fSAndrzej Pietrasiewicz 			io_data->buf = data;
79700a2430fSAndrzej Pietrasiewicz 			io_data->ep = ep->ep;
79800a2430fSAndrzej Pietrasiewicz 			io_data->req = req;
7995e33f6fdSRobert Baldyga 			io_data->ffs = epfile->ffs;
80000a2430fSAndrzej Pietrasiewicz 
80100a2430fSAndrzej Pietrasiewicz 			req->context  = io_data;
80200a2430fSAndrzej Pietrasiewicz 			req->complete = ffs_epfile_async_io_complete;
80300a2430fSAndrzej Pietrasiewicz 
80400a2430fSAndrzej Pietrasiewicz 			ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
80500a2430fSAndrzej Pietrasiewicz 			if (unlikely(ret)) {
80600a2430fSAndrzej Pietrasiewicz 				usb_ep_free_request(ep->ep, req);
80700a2430fSAndrzej Pietrasiewicz 				goto error_lock;
80800a2430fSAndrzej Pietrasiewicz 			}
80900a2430fSAndrzej Pietrasiewicz 			ret = -EIOCBQUEUED;
81000a2430fSAndrzej Pietrasiewicz 
81100a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&epfile->ffs->eps_lock);
81200a2430fSAndrzej Pietrasiewicz 		} else {
81300a2430fSAndrzej Pietrasiewicz 			DECLARE_COMPLETION_ONSTACK(done);
81400a2430fSAndrzej Pietrasiewicz 
81500a2430fSAndrzej Pietrasiewicz 			req = ep->req;
81600a2430fSAndrzej Pietrasiewicz 			req->buf      = data;
817c0d31b3cSDavid Cohen 			req->length   = data_len;
81800a2430fSAndrzej Pietrasiewicz 
81900a2430fSAndrzej Pietrasiewicz 			req->context  = &done;
82000a2430fSAndrzej Pietrasiewicz 			req->complete = ffs_epfile_io_complete;
82100a2430fSAndrzej Pietrasiewicz 
82200a2430fSAndrzej Pietrasiewicz 			ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
82300a2430fSAndrzej Pietrasiewicz 
82400a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&epfile->ffs->eps_lock);
82500a2430fSAndrzej Pietrasiewicz 
82600a2430fSAndrzej Pietrasiewicz 			if (unlikely(ret < 0)) {
82700a2430fSAndrzej Pietrasiewicz 				/* nop */
82800a2430fSAndrzej Pietrasiewicz 			} else if (unlikely(
82900a2430fSAndrzej Pietrasiewicz 				   wait_for_completion_interruptible(&done))) {
83000a2430fSAndrzej Pietrasiewicz 				ret = -EINTR;
83100a2430fSAndrzej Pietrasiewicz 				usb_ep_dequeue(ep->ep, req);
83200a2430fSAndrzej Pietrasiewicz 			} else {
83300a2430fSAndrzej Pietrasiewicz 				/*
83400a2430fSAndrzej Pietrasiewicz 				 * XXX We may end up silently droping data
83500a2430fSAndrzej Pietrasiewicz 				 * here.  Since data_len (i.e. req->length) may
83600a2430fSAndrzej Pietrasiewicz 				 * be bigger than len (after being rounded up
83700a2430fSAndrzej Pietrasiewicz 				 * to maxpacketsize), we may end up with more
83800a2430fSAndrzej Pietrasiewicz 				 * data then user space has space for.
83900a2430fSAndrzej Pietrasiewicz 				 */
84000a2430fSAndrzej Pietrasiewicz 				ret = ep->status;
84100a2430fSAndrzej Pietrasiewicz 				if (io_data->read && ret > 0) {
842c993c39bSAl Viro 					ret = copy_to_iter(data, ret, &io_data->data);
843342f39a6SRui Miguel Silva 					if (!ret)
84400a2430fSAndrzej Pietrasiewicz 						ret = -EFAULT;
84500a2430fSAndrzej Pietrasiewicz 				}
84600a2430fSAndrzej Pietrasiewicz 			}
84700a2430fSAndrzej Pietrasiewicz 			kfree(data);
84800a2430fSAndrzej Pietrasiewicz 		}
84900a2430fSAndrzej Pietrasiewicz 	}
85000a2430fSAndrzej Pietrasiewicz 
85100a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&epfile->mutex);
85200a2430fSAndrzej Pietrasiewicz 	return ret;
85300a2430fSAndrzej Pietrasiewicz 
85400a2430fSAndrzej Pietrasiewicz error_lock:
85500a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&epfile->ffs->eps_lock);
85600a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&epfile->mutex);
85700a2430fSAndrzej Pietrasiewicz error:
85800a2430fSAndrzej Pietrasiewicz 	kfree(data);
85900a2430fSAndrzej Pietrasiewicz 	return ret;
86000a2430fSAndrzej Pietrasiewicz }
86100a2430fSAndrzej Pietrasiewicz 
86200a2430fSAndrzej Pietrasiewicz static int
86300a2430fSAndrzej Pietrasiewicz ffs_epfile_open(struct inode *inode, struct file *file)
86400a2430fSAndrzej Pietrasiewicz {
86500a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = inode->i_private;
86600a2430fSAndrzej Pietrasiewicz 
86700a2430fSAndrzej Pietrasiewicz 	ENTER();
86800a2430fSAndrzej Pietrasiewicz 
86900a2430fSAndrzej Pietrasiewicz 	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
87000a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
87100a2430fSAndrzej Pietrasiewicz 
87200a2430fSAndrzej Pietrasiewicz 	file->private_data = epfile;
87300a2430fSAndrzej Pietrasiewicz 	ffs_data_opened(epfile->ffs);
87400a2430fSAndrzej Pietrasiewicz 
87500a2430fSAndrzej Pietrasiewicz 	return 0;
87600a2430fSAndrzej Pietrasiewicz }
87700a2430fSAndrzej Pietrasiewicz 
87800a2430fSAndrzej Pietrasiewicz static int ffs_aio_cancel(struct kiocb *kiocb)
87900a2430fSAndrzej Pietrasiewicz {
88000a2430fSAndrzej Pietrasiewicz 	struct ffs_io_data *io_data = kiocb->private;
88100a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = kiocb->ki_filp->private_data;
88200a2430fSAndrzej Pietrasiewicz 	int value;
88300a2430fSAndrzej Pietrasiewicz 
88400a2430fSAndrzej Pietrasiewicz 	ENTER();
88500a2430fSAndrzej Pietrasiewicz 
88600a2430fSAndrzej Pietrasiewicz 	spin_lock_irq(&epfile->ffs->eps_lock);
88700a2430fSAndrzej Pietrasiewicz 
88800a2430fSAndrzej Pietrasiewicz 	if (likely(io_data && io_data->ep && io_data->req))
88900a2430fSAndrzej Pietrasiewicz 		value = usb_ep_dequeue(io_data->ep, io_data->req);
89000a2430fSAndrzej Pietrasiewicz 	else
89100a2430fSAndrzej Pietrasiewicz 		value = -EINVAL;
89200a2430fSAndrzej Pietrasiewicz 
89300a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&epfile->ffs->eps_lock);
89400a2430fSAndrzej Pietrasiewicz 
89500a2430fSAndrzej Pietrasiewicz 	return value;
89600a2430fSAndrzej Pietrasiewicz }
89700a2430fSAndrzej Pietrasiewicz 
89870e60d91SAl Viro static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
89900a2430fSAndrzej Pietrasiewicz {
90070e60d91SAl Viro 	struct ffs_io_data io_data, *p = &io_data;
901de2080d4SAl Viro 	ssize_t res;
90200a2430fSAndrzej Pietrasiewicz 
90300a2430fSAndrzej Pietrasiewicz 	ENTER();
90400a2430fSAndrzej Pietrasiewicz 
90570e60d91SAl Viro 	if (!is_sync_kiocb(kiocb)) {
90670e60d91SAl Viro 		p = kmalloc(sizeof(io_data), GFP_KERNEL);
90770e60d91SAl Viro 		if (unlikely(!p))
90800a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
90970e60d91SAl Viro 		p->aio = true;
91070e60d91SAl Viro 	} else {
91170e60d91SAl Viro 		p->aio = false;
91270e60d91SAl Viro 	}
91300a2430fSAndrzej Pietrasiewicz 
91470e60d91SAl Viro 	p->read = false;
91570e60d91SAl Viro 	p->kiocb = kiocb;
91670e60d91SAl Viro 	p->data = *from;
91770e60d91SAl Viro 	p->mm = current->mm;
91800a2430fSAndrzej Pietrasiewicz 
91970e60d91SAl Viro 	kiocb->private = p;
92000a2430fSAndrzej Pietrasiewicz 
9214088acf1SRui Miguel Silva 	if (p->aio)
92200a2430fSAndrzej Pietrasiewicz 		kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
92300a2430fSAndrzej Pietrasiewicz 
92470e60d91SAl Viro 	res = ffs_epfile_io(kiocb->ki_filp, p);
92570e60d91SAl Viro 	if (res == -EIOCBQUEUED)
92670e60d91SAl Viro 		return res;
92770e60d91SAl Viro 	if (p->aio)
92870e60d91SAl Viro 		kfree(p);
92970e60d91SAl Viro 	else
93070e60d91SAl Viro 		*from = p->data;
931de2080d4SAl Viro 	return res;
93200a2430fSAndrzej Pietrasiewicz }
93300a2430fSAndrzej Pietrasiewicz 
93470e60d91SAl Viro static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
93500a2430fSAndrzej Pietrasiewicz {
93670e60d91SAl Viro 	struct ffs_io_data io_data, *p = &io_data;
937de2080d4SAl Viro 	ssize_t res;
93800a2430fSAndrzej Pietrasiewicz 
93900a2430fSAndrzej Pietrasiewicz 	ENTER();
94000a2430fSAndrzej Pietrasiewicz 
94170e60d91SAl Viro 	if (!is_sync_kiocb(kiocb)) {
94270e60d91SAl Viro 		p = kmalloc(sizeof(io_data), GFP_KERNEL);
94370e60d91SAl Viro 		if (unlikely(!p))
94400a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
94570e60d91SAl Viro 		p->aio = true;
94670e60d91SAl Viro 	} else {
94770e60d91SAl Viro 		p->aio = false;
94800a2430fSAndrzej Pietrasiewicz 	}
94900a2430fSAndrzej Pietrasiewicz 
95070e60d91SAl Viro 	p->read = true;
95170e60d91SAl Viro 	p->kiocb = kiocb;
95270e60d91SAl Viro 	if (p->aio) {
95370e60d91SAl Viro 		p->to_free = dup_iter(&p->data, to, GFP_KERNEL);
95470e60d91SAl Viro 		if (!p->to_free) {
95570e60d91SAl Viro 			kfree(p);
95670e60d91SAl Viro 			return -ENOMEM;
95770e60d91SAl Viro 		}
95870e60d91SAl Viro 	} else {
95970e60d91SAl Viro 		p->data = *to;
96070e60d91SAl Viro 		p->to_free = NULL;
96170e60d91SAl Viro 	}
96270e60d91SAl Viro 	p->mm = current->mm;
96300a2430fSAndrzej Pietrasiewicz 
96470e60d91SAl Viro 	kiocb->private = p;
96500a2430fSAndrzej Pietrasiewicz 
9664088acf1SRui Miguel Silva 	if (p->aio)
96700a2430fSAndrzej Pietrasiewicz 		kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
96800a2430fSAndrzej Pietrasiewicz 
96970e60d91SAl Viro 	res = ffs_epfile_io(kiocb->ki_filp, p);
97070e60d91SAl Viro 	if (res == -EIOCBQUEUED)
97170e60d91SAl Viro 		return res;
97270e60d91SAl Viro 
97370e60d91SAl Viro 	if (p->aio) {
97470e60d91SAl Viro 		kfree(p->to_free);
97570e60d91SAl Viro 		kfree(p);
97670e60d91SAl Viro 	} else {
97770e60d91SAl Viro 		*to = p->data;
978de2080d4SAl Viro 	}
979de2080d4SAl Viro 	return res;
98000a2430fSAndrzej Pietrasiewicz }
98100a2430fSAndrzej Pietrasiewicz 
98200a2430fSAndrzej Pietrasiewicz static int
98300a2430fSAndrzej Pietrasiewicz ffs_epfile_release(struct inode *inode, struct file *file)
98400a2430fSAndrzej Pietrasiewicz {
98500a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = inode->i_private;
98600a2430fSAndrzej Pietrasiewicz 
98700a2430fSAndrzej Pietrasiewicz 	ENTER();
98800a2430fSAndrzej Pietrasiewicz 
98900a2430fSAndrzej Pietrasiewicz 	ffs_data_closed(epfile->ffs);
99000a2430fSAndrzej Pietrasiewicz 
99100a2430fSAndrzej Pietrasiewicz 	return 0;
99200a2430fSAndrzej Pietrasiewicz }
99300a2430fSAndrzej Pietrasiewicz 
99400a2430fSAndrzej Pietrasiewicz static long ffs_epfile_ioctl(struct file *file, unsigned code,
99500a2430fSAndrzej Pietrasiewicz 			     unsigned long value)
99600a2430fSAndrzej Pietrasiewicz {
99700a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = file->private_data;
99800a2430fSAndrzej Pietrasiewicz 	int ret;
99900a2430fSAndrzej Pietrasiewicz 
100000a2430fSAndrzej Pietrasiewicz 	ENTER();
100100a2430fSAndrzej Pietrasiewicz 
100200a2430fSAndrzej Pietrasiewicz 	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
100300a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
100400a2430fSAndrzej Pietrasiewicz 
100500a2430fSAndrzej Pietrasiewicz 	spin_lock_irq(&epfile->ffs->eps_lock);
100600a2430fSAndrzej Pietrasiewicz 	if (likely(epfile->ep)) {
100700a2430fSAndrzej Pietrasiewicz 		switch (code) {
100800a2430fSAndrzej Pietrasiewicz 		case FUNCTIONFS_FIFO_STATUS:
100900a2430fSAndrzej Pietrasiewicz 			ret = usb_ep_fifo_status(epfile->ep->ep);
101000a2430fSAndrzej Pietrasiewicz 			break;
101100a2430fSAndrzej Pietrasiewicz 		case FUNCTIONFS_FIFO_FLUSH:
101200a2430fSAndrzej Pietrasiewicz 			usb_ep_fifo_flush(epfile->ep->ep);
101300a2430fSAndrzej Pietrasiewicz 			ret = 0;
101400a2430fSAndrzej Pietrasiewicz 			break;
101500a2430fSAndrzej Pietrasiewicz 		case FUNCTIONFS_CLEAR_HALT:
101600a2430fSAndrzej Pietrasiewicz 			ret = usb_ep_clear_halt(epfile->ep->ep);
101700a2430fSAndrzej Pietrasiewicz 			break;
101800a2430fSAndrzej Pietrasiewicz 		case FUNCTIONFS_ENDPOINT_REVMAP:
101900a2430fSAndrzej Pietrasiewicz 			ret = epfile->ep->num;
102000a2430fSAndrzej Pietrasiewicz 			break;
1021c559a353SRobert Baldyga 		case FUNCTIONFS_ENDPOINT_DESC:
1022c559a353SRobert Baldyga 		{
1023c559a353SRobert Baldyga 			int desc_idx;
1024c559a353SRobert Baldyga 			struct usb_endpoint_descriptor *desc;
1025c559a353SRobert Baldyga 
1026c559a353SRobert Baldyga 			switch (epfile->ffs->gadget->speed) {
1027c559a353SRobert Baldyga 			case USB_SPEED_SUPER:
1028c559a353SRobert Baldyga 				desc_idx = 2;
1029c559a353SRobert Baldyga 				break;
1030c559a353SRobert Baldyga 			case USB_SPEED_HIGH:
1031c559a353SRobert Baldyga 				desc_idx = 1;
1032c559a353SRobert Baldyga 				break;
1033c559a353SRobert Baldyga 			default:
1034c559a353SRobert Baldyga 				desc_idx = 0;
1035c559a353SRobert Baldyga 			}
1036c559a353SRobert Baldyga 			desc = epfile->ep->descs[desc_idx];
1037c559a353SRobert Baldyga 
1038c559a353SRobert Baldyga 			spin_unlock_irq(&epfile->ffs->eps_lock);
1039c559a353SRobert Baldyga 			ret = copy_to_user((void *)value, desc, sizeof(*desc));
1040c559a353SRobert Baldyga 			if (ret)
1041c559a353SRobert Baldyga 				ret = -EFAULT;
1042c559a353SRobert Baldyga 			return ret;
1043c559a353SRobert Baldyga 		}
104400a2430fSAndrzej Pietrasiewicz 		default:
104500a2430fSAndrzej Pietrasiewicz 			ret = -ENOTTY;
104600a2430fSAndrzej Pietrasiewicz 		}
104700a2430fSAndrzej Pietrasiewicz 	} else {
104800a2430fSAndrzej Pietrasiewicz 		ret = -ENODEV;
104900a2430fSAndrzej Pietrasiewicz 	}
105000a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&epfile->ffs->eps_lock);
105100a2430fSAndrzej Pietrasiewicz 
105200a2430fSAndrzej Pietrasiewicz 	return ret;
105300a2430fSAndrzej Pietrasiewicz }
105400a2430fSAndrzej Pietrasiewicz 
105500a2430fSAndrzej Pietrasiewicz static const struct file_operations ffs_epfile_operations = {
105600a2430fSAndrzej Pietrasiewicz 	.llseek =	no_llseek,
105700a2430fSAndrzej Pietrasiewicz 
105800a2430fSAndrzej Pietrasiewicz 	.open =		ffs_epfile_open,
105970e60d91SAl Viro 	.write_iter =	ffs_epfile_write_iter,
106070e60d91SAl Viro 	.read_iter =	ffs_epfile_read_iter,
106100a2430fSAndrzej Pietrasiewicz 	.release =	ffs_epfile_release,
106200a2430fSAndrzej Pietrasiewicz 	.unlocked_ioctl =	ffs_epfile_ioctl,
106300a2430fSAndrzej Pietrasiewicz };
106400a2430fSAndrzej Pietrasiewicz 
106500a2430fSAndrzej Pietrasiewicz 
106600a2430fSAndrzej Pietrasiewicz /* File system and super block operations ***********************************/
106700a2430fSAndrzej Pietrasiewicz 
106800a2430fSAndrzej Pietrasiewicz /*
106900a2430fSAndrzej Pietrasiewicz  * Mounting the file system creates a controller file, used first for
107000a2430fSAndrzej Pietrasiewicz  * function configuration then later for event monitoring.
107100a2430fSAndrzej Pietrasiewicz  */
107200a2430fSAndrzej Pietrasiewicz 
107300a2430fSAndrzej Pietrasiewicz static struct inode *__must_check
107400a2430fSAndrzej Pietrasiewicz ffs_sb_make_inode(struct super_block *sb, void *data,
107500a2430fSAndrzej Pietrasiewicz 		  const struct file_operations *fops,
107600a2430fSAndrzej Pietrasiewicz 		  const struct inode_operations *iops,
107700a2430fSAndrzej Pietrasiewicz 		  struct ffs_file_perms *perms)
107800a2430fSAndrzej Pietrasiewicz {
107900a2430fSAndrzej Pietrasiewicz 	struct inode *inode;
108000a2430fSAndrzej Pietrasiewicz 
108100a2430fSAndrzej Pietrasiewicz 	ENTER();
108200a2430fSAndrzej Pietrasiewicz 
108300a2430fSAndrzej Pietrasiewicz 	inode = new_inode(sb);
108400a2430fSAndrzej Pietrasiewicz 
108500a2430fSAndrzej Pietrasiewicz 	if (likely(inode)) {
108600a2430fSAndrzej Pietrasiewicz 		struct timespec current_time = CURRENT_TIME;
108700a2430fSAndrzej Pietrasiewicz 
108800a2430fSAndrzej Pietrasiewicz 		inode->i_ino	 = get_next_ino();
108900a2430fSAndrzej Pietrasiewicz 		inode->i_mode    = perms->mode;
109000a2430fSAndrzej Pietrasiewicz 		inode->i_uid     = perms->uid;
109100a2430fSAndrzej Pietrasiewicz 		inode->i_gid     = perms->gid;
109200a2430fSAndrzej Pietrasiewicz 		inode->i_atime   = current_time;
109300a2430fSAndrzej Pietrasiewicz 		inode->i_mtime   = current_time;
109400a2430fSAndrzej Pietrasiewicz 		inode->i_ctime   = current_time;
109500a2430fSAndrzej Pietrasiewicz 		inode->i_private = data;
109600a2430fSAndrzej Pietrasiewicz 		if (fops)
109700a2430fSAndrzej Pietrasiewicz 			inode->i_fop = fops;
109800a2430fSAndrzej Pietrasiewicz 		if (iops)
109900a2430fSAndrzej Pietrasiewicz 			inode->i_op  = iops;
110000a2430fSAndrzej Pietrasiewicz 	}
110100a2430fSAndrzej Pietrasiewicz 
110200a2430fSAndrzej Pietrasiewicz 	return inode;
110300a2430fSAndrzej Pietrasiewicz }
110400a2430fSAndrzej Pietrasiewicz 
110500a2430fSAndrzej Pietrasiewicz /* Create "regular" file */
11061bb27cacSAl Viro static struct dentry *ffs_sb_create_file(struct super_block *sb,
110700a2430fSAndrzej Pietrasiewicz 					const char *name, void *data,
11081bb27cacSAl Viro 					const struct file_operations *fops)
110900a2430fSAndrzej Pietrasiewicz {
111000a2430fSAndrzej Pietrasiewicz 	struct ffs_data	*ffs = sb->s_fs_info;
111100a2430fSAndrzej Pietrasiewicz 	struct dentry	*dentry;
111200a2430fSAndrzej Pietrasiewicz 	struct inode	*inode;
111300a2430fSAndrzej Pietrasiewicz 
111400a2430fSAndrzej Pietrasiewicz 	ENTER();
111500a2430fSAndrzej Pietrasiewicz 
111600a2430fSAndrzej Pietrasiewicz 	dentry = d_alloc_name(sb->s_root, name);
111700a2430fSAndrzej Pietrasiewicz 	if (unlikely(!dentry))
111800a2430fSAndrzej Pietrasiewicz 		return NULL;
111900a2430fSAndrzej Pietrasiewicz 
112000a2430fSAndrzej Pietrasiewicz 	inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
112100a2430fSAndrzej Pietrasiewicz 	if (unlikely(!inode)) {
112200a2430fSAndrzej Pietrasiewicz 		dput(dentry);
112300a2430fSAndrzej Pietrasiewicz 		return NULL;
112400a2430fSAndrzej Pietrasiewicz 	}
112500a2430fSAndrzej Pietrasiewicz 
112600a2430fSAndrzej Pietrasiewicz 	d_add(dentry, inode);
11271bb27cacSAl Viro 	return dentry;
112800a2430fSAndrzej Pietrasiewicz }
112900a2430fSAndrzej Pietrasiewicz 
113000a2430fSAndrzej Pietrasiewicz /* Super block */
113100a2430fSAndrzej Pietrasiewicz static const struct super_operations ffs_sb_operations = {
113200a2430fSAndrzej Pietrasiewicz 	.statfs =	simple_statfs,
113300a2430fSAndrzej Pietrasiewicz 	.drop_inode =	generic_delete_inode,
113400a2430fSAndrzej Pietrasiewicz };
113500a2430fSAndrzej Pietrasiewicz 
113600a2430fSAndrzej Pietrasiewicz struct ffs_sb_fill_data {
113700a2430fSAndrzej Pietrasiewicz 	struct ffs_file_perms perms;
113800a2430fSAndrzej Pietrasiewicz 	umode_t root_mode;
113900a2430fSAndrzej Pietrasiewicz 	const char *dev_name;
114018d6b32fSRobert Baldyga 	bool no_disconnect;
114100a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs_data;
114200a2430fSAndrzej Pietrasiewicz };
114300a2430fSAndrzej Pietrasiewicz 
114400a2430fSAndrzej Pietrasiewicz static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
114500a2430fSAndrzej Pietrasiewicz {
114600a2430fSAndrzej Pietrasiewicz 	struct ffs_sb_fill_data *data = _data;
114700a2430fSAndrzej Pietrasiewicz 	struct inode	*inode;
114800a2430fSAndrzej Pietrasiewicz 	struct ffs_data	*ffs = data->ffs_data;
114900a2430fSAndrzej Pietrasiewicz 
115000a2430fSAndrzej Pietrasiewicz 	ENTER();
115100a2430fSAndrzej Pietrasiewicz 
115200a2430fSAndrzej Pietrasiewicz 	ffs->sb              = sb;
115300a2430fSAndrzej Pietrasiewicz 	data->ffs_data       = NULL;
115400a2430fSAndrzej Pietrasiewicz 	sb->s_fs_info        = ffs;
115500a2430fSAndrzej Pietrasiewicz 	sb->s_blocksize      = PAGE_CACHE_SIZE;
115600a2430fSAndrzej Pietrasiewicz 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
115700a2430fSAndrzej Pietrasiewicz 	sb->s_magic          = FUNCTIONFS_MAGIC;
115800a2430fSAndrzej Pietrasiewicz 	sb->s_op             = &ffs_sb_operations;
115900a2430fSAndrzej Pietrasiewicz 	sb->s_time_gran      = 1;
116000a2430fSAndrzej Pietrasiewicz 
116100a2430fSAndrzej Pietrasiewicz 	/* Root inode */
116200a2430fSAndrzej Pietrasiewicz 	data->perms.mode = data->root_mode;
116300a2430fSAndrzej Pietrasiewicz 	inode = ffs_sb_make_inode(sb, NULL,
116400a2430fSAndrzej Pietrasiewicz 				  &simple_dir_operations,
116500a2430fSAndrzej Pietrasiewicz 				  &simple_dir_inode_operations,
116600a2430fSAndrzej Pietrasiewicz 				  &data->perms);
116700a2430fSAndrzej Pietrasiewicz 	sb->s_root = d_make_root(inode);
116800a2430fSAndrzej Pietrasiewicz 	if (unlikely(!sb->s_root))
116900a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
117000a2430fSAndrzej Pietrasiewicz 
117100a2430fSAndrzej Pietrasiewicz 	/* EP0 file */
117200a2430fSAndrzej Pietrasiewicz 	if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
11731bb27cacSAl Viro 					 &ffs_ep0_operations)))
117400a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
117500a2430fSAndrzej Pietrasiewicz 
117600a2430fSAndrzej Pietrasiewicz 	return 0;
117700a2430fSAndrzej Pietrasiewicz }
117800a2430fSAndrzej Pietrasiewicz 
117900a2430fSAndrzej Pietrasiewicz static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
118000a2430fSAndrzej Pietrasiewicz {
118100a2430fSAndrzej Pietrasiewicz 	ENTER();
118200a2430fSAndrzej Pietrasiewicz 
118300a2430fSAndrzej Pietrasiewicz 	if (!opts || !*opts)
118400a2430fSAndrzej Pietrasiewicz 		return 0;
118500a2430fSAndrzej Pietrasiewicz 
118600a2430fSAndrzej Pietrasiewicz 	for (;;) {
118700a2430fSAndrzej Pietrasiewicz 		unsigned long value;
118800a2430fSAndrzej Pietrasiewicz 		char *eq, *comma;
118900a2430fSAndrzej Pietrasiewicz 
119000a2430fSAndrzej Pietrasiewicz 		/* Option limit */
119100a2430fSAndrzej Pietrasiewicz 		comma = strchr(opts, ',');
119200a2430fSAndrzej Pietrasiewicz 		if (comma)
119300a2430fSAndrzej Pietrasiewicz 			*comma = 0;
119400a2430fSAndrzej Pietrasiewicz 
119500a2430fSAndrzej Pietrasiewicz 		/* Value limit */
119600a2430fSAndrzej Pietrasiewicz 		eq = strchr(opts, '=');
119700a2430fSAndrzej Pietrasiewicz 		if (unlikely(!eq)) {
119800a2430fSAndrzej Pietrasiewicz 			pr_err("'=' missing in %s\n", opts);
119900a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
120000a2430fSAndrzej Pietrasiewicz 		}
120100a2430fSAndrzej Pietrasiewicz 		*eq = 0;
120200a2430fSAndrzej Pietrasiewicz 
120300a2430fSAndrzej Pietrasiewicz 		/* Parse value */
120400a2430fSAndrzej Pietrasiewicz 		if (kstrtoul(eq + 1, 0, &value)) {
120500a2430fSAndrzej Pietrasiewicz 			pr_err("%s: invalid value: %s\n", opts, eq + 1);
120600a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
120700a2430fSAndrzej Pietrasiewicz 		}
120800a2430fSAndrzej Pietrasiewicz 
120900a2430fSAndrzej Pietrasiewicz 		/* Interpret option */
121000a2430fSAndrzej Pietrasiewicz 		switch (eq - opts) {
121118d6b32fSRobert Baldyga 		case 13:
121218d6b32fSRobert Baldyga 			if (!memcmp(opts, "no_disconnect", 13))
121318d6b32fSRobert Baldyga 				data->no_disconnect = !!value;
121418d6b32fSRobert Baldyga 			else
121518d6b32fSRobert Baldyga 				goto invalid;
121618d6b32fSRobert Baldyga 			break;
121700a2430fSAndrzej Pietrasiewicz 		case 5:
121800a2430fSAndrzej Pietrasiewicz 			if (!memcmp(opts, "rmode", 5))
121900a2430fSAndrzej Pietrasiewicz 				data->root_mode  = (value & 0555) | S_IFDIR;
122000a2430fSAndrzej Pietrasiewicz 			else if (!memcmp(opts, "fmode", 5))
122100a2430fSAndrzej Pietrasiewicz 				data->perms.mode = (value & 0666) | S_IFREG;
122200a2430fSAndrzej Pietrasiewicz 			else
122300a2430fSAndrzej Pietrasiewicz 				goto invalid;
122400a2430fSAndrzej Pietrasiewicz 			break;
122500a2430fSAndrzej Pietrasiewicz 
122600a2430fSAndrzej Pietrasiewicz 		case 4:
122700a2430fSAndrzej Pietrasiewicz 			if (!memcmp(opts, "mode", 4)) {
122800a2430fSAndrzej Pietrasiewicz 				data->root_mode  = (value & 0555) | S_IFDIR;
122900a2430fSAndrzej Pietrasiewicz 				data->perms.mode = (value & 0666) | S_IFREG;
123000a2430fSAndrzej Pietrasiewicz 			} else {
123100a2430fSAndrzej Pietrasiewicz 				goto invalid;
123200a2430fSAndrzej Pietrasiewicz 			}
123300a2430fSAndrzej Pietrasiewicz 			break;
123400a2430fSAndrzej Pietrasiewicz 
123500a2430fSAndrzej Pietrasiewicz 		case 3:
123600a2430fSAndrzej Pietrasiewicz 			if (!memcmp(opts, "uid", 3)) {
123700a2430fSAndrzej Pietrasiewicz 				data->perms.uid = make_kuid(current_user_ns(), value);
123800a2430fSAndrzej Pietrasiewicz 				if (!uid_valid(data->perms.uid)) {
123900a2430fSAndrzej Pietrasiewicz 					pr_err("%s: unmapped value: %lu\n", opts, value);
124000a2430fSAndrzej Pietrasiewicz 					return -EINVAL;
124100a2430fSAndrzej Pietrasiewicz 				}
124200a2430fSAndrzej Pietrasiewicz 			} else if (!memcmp(opts, "gid", 3)) {
124300a2430fSAndrzej Pietrasiewicz 				data->perms.gid = make_kgid(current_user_ns(), value);
124400a2430fSAndrzej Pietrasiewicz 				if (!gid_valid(data->perms.gid)) {
124500a2430fSAndrzej Pietrasiewicz 					pr_err("%s: unmapped value: %lu\n", opts, value);
124600a2430fSAndrzej Pietrasiewicz 					return -EINVAL;
124700a2430fSAndrzej Pietrasiewicz 				}
124800a2430fSAndrzej Pietrasiewicz 			} else {
124900a2430fSAndrzej Pietrasiewicz 				goto invalid;
125000a2430fSAndrzej Pietrasiewicz 			}
125100a2430fSAndrzej Pietrasiewicz 			break;
125200a2430fSAndrzej Pietrasiewicz 
125300a2430fSAndrzej Pietrasiewicz 		default:
125400a2430fSAndrzej Pietrasiewicz invalid:
125500a2430fSAndrzej Pietrasiewicz 			pr_err("%s: invalid option\n", opts);
125600a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
125700a2430fSAndrzej Pietrasiewicz 		}
125800a2430fSAndrzej Pietrasiewicz 
125900a2430fSAndrzej Pietrasiewicz 		/* Next iteration */
126000a2430fSAndrzej Pietrasiewicz 		if (!comma)
126100a2430fSAndrzej Pietrasiewicz 			break;
126200a2430fSAndrzej Pietrasiewicz 		opts = comma + 1;
126300a2430fSAndrzej Pietrasiewicz 	}
126400a2430fSAndrzej Pietrasiewicz 
126500a2430fSAndrzej Pietrasiewicz 	return 0;
126600a2430fSAndrzej Pietrasiewicz }
126700a2430fSAndrzej Pietrasiewicz 
126800a2430fSAndrzej Pietrasiewicz /* "mount -t functionfs dev_name /dev/function" ends up here */
126900a2430fSAndrzej Pietrasiewicz 
127000a2430fSAndrzej Pietrasiewicz static struct dentry *
127100a2430fSAndrzej Pietrasiewicz ffs_fs_mount(struct file_system_type *t, int flags,
127200a2430fSAndrzej Pietrasiewicz 	      const char *dev_name, void *opts)
127300a2430fSAndrzej Pietrasiewicz {
127400a2430fSAndrzej Pietrasiewicz 	struct ffs_sb_fill_data data = {
127500a2430fSAndrzej Pietrasiewicz 		.perms = {
127600a2430fSAndrzej Pietrasiewicz 			.mode = S_IFREG | 0600,
127700a2430fSAndrzej Pietrasiewicz 			.uid = GLOBAL_ROOT_UID,
127800a2430fSAndrzej Pietrasiewicz 			.gid = GLOBAL_ROOT_GID,
127900a2430fSAndrzej Pietrasiewicz 		},
128000a2430fSAndrzej Pietrasiewicz 		.root_mode = S_IFDIR | 0500,
128118d6b32fSRobert Baldyga 		.no_disconnect = false,
128200a2430fSAndrzej Pietrasiewicz 	};
128300a2430fSAndrzej Pietrasiewicz 	struct dentry *rv;
128400a2430fSAndrzej Pietrasiewicz 	int ret;
128500a2430fSAndrzej Pietrasiewicz 	void *ffs_dev;
128600a2430fSAndrzej Pietrasiewicz 	struct ffs_data	*ffs;
128700a2430fSAndrzej Pietrasiewicz 
128800a2430fSAndrzej Pietrasiewicz 	ENTER();
128900a2430fSAndrzej Pietrasiewicz 
129000a2430fSAndrzej Pietrasiewicz 	ret = ffs_fs_parse_opts(&data, opts);
129100a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret < 0))
129200a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(ret);
129300a2430fSAndrzej Pietrasiewicz 
129400a2430fSAndrzej Pietrasiewicz 	ffs = ffs_data_new();
129500a2430fSAndrzej Pietrasiewicz 	if (unlikely(!ffs))
129600a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
129700a2430fSAndrzej Pietrasiewicz 	ffs->file_perms = data.perms;
129818d6b32fSRobert Baldyga 	ffs->no_disconnect = data.no_disconnect;
129900a2430fSAndrzej Pietrasiewicz 
130000a2430fSAndrzej Pietrasiewicz 	ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
130100a2430fSAndrzej Pietrasiewicz 	if (unlikely(!ffs->dev_name)) {
130200a2430fSAndrzej Pietrasiewicz 		ffs_data_put(ffs);
130300a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
130400a2430fSAndrzej Pietrasiewicz 	}
130500a2430fSAndrzej Pietrasiewicz 
130600a2430fSAndrzej Pietrasiewicz 	ffs_dev = ffs_acquire_dev(dev_name);
130700a2430fSAndrzej Pietrasiewicz 	if (IS_ERR(ffs_dev)) {
130800a2430fSAndrzej Pietrasiewicz 		ffs_data_put(ffs);
130900a2430fSAndrzej Pietrasiewicz 		return ERR_CAST(ffs_dev);
131000a2430fSAndrzej Pietrasiewicz 	}
131100a2430fSAndrzej Pietrasiewicz 	ffs->private_data = ffs_dev;
131200a2430fSAndrzej Pietrasiewicz 	data.ffs_data = ffs;
131300a2430fSAndrzej Pietrasiewicz 
131400a2430fSAndrzej Pietrasiewicz 	rv = mount_nodev(t, flags, &data, ffs_sb_fill);
131500a2430fSAndrzej Pietrasiewicz 	if (IS_ERR(rv) && data.ffs_data) {
131600a2430fSAndrzej Pietrasiewicz 		ffs_release_dev(data.ffs_data);
131700a2430fSAndrzej Pietrasiewicz 		ffs_data_put(data.ffs_data);
131800a2430fSAndrzej Pietrasiewicz 	}
131900a2430fSAndrzej Pietrasiewicz 	return rv;
132000a2430fSAndrzej Pietrasiewicz }
132100a2430fSAndrzej Pietrasiewicz 
132200a2430fSAndrzej Pietrasiewicz static void
132300a2430fSAndrzej Pietrasiewicz ffs_fs_kill_sb(struct super_block *sb)
132400a2430fSAndrzej Pietrasiewicz {
132500a2430fSAndrzej Pietrasiewicz 	ENTER();
132600a2430fSAndrzej Pietrasiewicz 
132700a2430fSAndrzej Pietrasiewicz 	kill_litter_super(sb);
132800a2430fSAndrzej Pietrasiewicz 	if (sb->s_fs_info) {
132900a2430fSAndrzej Pietrasiewicz 		ffs_release_dev(sb->s_fs_info);
133018d6b32fSRobert Baldyga 		ffs_data_closed(sb->s_fs_info);
133100a2430fSAndrzej Pietrasiewicz 		ffs_data_put(sb->s_fs_info);
133200a2430fSAndrzej Pietrasiewicz 	}
133300a2430fSAndrzej Pietrasiewicz }
133400a2430fSAndrzej Pietrasiewicz 
133500a2430fSAndrzej Pietrasiewicz static struct file_system_type ffs_fs_type = {
133600a2430fSAndrzej Pietrasiewicz 	.owner		= THIS_MODULE,
133700a2430fSAndrzej Pietrasiewicz 	.name		= "functionfs",
133800a2430fSAndrzej Pietrasiewicz 	.mount		= ffs_fs_mount,
133900a2430fSAndrzej Pietrasiewicz 	.kill_sb	= ffs_fs_kill_sb,
134000a2430fSAndrzej Pietrasiewicz };
134100a2430fSAndrzej Pietrasiewicz MODULE_ALIAS_FS("functionfs");
134200a2430fSAndrzej Pietrasiewicz 
134300a2430fSAndrzej Pietrasiewicz 
134400a2430fSAndrzej Pietrasiewicz /* Driver's main init/cleanup functions *************************************/
134500a2430fSAndrzej Pietrasiewicz 
134600a2430fSAndrzej Pietrasiewicz static int functionfs_init(void)
134700a2430fSAndrzej Pietrasiewicz {
134800a2430fSAndrzej Pietrasiewicz 	int ret;
134900a2430fSAndrzej Pietrasiewicz 
135000a2430fSAndrzej Pietrasiewicz 	ENTER();
135100a2430fSAndrzej Pietrasiewicz 
135200a2430fSAndrzej Pietrasiewicz 	ret = register_filesystem(&ffs_fs_type);
135300a2430fSAndrzej Pietrasiewicz 	if (likely(!ret))
135400a2430fSAndrzej Pietrasiewicz 		pr_info("file system registered\n");
135500a2430fSAndrzej Pietrasiewicz 	else
135600a2430fSAndrzej Pietrasiewicz 		pr_err("failed registering file system (%d)\n", ret);
135700a2430fSAndrzej Pietrasiewicz 
135800a2430fSAndrzej Pietrasiewicz 	return ret;
135900a2430fSAndrzej Pietrasiewicz }
136000a2430fSAndrzej Pietrasiewicz 
136100a2430fSAndrzej Pietrasiewicz static void functionfs_cleanup(void)
136200a2430fSAndrzej Pietrasiewicz {
136300a2430fSAndrzej Pietrasiewicz 	ENTER();
136400a2430fSAndrzej Pietrasiewicz 
136500a2430fSAndrzej Pietrasiewicz 	pr_info("unloading\n");
136600a2430fSAndrzej Pietrasiewicz 	unregister_filesystem(&ffs_fs_type);
136700a2430fSAndrzej Pietrasiewicz }
136800a2430fSAndrzej Pietrasiewicz 
136900a2430fSAndrzej Pietrasiewicz 
137000a2430fSAndrzej Pietrasiewicz /* ffs_data and ffs_function construction and destruction code **************/
137100a2430fSAndrzej Pietrasiewicz 
137200a2430fSAndrzej Pietrasiewicz static void ffs_data_clear(struct ffs_data *ffs);
137300a2430fSAndrzej Pietrasiewicz static void ffs_data_reset(struct ffs_data *ffs);
137400a2430fSAndrzej Pietrasiewicz 
137500a2430fSAndrzej Pietrasiewicz static void ffs_data_get(struct ffs_data *ffs)
137600a2430fSAndrzej Pietrasiewicz {
137700a2430fSAndrzej Pietrasiewicz 	ENTER();
137800a2430fSAndrzej Pietrasiewicz 
137900a2430fSAndrzej Pietrasiewicz 	atomic_inc(&ffs->ref);
138000a2430fSAndrzej Pietrasiewicz }
138100a2430fSAndrzej Pietrasiewicz 
138200a2430fSAndrzej Pietrasiewicz static void ffs_data_opened(struct ffs_data *ffs)
138300a2430fSAndrzej Pietrasiewicz {
138400a2430fSAndrzej Pietrasiewicz 	ENTER();
138500a2430fSAndrzej Pietrasiewicz 
138600a2430fSAndrzej Pietrasiewicz 	atomic_inc(&ffs->ref);
138718d6b32fSRobert Baldyga 	if (atomic_add_return(1, &ffs->opened) == 1 &&
138818d6b32fSRobert Baldyga 			ffs->state == FFS_DEACTIVATED) {
138918d6b32fSRobert Baldyga 		ffs->state = FFS_CLOSING;
139018d6b32fSRobert Baldyga 		ffs_data_reset(ffs);
139118d6b32fSRobert Baldyga 	}
139200a2430fSAndrzej Pietrasiewicz }
139300a2430fSAndrzej Pietrasiewicz 
139400a2430fSAndrzej Pietrasiewicz static void ffs_data_put(struct ffs_data *ffs)
139500a2430fSAndrzej Pietrasiewicz {
139600a2430fSAndrzej Pietrasiewicz 	ENTER();
139700a2430fSAndrzej Pietrasiewicz 
139800a2430fSAndrzej Pietrasiewicz 	if (unlikely(atomic_dec_and_test(&ffs->ref))) {
139900a2430fSAndrzej Pietrasiewicz 		pr_info("%s(): freeing\n", __func__);
140000a2430fSAndrzej Pietrasiewicz 		ffs_data_clear(ffs);
140100a2430fSAndrzej Pietrasiewicz 		BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
140200a2430fSAndrzej Pietrasiewicz 		       waitqueue_active(&ffs->ep0req_completion.wait));
140300a2430fSAndrzej Pietrasiewicz 		kfree(ffs->dev_name);
140400a2430fSAndrzej Pietrasiewicz 		kfree(ffs);
140500a2430fSAndrzej Pietrasiewicz 	}
140600a2430fSAndrzej Pietrasiewicz }
140700a2430fSAndrzej Pietrasiewicz 
140800a2430fSAndrzej Pietrasiewicz static void ffs_data_closed(struct ffs_data *ffs)
140900a2430fSAndrzej Pietrasiewicz {
141000a2430fSAndrzej Pietrasiewicz 	ENTER();
141100a2430fSAndrzej Pietrasiewicz 
141200a2430fSAndrzej Pietrasiewicz 	if (atomic_dec_and_test(&ffs->opened)) {
141318d6b32fSRobert Baldyga 		if (ffs->no_disconnect) {
141418d6b32fSRobert Baldyga 			ffs->state = FFS_DEACTIVATED;
141518d6b32fSRobert Baldyga 			if (ffs->epfiles) {
141618d6b32fSRobert Baldyga 				ffs_epfiles_destroy(ffs->epfiles,
141718d6b32fSRobert Baldyga 						   ffs->eps_count);
141818d6b32fSRobert Baldyga 				ffs->epfiles = NULL;
141918d6b32fSRobert Baldyga 			}
142018d6b32fSRobert Baldyga 			if (ffs->setup_state == FFS_SETUP_PENDING)
142118d6b32fSRobert Baldyga 				__ffs_ep0_stall(ffs);
142218d6b32fSRobert Baldyga 		} else {
142318d6b32fSRobert Baldyga 			ffs->state = FFS_CLOSING;
142418d6b32fSRobert Baldyga 			ffs_data_reset(ffs);
142518d6b32fSRobert Baldyga 		}
142618d6b32fSRobert Baldyga 	}
142718d6b32fSRobert Baldyga 	if (atomic_read(&ffs->opened) < 0) {
142800a2430fSAndrzej Pietrasiewicz 		ffs->state = FFS_CLOSING;
142900a2430fSAndrzej Pietrasiewicz 		ffs_data_reset(ffs);
143000a2430fSAndrzej Pietrasiewicz 	}
143100a2430fSAndrzej Pietrasiewicz 
143200a2430fSAndrzej Pietrasiewicz 	ffs_data_put(ffs);
143300a2430fSAndrzej Pietrasiewicz }
143400a2430fSAndrzej Pietrasiewicz 
143500a2430fSAndrzej Pietrasiewicz static struct ffs_data *ffs_data_new(void)
143600a2430fSAndrzej Pietrasiewicz {
143700a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
143800a2430fSAndrzej Pietrasiewicz 	if (unlikely(!ffs))
143900a2430fSAndrzej Pietrasiewicz 		return NULL;
144000a2430fSAndrzej Pietrasiewicz 
144100a2430fSAndrzej Pietrasiewicz 	ENTER();
144200a2430fSAndrzej Pietrasiewicz 
144300a2430fSAndrzej Pietrasiewicz 	atomic_set(&ffs->ref, 1);
144400a2430fSAndrzej Pietrasiewicz 	atomic_set(&ffs->opened, 0);
144500a2430fSAndrzej Pietrasiewicz 	ffs->state = FFS_READ_DESCRIPTORS;
144600a2430fSAndrzej Pietrasiewicz 	mutex_init(&ffs->mutex);
144700a2430fSAndrzej Pietrasiewicz 	spin_lock_init(&ffs->eps_lock);
144800a2430fSAndrzej Pietrasiewicz 	init_waitqueue_head(&ffs->ev.waitq);
144900a2430fSAndrzej Pietrasiewicz 	init_completion(&ffs->ep0req_completion);
145000a2430fSAndrzej Pietrasiewicz 
145100a2430fSAndrzej Pietrasiewicz 	/* XXX REVISIT need to update it in some places, or do we? */
145200a2430fSAndrzej Pietrasiewicz 	ffs->ev.can_stall = 1;
145300a2430fSAndrzej Pietrasiewicz 
145400a2430fSAndrzej Pietrasiewicz 	return ffs;
145500a2430fSAndrzej Pietrasiewicz }
145600a2430fSAndrzej Pietrasiewicz 
145700a2430fSAndrzej Pietrasiewicz static void ffs_data_clear(struct ffs_data *ffs)
145800a2430fSAndrzej Pietrasiewicz {
145900a2430fSAndrzej Pietrasiewicz 	ENTER();
146000a2430fSAndrzej Pietrasiewicz 
146100a2430fSAndrzej Pietrasiewicz 	ffs_closed(ffs);
146200a2430fSAndrzej Pietrasiewicz 
146300a2430fSAndrzej Pietrasiewicz 	BUG_ON(ffs->gadget);
146400a2430fSAndrzej Pietrasiewicz 
146500a2430fSAndrzej Pietrasiewicz 	if (ffs->epfiles)
146600a2430fSAndrzej Pietrasiewicz 		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
146700a2430fSAndrzej Pietrasiewicz 
14685e33f6fdSRobert Baldyga 	if (ffs->ffs_eventfd)
14695e33f6fdSRobert Baldyga 		eventfd_ctx_put(ffs->ffs_eventfd);
14705e33f6fdSRobert Baldyga 
147100a2430fSAndrzej Pietrasiewicz 	kfree(ffs->raw_descs_data);
147200a2430fSAndrzej Pietrasiewicz 	kfree(ffs->raw_strings);
147300a2430fSAndrzej Pietrasiewicz 	kfree(ffs->stringtabs);
147400a2430fSAndrzej Pietrasiewicz }
147500a2430fSAndrzej Pietrasiewicz 
147600a2430fSAndrzej Pietrasiewicz static void ffs_data_reset(struct ffs_data *ffs)
147700a2430fSAndrzej Pietrasiewicz {
147800a2430fSAndrzej Pietrasiewicz 	ENTER();
147900a2430fSAndrzej Pietrasiewicz 
148000a2430fSAndrzej Pietrasiewicz 	ffs_data_clear(ffs);
148100a2430fSAndrzej Pietrasiewicz 
148200a2430fSAndrzej Pietrasiewicz 	ffs->epfiles = NULL;
148300a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs_data = NULL;
148400a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs = NULL;
148500a2430fSAndrzej Pietrasiewicz 	ffs->raw_strings = NULL;
148600a2430fSAndrzej Pietrasiewicz 	ffs->stringtabs = NULL;
148700a2430fSAndrzej Pietrasiewicz 
148800a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs_length = 0;
148900a2430fSAndrzej Pietrasiewicz 	ffs->fs_descs_count = 0;
149000a2430fSAndrzej Pietrasiewicz 	ffs->hs_descs_count = 0;
149100a2430fSAndrzej Pietrasiewicz 	ffs->ss_descs_count = 0;
149200a2430fSAndrzej Pietrasiewicz 
149300a2430fSAndrzej Pietrasiewicz 	ffs->strings_count = 0;
149400a2430fSAndrzej Pietrasiewicz 	ffs->interfaces_count = 0;
149500a2430fSAndrzej Pietrasiewicz 	ffs->eps_count = 0;
149600a2430fSAndrzej Pietrasiewicz 
149700a2430fSAndrzej Pietrasiewicz 	ffs->ev.count = 0;
149800a2430fSAndrzej Pietrasiewicz 
149900a2430fSAndrzej Pietrasiewicz 	ffs->state = FFS_READ_DESCRIPTORS;
150000a2430fSAndrzej Pietrasiewicz 	ffs->setup_state = FFS_NO_SETUP;
150100a2430fSAndrzej Pietrasiewicz 	ffs->flags = 0;
150200a2430fSAndrzej Pietrasiewicz }
150300a2430fSAndrzej Pietrasiewicz 
150400a2430fSAndrzej Pietrasiewicz 
150500a2430fSAndrzej Pietrasiewicz static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
150600a2430fSAndrzej Pietrasiewicz {
150700a2430fSAndrzej Pietrasiewicz 	struct usb_gadget_strings **lang;
150800a2430fSAndrzej Pietrasiewicz 	int first_id;
150900a2430fSAndrzej Pietrasiewicz 
151000a2430fSAndrzej Pietrasiewicz 	ENTER();
151100a2430fSAndrzej Pietrasiewicz 
151200a2430fSAndrzej Pietrasiewicz 	if (WARN_ON(ffs->state != FFS_ACTIVE
151300a2430fSAndrzej Pietrasiewicz 		 || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
151400a2430fSAndrzej Pietrasiewicz 		return -EBADFD;
151500a2430fSAndrzej Pietrasiewicz 
151600a2430fSAndrzej Pietrasiewicz 	first_id = usb_string_ids_n(cdev, ffs->strings_count);
151700a2430fSAndrzej Pietrasiewicz 	if (unlikely(first_id < 0))
151800a2430fSAndrzej Pietrasiewicz 		return first_id;
151900a2430fSAndrzej Pietrasiewicz 
152000a2430fSAndrzej Pietrasiewicz 	ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
152100a2430fSAndrzej Pietrasiewicz 	if (unlikely(!ffs->ep0req))
152200a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
152300a2430fSAndrzej Pietrasiewicz 	ffs->ep0req->complete = ffs_ep0_complete;
152400a2430fSAndrzej Pietrasiewicz 	ffs->ep0req->context = ffs;
152500a2430fSAndrzej Pietrasiewicz 
152600a2430fSAndrzej Pietrasiewicz 	lang = ffs->stringtabs;
152761fe2d75SGreg Kroah-Hartman 	if (lang) {
152861fe2d75SGreg Kroah-Hartman 		for (; *lang; ++lang) {
152900a2430fSAndrzej Pietrasiewicz 			struct usb_string *str = (*lang)->strings;
153000a2430fSAndrzej Pietrasiewicz 			int id = first_id;
153100a2430fSAndrzej Pietrasiewicz 			for (; str->s; ++id, ++str)
153200a2430fSAndrzej Pietrasiewicz 				str->id = id;
153300a2430fSAndrzej Pietrasiewicz 		}
153461fe2d75SGreg Kroah-Hartman 	}
153500a2430fSAndrzej Pietrasiewicz 
153600a2430fSAndrzej Pietrasiewicz 	ffs->gadget = cdev->gadget;
153700a2430fSAndrzej Pietrasiewicz 	ffs_data_get(ffs);
153800a2430fSAndrzej Pietrasiewicz 	return 0;
153900a2430fSAndrzej Pietrasiewicz }
154000a2430fSAndrzej Pietrasiewicz 
154100a2430fSAndrzej Pietrasiewicz static void functionfs_unbind(struct ffs_data *ffs)
154200a2430fSAndrzej Pietrasiewicz {
154300a2430fSAndrzej Pietrasiewicz 	ENTER();
154400a2430fSAndrzej Pietrasiewicz 
154500a2430fSAndrzej Pietrasiewicz 	if (!WARN_ON(!ffs->gadget)) {
154600a2430fSAndrzej Pietrasiewicz 		usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
154700a2430fSAndrzej Pietrasiewicz 		ffs->ep0req = NULL;
154800a2430fSAndrzej Pietrasiewicz 		ffs->gadget = NULL;
154900a2430fSAndrzej Pietrasiewicz 		clear_bit(FFS_FL_BOUND, &ffs->flags);
155000a2430fSAndrzej Pietrasiewicz 		ffs_data_put(ffs);
155100a2430fSAndrzej Pietrasiewicz 	}
155200a2430fSAndrzej Pietrasiewicz }
155300a2430fSAndrzej Pietrasiewicz 
155400a2430fSAndrzej Pietrasiewicz static int ffs_epfiles_create(struct ffs_data *ffs)
155500a2430fSAndrzej Pietrasiewicz {
155600a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile, *epfiles;
155700a2430fSAndrzej Pietrasiewicz 	unsigned i, count;
155800a2430fSAndrzej Pietrasiewicz 
155900a2430fSAndrzej Pietrasiewicz 	ENTER();
156000a2430fSAndrzej Pietrasiewicz 
156100a2430fSAndrzej Pietrasiewicz 	count = ffs->eps_count;
156200a2430fSAndrzej Pietrasiewicz 	epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
156300a2430fSAndrzej Pietrasiewicz 	if (!epfiles)
156400a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
156500a2430fSAndrzej Pietrasiewicz 
156600a2430fSAndrzej Pietrasiewicz 	epfile = epfiles;
156700a2430fSAndrzej Pietrasiewicz 	for (i = 1; i <= count; ++i, ++epfile) {
156800a2430fSAndrzej Pietrasiewicz 		epfile->ffs = ffs;
156900a2430fSAndrzej Pietrasiewicz 		mutex_init(&epfile->mutex);
157000a2430fSAndrzej Pietrasiewicz 		init_waitqueue_head(&epfile->wait);
15711b0bf88fSRobert Baldyga 		if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
1572acba23feSMario Schuknecht 			sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
15731b0bf88fSRobert Baldyga 		else
1574acba23feSMario Schuknecht 			sprintf(epfile->name, "ep%u", i);
1575acba23feSMario Schuknecht 		epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
15761bb27cacSAl Viro 						 epfile,
15771bb27cacSAl Viro 						 &ffs_epfile_operations);
15781bb27cacSAl Viro 		if (unlikely(!epfile->dentry)) {
157900a2430fSAndrzej Pietrasiewicz 			ffs_epfiles_destroy(epfiles, i - 1);
158000a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
158100a2430fSAndrzej Pietrasiewicz 		}
158200a2430fSAndrzej Pietrasiewicz 	}
158300a2430fSAndrzej Pietrasiewicz 
158400a2430fSAndrzej Pietrasiewicz 	ffs->epfiles = epfiles;
158500a2430fSAndrzej Pietrasiewicz 	return 0;
158600a2430fSAndrzej Pietrasiewicz }
158700a2430fSAndrzej Pietrasiewicz 
158800a2430fSAndrzej Pietrasiewicz static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
158900a2430fSAndrzej Pietrasiewicz {
159000a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = epfiles;
159100a2430fSAndrzej Pietrasiewicz 
159200a2430fSAndrzej Pietrasiewicz 	ENTER();
159300a2430fSAndrzej Pietrasiewicz 
159400a2430fSAndrzej Pietrasiewicz 	for (; count; --count, ++epfile) {
159500a2430fSAndrzej Pietrasiewicz 		BUG_ON(mutex_is_locked(&epfile->mutex) ||
159600a2430fSAndrzej Pietrasiewicz 		       waitqueue_active(&epfile->wait));
159700a2430fSAndrzej Pietrasiewicz 		if (epfile->dentry) {
159800a2430fSAndrzej Pietrasiewicz 			d_delete(epfile->dentry);
159900a2430fSAndrzej Pietrasiewicz 			dput(epfile->dentry);
160000a2430fSAndrzej Pietrasiewicz 			epfile->dentry = NULL;
160100a2430fSAndrzej Pietrasiewicz 		}
160200a2430fSAndrzej Pietrasiewicz 	}
160300a2430fSAndrzej Pietrasiewicz 
160400a2430fSAndrzej Pietrasiewicz 	kfree(epfiles);
160500a2430fSAndrzej Pietrasiewicz }
160600a2430fSAndrzej Pietrasiewicz 
160700a2430fSAndrzej Pietrasiewicz static void ffs_func_eps_disable(struct ffs_function *func)
160800a2430fSAndrzej Pietrasiewicz {
160900a2430fSAndrzej Pietrasiewicz 	struct ffs_ep *ep         = func->eps;
161000a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = func->ffs->epfiles;
161100a2430fSAndrzej Pietrasiewicz 	unsigned count            = func->ffs->eps_count;
161200a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
161300a2430fSAndrzej Pietrasiewicz 
161400a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
161500a2430fSAndrzej Pietrasiewicz 	do {
161600a2430fSAndrzej Pietrasiewicz 		/* pending requests get nuked */
161700a2430fSAndrzej Pietrasiewicz 		if (likely(ep->ep))
161800a2430fSAndrzej Pietrasiewicz 			usb_ep_disable(ep->ep);
161900a2430fSAndrzej Pietrasiewicz 		++ep;
162018d6b32fSRobert Baldyga 
162118d6b32fSRobert Baldyga 		if (epfile) {
162218d6b32fSRobert Baldyga 			epfile->ep = NULL;
162300a2430fSAndrzej Pietrasiewicz 			++epfile;
162418d6b32fSRobert Baldyga 		}
162500a2430fSAndrzej Pietrasiewicz 	} while (--count);
162600a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
162700a2430fSAndrzej Pietrasiewicz }
162800a2430fSAndrzej Pietrasiewicz 
162900a2430fSAndrzej Pietrasiewicz static int ffs_func_eps_enable(struct ffs_function *func)
163000a2430fSAndrzej Pietrasiewicz {
163100a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs      = func->ffs;
163200a2430fSAndrzej Pietrasiewicz 	struct ffs_ep *ep         = func->eps;
163300a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = ffs->epfiles;
163400a2430fSAndrzej Pietrasiewicz 	unsigned count            = ffs->eps_count;
163500a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
163600a2430fSAndrzej Pietrasiewicz 	int ret = 0;
163700a2430fSAndrzej Pietrasiewicz 
163800a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
163900a2430fSAndrzej Pietrasiewicz 	do {
164000a2430fSAndrzej Pietrasiewicz 		struct usb_endpoint_descriptor *ds;
164100a2430fSAndrzej Pietrasiewicz 		int desc_idx;
164200a2430fSAndrzej Pietrasiewicz 
164300a2430fSAndrzej Pietrasiewicz 		if (ffs->gadget->speed == USB_SPEED_SUPER)
164400a2430fSAndrzej Pietrasiewicz 			desc_idx = 2;
164500a2430fSAndrzej Pietrasiewicz 		else if (ffs->gadget->speed == USB_SPEED_HIGH)
164600a2430fSAndrzej Pietrasiewicz 			desc_idx = 1;
164700a2430fSAndrzej Pietrasiewicz 		else
164800a2430fSAndrzej Pietrasiewicz 			desc_idx = 0;
164900a2430fSAndrzej Pietrasiewicz 
165000a2430fSAndrzej Pietrasiewicz 		/* fall-back to lower speed if desc missing for current speed */
165100a2430fSAndrzej Pietrasiewicz 		do {
165200a2430fSAndrzej Pietrasiewicz 			ds = ep->descs[desc_idx];
165300a2430fSAndrzej Pietrasiewicz 		} while (!ds && --desc_idx >= 0);
165400a2430fSAndrzej Pietrasiewicz 
165500a2430fSAndrzej Pietrasiewicz 		if (!ds) {
165600a2430fSAndrzej Pietrasiewicz 			ret = -EINVAL;
165700a2430fSAndrzej Pietrasiewicz 			break;
165800a2430fSAndrzej Pietrasiewicz 		}
165900a2430fSAndrzej Pietrasiewicz 
166000a2430fSAndrzej Pietrasiewicz 		ep->ep->driver_data = ep;
166100a2430fSAndrzej Pietrasiewicz 		ep->ep->desc = ds;
166200a2430fSAndrzej Pietrasiewicz 		ret = usb_ep_enable(ep->ep);
166300a2430fSAndrzej Pietrasiewicz 		if (likely(!ret)) {
166400a2430fSAndrzej Pietrasiewicz 			epfile->ep = ep;
166500a2430fSAndrzej Pietrasiewicz 			epfile->in = usb_endpoint_dir_in(ds);
166600a2430fSAndrzej Pietrasiewicz 			epfile->isoc = usb_endpoint_xfer_isoc(ds);
166700a2430fSAndrzej Pietrasiewicz 		} else {
166800a2430fSAndrzej Pietrasiewicz 			break;
166900a2430fSAndrzej Pietrasiewicz 		}
167000a2430fSAndrzej Pietrasiewicz 
167100a2430fSAndrzej Pietrasiewicz 		wake_up(&epfile->wait);
167200a2430fSAndrzej Pietrasiewicz 
167300a2430fSAndrzej Pietrasiewicz 		++ep;
167400a2430fSAndrzej Pietrasiewicz 		++epfile;
167500a2430fSAndrzej Pietrasiewicz 	} while (--count);
167600a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
167700a2430fSAndrzej Pietrasiewicz 
167800a2430fSAndrzej Pietrasiewicz 	return ret;
167900a2430fSAndrzej Pietrasiewicz }
168000a2430fSAndrzej Pietrasiewicz 
168100a2430fSAndrzej Pietrasiewicz 
168200a2430fSAndrzej Pietrasiewicz /* Parsing and building descriptors and strings *****************************/
168300a2430fSAndrzej Pietrasiewicz 
168400a2430fSAndrzej Pietrasiewicz /*
168500a2430fSAndrzej Pietrasiewicz  * This validates if data pointed by data is a valid USB descriptor as
168600a2430fSAndrzej Pietrasiewicz  * well as record how many interfaces, endpoints and strings are
168700a2430fSAndrzej Pietrasiewicz  * required by given configuration.  Returns address after the
168800a2430fSAndrzej Pietrasiewicz  * descriptor or NULL if data is invalid.
168900a2430fSAndrzej Pietrasiewicz  */
169000a2430fSAndrzej Pietrasiewicz 
169100a2430fSAndrzej Pietrasiewicz enum ffs_entity_type {
169200a2430fSAndrzej Pietrasiewicz 	FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
169300a2430fSAndrzej Pietrasiewicz };
169400a2430fSAndrzej Pietrasiewicz 
169500a2430fSAndrzej Pietrasiewicz enum ffs_os_desc_type {
169600a2430fSAndrzej Pietrasiewicz 	FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP
169700a2430fSAndrzej Pietrasiewicz };
169800a2430fSAndrzej Pietrasiewicz 
169900a2430fSAndrzej Pietrasiewicz typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
170000a2430fSAndrzej Pietrasiewicz 				   u8 *valuep,
170100a2430fSAndrzej Pietrasiewicz 				   struct usb_descriptor_header *desc,
170200a2430fSAndrzej Pietrasiewicz 				   void *priv);
170300a2430fSAndrzej Pietrasiewicz 
170400a2430fSAndrzej Pietrasiewicz typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
170500a2430fSAndrzej Pietrasiewicz 				    struct usb_os_desc_header *h, void *data,
170600a2430fSAndrzej Pietrasiewicz 				    unsigned len, void *priv);
170700a2430fSAndrzej Pietrasiewicz 
170800a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_single_desc(char *data, unsigned len,
170900a2430fSAndrzej Pietrasiewicz 					   ffs_entity_callback entity,
171000a2430fSAndrzej Pietrasiewicz 					   void *priv)
171100a2430fSAndrzej Pietrasiewicz {
171200a2430fSAndrzej Pietrasiewicz 	struct usb_descriptor_header *_ds = (void *)data;
171300a2430fSAndrzej Pietrasiewicz 	u8 length;
171400a2430fSAndrzej Pietrasiewicz 	int ret;
171500a2430fSAndrzej Pietrasiewicz 
171600a2430fSAndrzej Pietrasiewicz 	ENTER();
171700a2430fSAndrzej Pietrasiewicz 
171800a2430fSAndrzej Pietrasiewicz 	/* At least two bytes are required: length and type */
171900a2430fSAndrzej Pietrasiewicz 	if (len < 2) {
172000a2430fSAndrzej Pietrasiewicz 		pr_vdebug("descriptor too short\n");
172100a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
172200a2430fSAndrzej Pietrasiewicz 	}
172300a2430fSAndrzej Pietrasiewicz 
172400a2430fSAndrzej Pietrasiewicz 	/* If we have at least as many bytes as the descriptor takes? */
172500a2430fSAndrzej Pietrasiewicz 	length = _ds->bLength;
172600a2430fSAndrzej Pietrasiewicz 	if (len < length) {
172700a2430fSAndrzej Pietrasiewicz 		pr_vdebug("descriptor longer then available data\n");
172800a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
172900a2430fSAndrzej Pietrasiewicz 	}
173000a2430fSAndrzej Pietrasiewicz 
173100a2430fSAndrzej Pietrasiewicz #define __entity_check_INTERFACE(val)  1
173200a2430fSAndrzej Pietrasiewicz #define __entity_check_STRING(val)     (val)
173300a2430fSAndrzej Pietrasiewicz #define __entity_check_ENDPOINT(val)   ((val) & USB_ENDPOINT_NUMBER_MASK)
173400a2430fSAndrzej Pietrasiewicz #define __entity(type, val) do {					\
173500a2430fSAndrzej Pietrasiewicz 		pr_vdebug("entity " #type "(%02x)\n", (val));		\
173600a2430fSAndrzej Pietrasiewicz 		if (unlikely(!__entity_check_ ##type(val))) {		\
173700a2430fSAndrzej Pietrasiewicz 			pr_vdebug("invalid entity's value\n");		\
173800a2430fSAndrzej Pietrasiewicz 			return -EINVAL;					\
173900a2430fSAndrzej Pietrasiewicz 		}							\
174000a2430fSAndrzej Pietrasiewicz 		ret = entity(FFS_ ##type, &val, _ds, priv);		\
174100a2430fSAndrzej Pietrasiewicz 		if (unlikely(ret < 0)) {				\
174200a2430fSAndrzej Pietrasiewicz 			pr_debug("entity " #type "(%02x); ret = %d\n",	\
174300a2430fSAndrzej Pietrasiewicz 				 (val), ret);				\
174400a2430fSAndrzej Pietrasiewicz 			return ret;					\
174500a2430fSAndrzej Pietrasiewicz 		}							\
174600a2430fSAndrzej Pietrasiewicz 	} while (0)
174700a2430fSAndrzej Pietrasiewicz 
174800a2430fSAndrzej Pietrasiewicz 	/* Parse descriptor depending on type. */
174900a2430fSAndrzej Pietrasiewicz 	switch (_ds->bDescriptorType) {
175000a2430fSAndrzej Pietrasiewicz 	case USB_DT_DEVICE:
175100a2430fSAndrzej Pietrasiewicz 	case USB_DT_CONFIG:
175200a2430fSAndrzej Pietrasiewicz 	case USB_DT_STRING:
175300a2430fSAndrzej Pietrasiewicz 	case USB_DT_DEVICE_QUALIFIER:
175400a2430fSAndrzej Pietrasiewicz 		/* function can't have any of those */
175500a2430fSAndrzej Pietrasiewicz 		pr_vdebug("descriptor reserved for gadget: %d\n",
175600a2430fSAndrzej Pietrasiewicz 		      _ds->bDescriptorType);
175700a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
175800a2430fSAndrzej Pietrasiewicz 
175900a2430fSAndrzej Pietrasiewicz 	case USB_DT_INTERFACE: {
176000a2430fSAndrzej Pietrasiewicz 		struct usb_interface_descriptor *ds = (void *)_ds;
176100a2430fSAndrzej Pietrasiewicz 		pr_vdebug("interface descriptor\n");
176200a2430fSAndrzej Pietrasiewicz 		if (length != sizeof *ds)
176300a2430fSAndrzej Pietrasiewicz 			goto inv_length;
176400a2430fSAndrzej Pietrasiewicz 
176500a2430fSAndrzej Pietrasiewicz 		__entity(INTERFACE, ds->bInterfaceNumber);
176600a2430fSAndrzej Pietrasiewicz 		if (ds->iInterface)
176700a2430fSAndrzej Pietrasiewicz 			__entity(STRING, ds->iInterface);
176800a2430fSAndrzej Pietrasiewicz 	}
176900a2430fSAndrzej Pietrasiewicz 		break;
177000a2430fSAndrzej Pietrasiewicz 
177100a2430fSAndrzej Pietrasiewicz 	case USB_DT_ENDPOINT: {
177200a2430fSAndrzej Pietrasiewicz 		struct usb_endpoint_descriptor *ds = (void *)_ds;
177300a2430fSAndrzej Pietrasiewicz 		pr_vdebug("endpoint descriptor\n");
177400a2430fSAndrzej Pietrasiewicz 		if (length != USB_DT_ENDPOINT_SIZE &&
177500a2430fSAndrzej Pietrasiewicz 		    length != USB_DT_ENDPOINT_AUDIO_SIZE)
177600a2430fSAndrzej Pietrasiewicz 			goto inv_length;
177700a2430fSAndrzej Pietrasiewicz 		__entity(ENDPOINT, ds->bEndpointAddress);
177800a2430fSAndrzej Pietrasiewicz 	}
177900a2430fSAndrzej Pietrasiewicz 		break;
178000a2430fSAndrzej Pietrasiewicz 
178100a2430fSAndrzej Pietrasiewicz 	case HID_DT_HID:
178200a2430fSAndrzej Pietrasiewicz 		pr_vdebug("hid descriptor\n");
178300a2430fSAndrzej Pietrasiewicz 		if (length != sizeof(struct hid_descriptor))
178400a2430fSAndrzej Pietrasiewicz 			goto inv_length;
178500a2430fSAndrzej Pietrasiewicz 		break;
178600a2430fSAndrzej Pietrasiewicz 
178700a2430fSAndrzej Pietrasiewicz 	case USB_DT_OTG:
178800a2430fSAndrzej Pietrasiewicz 		if (length != sizeof(struct usb_otg_descriptor))
178900a2430fSAndrzej Pietrasiewicz 			goto inv_length;
179000a2430fSAndrzej Pietrasiewicz 		break;
179100a2430fSAndrzej Pietrasiewicz 
179200a2430fSAndrzej Pietrasiewicz 	case USB_DT_INTERFACE_ASSOCIATION: {
179300a2430fSAndrzej Pietrasiewicz 		struct usb_interface_assoc_descriptor *ds = (void *)_ds;
179400a2430fSAndrzej Pietrasiewicz 		pr_vdebug("interface association descriptor\n");
179500a2430fSAndrzej Pietrasiewicz 		if (length != sizeof *ds)
179600a2430fSAndrzej Pietrasiewicz 			goto inv_length;
179700a2430fSAndrzej Pietrasiewicz 		if (ds->iFunction)
179800a2430fSAndrzej Pietrasiewicz 			__entity(STRING, ds->iFunction);
179900a2430fSAndrzej Pietrasiewicz 	}
180000a2430fSAndrzej Pietrasiewicz 		break;
180100a2430fSAndrzej Pietrasiewicz 
180200a2430fSAndrzej Pietrasiewicz 	case USB_DT_SS_ENDPOINT_COMP:
180300a2430fSAndrzej Pietrasiewicz 		pr_vdebug("EP SS companion descriptor\n");
180400a2430fSAndrzej Pietrasiewicz 		if (length != sizeof(struct usb_ss_ep_comp_descriptor))
180500a2430fSAndrzej Pietrasiewicz 			goto inv_length;
180600a2430fSAndrzej Pietrasiewicz 		break;
180700a2430fSAndrzej Pietrasiewicz 
180800a2430fSAndrzej Pietrasiewicz 	case USB_DT_OTHER_SPEED_CONFIG:
180900a2430fSAndrzej Pietrasiewicz 	case USB_DT_INTERFACE_POWER:
181000a2430fSAndrzej Pietrasiewicz 	case USB_DT_DEBUG:
181100a2430fSAndrzej Pietrasiewicz 	case USB_DT_SECURITY:
181200a2430fSAndrzej Pietrasiewicz 	case USB_DT_CS_RADIO_CONTROL:
181300a2430fSAndrzej Pietrasiewicz 		/* TODO */
181400a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
181500a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
181600a2430fSAndrzej Pietrasiewicz 
181700a2430fSAndrzej Pietrasiewicz 	default:
181800a2430fSAndrzej Pietrasiewicz 		/* We should never be here */
181900a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
182000a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
182100a2430fSAndrzej Pietrasiewicz 
182200a2430fSAndrzej Pietrasiewicz inv_length:
182300a2430fSAndrzej Pietrasiewicz 		pr_vdebug("invalid length: %d (descriptor %d)\n",
182400a2430fSAndrzej Pietrasiewicz 			  _ds->bLength, _ds->bDescriptorType);
182500a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
182600a2430fSAndrzej Pietrasiewicz 	}
182700a2430fSAndrzej Pietrasiewicz 
182800a2430fSAndrzej Pietrasiewicz #undef __entity
182900a2430fSAndrzej Pietrasiewicz #undef __entity_check_DESCRIPTOR
183000a2430fSAndrzej Pietrasiewicz #undef __entity_check_INTERFACE
183100a2430fSAndrzej Pietrasiewicz #undef __entity_check_STRING
183200a2430fSAndrzej Pietrasiewicz #undef __entity_check_ENDPOINT
183300a2430fSAndrzej Pietrasiewicz 
183400a2430fSAndrzej Pietrasiewicz 	return length;
183500a2430fSAndrzej Pietrasiewicz }
183600a2430fSAndrzej Pietrasiewicz 
183700a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
183800a2430fSAndrzej Pietrasiewicz 				     ffs_entity_callback entity, void *priv)
183900a2430fSAndrzej Pietrasiewicz {
184000a2430fSAndrzej Pietrasiewicz 	const unsigned _len = len;
184100a2430fSAndrzej Pietrasiewicz 	unsigned long num = 0;
184200a2430fSAndrzej Pietrasiewicz 
184300a2430fSAndrzej Pietrasiewicz 	ENTER();
184400a2430fSAndrzej Pietrasiewicz 
184500a2430fSAndrzej Pietrasiewicz 	for (;;) {
184600a2430fSAndrzej Pietrasiewicz 		int ret;
184700a2430fSAndrzej Pietrasiewicz 
184800a2430fSAndrzej Pietrasiewicz 		if (num == count)
184900a2430fSAndrzej Pietrasiewicz 			data = NULL;
185000a2430fSAndrzej Pietrasiewicz 
185100a2430fSAndrzej Pietrasiewicz 		/* Record "descriptor" entity */
185200a2430fSAndrzej Pietrasiewicz 		ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
185300a2430fSAndrzej Pietrasiewicz 		if (unlikely(ret < 0)) {
185400a2430fSAndrzej Pietrasiewicz 			pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
185500a2430fSAndrzej Pietrasiewicz 				 num, ret);
185600a2430fSAndrzej Pietrasiewicz 			return ret;
185700a2430fSAndrzej Pietrasiewicz 		}
185800a2430fSAndrzej Pietrasiewicz 
185900a2430fSAndrzej Pietrasiewicz 		if (!data)
186000a2430fSAndrzej Pietrasiewicz 			return _len - len;
186100a2430fSAndrzej Pietrasiewicz 
186200a2430fSAndrzej Pietrasiewicz 		ret = ffs_do_single_desc(data, len, entity, priv);
186300a2430fSAndrzej Pietrasiewicz 		if (unlikely(ret < 0)) {
186400a2430fSAndrzej Pietrasiewicz 			pr_debug("%s returns %d\n", __func__, ret);
186500a2430fSAndrzej Pietrasiewicz 			return ret;
186600a2430fSAndrzej Pietrasiewicz 		}
186700a2430fSAndrzej Pietrasiewicz 
186800a2430fSAndrzej Pietrasiewicz 		len -= ret;
186900a2430fSAndrzej Pietrasiewicz 		data += ret;
187000a2430fSAndrzej Pietrasiewicz 		++num;
187100a2430fSAndrzej Pietrasiewicz 	}
187200a2430fSAndrzej Pietrasiewicz }
187300a2430fSAndrzej Pietrasiewicz 
187400a2430fSAndrzej Pietrasiewicz static int __ffs_data_do_entity(enum ffs_entity_type type,
187500a2430fSAndrzej Pietrasiewicz 				u8 *valuep, struct usb_descriptor_header *desc,
187600a2430fSAndrzej Pietrasiewicz 				void *priv)
187700a2430fSAndrzej Pietrasiewicz {
18786d5c1c77SRobert Baldyga 	struct ffs_desc_helper *helper = priv;
18796d5c1c77SRobert Baldyga 	struct usb_endpoint_descriptor *d;
188000a2430fSAndrzej Pietrasiewicz 
188100a2430fSAndrzej Pietrasiewicz 	ENTER();
188200a2430fSAndrzej Pietrasiewicz 
188300a2430fSAndrzej Pietrasiewicz 	switch (type) {
188400a2430fSAndrzej Pietrasiewicz 	case FFS_DESCRIPTOR:
188500a2430fSAndrzej Pietrasiewicz 		break;
188600a2430fSAndrzej Pietrasiewicz 
188700a2430fSAndrzej Pietrasiewicz 	case FFS_INTERFACE:
188800a2430fSAndrzej Pietrasiewicz 		/*
188900a2430fSAndrzej Pietrasiewicz 		 * Interfaces are indexed from zero so if we
189000a2430fSAndrzej Pietrasiewicz 		 * encountered interface "n" then there are at least
189100a2430fSAndrzej Pietrasiewicz 		 * "n+1" interfaces.
189200a2430fSAndrzej Pietrasiewicz 		 */
18936d5c1c77SRobert Baldyga 		if (*valuep >= helper->interfaces_count)
18946d5c1c77SRobert Baldyga 			helper->interfaces_count = *valuep + 1;
189500a2430fSAndrzej Pietrasiewicz 		break;
189600a2430fSAndrzej Pietrasiewicz 
189700a2430fSAndrzej Pietrasiewicz 	case FFS_STRING:
189800a2430fSAndrzej Pietrasiewicz 		/*
189900a2430fSAndrzej Pietrasiewicz 		 * Strings are indexed from 1 (0 is magic ;) reserved
190000a2430fSAndrzej Pietrasiewicz 		 * for languages list or some such)
190100a2430fSAndrzej Pietrasiewicz 		 */
19026d5c1c77SRobert Baldyga 		if (*valuep > helper->ffs->strings_count)
19036d5c1c77SRobert Baldyga 			helper->ffs->strings_count = *valuep;
190400a2430fSAndrzej Pietrasiewicz 		break;
190500a2430fSAndrzej Pietrasiewicz 
190600a2430fSAndrzej Pietrasiewicz 	case FFS_ENDPOINT:
19076d5c1c77SRobert Baldyga 		d = (void *)desc;
19086d5c1c77SRobert Baldyga 		helper->eps_count++;
19096d5c1c77SRobert Baldyga 		if (helper->eps_count >= 15)
19106d5c1c77SRobert Baldyga 			return -EINVAL;
19116d5c1c77SRobert Baldyga 		/* Check if descriptors for any speed were already parsed */
19126d5c1c77SRobert Baldyga 		if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
19136d5c1c77SRobert Baldyga 			helper->ffs->eps_addrmap[helper->eps_count] =
19146d5c1c77SRobert Baldyga 				d->bEndpointAddress;
19156d5c1c77SRobert Baldyga 		else if (helper->ffs->eps_addrmap[helper->eps_count] !=
19166d5c1c77SRobert Baldyga 				d->bEndpointAddress)
19176d5c1c77SRobert Baldyga 			return -EINVAL;
191800a2430fSAndrzej Pietrasiewicz 		break;
191900a2430fSAndrzej Pietrasiewicz 	}
192000a2430fSAndrzej Pietrasiewicz 
192100a2430fSAndrzej Pietrasiewicz 	return 0;
192200a2430fSAndrzej Pietrasiewicz }
192300a2430fSAndrzej Pietrasiewicz 
192400a2430fSAndrzej Pietrasiewicz static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
192500a2430fSAndrzej Pietrasiewicz 				   struct usb_os_desc_header *desc)
192600a2430fSAndrzej Pietrasiewicz {
192700a2430fSAndrzej Pietrasiewicz 	u16 bcd_version = le16_to_cpu(desc->bcdVersion);
192800a2430fSAndrzej Pietrasiewicz 	u16 w_index = le16_to_cpu(desc->wIndex);
192900a2430fSAndrzej Pietrasiewicz 
193000a2430fSAndrzej Pietrasiewicz 	if (bcd_version != 1) {
193100a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unsupported os descriptors version: %d",
193200a2430fSAndrzej Pietrasiewicz 			  bcd_version);
193300a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
193400a2430fSAndrzej Pietrasiewicz 	}
193500a2430fSAndrzej Pietrasiewicz 	switch (w_index) {
193600a2430fSAndrzej Pietrasiewicz 	case 0x4:
193700a2430fSAndrzej Pietrasiewicz 		*next_type = FFS_OS_DESC_EXT_COMPAT;
193800a2430fSAndrzej Pietrasiewicz 		break;
193900a2430fSAndrzej Pietrasiewicz 	case 0x5:
194000a2430fSAndrzej Pietrasiewicz 		*next_type = FFS_OS_DESC_EXT_PROP;
194100a2430fSAndrzej Pietrasiewicz 		break;
194200a2430fSAndrzej Pietrasiewicz 	default:
194300a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unsupported os descriptor type: %d", w_index);
194400a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
194500a2430fSAndrzej Pietrasiewicz 	}
194600a2430fSAndrzej Pietrasiewicz 
194700a2430fSAndrzej Pietrasiewicz 	return sizeof(*desc);
194800a2430fSAndrzej Pietrasiewicz }
194900a2430fSAndrzej Pietrasiewicz 
195000a2430fSAndrzej Pietrasiewicz /*
195100a2430fSAndrzej Pietrasiewicz  * Process all extended compatibility/extended property descriptors
195200a2430fSAndrzej Pietrasiewicz  * of a feature descriptor
195300a2430fSAndrzej Pietrasiewicz  */
195400a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
195500a2430fSAndrzej Pietrasiewicz 					      enum ffs_os_desc_type type,
195600a2430fSAndrzej Pietrasiewicz 					      u16 feature_count,
195700a2430fSAndrzej Pietrasiewicz 					      ffs_os_desc_callback entity,
195800a2430fSAndrzej Pietrasiewicz 					      void *priv,
195900a2430fSAndrzej Pietrasiewicz 					      struct usb_os_desc_header *h)
196000a2430fSAndrzej Pietrasiewicz {
196100a2430fSAndrzej Pietrasiewicz 	int ret;
196200a2430fSAndrzej Pietrasiewicz 	const unsigned _len = len;
196300a2430fSAndrzej Pietrasiewicz 
196400a2430fSAndrzej Pietrasiewicz 	ENTER();
196500a2430fSAndrzej Pietrasiewicz 
196600a2430fSAndrzej Pietrasiewicz 	/* loop over all ext compat/ext prop descriptors */
196700a2430fSAndrzej Pietrasiewicz 	while (feature_count--) {
196800a2430fSAndrzej Pietrasiewicz 		ret = entity(type, h, data, len, priv);
196900a2430fSAndrzej Pietrasiewicz 		if (unlikely(ret < 0)) {
197000a2430fSAndrzej Pietrasiewicz 			pr_debug("bad OS descriptor, type: %d\n", type);
197100a2430fSAndrzej Pietrasiewicz 			return ret;
197200a2430fSAndrzej Pietrasiewicz 		}
197300a2430fSAndrzej Pietrasiewicz 		data += ret;
197400a2430fSAndrzej Pietrasiewicz 		len -= ret;
197500a2430fSAndrzej Pietrasiewicz 	}
197600a2430fSAndrzej Pietrasiewicz 	return _len - len;
197700a2430fSAndrzej Pietrasiewicz }
197800a2430fSAndrzej Pietrasiewicz 
197900a2430fSAndrzej Pietrasiewicz /* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */
198000a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_os_descs(unsigned count,
198100a2430fSAndrzej Pietrasiewicz 					char *data, unsigned len,
198200a2430fSAndrzej Pietrasiewicz 					ffs_os_desc_callback entity, void *priv)
198300a2430fSAndrzej Pietrasiewicz {
198400a2430fSAndrzej Pietrasiewicz 	const unsigned _len = len;
198500a2430fSAndrzej Pietrasiewicz 	unsigned long num = 0;
198600a2430fSAndrzej Pietrasiewicz 
198700a2430fSAndrzej Pietrasiewicz 	ENTER();
198800a2430fSAndrzej Pietrasiewicz 
198900a2430fSAndrzej Pietrasiewicz 	for (num = 0; num < count; ++num) {
199000a2430fSAndrzej Pietrasiewicz 		int ret;
199100a2430fSAndrzej Pietrasiewicz 		enum ffs_os_desc_type type;
199200a2430fSAndrzej Pietrasiewicz 		u16 feature_count;
199300a2430fSAndrzej Pietrasiewicz 		struct usb_os_desc_header *desc = (void *)data;
199400a2430fSAndrzej Pietrasiewicz 
199500a2430fSAndrzej Pietrasiewicz 		if (len < sizeof(*desc))
199600a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
199700a2430fSAndrzej Pietrasiewicz 
199800a2430fSAndrzej Pietrasiewicz 		/*
199900a2430fSAndrzej Pietrasiewicz 		 * Record "descriptor" entity.
200000a2430fSAndrzej Pietrasiewicz 		 * Process dwLength, bcdVersion, wIndex, get b/wCount.
200100a2430fSAndrzej Pietrasiewicz 		 * Move the data pointer to the beginning of extended
200200a2430fSAndrzej Pietrasiewicz 		 * compatibilities proper or extended properties proper
200300a2430fSAndrzej Pietrasiewicz 		 * portions of the data
200400a2430fSAndrzej Pietrasiewicz 		 */
200500a2430fSAndrzej Pietrasiewicz 		if (le32_to_cpu(desc->dwLength) > len)
200600a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
200700a2430fSAndrzej Pietrasiewicz 
200800a2430fSAndrzej Pietrasiewicz 		ret = __ffs_do_os_desc_header(&type, desc);
200900a2430fSAndrzej Pietrasiewicz 		if (unlikely(ret < 0)) {
201000a2430fSAndrzej Pietrasiewicz 			pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
201100a2430fSAndrzej Pietrasiewicz 				 num, ret);
201200a2430fSAndrzej Pietrasiewicz 			return ret;
201300a2430fSAndrzej Pietrasiewicz 		}
201400a2430fSAndrzej Pietrasiewicz 		/*
201500a2430fSAndrzej Pietrasiewicz 		 * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??"
201600a2430fSAndrzej Pietrasiewicz 		 */
201700a2430fSAndrzej Pietrasiewicz 		feature_count = le16_to_cpu(desc->wCount);
201800a2430fSAndrzej Pietrasiewicz 		if (type == FFS_OS_DESC_EXT_COMPAT &&
201900a2430fSAndrzej Pietrasiewicz 		    (feature_count > 255 || desc->Reserved))
202000a2430fSAndrzej Pietrasiewicz 				return -EINVAL;
202100a2430fSAndrzej Pietrasiewicz 		len -= ret;
202200a2430fSAndrzej Pietrasiewicz 		data += ret;
202300a2430fSAndrzej Pietrasiewicz 
202400a2430fSAndrzej Pietrasiewicz 		/*
202500a2430fSAndrzej Pietrasiewicz 		 * Process all function/property descriptors
202600a2430fSAndrzej Pietrasiewicz 		 * of this Feature Descriptor
202700a2430fSAndrzej Pietrasiewicz 		 */
202800a2430fSAndrzej Pietrasiewicz 		ret = ffs_do_single_os_desc(data, len, type,
202900a2430fSAndrzej Pietrasiewicz 					    feature_count, entity, priv, desc);
203000a2430fSAndrzej Pietrasiewicz 		if (unlikely(ret < 0)) {
203100a2430fSAndrzej Pietrasiewicz 			pr_debug("%s returns %d\n", __func__, ret);
203200a2430fSAndrzej Pietrasiewicz 			return ret;
203300a2430fSAndrzej Pietrasiewicz 		}
203400a2430fSAndrzej Pietrasiewicz 
203500a2430fSAndrzej Pietrasiewicz 		len -= ret;
203600a2430fSAndrzej Pietrasiewicz 		data += ret;
203700a2430fSAndrzej Pietrasiewicz 	}
203800a2430fSAndrzej Pietrasiewicz 	return _len - len;
203900a2430fSAndrzej Pietrasiewicz }
204000a2430fSAndrzej Pietrasiewicz 
204100a2430fSAndrzej Pietrasiewicz /**
204200a2430fSAndrzej Pietrasiewicz  * Validate contents of the buffer from userspace related to OS descriptors.
204300a2430fSAndrzej Pietrasiewicz  */
204400a2430fSAndrzej Pietrasiewicz static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
204500a2430fSAndrzej Pietrasiewicz 				 struct usb_os_desc_header *h, void *data,
204600a2430fSAndrzej Pietrasiewicz 				 unsigned len, void *priv)
204700a2430fSAndrzej Pietrasiewicz {
204800a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = priv;
204900a2430fSAndrzej Pietrasiewicz 	u8 length;
205000a2430fSAndrzej Pietrasiewicz 
205100a2430fSAndrzej Pietrasiewicz 	ENTER();
205200a2430fSAndrzej Pietrasiewicz 
205300a2430fSAndrzej Pietrasiewicz 	switch (type) {
205400a2430fSAndrzej Pietrasiewicz 	case FFS_OS_DESC_EXT_COMPAT: {
205500a2430fSAndrzej Pietrasiewicz 		struct usb_ext_compat_desc *d = data;
205600a2430fSAndrzej Pietrasiewicz 		int i;
205700a2430fSAndrzej Pietrasiewicz 
205800a2430fSAndrzej Pietrasiewicz 		if (len < sizeof(*d) ||
205900a2430fSAndrzej Pietrasiewicz 		    d->bFirstInterfaceNumber >= ffs->interfaces_count ||
206000a2430fSAndrzej Pietrasiewicz 		    d->Reserved1)
206100a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
206200a2430fSAndrzej Pietrasiewicz 		for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
206300a2430fSAndrzej Pietrasiewicz 			if (d->Reserved2[i])
206400a2430fSAndrzej Pietrasiewicz 				return -EINVAL;
206500a2430fSAndrzej Pietrasiewicz 
206600a2430fSAndrzej Pietrasiewicz 		length = sizeof(struct usb_ext_compat_desc);
206700a2430fSAndrzej Pietrasiewicz 	}
206800a2430fSAndrzej Pietrasiewicz 		break;
206900a2430fSAndrzej Pietrasiewicz 	case FFS_OS_DESC_EXT_PROP: {
207000a2430fSAndrzej Pietrasiewicz 		struct usb_ext_prop_desc *d = data;
207100a2430fSAndrzej Pietrasiewicz 		u32 type, pdl;
207200a2430fSAndrzej Pietrasiewicz 		u16 pnl;
207300a2430fSAndrzej Pietrasiewicz 
207400a2430fSAndrzej Pietrasiewicz 		if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
207500a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
207600a2430fSAndrzej Pietrasiewicz 		length = le32_to_cpu(d->dwSize);
207700a2430fSAndrzej Pietrasiewicz 		type = le32_to_cpu(d->dwPropertyDataType);
207800a2430fSAndrzej Pietrasiewicz 		if (type < USB_EXT_PROP_UNICODE ||
207900a2430fSAndrzej Pietrasiewicz 		    type > USB_EXT_PROP_UNICODE_MULTI) {
208000a2430fSAndrzej Pietrasiewicz 			pr_vdebug("unsupported os descriptor property type: %d",
208100a2430fSAndrzej Pietrasiewicz 				  type);
208200a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
208300a2430fSAndrzej Pietrasiewicz 		}
208400a2430fSAndrzej Pietrasiewicz 		pnl = le16_to_cpu(d->wPropertyNameLength);
208500a2430fSAndrzej Pietrasiewicz 		pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl));
208600a2430fSAndrzej Pietrasiewicz 		if (length != 14 + pnl + pdl) {
208700a2430fSAndrzej Pietrasiewicz 			pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
208800a2430fSAndrzej Pietrasiewicz 				  length, pnl, pdl, type);
208900a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
209000a2430fSAndrzej Pietrasiewicz 		}
209100a2430fSAndrzej Pietrasiewicz 		++ffs->ms_os_descs_ext_prop_count;
209200a2430fSAndrzej Pietrasiewicz 		/* property name reported to the host as "WCHAR"s */
209300a2430fSAndrzej Pietrasiewicz 		ffs->ms_os_descs_ext_prop_name_len += pnl * 2;
209400a2430fSAndrzej Pietrasiewicz 		ffs->ms_os_descs_ext_prop_data_len += pdl;
209500a2430fSAndrzej Pietrasiewicz 	}
209600a2430fSAndrzej Pietrasiewicz 		break;
209700a2430fSAndrzej Pietrasiewicz 	default:
209800a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unknown descriptor: %d\n", type);
209900a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
210000a2430fSAndrzej Pietrasiewicz 	}
210100a2430fSAndrzej Pietrasiewicz 	return length;
210200a2430fSAndrzej Pietrasiewicz }
210300a2430fSAndrzej Pietrasiewicz 
210400a2430fSAndrzej Pietrasiewicz static int __ffs_data_got_descs(struct ffs_data *ffs,
210500a2430fSAndrzej Pietrasiewicz 				char *const _data, size_t len)
210600a2430fSAndrzej Pietrasiewicz {
210700a2430fSAndrzej Pietrasiewicz 	char *data = _data, *raw_descs;
210800a2430fSAndrzej Pietrasiewicz 	unsigned os_descs_count = 0, counts[3], flags;
210900a2430fSAndrzej Pietrasiewicz 	int ret = -EINVAL, i;
21106d5c1c77SRobert Baldyga 	struct ffs_desc_helper helper;
211100a2430fSAndrzej Pietrasiewicz 
211200a2430fSAndrzej Pietrasiewicz 	ENTER();
211300a2430fSAndrzej Pietrasiewicz 
211400a2430fSAndrzej Pietrasiewicz 	if (get_unaligned_le32(data + 4) != len)
211500a2430fSAndrzej Pietrasiewicz 		goto error;
211600a2430fSAndrzej Pietrasiewicz 
211700a2430fSAndrzej Pietrasiewicz 	switch (get_unaligned_le32(data)) {
211800a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_DESCRIPTORS_MAGIC:
211900a2430fSAndrzej Pietrasiewicz 		flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
212000a2430fSAndrzej Pietrasiewicz 		data += 8;
212100a2430fSAndrzej Pietrasiewicz 		len  -= 8;
212200a2430fSAndrzej Pietrasiewicz 		break;
212300a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_DESCRIPTORS_MAGIC_V2:
212400a2430fSAndrzej Pietrasiewicz 		flags = get_unaligned_le32(data + 8);
21251b0bf88fSRobert Baldyga 		ffs->user_flags = flags;
212600a2430fSAndrzej Pietrasiewicz 		if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
212700a2430fSAndrzej Pietrasiewicz 			      FUNCTIONFS_HAS_HS_DESC |
212800a2430fSAndrzej Pietrasiewicz 			      FUNCTIONFS_HAS_SS_DESC |
21291b0bf88fSRobert Baldyga 			      FUNCTIONFS_HAS_MS_OS_DESC |
21305e33f6fdSRobert Baldyga 			      FUNCTIONFS_VIRTUAL_ADDR |
21315e33f6fdSRobert Baldyga 			      FUNCTIONFS_EVENTFD)) {
213200a2430fSAndrzej Pietrasiewicz 			ret = -ENOSYS;
213300a2430fSAndrzej Pietrasiewicz 			goto error;
213400a2430fSAndrzej Pietrasiewicz 		}
213500a2430fSAndrzej Pietrasiewicz 		data += 12;
213600a2430fSAndrzej Pietrasiewicz 		len  -= 12;
213700a2430fSAndrzej Pietrasiewicz 		break;
213800a2430fSAndrzej Pietrasiewicz 	default:
213900a2430fSAndrzej Pietrasiewicz 		goto error;
214000a2430fSAndrzej Pietrasiewicz 	}
214100a2430fSAndrzej Pietrasiewicz 
21425e33f6fdSRobert Baldyga 	if (flags & FUNCTIONFS_EVENTFD) {
21435e33f6fdSRobert Baldyga 		if (len < 4)
21445e33f6fdSRobert Baldyga 			goto error;
21455e33f6fdSRobert Baldyga 		ffs->ffs_eventfd =
21465e33f6fdSRobert Baldyga 			eventfd_ctx_fdget((int)get_unaligned_le32(data));
21475e33f6fdSRobert Baldyga 		if (IS_ERR(ffs->ffs_eventfd)) {
21485e33f6fdSRobert Baldyga 			ret = PTR_ERR(ffs->ffs_eventfd);
21495e33f6fdSRobert Baldyga 			ffs->ffs_eventfd = NULL;
21505e33f6fdSRobert Baldyga 			goto error;
21515e33f6fdSRobert Baldyga 		}
21525e33f6fdSRobert Baldyga 		data += 4;
21535e33f6fdSRobert Baldyga 		len  -= 4;
21545e33f6fdSRobert Baldyga 	}
21555e33f6fdSRobert Baldyga 
215600a2430fSAndrzej Pietrasiewicz 	/* Read fs_count, hs_count and ss_count (if present) */
215700a2430fSAndrzej Pietrasiewicz 	for (i = 0; i < 3; ++i) {
215800a2430fSAndrzej Pietrasiewicz 		if (!(flags & (1 << i))) {
215900a2430fSAndrzej Pietrasiewicz 			counts[i] = 0;
216000a2430fSAndrzej Pietrasiewicz 		} else if (len < 4) {
216100a2430fSAndrzej Pietrasiewicz 			goto error;
216200a2430fSAndrzej Pietrasiewicz 		} else {
216300a2430fSAndrzej Pietrasiewicz 			counts[i] = get_unaligned_le32(data);
216400a2430fSAndrzej Pietrasiewicz 			data += 4;
216500a2430fSAndrzej Pietrasiewicz 			len  -= 4;
216600a2430fSAndrzej Pietrasiewicz 		}
216700a2430fSAndrzej Pietrasiewicz 	}
216800a2430fSAndrzej Pietrasiewicz 	if (flags & (1 << i)) {
216900a2430fSAndrzej Pietrasiewicz 		os_descs_count = get_unaligned_le32(data);
217000a2430fSAndrzej Pietrasiewicz 		data += 4;
217100a2430fSAndrzej Pietrasiewicz 		len -= 4;
217200a2430fSAndrzej Pietrasiewicz 	};
217300a2430fSAndrzej Pietrasiewicz 
217400a2430fSAndrzej Pietrasiewicz 	/* Read descriptors */
217500a2430fSAndrzej Pietrasiewicz 	raw_descs = data;
21766d5c1c77SRobert Baldyga 	helper.ffs = ffs;
217700a2430fSAndrzej Pietrasiewicz 	for (i = 0; i < 3; ++i) {
217800a2430fSAndrzej Pietrasiewicz 		if (!counts[i])
217900a2430fSAndrzej Pietrasiewicz 			continue;
21806d5c1c77SRobert Baldyga 		helper.interfaces_count = 0;
21816d5c1c77SRobert Baldyga 		helper.eps_count = 0;
218200a2430fSAndrzej Pietrasiewicz 		ret = ffs_do_descs(counts[i], data, len,
21836d5c1c77SRobert Baldyga 				   __ffs_data_do_entity, &helper);
218400a2430fSAndrzej Pietrasiewicz 		if (ret < 0)
218500a2430fSAndrzej Pietrasiewicz 			goto error;
21866d5c1c77SRobert Baldyga 		if (!ffs->eps_count && !ffs->interfaces_count) {
21876d5c1c77SRobert Baldyga 			ffs->eps_count = helper.eps_count;
21886d5c1c77SRobert Baldyga 			ffs->interfaces_count = helper.interfaces_count;
21896d5c1c77SRobert Baldyga 		} else {
21906d5c1c77SRobert Baldyga 			if (ffs->eps_count != helper.eps_count) {
21916d5c1c77SRobert Baldyga 				ret = -EINVAL;
21926d5c1c77SRobert Baldyga 				goto error;
21936d5c1c77SRobert Baldyga 			}
21946d5c1c77SRobert Baldyga 			if (ffs->interfaces_count != helper.interfaces_count) {
21956d5c1c77SRobert Baldyga 				ret = -EINVAL;
21966d5c1c77SRobert Baldyga 				goto error;
21976d5c1c77SRobert Baldyga 			}
21986d5c1c77SRobert Baldyga 		}
219900a2430fSAndrzej Pietrasiewicz 		data += ret;
220000a2430fSAndrzej Pietrasiewicz 		len  -= ret;
220100a2430fSAndrzej Pietrasiewicz 	}
220200a2430fSAndrzej Pietrasiewicz 	if (os_descs_count) {
220300a2430fSAndrzej Pietrasiewicz 		ret = ffs_do_os_descs(os_descs_count, data, len,
220400a2430fSAndrzej Pietrasiewicz 				      __ffs_data_do_os_desc, ffs);
220500a2430fSAndrzej Pietrasiewicz 		if (ret < 0)
220600a2430fSAndrzej Pietrasiewicz 			goto error;
220700a2430fSAndrzej Pietrasiewicz 		data += ret;
220800a2430fSAndrzej Pietrasiewicz 		len -= ret;
220900a2430fSAndrzej Pietrasiewicz 	}
221000a2430fSAndrzej Pietrasiewicz 
221100a2430fSAndrzej Pietrasiewicz 	if (raw_descs == data || len) {
221200a2430fSAndrzej Pietrasiewicz 		ret = -EINVAL;
221300a2430fSAndrzej Pietrasiewicz 		goto error;
221400a2430fSAndrzej Pietrasiewicz 	}
221500a2430fSAndrzej Pietrasiewicz 
221600a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs_data	= _data;
221700a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs		= raw_descs;
221800a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs_length	= data - raw_descs;
221900a2430fSAndrzej Pietrasiewicz 	ffs->fs_descs_count	= counts[0];
222000a2430fSAndrzej Pietrasiewicz 	ffs->hs_descs_count	= counts[1];
222100a2430fSAndrzej Pietrasiewicz 	ffs->ss_descs_count	= counts[2];
222200a2430fSAndrzej Pietrasiewicz 	ffs->ms_os_descs_count	= os_descs_count;
222300a2430fSAndrzej Pietrasiewicz 
222400a2430fSAndrzej Pietrasiewicz 	return 0;
222500a2430fSAndrzej Pietrasiewicz 
222600a2430fSAndrzej Pietrasiewicz error:
222700a2430fSAndrzej Pietrasiewicz 	kfree(_data);
222800a2430fSAndrzej Pietrasiewicz 	return ret;
222900a2430fSAndrzej Pietrasiewicz }
223000a2430fSAndrzej Pietrasiewicz 
223100a2430fSAndrzej Pietrasiewicz static int __ffs_data_got_strings(struct ffs_data *ffs,
223200a2430fSAndrzej Pietrasiewicz 				  char *const _data, size_t len)
223300a2430fSAndrzej Pietrasiewicz {
223400a2430fSAndrzej Pietrasiewicz 	u32 str_count, needed_count, lang_count;
223500a2430fSAndrzej Pietrasiewicz 	struct usb_gadget_strings **stringtabs, *t;
223600a2430fSAndrzej Pietrasiewicz 	struct usb_string *strings, *s;
223700a2430fSAndrzej Pietrasiewicz 	const char *data = _data;
223800a2430fSAndrzej Pietrasiewicz 
223900a2430fSAndrzej Pietrasiewicz 	ENTER();
224000a2430fSAndrzej Pietrasiewicz 
224100a2430fSAndrzej Pietrasiewicz 	if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
224200a2430fSAndrzej Pietrasiewicz 		     get_unaligned_le32(data + 4) != len))
224300a2430fSAndrzej Pietrasiewicz 		goto error;
224400a2430fSAndrzej Pietrasiewicz 	str_count  = get_unaligned_le32(data + 8);
224500a2430fSAndrzej Pietrasiewicz 	lang_count = get_unaligned_le32(data + 12);
224600a2430fSAndrzej Pietrasiewicz 
224700a2430fSAndrzej Pietrasiewicz 	/* if one is zero the other must be zero */
224800a2430fSAndrzej Pietrasiewicz 	if (unlikely(!str_count != !lang_count))
224900a2430fSAndrzej Pietrasiewicz 		goto error;
225000a2430fSAndrzej Pietrasiewicz 
225100a2430fSAndrzej Pietrasiewicz 	/* Do we have at least as many strings as descriptors need? */
225200a2430fSAndrzej Pietrasiewicz 	needed_count = ffs->strings_count;
225300a2430fSAndrzej Pietrasiewicz 	if (unlikely(str_count < needed_count))
225400a2430fSAndrzej Pietrasiewicz 		goto error;
225500a2430fSAndrzej Pietrasiewicz 
225600a2430fSAndrzej Pietrasiewicz 	/*
225700a2430fSAndrzej Pietrasiewicz 	 * If we don't need any strings just return and free all
225800a2430fSAndrzej Pietrasiewicz 	 * memory.
225900a2430fSAndrzej Pietrasiewicz 	 */
226000a2430fSAndrzej Pietrasiewicz 	if (!needed_count) {
226100a2430fSAndrzej Pietrasiewicz 		kfree(_data);
226200a2430fSAndrzej Pietrasiewicz 		return 0;
226300a2430fSAndrzej Pietrasiewicz 	}
226400a2430fSAndrzej Pietrasiewicz 
226500a2430fSAndrzej Pietrasiewicz 	/* Allocate everything in one chunk so there's less maintenance. */
226600a2430fSAndrzej Pietrasiewicz 	{
226700a2430fSAndrzej Pietrasiewicz 		unsigned i = 0;
226800a2430fSAndrzej Pietrasiewicz 		vla_group(d);
226900a2430fSAndrzej Pietrasiewicz 		vla_item(d, struct usb_gadget_strings *, stringtabs,
227000a2430fSAndrzej Pietrasiewicz 			lang_count + 1);
227100a2430fSAndrzej Pietrasiewicz 		vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
227200a2430fSAndrzej Pietrasiewicz 		vla_item(d, struct usb_string, strings,
227300a2430fSAndrzej Pietrasiewicz 			lang_count*(needed_count+1));
227400a2430fSAndrzej Pietrasiewicz 
227500a2430fSAndrzej Pietrasiewicz 		char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
227600a2430fSAndrzej Pietrasiewicz 
227700a2430fSAndrzej Pietrasiewicz 		if (unlikely(!vlabuf)) {
227800a2430fSAndrzej Pietrasiewicz 			kfree(_data);
227900a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
228000a2430fSAndrzej Pietrasiewicz 		}
228100a2430fSAndrzej Pietrasiewicz 
228200a2430fSAndrzej Pietrasiewicz 		/* Initialize the VLA pointers */
228300a2430fSAndrzej Pietrasiewicz 		stringtabs = vla_ptr(vlabuf, d, stringtabs);
228400a2430fSAndrzej Pietrasiewicz 		t = vla_ptr(vlabuf, d, stringtab);
228500a2430fSAndrzej Pietrasiewicz 		i = lang_count;
228600a2430fSAndrzej Pietrasiewicz 		do {
228700a2430fSAndrzej Pietrasiewicz 			*stringtabs++ = t++;
228800a2430fSAndrzej Pietrasiewicz 		} while (--i);
228900a2430fSAndrzej Pietrasiewicz 		*stringtabs = NULL;
229000a2430fSAndrzej Pietrasiewicz 
229100a2430fSAndrzej Pietrasiewicz 		/* stringtabs = vlabuf = d_stringtabs for later kfree */
229200a2430fSAndrzej Pietrasiewicz 		stringtabs = vla_ptr(vlabuf, d, stringtabs);
229300a2430fSAndrzej Pietrasiewicz 		t = vla_ptr(vlabuf, d, stringtab);
229400a2430fSAndrzej Pietrasiewicz 		s = vla_ptr(vlabuf, d, strings);
229500a2430fSAndrzej Pietrasiewicz 		strings = s;
229600a2430fSAndrzej Pietrasiewicz 	}
229700a2430fSAndrzej Pietrasiewicz 
229800a2430fSAndrzej Pietrasiewicz 	/* For each language */
229900a2430fSAndrzej Pietrasiewicz 	data += 16;
230000a2430fSAndrzej Pietrasiewicz 	len -= 16;
230100a2430fSAndrzej Pietrasiewicz 
230200a2430fSAndrzej Pietrasiewicz 	do { /* lang_count > 0 so we can use do-while */
230300a2430fSAndrzej Pietrasiewicz 		unsigned needed = needed_count;
230400a2430fSAndrzej Pietrasiewicz 
230500a2430fSAndrzej Pietrasiewicz 		if (unlikely(len < 3))
230600a2430fSAndrzej Pietrasiewicz 			goto error_free;
230700a2430fSAndrzej Pietrasiewicz 		t->language = get_unaligned_le16(data);
230800a2430fSAndrzej Pietrasiewicz 		t->strings  = s;
230900a2430fSAndrzej Pietrasiewicz 		++t;
231000a2430fSAndrzej Pietrasiewicz 
231100a2430fSAndrzej Pietrasiewicz 		data += 2;
231200a2430fSAndrzej Pietrasiewicz 		len -= 2;
231300a2430fSAndrzej Pietrasiewicz 
231400a2430fSAndrzej Pietrasiewicz 		/* For each string */
231500a2430fSAndrzej Pietrasiewicz 		do { /* str_count > 0 so we can use do-while */
231600a2430fSAndrzej Pietrasiewicz 			size_t length = strnlen(data, len);
231700a2430fSAndrzej Pietrasiewicz 
231800a2430fSAndrzej Pietrasiewicz 			if (unlikely(length == len))
231900a2430fSAndrzej Pietrasiewicz 				goto error_free;
232000a2430fSAndrzej Pietrasiewicz 
232100a2430fSAndrzej Pietrasiewicz 			/*
232200a2430fSAndrzej Pietrasiewicz 			 * User may provide more strings then we need,
232300a2430fSAndrzej Pietrasiewicz 			 * if that's the case we simply ignore the
232400a2430fSAndrzej Pietrasiewicz 			 * rest
232500a2430fSAndrzej Pietrasiewicz 			 */
232600a2430fSAndrzej Pietrasiewicz 			if (likely(needed)) {
232700a2430fSAndrzej Pietrasiewicz 				/*
232800a2430fSAndrzej Pietrasiewicz 				 * s->id will be set while adding
232900a2430fSAndrzej Pietrasiewicz 				 * function to configuration so for
233000a2430fSAndrzej Pietrasiewicz 				 * now just leave garbage here.
233100a2430fSAndrzej Pietrasiewicz 				 */
233200a2430fSAndrzej Pietrasiewicz 				s->s = data;
233300a2430fSAndrzej Pietrasiewicz 				--needed;
233400a2430fSAndrzej Pietrasiewicz 				++s;
233500a2430fSAndrzej Pietrasiewicz 			}
233600a2430fSAndrzej Pietrasiewicz 
233700a2430fSAndrzej Pietrasiewicz 			data += length + 1;
233800a2430fSAndrzej Pietrasiewicz 			len -= length + 1;
233900a2430fSAndrzej Pietrasiewicz 		} while (--str_count);
234000a2430fSAndrzej Pietrasiewicz 
234100a2430fSAndrzej Pietrasiewicz 		s->id = 0;   /* terminator */
234200a2430fSAndrzej Pietrasiewicz 		s->s = NULL;
234300a2430fSAndrzej Pietrasiewicz 		++s;
234400a2430fSAndrzej Pietrasiewicz 
234500a2430fSAndrzej Pietrasiewicz 	} while (--lang_count);
234600a2430fSAndrzej Pietrasiewicz 
234700a2430fSAndrzej Pietrasiewicz 	/* Some garbage left? */
234800a2430fSAndrzej Pietrasiewicz 	if (unlikely(len))
234900a2430fSAndrzej Pietrasiewicz 		goto error_free;
235000a2430fSAndrzej Pietrasiewicz 
235100a2430fSAndrzej Pietrasiewicz 	/* Done! */
235200a2430fSAndrzej Pietrasiewicz 	ffs->stringtabs = stringtabs;
235300a2430fSAndrzej Pietrasiewicz 	ffs->raw_strings = _data;
235400a2430fSAndrzej Pietrasiewicz 
235500a2430fSAndrzej Pietrasiewicz 	return 0;
235600a2430fSAndrzej Pietrasiewicz 
235700a2430fSAndrzej Pietrasiewicz error_free:
235800a2430fSAndrzej Pietrasiewicz 	kfree(stringtabs);
235900a2430fSAndrzej Pietrasiewicz error:
236000a2430fSAndrzej Pietrasiewicz 	kfree(_data);
236100a2430fSAndrzej Pietrasiewicz 	return -EINVAL;
236200a2430fSAndrzej Pietrasiewicz }
236300a2430fSAndrzej Pietrasiewicz 
236400a2430fSAndrzej Pietrasiewicz 
236500a2430fSAndrzej Pietrasiewicz /* Events handling and management *******************************************/
236600a2430fSAndrzej Pietrasiewicz 
236700a2430fSAndrzej Pietrasiewicz static void __ffs_event_add(struct ffs_data *ffs,
236800a2430fSAndrzej Pietrasiewicz 			    enum usb_functionfs_event_type type)
236900a2430fSAndrzej Pietrasiewicz {
237000a2430fSAndrzej Pietrasiewicz 	enum usb_functionfs_event_type rem_type1, rem_type2 = type;
237100a2430fSAndrzej Pietrasiewicz 	int neg = 0;
237200a2430fSAndrzej Pietrasiewicz 
237300a2430fSAndrzej Pietrasiewicz 	/*
237400a2430fSAndrzej Pietrasiewicz 	 * Abort any unhandled setup
237500a2430fSAndrzej Pietrasiewicz 	 *
237600a2430fSAndrzej Pietrasiewicz 	 * We do not need to worry about some cmpxchg() changing value
237700a2430fSAndrzej Pietrasiewicz 	 * of ffs->setup_state without holding the lock because when
237800a2430fSAndrzej Pietrasiewicz 	 * state is FFS_SETUP_PENDING cmpxchg() in several places in
237900a2430fSAndrzej Pietrasiewicz 	 * the source does nothing.
238000a2430fSAndrzej Pietrasiewicz 	 */
238100a2430fSAndrzej Pietrasiewicz 	if (ffs->setup_state == FFS_SETUP_PENDING)
238200a2430fSAndrzej Pietrasiewicz 		ffs->setup_state = FFS_SETUP_CANCELLED;
238300a2430fSAndrzej Pietrasiewicz 
238467913bbdSMichal Nazarewicz 	/*
238567913bbdSMichal Nazarewicz 	 * Logic of this function guarantees that there are at most four pending
238667913bbdSMichal Nazarewicz 	 * evens on ffs->ev.types queue.  This is important because the queue
238767913bbdSMichal Nazarewicz 	 * has space for four elements only and __ffs_ep0_read_events function
238867913bbdSMichal Nazarewicz 	 * depends on that limit as well.  If more event types are added, those
238967913bbdSMichal Nazarewicz 	 * limits have to be revisited or guaranteed to still hold.
239067913bbdSMichal Nazarewicz 	 */
239100a2430fSAndrzej Pietrasiewicz 	switch (type) {
239200a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_RESUME:
239300a2430fSAndrzej Pietrasiewicz 		rem_type2 = FUNCTIONFS_SUSPEND;
239400a2430fSAndrzej Pietrasiewicz 		/* FALL THROUGH */
239500a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_SUSPEND:
239600a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_SETUP:
239700a2430fSAndrzej Pietrasiewicz 		rem_type1 = type;
239800a2430fSAndrzej Pietrasiewicz 		/* Discard all similar events */
239900a2430fSAndrzej Pietrasiewicz 		break;
240000a2430fSAndrzej Pietrasiewicz 
240100a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_BIND:
240200a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_UNBIND:
240300a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_DISABLE:
240400a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_ENABLE:
240500a2430fSAndrzej Pietrasiewicz 		/* Discard everything other then power management. */
240600a2430fSAndrzej Pietrasiewicz 		rem_type1 = FUNCTIONFS_SUSPEND;
240700a2430fSAndrzej Pietrasiewicz 		rem_type2 = FUNCTIONFS_RESUME;
240800a2430fSAndrzej Pietrasiewicz 		neg = 1;
240900a2430fSAndrzej Pietrasiewicz 		break;
241000a2430fSAndrzej Pietrasiewicz 
241100a2430fSAndrzej Pietrasiewicz 	default:
2412fe00bcbfSMichal Nazarewicz 		WARN(1, "%d: unknown event, this should not happen\n", type);
2413fe00bcbfSMichal Nazarewicz 		return;
241400a2430fSAndrzej Pietrasiewicz 	}
241500a2430fSAndrzej Pietrasiewicz 
241600a2430fSAndrzej Pietrasiewicz 	{
241700a2430fSAndrzej Pietrasiewicz 		u8 *ev  = ffs->ev.types, *out = ev;
241800a2430fSAndrzej Pietrasiewicz 		unsigned n = ffs->ev.count;
241900a2430fSAndrzej Pietrasiewicz 		for (; n; --n, ++ev)
242000a2430fSAndrzej Pietrasiewicz 			if ((*ev == rem_type1 || *ev == rem_type2) == neg)
242100a2430fSAndrzej Pietrasiewicz 				*out++ = *ev;
242200a2430fSAndrzej Pietrasiewicz 			else
242300a2430fSAndrzej Pietrasiewicz 				pr_vdebug("purging event %d\n", *ev);
242400a2430fSAndrzej Pietrasiewicz 		ffs->ev.count = out - ffs->ev.types;
242500a2430fSAndrzej Pietrasiewicz 	}
242600a2430fSAndrzej Pietrasiewicz 
242700a2430fSAndrzej Pietrasiewicz 	pr_vdebug("adding event %d\n", type);
242800a2430fSAndrzej Pietrasiewicz 	ffs->ev.types[ffs->ev.count++] = type;
242900a2430fSAndrzej Pietrasiewicz 	wake_up_locked(&ffs->ev.waitq);
24305e33f6fdSRobert Baldyga 	if (ffs->ffs_eventfd)
24315e33f6fdSRobert Baldyga 		eventfd_signal(ffs->ffs_eventfd, 1);
243200a2430fSAndrzej Pietrasiewicz }
243300a2430fSAndrzej Pietrasiewicz 
243400a2430fSAndrzej Pietrasiewicz static void ffs_event_add(struct ffs_data *ffs,
243500a2430fSAndrzej Pietrasiewicz 			  enum usb_functionfs_event_type type)
243600a2430fSAndrzej Pietrasiewicz {
243700a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
243800a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
243900a2430fSAndrzej Pietrasiewicz 	__ffs_event_add(ffs, type);
244000a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
244100a2430fSAndrzej Pietrasiewicz }
244200a2430fSAndrzej Pietrasiewicz 
244300a2430fSAndrzej Pietrasiewicz /* Bind/unbind USB function hooks *******************************************/
244400a2430fSAndrzej Pietrasiewicz 
24456d5c1c77SRobert Baldyga static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
24466d5c1c77SRobert Baldyga {
24476d5c1c77SRobert Baldyga 	int i;
24486d5c1c77SRobert Baldyga 
24496d5c1c77SRobert Baldyga 	for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
24506d5c1c77SRobert Baldyga 		if (ffs->eps_addrmap[i] == endpoint_address)
24516d5c1c77SRobert Baldyga 			return i;
24526d5c1c77SRobert Baldyga 	return -ENOENT;
24536d5c1c77SRobert Baldyga }
24546d5c1c77SRobert Baldyga 
245500a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
245600a2430fSAndrzej Pietrasiewicz 				    struct usb_descriptor_header *desc,
245700a2430fSAndrzej Pietrasiewicz 				    void *priv)
245800a2430fSAndrzej Pietrasiewicz {
245900a2430fSAndrzej Pietrasiewicz 	struct usb_endpoint_descriptor *ds = (void *)desc;
246000a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = priv;
246100a2430fSAndrzej Pietrasiewicz 	struct ffs_ep *ffs_ep;
246285b06f5eSDan Carpenter 	unsigned ep_desc_id;
246385b06f5eSDan Carpenter 	int idx;
246400a2430fSAndrzej Pietrasiewicz 	static const char *speed_names[] = { "full", "high", "super" };
246500a2430fSAndrzej Pietrasiewicz 
246600a2430fSAndrzej Pietrasiewicz 	if (type != FFS_DESCRIPTOR)
246700a2430fSAndrzej Pietrasiewicz 		return 0;
246800a2430fSAndrzej Pietrasiewicz 
246900a2430fSAndrzej Pietrasiewicz 	/*
247000a2430fSAndrzej Pietrasiewicz 	 * If ss_descriptors is not NULL, we are reading super speed
247100a2430fSAndrzej Pietrasiewicz 	 * descriptors; if hs_descriptors is not NULL, we are reading high
247200a2430fSAndrzej Pietrasiewicz 	 * speed descriptors; otherwise, we are reading full speed
247300a2430fSAndrzej Pietrasiewicz 	 * descriptors.
247400a2430fSAndrzej Pietrasiewicz 	 */
247500a2430fSAndrzej Pietrasiewicz 	if (func->function.ss_descriptors) {
247600a2430fSAndrzej Pietrasiewicz 		ep_desc_id = 2;
247700a2430fSAndrzej Pietrasiewicz 		func->function.ss_descriptors[(long)valuep] = desc;
247800a2430fSAndrzej Pietrasiewicz 	} else if (func->function.hs_descriptors) {
247900a2430fSAndrzej Pietrasiewicz 		ep_desc_id = 1;
248000a2430fSAndrzej Pietrasiewicz 		func->function.hs_descriptors[(long)valuep] = desc;
248100a2430fSAndrzej Pietrasiewicz 	} else {
248200a2430fSAndrzej Pietrasiewicz 		ep_desc_id = 0;
248300a2430fSAndrzej Pietrasiewicz 		func->function.fs_descriptors[(long)valuep]    = desc;
248400a2430fSAndrzej Pietrasiewicz 	}
248500a2430fSAndrzej Pietrasiewicz 
248600a2430fSAndrzej Pietrasiewicz 	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
248700a2430fSAndrzej Pietrasiewicz 		return 0;
248800a2430fSAndrzej Pietrasiewicz 
24896d5c1c77SRobert Baldyga 	idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
24906d5c1c77SRobert Baldyga 	if (idx < 0)
24916d5c1c77SRobert Baldyga 		return idx;
24926d5c1c77SRobert Baldyga 
249300a2430fSAndrzej Pietrasiewicz 	ffs_ep = func->eps + idx;
249400a2430fSAndrzej Pietrasiewicz 
249500a2430fSAndrzej Pietrasiewicz 	if (unlikely(ffs_ep->descs[ep_desc_id])) {
249600a2430fSAndrzej Pietrasiewicz 		pr_err("two %sspeed descriptors for EP %d\n",
249700a2430fSAndrzej Pietrasiewicz 			  speed_names[ep_desc_id],
249800a2430fSAndrzej Pietrasiewicz 			  ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
249900a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
250000a2430fSAndrzej Pietrasiewicz 	}
250100a2430fSAndrzej Pietrasiewicz 	ffs_ep->descs[ep_desc_id] = ds;
250200a2430fSAndrzej Pietrasiewicz 
250300a2430fSAndrzej Pietrasiewicz 	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
250400a2430fSAndrzej Pietrasiewicz 	if (ffs_ep->ep) {
250500a2430fSAndrzej Pietrasiewicz 		ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
250600a2430fSAndrzej Pietrasiewicz 		if (!ds->wMaxPacketSize)
250700a2430fSAndrzej Pietrasiewicz 			ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
250800a2430fSAndrzej Pietrasiewicz 	} else {
250900a2430fSAndrzej Pietrasiewicz 		struct usb_request *req;
251000a2430fSAndrzej Pietrasiewicz 		struct usb_ep *ep;
25111b0bf88fSRobert Baldyga 		u8 bEndpointAddress;
251200a2430fSAndrzej Pietrasiewicz 
25131b0bf88fSRobert Baldyga 		/*
25141b0bf88fSRobert Baldyga 		 * We back up bEndpointAddress because autoconfig overwrites
25151b0bf88fSRobert Baldyga 		 * it with physical endpoint address.
25161b0bf88fSRobert Baldyga 		 */
25171b0bf88fSRobert Baldyga 		bEndpointAddress = ds->bEndpointAddress;
251800a2430fSAndrzej Pietrasiewicz 		pr_vdebug("autoconfig\n");
251900a2430fSAndrzej Pietrasiewicz 		ep = usb_ep_autoconfig(func->gadget, ds);
252000a2430fSAndrzej Pietrasiewicz 		if (unlikely(!ep))
252100a2430fSAndrzej Pietrasiewicz 			return -ENOTSUPP;
252200a2430fSAndrzej Pietrasiewicz 		ep->driver_data = func->eps + idx;
252300a2430fSAndrzej Pietrasiewicz 
252400a2430fSAndrzej Pietrasiewicz 		req = usb_ep_alloc_request(ep, GFP_KERNEL);
252500a2430fSAndrzej Pietrasiewicz 		if (unlikely(!req))
252600a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
252700a2430fSAndrzej Pietrasiewicz 
252800a2430fSAndrzej Pietrasiewicz 		ffs_ep->ep  = ep;
252900a2430fSAndrzej Pietrasiewicz 		ffs_ep->req = req;
253000a2430fSAndrzej Pietrasiewicz 		func->eps_revmap[ds->bEndpointAddress &
253100a2430fSAndrzej Pietrasiewicz 				 USB_ENDPOINT_NUMBER_MASK] = idx + 1;
25321b0bf88fSRobert Baldyga 		/*
25331b0bf88fSRobert Baldyga 		 * If we use virtual address mapping, we restore
25341b0bf88fSRobert Baldyga 		 * original bEndpointAddress value.
25351b0bf88fSRobert Baldyga 		 */
25361b0bf88fSRobert Baldyga 		if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
25371b0bf88fSRobert Baldyga 			ds->bEndpointAddress = bEndpointAddress;
253800a2430fSAndrzej Pietrasiewicz 	}
253900a2430fSAndrzej Pietrasiewicz 	ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
254000a2430fSAndrzej Pietrasiewicz 
254100a2430fSAndrzej Pietrasiewicz 	return 0;
254200a2430fSAndrzej Pietrasiewicz }
254300a2430fSAndrzej Pietrasiewicz 
254400a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
254500a2430fSAndrzej Pietrasiewicz 				   struct usb_descriptor_header *desc,
254600a2430fSAndrzej Pietrasiewicz 				   void *priv)
254700a2430fSAndrzej Pietrasiewicz {
254800a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = priv;
254900a2430fSAndrzej Pietrasiewicz 	unsigned idx;
255000a2430fSAndrzej Pietrasiewicz 	u8 newValue;
255100a2430fSAndrzej Pietrasiewicz 
255200a2430fSAndrzej Pietrasiewicz 	switch (type) {
255300a2430fSAndrzej Pietrasiewicz 	default:
255400a2430fSAndrzej Pietrasiewicz 	case FFS_DESCRIPTOR:
255500a2430fSAndrzej Pietrasiewicz 		/* Handled in previous pass by __ffs_func_bind_do_descs() */
255600a2430fSAndrzej Pietrasiewicz 		return 0;
255700a2430fSAndrzej Pietrasiewicz 
255800a2430fSAndrzej Pietrasiewicz 	case FFS_INTERFACE:
255900a2430fSAndrzej Pietrasiewicz 		idx = *valuep;
256000a2430fSAndrzej Pietrasiewicz 		if (func->interfaces_nums[idx] < 0) {
256100a2430fSAndrzej Pietrasiewicz 			int id = usb_interface_id(func->conf, &func->function);
256200a2430fSAndrzej Pietrasiewicz 			if (unlikely(id < 0))
256300a2430fSAndrzej Pietrasiewicz 				return id;
256400a2430fSAndrzej Pietrasiewicz 			func->interfaces_nums[idx] = id;
256500a2430fSAndrzej Pietrasiewicz 		}
256600a2430fSAndrzej Pietrasiewicz 		newValue = func->interfaces_nums[idx];
256700a2430fSAndrzej Pietrasiewicz 		break;
256800a2430fSAndrzej Pietrasiewicz 
256900a2430fSAndrzej Pietrasiewicz 	case FFS_STRING:
257000a2430fSAndrzej Pietrasiewicz 		/* String' IDs are allocated when fsf_data is bound to cdev */
257100a2430fSAndrzej Pietrasiewicz 		newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
257200a2430fSAndrzej Pietrasiewicz 		break;
257300a2430fSAndrzej Pietrasiewicz 
257400a2430fSAndrzej Pietrasiewicz 	case FFS_ENDPOINT:
257500a2430fSAndrzej Pietrasiewicz 		/*
257600a2430fSAndrzej Pietrasiewicz 		 * USB_DT_ENDPOINT are handled in
257700a2430fSAndrzej Pietrasiewicz 		 * __ffs_func_bind_do_descs().
257800a2430fSAndrzej Pietrasiewicz 		 */
257900a2430fSAndrzej Pietrasiewicz 		if (desc->bDescriptorType == USB_DT_ENDPOINT)
258000a2430fSAndrzej Pietrasiewicz 			return 0;
258100a2430fSAndrzej Pietrasiewicz 
258200a2430fSAndrzej Pietrasiewicz 		idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
258300a2430fSAndrzej Pietrasiewicz 		if (unlikely(!func->eps[idx].ep))
258400a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
258500a2430fSAndrzej Pietrasiewicz 
258600a2430fSAndrzej Pietrasiewicz 		{
258700a2430fSAndrzej Pietrasiewicz 			struct usb_endpoint_descriptor **descs;
258800a2430fSAndrzej Pietrasiewicz 			descs = func->eps[idx].descs;
258900a2430fSAndrzej Pietrasiewicz 			newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
259000a2430fSAndrzej Pietrasiewicz 		}
259100a2430fSAndrzej Pietrasiewicz 		break;
259200a2430fSAndrzej Pietrasiewicz 	}
259300a2430fSAndrzej Pietrasiewicz 
259400a2430fSAndrzej Pietrasiewicz 	pr_vdebug("%02x -> %02x\n", *valuep, newValue);
259500a2430fSAndrzej Pietrasiewicz 	*valuep = newValue;
259600a2430fSAndrzej Pietrasiewicz 	return 0;
259700a2430fSAndrzej Pietrasiewicz }
259800a2430fSAndrzej Pietrasiewicz 
259900a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
260000a2430fSAndrzej Pietrasiewicz 				      struct usb_os_desc_header *h, void *data,
260100a2430fSAndrzej Pietrasiewicz 				      unsigned len, void *priv)
260200a2430fSAndrzej Pietrasiewicz {
260300a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = priv;
260400a2430fSAndrzej Pietrasiewicz 	u8 length = 0;
260500a2430fSAndrzej Pietrasiewicz 
260600a2430fSAndrzej Pietrasiewicz 	switch (type) {
260700a2430fSAndrzej Pietrasiewicz 	case FFS_OS_DESC_EXT_COMPAT: {
260800a2430fSAndrzej Pietrasiewicz 		struct usb_ext_compat_desc *desc = data;
260900a2430fSAndrzej Pietrasiewicz 		struct usb_os_desc_table *t;
261000a2430fSAndrzej Pietrasiewicz 
261100a2430fSAndrzej Pietrasiewicz 		t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
261200a2430fSAndrzej Pietrasiewicz 		t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
261300a2430fSAndrzej Pietrasiewicz 		memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID,
261400a2430fSAndrzej Pietrasiewicz 		       ARRAY_SIZE(desc->CompatibleID) +
261500a2430fSAndrzej Pietrasiewicz 		       ARRAY_SIZE(desc->SubCompatibleID));
261600a2430fSAndrzej Pietrasiewicz 		length = sizeof(*desc);
261700a2430fSAndrzej Pietrasiewicz 	}
261800a2430fSAndrzej Pietrasiewicz 		break;
261900a2430fSAndrzej Pietrasiewicz 	case FFS_OS_DESC_EXT_PROP: {
262000a2430fSAndrzej Pietrasiewicz 		struct usb_ext_prop_desc *desc = data;
262100a2430fSAndrzej Pietrasiewicz 		struct usb_os_desc_table *t;
262200a2430fSAndrzej Pietrasiewicz 		struct usb_os_desc_ext_prop *ext_prop;
262300a2430fSAndrzej Pietrasiewicz 		char *ext_prop_name;
262400a2430fSAndrzej Pietrasiewicz 		char *ext_prop_data;
262500a2430fSAndrzej Pietrasiewicz 
262600a2430fSAndrzej Pietrasiewicz 		t = &func->function.os_desc_table[h->interface];
262700a2430fSAndrzej Pietrasiewicz 		t->if_id = func->interfaces_nums[h->interface];
262800a2430fSAndrzej Pietrasiewicz 
262900a2430fSAndrzej Pietrasiewicz 		ext_prop = func->ffs->ms_os_descs_ext_prop_avail;
263000a2430fSAndrzej Pietrasiewicz 		func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop);
263100a2430fSAndrzej Pietrasiewicz 
263200a2430fSAndrzej Pietrasiewicz 		ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
263300a2430fSAndrzej Pietrasiewicz 		ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
263400a2430fSAndrzej Pietrasiewicz 		ext_prop->data_len = le32_to_cpu(*(u32 *)
263500a2430fSAndrzej Pietrasiewicz 			usb_ext_prop_data_len_ptr(data, ext_prop->name_len));
263600a2430fSAndrzej Pietrasiewicz 		length = ext_prop->name_len + ext_prop->data_len + 14;
263700a2430fSAndrzej Pietrasiewicz 
263800a2430fSAndrzej Pietrasiewicz 		ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail;
263900a2430fSAndrzej Pietrasiewicz 		func->ffs->ms_os_descs_ext_prop_name_avail +=
264000a2430fSAndrzej Pietrasiewicz 			ext_prop->name_len;
264100a2430fSAndrzej Pietrasiewicz 
264200a2430fSAndrzej Pietrasiewicz 		ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
264300a2430fSAndrzej Pietrasiewicz 		func->ffs->ms_os_descs_ext_prop_data_avail +=
264400a2430fSAndrzej Pietrasiewicz 			ext_prop->data_len;
264500a2430fSAndrzej Pietrasiewicz 		memcpy(ext_prop_data,
264600a2430fSAndrzej Pietrasiewicz 		       usb_ext_prop_data_ptr(data, ext_prop->name_len),
264700a2430fSAndrzej Pietrasiewicz 		       ext_prop->data_len);
264800a2430fSAndrzej Pietrasiewicz 		/* unicode data reported to the host as "WCHAR"s */
264900a2430fSAndrzej Pietrasiewicz 		switch (ext_prop->type) {
265000a2430fSAndrzej Pietrasiewicz 		case USB_EXT_PROP_UNICODE:
265100a2430fSAndrzej Pietrasiewicz 		case USB_EXT_PROP_UNICODE_ENV:
265200a2430fSAndrzej Pietrasiewicz 		case USB_EXT_PROP_UNICODE_LINK:
265300a2430fSAndrzej Pietrasiewicz 		case USB_EXT_PROP_UNICODE_MULTI:
265400a2430fSAndrzej Pietrasiewicz 			ext_prop->data_len *= 2;
265500a2430fSAndrzej Pietrasiewicz 			break;
265600a2430fSAndrzej Pietrasiewicz 		}
265700a2430fSAndrzej Pietrasiewicz 		ext_prop->data = ext_prop_data;
265800a2430fSAndrzej Pietrasiewicz 
265900a2430fSAndrzej Pietrasiewicz 		memcpy(ext_prop_name, usb_ext_prop_name_ptr(data),
266000a2430fSAndrzej Pietrasiewicz 		       ext_prop->name_len);
266100a2430fSAndrzej Pietrasiewicz 		/* property name reported to the host as "WCHAR"s */
266200a2430fSAndrzej Pietrasiewicz 		ext_prop->name_len *= 2;
266300a2430fSAndrzej Pietrasiewicz 		ext_prop->name = ext_prop_name;
266400a2430fSAndrzej Pietrasiewicz 
266500a2430fSAndrzej Pietrasiewicz 		t->os_desc->ext_prop_len +=
266600a2430fSAndrzej Pietrasiewicz 			ext_prop->name_len + ext_prop->data_len + 14;
266700a2430fSAndrzej Pietrasiewicz 		++t->os_desc->ext_prop_count;
266800a2430fSAndrzej Pietrasiewicz 		list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop);
266900a2430fSAndrzej Pietrasiewicz 	}
267000a2430fSAndrzej Pietrasiewicz 		break;
267100a2430fSAndrzej Pietrasiewicz 	default:
267200a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unknown descriptor: %d\n", type);
267300a2430fSAndrzej Pietrasiewicz 	}
267400a2430fSAndrzej Pietrasiewicz 
267500a2430fSAndrzej Pietrasiewicz 	return length;
267600a2430fSAndrzej Pietrasiewicz }
267700a2430fSAndrzej Pietrasiewicz 
267800a2430fSAndrzej Pietrasiewicz static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
267900a2430fSAndrzej Pietrasiewicz 						struct usb_configuration *c)
268000a2430fSAndrzej Pietrasiewicz {
268100a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
268200a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *ffs_opts =
268300a2430fSAndrzej Pietrasiewicz 		container_of(f->fi, struct f_fs_opts, func_inst);
268400a2430fSAndrzej Pietrasiewicz 	int ret;
268500a2430fSAndrzej Pietrasiewicz 
268600a2430fSAndrzej Pietrasiewicz 	ENTER();
268700a2430fSAndrzej Pietrasiewicz 
268800a2430fSAndrzej Pietrasiewicz 	/*
268900a2430fSAndrzej Pietrasiewicz 	 * Legacy gadget triggers binding in functionfs_ready_callback,
269000a2430fSAndrzej Pietrasiewicz 	 * which already uses locking; taking the same lock here would
269100a2430fSAndrzej Pietrasiewicz 	 * cause a deadlock.
269200a2430fSAndrzej Pietrasiewicz 	 *
269300a2430fSAndrzej Pietrasiewicz 	 * Configfs-enabled gadgets however do need ffs_dev_lock.
269400a2430fSAndrzej Pietrasiewicz 	 */
269500a2430fSAndrzej Pietrasiewicz 	if (!ffs_opts->no_configfs)
269600a2430fSAndrzej Pietrasiewicz 		ffs_dev_lock();
269700a2430fSAndrzej Pietrasiewicz 	ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
269800a2430fSAndrzej Pietrasiewicz 	func->ffs = ffs_opts->dev->ffs_data;
269900a2430fSAndrzej Pietrasiewicz 	if (!ffs_opts->no_configfs)
270000a2430fSAndrzej Pietrasiewicz 		ffs_dev_unlock();
270100a2430fSAndrzej Pietrasiewicz 	if (ret)
270200a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(ret);
270300a2430fSAndrzej Pietrasiewicz 
270400a2430fSAndrzej Pietrasiewicz 	func->conf = c;
270500a2430fSAndrzej Pietrasiewicz 	func->gadget = c->cdev->gadget;
270600a2430fSAndrzej Pietrasiewicz 
270700a2430fSAndrzej Pietrasiewicz 	/*
270800a2430fSAndrzej Pietrasiewicz 	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
270900a2430fSAndrzej Pietrasiewicz 	 * configurations are bound in sequence with list_for_each_entry,
271000a2430fSAndrzej Pietrasiewicz 	 * in each configuration its functions are bound in sequence
271100a2430fSAndrzej Pietrasiewicz 	 * with list_for_each_entry, so we assume no race condition
271200a2430fSAndrzej Pietrasiewicz 	 * with regard to ffs_opts->bound access
271300a2430fSAndrzej Pietrasiewicz 	 */
271400a2430fSAndrzej Pietrasiewicz 	if (!ffs_opts->refcnt) {
271500a2430fSAndrzej Pietrasiewicz 		ret = functionfs_bind(func->ffs, c->cdev);
271600a2430fSAndrzej Pietrasiewicz 		if (ret)
271700a2430fSAndrzej Pietrasiewicz 			return ERR_PTR(ret);
271800a2430fSAndrzej Pietrasiewicz 	}
271900a2430fSAndrzej Pietrasiewicz 	ffs_opts->refcnt++;
272000a2430fSAndrzej Pietrasiewicz 	func->function.strings = func->ffs->stringtabs;
272100a2430fSAndrzej Pietrasiewicz 
272200a2430fSAndrzej Pietrasiewicz 	return ffs_opts;
272300a2430fSAndrzej Pietrasiewicz }
272400a2430fSAndrzej Pietrasiewicz 
272500a2430fSAndrzej Pietrasiewicz static int _ffs_func_bind(struct usb_configuration *c,
272600a2430fSAndrzej Pietrasiewicz 			  struct usb_function *f)
272700a2430fSAndrzej Pietrasiewicz {
272800a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
272900a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = func->ffs;
273000a2430fSAndrzej Pietrasiewicz 
273100a2430fSAndrzej Pietrasiewicz 	const int full = !!func->ffs->fs_descs_count;
273200a2430fSAndrzej Pietrasiewicz 	const int high = gadget_is_dualspeed(func->gadget) &&
273300a2430fSAndrzej Pietrasiewicz 		func->ffs->hs_descs_count;
273400a2430fSAndrzej Pietrasiewicz 	const int super = gadget_is_superspeed(func->gadget) &&
273500a2430fSAndrzej Pietrasiewicz 		func->ffs->ss_descs_count;
273600a2430fSAndrzej Pietrasiewicz 
273700a2430fSAndrzej Pietrasiewicz 	int fs_len, hs_len, ss_len, ret, i;
273800a2430fSAndrzej Pietrasiewicz 
273900a2430fSAndrzej Pietrasiewicz 	/* Make it a single chunk, less management later on */
274000a2430fSAndrzej Pietrasiewicz 	vla_group(d);
274100a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count);
274200a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs,
274300a2430fSAndrzej Pietrasiewicz 		full ? ffs->fs_descs_count + 1 : 0);
274400a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
274500a2430fSAndrzej Pietrasiewicz 		high ? ffs->hs_descs_count + 1 : 0);
274600a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
274700a2430fSAndrzej Pietrasiewicz 		super ? ffs->ss_descs_count + 1 : 0);
274800a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, short, inums, ffs->interfaces_count);
274900a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table,
275000a2430fSAndrzej Pietrasiewicz 			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
275100a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, char[16], ext_compat,
275200a2430fSAndrzej Pietrasiewicz 			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
275300a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_os_desc, os_desc,
275400a2430fSAndrzej Pietrasiewicz 			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
275500a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop,
275600a2430fSAndrzej Pietrasiewicz 			 ffs->ms_os_descs_ext_prop_count);
275700a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, char, ext_prop_name,
275800a2430fSAndrzej Pietrasiewicz 			 ffs->ms_os_descs_ext_prop_name_len);
275900a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, char, ext_prop_data,
276000a2430fSAndrzej Pietrasiewicz 			 ffs->ms_os_descs_ext_prop_data_len);
276100a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
276200a2430fSAndrzej Pietrasiewicz 	char *vlabuf;
276300a2430fSAndrzej Pietrasiewicz 
276400a2430fSAndrzej Pietrasiewicz 	ENTER();
276500a2430fSAndrzej Pietrasiewicz 
276600a2430fSAndrzej Pietrasiewicz 	/* Has descriptors only for speeds gadget does not support */
276700a2430fSAndrzej Pietrasiewicz 	if (unlikely(!(full | high | super)))
276800a2430fSAndrzej Pietrasiewicz 		return -ENOTSUPP;
276900a2430fSAndrzej Pietrasiewicz 
277000a2430fSAndrzej Pietrasiewicz 	/* Allocate a single chunk, less management later on */
277100a2430fSAndrzej Pietrasiewicz 	vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL);
277200a2430fSAndrzej Pietrasiewicz 	if (unlikely(!vlabuf))
277300a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
277400a2430fSAndrzej Pietrasiewicz 
277500a2430fSAndrzej Pietrasiewicz 	ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
277600a2430fSAndrzej Pietrasiewicz 	ffs->ms_os_descs_ext_prop_name_avail =
277700a2430fSAndrzej Pietrasiewicz 		vla_ptr(vlabuf, d, ext_prop_name);
277800a2430fSAndrzej Pietrasiewicz 	ffs->ms_os_descs_ext_prop_data_avail =
277900a2430fSAndrzej Pietrasiewicz 		vla_ptr(vlabuf, d, ext_prop_data);
278000a2430fSAndrzej Pietrasiewicz 
278100a2430fSAndrzej Pietrasiewicz 	/* Copy descriptors  */
278200a2430fSAndrzej Pietrasiewicz 	memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
278300a2430fSAndrzej Pietrasiewicz 	       ffs->raw_descs_length);
278400a2430fSAndrzej Pietrasiewicz 
278500a2430fSAndrzej Pietrasiewicz 	memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
278600a2430fSAndrzej Pietrasiewicz 	for (ret = ffs->eps_count; ret; --ret) {
278700a2430fSAndrzej Pietrasiewicz 		struct ffs_ep *ptr;
278800a2430fSAndrzej Pietrasiewicz 
278900a2430fSAndrzej Pietrasiewicz 		ptr = vla_ptr(vlabuf, d, eps);
279000a2430fSAndrzej Pietrasiewicz 		ptr[ret].num = -1;
279100a2430fSAndrzej Pietrasiewicz 	}
279200a2430fSAndrzej Pietrasiewicz 
279300a2430fSAndrzej Pietrasiewicz 	/* Save pointers
279400a2430fSAndrzej Pietrasiewicz 	 * d_eps == vlabuf, func->eps used to kfree vlabuf later
279500a2430fSAndrzej Pietrasiewicz 	*/
279600a2430fSAndrzej Pietrasiewicz 	func->eps             = vla_ptr(vlabuf, d, eps);
279700a2430fSAndrzej Pietrasiewicz 	func->interfaces_nums = vla_ptr(vlabuf, d, inums);
279800a2430fSAndrzej Pietrasiewicz 
279900a2430fSAndrzej Pietrasiewicz 	/*
280000a2430fSAndrzej Pietrasiewicz 	 * Go through all the endpoint descriptors and allocate
280100a2430fSAndrzej Pietrasiewicz 	 * endpoints first, so that later we can rewrite the endpoint
280200a2430fSAndrzej Pietrasiewicz 	 * numbers without worrying that it may be described later on.
280300a2430fSAndrzej Pietrasiewicz 	 */
280400a2430fSAndrzej Pietrasiewicz 	if (likely(full)) {
280500a2430fSAndrzej Pietrasiewicz 		func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
280600a2430fSAndrzej Pietrasiewicz 		fs_len = ffs_do_descs(ffs->fs_descs_count,
280700a2430fSAndrzej Pietrasiewicz 				      vla_ptr(vlabuf, d, raw_descs),
280800a2430fSAndrzej Pietrasiewicz 				      d_raw_descs__sz,
280900a2430fSAndrzej Pietrasiewicz 				      __ffs_func_bind_do_descs, func);
281000a2430fSAndrzej Pietrasiewicz 		if (unlikely(fs_len < 0)) {
281100a2430fSAndrzej Pietrasiewicz 			ret = fs_len;
281200a2430fSAndrzej Pietrasiewicz 			goto error;
281300a2430fSAndrzej Pietrasiewicz 		}
281400a2430fSAndrzej Pietrasiewicz 	} else {
281500a2430fSAndrzej Pietrasiewicz 		fs_len = 0;
281600a2430fSAndrzej Pietrasiewicz 	}
281700a2430fSAndrzej Pietrasiewicz 
281800a2430fSAndrzej Pietrasiewicz 	if (likely(high)) {
281900a2430fSAndrzej Pietrasiewicz 		func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
282000a2430fSAndrzej Pietrasiewicz 		hs_len = ffs_do_descs(ffs->hs_descs_count,
282100a2430fSAndrzej Pietrasiewicz 				      vla_ptr(vlabuf, d, raw_descs) + fs_len,
282200a2430fSAndrzej Pietrasiewicz 				      d_raw_descs__sz - fs_len,
282300a2430fSAndrzej Pietrasiewicz 				      __ffs_func_bind_do_descs, func);
282400a2430fSAndrzej Pietrasiewicz 		if (unlikely(hs_len < 0)) {
282500a2430fSAndrzej Pietrasiewicz 			ret = hs_len;
282600a2430fSAndrzej Pietrasiewicz 			goto error;
282700a2430fSAndrzej Pietrasiewicz 		}
282800a2430fSAndrzej Pietrasiewicz 	} else {
282900a2430fSAndrzej Pietrasiewicz 		hs_len = 0;
283000a2430fSAndrzej Pietrasiewicz 	}
283100a2430fSAndrzej Pietrasiewicz 
283200a2430fSAndrzej Pietrasiewicz 	if (likely(super)) {
283300a2430fSAndrzej Pietrasiewicz 		func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
283400a2430fSAndrzej Pietrasiewicz 		ss_len = ffs_do_descs(ffs->ss_descs_count,
283500a2430fSAndrzej Pietrasiewicz 				vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
283600a2430fSAndrzej Pietrasiewicz 				d_raw_descs__sz - fs_len - hs_len,
283700a2430fSAndrzej Pietrasiewicz 				__ffs_func_bind_do_descs, func);
283800a2430fSAndrzej Pietrasiewicz 		if (unlikely(ss_len < 0)) {
283900a2430fSAndrzej Pietrasiewicz 			ret = ss_len;
284000a2430fSAndrzej Pietrasiewicz 			goto error;
284100a2430fSAndrzej Pietrasiewicz 		}
284200a2430fSAndrzej Pietrasiewicz 	} else {
284300a2430fSAndrzej Pietrasiewicz 		ss_len = 0;
284400a2430fSAndrzej Pietrasiewicz 	}
284500a2430fSAndrzej Pietrasiewicz 
284600a2430fSAndrzej Pietrasiewicz 	/*
284700a2430fSAndrzej Pietrasiewicz 	 * Now handle interface numbers allocation and interface and
284800a2430fSAndrzej Pietrasiewicz 	 * endpoint numbers rewriting.  We can do that in one go
284900a2430fSAndrzej Pietrasiewicz 	 * now.
285000a2430fSAndrzej Pietrasiewicz 	 */
285100a2430fSAndrzej Pietrasiewicz 	ret = ffs_do_descs(ffs->fs_descs_count +
285200a2430fSAndrzej Pietrasiewicz 			   (high ? ffs->hs_descs_count : 0) +
285300a2430fSAndrzej Pietrasiewicz 			   (super ? ffs->ss_descs_count : 0),
285400a2430fSAndrzej Pietrasiewicz 			   vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
285500a2430fSAndrzej Pietrasiewicz 			   __ffs_func_bind_do_nums, func);
285600a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret < 0))
285700a2430fSAndrzej Pietrasiewicz 		goto error;
285800a2430fSAndrzej Pietrasiewicz 
285900a2430fSAndrzej Pietrasiewicz 	func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
286000a2430fSAndrzej Pietrasiewicz 	if (c->cdev->use_os_string)
286100a2430fSAndrzej Pietrasiewicz 		for (i = 0; i < ffs->interfaces_count; ++i) {
286200a2430fSAndrzej Pietrasiewicz 			struct usb_os_desc *desc;
286300a2430fSAndrzej Pietrasiewicz 
286400a2430fSAndrzej Pietrasiewicz 			desc = func->function.os_desc_table[i].os_desc =
286500a2430fSAndrzej Pietrasiewicz 				vla_ptr(vlabuf, d, os_desc) +
286600a2430fSAndrzej Pietrasiewicz 				i * sizeof(struct usb_os_desc);
286700a2430fSAndrzej Pietrasiewicz 			desc->ext_compat_id =
286800a2430fSAndrzej Pietrasiewicz 				vla_ptr(vlabuf, d, ext_compat) + i * 16;
286900a2430fSAndrzej Pietrasiewicz 			INIT_LIST_HEAD(&desc->ext_prop);
287000a2430fSAndrzej Pietrasiewicz 		}
287100a2430fSAndrzej Pietrasiewicz 	ret = ffs_do_os_descs(ffs->ms_os_descs_count,
287200a2430fSAndrzej Pietrasiewicz 			      vla_ptr(vlabuf, d, raw_descs) +
287300a2430fSAndrzej Pietrasiewicz 			      fs_len + hs_len + ss_len,
287400a2430fSAndrzej Pietrasiewicz 			      d_raw_descs__sz - fs_len - hs_len - ss_len,
287500a2430fSAndrzej Pietrasiewicz 			      __ffs_func_bind_do_os_desc, func);
287600a2430fSAndrzej Pietrasiewicz 	if (unlikely(ret < 0))
287700a2430fSAndrzej Pietrasiewicz 		goto error;
287800a2430fSAndrzej Pietrasiewicz 	func->function.os_desc_n =
287900a2430fSAndrzej Pietrasiewicz 		c->cdev->use_os_string ? ffs->interfaces_count : 0;
288000a2430fSAndrzej Pietrasiewicz 
288100a2430fSAndrzej Pietrasiewicz 	/* And we're done */
288200a2430fSAndrzej Pietrasiewicz 	ffs_event_add(ffs, FUNCTIONFS_BIND);
288300a2430fSAndrzej Pietrasiewicz 	return 0;
288400a2430fSAndrzej Pietrasiewicz 
288500a2430fSAndrzej Pietrasiewicz error:
288600a2430fSAndrzej Pietrasiewicz 	/* XXX Do we need to release all claimed endpoints here? */
288700a2430fSAndrzej Pietrasiewicz 	return ret;
288800a2430fSAndrzej Pietrasiewicz }
288900a2430fSAndrzej Pietrasiewicz 
289000a2430fSAndrzej Pietrasiewicz static int ffs_func_bind(struct usb_configuration *c,
289100a2430fSAndrzej Pietrasiewicz 			 struct usb_function *f)
289200a2430fSAndrzej Pietrasiewicz {
289300a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c);
289455d81121SRobert Baldyga 	struct ffs_function *func = ffs_func_from_usb(f);
289555d81121SRobert Baldyga 	int ret;
289600a2430fSAndrzej Pietrasiewicz 
289700a2430fSAndrzej Pietrasiewicz 	if (IS_ERR(ffs_opts))
289800a2430fSAndrzej Pietrasiewicz 		return PTR_ERR(ffs_opts);
289900a2430fSAndrzej Pietrasiewicz 
290055d81121SRobert Baldyga 	ret = _ffs_func_bind(c, f);
290155d81121SRobert Baldyga 	if (ret && !--ffs_opts->refcnt)
290255d81121SRobert Baldyga 		functionfs_unbind(func->ffs);
290355d81121SRobert Baldyga 
290455d81121SRobert Baldyga 	return ret;
290500a2430fSAndrzej Pietrasiewicz }
290600a2430fSAndrzej Pietrasiewicz 
290700a2430fSAndrzej Pietrasiewicz 
290800a2430fSAndrzej Pietrasiewicz /* Other USB function hooks *************************************************/
290900a2430fSAndrzej Pietrasiewicz 
291018d6b32fSRobert Baldyga static void ffs_reset_work(struct work_struct *work)
291118d6b32fSRobert Baldyga {
291218d6b32fSRobert Baldyga 	struct ffs_data *ffs = container_of(work,
291318d6b32fSRobert Baldyga 		struct ffs_data, reset_work);
291418d6b32fSRobert Baldyga 	ffs_data_reset(ffs);
291518d6b32fSRobert Baldyga }
291618d6b32fSRobert Baldyga 
291700a2430fSAndrzej Pietrasiewicz static int ffs_func_set_alt(struct usb_function *f,
291800a2430fSAndrzej Pietrasiewicz 			    unsigned interface, unsigned alt)
291900a2430fSAndrzej Pietrasiewicz {
292000a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
292100a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = func->ffs;
292200a2430fSAndrzej Pietrasiewicz 	int ret = 0, intf;
292300a2430fSAndrzej Pietrasiewicz 
292400a2430fSAndrzej Pietrasiewicz 	if (alt != (unsigned)-1) {
292500a2430fSAndrzej Pietrasiewicz 		intf = ffs_func_revmap_intf(func, interface);
292600a2430fSAndrzej Pietrasiewicz 		if (unlikely(intf < 0))
292700a2430fSAndrzej Pietrasiewicz 			return intf;
292800a2430fSAndrzej Pietrasiewicz 	}
292900a2430fSAndrzej Pietrasiewicz 
293000a2430fSAndrzej Pietrasiewicz 	if (ffs->func)
293100a2430fSAndrzej Pietrasiewicz 		ffs_func_eps_disable(ffs->func);
293200a2430fSAndrzej Pietrasiewicz 
293318d6b32fSRobert Baldyga 	if (ffs->state == FFS_DEACTIVATED) {
293418d6b32fSRobert Baldyga 		ffs->state = FFS_CLOSING;
293518d6b32fSRobert Baldyga 		INIT_WORK(&ffs->reset_work, ffs_reset_work);
293618d6b32fSRobert Baldyga 		schedule_work(&ffs->reset_work);
293718d6b32fSRobert Baldyga 		return -ENODEV;
293818d6b32fSRobert Baldyga 	}
293918d6b32fSRobert Baldyga 
294000a2430fSAndrzej Pietrasiewicz 	if (ffs->state != FFS_ACTIVE)
294100a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
294200a2430fSAndrzej Pietrasiewicz 
294300a2430fSAndrzej Pietrasiewicz 	if (alt == (unsigned)-1) {
294400a2430fSAndrzej Pietrasiewicz 		ffs->func = NULL;
294500a2430fSAndrzej Pietrasiewicz 		ffs_event_add(ffs, FUNCTIONFS_DISABLE);
294600a2430fSAndrzej Pietrasiewicz 		return 0;
294700a2430fSAndrzej Pietrasiewicz 	}
294800a2430fSAndrzej Pietrasiewicz 
294900a2430fSAndrzej Pietrasiewicz 	ffs->func = func;
295000a2430fSAndrzej Pietrasiewicz 	ret = ffs_func_eps_enable(func);
295100a2430fSAndrzej Pietrasiewicz 	if (likely(ret >= 0))
295200a2430fSAndrzej Pietrasiewicz 		ffs_event_add(ffs, FUNCTIONFS_ENABLE);
295300a2430fSAndrzej Pietrasiewicz 	return ret;
295400a2430fSAndrzej Pietrasiewicz }
295500a2430fSAndrzej Pietrasiewicz 
295600a2430fSAndrzej Pietrasiewicz static void ffs_func_disable(struct usb_function *f)
295700a2430fSAndrzej Pietrasiewicz {
295800a2430fSAndrzej Pietrasiewicz 	ffs_func_set_alt(f, 0, (unsigned)-1);
295900a2430fSAndrzej Pietrasiewicz }
296000a2430fSAndrzej Pietrasiewicz 
296100a2430fSAndrzej Pietrasiewicz static int ffs_func_setup(struct usb_function *f,
296200a2430fSAndrzej Pietrasiewicz 			  const struct usb_ctrlrequest *creq)
296300a2430fSAndrzej Pietrasiewicz {
296400a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
296500a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = func->ffs;
296600a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
296700a2430fSAndrzej Pietrasiewicz 	int ret;
296800a2430fSAndrzej Pietrasiewicz 
296900a2430fSAndrzej Pietrasiewicz 	ENTER();
297000a2430fSAndrzej Pietrasiewicz 
297100a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
297200a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->bRequest     = %02x\n", creq->bRequest);
297300a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->wValue       = %04x\n", le16_to_cpu(creq->wValue));
297400a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->wIndex       = %04x\n", le16_to_cpu(creq->wIndex));
297500a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->wLength      = %04x\n", le16_to_cpu(creq->wLength));
297600a2430fSAndrzej Pietrasiewicz 
297700a2430fSAndrzej Pietrasiewicz 	/*
297800a2430fSAndrzej Pietrasiewicz 	 * Most requests directed to interface go through here
297900a2430fSAndrzej Pietrasiewicz 	 * (notable exceptions are set/get interface) so we need to
298000a2430fSAndrzej Pietrasiewicz 	 * handle them.  All other either handled by composite or
298100a2430fSAndrzej Pietrasiewicz 	 * passed to usb_configuration->setup() (if one is set).  No
298200a2430fSAndrzej Pietrasiewicz 	 * matter, we will handle requests directed to endpoint here
298300a2430fSAndrzej Pietrasiewicz 	 * as well (as it's straightforward) but what to do with any
298400a2430fSAndrzej Pietrasiewicz 	 * other request?
298500a2430fSAndrzej Pietrasiewicz 	 */
298600a2430fSAndrzej Pietrasiewicz 	if (ffs->state != FFS_ACTIVE)
298700a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
298800a2430fSAndrzej Pietrasiewicz 
298900a2430fSAndrzej Pietrasiewicz 	switch (creq->bRequestType & USB_RECIP_MASK) {
299000a2430fSAndrzej Pietrasiewicz 	case USB_RECIP_INTERFACE:
299100a2430fSAndrzej Pietrasiewicz 		ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
299200a2430fSAndrzej Pietrasiewicz 		if (unlikely(ret < 0))
299300a2430fSAndrzej Pietrasiewicz 			return ret;
299400a2430fSAndrzej Pietrasiewicz 		break;
299500a2430fSAndrzej Pietrasiewicz 
299600a2430fSAndrzej Pietrasiewicz 	case USB_RECIP_ENDPOINT:
299700a2430fSAndrzej Pietrasiewicz 		ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
299800a2430fSAndrzej Pietrasiewicz 		if (unlikely(ret < 0))
299900a2430fSAndrzej Pietrasiewicz 			return ret;
30001b0bf88fSRobert Baldyga 		if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
30011b0bf88fSRobert Baldyga 			ret = func->ffs->eps_addrmap[ret];
300200a2430fSAndrzej Pietrasiewicz 		break;
300300a2430fSAndrzej Pietrasiewicz 
300400a2430fSAndrzej Pietrasiewicz 	default:
300500a2430fSAndrzej Pietrasiewicz 		return -EOPNOTSUPP;
300600a2430fSAndrzej Pietrasiewicz 	}
300700a2430fSAndrzej Pietrasiewicz 
300800a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
300900a2430fSAndrzej Pietrasiewicz 	ffs->ev.setup = *creq;
301000a2430fSAndrzej Pietrasiewicz 	ffs->ev.setup.wIndex = cpu_to_le16(ret);
301100a2430fSAndrzej Pietrasiewicz 	__ffs_event_add(ffs, FUNCTIONFS_SETUP);
301200a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
301300a2430fSAndrzej Pietrasiewicz 
301400a2430fSAndrzej Pietrasiewicz 	return 0;
301500a2430fSAndrzej Pietrasiewicz }
301600a2430fSAndrzej Pietrasiewicz 
301700a2430fSAndrzej Pietrasiewicz static void ffs_func_suspend(struct usb_function *f)
301800a2430fSAndrzej Pietrasiewicz {
301900a2430fSAndrzej Pietrasiewicz 	ENTER();
302000a2430fSAndrzej Pietrasiewicz 	ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
302100a2430fSAndrzej Pietrasiewicz }
302200a2430fSAndrzej Pietrasiewicz 
302300a2430fSAndrzej Pietrasiewicz static void ffs_func_resume(struct usb_function *f)
302400a2430fSAndrzej Pietrasiewicz {
302500a2430fSAndrzej Pietrasiewicz 	ENTER();
302600a2430fSAndrzej Pietrasiewicz 	ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
302700a2430fSAndrzej Pietrasiewicz }
302800a2430fSAndrzej Pietrasiewicz 
302900a2430fSAndrzej Pietrasiewicz 
303000a2430fSAndrzej Pietrasiewicz /* Endpoint and interface numbers reverse mapping ***************************/
303100a2430fSAndrzej Pietrasiewicz 
303200a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
303300a2430fSAndrzej Pietrasiewicz {
303400a2430fSAndrzej Pietrasiewicz 	num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
303500a2430fSAndrzej Pietrasiewicz 	return num ? num : -EDOM;
303600a2430fSAndrzej Pietrasiewicz }
303700a2430fSAndrzej Pietrasiewicz 
303800a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
303900a2430fSAndrzej Pietrasiewicz {
304000a2430fSAndrzej Pietrasiewicz 	short *nums = func->interfaces_nums;
304100a2430fSAndrzej Pietrasiewicz 	unsigned count = func->ffs->interfaces_count;
304200a2430fSAndrzej Pietrasiewicz 
304300a2430fSAndrzej Pietrasiewicz 	for (; count; --count, ++nums) {
304400a2430fSAndrzej Pietrasiewicz 		if (*nums >= 0 && *nums == intf)
304500a2430fSAndrzej Pietrasiewicz 			return nums - func->interfaces_nums;
304600a2430fSAndrzej Pietrasiewicz 	}
304700a2430fSAndrzej Pietrasiewicz 
304800a2430fSAndrzej Pietrasiewicz 	return -EDOM;
304900a2430fSAndrzej Pietrasiewicz }
305000a2430fSAndrzej Pietrasiewicz 
305100a2430fSAndrzej Pietrasiewicz 
305200a2430fSAndrzej Pietrasiewicz /* Devices management *******************************************************/
305300a2430fSAndrzej Pietrasiewicz 
305400a2430fSAndrzej Pietrasiewicz static LIST_HEAD(ffs_devices);
305500a2430fSAndrzej Pietrasiewicz 
305600a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_do_find_dev(const char *name)
305700a2430fSAndrzej Pietrasiewicz {
305800a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
305900a2430fSAndrzej Pietrasiewicz 
306000a2430fSAndrzej Pietrasiewicz 	list_for_each_entry(dev, &ffs_devices, entry) {
306100a2430fSAndrzej Pietrasiewicz 		if (!dev->name || !name)
306200a2430fSAndrzej Pietrasiewicz 			continue;
306300a2430fSAndrzej Pietrasiewicz 		if (strcmp(dev->name, name) == 0)
306400a2430fSAndrzej Pietrasiewicz 			return dev;
306500a2430fSAndrzej Pietrasiewicz 	}
306600a2430fSAndrzej Pietrasiewicz 
306700a2430fSAndrzej Pietrasiewicz 	return NULL;
306800a2430fSAndrzej Pietrasiewicz }
306900a2430fSAndrzej Pietrasiewicz 
307000a2430fSAndrzej Pietrasiewicz /*
307100a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
307200a2430fSAndrzej Pietrasiewicz  */
307300a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_get_single_dev(void)
307400a2430fSAndrzej Pietrasiewicz {
307500a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
307600a2430fSAndrzej Pietrasiewicz 
307700a2430fSAndrzej Pietrasiewicz 	if (list_is_singular(&ffs_devices)) {
307800a2430fSAndrzej Pietrasiewicz 		dev = list_first_entry(&ffs_devices, struct ffs_dev, entry);
307900a2430fSAndrzej Pietrasiewicz 		if (dev->single)
308000a2430fSAndrzej Pietrasiewicz 			return dev;
308100a2430fSAndrzej Pietrasiewicz 	}
308200a2430fSAndrzej Pietrasiewicz 
308300a2430fSAndrzej Pietrasiewicz 	return NULL;
308400a2430fSAndrzej Pietrasiewicz }
308500a2430fSAndrzej Pietrasiewicz 
308600a2430fSAndrzej Pietrasiewicz /*
308700a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
308800a2430fSAndrzej Pietrasiewicz  */
308900a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_find_dev(const char *name)
309000a2430fSAndrzej Pietrasiewicz {
309100a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
309200a2430fSAndrzej Pietrasiewicz 
309300a2430fSAndrzej Pietrasiewicz 	dev = _ffs_get_single_dev();
309400a2430fSAndrzej Pietrasiewicz 	if (dev)
309500a2430fSAndrzej Pietrasiewicz 		return dev;
309600a2430fSAndrzej Pietrasiewicz 
309700a2430fSAndrzej Pietrasiewicz 	return _ffs_do_find_dev(name);
309800a2430fSAndrzej Pietrasiewicz }
309900a2430fSAndrzej Pietrasiewicz 
310000a2430fSAndrzej Pietrasiewicz /* Configfs support *********************************************************/
310100a2430fSAndrzej Pietrasiewicz 
310200a2430fSAndrzej Pietrasiewicz static inline struct f_fs_opts *to_ffs_opts(struct config_item *item)
310300a2430fSAndrzej Pietrasiewicz {
310400a2430fSAndrzej Pietrasiewicz 	return container_of(to_config_group(item), struct f_fs_opts,
310500a2430fSAndrzej Pietrasiewicz 			    func_inst.group);
310600a2430fSAndrzej Pietrasiewicz }
310700a2430fSAndrzej Pietrasiewicz 
310800a2430fSAndrzej Pietrasiewicz static void ffs_attr_release(struct config_item *item)
310900a2430fSAndrzej Pietrasiewicz {
311000a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts = to_ffs_opts(item);
311100a2430fSAndrzej Pietrasiewicz 
311200a2430fSAndrzej Pietrasiewicz 	usb_put_function_instance(&opts->func_inst);
311300a2430fSAndrzej Pietrasiewicz }
311400a2430fSAndrzej Pietrasiewicz 
311500a2430fSAndrzej Pietrasiewicz static struct configfs_item_operations ffs_item_ops = {
311600a2430fSAndrzej Pietrasiewicz 	.release	= ffs_attr_release,
311700a2430fSAndrzej Pietrasiewicz };
311800a2430fSAndrzej Pietrasiewicz 
311900a2430fSAndrzej Pietrasiewicz static struct config_item_type ffs_func_type = {
312000a2430fSAndrzej Pietrasiewicz 	.ct_item_ops	= &ffs_item_ops,
312100a2430fSAndrzej Pietrasiewicz 	.ct_owner	= THIS_MODULE,
312200a2430fSAndrzej Pietrasiewicz };
312300a2430fSAndrzej Pietrasiewicz 
312400a2430fSAndrzej Pietrasiewicz 
312500a2430fSAndrzej Pietrasiewicz /* Function registration interface ******************************************/
312600a2430fSAndrzej Pietrasiewicz 
312700a2430fSAndrzej Pietrasiewicz static void ffs_free_inst(struct usb_function_instance *f)
312800a2430fSAndrzej Pietrasiewicz {
312900a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts;
313000a2430fSAndrzej Pietrasiewicz 
313100a2430fSAndrzej Pietrasiewicz 	opts = to_f_fs_opts(f);
313200a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
313300a2430fSAndrzej Pietrasiewicz 	_ffs_free_dev(opts->dev);
313400a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
313500a2430fSAndrzej Pietrasiewicz 	kfree(opts);
313600a2430fSAndrzej Pietrasiewicz }
313700a2430fSAndrzej Pietrasiewicz 
313800a2430fSAndrzej Pietrasiewicz #define MAX_INST_NAME_LEN	40
313900a2430fSAndrzej Pietrasiewicz 
314000a2430fSAndrzej Pietrasiewicz static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
314100a2430fSAndrzej Pietrasiewicz {
314200a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts;
314300a2430fSAndrzej Pietrasiewicz 	char *ptr;
314400a2430fSAndrzej Pietrasiewicz 	const char *tmp;
314500a2430fSAndrzej Pietrasiewicz 	int name_len, ret;
314600a2430fSAndrzej Pietrasiewicz 
314700a2430fSAndrzej Pietrasiewicz 	name_len = strlen(name) + 1;
314800a2430fSAndrzej Pietrasiewicz 	if (name_len > MAX_INST_NAME_LEN)
314900a2430fSAndrzej Pietrasiewicz 		return -ENAMETOOLONG;
315000a2430fSAndrzej Pietrasiewicz 
315100a2430fSAndrzej Pietrasiewicz 	ptr = kstrndup(name, name_len, GFP_KERNEL);
315200a2430fSAndrzej Pietrasiewicz 	if (!ptr)
315300a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
315400a2430fSAndrzej Pietrasiewicz 
315500a2430fSAndrzej Pietrasiewicz 	opts = to_f_fs_opts(fi);
315600a2430fSAndrzej Pietrasiewicz 	tmp = NULL;
315700a2430fSAndrzej Pietrasiewicz 
315800a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
315900a2430fSAndrzej Pietrasiewicz 
316000a2430fSAndrzej Pietrasiewicz 	tmp = opts->dev->name_allocated ? opts->dev->name : NULL;
316100a2430fSAndrzej Pietrasiewicz 	ret = _ffs_name_dev(opts->dev, ptr);
316200a2430fSAndrzej Pietrasiewicz 	if (ret) {
316300a2430fSAndrzej Pietrasiewicz 		kfree(ptr);
316400a2430fSAndrzej Pietrasiewicz 		ffs_dev_unlock();
316500a2430fSAndrzej Pietrasiewicz 		return ret;
316600a2430fSAndrzej Pietrasiewicz 	}
316700a2430fSAndrzej Pietrasiewicz 	opts->dev->name_allocated = true;
316800a2430fSAndrzej Pietrasiewicz 
316900a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
317000a2430fSAndrzej Pietrasiewicz 
317100a2430fSAndrzej Pietrasiewicz 	kfree(tmp);
317200a2430fSAndrzej Pietrasiewicz 
317300a2430fSAndrzej Pietrasiewicz 	return 0;
317400a2430fSAndrzej Pietrasiewicz }
317500a2430fSAndrzej Pietrasiewicz 
317600a2430fSAndrzej Pietrasiewicz static struct usb_function_instance *ffs_alloc_inst(void)
317700a2430fSAndrzej Pietrasiewicz {
317800a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts;
317900a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
318000a2430fSAndrzej Pietrasiewicz 
318100a2430fSAndrzej Pietrasiewicz 	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
318200a2430fSAndrzej Pietrasiewicz 	if (!opts)
318300a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
318400a2430fSAndrzej Pietrasiewicz 
318500a2430fSAndrzej Pietrasiewicz 	opts->func_inst.set_inst_name = ffs_set_inst_name;
318600a2430fSAndrzej Pietrasiewicz 	opts->func_inst.free_func_inst = ffs_free_inst;
318700a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
318800a2430fSAndrzej Pietrasiewicz 	dev = _ffs_alloc_dev();
318900a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
319000a2430fSAndrzej Pietrasiewicz 	if (IS_ERR(dev)) {
319100a2430fSAndrzej Pietrasiewicz 		kfree(opts);
319200a2430fSAndrzej Pietrasiewicz 		return ERR_CAST(dev);
319300a2430fSAndrzej Pietrasiewicz 	}
319400a2430fSAndrzej Pietrasiewicz 	opts->dev = dev;
319500a2430fSAndrzej Pietrasiewicz 	dev->opts = opts;
319600a2430fSAndrzej Pietrasiewicz 
319700a2430fSAndrzej Pietrasiewicz 	config_group_init_type_name(&opts->func_inst.group, "",
319800a2430fSAndrzej Pietrasiewicz 				    &ffs_func_type);
319900a2430fSAndrzej Pietrasiewicz 	return &opts->func_inst;
320000a2430fSAndrzej Pietrasiewicz }
320100a2430fSAndrzej Pietrasiewicz 
320200a2430fSAndrzej Pietrasiewicz static void ffs_free(struct usb_function *f)
320300a2430fSAndrzej Pietrasiewicz {
320400a2430fSAndrzej Pietrasiewicz 	kfree(ffs_func_from_usb(f));
320500a2430fSAndrzej Pietrasiewicz }
320600a2430fSAndrzej Pietrasiewicz 
320700a2430fSAndrzej Pietrasiewicz static void ffs_func_unbind(struct usb_configuration *c,
320800a2430fSAndrzej Pietrasiewicz 			    struct usb_function *f)
320900a2430fSAndrzej Pietrasiewicz {
321000a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
321100a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = func->ffs;
321200a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts =
321300a2430fSAndrzej Pietrasiewicz 		container_of(f->fi, struct f_fs_opts, func_inst);
321400a2430fSAndrzej Pietrasiewicz 	struct ffs_ep *ep = func->eps;
321500a2430fSAndrzej Pietrasiewicz 	unsigned count = ffs->eps_count;
321600a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
321700a2430fSAndrzej Pietrasiewicz 
321800a2430fSAndrzej Pietrasiewicz 	ENTER();
321900a2430fSAndrzej Pietrasiewicz 	if (ffs->func == func) {
322000a2430fSAndrzej Pietrasiewicz 		ffs_func_eps_disable(func);
322100a2430fSAndrzej Pietrasiewicz 		ffs->func = NULL;
322200a2430fSAndrzej Pietrasiewicz 	}
322300a2430fSAndrzej Pietrasiewicz 
322400a2430fSAndrzej Pietrasiewicz 	if (!--opts->refcnt)
322500a2430fSAndrzej Pietrasiewicz 		functionfs_unbind(ffs);
322600a2430fSAndrzej Pietrasiewicz 
322700a2430fSAndrzej Pietrasiewicz 	/* cleanup after autoconfig */
322800a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
322900a2430fSAndrzej Pietrasiewicz 	do {
323000a2430fSAndrzej Pietrasiewicz 		if (ep->ep && ep->req)
323100a2430fSAndrzej Pietrasiewicz 			usb_ep_free_request(ep->ep, ep->req);
323200a2430fSAndrzej Pietrasiewicz 		ep->req = NULL;
323300a2430fSAndrzej Pietrasiewicz 		++ep;
323400a2430fSAndrzej Pietrasiewicz 	} while (--count);
323500a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
323600a2430fSAndrzej Pietrasiewicz 	kfree(func->eps);
323700a2430fSAndrzej Pietrasiewicz 	func->eps = NULL;
323800a2430fSAndrzej Pietrasiewicz 	/*
323900a2430fSAndrzej Pietrasiewicz 	 * eps, descriptors and interfaces_nums are allocated in the
324000a2430fSAndrzej Pietrasiewicz 	 * same chunk so only one free is required.
324100a2430fSAndrzej Pietrasiewicz 	 */
324200a2430fSAndrzej Pietrasiewicz 	func->function.fs_descriptors = NULL;
324300a2430fSAndrzej Pietrasiewicz 	func->function.hs_descriptors = NULL;
324400a2430fSAndrzej Pietrasiewicz 	func->function.ss_descriptors = NULL;
324500a2430fSAndrzej Pietrasiewicz 	func->interfaces_nums = NULL;
324600a2430fSAndrzej Pietrasiewicz 
324700a2430fSAndrzej Pietrasiewicz 	ffs_event_add(ffs, FUNCTIONFS_UNBIND);
324800a2430fSAndrzej Pietrasiewicz }
324900a2430fSAndrzej Pietrasiewicz 
325000a2430fSAndrzej Pietrasiewicz static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
325100a2430fSAndrzej Pietrasiewicz {
325200a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func;
325300a2430fSAndrzej Pietrasiewicz 
325400a2430fSAndrzej Pietrasiewicz 	ENTER();
325500a2430fSAndrzej Pietrasiewicz 
325600a2430fSAndrzej Pietrasiewicz 	func = kzalloc(sizeof(*func), GFP_KERNEL);
325700a2430fSAndrzej Pietrasiewicz 	if (unlikely(!func))
325800a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
325900a2430fSAndrzej Pietrasiewicz 
326000a2430fSAndrzej Pietrasiewicz 	func->function.name    = "Function FS Gadget";
326100a2430fSAndrzej Pietrasiewicz 
326200a2430fSAndrzej Pietrasiewicz 	func->function.bind    = ffs_func_bind;
326300a2430fSAndrzej Pietrasiewicz 	func->function.unbind  = ffs_func_unbind;
326400a2430fSAndrzej Pietrasiewicz 	func->function.set_alt = ffs_func_set_alt;
326500a2430fSAndrzej Pietrasiewicz 	func->function.disable = ffs_func_disable;
326600a2430fSAndrzej Pietrasiewicz 	func->function.setup   = ffs_func_setup;
326700a2430fSAndrzej Pietrasiewicz 	func->function.suspend = ffs_func_suspend;
326800a2430fSAndrzej Pietrasiewicz 	func->function.resume  = ffs_func_resume;
326900a2430fSAndrzej Pietrasiewicz 	func->function.free_func = ffs_free;
327000a2430fSAndrzej Pietrasiewicz 
327100a2430fSAndrzej Pietrasiewicz 	return &func->function;
327200a2430fSAndrzej Pietrasiewicz }
327300a2430fSAndrzej Pietrasiewicz 
327400a2430fSAndrzej Pietrasiewicz /*
327500a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
327600a2430fSAndrzej Pietrasiewicz  */
327700a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_alloc_dev(void)
327800a2430fSAndrzej Pietrasiewicz {
327900a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
328000a2430fSAndrzej Pietrasiewicz 	int ret;
328100a2430fSAndrzej Pietrasiewicz 
328200a2430fSAndrzej Pietrasiewicz 	if (_ffs_get_single_dev())
328300a2430fSAndrzej Pietrasiewicz 			return ERR_PTR(-EBUSY);
328400a2430fSAndrzej Pietrasiewicz 
328500a2430fSAndrzej Pietrasiewicz 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
328600a2430fSAndrzej Pietrasiewicz 	if (!dev)
328700a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
328800a2430fSAndrzej Pietrasiewicz 
328900a2430fSAndrzej Pietrasiewicz 	if (list_empty(&ffs_devices)) {
329000a2430fSAndrzej Pietrasiewicz 		ret = functionfs_init();
329100a2430fSAndrzej Pietrasiewicz 		if (ret) {
329200a2430fSAndrzej Pietrasiewicz 			kfree(dev);
329300a2430fSAndrzej Pietrasiewicz 			return ERR_PTR(ret);
329400a2430fSAndrzej Pietrasiewicz 		}
329500a2430fSAndrzej Pietrasiewicz 	}
329600a2430fSAndrzej Pietrasiewicz 
329700a2430fSAndrzej Pietrasiewicz 	list_add(&dev->entry, &ffs_devices);
329800a2430fSAndrzej Pietrasiewicz 
329900a2430fSAndrzej Pietrasiewicz 	return dev;
330000a2430fSAndrzej Pietrasiewicz }
330100a2430fSAndrzej Pietrasiewicz 
330200a2430fSAndrzej Pietrasiewicz /*
330300a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
330400a2430fSAndrzej Pietrasiewicz  * The caller is responsible for "name" being available whenever f_fs needs it
330500a2430fSAndrzej Pietrasiewicz  */
330600a2430fSAndrzej Pietrasiewicz static int _ffs_name_dev(struct ffs_dev *dev, const char *name)
330700a2430fSAndrzej Pietrasiewicz {
330800a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *existing;
330900a2430fSAndrzej Pietrasiewicz 
331000a2430fSAndrzej Pietrasiewicz 	existing = _ffs_do_find_dev(name);
331100a2430fSAndrzej Pietrasiewicz 	if (existing)
331200a2430fSAndrzej Pietrasiewicz 		return -EBUSY;
331300a2430fSAndrzej Pietrasiewicz 
331400a2430fSAndrzej Pietrasiewicz 	dev->name = name;
331500a2430fSAndrzej Pietrasiewicz 
331600a2430fSAndrzej Pietrasiewicz 	return 0;
331700a2430fSAndrzej Pietrasiewicz }
331800a2430fSAndrzej Pietrasiewicz 
331900a2430fSAndrzej Pietrasiewicz /*
332000a2430fSAndrzej Pietrasiewicz  * The caller is responsible for "name" being available whenever f_fs needs it
332100a2430fSAndrzej Pietrasiewicz  */
332200a2430fSAndrzej Pietrasiewicz int ffs_name_dev(struct ffs_dev *dev, const char *name)
332300a2430fSAndrzej Pietrasiewicz {
332400a2430fSAndrzej Pietrasiewicz 	int ret;
332500a2430fSAndrzej Pietrasiewicz 
332600a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
332700a2430fSAndrzej Pietrasiewicz 	ret = _ffs_name_dev(dev, name);
332800a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
332900a2430fSAndrzej Pietrasiewicz 
333000a2430fSAndrzej Pietrasiewicz 	return ret;
333100a2430fSAndrzej Pietrasiewicz }
333200a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_name_dev);
333300a2430fSAndrzej Pietrasiewicz 
333400a2430fSAndrzej Pietrasiewicz int ffs_single_dev(struct ffs_dev *dev)
333500a2430fSAndrzej Pietrasiewicz {
333600a2430fSAndrzej Pietrasiewicz 	int ret;
333700a2430fSAndrzej Pietrasiewicz 
333800a2430fSAndrzej Pietrasiewicz 	ret = 0;
333900a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
334000a2430fSAndrzej Pietrasiewicz 
334100a2430fSAndrzej Pietrasiewicz 	if (!list_is_singular(&ffs_devices))
334200a2430fSAndrzej Pietrasiewicz 		ret = -EBUSY;
334300a2430fSAndrzej Pietrasiewicz 	else
334400a2430fSAndrzej Pietrasiewicz 		dev->single = true;
334500a2430fSAndrzej Pietrasiewicz 
334600a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
334700a2430fSAndrzej Pietrasiewicz 	return ret;
334800a2430fSAndrzej Pietrasiewicz }
334900a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_single_dev);
335000a2430fSAndrzej Pietrasiewicz 
335100a2430fSAndrzej Pietrasiewicz /*
335200a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
335300a2430fSAndrzej Pietrasiewicz  */
335400a2430fSAndrzej Pietrasiewicz static void _ffs_free_dev(struct ffs_dev *dev)
335500a2430fSAndrzej Pietrasiewicz {
335600a2430fSAndrzej Pietrasiewicz 	list_del(&dev->entry);
335700a2430fSAndrzej Pietrasiewicz 	if (dev->name_allocated)
335800a2430fSAndrzej Pietrasiewicz 		kfree(dev->name);
335900a2430fSAndrzej Pietrasiewicz 	kfree(dev);
336000a2430fSAndrzej Pietrasiewicz 	if (list_empty(&ffs_devices))
336100a2430fSAndrzej Pietrasiewicz 		functionfs_cleanup();
336200a2430fSAndrzej Pietrasiewicz }
336300a2430fSAndrzej Pietrasiewicz 
336400a2430fSAndrzej Pietrasiewicz static void *ffs_acquire_dev(const char *dev_name)
336500a2430fSAndrzej Pietrasiewicz {
336600a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *ffs_dev;
336700a2430fSAndrzej Pietrasiewicz 
336800a2430fSAndrzej Pietrasiewicz 	ENTER();
336900a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
337000a2430fSAndrzej Pietrasiewicz 
337100a2430fSAndrzej Pietrasiewicz 	ffs_dev = _ffs_find_dev(dev_name);
337200a2430fSAndrzej Pietrasiewicz 	if (!ffs_dev)
337300a2430fSAndrzej Pietrasiewicz 		ffs_dev = ERR_PTR(-ENOENT);
337400a2430fSAndrzej Pietrasiewicz 	else if (ffs_dev->mounted)
337500a2430fSAndrzej Pietrasiewicz 		ffs_dev = ERR_PTR(-EBUSY);
337600a2430fSAndrzej Pietrasiewicz 	else if (ffs_dev->ffs_acquire_dev_callback &&
337700a2430fSAndrzej Pietrasiewicz 	    ffs_dev->ffs_acquire_dev_callback(ffs_dev))
337800a2430fSAndrzej Pietrasiewicz 		ffs_dev = ERR_PTR(-ENOENT);
337900a2430fSAndrzej Pietrasiewicz 	else
338000a2430fSAndrzej Pietrasiewicz 		ffs_dev->mounted = true;
338100a2430fSAndrzej Pietrasiewicz 
338200a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
338300a2430fSAndrzej Pietrasiewicz 	return ffs_dev;
338400a2430fSAndrzej Pietrasiewicz }
338500a2430fSAndrzej Pietrasiewicz 
338600a2430fSAndrzej Pietrasiewicz static void ffs_release_dev(struct ffs_data *ffs_data)
338700a2430fSAndrzej Pietrasiewicz {
338800a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *ffs_dev;
338900a2430fSAndrzej Pietrasiewicz 
339000a2430fSAndrzej Pietrasiewicz 	ENTER();
339100a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
339200a2430fSAndrzej Pietrasiewicz 
339300a2430fSAndrzej Pietrasiewicz 	ffs_dev = ffs_data->private_data;
339400a2430fSAndrzej Pietrasiewicz 	if (ffs_dev) {
339500a2430fSAndrzej Pietrasiewicz 		ffs_dev->mounted = false;
339600a2430fSAndrzej Pietrasiewicz 
339700a2430fSAndrzej Pietrasiewicz 		if (ffs_dev->ffs_release_dev_callback)
339800a2430fSAndrzej Pietrasiewicz 			ffs_dev->ffs_release_dev_callback(ffs_dev);
339900a2430fSAndrzej Pietrasiewicz 	}
340000a2430fSAndrzej Pietrasiewicz 
340100a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
340200a2430fSAndrzej Pietrasiewicz }
340300a2430fSAndrzej Pietrasiewicz 
340400a2430fSAndrzej Pietrasiewicz static int ffs_ready(struct ffs_data *ffs)
340500a2430fSAndrzej Pietrasiewicz {
340600a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *ffs_obj;
340700a2430fSAndrzej Pietrasiewicz 	int ret = 0;
340800a2430fSAndrzej Pietrasiewicz 
340900a2430fSAndrzej Pietrasiewicz 	ENTER();
341000a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
341100a2430fSAndrzej Pietrasiewicz 
341200a2430fSAndrzej Pietrasiewicz 	ffs_obj = ffs->private_data;
341300a2430fSAndrzej Pietrasiewicz 	if (!ffs_obj) {
341400a2430fSAndrzej Pietrasiewicz 		ret = -EINVAL;
341500a2430fSAndrzej Pietrasiewicz 		goto done;
341600a2430fSAndrzej Pietrasiewicz 	}
341700a2430fSAndrzej Pietrasiewicz 	if (WARN_ON(ffs_obj->desc_ready)) {
341800a2430fSAndrzej Pietrasiewicz 		ret = -EBUSY;
341900a2430fSAndrzej Pietrasiewicz 		goto done;
342000a2430fSAndrzej Pietrasiewicz 	}
342100a2430fSAndrzej Pietrasiewicz 
342200a2430fSAndrzej Pietrasiewicz 	ffs_obj->desc_ready = true;
342300a2430fSAndrzej Pietrasiewicz 	ffs_obj->ffs_data = ffs;
342400a2430fSAndrzej Pietrasiewicz 
342549a79d8bSKrzysztof Opasiak 	if (ffs_obj->ffs_ready_callback) {
342600a2430fSAndrzej Pietrasiewicz 		ret = ffs_obj->ffs_ready_callback(ffs);
342749a79d8bSKrzysztof Opasiak 		if (ret)
342849a79d8bSKrzysztof Opasiak 			goto done;
342949a79d8bSKrzysztof Opasiak 	}
343000a2430fSAndrzej Pietrasiewicz 
343149a79d8bSKrzysztof Opasiak 	set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
343200a2430fSAndrzej Pietrasiewicz done:
343300a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
343400a2430fSAndrzej Pietrasiewicz 	return ret;
343500a2430fSAndrzej Pietrasiewicz }
343600a2430fSAndrzej Pietrasiewicz 
343700a2430fSAndrzej Pietrasiewicz static void ffs_closed(struct ffs_data *ffs)
343800a2430fSAndrzej Pietrasiewicz {
343900a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *ffs_obj;
3440f14e9ad1SRui Miguel Silva 	struct f_fs_opts *opts;
344100a2430fSAndrzej Pietrasiewicz 
344200a2430fSAndrzej Pietrasiewicz 	ENTER();
344300a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
344400a2430fSAndrzej Pietrasiewicz 
344500a2430fSAndrzej Pietrasiewicz 	ffs_obj = ffs->private_data;
344600a2430fSAndrzej Pietrasiewicz 	if (!ffs_obj)
344700a2430fSAndrzej Pietrasiewicz 		goto done;
344800a2430fSAndrzej Pietrasiewicz 
344900a2430fSAndrzej Pietrasiewicz 	ffs_obj->desc_ready = false;
345000a2430fSAndrzej Pietrasiewicz 
345149a79d8bSKrzysztof Opasiak 	if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
345249a79d8bSKrzysztof Opasiak 	    ffs_obj->ffs_closed_callback)
345300a2430fSAndrzej Pietrasiewicz 		ffs_obj->ffs_closed_callback(ffs);
345400a2430fSAndrzej Pietrasiewicz 
3455f14e9ad1SRui Miguel Silva 	if (ffs_obj->opts)
3456f14e9ad1SRui Miguel Silva 		opts = ffs_obj->opts;
3457f14e9ad1SRui Miguel Silva 	else
3458f14e9ad1SRui Miguel Silva 		goto done;
3459f14e9ad1SRui Miguel Silva 
3460f14e9ad1SRui Miguel Silva 	if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent
3461f14e9ad1SRui Miguel Silva 	    || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount))
346200a2430fSAndrzej Pietrasiewicz 		goto done;
346300a2430fSAndrzej Pietrasiewicz 
346400a2430fSAndrzej Pietrasiewicz 	unregister_gadget_item(ffs_obj->opts->
346500a2430fSAndrzej Pietrasiewicz 			       func_inst.group.cg_item.ci_parent->ci_parent);
346600a2430fSAndrzej Pietrasiewicz done:
346700a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
346800a2430fSAndrzej Pietrasiewicz }
346900a2430fSAndrzej Pietrasiewicz 
347000a2430fSAndrzej Pietrasiewicz /* Misc helper functions ****************************************************/
347100a2430fSAndrzej Pietrasiewicz 
347200a2430fSAndrzej Pietrasiewicz static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
347300a2430fSAndrzej Pietrasiewicz {
347400a2430fSAndrzej Pietrasiewicz 	return nonblock
347500a2430fSAndrzej Pietrasiewicz 		? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN
347600a2430fSAndrzej Pietrasiewicz 		: mutex_lock_interruptible(mutex);
347700a2430fSAndrzej Pietrasiewicz }
347800a2430fSAndrzej Pietrasiewicz 
347900a2430fSAndrzej Pietrasiewicz static char *ffs_prepare_buffer(const char __user *buf, size_t len)
348000a2430fSAndrzej Pietrasiewicz {
348100a2430fSAndrzej Pietrasiewicz 	char *data;
348200a2430fSAndrzej Pietrasiewicz 
348300a2430fSAndrzej Pietrasiewicz 	if (unlikely(!len))
348400a2430fSAndrzej Pietrasiewicz 		return NULL;
348500a2430fSAndrzej Pietrasiewicz 
348600a2430fSAndrzej Pietrasiewicz 	data = kmalloc(len, GFP_KERNEL);
348700a2430fSAndrzej Pietrasiewicz 	if (unlikely(!data))
348800a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
348900a2430fSAndrzej Pietrasiewicz 
34907fe9a937SDaniel Walter 	if (unlikely(copy_from_user(data, buf, len))) {
349100a2430fSAndrzej Pietrasiewicz 		kfree(data);
349200a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-EFAULT);
349300a2430fSAndrzej Pietrasiewicz 	}
349400a2430fSAndrzej Pietrasiewicz 
349500a2430fSAndrzej Pietrasiewicz 	pr_vdebug("Buffer from user space:\n");
349600a2430fSAndrzej Pietrasiewicz 	ffs_dump_mem("", data, len);
349700a2430fSAndrzej Pietrasiewicz 
349800a2430fSAndrzej Pietrasiewicz 	return data;
349900a2430fSAndrzej Pietrasiewicz }
350000a2430fSAndrzej Pietrasiewicz 
350100a2430fSAndrzej Pietrasiewicz DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
350200a2430fSAndrzej Pietrasiewicz MODULE_LICENSE("GPL");
350300a2430fSAndrzej Pietrasiewicz MODULE_AUTHOR("Michal Nazarewicz");
3504