xref: /openbmc/linux/drivers/usb/gadget/function/f_fs.c (revision b7db5733)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
200a2430fSAndrzej Pietrasiewicz /*
300a2430fSAndrzej Pietrasiewicz  * f_fs.c -- user mode file system API for USB composite function controllers
400a2430fSAndrzej Pietrasiewicz  *
500a2430fSAndrzej Pietrasiewicz  * Copyright (C) 2010 Samsung Electronics
600a2430fSAndrzej Pietrasiewicz  * Author: Michal Nazarewicz <mina86@mina86.com>
700a2430fSAndrzej Pietrasiewicz  *
800a2430fSAndrzej Pietrasiewicz  * Based on inode.c (GadgetFS) which was:
900a2430fSAndrzej Pietrasiewicz  * Copyright (C) 2003-2004 David Brownell
1000a2430fSAndrzej Pietrasiewicz  * Copyright (C) 2003 Agilent Technologies
1100a2430fSAndrzej Pietrasiewicz  */
1200a2430fSAndrzej Pietrasiewicz 
1300a2430fSAndrzej Pietrasiewicz 
1400a2430fSAndrzej Pietrasiewicz /* #define DEBUG */
1500a2430fSAndrzej Pietrasiewicz /* #define VERBOSE_DEBUG */
1600a2430fSAndrzej Pietrasiewicz 
1700a2430fSAndrzej Pietrasiewicz #include <linux/blkdev.h>
1800a2430fSAndrzej Pietrasiewicz #include <linux/pagemap.h>
1900a2430fSAndrzej Pietrasiewicz #include <linux/export.h>
20dec90f61SDavid Howells #include <linux/fs_parser.h>
2100a2430fSAndrzej Pietrasiewicz #include <linux/hid.h>
22772a7a72SAndrzej Pietrasiewicz #include <linux/mm.h>
2300a2430fSAndrzej Pietrasiewicz #include <linux/module.h>
24772a7a72SAndrzej Pietrasiewicz #include <linux/scatterlist.h>
25174cd4b1SIngo Molnar #include <linux/sched/signal.h>
26e2e40f2cSChristoph Hellwig #include <linux/uio.h>
27772a7a72SAndrzej Pietrasiewicz #include <linux/vmalloc.h>
2800a2430fSAndrzej Pietrasiewicz #include <asm/unaligned.h>
2900a2430fSAndrzej Pietrasiewicz 
307f7c548cSVincent Pelletier #include <linux/usb/ccid.h>
3100a2430fSAndrzej Pietrasiewicz #include <linux/usb/composite.h>
3200a2430fSAndrzej Pietrasiewicz #include <linux/usb/functionfs.h>
3300a2430fSAndrzej Pietrasiewicz 
3400a2430fSAndrzej Pietrasiewicz #include <linux/aio.h>
359bf5b9ebSChristoph Hellwig #include <linux/kthread.h>
3600a2430fSAndrzej Pietrasiewicz #include <linux/poll.h>
375e33f6fdSRobert Baldyga #include <linux/eventfd.h>
3800a2430fSAndrzej Pietrasiewicz 
3900a2430fSAndrzej Pietrasiewicz #include "u_fs.h"
4000a2430fSAndrzej Pietrasiewicz #include "u_f.h"
4100a2430fSAndrzej Pietrasiewicz #include "u_os_desc.h"
4200a2430fSAndrzej Pietrasiewicz #include "configfs.h"
4300a2430fSAndrzej Pietrasiewicz 
4400a2430fSAndrzej Pietrasiewicz #define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */
4500a2430fSAndrzej Pietrasiewicz 
4600a2430fSAndrzej Pietrasiewicz /* Reference counter handling */
4700a2430fSAndrzej Pietrasiewicz static void ffs_data_get(struct ffs_data *ffs);
4800a2430fSAndrzej Pietrasiewicz static void ffs_data_put(struct ffs_data *ffs);
4900a2430fSAndrzej Pietrasiewicz /* Creates new ffs_data object. */
50addfc582SJohn Keeping static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
51addfc582SJohn Keeping 	__attribute__((malloc));
5200a2430fSAndrzej Pietrasiewicz 
5300a2430fSAndrzej Pietrasiewicz /* Opened counter handling. */
5400a2430fSAndrzej Pietrasiewicz static void ffs_data_opened(struct ffs_data *ffs);
5500a2430fSAndrzej Pietrasiewicz static void ffs_data_closed(struct ffs_data *ffs);
5600a2430fSAndrzej Pietrasiewicz 
5700a2430fSAndrzej Pietrasiewicz /* Called with ffs->mutex held; take over ownership of data. */
5800a2430fSAndrzej Pietrasiewicz static int __must_check
5900a2430fSAndrzej Pietrasiewicz __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
6000a2430fSAndrzej Pietrasiewicz static int __must_check
6100a2430fSAndrzej Pietrasiewicz __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
6200a2430fSAndrzej Pietrasiewicz 
6300a2430fSAndrzej Pietrasiewicz 
6400a2430fSAndrzej Pietrasiewicz /* The function structure ***************************************************/
6500a2430fSAndrzej Pietrasiewicz 
6600a2430fSAndrzej Pietrasiewicz struct ffs_ep;
6700a2430fSAndrzej Pietrasiewicz 
6800a2430fSAndrzej Pietrasiewicz struct ffs_function {
6900a2430fSAndrzej Pietrasiewicz 	struct usb_configuration	*conf;
7000a2430fSAndrzej Pietrasiewicz 	struct usb_gadget		*gadget;
7100a2430fSAndrzej Pietrasiewicz 	struct ffs_data			*ffs;
7200a2430fSAndrzej Pietrasiewicz 
7300a2430fSAndrzej Pietrasiewicz 	struct ffs_ep			*eps;
7400a2430fSAndrzej Pietrasiewicz 	u8				eps_revmap[16];
7500a2430fSAndrzej Pietrasiewicz 	short				*interfaces_nums;
7600a2430fSAndrzej Pietrasiewicz 
7700a2430fSAndrzej Pietrasiewicz 	struct usb_function		function;
7800a2430fSAndrzej Pietrasiewicz };
7900a2430fSAndrzej Pietrasiewicz 
8000a2430fSAndrzej Pietrasiewicz 
8100a2430fSAndrzej Pietrasiewicz static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
8200a2430fSAndrzej Pietrasiewicz {
8300a2430fSAndrzej Pietrasiewicz 	return container_of(f, struct ffs_function, function);
8400a2430fSAndrzej Pietrasiewicz }
8500a2430fSAndrzej Pietrasiewicz 
8600a2430fSAndrzej Pietrasiewicz 
8700a2430fSAndrzej Pietrasiewicz static inline enum ffs_setup_state
8800a2430fSAndrzej Pietrasiewicz ffs_setup_state_clear_cancelled(struct ffs_data *ffs)
8900a2430fSAndrzej Pietrasiewicz {
9000a2430fSAndrzej Pietrasiewicz 	return (enum ffs_setup_state)
9100a2430fSAndrzej Pietrasiewicz 		cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP);
9200a2430fSAndrzej Pietrasiewicz }
9300a2430fSAndrzej Pietrasiewicz 
9400a2430fSAndrzej Pietrasiewicz 
9500a2430fSAndrzej Pietrasiewicz static void ffs_func_eps_disable(struct ffs_function *func);
9600a2430fSAndrzej Pietrasiewicz static int __must_check ffs_func_eps_enable(struct ffs_function *func);
9700a2430fSAndrzej Pietrasiewicz 
9800a2430fSAndrzej Pietrasiewicz static int ffs_func_bind(struct usb_configuration *,
9900a2430fSAndrzej Pietrasiewicz 			 struct usb_function *);
10000a2430fSAndrzej Pietrasiewicz static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
10100a2430fSAndrzej Pietrasiewicz static void ffs_func_disable(struct usb_function *);
10200a2430fSAndrzej Pietrasiewicz static int ffs_func_setup(struct usb_function *,
10300a2430fSAndrzej Pietrasiewicz 			  const struct usb_ctrlrequest *);
10454dfce6dSFelix Hädicke static bool ffs_func_req_match(struct usb_function *,
1051a00b457SFelix Hädicke 			       const struct usb_ctrlrequest *,
1061a00b457SFelix Hädicke 			       bool config0);
10700a2430fSAndrzej Pietrasiewicz static void ffs_func_suspend(struct usb_function *);
10800a2430fSAndrzej Pietrasiewicz static void ffs_func_resume(struct usb_function *);
10900a2430fSAndrzej Pietrasiewicz 
11000a2430fSAndrzej Pietrasiewicz 
11100a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
11200a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
11300a2430fSAndrzej Pietrasiewicz 
11400a2430fSAndrzej Pietrasiewicz 
11500a2430fSAndrzej Pietrasiewicz /* The endpoints structures *************************************************/
11600a2430fSAndrzej Pietrasiewicz 
11700a2430fSAndrzej Pietrasiewicz struct ffs_ep {
11800a2430fSAndrzej Pietrasiewicz 	struct usb_ep			*ep;	/* P: ffs->eps_lock */
11900a2430fSAndrzej Pietrasiewicz 	struct usb_request		*req;	/* P: epfile->mutex */
12000a2430fSAndrzej Pietrasiewicz 
12100a2430fSAndrzej Pietrasiewicz 	/* [0]: full speed, [1]: high speed, [2]: super speed */
12200a2430fSAndrzej Pietrasiewicz 	struct usb_endpoint_descriptor	*descs[3];
12300a2430fSAndrzej Pietrasiewicz 
12400a2430fSAndrzej Pietrasiewicz 	u8				num;
12500a2430fSAndrzej Pietrasiewicz };
12600a2430fSAndrzej Pietrasiewicz 
12700a2430fSAndrzej Pietrasiewicz struct ffs_epfile {
12800a2430fSAndrzej Pietrasiewicz 	/* Protects ep->ep and ep->req. */
12900a2430fSAndrzej Pietrasiewicz 	struct mutex			mutex;
13000a2430fSAndrzej Pietrasiewicz 
13100a2430fSAndrzej Pietrasiewicz 	struct ffs_data			*ffs;
13200a2430fSAndrzej Pietrasiewicz 	struct ffs_ep			*ep;	/* P: ffs->eps_lock */
13300a2430fSAndrzej Pietrasiewicz 
13400a2430fSAndrzej Pietrasiewicz 	struct dentry			*dentry;
13500a2430fSAndrzej Pietrasiewicz 
1369353afbbSMichal Nazarewicz 	/*
1379353afbbSMichal Nazarewicz 	 * Buffer for holding data from partial reads which may happen since
1389353afbbSMichal Nazarewicz 	 * we’re rounding user read requests to a multiple of a max packet size.
139a9e6f83cSMichal Nazarewicz 	 *
140a9e6f83cSMichal Nazarewicz 	 * The pointer is initialised with NULL value and may be set by
141a9e6f83cSMichal Nazarewicz 	 * __ffs_epfile_read_data function to point to a temporary buffer.
142a9e6f83cSMichal Nazarewicz 	 *
143a9e6f83cSMichal Nazarewicz 	 * In normal operation, calls to __ffs_epfile_read_buffered will consume
144a9e6f83cSMichal Nazarewicz 	 * data from said buffer and eventually free it.  Importantly, while the
145a9e6f83cSMichal Nazarewicz 	 * function is using the buffer, it sets the pointer to NULL.  This is
146a9e6f83cSMichal Nazarewicz 	 * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered
147a9e6f83cSMichal Nazarewicz 	 * can never run concurrently (they are synchronised by epfile->mutex)
148a9e6f83cSMichal Nazarewicz 	 * so the latter will not assign a new value to the pointer.
149a9e6f83cSMichal Nazarewicz 	 *
150a9e6f83cSMichal Nazarewicz 	 * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is
151a9e6f83cSMichal Nazarewicz 	 * valid) and sets the pointer to READ_BUFFER_DROP value.  This special
152a9e6f83cSMichal Nazarewicz 	 * value is crux of the synchronisation between ffs_func_eps_disable and
153a9e6f83cSMichal Nazarewicz 	 * __ffs_epfile_read_data.
154a9e6f83cSMichal Nazarewicz 	 *
155a9e6f83cSMichal Nazarewicz 	 * Once __ffs_epfile_read_data is about to finish it will try to set the
156a9e6f83cSMichal Nazarewicz 	 * pointer back to its old value (as described above), but seeing as the
157a9e6f83cSMichal Nazarewicz 	 * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free
158a9e6f83cSMichal Nazarewicz 	 * the buffer.
159a9e6f83cSMichal Nazarewicz 	 *
160a9e6f83cSMichal Nazarewicz 	 * == State transitions ==
161a9e6f83cSMichal Nazarewicz 	 *
162a9e6f83cSMichal Nazarewicz 	 * • ptr == NULL:  (initial state)
163a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP
164a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffered:    nop
165a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf
166a9e6f83cSMichal Nazarewicz 	 *   ◦ reading finishes:              n/a, not in ‘and reading’ state
167a9e6f83cSMichal Nazarewicz 	 * • ptr == DROP:
168a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffer_free: nop
169a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffered:    go to ptr == NULL
170a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop
171a9e6f83cSMichal Nazarewicz 	 *   ◦ reading finishes:              n/a, not in ‘and reading’ state
172a9e6f83cSMichal Nazarewicz 	 * • ptr == buf:
173a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP
174a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffered:    go to ptr == NULL and reading
175a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_data:        n/a, __ffs_epfile_read_buffered
176a9e6f83cSMichal Nazarewicz 	 *                                    is always called first
177a9e6f83cSMichal Nazarewicz 	 *   ◦ reading finishes:              n/a, not in ‘and reading’ state
178a9e6f83cSMichal Nazarewicz 	 * • ptr == NULL and reading:
179a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading
180a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffered:    n/a, mutex is held
181a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_data:        n/a, mutex is held
182a9e6f83cSMichal Nazarewicz 	 *   ◦ reading finishes and …
183a9e6f83cSMichal Nazarewicz 	 *     … all data read:               free buf, go to ptr == NULL
184a9e6f83cSMichal Nazarewicz 	 *     … otherwise:                   go to ptr == buf and reading
185a9e6f83cSMichal Nazarewicz 	 * • ptr == DROP and reading:
186a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffer_free: nop
187a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_buffered:    n/a, mutex is held
188a9e6f83cSMichal Nazarewicz 	 *   ◦ __ffs_epfile_read_data:        n/a, mutex is held
189a9e6f83cSMichal Nazarewicz 	 *   ◦ reading finishes:              free buf, go to ptr == DROP
1909353afbbSMichal Nazarewicz 	 */
191a9e6f83cSMichal Nazarewicz 	struct ffs_buffer		*read_buffer;
192a9e6f83cSMichal Nazarewicz #define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN))
1939353afbbSMichal Nazarewicz 
19400a2430fSAndrzej Pietrasiewicz 	char				name[5];
19500a2430fSAndrzej Pietrasiewicz 
19600a2430fSAndrzej Pietrasiewicz 	unsigned char			in;	/* P: ffs->eps_lock */
19700a2430fSAndrzej Pietrasiewicz 	unsigned char			isoc;	/* P: ffs->eps_lock */
19800a2430fSAndrzej Pietrasiewicz 
19900a2430fSAndrzej Pietrasiewicz 	unsigned char			_pad;
20000a2430fSAndrzej Pietrasiewicz };
20100a2430fSAndrzej Pietrasiewicz 
2029353afbbSMichal Nazarewicz struct ffs_buffer {
2039353afbbSMichal Nazarewicz 	size_t length;
2049353afbbSMichal Nazarewicz 	char *data;
2059353afbbSMichal Nazarewicz 	char storage[];
2069353afbbSMichal Nazarewicz };
2079353afbbSMichal Nazarewicz 
20800a2430fSAndrzej Pietrasiewicz /*  ffs_io_data structure ***************************************************/
20900a2430fSAndrzej Pietrasiewicz 
21000a2430fSAndrzej Pietrasiewicz struct ffs_io_data {
21100a2430fSAndrzej Pietrasiewicz 	bool aio;
21200a2430fSAndrzej Pietrasiewicz 	bool read;
21300a2430fSAndrzej Pietrasiewicz 
21400a2430fSAndrzej Pietrasiewicz 	struct kiocb *kiocb;
215c993c39bSAl Viro 	struct iov_iter data;
216c993c39bSAl Viro 	const void *to_free;
217c993c39bSAl Viro 	char *buf;
21800a2430fSAndrzej Pietrasiewicz 
21900a2430fSAndrzej Pietrasiewicz 	struct mm_struct *mm;
22000a2430fSAndrzej Pietrasiewicz 	struct work_struct work;
22100a2430fSAndrzej Pietrasiewicz 
22200a2430fSAndrzej Pietrasiewicz 	struct usb_ep *ep;
22300a2430fSAndrzej Pietrasiewicz 	struct usb_request *req;
224772a7a72SAndrzej Pietrasiewicz 	struct sg_table sgt;
225772a7a72SAndrzej Pietrasiewicz 	bool use_sg;
2265e33f6fdSRobert Baldyga 
2275e33f6fdSRobert Baldyga 	struct ffs_data *ffs;
228fb1f16d7SLinyu Yuan 
229fb1f16d7SLinyu Yuan 	int status;
230fb1f16d7SLinyu Yuan 	struct completion done;
23100a2430fSAndrzej Pietrasiewicz };
23200a2430fSAndrzej Pietrasiewicz 
2336d5c1c77SRobert Baldyga struct ffs_desc_helper {
2346d5c1c77SRobert Baldyga 	struct ffs_data *ffs;
2356d5c1c77SRobert Baldyga 	unsigned interfaces_count;
2366d5c1c77SRobert Baldyga 	unsigned eps_count;
2376d5c1c77SRobert Baldyga };
2386d5c1c77SRobert Baldyga 
23900a2430fSAndrzej Pietrasiewicz static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);
24000a2430fSAndrzej Pietrasiewicz static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
24100a2430fSAndrzej Pietrasiewicz 
2421bb27cacSAl Viro static struct dentry *
24300a2430fSAndrzej Pietrasiewicz ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
2441bb27cacSAl Viro 		   const struct file_operations *fops);
24500a2430fSAndrzej Pietrasiewicz 
24600a2430fSAndrzej Pietrasiewicz /* Devices management *******************************************************/
24700a2430fSAndrzej Pietrasiewicz 
24800a2430fSAndrzej Pietrasiewicz DEFINE_MUTEX(ffs_lock);
24900a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_lock);
25000a2430fSAndrzej Pietrasiewicz 
25100a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_find_dev(const char *name);
25200a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_alloc_dev(void);
25300a2430fSAndrzej Pietrasiewicz static void _ffs_free_dev(struct ffs_dev *dev);
254ecfbd7b9SAndrew Gabbasov static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
255ecfbd7b9SAndrew Gabbasov static void ffs_release_dev(struct ffs_dev *ffs_dev);
25600a2430fSAndrzej Pietrasiewicz static int ffs_ready(struct ffs_data *ffs);
25700a2430fSAndrzej Pietrasiewicz static void ffs_closed(struct ffs_data *ffs);
25800a2430fSAndrzej Pietrasiewicz 
25900a2430fSAndrzej Pietrasiewicz /* Misc helper functions ****************************************************/
26000a2430fSAndrzej Pietrasiewicz 
26100a2430fSAndrzej Pietrasiewicz static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
26200a2430fSAndrzej Pietrasiewicz 	__attribute__((warn_unused_result, nonnull));
26300a2430fSAndrzej Pietrasiewicz static char *ffs_prepare_buffer(const char __user *buf, size_t len)
26400a2430fSAndrzej Pietrasiewicz 	__attribute__((warn_unused_result, nonnull));
26500a2430fSAndrzej Pietrasiewicz 
26600a2430fSAndrzej Pietrasiewicz 
26700a2430fSAndrzej Pietrasiewicz /* Control file aka ep0 *****************************************************/
26800a2430fSAndrzej Pietrasiewicz 
26900a2430fSAndrzej Pietrasiewicz static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
27000a2430fSAndrzej Pietrasiewicz {
27100a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = req->context;
27200a2430fSAndrzej Pietrasiewicz 
2735bdcde90SDaniel Wagner 	complete(&ffs->ep0req_completion);
27400a2430fSAndrzej Pietrasiewicz }
27500a2430fSAndrzej Pietrasiewicz 
27600a2430fSAndrzej Pietrasiewicz static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
277c40619bbSVincent Pelletier 	__releases(&ffs->ev.waitq.lock)
27800a2430fSAndrzej Pietrasiewicz {
27900a2430fSAndrzej Pietrasiewicz 	struct usb_request *req = ffs->ep0req;
28000a2430fSAndrzej Pietrasiewicz 	int ret;
28100a2430fSAndrzej Pietrasiewicz 
28200a2430fSAndrzej Pietrasiewicz 	req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
28300a2430fSAndrzej Pietrasiewicz 
28400a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&ffs->ev.waitq.lock);
28500a2430fSAndrzej Pietrasiewicz 
28600a2430fSAndrzej Pietrasiewicz 	req->buf      = data;
28700a2430fSAndrzej Pietrasiewicz 	req->length   = len;
28800a2430fSAndrzej Pietrasiewicz 
28900a2430fSAndrzej Pietrasiewicz 	/*
29000a2430fSAndrzej Pietrasiewicz 	 * UDC layer requires to provide a buffer even for ZLP, but should
29100a2430fSAndrzej Pietrasiewicz 	 * not use it at all. Let's provide some poisoned pointer to catch
29200a2430fSAndrzej Pietrasiewicz 	 * possible bug in the driver.
29300a2430fSAndrzej Pietrasiewicz 	 */
29400a2430fSAndrzej Pietrasiewicz 	if (req->buf == NULL)
29500a2430fSAndrzej Pietrasiewicz 		req->buf = (void *)0xDEADBABE;
29600a2430fSAndrzej Pietrasiewicz 
29700a2430fSAndrzej Pietrasiewicz 	reinit_completion(&ffs->ep0req_completion);
29800a2430fSAndrzej Pietrasiewicz 
29900a2430fSAndrzej Pietrasiewicz 	ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
3008704fd73SGreg Kroah-Hartman 	if (ret < 0)
30100a2430fSAndrzej Pietrasiewicz 		return ret;
30200a2430fSAndrzej Pietrasiewicz 
30300a2430fSAndrzej Pietrasiewicz 	ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
3048704fd73SGreg Kroah-Hartman 	if (ret) {
30500a2430fSAndrzej Pietrasiewicz 		usb_ep_dequeue(ffs->gadget->ep0, req);
30600a2430fSAndrzej Pietrasiewicz 		return -EINTR;
30700a2430fSAndrzej Pietrasiewicz 	}
30800a2430fSAndrzej Pietrasiewicz 
30900a2430fSAndrzej Pietrasiewicz 	ffs->setup_state = FFS_NO_SETUP;
31000a2430fSAndrzej Pietrasiewicz 	return req->status ? req->status : req->actual;
31100a2430fSAndrzej Pietrasiewicz }
31200a2430fSAndrzej Pietrasiewicz 
31300a2430fSAndrzej Pietrasiewicz static int __ffs_ep0_stall(struct ffs_data *ffs)
31400a2430fSAndrzej Pietrasiewicz {
31500a2430fSAndrzej Pietrasiewicz 	if (ffs->ev.can_stall) {
31600a2430fSAndrzej Pietrasiewicz 		pr_vdebug("ep0 stall\n");
31700a2430fSAndrzej Pietrasiewicz 		usb_ep_set_halt(ffs->gadget->ep0);
31800a2430fSAndrzej Pietrasiewicz 		ffs->setup_state = FFS_NO_SETUP;
31900a2430fSAndrzej Pietrasiewicz 		return -EL2HLT;
32000a2430fSAndrzej Pietrasiewicz 	} else {
32100a2430fSAndrzej Pietrasiewicz 		pr_debug("bogus ep0 stall!\n");
32200a2430fSAndrzej Pietrasiewicz 		return -ESRCH;
32300a2430fSAndrzej Pietrasiewicz 	}
32400a2430fSAndrzej Pietrasiewicz }
32500a2430fSAndrzej Pietrasiewicz 
32600a2430fSAndrzej Pietrasiewicz static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
32700a2430fSAndrzej Pietrasiewicz 			     size_t len, loff_t *ptr)
32800a2430fSAndrzej Pietrasiewicz {
32900a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
33000a2430fSAndrzej Pietrasiewicz 	ssize_t ret;
33100a2430fSAndrzej Pietrasiewicz 	char *data;
33200a2430fSAndrzej Pietrasiewicz 
33300a2430fSAndrzej Pietrasiewicz 	ENTER();
33400a2430fSAndrzej Pietrasiewicz 
33500a2430fSAndrzej Pietrasiewicz 	/* Fast check if setup was canceled */
33600a2430fSAndrzej Pietrasiewicz 	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
33700a2430fSAndrzej Pietrasiewicz 		return -EIDRM;
33800a2430fSAndrzej Pietrasiewicz 
33900a2430fSAndrzej Pietrasiewicz 	/* Acquire mutex */
34000a2430fSAndrzej Pietrasiewicz 	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
3418704fd73SGreg Kroah-Hartman 	if (ret < 0)
34200a2430fSAndrzej Pietrasiewicz 		return ret;
34300a2430fSAndrzej Pietrasiewicz 
34400a2430fSAndrzej Pietrasiewicz 	/* Check state */
34500a2430fSAndrzej Pietrasiewicz 	switch (ffs->state) {
34600a2430fSAndrzej Pietrasiewicz 	case FFS_READ_DESCRIPTORS:
34700a2430fSAndrzej Pietrasiewicz 	case FFS_READ_STRINGS:
34800a2430fSAndrzej Pietrasiewicz 		/* Copy data */
3498704fd73SGreg Kroah-Hartman 		if (len < 16) {
35000a2430fSAndrzej Pietrasiewicz 			ret = -EINVAL;
35100a2430fSAndrzej Pietrasiewicz 			break;
35200a2430fSAndrzej Pietrasiewicz 		}
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 		/* Handle data */
36100a2430fSAndrzej Pietrasiewicz 		if (ffs->state == FFS_READ_DESCRIPTORS) {
36200a2430fSAndrzej Pietrasiewicz 			pr_info("read descriptors\n");
36300a2430fSAndrzej Pietrasiewicz 			ret = __ffs_data_got_descs(ffs, data, len);
3648704fd73SGreg Kroah-Hartman 			if (ret < 0)
36500a2430fSAndrzej Pietrasiewicz 				break;
36600a2430fSAndrzej Pietrasiewicz 
36700a2430fSAndrzej Pietrasiewicz 			ffs->state = FFS_READ_STRINGS;
36800a2430fSAndrzej Pietrasiewicz 			ret = len;
36900a2430fSAndrzej Pietrasiewicz 		} else {
37000a2430fSAndrzej Pietrasiewicz 			pr_info("read strings\n");
37100a2430fSAndrzej Pietrasiewicz 			ret = __ffs_data_got_strings(ffs, data, len);
3728704fd73SGreg Kroah-Hartman 			if (ret < 0)
37300a2430fSAndrzej Pietrasiewicz 				break;
37400a2430fSAndrzej Pietrasiewicz 
37500a2430fSAndrzej Pietrasiewicz 			ret = ffs_epfiles_create(ffs);
3768704fd73SGreg Kroah-Hartman 			if (ret) {
37700a2430fSAndrzej Pietrasiewicz 				ffs->state = FFS_CLOSING;
37800a2430fSAndrzej Pietrasiewicz 				break;
37900a2430fSAndrzej Pietrasiewicz 			}
38000a2430fSAndrzej Pietrasiewicz 
38100a2430fSAndrzej Pietrasiewicz 			ffs->state = FFS_ACTIVE;
38200a2430fSAndrzej Pietrasiewicz 			mutex_unlock(&ffs->mutex);
38300a2430fSAndrzej Pietrasiewicz 
38400a2430fSAndrzej Pietrasiewicz 			ret = ffs_ready(ffs);
3858704fd73SGreg Kroah-Hartman 			if (ret < 0) {
38600a2430fSAndrzej Pietrasiewicz 				ffs->state = FFS_CLOSING;
38700a2430fSAndrzej Pietrasiewicz 				return ret;
38800a2430fSAndrzej Pietrasiewicz 			}
38900a2430fSAndrzej Pietrasiewicz 
39000a2430fSAndrzej Pietrasiewicz 			return len;
39100a2430fSAndrzej Pietrasiewicz 		}
39200a2430fSAndrzej Pietrasiewicz 		break;
39300a2430fSAndrzej Pietrasiewicz 
39400a2430fSAndrzej Pietrasiewicz 	case FFS_ACTIVE:
39500a2430fSAndrzej Pietrasiewicz 		data = NULL;
39600a2430fSAndrzej Pietrasiewicz 		/*
39700a2430fSAndrzej Pietrasiewicz 		 * We're called from user space, we can use _irq
39800a2430fSAndrzej Pietrasiewicz 		 * rather then _irqsave
39900a2430fSAndrzej Pietrasiewicz 		 */
40000a2430fSAndrzej Pietrasiewicz 		spin_lock_irq(&ffs->ev.waitq.lock);
40100a2430fSAndrzej Pietrasiewicz 		switch (ffs_setup_state_clear_cancelled(ffs)) {
40200a2430fSAndrzej Pietrasiewicz 		case FFS_SETUP_CANCELLED:
40300a2430fSAndrzej Pietrasiewicz 			ret = -EIDRM;
40400a2430fSAndrzej Pietrasiewicz 			goto done_spin;
40500a2430fSAndrzej Pietrasiewicz 
40600a2430fSAndrzej Pietrasiewicz 		case FFS_NO_SETUP:
40700a2430fSAndrzej Pietrasiewicz 			ret = -ESRCH;
40800a2430fSAndrzej Pietrasiewicz 			goto done_spin;
40900a2430fSAndrzej Pietrasiewicz 
41000a2430fSAndrzej Pietrasiewicz 		case FFS_SETUP_PENDING:
41100a2430fSAndrzej Pietrasiewicz 			break;
41200a2430fSAndrzej Pietrasiewicz 		}
41300a2430fSAndrzej Pietrasiewicz 
41400a2430fSAndrzej Pietrasiewicz 		/* FFS_SETUP_PENDING */
41500a2430fSAndrzej Pietrasiewicz 		if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
41600a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&ffs->ev.waitq.lock);
41700a2430fSAndrzej Pietrasiewicz 			ret = __ffs_ep0_stall(ffs);
41800a2430fSAndrzej Pietrasiewicz 			break;
41900a2430fSAndrzej Pietrasiewicz 		}
42000a2430fSAndrzej Pietrasiewicz 
42100a2430fSAndrzej Pietrasiewicz 		/* FFS_SETUP_PENDING and not stall */
42200a2430fSAndrzej Pietrasiewicz 		len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
42300a2430fSAndrzej Pietrasiewicz 
42400a2430fSAndrzej Pietrasiewicz 		spin_unlock_irq(&ffs->ev.waitq.lock);
42500a2430fSAndrzej Pietrasiewicz 
42600a2430fSAndrzej Pietrasiewicz 		data = ffs_prepare_buffer(buf, len);
42700a2430fSAndrzej Pietrasiewicz 		if (IS_ERR(data)) {
42800a2430fSAndrzej Pietrasiewicz 			ret = PTR_ERR(data);
42900a2430fSAndrzej Pietrasiewicz 			break;
43000a2430fSAndrzej Pietrasiewicz 		}
43100a2430fSAndrzej Pietrasiewicz 
43200a2430fSAndrzej Pietrasiewicz 		spin_lock_irq(&ffs->ev.waitq.lock);
43300a2430fSAndrzej Pietrasiewicz 
43400a2430fSAndrzej Pietrasiewicz 		/*
43500a2430fSAndrzej Pietrasiewicz 		 * We are guaranteed to be still in FFS_ACTIVE state
43600a2430fSAndrzej Pietrasiewicz 		 * but the state of setup could have changed from
43700a2430fSAndrzej Pietrasiewicz 		 * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need
43800a2430fSAndrzej Pietrasiewicz 		 * to check for that.  If that happened we copied data
43900a2430fSAndrzej Pietrasiewicz 		 * from user space in vain but it's unlikely.
44000a2430fSAndrzej Pietrasiewicz 		 *
44100a2430fSAndrzej Pietrasiewicz 		 * For sure we are not in FFS_NO_SETUP since this is
44200a2430fSAndrzej Pietrasiewicz 		 * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
44300a2430fSAndrzej Pietrasiewicz 		 * transition can be performed and it's protected by
44400a2430fSAndrzej Pietrasiewicz 		 * mutex.
44500a2430fSAndrzej Pietrasiewicz 		 */
44600a2430fSAndrzej Pietrasiewicz 		if (ffs_setup_state_clear_cancelled(ffs) ==
44700a2430fSAndrzej Pietrasiewicz 		    FFS_SETUP_CANCELLED) {
44800a2430fSAndrzej Pietrasiewicz 			ret = -EIDRM;
44900a2430fSAndrzej Pietrasiewicz done_spin:
45000a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&ffs->ev.waitq.lock);
45100a2430fSAndrzej Pietrasiewicz 		} else {
45200a2430fSAndrzej Pietrasiewicz 			/* unlocks spinlock */
45300a2430fSAndrzej Pietrasiewicz 			ret = __ffs_ep0_queue_wait(ffs, data, len);
45400a2430fSAndrzej Pietrasiewicz 		}
45500a2430fSAndrzej Pietrasiewicz 		kfree(data);
45600a2430fSAndrzej Pietrasiewicz 		break;
45700a2430fSAndrzej Pietrasiewicz 
45800a2430fSAndrzej Pietrasiewicz 	default:
45900a2430fSAndrzej Pietrasiewicz 		ret = -EBADFD;
46000a2430fSAndrzej Pietrasiewicz 		break;
46100a2430fSAndrzej Pietrasiewicz 	}
46200a2430fSAndrzej Pietrasiewicz 
46300a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&ffs->mutex);
46400a2430fSAndrzej Pietrasiewicz 	return ret;
46500a2430fSAndrzej Pietrasiewicz }
46600a2430fSAndrzej Pietrasiewicz 
46767913bbdSMichal Nazarewicz /* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
46800a2430fSAndrzej Pietrasiewicz static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
46900a2430fSAndrzej Pietrasiewicz 				     size_t n)
470c40619bbSVincent Pelletier 	__releases(&ffs->ev.waitq.lock)
47100a2430fSAndrzej Pietrasiewicz {
47200a2430fSAndrzej Pietrasiewicz 	/*
47367913bbdSMichal Nazarewicz 	 * n cannot be bigger than ffs->ev.count, which cannot be bigger than
47467913bbdSMichal Nazarewicz 	 * size of ffs->ev.types array (which is four) so that's how much space
47567913bbdSMichal Nazarewicz 	 * we reserve.
47600a2430fSAndrzej Pietrasiewicz 	 */
47767913bbdSMichal Nazarewicz 	struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
47867913bbdSMichal Nazarewicz 	const size_t size = n * sizeof *events;
47900a2430fSAndrzej Pietrasiewicz 	unsigned i = 0;
48000a2430fSAndrzej Pietrasiewicz 
48167913bbdSMichal Nazarewicz 	memset(events, 0, size);
48200a2430fSAndrzej Pietrasiewicz 
48300a2430fSAndrzej Pietrasiewicz 	do {
48400a2430fSAndrzej Pietrasiewicz 		events[i].type = ffs->ev.types[i];
48500a2430fSAndrzej Pietrasiewicz 		if (events[i].type == FUNCTIONFS_SETUP) {
48600a2430fSAndrzej Pietrasiewicz 			events[i].u.setup = ffs->ev.setup;
48700a2430fSAndrzej Pietrasiewicz 			ffs->setup_state = FFS_SETUP_PENDING;
48800a2430fSAndrzej Pietrasiewicz 		}
48900a2430fSAndrzej Pietrasiewicz 	} while (++i < n);
49000a2430fSAndrzej Pietrasiewicz 
49100a2430fSAndrzej Pietrasiewicz 	ffs->ev.count -= n;
49267913bbdSMichal Nazarewicz 	if (ffs->ev.count)
49300a2430fSAndrzej Pietrasiewicz 		memmove(ffs->ev.types, ffs->ev.types + n,
49400a2430fSAndrzej Pietrasiewicz 			ffs->ev.count * sizeof *ffs->ev.types);
49500a2430fSAndrzej Pietrasiewicz 
49600a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&ffs->ev.waitq.lock);
49700a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&ffs->mutex);
49800a2430fSAndrzej Pietrasiewicz 
4998704fd73SGreg Kroah-Hartman 	return copy_to_user(buf, events, size) ? -EFAULT : size;
50000a2430fSAndrzej Pietrasiewicz }
50100a2430fSAndrzej Pietrasiewicz 
50200a2430fSAndrzej Pietrasiewicz static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
50300a2430fSAndrzej Pietrasiewicz 			    size_t len, loff_t *ptr)
50400a2430fSAndrzej Pietrasiewicz {
50500a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
50600a2430fSAndrzej Pietrasiewicz 	char *data = NULL;
50700a2430fSAndrzej Pietrasiewicz 	size_t n;
50800a2430fSAndrzej Pietrasiewicz 	int ret;
50900a2430fSAndrzej Pietrasiewicz 
51000a2430fSAndrzej Pietrasiewicz 	ENTER();
51100a2430fSAndrzej Pietrasiewicz 
51200a2430fSAndrzej Pietrasiewicz 	/* Fast check if setup was canceled */
51300a2430fSAndrzej Pietrasiewicz 	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
51400a2430fSAndrzej Pietrasiewicz 		return -EIDRM;
51500a2430fSAndrzej Pietrasiewicz 
51600a2430fSAndrzej Pietrasiewicz 	/* Acquire mutex */
51700a2430fSAndrzej Pietrasiewicz 	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
5188704fd73SGreg Kroah-Hartman 	if (ret < 0)
51900a2430fSAndrzej Pietrasiewicz 		return ret;
52000a2430fSAndrzej Pietrasiewicz 
52100a2430fSAndrzej Pietrasiewicz 	/* Check state */
52200a2430fSAndrzej Pietrasiewicz 	if (ffs->state != FFS_ACTIVE) {
52300a2430fSAndrzej Pietrasiewicz 		ret = -EBADFD;
52400a2430fSAndrzej Pietrasiewicz 		goto done_mutex;
52500a2430fSAndrzej Pietrasiewicz 	}
52600a2430fSAndrzej Pietrasiewicz 
52700a2430fSAndrzej Pietrasiewicz 	/*
52800a2430fSAndrzej Pietrasiewicz 	 * We're called from user space, we can use _irq rather then
52900a2430fSAndrzej Pietrasiewicz 	 * _irqsave
53000a2430fSAndrzej Pietrasiewicz 	 */
53100a2430fSAndrzej Pietrasiewicz 	spin_lock_irq(&ffs->ev.waitq.lock);
53200a2430fSAndrzej Pietrasiewicz 
53300a2430fSAndrzej Pietrasiewicz 	switch (ffs_setup_state_clear_cancelled(ffs)) {
53400a2430fSAndrzej Pietrasiewicz 	case FFS_SETUP_CANCELLED:
53500a2430fSAndrzej Pietrasiewicz 		ret = -EIDRM;
53600a2430fSAndrzej Pietrasiewicz 		break;
53700a2430fSAndrzej Pietrasiewicz 
53800a2430fSAndrzej Pietrasiewicz 	case FFS_NO_SETUP:
53900a2430fSAndrzej Pietrasiewicz 		n = len / sizeof(struct usb_functionfs_event);
5408704fd73SGreg Kroah-Hartman 		if (!n) {
54100a2430fSAndrzej Pietrasiewicz 			ret = -EINVAL;
54200a2430fSAndrzej Pietrasiewicz 			break;
54300a2430fSAndrzej Pietrasiewicz 		}
54400a2430fSAndrzej Pietrasiewicz 
54500a2430fSAndrzej Pietrasiewicz 		if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
54600a2430fSAndrzej Pietrasiewicz 			ret = -EAGAIN;
54700a2430fSAndrzej Pietrasiewicz 			break;
54800a2430fSAndrzej Pietrasiewicz 		}
54900a2430fSAndrzej Pietrasiewicz 
55000a2430fSAndrzej Pietrasiewicz 		if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
55100a2430fSAndrzej Pietrasiewicz 							ffs->ev.count)) {
55200a2430fSAndrzej Pietrasiewicz 			ret = -EINTR;
55300a2430fSAndrzej Pietrasiewicz 			break;
55400a2430fSAndrzej Pietrasiewicz 		}
55500a2430fSAndrzej Pietrasiewicz 
556c40619bbSVincent Pelletier 		/* unlocks spinlock */
55700a2430fSAndrzej Pietrasiewicz 		return __ffs_ep0_read_events(ffs, buf,
55800a2430fSAndrzej Pietrasiewicz 					     min(n, (size_t)ffs->ev.count));
55900a2430fSAndrzej Pietrasiewicz 
56000a2430fSAndrzej Pietrasiewicz 	case FFS_SETUP_PENDING:
56100a2430fSAndrzej Pietrasiewicz 		if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
56200a2430fSAndrzej Pietrasiewicz 			spin_unlock_irq(&ffs->ev.waitq.lock);
56300a2430fSAndrzej Pietrasiewicz 			ret = __ffs_ep0_stall(ffs);
56400a2430fSAndrzej Pietrasiewicz 			goto done_mutex;
56500a2430fSAndrzej Pietrasiewicz 		}
56600a2430fSAndrzej Pietrasiewicz 
56700a2430fSAndrzej Pietrasiewicz 		len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
56800a2430fSAndrzej Pietrasiewicz 
56900a2430fSAndrzej Pietrasiewicz 		spin_unlock_irq(&ffs->ev.waitq.lock);
57000a2430fSAndrzej Pietrasiewicz 
5718704fd73SGreg Kroah-Hartman 		if (len) {
57200a2430fSAndrzej Pietrasiewicz 			data = kmalloc(len, GFP_KERNEL);
5738704fd73SGreg Kroah-Hartman 			if (!data) {
57400a2430fSAndrzej Pietrasiewicz 				ret = -ENOMEM;
57500a2430fSAndrzej Pietrasiewicz 				goto done_mutex;
57600a2430fSAndrzej Pietrasiewicz 			}
57700a2430fSAndrzej Pietrasiewicz 		}
57800a2430fSAndrzej Pietrasiewicz 
57900a2430fSAndrzej Pietrasiewicz 		spin_lock_irq(&ffs->ev.waitq.lock);
58000a2430fSAndrzej Pietrasiewicz 
58100a2430fSAndrzej Pietrasiewicz 		/* See ffs_ep0_write() */
58200a2430fSAndrzej Pietrasiewicz 		if (ffs_setup_state_clear_cancelled(ffs) ==
58300a2430fSAndrzej Pietrasiewicz 		    FFS_SETUP_CANCELLED) {
58400a2430fSAndrzej Pietrasiewicz 			ret = -EIDRM;
58500a2430fSAndrzej Pietrasiewicz 			break;
58600a2430fSAndrzej Pietrasiewicz 		}
58700a2430fSAndrzej Pietrasiewicz 
58800a2430fSAndrzej Pietrasiewicz 		/* unlocks spinlock */
58900a2430fSAndrzej Pietrasiewicz 		ret = __ffs_ep0_queue_wait(ffs, data, len);
5908704fd73SGreg Kroah-Hartman 		if ((ret > 0) && (copy_to_user(buf, data, len)))
59100a2430fSAndrzej Pietrasiewicz 			ret = -EFAULT;
59200a2430fSAndrzej Pietrasiewicz 		goto done_mutex;
59300a2430fSAndrzej Pietrasiewicz 
59400a2430fSAndrzej Pietrasiewicz 	default:
59500a2430fSAndrzej Pietrasiewicz 		ret = -EBADFD;
59600a2430fSAndrzej Pietrasiewicz 		break;
59700a2430fSAndrzej Pietrasiewicz 	}
59800a2430fSAndrzej Pietrasiewicz 
59900a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&ffs->ev.waitq.lock);
60000a2430fSAndrzej Pietrasiewicz done_mutex:
60100a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&ffs->mutex);
60200a2430fSAndrzej Pietrasiewicz 	kfree(data);
60300a2430fSAndrzej Pietrasiewicz 	return ret;
60400a2430fSAndrzej Pietrasiewicz }
60500a2430fSAndrzej Pietrasiewicz 
60600a2430fSAndrzej Pietrasiewicz static int ffs_ep0_open(struct inode *inode, struct file *file)
60700a2430fSAndrzej Pietrasiewicz {
60800a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = inode->i_private;
60900a2430fSAndrzej Pietrasiewicz 
61000a2430fSAndrzej Pietrasiewicz 	ENTER();
61100a2430fSAndrzej Pietrasiewicz 
6128704fd73SGreg Kroah-Hartman 	if (ffs->state == FFS_CLOSING)
61300a2430fSAndrzej Pietrasiewicz 		return -EBUSY;
61400a2430fSAndrzej Pietrasiewicz 
61500a2430fSAndrzej Pietrasiewicz 	file->private_data = ffs;
61600a2430fSAndrzej Pietrasiewicz 	ffs_data_opened(ffs);
61700a2430fSAndrzej Pietrasiewicz 
618c76ef96fSPavankumar Kondeti 	return stream_open(inode, file);
61900a2430fSAndrzej Pietrasiewicz }
62000a2430fSAndrzej Pietrasiewicz 
62100a2430fSAndrzej Pietrasiewicz static int ffs_ep0_release(struct inode *inode, struct file *file)
62200a2430fSAndrzej Pietrasiewicz {
62300a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
62400a2430fSAndrzej Pietrasiewicz 
62500a2430fSAndrzej Pietrasiewicz 	ENTER();
62600a2430fSAndrzej Pietrasiewicz 
62700a2430fSAndrzej Pietrasiewicz 	ffs_data_closed(ffs);
62800a2430fSAndrzej Pietrasiewicz 
62900a2430fSAndrzej Pietrasiewicz 	return 0;
63000a2430fSAndrzej Pietrasiewicz }
63100a2430fSAndrzej Pietrasiewicz 
63200a2430fSAndrzej Pietrasiewicz static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
63300a2430fSAndrzej Pietrasiewicz {
63400a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
63500a2430fSAndrzej Pietrasiewicz 	struct usb_gadget *gadget = ffs->gadget;
63600a2430fSAndrzej Pietrasiewicz 	long ret;
63700a2430fSAndrzej Pietrasiewicz 
63800a2430fSAndrzej Pietrasiewicz 	ENTER();
63900a2430fSAndrzej Pietrasiewicz 
64000a2430fSAndrzej Pietrasiewicz 	if (code == FUNCTIONFS_INTERFACE_REVMAP) {
64100a2430fSAndrzej Pietrasiewicz 		struct ffs_function *func = ffs->func;
64200a2430fSAndrzej Pietrasiewicz 		ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
64300a2430fSAndrzej Pietrasiewicz 	} else if (gadget && gadget->ops->ioctl) {
64400a2430fSAndrzej Pietrasiewicz 		ret = gadget->ops->ioctl(gadget, code, value);
64500a2430fSAndrzej Pietrasiewicz 	} else {
64600a2430fSAndrzej Pietrasiewicz 		ret = -ENOTTY;
64700a2430fSAndrzej Pietrasiewicz 	}
64800a2430fSAndrzej Pietrasiewicz 
64900a2430fSAndrzej Pietrasiewicz 	return ret;
65000a2430fSAndrzej Pietrasiewicz }
65100a2430fSAndrzej Pietrasiewicz 
652afc9a42bSAl Viro static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait)
65300a2430fSAndrzej Pietrasiewicz {
65400a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = file->private_data;
655a9a08845SLinus Torvalds 	__poll_t mask = EPOLLWRNORM;
65600a2430fSAndrzej Pietrasiewicz 	int ret;
65700a2430fSAndrzej Pietrasiewicz 
65800a2430fSAndrzej Pietrasiewicz 	poll_wait(file, &ffs->ev.waitq, wait);
65900a2430fSAndrzej Pietrasiewicz 
66000a2430fSAndrzej Pietrasiewicz 	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
6618704fd73SGreg Kroah-Hartman 	if (ret < 0)
66200a2430fSAndrzej Pietrasiewicz 		return mask;
66300a2430fSAndrzej Pietrasiewicz 
66400a2430fSAndrzej Pietrasiewicz 	switch (ffs->state) {
66500a2430fSAndrzej Pietrasiewicz 	case FFS_READ_DESCRIPTORS:
66600a2430fSAndrzej Pietrasiewicz 	case FFS_READ_STRINGS:
667a9a08845SLinus Torvalds 		mask |= EPOLLOUT;
66800a2430fSAndrzej Pietrasiewicz 		break;
66900a2430fSAndrzej Pietrasiewicz 
67000a2430fSAndrzej Pietrasiewicz 	case FFS_ACTIVE:
67100a2430fSAndrzej Pietrasiewicz 		switch (ffs->setup_state) {
67200a2430fSAndrzej Pietrasiewicz 		case FFS_NO_SETUP:
67300a2430fSAndrzej Pietrasiewicz 			if (ffs->ev.count)
674a9a08845SLinus Torvalds 				mask |= EPOLLIN;
67500a2430fSAndrzej Pietrasiewicz 			break;
67600a2430fSAndrzej Pietrasiewicz 
67700a2430fSAndrzej Pietrasiewicz 		case FFS_SETUP_PENDING:
67800a2430fSAndrzej Pietrasiewicz 		case FFS_SETUP_CANCELLED:
679a9a08845SLinus Torvalds 			mask |= (EPOLLIN | EPOLLOUT);
68000a2430fSAndrzej Pietrasiewicz 			break;
68100a2430fSAndrzej Pietrasiewicz 		}
68293c747edSGustavo A. R. Silva 		break;
68393c747edSGustavo A. R. Silva 
68400a2430fSAndrzej Pietrasiewicz 	case FFS_CLOSING:
68500a2430fSAndrzej Pietrasiewicz 		break;
68618d6b32fSRobert Baldyga 	case FFS_DEACTIVATED:
68718d6b32fSRobert Baldyga 		break;
68800a2430fSAndrzej Pietrasiewicz 	}
68900a2430fSAndrzej Pietrasiewicz 
69000a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&ffs->mutex);
69100a2430fSAndrzej Pietrasiewicz 
69200a2430fSAndrzej Pietrasiewicz 	return mask;
69300a2430fSAndrzej Pietrasiewicz }
69400a2430fSAndrzej Pietrasiewicz 
69500a2430fSAndrzej Pietrasiewicz static const struct file_operations ffs_ep0_operations = {
69600a2430fSAndrzej Pietrasiewicz 	.llseek =	no_llseek,
69700a2430fSAndrzej Pietrasiewicz 
69800a2430fSAndrzej Pietrasiewicz 	.open =		ffs_ep0_open,
69900a2430fSAndrzej Pietrasiewicz 	.write =	ffs_ep0_write,
70000a2430fSAndrzej Pietrasiewicz 	.read =		ffs_ep0_read,
70100a2430fSAndrzej Pietrasiewicz 	.release =	ffs_ep0_release,
70200a2430fSAndrzej Pietrasiewicz 	.unlocked_ioctl =	ffs_ep0_ioctl,
70300a2430fSAndrzej Pietrasiewicz 	.poll =		ffs_ep0_poll,
70400a2430fSAndrzej Pietrasiewicz };
70500a2430fSAndrzej Pietrasiewicz 
70600a2430fSAndrzej Pietrasiewicz 
70700a2430fSAndrzej Pietrasiewicz /* "Normal" endpoints operations ********************************************/
70800a2430fSAndrzej Pietrasiewicz 
70900a2430fSAndrzej Pietrasiewicz static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
71000a2430fSAndrzej Pietrasiewicz {
711fb1f16d7SLinyu Yuan 	struct ffs_io_data *io_data = req->context;
712fb1f16d7SLinyu Yuan 
71300a2430fSAndrzej Pietrasiewicz 	ENTER();
714fb1f16d7SLinyu Yuan 	if (req->status)
715fb1f16d7SLinyu Yuan 		io_data->status = req->status;
716fb1f16d7SLinyu Yuan 	else
717fb1f16d7SLinyu Yuan 		io_data->status = req->actual;
718fb1f16d7SLinyu Yuan 
719fb1f16d7SLinyu Yuan 	complete(&io_data->done);
72000a2430fSAndrzej Pietrasiewicz }
72100a2430fSAndrzej Pietrasiewicz 
722c662a31bSMichal Nazarewicz static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
723c662a31bSMichal Nazarewicz {
724c662a31bSMichal Nazarewicz 	ssize_t ret = copy_to_iter(data, data_len, iter);
7258704fd73SGreg Kroah-Hartman 	if (ret == data_len)
726c662a31bSMichal Nazarewicz 		return ret;
727c662a31bSMichal Nazarewicz 
7288704fd73SGreg Kroah-Hartman 	if (iov_iter_count(iter))
729c662a31bSMichal Nazarewicz 		return -EFAULT;
730c662a31bSMichal Nazarewicz 
731c662a31bSMichal Nazarewicz 	/*
732c662a31bSMichal Nazarewicz 	 * Dear user space developer!
733c662a31bSMichal Nazarewicz 	 *
734c662a31bSMichal Nazarewicz 	 * TL;DR: To stop getting below error message in your kernel log, change
735c662a31bSMichal Nazarewicz 	 * user space code using functionfs to align read buffers to a max
736c662a31bSMichal Nazarewicz 	 * packet size.
737c662a31bSMichal Nazarewicz 	 *
738c662a31bSMichal Nazarewicz 	 * Some UDCs (e.g. dwc3) require request sizes to be a multiple of a max
739c662a31bSMichal Nazarewicz 	 * packet size.  When unaligned buffer is passed to functionfs, it
740c662a31bSMichal Nazarewicz 	 * internally uses a larger, aligned buffer so that such UDCs are happy.
741c662a31bSMichal Nazarewicz 	 *
742c662a31bSMichal Nazarewicz 	 * Unfortunately, this means that host may send more data than was
743c662a31bSMichal Nazarewicz 	 * requested in read(2) system call.  f_fs doesn’t know what to do with
744c662a31bSMichal Nazarewicz 	 * that excess data so it simply drops it.
745c662a31bSMichal Nazarewicz 	 *
746c662a31bSMichal Nazarewicz 	 * Was the buffer aligned in the first place, no such problem would
747c662a31bSMichal Nazarewicz 	 * happen.
748c662a31bSMichal Nazarewicz 	 *
7499353afbbSMichal Nazarewicz 	 * Data may be dropped only in AIO reads.  Synchronous reads are handled
7509353afbbSMichal Nazarewicz 	 * by splitting a request into multiple parts.  This splitting may still
7519353afbbSMichal Nazarewicz 	 * be a problem though so it’s likely best to align the buffer
7529353afbbSMichal Nazarewicz 	 * regardless of it being AIO or not..
7539353afbbSMichal Nazarewicz 	 *
754c662a31bSMichal Nazarewicz 	 * This only affects OUT endpoints, i.e. reading data with a read(2),
755c662a31bSMichal Nazarewicz 	 * aio_read(2) etc. system calls.  Writing data to an IN endpoint is not
756c662a31bSMichal Nazarewicz 	 * affected.
757c662a31bSMichal Nazarewicz 	 */
758c662a31bSMichal Nazarewicz 	pr_err("functionfs read size %d > requested size %zd, dropping excess data. "
759c662a31bSMichal Nazarewicz 	       "Align read buffer size to max packet size to avoid the problem.\n",
760c662a31bSMichal Nazarewicz 	       data_len, ret);
761c662a31bSMichal Nazarewicz 
762c662a31bSMichal Nazarewicz 	return ret;
763c662a31bSMichal Nazarewicz }
764c662a31bSMichal Nazarewicz 
765772a7a72SAndrzej Pietrasiewicz /*
766772a7a72SAndrzej Pietrasiewicz  * allocate a virtually contiguous buffer and create a scatterlist describing it
767772a7a72SAndrzej Pietrasiewicz  * @sg_table	- pointer to a place to be filled with sg_table contents
768772a7a72SAndrzej Pietrasiewicz  * @size	- required buffer size
769772a7a72SAndrzej Pietrasiewicz  */
770772a7a72SAndrzej Pietrasiewicz static void *ffs_build_sg_list(struct sg_table *sgt, size_t sz)
771772a7a72SAndrzej Pietrasiewicz {
772772a7a72SAndrzej Pietrasiewicz 	struct page **pages;
773772a7a72SAndrzej Pietrasiewicz 	void *vaddr, *ptr;
774772a7a72SAndrzej Pietrasiewicz 	unsigned int n_pages;
775772a7a72SAndrzej Pietrasiewicz 	int i;
776772a7a72SAndrzej Pietrasiewicz 
777772a7a72SAndrzej Pietrasiewicz 	vaddr = vmalloc(sz);
778772a7a72SAndrzej Pietrasiewicz 	if (!vaddr)
779772a7a72SAndrzej Pietrasiewicz 		return NULL;
780772a7a72SAndrzej Pietrasiewicz 
781772a7a72SAndrzej Pietrasiewicz 	n_pages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
782772a7a72SAndrzej Pietrasiewicz 	pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL);
783772a7a72SAndrzej Pietrasiewicz 	if (!pages) {
784772a7a72SAndrzej Pietrasiewicz 		vfree(vaddr);
785772a7a72SAndrzej Pietrasiewicz 
786772a7a72SAndrzej Pietrasiewicz 		return NULL;
787772a7a72SAndrzej Pietrasiewicz 	}
788772a7a72SAndrzej Pietrasiewicz 	for (i = 0, ptr = vaddr; i < n_pages; ++i, ptr += PAGE_SIZE)
789772a7a72SAndrzej Pietrasiewicz 		pages[i] = vmalloc_to_page(ptr);
790772a7a72SAndrzej Pietrasiewicz 
791772a7a72SAndrzej Pietrasiewicz 	if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL)) {
792772a7a72SAndrzej Pietrasiewicz 		kvfree(pages);
793772a7a72SAndrzej Pietrasiewicz 		vfree(vaddr);
794772a7a72SAndrzej Pietrasiewicz 
795772a7a72SAndrzej Pietrasiewicz 		return NULL;
796772a7a72SAndrzej Pietrasiewicz 	}
797772a7a72SAndrzej Pietrasiewicz 	kvfree(pages);
798772a7a72SAndrzej Pietrasiewicz 
799772a7a72SAndrzej Pietrasiewicz 	return vaddr;
800772a7a72SAndrzej Pietrasiewicz }
801772a7a72SAndrzej Pietrasiewicz 
802772a7a72SAndrzej Pietrasiewicz static inline void *ffs_alloc_buffer(struct ffs_io_data *io_data,
803772a7a72SAndrzej Pietrasiewicz 	size_t data_len)
804772a7a72SAndrzej Pietrasiewicz {
805772a7a72SAndrzej Pietrasiewicz 	if (io_data->use_sg)
806772a7a72SAndrzej Pietrasiewicz 		return ffs_build_sg_list(&io_data->sgt, data_len);
807772a7a72SAndrzej Pietrasiewicz 
808772a7a72SAndrzej Pietrasiewicz 	return kmalloc(data_len, GFP_KERNEL);
809772a7a72SAndrzej Pietrasiewicz }
810772a7a72SAndrzej Pietrasiewicz 
811772a7a72SAndrzej Pietrasiewicz static inline void ffs_free_buffer(struct ffs_io_data *io_data)
812772a7a72SAndrzej Pietrasiewicz {
813772a7a72SAndrzej Pietrasiewicz 	if (!io_data->buf)
814772a7a72SAndrzej Pietrasiewicz 		return;
815772a7a72SAndrzej Pietrasiewicz 
816772a7a72SAndrzej Pietrasiewicz 	if (io_data->use_sg) {
817772a7a72SAndrzej Pietrasiewicz 		sg_free_table(&io_data->sgt);
818772a7a72SAndrzej Pietrasiewicz 		vfree(io_data->buf);
819772a7a72SAndrzej Pietrasiewicz 	} else {
820772a7a72SAndrzej Pietrasiewicz 		kfree(io_data->buf);
821772a7a72SAndrzej Pietrasiewicz 	}
822772a7a72SAndrzej Pietrasiewicz }
823772a7a72SAndrzej Pietrasiewicz 
82400a2430fSAndrzej Pietrasiewicz static void ffs_user_copy_worker(struct work_struct *work)
82500a2430fSAndrzej Pietrasiewicz {
82600a2430fSAndrzej Pietrasiewicz 	struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
82700a2430fSAndrzej Pietrasiewicz 						   work);
82800a2430fSAndrzej Pietrasiewicz 	int ret = io_data->req->status ? io_data->req->status :
82900a2430fSAndrzej Pietrasiewicz 					 io_data->req->actual;
83038740a5bSLars-Peter Clausen 	bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
83100a2430fSAndrzej Pietrasiewicz 
83200a2430fSAndrzej Pietrasiewicz 	if (io_data->read && ret > 0) {
833f5678e7fSChristoph Hellwig 		kthread_use_mm(io_data->mm);
834c662a31bSMichal Nazarewicz 		ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data);
835f5678e7fSChristoph Hellwig 		kthread_unuse_mm(io_data->mm);
83600a2430fSAndrzej Pietrasiewicz 	}
83700a2430fSAndrzej Pietrasiewicz 
8386b19b766SJens Axboe 	io_data->kiocb->ki_complete(io_data->kiocb, ret);
83900a2430fSAndrzej Pietrasiewicz 
84038740a5bSLars-Peter Clausen 	if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
8415e33f6fdSRobert Baldyga 		eventfd_signal(io_data->ffs->ffs_eventfd, 1);
8425e33f6fdSRobert Baldyga 
84300a2430fSAndrzej Pietrasiewicz 	usb_ep_free_request(io_data->ep, io_data->req);
84400a2430fSAndrzej Pietrasiewicz 
84500a2430fSAndrzej Pietrasiewicz 	if (io_data->read)
846c993c39bSAl Viro 		kfree(io_data->to_free);
847772a7a72SAndrzej Pietrasiewicz 	ffs_free_buffer(io_data);
84800a2430fSAndrzej Pietrasiewicz 	kfree(io_data);
84900a2430fSAndrzej Pietrasiewicz }
85000a2430fSAndrzej Pietrasiewicz 
85100a2430fSAndrzej Pietrasiewicz static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
85200a2430fSAndrzej Pietrasiewicz 					 struct usb_request *req)
85300a2430fSAndrzej Pietrasiewicz {
85400a2430fSAndrzej Pietrasiewicz 	struct ffs_io_data *io_data = req->context;
855addfc582SJohn Keeping 	struct ffs_data *ffs = io_data->ffs;
85600a2430fSAndrzej Pietrasiewicz 
85700a2430fSAndrzej Pietrasiewicz 	ENTER();
85800a2430fSAndrzej Pietrasiewicz 
85900a2430fSAndrzej Pietrasiewicz 	INIT_WORK(&io_data->work, ffs_user_copy_worker);
860addfc582SJohn Keeping 	queue_work(ffs->io_completion_wq, &io_data->work);
86100a2430fSAndrzej Pietrasiewicz }
86200a2430fSAndrzej Pietrasiewicz 
863a9e6f83cSMichal Nazarewicz static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
864a9e6f83cSMichal Nazarewicz {
865a9e6f83cSMichal Nazarewicz 	/*
866a9e6f83cSMichal Nazarewicz 	 * See comment in struct ffs_epfile for full read_buffer pointer
867a9e6f83cSMichal Nazarewicz 	 * synchronisation story.
868a9e6f83cSMichal Nazarewicz 	 */
869a9e6f83cSMichal Nazarewicz 	struct ffs_buffer *buf = xchg(&epfile->read_buffer, READ_BUFFER_DROP);
870a9e6f83cSMichal Nazarewicz 	if (buf && buf != READ_BUFFER_DROP)
871a9e6f83cSMichal Nazarewicz 		kfree(buf);
872a9e6f83cSMichal Nazarewicz }
873a9e6f83cSMichal Nazarewicz 
8749353afbbSMichal Nazarewicz /* Assumes epfile->mutex is held. */
8759353afbbSMichal Nazarewicz static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile,
8769353afbbSMichal Nazarewicz 					  struct iov_iter *iter)
8779353afbbSMichal Nazarewicz {
878a9e6f83cSMichal Nazarewicz 	/*
879a9e6f83cSMichal Nazarewicz 	 * Null out epfile->read_buffer so ffs_func_eps_disable does not free
880a9e6f83cSMichal Nazarewicz 	 * the buffer while we are using it.  See comment in struct ffs_epfile
881a9e6f83cSMichal Nazarewicz 	 * for full read_buffer pointer synchronisation story.
882a9e6f83cSMichal Nazarewicz 	 */
883a9e6f83cSMichal Nazarewicz 	struct ffs_buffer *buf = xchg(&epfile->read_buffer, NULL);
8849353afbbSMichal Nazarewicz 	ssize_t ret;
885a9e6f83cSMichal Nazarewicz 	if (!buf || buf == READ_BUFFER_DROP)
8869353afbbSMichal Nazarewicz 		return 0;
8879353afbbSMichal Nazarewicz 
8889353afbbSMichal Nazarewicz 	ret = copy_to_iter(buf->data, buf->length, iter);
8899353afbbSMichal Nazarewicz 	if (buf->length == ret) {
8909353afbbSMichal Nazarewicz 		kfree(buf);
891a9e6f83cSMichal Nazarewicz 		return ret;
892a9e6f83cSMichal Nazarewicz 	}
893a9e6f83cSMichal Nazarewicz 
8948704fd73SGreg Kroah-Hartman 	if (iov_iter_count(iter)) {
8959353afbbSMichal Nazarewicz 		ret = -EFAULT;
8969353afbbSMichal Nazarewicz 	} else {
8979353afbbSMichal Nazarewicz 		buf->length -= ret;
8989353afbbSMichal Nazarewicz 		buf->data += ret;
8999353afbbSMichal Nazarewicz 	}
900a9e6f83cSMichal Nazarewicz 
901a9e6f83cSMichal Nazarewicz 	if (cmpxchg(&epfile->read_buffer, NULL, buf))
902a9e6f83cSMichal Nazarewicz 		kfree(buf);
903a9e6f83cSMichal Nazarewicz 
9049353afbbSMichal Nazarewicz 	return ret;
9059353afbbSMichal Nazarewicz }
9069353afbbSMichal Nazarewicz 
9079353afbbSMichal Nazarewicz /* Assumes epfile->mutex is held. */
9089353afbbSMichal Nazarewicz static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
9099353afbbSMichal Nazarewicz 				      void *data, int data_len,
9109353afbbSMichal Nazarewicz 				      struct iov_iter *iter)
9119353afbbSMichal Nazarewicz {
9129353afbbSMichal Nazarewicz 	struct ffs_buffer *buf;
9139353afbbSMichal Nazarewicz 
9149353afbbSMichal Nazarewicz 	ssize_t ret = copy_to_iter(data, data_len, iter);
9158704fd73SGreg Kroah-Hartman 	if (data_len == ret)
9169353afbbSMichal Nazarewicz 		return ret;
9179353afbbSMichal Nazarewicz 
9188704fd73SGreg Kroah-Hartman 	if (iov_iter_count(iter))
9199353afbbSMichal Nazarewicz 		return -EFAULT;
9209353afbbSMichal Nazarewicz 
9219353afbbSMichal Nazarewicz 	/* See ffs_copy_to_iter for more context. */
9229353afbbSMichal Nazarewicz 	pr_warn("functionfs read size %d > requested size %zd, splitting request into multiple reads.",
9239353afbbSMichal Nazarewicz 		data_len, ret);
9249353afbbSMichal Nazarewicz 
9259353afbbSMichal Nazarewicz 	data_len -= ret;
9264213e92eSGustavo A. R. Silva 	buf = kmalloc(struct_size(buf, storage, data_len), GFP_KERNEL);
92744963d64SDan Carpenter 	if (!buf)
92844963d64SDan Carpenter 		return -ENOMEM;
9299353afbbSMichal Nazarewicz 	buf->length = data_len;
9309353afbbSMichal Nazarewicz 	buf->data = buf->storage;
9314213e92eSGustavo A. R. Silva 	memcpy(buf->storage, data + ret, flex_array_size(buf, storage, data_len));
932a9e6f83cSMichal Nazarewicz 
933a9e6f83cSMichal Nazarewicz 	/*
934a9e6f83cSMichal Nazarewicz 	 * At this point read_buffer is NULL or READ_BUFFER_DROP (if
935a9e6f83cSMichal Nazarewicz 	 * ffs_func_eps_disable has been called in the meanwhile).  See comment
936a9e6f83cSMichal Nazarewicz 	 * in struct ffs_epfile for full read_buffer pointer synchronisation
937a9e6f83cSMichal Nazarewicz 	 * story.
938a9e6f83cSMichal Nazarewicz 	 */
9398704fd73SGreg Kroah-Hartman 	if (cmpxchg(&epfile->read_buffer, NULL, buf))
940a9e6f83cSMichal Nazarewicz 		kfree(buf);
9419353afbbSMichal Nazarewicz 
9429353afbbSMichal Nazarewicz 	return ret;
9439353afbbSMichal Nazarewicz }
9449353afbbSMichal Nazarewicz 
94500a2430fSAndrzej Pietrasiewicz static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
94600a2430fSAndrzej Pietrasiewicz {
94700a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = file->private_data;
948ae76e134SMichal Nazarewicz 	struct usb_request *req;
94900a2430fSAndrzej Pietrasiewicz 	struct ffs_ep *ep;
95000a2430fSAndrzej Pietrasiewicz 	char *data = NULL;
951c0d31b3cSDavid Cohen 	ssize_t ret, data_len = -EINVAL;
95200a2430fSAndrzej Pietrasiewicz 	int halt;
95300a2430fSAndrzej Pietrasiewicz 
95400a2430fSAndrzej Pietrasiewicz 	/* Are we still active? */
955b3591f67SMichal Nazarewicz 	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
956b3591f67SMichal Nazarewicz 		return -ENODEV;
95700a2430fSAndrzej Pietrasiewicz 
95800a2430fSAndrzej Pietrasiewicz 	/* Wait for endpoint to be enabled */
95900a2430fSAndrzej Pietrasiewicz 	ep = epfile->ep;
96000a2430fSAndrzej Pietrasiewicz 	if (!ep) {
961b3591f67SMichal Nazarewicz 		if (file->f_flags & O_NONBLOCK)
962b3591f67SMichal Nazarewicz 			return -EAGAIN;
96300a2430fSAndrzej Pietrasiewicz 
964e16828cfSJerry Zhang 		ret = wait_event_interruptible(
965e16828cfSJerry Zhang 				epfile->ffs->wait, (ep = epfile->ep));
966b3591f67SMichal Nazarewicz 		if (ret)
967b3591f67SMichal Nazarewicz 			return -EINTR;
96800a2430fSAndrzej Pietrasiewicz 	}
96900a2430fSAndrzej Pietrasiewicz 
97000a2430fSAndrzej Pietrasiewicz 	/* Do we halt? */
97100a2430fSAndrzej Pietrasiewicz 	halt = (!io_data->read == !epfile->in);
972b3591f67SMichal Nazarewicz 	if (halt && epfile->isoc)
973b3591f67SMichal Nazarewicz 		return -EINVAL;
97400a2430fSAndrzej Pietrasiewicz 
9759353afbbSMichal Nazarewicz 	/* We will be using request and read_buffer */
9769353afbbSMichal Nazarewicz 	ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
9778704fd73SGreg Kroah-Hartman 	if (ret)
9789353afbbSMichal Nazarewicz 		goto error;
9799353afbbSMichal Nazarewicz 
98000a2430fSAndrzej Pietrasiewicz 	/* Allocate & copy */
98100a2430fSAndrzej Pietrasiewicz 	if (!halt) {
9829353afbbSMichal Nazarewicz 		struct usb_gadget *gadget;
9839353afbbSMichal Nazarewicz 
9849353afbbSMichal Nazarewicz 		/*
9859353afbbSMichal Nazarewicz 		 * Do we have buffered data from previous partial read?  Check
9869353afbbSMichal Nazarewicz 		 * that for synchronous case only because we do not have
9879353afbbSMichal Nazarewicz 		 * facility to ‘wake up’ a pending asynchronous read and push
9889353afbbSMichal Nazarewicz 		 * buffered data to it which we would need to make things behave
9899353afbbSMichal Nazarewicz 		 * consistently.
9909353afbbSMichal Nazarewicz 		 */
9919353afbbSMichal Nazarewicz 		if (!io_data->aio && io_data->read) {
9929353afbbSMichal Nazarewicz 			ret = __ffs_epfile_read_buffered(epfile, &io_data->data);
9939353afbbSMichal Nazarewicz 			if (ret)
9949353afbbSMichal Nazarewicz 				goto error_mutex;
9959353afbbSMichal Nazarewicz 		}
9969353afbbSMichal Nazarewicz 
99700a2430fSAndrzej Pietrasiewicz 		/*
99800a2430fSAndrzej Pietrasiewicz 		 * if we _do_ wait above, the epfile->ffs->gadget might be NULL
999ae76e134SMichal Nazarewicz 		 * before the waiting completes, so do not assign to 'gadget'
1000ae76e134SMichal Nazarewicz 		 * earlier
100100a2430fSAndrzej Pietrasiewicz 		 */
10029353afbbSMichal Nazarewicz 		gadget = epfile->ffs->gadget;
100300a2430fSAndrzej Pietrasiewicz 
100400a2430fSAndrzej Pietrasiewicz 		spin_lock_irq(&epfile->ffs->eps_lock);
100500a2430fSAndrzej Pietrasiewicz 		/* In the meantime, endpoint got disabled or changed. */
100600a2430fSAndrzej Pietrasiewicz 		if (epfile->ep != ep) {
10079353afbbSMichal Nazarewicz 			ret = -ESHUTDOWN;
10089353afbbSMichal Nazarewicz 			goto error_lock;
100900a2430fSAndrzej Pietrasiewicz 		}
1010c993c39bSAl Viro 		data_len = iov_iter_count(&io_data->data);
101100a2430fSAndrzej Pietrasiewicz 		/*
101200a2430fSAndrzej Pietrasiewicz 		 * Controller may require buffer size to be aligned to
101300a2430fSAndrzej Pietrasiewicz 		 * maxpacketsize of an out endpoint.
101400a2430fSAndrzej Pietrasiewicz 		 */
1015c993c39bSAl Viro 		if (io_data->read)
1016c993c39bSAl Viro 			data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
10174833a94eSFei Yang 
10184833a94eSFei Yang 		io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
101900a2430fSAndrzej Pietrasiewicz 		spin_unlock_irq(&epfile->ffs->eps_lock);
102000a2430fSAndrzej Pietrasiewicz 
1021772a7a72SAndrzej Pietrasiewicz 		data = ffs_alloc_buffer(io_data, data_len);
10228704fd73SGreg Kroah-Hartman 		if (!data) {
10239353afbbSMichal Nazarewicz 			ret = -ENOMEM;
10249353afbbSMichal Nazarewicz 			goto error_mutex;
10259353afbbSMichal Nazarewicz 		}
10269353afbbSMichal Nazarewicz 		if (!io_data->read &&
1027cbbd26b8SAl Viro 		    !copy_from_iter_full(data, data_len, &io_data->data)) {
102800a2430fSAndrzej Pietrasiewicz 			ret = -EFAULT;
10299353afbbSMichal Nazarewicz 			goto error_mutex;
103000a2430fSAndrzej Pietrasiewicz 		}
103100a2430fSAndrzej Pietrasiewicz 	}
103200a2430fSAndrzej Pietrasiewicz 
103300a2430fSAndrzej Pietrasiewicz 	spin_lock_irq(&epfile->ffs->eps_lock);
103400a2430fSAndrzej Pietrasiewicz 
103500a2430fSAndrzej Pietrasiewicz 	if (epfile->ep != ep) {
103600a2430fSAndrzej Pietrasiewicz 		/* In the meantime, endpoint got disabled or changed. */
103700a2430fSAndrzej Pietrasiewicz 		ret = -ESHUTDOWN;
103800a2430fSAndrzej Pietrasiewicz 	} else if (halt) {
1039cdff9f8eSJerry Zhang 		ret = usb_ep_set_halt(ep->ep);
1040cdff9f8eSJerry Zhang 		if (!ret)
104100a2430fSAndrzej Pietrasiewicz 			ret = -EBADMSG;
10428704fd73SGreg Kroah-Hartman 	} else if (data_len == -EINVAL) {
1043c0d31b3cSDavid Cohen 		/*
1044c0d31b3cSDavid Cohen 		 * Sanity Check: even though data_len can't be used
1045c0d31b3cSDavid Cohen 		 * uninitialized at the time I write this comment, some
1046c0d31b3cSDavid Cohen 		 * compilers complain about this situation.
1047c0d31b3cSDavid Cohen 		 * In order to keep the code clean from warnings, data_len is
1048c0d31b3cSDavid Cohen 		 * being initialized to -EINVAL during its declaration, which
1049c0d31b3cSDavid Cohen 		 * means we can't rely on compiler anymore to warn no future
1050c0d31b3cSDavid Cohen 		 * changes won't result in data_len being used uninitialized.
1051c0d31b3cSDavid Cohen 		 * For such reason, we're adding this redundant sanity check
1052c0d31b3cSDavid Cohen 		 * here.
1053c0d31b3cSDavid Cohen 		 */
1054c0d31b3cSDavid Cohen 		WARN(1, "%s: data_len == -EINVAL\n", __func__);
1055c0d31b3cSDavid Cohen 		ret = -EINVAL;
1056ae76e134SMichal Nazarewicz 	} else if (!io_data->aio) {
1057ef150884SDu, Changbin 		bool interrupted = false;
1058ae76e134SMichal Nazarewicz 
1059ae76e134SMichal Nazarewicz 		req = ep->req;
1060772a7a72SAndrzej Pietrasiewicz 		if (io_data->use_sg) {
1061772a7a72SAndrzej Pietrasiewicz 			req->buf = NULL;
1062772a7a72SAndrzej Pietrasiewicz 			req->sg	= io_data->sgt.sgl;
1063772a7a72SAndrzej Pietrasiewicz 			req->num_sgs = io_data->sgt.nents;
1064772a7a72SAndrzej Pietrasiewicz 		} else {
1065ae76e134SMichal Nazarewicz 			req->buf = data;
1066d2450c69SPeter Chen 			req->num_sgs = 0;
1067772a7a72SAndrzej Pietrasiewicz 		}
1068ae76e134SMichal Nazarewicz 		req->length = data_len;
1069ae76e134SMichal Nazarewicz 
1070772a7a72SAndrzej Pietrasiewicz 		io_data->buf = data;
1071772a7a72SAndrzej Pietrasiewicz 
1072fb1f16d7SLinyu Yuan 		init_completion(&io_data->done);
1073fb1f16d7SLinyu Yuan 		req->context  = io_data;
1074ae76e134SMichal Nazarewicz 		req->complete = ffs_epfile_io_complete;
1075ae76e134SMichal Nazarewicz 
1076ae76e134SMichal Nazarewicz 		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
10778704fd73SGreg Kroah-Hartman 		if (ret < 0)
1078c0d31b3cSDavid Cohen 			goto error_lock;
1079ae76e134SMichal Nazarewicz 
1080ae76e134SMichal Nazarewicz 		spin_unlock_irq(&epfile->ffs->eps_lock);
1081ae76e134SMichal Nazarewicz 
1082fb1f16d7SLinyu Yuan 		if (wait_for_completion_interruptible(&io_data->done)) {
10830698f020SLinyu Yuan 			spin_lock_irq(&epfile->ffs->eps_lock);
10840698f020SLinyu Yuan 			if (epfile->ep != ep) {
10850698f020SLinyu Yuan 				ret = -ESHUTDOWN;
10860698f020SLinyu Yuan 				goto error_lock;
10870698f020SLinyu Yuan 			}
1088ef150884SDu, Changbin 			/*
1089ef150884SDu, Changbin 			 * To avoid race condition with ffs_epfile_io_complete,
1090ef150884SDu, Changbin 			 * dequeue the request first then check
1091ef150884SDu, Changbin 			 * status. usb_ep_dequeue API should guarantee no race
1092ef150884SDu, Changbin 			 * condition with req->complete callback.
1093ef150884SDu, Changbin 			 */
1094ae76e134SMichal Nazarewicz 			usb_ep_dequeue(ep->ep, req);
10950698f020SLinyu Yuan 			spin_unlock_irq(&epfile->ffs->eps_lock);
1096fb1f16d7SLinyu Yuan 			wait_for_completion(&io_data->done);
1097fb1f16d7SLinyu Yuan 			interrupted = io_data->status < 0;
1098c0d31b3cSDavid Cohen 		}
1099c0d31b3cSDavid Cohen 
1100c662a31bSMichal Nazarewicz 		if (interrupted)
1101c662a31bSMichal Nazarewicz 			ret = -EINTR;
1102fb1f16d7SLinyu Yuan 		else if (io_data->read && io_data->status > 0)
1103fb1f16d7SLinyu Yuan 			ret = __ffs_epfile_read_data(epfile, data, io_data->status,
1104c662a31bSMichal Nazarewicz 						     &io_data->data);
1105c662a31bSMichal Nazarewicz 		else
1106fb1f16d7SLinyu Yuan 			ret = io_data->status;
1107ae76e134SMichal Nazarewicz 		goto error_mutex;
110830bf90ccSVincent Pelletier 	} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) {
11093163c79eSMichal Nazarewicz 		ret = -ENOMEM;
1110ae76e134SMichal Nazarewicz 	} else {
1111772a7a72SAndrzej Pietrasiewicz 		if (io_data->use_sg) {
1112772a7a72SAndrzej Pietrasiewicz 			req->buf = NULL;
1113772a7a72SAndrzej Pietrasiewicz 			req->sg	= io_data->sgt.sgl;
1114772a7a72SAndrzej Pietrasiewicz 			req->num_sgs = io_data->sgt.nents;
1115772a7a72SAndrzej Pietrasiewicz 		} else {
111600a2430fSAndrzej Pietrasiewicz 			req->buf = data;
1117d2450c69SPeter Chen 			req->num_sgs = 0;
1118772a7a72SAndrzej Pietrasiewicz 		}
1119c0d31b3cSDavid Cohen 		req->length = data_len;
112000a2430fSAndrzej Pietrasiewicz 
112100a2430fSAndrzej Pietrasiewicz 		io_data->buf = data;
112200a2430fSAndrzej Pietrasiewicz 		io_data->ep = ep->ep;
112300a2430fSAndrzej Pietrasiewicz 		io_data->req = req;
11245e33f6fdSRobert Baldyga 		io_data->ffs = epfile->ffs;
112500a2430fSAndrzej Pietrasiewicz 
112600a2430fSAndrzej Pietrasiewicz 		req->context  = io_data;
112700a2430fSAndrzej Pietrasiewicz 		req->complete = ffs_epfile_async_io_complete;
112800a2430fSAndrzej Pietrasiewicz 
112900a2430fSAndrzej Pietrasiewicz 		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
11308704fd73SGreg Kroah-Hartman 		if (ret) {
1131f63ec55fSSriharsha Allenki 			io_data->req = NULL;
113200a2430fSAndrzej Pietrasiewicz 			usb_ep_free_request(ep->ep, req);
113300a2430fSAndrzej Pietrasiewicz 			goto error_lock;
113400a2430fSAndrzej Pietrasiewicz 		}
1135ae76e134SMichal Nazarewicz 
113600a2430fSAndrzej Pietrasiewicz 		ret = -EIOCBQUEUED;
113700a2430fSAndrzej Pietrasiewicz 		/*
1138ae76e134SMichal Nazarewicz 		 * Do not kfree the buffer in this function.  It will be freed
1139ae76e134SMichal Nazarewicz 		 * by ffs_user_copy_worker.
114000a2430fSAndrzej Pietrasiewicz 		 */
1141ae76e134SMichal Nazarewicz 		data = NULL;
114200a2430fSAndrzej Pietrasiewicz 	}
114300a2430fSAndrzej Pietrasiewicz 
114400a2430fSAndrzej Pietrasiewicz error_lock:
114500a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&epfile->ffs->eps_lock);
1146ae76e134SMichal Nazarewicz error_mutex:
114700a2430fSAndrzej Pietrasiewicz 	mutex_unlock(&epfile->mutex);
114800a2430fSAndrzej Pietrasiewicz error:
114973103c7fSFei Yang 	if (ret != -EIOCBQUEUED) /* don't free if there is iocb queued */
1150772a7a72SAndrzej Pietrasiewicz 		ffs_free_buffer(io_data);
115100a2430fSAndrzej Pietrasiewicz 	return ret;
115200a2430fSAndrzej Pietrasiewicz }
115300a2430fSAndrzej Pietrasiewicz 
115400a2430fSAndrzej Pietrasiewicz static int
115500a2430fSAndrzej Pietrasiewicz ffs_epfile_open(struct inode *inode, struct file *file)
115600a2430fSAndrzej Pietrasiewicz {
115700a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = inode->i_private;
115800a2430fSAndrzej Pietrasiewicz 
115900a2430fSAndrzej Pietrasiewicz 	ENTER();
116000a2430fSAndrzej Pietrasiewicz 
116100a2430fSAndrzej Pietrasiewicz 	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
116200a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
116300a2430fSAndrzej Pietrasiewicz 
116400a2430fSAndrzej Pietrasiewicz 	file->private_data = epfile;
116500a2430fSAndrzej Pietrasiewicz 	ffs_data_opened(epfile->ffs);
116600a2430fSAndrzej Pietrasiewicz 
1167c76ef96fSPavankumar Kondeti 	return stream_open(inode, file);
116800a2430fSAndrzej Pietrasiewicz }
116900a2430fSAndrzej Pietrasiewicz 
117000a2430fSAndrzej Pietrasiewicz static int ffs_aio_cancel(struct kiocb *kiocb)
117100a2430fSAndrzej Pietrasiewicz {
117200a2430fSAndrzej Pietrasiewicz 	struct ffs_io_data *io_data = kiocb->private;
1173a9c85903SShen Jing 	struct ffs_epfile *epfile = kiocb->ki_filp->private_data;
117443d56572SLars-Peter Clausen 	unsigned long flags;
117500a2430fSAndrzej Pietrasiewicz 	int value;
117600a2430fSAndrzej Pietrasiewicz 
117700a2430fSAndrzej Pietrasiewicz 	ENTER();
117800a2430fSAndrzej Pietrasiewicz 
117943d56572SLars-Peter Clausen 	spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
1180a9c85903SShen Jing 
11818704fd73SGreg Kroah-Hartman 	if (io_data && io_data->ep && io_data->req)
1182a9c85903SShen Jing 		value = usb_ep_dequeue(io_data->ep, io_data->req);
1183a9c85903SShen Jing 	else
118400a2430fSAndrzej Pietrasiewicz 		value = -EINVAL;
1185a9c85903SShen Jing 
118643d56572SLars-Peter Clausen 	spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
118700a2430fSAndrzej Pietrasiewicz 
118800a2430fSAndrzej Pietrasiewicz 	return value;
118900a2430fSAndrzej Pietrasiewicz }
119000a2430fSAndrzej Pietrasiewicz 
119170e60d91SAl Viro static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
119200a2430fSAndrzej Pietrasiewicz {
119370e60d91SAl Viro 	struct ffs_io_data io_data, *p = &io_data;
1194de2080d4SAl Viro 	ssize_t res;
119500a2430fSAndrzej Pietrasiewicz 
119600a2430fSAndrzej Pietrasiewicz 	ENTER();
119700a2430fSAndrzej Pietrasiewicz 
119870e60d91SAl Viro 	if (!is_sync_kiocb(kiocb)) {
119950859551SAndrzej Pietrasiewicz 		p = kzalloc(sizeof(io_data), GFP_KERNEL);
12008704fd73SGreg Kroah-Hartman 		if (!p)
120100a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
120270e60d91SAl Viro 		p->aio = true;
120370e60d91SAl Viro 	} else {
120450859551SAndrzej Pietrasiewicz 		memset(p, 0, sizeof(*p));
120570e60d91SAl Viro 		p->aio = false;
120670e60d91SAl Viro 	}
120700a2430fSAndrzej Pietrasiewicz 
120870e60d91SAl Viro 	p->read = false;
120970e60d91SAl Viro 	p->kiocb = kiocb;
121070e60d91SAl Viro 	p->data = *from;
121170e60d91SAl Viro 	p->mm = current->mm;
121200a2430fSAndrzej Pietrasiewicz 
121370e60d91SAl Viro 	kiocb->private = p;
121400a2430fSAndrzej Pietrasiewicz 
12154088acf1SRui Miguel Silva 	if (p->aio)
121600a2430fSAndrzej Pietrasiewicz 		kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
121700a2430fSAndrzej Pietrasiewicz 
121870e60d91SAl Viro 	res = ffs_epfile_io(kiocb->ki_filp, p);
121970e60d91SAl Viro 	if (res == -EIOCBQUEUED)
122070e60d91SAl Viro 		return res;
122170e60d91SAl Viro 	if (p->aio)
122270e60d91SAl Viro 		kfree(p);
122370e60d91SAl Viro 	else
122470e60d91SAl Viro 		*from = p->data;
1225de2080d4SAl Viro 	return res;
122600a2430fSAndrzej Pietrasiewicz }
122700a2430fSAndrzej Pietrasiewicz 
122870e60d91SAl Viro static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
122900a2430fSAndrzej Pietrasiewicz {
123070e60d91SAl Viro 	struct ffs_io_data io_data, *p = &io_data;
1231de2080d4SAl Viro 	ssize_t res;
123200a2430fSAndrzej Pietrasiewicz 
123300a2430fSAndrzej Pietrasiewicz 	ENTER();
123400a2430fSAndrzej Pietrasiewicz 
123570e60d91SAl Viro 	if (!is_sync_kiocb(kiocb)) {
123650859551SAndrzej Pietrasiewicz 		p = kzalloc(sizeof(io_data), GFP_KERNEL);
12378704fd73SGreg Kroah-Hartman 		if (!p)
123800a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
123970e60d91SAl Viro 		p->aio = true;
124070e60d91SAl Viro 	} else {
124150859551SAndrzej Pietrasiewicz 		memset(p, 0, sizeof(*p));
124270e60d91SAl Viro 		p->aio = false;
124300a2430fSAndrzej Pietrasiewicz 	}
124400a2430fSAndrzej Pietrasiewicz 
124570e60d91SAl Viro 	p->read = true;
124670e60d91SAl Viro 	p->kiocb = kiocb;
124770e60d91SAl Viro 	if (p->aio) {
124870e60d91SAl Viro 		p->to_free = dup_iter(&p->data, to, GFP_KERNEL);
124970e60d91SAl Viro 		if (!p->to_free) {
125070e60d91SAl Viro 			kfree(p);
125170e60d91SAl Viro 			return -ENOMEM;
125270e60d91SAl Viro 		}
125370e60d91SAl Viro 	} else {
125470e60d91SAl Viro 		p->data = *to;
125570e60d91SAl Viro 		p->to_free = NULL;
125670e60d91SAl Viro 	}
125770e60d91SAl Viro 	p->mm = current->mm;
125800a2430fSAndrzej Pietrasiewicz 
125970e60d91SAl Viro 	kiocb->private = p;
126000a2430fSAndrzej Pietrasiewicz 
12614088acf1SRui Miguel Silva 	if (p->aio)
126200a2430fSAndrzej Pietrasiewicz 		kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
126300a2430fSAndrzej Pietrasiewicz 
126470e60d91SAl Viro 	res = ffs_epfile_io(kiocb->ki_filp, p);
126570e60d91SAl Viro 	if (res == -EIOCBQUEUED)
126670e60d91SAl Viro 		return res;
126770e60d91SAl Viro 
126870e60d91SAl Viro 	if (p->aio) {
126970e60d91SAl Viro 		kfree(p->to_free);
127070e60d91SAl Viro 		kfree(p);
127170e60d91SAl Viro 	} else {
127270e60d91SAl Viro 		*to = p->data;
1273de2080d4SAl Viro 	}
1274de2080d4SAl Viro 	return res;
127500a2430fSAndrzej Pietrasiewicz }
127600a2430fSAndrzej Pietrasiewicz 
127700a2430fSAndrzej Pietrasiewicz static int
127800a2430fSAndrzej Pietrasiewicz ffs_epfile_release(struct inode *inode, struct file *file)
127900a2430fSAndrzej Pietrasiewicz {
128000a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = inode->i_private;
128100a2430fSAndrzej Pietrasiewicz 
128200a2430fSAndrzej Pietrasiewicz 	ENTER();
128300a2430fSAndrzej Pietrasiewicz 
1284a9e6f83cSMichal Nazarewicz 	__ffs_epfile_read_buffer_free(epfile);
128500a2430fSAndrzej Pietrasiewicz 	ffs_data_closed(epfile->ffs);
128600a2430fSAndrzej Pietrasiewicz 
128700a2430fSAndrzej Pietrasiewicz 	return 0;
128800a2430fSAndrzej Pietrasiewicz }
128900a2430fSAndrzej Pietrasiewicz 
129000a2430fSAndrzej Pietrasiewicz static long ffs_epfile_ioctl(struct file *file, unsigned code,
129100a2430fSAndrzej Pietrasiewicz 			     unsigned long value)
129200a2430fSAndrzej Pietrasiewicz {
129300a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = file->private_data;
1294222155deSJerry Zhang 	struct ffs_ep *ep;
129500a2430fSAndrzej Pietrasiewicz 	int ret;
129600a2430fSAndrzej Pietrasiewicz 
129700a2430fSAndrzej Pietrasiewicz 	ENTER();
129800a2430fSAndrzej Pietrasiewicz 
129900a2430fSAndrzej Pietrasiewicz 	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
130000a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
130100a2430fSAndrzej Pietrasiewicz 
1302222155deSJerry Zhang 	/* Wait for endpoint to be enabled */
1303222155deSJerry Zhang 	ep = epfile->ep;
1304222155deSJerry Zhang 	if (!ep) {
1305222155deSJerry Zhang 		if (file->f_flags & O_NONBLOCK)
1306222155deSJerry Zhang 			return -EAGAIN;
1307222155deSJerry Zhang 
1308e16828cfSJerry Zhang 		ret = wait_event_interruptible(
1309e16828cfSJerry Zhang 				epfile->ffs->wait, (ep = epfile->ep));
1310222155deSJerry Zhang 		if (ret)
1311222155deSJerry Zhang 			return -EINTR;
1312222155deSJerry Zhang 	}
1313222155deSJerry Zhang 
131400a2430fSAndrzej Pietrasiewicz 	spin_lock_irq(&epfile->ffs->eps_lock);
1315222155deSJerry Zhang 
1316222155deSJerry Zhang 	/* In the meantime, endpoint got disabled or changed. */
1317222155deSJerry Zhang 	if (epfile->ep != ep) {
1318222155deSJerry Zhang 		spin_unlock_irq(&epfile->ffs->eps_lock);
1319222155deSJerry Zhang 		return -ESHUTDOWN;
1320222155deSJerry Zhang 	}
1321222155deSJerry Zhang 
132200a2430fSAndrzej Pietrasiewicz 	switch (code) {
132300a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_FIFO_STATUS:
132400a2430fSAndrzej Pietrasiewicz 		ret = usb_ep_fifo_status(epfile->ep->ep);
132500a2430fSAndrzej Pietrasiewicz 		break;
132600a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_FIFO_FLUSH:
132700a2430fSAndrzej Pietrasiewicz 		usb_ep_fifo_flush(epfile->ep->ep);
132800a2430fSAndrzej Pietrasiewicz 		ret = 0;
132900a2430fSAndrzej Pietrasiewicz 		break;
133000a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_CLEAR_HALT:
133100a2430fSAndrzej Pietrasiewicz 		ret = usb_ep_clear_halt(epfile->ep->ep);
133200a2430fSAndrzej Pietrasiewicz 		break;
133300a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_ENDPOINT_REVMAP:
133400a2430fSAndrzej Pietrasiewicz 		ret = epfile->ep->num;
133500a2430fSAndrzej Pietrasiewicz 		break;
1336c559a353SRobert Baldyga 	case FUNCTIONFS_ENDPOINT_DESC:
1337c559a353SRobert Baldyga 	{
1338c559a353SRobert Baldyga 		int desc_idx;
1339a4b98a75SVamsi Krishna Samavedam 		struct usb_endpoint_descriptor desc1, *desc;
1340c559a353SRobert Baldyga 
1341c559a353SRobert Baldyga 		switch (epfile->ffs->gadget->speed) {
1342c559a353SRobert Baldyga 		case USB_SPEED_SUPER:
1343a353397bSJack Pham 		case USB_SPEED_SUPER_PLUS:
1344c559a353SRobert Baldyga 			desc_idx = 2;
1345c559a353SRobert Baldyga 			break;
1346c559a353SRobert Baldyga 		case USB_SPEED_HIGH:
1347c559a353SRobert Baldyga 			desc_idx = 1;
1348c559a353SRobert Baldyga 			break;
1349c559a353SRobert Baldyga 		default:
1350c559a353SRobert Baldyga 			desc_idx = 0;
1351c559a353SRobert Baldyga 		}
1352a4b98a75SVamsi Krishna Samavedam 
1353c559a353SRobert Baldyga 		desc = epfile->ep->descs[desc_idx];
1354a4b98a75SVamsi Krishna Samavedam 		memcpy(&desc1, desc, desc->bLength);
1355c559a353SRobert Baldyga 
1356c559a353SRobert Baldyga 		spin_unlock_irq(&epfile->ffs->eps_lock);
1357a4b98a75SVamsi Krishna Samavedam 		ret = copy_to_user((void __user *)value, &desc1, desc1.bLength);
1358c559a353SRobert Baldyga 		if (ret)
1359c559a353SRobert Baldyga 			ret = -EFAULT;
1360c559a353SRobert Baldyga 		return ret;
1361c559a353SRobert Baldyga 	}
136200a2430fSAndrzej Pietrasiewicz 	default:
136300a2430fSAndrzej Pietrasiewicz 		ret = -ENOTTY;
136400a2430fSAndrzej Pietrasiewicz 	}
136500a2430fSAndrzej Pietrasiewicz 	spin_unlock_irq(&epfile->ffs->eps_lock);
136600a2430fSAndrzej Pietrasiewicz 
136700a2430fSAndrzej Pietrasiewicz 	return ret;
136800a2430fSAndrzej Pietrasiewicz }
136900a2430fSAndrzej Pietrasiewicz 
137000a2430fSAndrzej Pietrasiewicz static const struct file_operations ffs_epfile_operations = {
137100a2430fSAndrzej Pietrasiewicz 	.llseek =	no_llseek,
137200a2430fSAndrzej Pietrasiewicz 
137300a2430fSAndrzej Pietrasiewicz 	.open =		ffs_epfile_open,
137470e60d91SAl Viro 	.write_iter =	ffs_epfile_write_iter,
137570e60d91SAl Viro 	.read_iter =	ffs_epfile_read_iter,
137600a2430fSAndrzej Pietrasiewicz 	.release =	ffs_epfile_release,
137700a2430fSAndrzej Pietrasiewicz 	.unlocked_ioctl =	ffs_epfile_ioctl,
137801b8bca8SArnd Bergmann 	.compat_ioctl = compat_ptr_ioctl,
137900a2430fSAndrzej Pietrasiewicz };
138000a2430fSAndrzej Pietrasiewicz 
138100a2430fSAndrzej Pietrasiewicz 
138200a2430fSAndrzej Pietrasiewicz /* File system and super block operations ***********************************/
138300a2430fSAndrzej Pietrasiewicz 
138400a2430fSAndrzej Pietrasiewicz /*
138500a2430fSAndrzej Pietrasiewicz  * Mounting the file system creates a controller file, used first for
138600a2430fSAndrzej Pietrasiewicz  * function configuration then later for event monitoring.
138700a2430fSAndrzej Pietrasiewicz  */
138800a2430fSAndrzej Pietrasiewicz 
138900a2430fSAndrzej Pietrasiewicz static struct inode *__must_check
139000a2430fSAndrzej Pietrasiewicz ffs_sb_make_inode(struct super_block *sb, void *data,
139100a2430fSAndrzej Pietrasiewicz 		  const struct file_operations *fops,
139200a2430fSAndrzej Pietrasiewicz 		  const struct inode_operations *iops,
139300a2430fSAndrzej Pietrasiewicz 		  struct ffs_file_perms *perms)
139400a2430fSAndrzej Pietrasiewicz {
139500a2430fSAndrzej Pietrasiewicz 	struct inode *inode;
139600a2430fSAndrzej Pietrasiewicz 
139700a2430fSAndrzej Pietrasiewicz 	ENTER();
139800a2430fSAndrzej Pietrasiewicz 
139900a2430fSAndrzej Pietrasiewicz 	inode = new_inode(sb);
140000a2430fSAndrzej Pietrasiewicz 
14018704fd73SGreg Kroah-Hartman 	if (inode) {
140295582b00SDeepa Dinamani 		struct timespec64 ts = current_time(inode);
140300a2430fSAndrzej Pietrasiewicz 
140400a2430fSAndrzej Pietrasiewicz 		inode->i_ino	 = get_next_ino();
140500a2430fSAndrzej Pietrasiewicz 		inode->i_mode    = perms->mode;
140600a2430fSAndrzej Pietrasiewicz 		inode->i_uid     = perms->uid;
140700a2430fSAndrzej Pietrasiewicz 		inode->i_gid     = perms->gid;
1408078cd827SDeepa Dinamani 		inode->i_atime   = ts;
1409078cd827SDeepa Dinamani 		inode->i_mtime   = ts;
1410078cd827SDeepa Dinamani 		inode->i_ctime   = ts;
141100a2430fSAndrzej Pietrasiewicz 		inode->i_private = data;
141200a2430fSAndrzej Pietrasiewicz 		if (fops)
141300a2430fSAndrzej Pietrasiewicz 			inode->i_fop = fops;
141400a2430fSAndrzej Pietrasiewicz 		if (iops)
141500a2430fSAndrzej Pietrasiewicz 			inode->i_op  = iops;
141600a2430fSAndrzej Pietrasiewicz 	}
141700a2430fSAndrzej Pietrasiewicz 
141800a2430fSAndrzej Pietrasiewicz 	return inode;
141900a2430fSAndrzej Pietrasiewicz }
142000a2430fSAndrzej Pietrasiewicz 
142100a2430fSAndrzej Pietrasiewicz /* Create "regular" file */
14221bb27cacSAl Viro static struct dentry *ffs_sb_create_file(struct super_block *sb,
142300a2430fSAndrzej Pietrasiewicz 					const char *name, void *data,
14241bb27cacSAl Viro 					const struct file_operations *fops)
142500a2430fSAndrzej Pietrasiewicz {
142600a2430fSAndrzej Pietrasiewicz 	struct ffs_data	*ffs = sb->s_fs_info;
142700a2430fSAndrzej Pietrasiewicz 	struct dentry	*dentry;
142800a2430fSAndrzej Pietrasiewicz 	struct inode	*inode;
142900a2430fSAndrzej Pietrasiewicz 
143000a2430fSAndrzej Pietrasiewicz 	ENTER();
143100a2430fSAndrzej Pietrasiewicz 
143200a2430fSAndrzej Pietrasiewicz 	dentry = d_alloc_name(sb->s_root, name);
14338704fd73SGreg Kroah-Hartman 	if (!dentry)
143400a2430fSAndrzej Pietrasiewicz 		return NULL;
143500a2430fSAndrzej Pietrasiewicz 
143600a2430fSAndrzej Pietrasiewicz 	inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
14378704fd73SGreg Kroah-Hartman 	if (!inode) {
143800a2430fSAndrzej Pietrasiewicz 		dput(dentry);
143900a2430fSAndrzej Pietrasiewicz 		return NULL;
144000a2430fSAndrzej Pietrasiewicz 	}
144100a2430fSAndrzej Pietrasiewicz 
144200a2430fSAndrzej Pietrasiewicz 	d_add(dentry, inode);
14431bb27cacSAl Viro 	return dentry;
144400a2430fSAndrzej Pietrasiewicz }
144500a2430fSAndrzej Pietrasiewicz 
144600a2430fSAndrzej Pietrasiewicz /* Super block */
144700a2430fSAndrzej Pietrasiewicz static const struct super_operations ffs_sb_operations = {
144800a2430fSAndrzej Pietrasiewicz 	.statfs =	simple_statfs,
144900a2430fSAndrzej Pietrasiewicz 	.drop_inode =	generic_delete_inode,
145000a2430fSAndrzej Pietrasiewicz };
145100a2430fSAndrzej Pietrasiewicz 
145200a2430fSAndrzej Pietrasiewicz struct ffs_sb_fill_data {
145300a2430fSAndrzej Pietrasiewicz 	struct ffs_file_perms perms;
145400a2430fSAndrzej Pietrasiewicz 	umode_t root_mode;
145500a2430fSAndrzej Pietrasiewicz 	const char *dev_name;
145618d6b32fSRobert Baldyga 	bool no_disconnect;
145700a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs_data;
145800a2430fSAndrzej Pietrasiewicz };
145900a2430fSAndrzej Pietrasiewicz 
1460dec90f61SDavid Howells static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
146100a2430fSAndrzej Pietrasiewicz {
1462dec90f61SDavid Howells 	struct ffs_sb_fill_data *data = fc->fs_private;
146300a2430fSAndrzej Pietrasiewicz 	struct inode	*inode;
146400a2430fSAndrzej Pietrasiewicz 	struct ffs_data	*ffs = data->ffs_data;
146500a2430fSAndrzej Pietrasiewicz 
146600a2430fSAndrzej Pietrasiewicz 	ENTER();
146700a2430fSAndrzej Pietrasiewicz 
146800a2430fSAndrzej Pietrasiewicz 	ffs->sb              = sb;
146900a2430fSAndrzej Pietrasiewicz 	data->ffs_data       = NULL;
147000a2430fSAndrzej Pietrasiewicz 	sb->s_fs_info        = ffs;
147109cbfeafSKirill A. Shutemov 	sb->s_blocksize      = PAGE_SIZE;
147209cbfeafSKirill A. Shutemov 	sb->s_blocksize_bits = PAGE_SHIFT;
147300a2430fSAndrzej Pietrasiewicz 	sb->s_magic          = FUNCTIONFS_MAGIC;
147400a2430fSAndrzej Pietrasiewicz 	sb->s_op             = &ffs_sb_operations;
147500a2430fSAndrzej Pietrasiewicz 	sb->s_time_gran      = 1;
147600a2430fSAndrzej Pietrasiewicz 
147700a2430fSAndrzej Pietrasiewicz 	/* Root inode */
147800a2430fSAndrzej Pietrasiewicz 	data->perms.mode = data->root_mode;
147900a2430fSAndrzej Pietrasiewicz 	inode = ffs_sb_make_inode(sb, NULL,
148000a2430fSAndrzej Pietrasiewicz 				  &simple_dir_operations,
148100a2430fSAndrzej Pietrasiewicz 				  &simple_dir_inode_operations,
148200a2430fSAndrzej Pietrasiewicz 				  &data->perms);
148300a2430fSAndrzej Pietrasiewicz 	sb->s_root = d_make_root(inode);
14848704fd73SGreg Kroah-Hartman 	if (!sb->s_root)
148500a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
148600a2430fSAndrzej Pietrasiewicz 
148700a2430fSAndrzej Pietrasiewicz 	/* EP0 file */
14888704fd73SGreg Kroah-Hartman 	if (!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations))
148900a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
149000a2430fSAndrzej Pietrasiewicz 
149100a2430fSAndrzej Pietrasiewicz 	return 0;
149200a2430fSAndrzej Pietrasiewicz }
149300a2430fSAndrzej Pietrasiewicz 
1494dec90f61SDavid Howells enum {
1495dec90f61SDavid Howells 	Opt_no_disconnect,
1496dec90f61SDavid Howells 	Opt_rmode,
1497dec90f61SDavid Howells 	Opt_fmode,
1498dec90f61SDavid Howells 	Opt_mode,
1499dec90f61SDavid Howells 	Opt_uid,
1500dec90f61SDavid Howells 	Opt_gid,
1501dec90f61SDavid Howells };
1502dec90f61SDavid Howells 
1503d7167b14SAl Viro static const struct fs_parameter_spec ffs_fs_fs_parameters[] = {
1504dec90f61SDavid Howells 	fsparam_bool	("no_disconnect",	Opt_no_disconnect),
1505dec90f61SDavid Howells 	fsparam_u32	("rmode",		Opt_rmode),
1506dec90f61SDavid Howells 	fsparam_u32	("fmode",		Opt_fmode),
1507dec90f61SDavid Howells 	fsparam_u32	("mode",		Opt_mode),
1508dec90f61SDavid Howells 	fsparam_u32	("uid",			Opt_uid),
1509dec90f61SDavid Howells 	fsparam_u32	("gid",			Opt_gid),
1510dec90f61SDavid Howells 	{}
1511dec90f61SDavid Howells };
1512dec90f61SDavid Howells 
1513dec90f61SDavid Howells static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
151400a2430fSAndrzej Pietrasiewicz {
1515dec90f61SDavid Howells 	struct ffs_sb_fill_data *data = fc->fs_private;
1516dec90f61SDavid Howells 	struct fs_parse_result result;
1517dec90f61SDavid Howells 	int opt;
1518dec90f61SDavid Howells 
151900a2430fSAndrzej Pietrasiewicz 	ENTER();
152000a2430fSAndrzej Pietrasiewicz 
1521d7167b14SAl Viro 	opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result);
1522dec90f61SDavid Howells 	if (opt < 0)
1523dec90f61SDavid Howells 		return opt;
152400a2430fSAndrzej Pietrasiewicz 
1525dec90f61SDavid Howells 	switch (opt) {
1526dec90f61SDavid Howells 	case Opt_no_disconnect:
1527dec90f61SDavid Howells 		data->no_disconnect = result.boolean;
152818d6b32fSRobert Baldyga 		break;
1529dec90f61SDavid Howells 	case Opt_rmode:
1530dec90f61SDavid Howells 		data->root_mode  = (result.uint_32 & 0555) | S_IFDIR;
1531dec90f61SDavid Howells 		break;
1532dec90f61SDavid Howells 	case Opt_fmode:
1533dec90f61SDavid Howells 		data->perms.mode = (result.uint_32 & 0666) | S_IFREG;
1534dec90f61SDavid Howells 		break;
1535dec90f61SDavid Howells 	case Opt_mode:
1536dec90f61SDavid Howells 		data->root_mode  = (result.uint_32 & 0555) | S_IFDIR;
1537dec90f61SDavid Howells 		data->perms.mode = (result.uint_32 & 0666) | S_IFREG;
153800a2430fSAndrzej Pietrasiewicz 		break;
153900a2430fSAndrzej Pietrasiewicz 
1540dec90f61SDavid Howells 	case Opt_uid:
1541dec90f61SDavid Howells 		data->perms.uid = make_kuid(current_user_ns(), result.uint_32);
1542dec90f61SDavid Howells 		if (!uid_valid(data->perms.uid))
1543dec90f61SDavid Howells 			goto unmapped_value;
154400a2430fSAndrzej Pietrasiewicz 		break;
1545dec90f61SDavid Howells 	case Opt_gid:
1546dec90f61SDavid Howells 		data->perms.gid = make_kgid(current_user_ns(), result.uint_32);
1547dec90f61SDavid Howells 		if (!gid_valid(data->perms.gid))
1548dec90f61SDavid Howells 			goto unmapped_value;
154900a2430fSAndrzej Pietrasiewicz 		break;
155000a2430fSAndrzej Pietrasiewicz 
155100a2430fSAndrzej Pietrasiewicz 	default:
1552dec90f61SDavid Howells 		return -ENOPARAM;
155300a2430fSAndrzej Pietrasiewicz 	}
155400a2430fSAndrzej Pietrasiewicz 
155500a2430fSAndrzej Pietrasiewicz 	return 0;
1556dec90f61SDavid Howells 
1557dec90f61SDavid Howells unmapped_value:
1558dec90f61SDavid Howells 	return invalf(fc, "%s: unmapped value: %u", param->key, result.uint_32);
155900a2430fSAndrzej Pietrasiewicz }
156000a2430fSAndrzej Pietrasiewicz 
1561dec90f61SDavid Howells /*
1562dec90f61SDavid Howells  * Set up the superblock for a mount.
1563dec90f61SDavid Howells  */
1564dec90f61SDavid Howells static int ffs_fs_get_tree(struct fs_context *fc)
156500a2430fSAndrzej Pietrasiewicz {
1566dec90f61SDavid Howells 	struct ffs_sb_fill_data *ctx = fc->fs_private;
156700a2430fSAndrzej Pietrasiewicz 	struct ffs_data	*ffs;
1568ecfbd7b9SAndrew Gabbasov 	int ret;
156900a2430fSAndrzej Pietrasiewicz 
157000a2430fSAndrzej Pietrasiewicz 	ENTER();
157100a2430fSAndrzej Pietrasiewicz 
1572dec90f61SDavid Howells 	if (!fc->source)
1573dec90f61SDavid Howells 		return invalf(fc, "No source specified");
157400a2430fSAndrzej Pietrasiewicz 
1575dec90f61SDavid Howells 	ffs = ffs_data_new(fc->source);
15768704fd73SGreg Kroah-Hartman 	if (!ffs)
1577dec90f61SDavid Howells 		return -ENOMEM;
1578dec90f61SDavid Howells 	ffs->file_perms = ctx->perms;
1579dec90f61SDavid Howells 	ffs->no_disconnect = ctx->no_disconnect;
158000a2430fSAndrzej Pietrasiewicz 
1581dec90f61SDavid Howells 	ffs->dev_name = kstrdup(fc->source, GFP_KERNEL);
15828704fd73SGreg Kroah-Hartman 	if (!ffs->dev_name) {
158300a2430fSAndrzej Pietrasiewicz 		ffs_data_put(ffs);
1584dec90f61SDavid Howells 		return -ENOMEM;
158500a2430fSAndrzej Pietrasiewicz 	}
158600a2430fSAndrzej Pietrasiewicz 
1587ecfbd7b9SAndrew Gabbasov 	ret = ffs_acquire_dev(ffs->dev_name, ffs);
1588ecfbd7b9SAndrew Gabbasov 	if (ret) {
158900a2430fSAndrzej Pietrasiewicz 		ffs_data_put(ffs);
1590ecfbd7b9SAndrew Gabbasov 		return ret;
159100a2430fSAndrzej Pietrasiewicz 	}
159200a2430fSAndrzej Pietrasiewicz 
1593dec90f61SDavid Howells 	ctx->ffs_data = ffs;
1594dec90f61SDavid Howells 	return get_tree_nodev(fc, ffs_sb_fill);
159500a2430fSAndrzej Pietrasiewicz }
1596dec90f61SDavid Howells 
1597dec90f61SDavid Howells static void ffs_fs_free_fc(struct fs_context *fc)
1598dec90f61SDavid Howells {
1599dec90f61SDavid Howells 	struct ffs_sb_fill_data *ctx = fc->fs_private;
1600dec90f61SDavid Howells 
1601dec90f61SDavid Howells 	if (ctx) {
1602dec90f61SDavid Howells 		if (ctx->ffs_data) {
1603dec90f61SDavid Howells 			ffs_data_put(ctx->ffs_data);
1604dec90f61SDavid Howells 		}
1605dec90f61SDavid Howells 
1606dec90f61SDavid Howells 		kfree(ctx);
1607dec90f61SDavid Howells 	}
1608dec90f61SDavid Howells }
1609dec90f61SDavid Howells 
1610dec90f61SDavid Howells static const struct fs_context_operations ffs_fs_context_ops = {
1611dec90f61SDavid Howells 	.free		= ffs_fs_free_fc,
1612dec90f61SDavid Howells 	.parse_param	= ffs_fs_parse_param,
1613dec90f61SDavid Howells 	.get_tree	= ffs_fs_get_tree,
1614dec90f61SDavid Howells };
1615dec90f61SDavid Howells 
1616dec90f61SDavid Howells static int ffs_fs_init_fs_context(struct fs_context *fc)
1617dec90f61SDavid Howells {
1618dec90f61SDavid Howells 	struct ffs_sb_fill_data *ctx;
1619dec90f61SDavid Howells 
1620dec90f61SDavid Howells 	ctx = kzalloc(sizeof(struct ffs_sb_fill_data), GFP_KERNEL);
1621dec90f61SDavid Howells 	if (!ctx)
1622dec90f61SDavid Howells 		return -ENOMEM;
1623dec90f61SDavid Howells 
1624dec90f61SDavid Howells 	ctx->perms.mode = S_IFREG | 0600;
1625dec90f61SDavid Howells 	ctx->perms.uid = GLOBAL_ROOT_UID;
1626dec90f61SDavid Howells 	ctx->perms.gid = GLOBAL_ROOT_GID;
1627dec90f61SDavid Howells 	ctx->root_mode = S_IFDIR | 0500;
1628dec90f61SDavid Howells 	ctx->no_disconnect = false;
1629dec90f61SDavid Howells 
1630dec90f61SDavid Howells 	fc->fs_private = ctx;
1631dec90f61SDavid Howells 	fc->ops = &ffs_fs_context_ops;
1632dec90f61SDavid Howells 	return 0;
163300a2430fSAndrzej Pietrasiewicz }
163400a2430fSAndrzej Pietrasiewicz 
163500a2430fSAndrzej Pietrasiewicz static void
163600a2430fSAndrzej Pietrasiewicz ffs_fs_kill_sb(struct super_block *sb)
163700a2430fSAndrzej Pietrasiewicz {
163800a2430fSAndrzej Pietrasiewicz 	ENTER();
163900a2430fSAndrzej Pietrasiewicz 
164000a2430fSAndrzej Pietrasiewicz 	kill_litter_super(sb);
1641ecfbd7b9SAndrew Gabbasov 	if (sb->s_fs_info)
164218d6b32fSRobert Baldyga 		ffs_data_closed(sb->s_fs_info);
164300a2430fSAndrzej Pietrasiewicz }
164400a2430fSAndrzej Pietrasiewicz 
164500a2430fSAndrzej Pietrasiewicz static struct file_system_type ffs_fs_type = {
164600a2430fSAndrzej Pietrasiewicz 	.owner		= THIS_MODULE,
164700a2430fSAndrzej Pietrasiewicz 	.name		= "functionfs",
1648dec90f61SDavid Howells 	.init_fs_context = ffs_fs_init_fs_context,
1649d7167b14SAl Viro 	.parameters	= ffs_fs_fs_parameters,
165000a2430fSAndrzej Pietrasiewicz 	.kill_sb	= ffs_fs_kill_sb,
165100a2430fSAndrzej Pietrasiewicz };
165200a2430fSAndrzej Pietrasiewicz MODULE_ALIAS_FS("functionfs");
165300a2430fSAndrzej Pietrasiewicz 
165400a2430fSAndrzej Pietrasiewicz 
165500a2430fSAndrzej Pietrasiewicz /* Driver's main init/cleanup functions *************************************/
165600a2430fSAndrzej Pietrasiewicz 
165700a2430fSAndrzej Pietrasiewicz static int functionfs_init(void)
165800a2430fSAndrzej Pietrasiewicz {
165900a2430fSAndrzej Pietrasiewicz 	int ret;
166000a2430fSAndrzej Pietrasiewicz 
166100a2430fSAndrzej Pietrasiewicz 	ENTER();
166200a2430fSAndrzej Pietrasiewicz 
166300a2430fSAndrzej Pietrasiewicz 	ret = register_filesystem(&ffs_fs_type);
16648704fd73SGreg Kroah-Hartman 	if (!ret)
166500a2430fSAndrzej Pietrasiewicz 		pr_info("file system registered\n");
166600a2430fSAndrzej Pietrasiewicz 	else
166700a2430fSAndrzej Pietrasiewicz 		pr_err("failed registering file system (%d)\n", ret);
166800a2430fSAndrzej Pietrasiewicz 
166900a2430fSAndrzej Pietrasiewicz 	return ret;
167000a2430fSAndrzej Pietrasiewicz }
167100a2430fSAndrzej Pietrasiewicz 
167200a2430fSAndrzej Pietrasiewicz static void functionfs_cleanup(void)
167300a2430fSAndrzej Pietrasiewicz {
167400a2430fSAndrzej Pietrasiewicz 	ENTER();
167500a2430fSAndrzej Pietrasiewicz 
167600a2430fSAndrzej Pietrasiewicz 	pr_info("unloading\n");
167700a2430fSAndrzej Pietrasiewicz 	unregister_filesystem(&ffs_fs_type);
167800a2430fSAndrzej Pietrasiewicz }
167900a2430fSAndrzej Pietrasiewicz 
168000a2430fSAndrzej Pietrasiewicz 
168100a2430fSAndrzej Pietrasiewicz /* ffs_data and ffs_function construction and destruction code **************/
168200a2430fSAndrzej Pietrasiewicz 
168300a2430fSAndrzej Pietrasiewicz static void ffs_data_clear(struct ffs_data *ffs);
168400a2430fSAndrzej Pietrasiewicz static void ffs_data_reset(struct ffs_data *ffs);
168500a2430fSAndrzej Pietrasiewicz 
168600a2430fSAndrzej Pietrasiewicz static void ffs_data_get(struct ffs_data *ffs)
168700a2430fSAndrzej Pietrasiewicz {
168800a2430fSAndrzej Pietrasiewicz 	ENTER();
168900a2430fSAndrzej Pietrasiewicz 
169043938613SElena Reshetova 	refcount_inc(&ffs->ref);
169100a2430fSAndrzej Pietrasiewicz }
169200a2430fSAndrzej Pietrasiewicz 
169300a2430fSAndrzej Pietrasiewicz static void ffs_data_opened(struct ffs_data *ffs)
169400a2430fSAndrzej Pietrasiewicz {
169500a2430fSAndrzej Pietrasiewicz 	ENTER();
169600a2430fSAndrzej Pietrasiewicz 
169743938613SElena Reshetova 	refcount_inc(&ffs->ref);
169818d6b32fSRobert Baldyga 	if (atomic_add_return(1, &ffs->opened) == 1 &&
169918d6b32fSRobert Baldyga 			ffs->state == FFS_DEACTIVATED) {
170018d6b32fSRobert Baldyga 		ffs->state = FFS_CLOSING;
170118d6b32fSRobert Baldyga 		ffs_data_reset(ffs);
170218d6b32fSRobert Baldyga 	}
170300a2430fSAndrzej Pietrasiewicz }
170400a2430fSAndrzej Pietrasiewicz 
170500a2430fSAndrzej Pietrasiewicz static void ffs_data_put(struct ffs_data *ffs)
170600a2430fSAndrzej Pietrasiewicz {
170700a2430fSAndrzej Pietrasiewicz 	ENTER();
170800a2430fSAndrzej Pietrasiewicz 
17098704fd73SGreg Kroah-Hartman 	if (refcount_dec_and_test(&ffs->ref)) {
171000a2430fSAndrzej Pietrasiewicz 		pr_info("%s(): freeing\n", __func__);
171100a2430fSAndrzej Pietrasiewicz 		ffs_data_clear(ffs);
1712ecfbd7b9SAndrew Gabbasov 		ffs_release_dev(ffs->private_data);
171300a2430fSAndrzej Pietrasiewicz 		BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
1714a5c6234eSThomas Gleixner 		       swait_active(&ffs->ep0req_completion.wait) ||
1715e16828cfSJerry Zhang 		       waitqueue_active(&ffs->wait));
1716addfc582SJohn Keeping 		destroy_workqueue(ffs->io_completion_wq);
171700a2430fSAndrzej Pietrasiewicz 		kfree(ffs->dev_name);
171800a2430fSAndrzej Pietrasiewicz 		kfree(ffs);
171900a2430fSAndrzej Pietrasiewicz 	}
172000a2430fSAndrzej Pietrasiewicz }
172100a2430fSAndrzej Pietrasiewicz 
172200a2430fSAndrzej Pietrasiewicz static void ffs_data_closed(struct ffs_data *ffs)
172300a2430fSAndrzej Pietrasiewicz {
1724ebe2b1adSUdipto Goswami 	struct ffs_epfile *epfiles;
1725ebe2b1adSUdipto Goswami 	unsigned long flags;
1726ebe2b1adSUdipto Goswami 
172700a2430fSAndrzej Pietrasiewicz 	ENTER();
172800a2430fSAndrzej Pietrasiewicz 
172900a2430fSAndrzej Pietrasiewicz 	if (atomic_dec_and_test(&ffs->opened)) {
173018d6b32fSRobert Baldyga 		if (ffs->no_disconnect) {
173118d6b32fSRobert Baldyga 			ffs->state = FFS_DEACTIVATED;
1732ebe2b1adSUdipto Goswami 			spin_lock_irqsave(&ffs->eps_lock, flags);
1733ebe2b1adSUdipto Goswami 			epfiles = ffs->epfiles;
173418d6b32fSRobert Baldyga 			ffs->epfiles = NULL;
1735ebe2b1adSUdipto Goswami 			spin_unlock_irqrestore(&ffs->eps_lock,
1736ebe2b1adSUdipto Goswami 							flags);
1737ebe2b1adSUdipto Goswami 
1738ebe2b1adSUdipto Goswami 			if (epfiles)
1739ebe2b1adSUdipto Goswami 				ffs_epfiles_destroy(epfiles,
1740ebe2b1adSUdipto Goswami 						 ffs->eps_count);
1741ebe2b1adSUdipto Goswami 
174218d6b32fSRobert Baldyga 			if (ffs->setup_state == FFS_SETUP_PENDING)
174318d6b32fSRobert Baldyga 				__ffs_ep0_stall(ffs);
174418d6b32fSRobert Baldyga 		} else {
174518d6b32fSRobert Baldyga 			ffs->state = FFS_CLOSING;
174618d6b32fSRobert Baldyga 			ffs_data_reset(ffs);
174718d6b32fSRobert Baldyga 		}
174818d6b32fSRobert Baldyga 	}
174918d6b32fSRobert Baldyga 	if (atomic_read(&ffs->opened) < 0) {
175000a2430fSAndrzej Pietrasiewicz 		ffs->state = FFS_CLOSING;
175100a2430fSAndrzej Pietrasiewicz 		ffs_data_reset(ffs);
175200a2430fSAndrzej Pietrasiewicz 	}
175300a2430fSAndrzej Pietrasiewicz 
175400a2430fSAndrzej Pietrasiewicz 	ffs_data_put(ffs);
175500a2430fSAndrzej Pietrasiewicz }
175600a2430fSAndrzej Pietrasiewicz 
1757addfc582SJohn Keeping static struct ffs_data *ffs_data_new(const char *dev_name)
175800a2430fSAndrzej Pietrasiewicz {
175900a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
17608704fd73SGreg Kroah-Hartman 	if (!ffs)
176100a2430fSAndrzej Pietrasiewicz 		return NULL;
176200a2430fSAndrzej Pietrasiewicz 
176300a2430fSAndrzej Pietrasiewicz 	ENTER();
176400a2430fSAndrzej Pietrasiewicz 
1765addfc582SJohn Keeping 	ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
1766addfc582SJohn Keeping 	if (!ffs->io_completion_wq) {
1767addfc582SJohn Keeping 		kfree(ffs);
1768addfc582SJohn Keeping 		return NULL;
1769addfc582SJohn Keeping 	}
1770addfc582SJohn Keeping 
177143938613SElena Reshetova 	refcount_set(&ffs->ref, 1);
177200a2430fSAndrzej Pietrasiewicz 	atomic_set(&ffs->opened, 0);
177300a2430fSAndrzej Pietrasiewicz 	ffs->state = FFS_READ_DESCRIPTORS;
177400a2430fSAndrzej Pietrasiewicz 	mutex_init(&ffs->mutex);
177500a2430fSAndrzej Pietrasiewicz 	spin_lock_init(&ffs->eps_lock);
177600a2430fSAndrzej Pietrasiewicz 	init_waitqueue_head(&ffs->ev.waitq);
1777e16828cfSJerry Zhang 	init_waitqueue_head(&ffs->wait);
177800a2430fSAndrzej Pietrasiewicz 	init_completion(&ffs->ep0req_completion);
177900a2430fSAndrzej Pietrasiewicz 
178000a2430fSAndrzej Pietrasiewicz 	/* XXX REVISIT need to update it in some places, or do we? */
178100a2430fSAndrzej Pietrasiewicz 	ffs->ev.can_stall = 1;
178200a2430fSAndrzej Pietrasiewicz 
178300a2430fSAndrzej Pietrasiewicz 	return ffs;
178400a2430fSAndrzej Pietrasiewicz }
178500a2430fSAndrzej Pietrasiewicz 
178600a2430fSAndrzej Pietrasiewicz static void ffs_data_clear(struct ffs_data *ffs)
178700a2430fSAndrzej Pietrasiewicz {
1788ebe2b1adSUdipto Goswami 	struct ffs_epfile *epfiles;
1789ebe2b1adSUdipto Goswami 	unsigned long flags;
1790ebe2b1adSUdipto Goswami 
179100a2430fSAndrzej Pietrasiewicz 	ENTER();
179200a2430fSAndrzej Pietrasiewicz 
179300a2430fSAndrzej Pietrasiewicz 	ffs_closed(ffs);
179400a2430fSAndrzej Pietrasiewicz 
179500a2430fSAndrzej Pietrasiewicz 	BUG_ON(ffs->gadget);
179600a2430fSAndrzej Pietrasiewicz 
1797ebe2b1adSUdipto Goswami 	spin_lock_irqsave(&ffs->eps_lock, flags);
1798ebe2b1adSUdipto Goswami 	epfiles = ffs->epfiles;
1799ebe2b1adSUdipto Goswami 	ffs->epfiles = NULL;
1800ebe2b1adSUdipto Goswami 	spin_unlock_irqrestore(&ffs->eps_lock, flags);
1801ebe2b1adSUdipto Goswami 
1802ebe2b1adSUdipto Goswami 	/*
1803ebe2b1adSUdipto Goswami 	 * potential race possible between ffs_func_eps_disable
1804ebe2b1adSUdipto Goswami 	 * & ffs_epfile_release therefore maintaining a local
1805ebe2b1adSUdipto Goswami 	 * copy of epfile will save us from use-after-free.
1806ebe2b1adSUdipto Goswami 	 */
1807ebe2b1adSUdipto Goswami 	if (epfiles) {
1808ebe2b1adSUdipto Goswami 		ffs_epfiles_destroy(epfiles, ffs->eps_count);
1809b1e08873SVincent Pelletier 		ffs->epfiles = NULL;
1810b1e08873SVincent Pelletier 	}
181100a2430fSAndrzej Pietrasiewicz 
1812b1e08873SVincent Pelletier 	if (ffs->ffs_eventfd) {
18135e33f6fdSRobert Baldyga 		eventfd_ctx_put(ffs->ffs_eventfd);
1814b1e08873SVincent Pelletier 		ffs->ffs_eventfd = NULL;
1815b1e08873SVincent Pelletier 	}
18165e33f6fdSRobert Baldyga 
181700a2430fSAndrzej Pietrasiewicz 	kfree(ffs->raw_descs_data);
181800a2430fSAndrzej Pietrasiewicz 	kfree(ffs->raw_strings);
181900a2430fSAndrzej Pietrasiewicz 	kfree(ffs->stringtabs);
182000a2430fSAndrzej Pietrasiewicz }
182100a2430fSAndrzej Pietrasiewicz 
182200a2430fSAndrzej Pietrasiewicz static void ffs_data_reset(struct ffs_data *ffs)
182300a2430fSAndrzej Pietrasiewicz {
182400a2430fSAndrzej Pietrasiewicz 	ENTER();
182500a2430fSAndrzej Pietrasiewicz 
182600a2430fSAndrzej Pietrasiewicz 	ffs_data_clear(ffs);
182700a2430fSAndrzej Pietrasiewicz 
182800a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs_data = NULL;
182900a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs = NULL;
183000a2430fSAndrzej Pietrasiewicz 	ffs->raw_strings = NULL;
183100a2430fSAndrzej Pietrasiewicz 	ffs->stringtabs = NULL;
183200a2430fSAndrzej Pietrasiewicz 
183300a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs_length = 0;
183400a2430fSAndrzej Pietrasiewicz 	ffs->fs_descs_count = 0;
183500a2430fSAndrzej Pietrasiewicz 	ffs->hs_descs_count = 0;
183600a2430fSAndrzej Pietrasiewicz 	ffs->ss_descs_count = 0;
183700a2430fSAndrzej Pietrasiewicz 
183800a2430fSAndrzej Pietrasiewicz 	ffs->strings_count = 0;
183900a2430fSAndrzej Pietrasiewicz 	ffs->interfaces_count = 0;
184000a2430fSAndrzej Pietrasiewicz 	ffs->eps_count = 0;
184100a2430fSAndrzej Pietrasiewicz 
184200a2430fSAndrzej Pietrasiewicz 	ffs->ev.count = 0;
184300a2430fSAndrzej Pietrasiewicz 
184400a2430fSAndrzej Pietrasiewicz 	ffs->state = FFS_READ_DESCRIPTORS;
184500a2430fSAndrzej Pietrasiewicz 	ffs->setup_state = FFS_NO_SETUP;
184600a2430fSAndrzej Pietrasiewicz 	ffs->flags = 0;
18471c2e54fbSUdipto Goswami 
18481c2e54fbSUdipto Goswami 	ffs->ms_os_descs_ext_prop_count = 0;
18491c2e54fbSUdipto Goswami 	ffs->ms_os_descs_ext_prop_name_len = 0;
18501c2e54fbSUdipto Goswami 	ffs->ms_os_descs_ext_prop_data_len = 0;
185100a2430fSAndrzej Pietrasiewicz }
185200a2430fSAndrzej Pietrasiewicz 
185300a2430fSAndrzej Pietrasiewicz 
185400a2430fSAndrzej Pietrasiewicz static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
185500a2430fSAndrzej Pietrasiewicz {
185600a2430fSAndrzej Pietrasiewicz 	struct usb_gadget_strings **lang;
185700a2430fSAndrzej Pietrasiewicz 	int first_id;
185800a2430fSAndrzej Pietrasiewicz 
185900a2430fSAndrzej Pietrasiewicz 	ENTER();
186000a2430fSAndrzej Pietrasiewicz 
186100a2430fSAndrzej Pietrasiewicz 	if (WARN_ON(ffs->state != FFS_ACTIVE
186200a2430fSAndrzej Pietrasiewicz 		 || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
186300a2430fSAndrzej Pietrasiewicz 		return -EBADFD;
186400a2430fSAndrzej Pietrasiewicz 
186500a2430fSAndrzej Pietrasiewicz 	first_id = usb_string_ids_n(cdev, ffs->strings_count);
18668704fd73SGreg Kroah-Hartman 	if (first_id < 0)
186700a2430fSAndrzej Pietrasiewicz 		return first_id;
186800a2430fSAndrzej Pietrasiewicz 
186900a2430fSAndrzej Pietrasiewicz 	ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
18708704fd73SGreg Kroah-Hartman 	if (!ffs->ep0req)
187100a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
187200a2430fSAndrzej Pietrasiewicz 	ffs->ep0req->complete = ffs_ep0_complete;
187300a2430fSAndrzej Pietrasiewicz 	ffs->ep0req->context = ffs;
187400a2430fSAndrzej Pietrasiewicz 
187500a2430fSAndrzej Pietrasiewicz 	lang = ffs->stringtabs;
187661fe2d75SGreg Kroah-Hartman 	if (lang) {
187761fe2d75SGreg Kroah-Hartman 		for (; *lang; ++lang) {
187800a2430fSAndrzej Pietrasiewicz 			struct usb_string *str = (*lang)->strings;
187900a2430fSAndrzej Pietrasiewicz 			int id = first_id;
188000a2430fSAndrzej Pietrasiewicz 			for (; str->s; ++id, ++str)
188100a2430fSAndrzej Pietrasiewicz 				str->id = id;
188200a2430fSAndrzej Pietrasiewicz 		}
188361fe2d75SGreg Kroah-Hartman 	}
188400a2430fSAndrzej Pietrasiewicz 
188500a2430fSAndrzej Pietrasiewicz 	ffs->gadget = cdev->gadget;
188600a2430fSAndrzej Pietrasiewicz 	ffs_data_get(ffs);
188700a2430fSAndrzej Pietrasiewicz 	return 0;
188800a2430fSAndrzej Pietrasiewicz }
188900a2430fSAndrzej Pietrasiewicz 
189000a2430fSAndrzej Pietrasiewicz static void functionfs_unbind(struct ffs_data *ffs)
189100a2430fSAndrzej Pietrasiewicz {
189200a2430fSAndrzej Pietrasiewicz 	ENTER();
189300a2430fSAndrzej Pietrasiewicz 
189400a2430fSAndrzej Pietrasiewicz 	if (!WARN_ON(!ffs->gadget)) {
189500a2430fSAndrzej Pietrasiewicz 		usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
189600a2430fSAndrzej Pietrasiewicz 		ffs->ep0req = NULL;
189700a2430fSAndrzej Pietrasiewicz 		ffs->gadget = NULL;
189800a2430fSAndrzej Pietrasiewicz 		clear_bit(FFS_FL_BOUND, &ffs->flags);
189900a2430fSAndrzej Pietrasiewicz 		ffs_data_put(ffs);
190000a2430fSAndrzej Pietrasiewicz 	}
190100a2430fSAndrzej Pietrasiewicz }
190200a2430fSAndrzej Pietrasiewicz 
190300a2430fSAndrzej Pietrasiewicz static int ffs_epfiles_create(struct ffs_data *ffs)
190400a2430fSAndrzej Pietrasiewicz {
190500a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile, *epfiles;
190600a2430fSAndrzej Pietrasiewicz 	unsigned i, count;
190700a2430fSAndrzej Pietrasiewicz 
190800a2430fSAndrzej Pietrasiewicz 	ENTER();
190900a2430fSAndrzej Pietrasiewicz 
191000a2430fSAndrzej Pietrasiewicz 	count = ffs->eps_count;
191100a2430fSAndrzej Pietrasiewicz 	epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
191200a2430fSAndrzej Pietrasiewicz 	if (!epfiles)
191300a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
191400a2430fSAndrzej Pietrasiewicz 
191500a2430fSAndrzej Pietrasiewicz 	epfile = epfiles;
191600a2430fSAndrzej Pietrasiewicz 	for (i = 1; i <= count; ++i, ++epfile) {
191700a2430fSAndrzej Pietrasiewicz 		epfile->ffs = ffs;
191800a2430fSAndrzej Pietrasiewicz 		mutex_init(&epfile->mutex);
19191b0bf88fSRobert Baldyga 		if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
1920acba23feSMario Schuknecht 			sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
19211b0bf88fSRobert Baldyga 		else
1922acba23feSMario Schuknecht 			sprintf(epfile->name, "ep%u", i);
1923acba23feSMario Schuknecht 		epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
19241bb27cacSAl Viro 						 epfile,
19251bb27cacSAl Viro 						 &ffs_epfile_operations);
19268704fd73SGreg Kroah-Hartman 		if (!epfile->dentry) {
192700a2430fSAndrzej Pietrasiewicz 			ffs_epfiles_destroy(epfiles, i - 1);
192800a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
192900a2430fSAndrzej Pietrasiewicz 		}
193000a2430fSAndrzej Pietrasiewicz 	}
193100a2430fSAndrzej Pietrasiewicz 
193200a2430fSAndrzej Pietrasiewicz 	ffs->epfiles = epfiles;
193300a2430fSAndrzej Pietrasiewicz 	return 0;
193400a2430fSAndrzej Pietrasiewicz }
193500a2430fSAndrzej Pietrasiewicz 
193600a2430fSAndrzej Pietrasiewicz static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
193700a2430fSAndrzej Pietrasiewicz {
193800a2430fSAndrzej Pietrasiewicz 	struct ffs_epfile *epfile = epfiles;
193900a2430fSAndrzej Pietrasiewicz 
194000a2430fSAndrzej Pietrasiewicz 	ENTER();
194100a2430fSAndrzej Pietrasiewicz 
194200a2430fSAndrzej Pietrasiewicz 	for (; count; --count, ++epfile) {
1943e16828cfSJerry Zhang 		BUG_ON(mutex_is_locked(&epfile->mutex));
194400a2430fSAndrzej Pietrasiewicz 		if (epfile->dentry) {
194500a2430fSAndrzej Pietrasiewicz 			d_delete(epfile->dentry);
194600a2430fSAndrzej Pietrasiewicz 			dput(epfile->dentry);
194700a2430fSAndrzej Pietrasiewicz 			epfile->dentry = NULL;
194800a2430fSAndrzej Pietrasiewicz 		}
194900a2430fSAndrzej Pietrasiewicz 	}
195000a2430fSAndrzej Pietrasiewicz 
195100a2430fSAndrzej Pietrasiewicz 	kfree(epfiles);
195200a2430fSAndrzej Pietrasiewicz }
195300a2430fSAndrzej Pietrasiewicz 
195400a2430fSAndrzej Pietrasiewicz static void ffs_func_eps_disable(struct ffs_function *func)
195500a2430fSAndrzej Pietrasiewicz {
1956ebe2b1adSUdipto Goswami 	struct ffs_ep *ep;
1957ebe2b1adSUdipto Goswami 	struct ffs_epfile *epfile;
1958ebe2b1adSUdipto Goswami 	unsigned short count;
195900a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
196000a2430fSAndrzej Pietrasiewicz 
19619353afbbSMichal Nazarewicz 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
1962ebe2b1adSUdipto Goswami 	count = func->ffs->eps_count;
1963ebe2b1adSUdipto Goswami 	epfile = func->ffs->epfiles;
1964ebe2b1adSUdipto Goswami 	ep = func->eps;
196508f37148SVincent Pelletier 	while (count--) {
196600a2430fSAndrzej Pietrasiewicz 		/* pending requests get nuked */
19678704fd73SGreg Kroah-Hartman 		if (ep->ep)
196800a2430fSAndrzej Pietrasiewicz 			usb_ep_disable(ep->ep);
196900a2430fSAndrzej Pietrasiewicz 		++ep;
197018d6b32fSRobert Baldyga 
197118d6b32fSRobert Baldyga 		if (epfile) {
1972a9e6f83cSMichal Nazarewicz 			epfile->ep = NULL;
1973a9e6f83cSMichal Nazarewicz 			__ffs_epfile_read_buffer_free(epfile);
197400a2430fSAndrzej Pietrasiewicz 			++epfile;
197518d6b32fSRobert Baldyga 		}
197608f37148SVincent Pelletier 	}
1977a9e6f83cSMichal Nazarewicz 	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
197800a2430fSAndrzej Pietrasiewicz }
197900a2430fSAndrzej Pietrasiewicz 
198000a2430fSAndrzej Pietrasiewicz static int ffs_func_eps_enable(struct ffs_function *func)
198100a2430fSAndrzej Pietrasiewicz {
1982ebe2b1adSUdipto Goswami 	struct ffs_data *ffs;
1983ebe2b1adSUdipto Goswami 	struct ffs_ep *ep;
1984ebe2b1adSUdipto Goswami 	struct ffs_epfile *epfile;
1985ebe2b1adSUdipto Goswami 	unsigned short count;
198600a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
198700a2430fSAndrzej Pietrasiewicz 	int ret = 0;
198800a2430fSAndrzej Pietrasiewicz 
198900a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
1990ebe2b1adSUdipto Goswami 	ffs = func->ffs;
1991ebe2b1adSUdipto Goswami 	ep = func->eps;
1992ebe2b1adSUdipto Goswami 	epfile = ffs->epfiles;
1993ebe2b1adSUdipto Goswami 	count = ffs->eps_count;
199408f37148SVincent Pelletier 	while(count--) {
199500a2430fSAndrzej Pietrasiewicz 		ep->ep->driver_data = ep;
19962bfa0719SFelipe Balbi 
1997675272d0SJack Pham 		ret = config_ep_by_speed(func->gadget, &func->function, ep->ep);
1998675272d0SJack Pham 		if (ret) {
1999675272d0SJack Pham 			pr_err("%s: config_ep_by_speed(%s) returned %d\n",
2000675272d0SJack Pham 					__func__, ep->ep->name, ret);
2001675272d0SJack Pham 			break;
2002b7f73850SWilliam Wu 		}
20032bfa0719SFelipe Balbi 
200400a2430fSAndrzej Pietrasiewicz 		ret = usb_ep_enable(ep->ep);
20058704fd73SGreg Kroah-Hartman 		if (!ret) {
200600a2430fSAndrzej Pietrasiewicz 			epfile->ep = ep;
2007675272d0SJack Pham 			epfile->in = usb_endpoint_dir_in(ep->ep->desc);
2008675272d0SJack Pham 			epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
200900a2430fSAndrzej Pietrasiewicz 		} else {
201000a2430fSAndrzej Pietrasiewicz 			break;
201100a2430fSAndrzej Pietrasiewicz 		}
201200a2430fSAndrzej Pietrasiewicz 
201300a2430fSAndrzej Pietrasiewicz 		++ep;
201400a2430fSAndrzej Pietrasiewicz 		++epfile;
201508f37148SVincent Pelletier 	}
2016e16828cfSJerry Zhang 
2017e16828cfSJerry Zhang 	wake_up_interruptible(&ffs->wait);
201800a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
201900a2430fSAndrzej Pietrasiewicz 
202000a2430fSAndrzej Pietrasiewicz 	return ret;
202100a2430fSAndrzej Pietrasiewicz }
202200a2430fSAndrzej Pietrasiewicz 
202300a2430fSAndrzej Pietrasiewicz 
202400a2430fSAndrzej Pietrasiewicz /* Parsing and building descriptors and strings *****************************/
202500a2430fSAndrzej Pietrasiewicz 
202600a2430fSAndrzej Pietrasiewicz /*
202700a2430fSAndrzej Pietrasiewicz  * This validates if data pointed by data is a valid USB descriptor as
202800a2430fSAndrzej Pietrasiewicz  * well as record how many interfaces, endpoints and strings are
202900a2430fSAndrzej Pietrasiewicz  * required by given configuration.  Returns address after the
203000a2430fSAndrzej Pietrasiewicz  * descriptor or NULL if data is invalid.
203100a2430fSAndrzej Pietrasiewicz  */
203200a2430fSAndrzej Pietrasiewicz 
203300a2430fSAndrzej Pietrasiewicz enum ffs_entity_type {
203400a2430fSAndrzej Pietrasiewicz 	FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
203500a2430fSAndrzej Pietrasiewicz };
203600a2430fSAndrzej Pietrasiewicz 
203700a2430fSAndrzej Pietrasiewicz enum ffs_os_desc_type {
203800a2430fSAndrzej Pietrasiewicz 	FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP
203900a2430fSAndrzej Pietrasiewicz };
204000a2430fSAndrzej Pietrasiewicz 
204100a2430fSAndrzej Pietrasiewicz typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
204200a2430fSAndrzej Pietrasiewicz 				   u8 *valuep,
204300a2430fSAndrzej Pietrasiewicz 				   struct usb_descriptor_header *desc,
204400a2430fSAndrzej Pietrasiewicz 				   void *priv);
204500a2430fSAndrzej Pietrasiewicz 
204600a2430fSAndrzej Pietrasiewicz typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
204700a2430fSAndrzej Pietrasiewicz 				    struct usb_os_desc_header *h, void *data,
204800a2430fSAndrzej Pietrasiewicz 				    unsigned len, void *priv);
204900a2430fSAndrzej Pietrasiewicz 
205000a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_single_desc(char *data, unsigned len,
205100a2430fSAndrzej Pietrasiewicz 					   ffs_entity_callback entity,
20527f7c548cSVincent Pelletier 					   void *priv, int *current_class)
205300a2430fSAndrzej Pietrasiewicz {
205400a2430fSAndrzej Pietrasiewicz 	struct usb_descriptor_header *_ds = (void *)data;
205500a2430fSAndrzej Pietrasiewicz 	u8 length;
205600a2430fSAndrzej Pietrasiewicz 	int ret;
205700a2430fSAndrzej Pietrasiewicz 
205800a2430fSAndrzej Pietrasiewicz 	ENTER();
205900a2430fSAndrzej Pietrasiewicz 
206000a2430fSAndrzej Pietrasiewicz 	/* At least two bytes are required: length and type */
206100a2430fSAndrzej Pietrasiewicz 	if (len < 2) {
206200a2430fSAndrzej Pietrasiewicz 		pr_vdebug("descriptor too short\n");
206300a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
206400a2430fSAndrzej Pietrasiewicz 	}
206500a2430fSAndrzej Pietrasiewicz 
206600a2430fSAndrzej Pietrasiewicz 	/* If we have at least as many bytes as the descriptor takes? */
206700a2430fSAndrzej Pietrasiewicz 	length = _ds->bLength;
206800a2430fSAndrzej Pietrasiewicz 	if (len < length) {
206900a2430fSAndrzej Pietrasiewicz 		pr_vdebug("descriptor longer then available data\n");
207000a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
207100a2430fSAndrzej Pietrasiewicz 	}
207200a2430fSAndrzej Pietrasiewicz 
207300a2430fSAndrzej Pietrasiewicz #define __entity_check_INTERFACE(val)  1
207400a2430fSAndrzej Pietrasiewicz #define __entity_check_STRING(val)     (val)
207500a2430fSAndrzej Pietrasiewicz #define __entity_check_ENDPOINT(val)   ((val) & USB_ENDPOINT_NUMBER_MASK)
207600a2430fSAndrzej Pietrasiewicz #define __entity(type, val) do {					\
207700a2430fSAndrzej Pietrasiewicz 		pr_vdebug("entity " #type "(%02x)\n", (val));		\
20788704fd73SGreg Kroah-Hartman 		if (!__entity_check_ ##type(val)) {			\
207900a2430fSAndrzej Pietrasiewicz 			pr_vdebug("invalid entity's value\n");		\
208000a2430fSAndrzej Pietrasiewicz 			return -EINVAL;					\
208100a2430fSAndrzej Pietrasiewicz 		}							\
208200a2430fSAndrzej Pietrasiewicz 		ret = entity(FFS_ ##type, &val, _ds, priv);		\
20838704fd73SGreg Kroah-Hartman 		if (ret < 0) {						\
208400a2430fSAndrzej Pietrasiewicz 			pr_debug("entity " #type "(%02x); ret = %d\n",	\
208500a2430fSAndrzej Pietrasiewicz 				 (val), ret);				\
208600a2430fSAndrzej Pietrasiewicz 			return ret;					\
208700a2430fSAndrzej Pietrasiewicz 		}							\
208800a2430fSAndrzej Pietrasiewicz 	} while (0)
208900a2430fSAndrzej Pietrasiewicz 
209000a2430fSAndrzej Pietrasiewicz 	/* Parse descriptor depending on type. */
209100a2430fSAndrzej Pietrasiewicz 	switch (_ds->bDescriptorType) {
209200a2430fSAndrzej Pietrasiewicz 	case USB_DT_DEVICE:
209300a2430fSAndrzej Pietrasiewicz 	case USB_DT_CONFIG:
209400a2430fSAndrzej Pietrasiewicz 	case USB_DT_STRING:
209500a2430fSAndrzej Pietrasiewicz 	case USB_DT_DEVICE_QUALIFIER:
209600a2430fSAndrzej Pietrasiewicz 		/* function can't have any of those */
209700a2430fSAndrzej Pietrasiewicz 		pr_vdebug("descriptor reserved for gadget: %d\n",
209800a2430fSAndrzej Pietrasiewicz 		      _ds->bDescriptorType);
209900a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
210000a2430fSAndrzej Pietrasiewicz 
210100a2430fSAndrzej Pietrasiewicz 	case USB_DT_INTERFACE: {
210200a2430fSAndrzej Pietrasiewicz 		struct usb_interface_descriptor *ds = (void *)_ds;
210300a2430fSAndrzej Pietrasiewicz 		pr_vdebug("interface descriptor\n");
210400a2430fSAndrzej Pietrasiewicz 		if (length != sizeof *ds)
210500a2430fSAndrzej Pietrasiewicz 			goto inv_length;
210600a2430fSAndrzej Pietrasiewicz 
210700a2430fSAndrzej Pietrasiewicz 		__entity(INTERFACE, ds->bInterfaceNumber);
210800a2430fSAndrzej Pietrasiewicz 		if (ds->iInterface)
210900a2430fSAndrzej Pietrasiewicz 			__entity(STRING, ds->iInterface);
21107f7c548cSVincent Pelletier 		*current_class = ds->bInterfaceClass;
211100a2430fSAndrzej Pietrasiewicz 	}
211200a2430fSAndrzej Pietrasiewicz 		break;
211300a2430fSAndrzej Pietrasiewicz 
211400a2430fSAndrzej Pietrasiewicz 	case USB_DT_ENDPOINT: {
211500a2430fSAndrzej Pietrasiewicz 		struct usb_endpoint_descriptor *ds = (void *)_ds;
211600a2430fSAndrzej Pietrasiewicz 		pr_vdebug("endpoint descriptor\n");
211700a2430fSAndrzej Pietrasiewicz 		if (length != USB_DT_ENDPOINT_SIZE &&
211800a2430fSAndrzej Pietrasiewicz 		    length != USB_DT_ENDPOINT_AUDIO_SIZE)
211900a2430fSAndrzej Pietrasiewicz 			goto inv_length;
212000a2430fSAndrzej Pietrasiewicz 		__entity(ENDPOINT, ds->bEndpointAddress);
212100a2430fSAndrzej Pietrasiewicz 	}
212200a2430fSAndrzej Pietrasiewicz 		break;
212300a2430fSAndrzej Pietrasiewicz 
21247f7c548cSVincent Pelletier 	case USB_TYPE_CLASS | 0x01:
21257f7c548cSVincent Pelletier 		if (*current_class == USB_INTERFACE_CLASS_HID) {
212600a2430fSAndrzej Pietrasiewicz 			pr_vdebug("hid descriptor\n");
212700a2430fSAndrzej Pietrasiewicz 			if (length != sizeof(struct hid_descriptor))
212800a2430fSAndrzej Pietrasiewicz 				goto inv_length;
212900a2430fSAndrzej Pietrasiewicz 			break;
21307f7c548cSVincent Pelletier 		} else if (*current_class == USB_INTERFACE_CLASS_CCID) {
21317f7c548cSVincent Pelletier 			pr_vdebug("ccid descriptor\n");
21327f7c548cSVincent Pelletier 			if (length != sizeof(struct ccid_descriptor))
21337f7c548cSVincent Pelletier 				goto inv_length;
21347f7c548cSVincent Pelletier 			break;
21357f7c548cSVincent Pelletier 		} else {
21367f7c548cSVincent Pelletier 			pr_vdebug("unknown descriptor: %d for class %d\n",
21377f7c548cSVincent Pelletier 			      _ds->bDescriptorType, *current_class);
21387f7c548cSVincent Pelletier 			return -EINVAL;
21397f7c548cSVincent Pelletier 		}
214000a2430fSAndrzej Pietrasiewicz 
214100a2430fSAndrzej Pietrasiewicz 	case USB_DT_OTG:
214200a2430fSAndrzej Pietrasiewicz 		if (length != sizeof(struct usb_otg_descriptor))
214300a2430fSAndrzej Pietrasiewicz 			goto inv_length;
214400a2430fSAndrzej Pietrasiewicz 		break;
214500a2430fSAndrzej Pietrasiewicz 
214600a2430fSAndrzej Pietrasiewicz 	case USB_DT_INTERFACE_ASSOCIATION: {
214700a2430fSAndrzej Pietrasiewicz 		struct usb_interface_assoc_descriptor *ds = (void *)_ds;
214800a2430fSAndrzej Pietrasiewicz 		pr_vdebug("interface association descriptor\n");
214900a2430fSAndrzej Pietrasiewicz 		if (length != sizeof *ds)
215000a2430fSAndrzej Pietrasiewicz 			goto inv_length;
215100a2430fSAndrzej Pietrasiewicz 		if (ds->iFunction)
215200a2430fSAndrzej Pietrasiewicz 			__entity(STRING, ds->iFunction);
215300a2430fSAndrzej Pietrasiewicz 	}
215400a2430fSAndrzej Pietrasiewicz 		break;
215500a2430fSAndrzej Pietrasiewicz 
215600a2430fSAndrzej Pietrasiewicz 	case USB_DT_SS_ENDPOINT_COMP:
215700a2430fSAndrzej Pietrasiewicz 		pr_vdebug("EP SS companion descriptor\n");
215800a2430fSAndrzej Pietrasiewicz 		if (length != sizeof(struct usb_ss_ep_comp_descriptor))
215900a2430fSAndrzej Pietrasiewicz 			goto inv_length;
216000a2430fSAndrzej Pietrasiewicz 		break;
216100a2430fSAndrzej Pietrasiewicz 
216200a2430fSAndrzej Pietrasiewicz 	case USB_DT_OTHER_SPEED_CONFIG:
216300a2430fSAndrzej Pietrasiewicz 	case USB_DT_INTERFACE_POWER:
216400a2430fSAndrzej Pietrasiewicz 	case USB_DT_DEBUG:
216500a2430fSAndrzej Pietrasiewicz 	case USB_DT_SECURITY:
216600a2430fSAndrzej Pietrasiewicz 	case USB_DT_CS_RADIO_CONTROL:
216700a2430fSAndrzej Pietrasiewicz 		/* TODO */
216800a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
216900a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
217000a2430fSAndrzej Pietrasiewicz 
217100a2430fSAndrzej Pietrasiewicz 	default:
217200a2430fSAndrzej Pietrasiewicz 		/* We should never be here */
217300a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
217400a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
217500a2430fSAndrzej Pietrasiewicz 
217600a2430fSAndrzej Pietrasiewicz inv_length:
217700a2430fSAndrzej Pietrasiewicz 		pr_vdebug("invalid length: %d (descriptor %d)\n",
217800a2430fSAndrzej Pietrasiewicz 			  _ds->bLength, _ds->bDescriptorType);
217900a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
218000a2430fSAndrzej Pietrasiewicz 	}
218100a2430fSAndrzej Pietrasiewicz 
218200a2430fSAndrzej Pietrasiewicz #undef __entity
218300a2430fSAndrzej Pietrasiewicz #undef __entity_check_DESCRIPTOR
218400a2430fSAndrzej Pietrasiewicz #undef __entity_check_INTERFACE
218500a2430fSAndrzej Pietrasiewicz #undef __entity_check_STRING
218600a2430fSAndrzej Pietrasiewicz #undef __entity_check_ENDPOINT
218700a2430fSAndrzej Pietrasiewicz 
218800a2430fSAndrzej Pietrasiewicz 	return length;
218900a2430fSAndrzej Pietrasiewicz }
219000a2430fSAndrzej Pietrasiewicz 
219100a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
219200a2430fSAndrzej Pietrasiewicz 				     ffs_entity_callback entity, void *priv)
219300a2430fSAndrzej Pietrasiewicz {
219400a2430fSAndrzej Pietrasiewicz 	const unsigned _len = len;
219500a2430fSAndrzej Pietrasiewicz 	unsigned long num = 0;
21967f7c548cSVincent Pelletier 	int current_class = -1;
219700a2430fSAndrzej Pietrasiewicz 
219800a2430fSAndrzej Pietrasiewicz 	ENTER();
219900a2430fSAndrzej Pietrasiewicz 
220000a2430fSAndrzej Pietrasiewicz 	for (;;) {
220100a2430fSAndrzej Pietrasiewicz 		int ret;
220200a2430fSAndrzej Pietrasiewicz 
220300a2430fSAndrzej Pietrasiewicz 		if (num == count)
220400a2430fSAndrzej Pietrasiewicz 			data = NULL;
220500a2430fSAndrzej Pietrasiewicz 
220600a2430fSAndrzej Pietrasiewicz 		/* Record "descriptor" entity */
220700a2430fSAndrzej Pietrasiewicz 		ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
22088704fd73SGreg Kroah-Hartman 		if (ret < 0) {
220900a2430fSAndrzej Pietrasiewicz 			pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
221000a2430fSAndrzej Pietrasiewicz 				 num, ret);
221100a2430fSAndrzej Pietrasiewicz 			return ret;
221200a2430fSAndrzej Pietrasiewicz 		}
221300a2430fSAndrzej Pietrasiewicz 
221400a2430fSAndrzej Pietrasiewicz 		if (!data)
221500a2430fSAndrzej Pietrasiewicz 			return _len - len;
221600a2430fSAndrzej Pietrasiewicz 
22177f7c548cSVincent Pelletier 		ret = ffs_do_single_desc(data, len, entity, priv,
22187f7c548cSVincent Pelletier 			&current_class);
22198704fd73SGreg Kroah-Hartman 		if (ret < 0) {
222000a2430fSAndrzej Pietrasiewicz 			pr_debug("%s returns %d\n", __func__, ret);
222100a2430fSAndrzej Pietrasiewicz 			return ret;
222200a2430fSAndrzej Pietrasiewicz 		}
222300a2430fSAndrzej Pietrasiewicz 
222400a2430fSAndrzej Pietrasiewicz 		len -= ret;
222500a2430fSAndrzej Pietrasiewicz 		data += ret;
222600a2430fSAndrzej Pietrasiewicz 		++num;
222700a2430fSAndrzej Pietrasiewicz 	}
222800a2430fSAndrzej Pietrasiewicz }
222900a2430fSAndrzej Pietrasiewicz 
223000a2430fSAndrzej Pietrasiewicz static int __ffs_data_do_entity(enum ffs_entity_type type,
223100a2430fSAndrzej Pietrasiewicz 				u8 *valuep, struct usb_descriptor_header *desc,
223200a2430fSAndrzej Pietrasiewicz 				void *priv)
223300a2430fSAndrzej Pietrasiewicz {
22346d5c1c77SRobert Baldyga 	struct ffs_desc_helper *helper = priv;
22356d5c1c77SRobert Baldyga 	struct usb_endpoint_descriptor *d;
223600a2430fSAndrzej Pietrasiewicz 
223700a2430fSAndrzej Pietrasiewicz 	ENTER();
223800a2430fSAndrzej Pietrasiewicz 
223900a2430fSAndrzej Pietrasiewicz 	switch (type) {
224000a2430fSAndrzej Pietrasiewicz 	case FFS_DESCRIPTOR:
224100a2430fSAndrzej Pietrasiewicz 		break;
224200a2430fSAndrzej Pietrasiewicz 
224300a2430fSAndrzej Pietrasiewicz 	case FFS_INTERFACE:
224400a2430fSAndrzej Pietrasiewicz 		/*
224500a2430fSAndrzej Pietrasiewicz 		 * Interfaces are indexed from zero so if we
224600a2430fSAndrzej Pietrasiewicz 		 * encountered interface "n" then there are at least
224700a2430fSAndrzej Pietrasiewicz 		 * "n+1" interfaces.
224800a2430fSAndrzej Pietrasiewicz 		 */
22496d5c1c77SRobert Baldyga 		if (*valuep >= helper->interfaces_count)
22506d5c1c77SRobert Baldyga 			helper->interfaces_count = *valuep + 1;
225100a2430fSAndrzej Pietrasiewicz 		break;
225200a2430fSAndrzej Pietrasiewicz 
225300a2430fSAndrzej Pietrasiewicz 	case FFS_STRING:
225400a2430fSAndrzej Pietrasiewicz 		/*
225596a420d2SVincent Pelletier 		 * Strings are indexed from 1 (0 is reserved
225696a420d2SVincent Pelletier 		 * for languages list)
225700a2430fSAndrzej Pietrasiewicz 		 */
22586d5c1c77SRobert Baldyga 		if (*valuep > helper->ffs->strings_count)
22596d5c1c77SRobert Baldyga 			helper->ffs->strings_count = *valuep;
226000a2430fSAndrzej Pietrasiewicz 		break;
226100a2430fSAndrzej Pietrasiewicz 
226200a2430fSAndrzej Pietrasiewicz 	case FFS_ENDPOINT:
22636d5c1c77SRobert Baldyga 		d = (void *)desc;
22646d5c1c77SRobert Baldyga 		helper->eps_count++;
226541dc9ac1SVincent Pelletier 		if (helper->eps_count >= FFS_MAX_EPS_COUNT)
22666d5c1c77SRobert Baldyga 			return -EINVAL;
22676d5c1c77SRobert Baldyga 		/* Check if descriptors for any speed were already parsed */
22686d5c1c77SRobert Baldyga 		if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
22696d5c1c77SRobert Baldyga 			helper->ffs->eps_addrmap[helper->eps_count] =
22706d5c1c77SRobert Baldyga 				d->bEndpointAddress;
22716d5c1c77SRobert Baldyga 		else if (helper->ffs->eps_addrmap[helper->eps_count] !=
22726d5c1c77SRobert Baldyga 				d->bEndpointAddress)
22736d5c1c77SRobert Baldyga 			return -EINVAL;
227400a2430fSAndrzej Pietrasiewicz 		break;
227500a2430fSAndrzej Pietrasiewicz 	}
227600a2430fSAndrzej Pietrasiewicz 
227700a2430fSAndrzej Pietrasiewicz 	return 0;
227800a2430fSAndrzej Pietrasiewicz }
227900a2430fSAndrzej Pietrasiewicz 
228000a2430fSAndrzej Pietrasiewicz static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
228100a2430fSAndrzej Pietrasiewicz 				   struct usb_os_desc_header *desc)
228200a2430fSAndrzej Pietrasiewicz {
228300a2430fSAndrzej Pietrasiewicz 	u16 bcd_version = le16_to_cpu(desc->bcdVersion);
228400a2430fSAndrzej Pietrasiewicz 	u16 w_index = le16_to_cpu(desc->wIndex);
228500a2430fSAndrzej Pietrasiewicz 
228600a2430fSAndrzej Pietrasiewicz 	if (bcd_version != 1) {
228700a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unsupported os descriptors version: %d",
228800a2430fSAndrzej Pietrasiewicz 			  bcd_version);
228900a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
229000a2430fSAndrzej Pietrasiewicz 	}
229100a2430fSAndrzej Pietrasiewicz 	switch (w_index) {
229200a2430fSAndrzej Pietrasiewicz 	case 0x4:
229300a2430fSAndrzej Pietrasiewicz 		*next_type = FFS_OS_DESC_EXT_COMPAT;
229400a2430fSAndrzej Pietrasiewicz 		break;
229500a2430fSAndrzej Pietrasiewicz 	case 0x5:
229600a2430fSAndrzej Pietrasiewicz 		*next_type = FFS_OS_DESC_EXT_PROP;
229700a2430fSAndrzej Pietrasiewicz 		break;
229800a2430fSAndrzej Pietrasiewicz 	default:
229900a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unsupported os descriptor type: %d", w_index);
230000a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
230100a2430fSAndrzej Pietrasiewicz 	}
230200a2430fSAndrzej Pietrasiewicz 
230300a2430fSAndrzej Pietrasiewicz 	return sizeof(*desc);
230400a2430fSAndrzej Pietrasiewicz }
230500a2430fSAndrzej Pietrasiewicz 
230600a2430fSAndrzej Pietrasiewicz /*
230700a2430fSAndrzej Pietrasiewicz  * Process all extended compatibility/extended property descriptors
230800a2430fSAndrzej Pietrasiewicz  * of a feature descriptor
230900a2430fSAndrzej Pietrasiewicz  */
231000a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
231100a2430fSAndrzej Pietrasiewicz 					      enum ffs_os_desc_type type,
231200a2430fSAndrzej Pietrasiewicz 					      u16 feature_count,
231300a2430fSAndrzej Pietrasiewicz 					      ffs_os_desc_callback entity,
231400a2430fSAndrzej Pietrasiewicz 					      void *priv,
231500a2430fSAndrzej Pietrasiewicz 					      struct usb_os_desc_header *h)
231600a2430fSAndrzej Pietrasiewicz {
231700a2430fSAndrzej Pietrasiewicz 	int ret;
231800a2430fSAndrzej Pietrasiewicz 	const unsigned _len = len;
231900a2430fSAndrzej Pietrasiewicz 
232000a2430fSAndrzej Pietrasiewicz 	ENTER();
232100a2430fSAndrzej Pietrasiewicz 
232200a2430fSAndrzej Pietrasiewicz 	/* loop over all ext compat/ext prop descriptors */
232300a2430fSAndrzej Pietrasiewicz 	while (feature_count--) {
232400a2430fSAndrzej Pietrasiewicz 		ret = entity(type, h, data, len, priv);
23258704fd73SGreg Kroah-Hartman 		if (ret < 0) {
232600a2430fSAndrzej Pietrasiewicz 			pr_debug("bad OS descriptor, type: %d\n", type);
232700a2430fSAndrzej Pietrasiewicz 			return ret;
232800a2430fSAndrzej Pietrasiewicz 		}
232900a2430fSAndrzej Pietrasiewicz 		data += ret;
233000a2430fSAndrzej Pietrasiewicz 		len -= ret;
233100a2430fSAndrzej Pietrasiewicz 	}
233200a2430fSAndrzej Pietrasiewicz 	return _len - len;
233300a2430fSAndrzej Pietrasiewicz }
233400a2430fSAndrzej Pietrasiewicz 
233500a2430fSAndrzej Pietrasiewicz /* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */
233600a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_os_descs(unsigned count,
233700a2430fSAndrzej Pietrasiewicz 					char *data, unsigned len,
233800a2430fSAndrzej Pietrasiewicz 					ffs_os_desc_callback entity, void *priv)
233900a2430fSAndrzej Pietrasiewicz {
234000a2430fSAndrzej Pietrasiewicz 	const unsigned _len = len;
234100a2430fSAndrzej Pietrasiewicz 	unsigned long num = 0;
234200a2430fSAndrzej Pietrasiewicz 
234300a2430fSAndrzej Pietrasiewicz 	ENTER();
234400a2430fSAndrzej Pietrasiewicz 
234500a2430fSAndrzej Pietrasiewicz 	for (num = 0; num < count; ++num) {
234600a2430fSAndrzej Pietrasiewicz 		int ret;
234700a2430fSAndrzej Pietrasiewicz 		enum ffs_os_desc_type type;
234800a2430fSAndrzej Pietrasiewicz 		u16 feature_count;
234900a2430fSAndrzej Pietrasiewicz 		struct usb_os_desc_header *desc = (void *)data;
235000a2430fSAndrzej Pietrasiewicz 
235100a2430fSAndrzej Pietrasiewicz 		if (len < sizeof(*desc))
235200a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
235300a2430fSAndrzej Pietrasiewicz 
235400a2430fSAndrzej Pietrasiewicz 		/*
235500a2430fSAndrzej Pietrasiewicz 		 * Record "descriptor" entity.
235600a2430fSAndrzej Pietrasiewicz 		 * Process dwLength, bcdVersion, wIndex, get b/wCount.
235700a2430fSAndrzej Pietrasiewicz 		 * Move the data pointer to the beginning of extended
235800a2430fSAndrzej Pietrasiewicz 		 * compatibilities proper or extended properties proper
235900a2430fSAndrzej Pietrasiewicz 		 * portions of the data
236000a2430fSAndrzej Pietrasiewicz 		 */
236100a2430fSAndrzej Pietrasiewicz 		if (le32_to_cpu(desc->dwLength) > len)
236200a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
236300a2430fSAndrzej Pietrasiewicz 
236400a2430fSAndrzej Pietrasiewicz 		ret = __ffs_do_os_desc_header(&type, desc);
23658704fd73SGreg Kroah-Hartman 		if (ret < 0) {
236600a2430fSAndrzej Pietrasiewicz 			pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
236700a2430fSAndrzej Pietrasiewicz 				 num, ret);
236800a2430fSAndrzej Pietrasiewicz 			return ret;
236900a2430fSAndrzej Pietrasiewicz 		}
237000a2430fSAndrzej Pietrasiewicz 		/*
237100a2430fSAndrzej Pietrasiewicz 		 * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??"
237200a2430fSAndrzej Pietrasiewicz 		 */
237300a2430fSAndrzej Pietrasiewicz 		feature_count = le16_to_cpu(desc->wCount);
237400a2430fSAndrzej Pietrasiewicz 		if (type == FFS_OS_DESC_EXT_COMPAT &&
237500a2430fSAndrzej Pietrasiewicz 		    (feature_count > 255 || desc->Reserved))
237600a2430fSAndrzej Pietrasiewicz 				return -EINVAL;
237700a2430fSAndrzej Pietrasiewicz 		len -= ret;
237800a2430fSAndrzej Pietrasiewicz 		data += ret;
237900a2430fSAndrzej Pietrasiewicz 
238000a2430fSAndrzej Pietrasiewicz 		/*
238100a2430fSAndrzej Pietrasiewicz 		 * Process all function/property descriptors
238200a2430fSAndrzej Pietrasiewicz 		 * of this Feature Descriptor
238300a2430fSAndrzej Pietrasiewicz 		 */
238400a2430fSAndrzej Pietrasiewicz 		ret = ffs_do_single_os_desc(data, len, type,
238500a2430fSAndrzej Pietrasiewicz 					    feature_count, entity, priv, desc);
23868704fd73SGreg Kroah-Hartman 		if (ret < 0) {
238700a2430fSAndrzej Pietrasiewicz 			pr_debug("%s returns %d\n", __func__, ret);
238800a2430fSAndrzej Pietrasiewicz 			return ret;
238900a2430fSAndrzej Pietrasiewicz 		}
239000a2430fSAndrzej Pietrasiewicz 
239100a2430fSAndrzej Pietrasiewicz 		len -= ret;
239200a2430fSAndrzej Pietrasiewicz 		data += ret;
239300a2430fSAndrzej Pietrasiewicz 	}
239400a2430fSAndrzej Pietrasiewicz 	return _len - len;
239500a2430fSAndrzej Pietrasiewicz }
239600a2430fSAndrzej Pietrasiewicz 
23978f9a0e10SLee Jones /*
239800a2430fSAndrzej Pietrasiewicz  * Validate contents of the buffer from userspace related to OS descriptors.
239900a2430fSAndrzej Pietrasiewicz  */
240000a2430fSAndrzej Pietrasiewicz static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
240100a2430fSAndrzej Pietrasiewicz 				 struct usb_os_desc_header *h, void *data,
240200a2430fSAndrzej Pietrasiewicz 				 unsigned len, void *priv)
240300a2430fSAndrzej Pietrasiewicz {
240400a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = priv;
240500a2430fSAndrzej Pietrasiewicz 	u8 length;
240600a2430fSAndrzej Pietrasiewicz 
240700a2430fSAndrzej Pietrasiewicz 	ENTER();
240800a2430fSAndrzej Pietrasiewicz 
240900a2430fSAndrzej Pietrasiewicz 	switch (type) {
241000a2430fSAndrzej Pietrasiewicz 	case FFS_OS_DESC_EXT_COMPAT: {
241100a2430fSAndrzej Pietrasiewicz 		struct usb_ext_compat_desc *d = data;
241200a2430fSAndrzej Pietrasiewicz 		int i;
241300a2430fSAndrzej Pietrasiewicz 
241400a2430fSAndrzej Pietrasiewicz 		if (len < sizeof(*d) ||
2415a3acc696SJohn Keeping 		    d->bFirstInterfaceNumber >= ffs->interfaces_count)
241600a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
2417a3acc696SJohn Keeping 		if (d->Reserved1 != 1) {
2418a3acc696SJohn Keeping 			/*
2419a3acc696SJohn Keeping 			 * According to the spec, Reserved1 must be set to 1
2420a3acc696SJohn Keeping 			 * but older kernels incorrectly rejected non-zero
2421a3acc696SJohn Keeping 			 * values.  We fix it here to avoid returning EINVAL
2422a3acc696SJohn Keeping 			 * in response to values we used to accept.
2423a3acc696SJohn Keeping 			 */
2424a3acc696SJohn Keeping 			pr_debug("usb_ext_compat_desc::Reserved1 forced to 1\n");
2425a3acc696SJohn Keeping 			d->Reserved1 = 1;
2426a3acc696SJohn Keeping 		}
242700a2430fSAndrzej Pietrasiewicz 		for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
242800a2430fSAndrzej Pietrasiewicz 			if (d->Reserved2[i])
242900a2430fSAndrzej Pietrasiewicz 				return -EINVAL;
243000a2430fSAndrzej Pietrasiewicz 
243100a2430fSAndrzej Pietrasiewicz 		length = sizeof(struct usb_ext_compat_desc);
243200a2430fSAndrzej Pietrasiewicz 	}
243300a2430fSAndrzej Pietrasiewicz 		break;
243400a2430fSAndrzej Pietrasiewicz 	case FFS_OS_DESC_EXT_PROP: {
243500a2430fSAndrzej Pietrasiewicz 		struct usb_ext_prop_desc *d = data;
243600a2430fSAndrzej Pietrasiewicz 		u32 type, pdl;
243700a2430fSAndrzej Pietrasiewicz 		u16 pnl;
243800a2430fSAndrzej Pietrasiewicz 
243900a2430fSAndrzej Pietrasiewicz 		if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
244000a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
244100a2430fSAndrzej Pietrasiewicz 		length = le32_to_cpu(d->dwSize);
244283e526f2SVincent Pelletier 		if (len < length)
244383e526f2SVincent Pelletier 			return -EINVAL;
244400a2430fSAndrzej Pietrasiewicz 		type = le32_to_cpu(d->dwPropertyDataType);
244500a2430fSAndrzej Pietrasiewicz 		if (type < USB_EXT_PROP_UNICODE ||
244600a2430fSAndrzej Pietrasiewicz 		    type > USB_EXT_PROP_UNICODE_MULTI) {
244700a2430fSAndrzej Pietrasiewicz 			pr_vdebug("unsupported os descriptor property type: %d",
244800a2430fSAndrzej Pietrasiewicz 				  type);
244900a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
245000a2430fSAndrzej Pietrasiewicz 		}
245100a2430fSAndrzej Pietrasiewicz 		pnl = le16_to_cpu(d->wPropertyNameLength);
245283e526f2SVincent Pelletier 		if (length < 14 + pnl) {
245383e526f2SVincent Pelletier 			pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n",
245483e526f2SVincent Pelletier 				  length, pnl, type);
245583e526f2SVincent Pelletier 			return -EINVAL;
245683e526f2SVincent Pelletier 		}
2457c40619bbSVincent Pelletier 		pdl = le32_to_cpu(*(__le32 *)((u8 *)data + 10 + pnl));
245800a2430fSAndrzej Pietrasiewicz 		if (length != 14 + pnl + pdl) {
245900a2430fSAndrzej Pietrasiewicz 			pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
246000a2430fSAndrzej Pietrasiewicz 				  length, pnl, pdl, type);
246100a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
246200a2430fSAndrzej Pietrasiewicz 		}
246300a2430fSAndrzej Pietrasiewicz 		++ffs->ms_os_descs_ext_prop_count;
246400a2430fSAndrzej Pietrasiewicz 		/* property name reported to the host as "WCHAR"s */
246500a2430fSAndrzej Pietrasiewicz 		ffs->ms_os_descs_ext_prop_name_len += pnl * 2;
246600a2430fSAndrzej Pietrasiewicz 		ffs->ms_os_descs_ext_prop_data_len += pdl;
246700a2430fSAndrzej Pietrasiewicz 	}
246800a2430fSAndrzej Pietrasiewicz 		break;
246900a2430fSAndrzej Pietrasiewicz 	default:
247000a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unknown descriptor: %d\n", type);
247100a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
247200a2430fSAndrzej Pietrasiewicz 	}
247300a2430fSAndrzej Pietrasiewicz 	return length;
247400a2430fSAndrzej Pietrasiewicz }
247500a2430fSAndrzej Pietrasiewicz 
247600a2430fSAndrzej Pietrasiewicz static int __ffs_data_got_descs(struct ffs_data *ffs,
247700a2430fSAndrzej Pietrasiewicz 				char *const _data, size_t len)
247800a2430fSAndrzej Pietrasiewicz {
247900a2430fSAndrzej Pietrasiewicz 	char *data = _data, *raw_descs;
248000a2430fSAndrzej Pietrasiewicz 	unsigned os_descs_count = 0, counts[3], flags;
248100a2430fSAndrzej Pietrasiewicz 	int ret = -EINVAL, i;
24826d5c1c77SRobert Baldyga 	struct ffs_desc_helper helper;
248300a2430fSAndrzej Pietrasiewicz 
248400a2430fSAndrzej Pietrasiewicz 	ENTER();
248500a2430fSAndrzej Pietrasiewicz 
248600a2430fSAndrzej Pietrasiewicz 	if (get_unaligned_le32(data + 4) != len)
248700a2430fSAndrzej Pietrasiewicz 		goto error;
248800a2430fSAndrzej Pietrasiewicz 
248900a2430fSAndrzej Pietrasiewicz 	switch (get_unaligned_le32(data)) {
249000a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_DESCRIPTORS_MAGIC:
249100a2430fSAndrzej Pietrasiewicz 		flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
249200a2430fSAndrzej Pietrasiewicz 		data += 8;
249300a2430fSAndrzej Pietrasiewicz 		len  -= 8;
249400a2430fSAndrzej Pietrasiewicz 		break;
249500a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_DESCRIPTORS_MAGIC_V2:
249600a2430fSAndrzej Pietrasiewicz 		flags = get_unaligned_le32(data + 8);
24971b0bf88fSRobert Baldyga 		ffs->user_flags = flags;
249800a2430fSAndrzej Pietrasiewicz 		if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
249900a2430fSAndrzej Pietrasiewicz 			      FUNCTIONFS_HAS_HS_DESC |
250000a2430fSAndrzej Pietrasiewicz 			      FUNCTIONFS_HAS_SS_DESC |
25011b0bf88fSRobert Baldyga 			      FUNCTIONFS_HAS_MS_OS_DESC |
25025e33f6fdSRobert Baldyga 			      FUNCTIONFS_VIRTUAL_ADDR |
250354dfce6dSFelix Hädicke 			      FUNCTIONFS_EVENTFD |
25044368c28aSFelix Hädicke 			      FUNCTIONFS_ALL_CTRL_RECIP |
25054368c28aSFelix Hädicke 			      FUNCTIONFS_CONFIG0_SETUP)) {
250600a2430fSAndrzej Pietrasiewicz 			ret = -ENOSYS;
250700a2430fSAndrzej Pietrasiewicz 			goto error;
250800a2430fSAndrzej Pietrasiewicz 		}
250900a2430fSAndrzej Pietrasiewicz 		data += 12;
251000a2430fSAndrzej Pietrasiewicz 		len  -= 12;
251100a2430fSAndrzej Pietrasiewicz 		break;
251200a2430fSAndrzej Pietrasiewicz 	default:
251300a2430fSAndrzej Pietrasiewicz 		goto error;
251400a2430fSAndrzej Pietrasiewicz 	}
251500a2430fSAndrzej Pietrasiewicz 
25165e33f6fdSRobert Baldyga 	if (flags & FUNCTIONFS_EVENTFD) {
25175e33f6fdSRobert Baldyga 		if (len < 4)
25185e33f6fdSRobert Baldyga 			goto error;
25195e33f6fdSRobert Baldyga 		ffs->ffs_eventfd =
25205e33f6fdSRobert Baldyga 			eventfd_ctx_fdget((int)get_unaligned_le32(data));
25215e33f6fdSRobert Baldyga 		if (IS_ERR(ffs->ffs_eventfd)) {
25225e33f6fdSRobert Baldyga 			ret = PTR_ERR(ffs->ffs_eventfd);
25235e33f6fdSRobert Baldyga 			ffs->ffs_eventfd = NULL;
25245e33f6fdSRobert Baldyga 			goto error;
25255e33f6fdSRobert Baldyga 		}
25265e33f6fdSRobert Baldyga 		data += 4;
25275e33f6fdSRobert Baldyga 		len  -= 4;
25285e33f6fdSRobert Baldyga 	}
25295e33f6fdSRobert Baldyga 
253000a2430fSAndrzej Pietrasiewicz 	/* Read fs_count, hs_count and ss_count (if present) */
253100a2430fSAndrzej Pietrasiewicz 	for (i = 0; i < 3; ++i) {
253200a2430fSAndrzej Pietrasiewicz 		if (!(flags & (1 << i))) {
253300a2430fSAndrzej Pietrasiewicz 			counts[i] = 0;
253400a2430fSAndrzej Pietrasiewicz 		} else if (len < 4) {
253500a2430fSAndrzej Pietrasiewicz 			goto error;
253600a2430fSAndrzej Pietrasiewicz 		} else {
253700a2430fSAndrzej Pietrasiewicz 			counts[i] = get_unaligned_le32(data);
253800a2430fSAndrzej Pietrasiewicz 			data += 4;
253900a2430fSAndrzej Pietrasiewicz 			len  -= 4;
254000a2430fSAndrzej Pietrasiewicz 		}
254100a2430fSAndrzej Pietrasiewicz 	}
254200a2430fSAndrzej Pietrasiewicz 	if (flags & (1 << i)) {
254383e526f2SVincent Pelletier 		if (len < 4) {
254483e526f2SVincent Pelletier 			goto error;
254583e526f2SVincent Pelletier 		}
254600a2430fSAndrzej Pietrasiewicz 		os_descs_count = get_unaligned_le32(data);
254700a2430fSAndrzej Pietrasiewicz 		data += 4;
254800a2430fSAndrzej Pietrasiewicz 		len -= 4;
2549a54177d2SJason Yan 	}
255000a2430fSAndrzej Pietrasiewicz 
255100a2430fSAndrzej Pietrasiewicz 	/* Read descriptors */
255200a2430fSAndrzej Pietrasiewicz 	raw_descs = data;
25536d5c1c77SRobert Baldyga 	helper.ffs = ffs;
255400a2430fSAndrzej Pietrasiewicz 	for (i = 0; i < 3; ++i) {
255500a2430fSAndrzej Pietrasiewicz 		if (!counts[i])
255600a2430fSAndrzej Pietrasiewicz 			continue;
25576d5c1c77SRobert Baldyga 		helper.interfaces_count = 0;
25586d5c1c77SRobert Baldyga 		helper.eps_count = 0;
255900a2430fSAndrzej Pietrasiewicz 		ret = ffs_do_descs(counts[i], data, len,
25606d5c1c77SRobert Baldyga 				   __ffs_data_do_entity, &helper);
256100a2430fSAndrzej Pietrasiewicz 		if (ret < 0)
256200a2430fSAndrzej Pietrasiewicz 			goto error;
25636d5c1c77SRobert Baldyga 		if (!ffs->eps_count && !ffs->interfaces_count) {
25646d5c1c77SRobert Baldyga 			ffs->eps_count = helper.eps_count;
25656d5c1c77SRobert Baldyga 			ffs->interfaces_count = helper.interfaces_count;
25666d5c1c77SRobert Baldyga 		} else {
25676d5c1c77SRobert Baldyga 			if (ffs->eps_count != helper.eps_count) {
25686d5c1c77SRobert Baldyga 				ret = -EINVAL;
25696d5c1c77SRobert Baldyga 				goto error;
25706d5c1c77SRobert Baldyga 			}
25716d5c1c77SRobert Baldyga 			if (ffs->interfaces_count != helper.interfaces_count) {
25726d5c1c77SRobert Baldyga 				ret = -EINVAL;
25736d5c1c77SRobert Baldyga 				goto error;
25746d5c1c77SRobert Baldyga 			}
25756d5c1c77SRobert Baldyga 		}
257600a2430fSAndrzej Pietrasiewicz 		data += ret;
257700a2430fSAndrzej Pietrasiewicz 		len  -= ret;
257800a2430fSAndrzej Pietrasiewicz 	}
257900a2430fSAndrzej Pietrasiewicz 	if (os_descs_count) {
258000a2430fSAndrzej Pietrasiewicz 		ret = ffs_do_os_descs(os_descs_count, data, len,
258100a2430fSAndrzej Pietrasiewicz 				      __ffs_data_do_os_desc, ffs);
258200a2430fSAndrzej Pietrasiewicz 		if (ret < 0)
258300a2430fSAndrzej Pietrasiewicz 			goto error;
258400a2430fSAndrzej Pietrasiewicz 		data += ret;
258500a2430fSAndrzej Pietrasiewicz 		len -= ret;
258600a2430fSAndrzej Pietrasiewicz 	}
258700a2430fSAndrzej Pietrasiewicz 
258800a2430fSAndrzej Pietrasiewicz 	if (raw_descs == data || len) {
258900a2430fSAndrzej Pietrasiewicz 		ret = -EINVAL;
259000a2430fSAndrzej Pietrasiewicz 		goto error;
259100a2430fSAndrzej Pietrasiewicz 	}
259200a2430fSAndrzej Pietrasiewicz 
259300a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs_data	= _data;
259400a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs		= raw_descs;
259500a2430fSAndrzej Pietrasiewicz 	ffs->raw_descs_length	= data - raw_descs;
259600a2430fSAndrzej Pietrasiewicz 	ffs->fs_descs_count	= counts[0];
259700a2430fSAndrzej Pietrasiewicz 	ffs->hs_descs_count	= counts[1];
259800a2430fSAndrzej Pietrasiewicz 	ffs->ss_descs_count	= counts[2];
259900a2430fSAndrzej Pietrasiewicz 	ffs->ms_os_descs_count	= os_descs_count;
260000a2430fSAndrzej Pietrasiewicz 
260100a2430fSAndrzej Pietrasiewicz 	return 0;
260200a2430fSAndrzej Pietrasiewicz 
260300a2430fSAndrzej Pietrasiewicz error:
260400a2430fSAndrzej Pietrasiewicz 	kfree(_data);
260500a2430fSAndrzej Pietrasiewicz 	return ret;
260600a2430fSAndrzej Pietrasiewicz }
260700a2430fSAndrzej Pietrasiewicz 
260800a2430fSAndrzej Pietrasiewicz static int __ffs_data_got_strings(struct ffs_data *ffs,
260900a2430fSAndrzej Pietrasiewicz 				  char *const _data, size_t len)
261000a2430fSAndrzej Pietrasiewicz {
261100a2430fSAndrzej Pietrasiewicz 	u32 str_count, needed_count, lang_count;
261200a2430fSAndrzej Pietrasiewicz 	struct usb_gadget_strings **stringtabs, *t;
261300a2430fSAndrzej Pietrasiewicz 	const char *data = _data;
2614872ce511SMichal Nazarewicz 	struct usb_string *s;
261500a2430fSAndrzej Pietrasiewicz 
261600a2430fSAndrzej Pietrasiewicz 	ENTER();
261700a2430fSAndrzej Pietrasiewicz 
26188704fd73SGreg Kroah-Hartman 	if (len < 16 ||
261983e526f2SVincent Pelletier 	    get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
26208704fd73SGreg Kroah-Hartman 	    get_unaligned_le32(data + 4) != len)
262100a2430fSAndrzej Pietrasiewicz 		goto error;
262200a2430fSAndrzej Pietrasiewicz 	str_count  = get_unaligned_le32(data + 8);
262300a2430fSAndrzej Pietrasiewicz 	lang_count = get_unaligned_le32(data + 12);
262400a2430fSAndrzej Pietrasiewicz 
262500a2430fSAndrzej Pietrasiewicz 	/* if one is zero the other must be zero */
26268704fd73SGreg Kroah-Hartman 	if (!str_count != !lang_count)
262700a2430fSAndrzej Pietrasiewicz 		goto error;
262800a2430fSAndrzej Pietrasiewicz 
262900a2430fSAndrzej Pietrasiewicz 	/* Do we have at least as many strings as descriptors need? */
263000a2430fSAndrzej Pietrasiewicz 	needed_count = ffs->strings_count;
26318704fd73SGreg Kroah-Hartman 	if (str_count < needed_count)
263200a2430fSAndrzej Pietrasiewicz 		goto error;
263300a2430fSAndrzej Pietrasiewicz 
263400a2430fSAndrzej Pietrasiewicz 	/*
263500a2430fSAndrzej Pietrasiewicz 	 * If we don't need any strings just return and free all
263600a2430fSAndrzej Pietrasiewicz 	 * memory.
263700a2430fSAndrzej Pietrasiewicz 	 */
263800a2430fSAndrzej Pietrasiewicz 	if (!needed_count) {
263900a2430fSAndrzej Pietrasiewicz 		kfree(_data);
264000a2430fSAndrzej Pietrasiewicz 		return 0;
264100a2430fSAndrzej Pietrasiewicz 	}
264200a2430fSAndrzej Pietrasiewicz 
264300a2430fSAndrzej Pietrasiewicz 	/* Allocate everything in one chunk so there's less maintenance. */
264400a2430fSAndrzej Pietrasiewicz 	{
264500a2430fSAndrzej Pietrasiewicz 		unsigned i = 0;
264600a2430fSAndrzej Pietrasiewicz 		vla_group(d);
264700a2430fSAndrzej Pietrasiewicz 		vla_item(d, struct usb_gadget_strings *, stringtabs,
264800a2430fSAndrzej Pietrasiewicz 			lang_count + 1);
264900a2430fSAndrzej Pietrasiewicz 		vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
265000a2430fSAndrzej Pietrasiewicz 		vla_item(d, struct usb_string, strings,
265100a2430fSAndrzej Pietrasiewicz 			lang_count*(needed_count+1));
265200a2430fSAndrzej Pietrasiewicz 
265300a2430fSAndrzej Pietrasiewicz 		char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
265400a2430fSAndrzej Pietrasiewicz 
26558704fd73SGreg Kroah-Hartman 		if (!vlabuf) {
265600a2430fSAndrzej Pietrasiewicz 			kfree(_data);
265700a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
265800a2430fSAndrzej Pietrasiewicz 		}
265900a2430fSAndrzej Pietrasiewicz 
266000a2430fSAndrzej Pietrasiewicz 		/* Initialize the VLA pointers */
266100a2430fSAndrzej Pietrasiewicz 		stringtabs = vla_ptr(vlabuf, d, stringtabs);
266200a2430fSAndrzej Pietrasiewicz 		t = vla_ptr(vlabuf, d, stringtab);
266300a2430fSAndrzej Pietrasiewicz 		i = lang_count;
266400a2430fSAndrzej Pietrasiewicz 		do {
266500a2430fSAndrzej Pietrasiewicz 			*stringtabs++ = t++;
266600a2430fSAndrzej Pietrasiewicz 		} while (--i);
266700a2430fSAndrzej Pietrasiewicz 		*stringtabs = NULL;
266800a2430fSAndrzej Pietrasiewicz 
266900a2430fSAndrzej Pietrasiewicz 		/* stringtabs = vlabuf = d_stringtabs for later kfree */
267000a2430fSAndrzej Pietrasiewicz 		stringtabs = vla_ptr(vlabuf, d, stringtabs);
267100a2430fSAndrzej Pietrasiewicz 		t = vla_ptr(vlabuf, d, stringtab);
267200a2430fSAndrzej Pietrasiewicz 		s = vla_ptr(vlabuf, d, strings);
267300a2430fSAndrzej Pietrasiewicz 	}
267400a2430fSAndrzej Pietrasiewicz 
267500a2430fSAndrzej Pietrasiewicz 	/* For each language */
267600a2430fSAndrzej Pietrasiewicz 	data += 16;
267700a2430fSAndrzej Pietrasiewicz 	len -= 16;
267800a2430fSAndrzej Pietrasiewicz 
267900a2430fSAndrzej Pietrasiewicz 	do { /* lang_count > 0 so we can use do-while */
268000a2430fSAndrzej Pietrasiewicz 		unsigned needed = needed_count;
268155b74ce7SDean Anderson 		u32 str_per_lang = str_count;
268200a2430fSAndrzej Pietrasiewicz 
26838704fd73SGreg Kroah-Hartman 		if (len < 3)
268400a2430fSAndrzej Pietrasiewicz 			goto error_free;
268500a2430fSAndrzej Pietrasiewicz 		t->language = get_unaligned_le16(data);
268600a2430fSAndrzej Pietrasiewicz 		t->strings  = s;
268700a2430fSAndrzej Pietrasiewicz 		++t;
268800a2430fSAndrzej Pietrasiewicz 
268900a2430fSAndrzej Pietrasiewicz 		data += 2;
269000a2430fSAndrzej Pietrasiewicz 		len -= 2;
269100a2430fSAndrzej Pietrasiewicz 
269200a2430fSAndrzej Pietrasiewicz 		/* For each string */
269300a2430fSAndrzej Pietrasiewicz 		do { /* str_count > 0 so we can use do-while */
269400a2430fSAndrzej Pietrasiewicz 			size_t length = strnlen(data, len);
269500a2430fSAndrzej Pietrasiewicz 
26968704fd73SGreg Kroah-Hartman 			if (length == len)
269700a2430fSAndrzej Pietrasiewicz 				goto error_free;
269800a2430fSAndrzej Pietrasiewicz 
269900a2430fSAndrzej Pietrasiewicz 			/*
270000a2430fSAndrzej Pietrasiewicz 			 * User may provide more strings then we need,
270100a2430fSAndrzej Pietrasiewicz 			 * if that's the case we simply ignore the
270200a2430fSAndrzej Pietrasiewicz 			 * rest
270300a2430fSAndrzej Pietrasiewicz 			 */
27048704fd73SGreg Kroah-Hartman 			if (needed) {
270500a2430fSAndrzej Pietrasiewicz 				/*
270600a2430fSAndrzej Pietrasiewicz 				 * s->id will be set while adding
270700a2430fSAndrzej Pietrasiewicz 				 * function to configuration so for
270800a2430fSAndrzej Pietrasiewicz 				 * now just leave garbage here.
270900a2430fSAndrzej Pietrasiewicz 				 */
271000a2430fSAndrzej Pietrasiewicz 				s->s = data;
271100a2430fSAndrzej Pietrasiewicz 				--needed;
271200a2430fSAndrzej Pietrasiewicz 				++s;
271300a2430fSAndrzej Pietrasiewicz 			}
271400a2430fSAndrzej Pietrasiewicz 
271500a2430fSAndrzej Pietrasiewicz 			data += length + 1;
271600a2430fSAndrzej Pietrasiewicz 			len -= length + 1;
271755b74ce7SDean Anderson 		} while (--str_per_lang);
271800a2430fSAndrzej Pietrasiewicz 
271900a2430fSAndrzej Pietrasiewicz 		s->id = 0;   /* terminator */
272000a2430fSAndrzej Pietrasiewicz 		s->s = NULL;
272100a2430fSAndrzej Pietrasiewicz 		++s;
272200a2430fSAndrzej Pietrasiewicz 
272300a2430fSAndrzej Pietrasiewicz 	} while (--lang_count);
272400a2430fSAndrzej Pietrasiewicz 
272500a2430fSAndrzej Pietrasiewicz 	/* Some garbage left? */
27268704fd73SGreg Kroah-Hartman 	if (len)
272700a2430fSAndrzej Pietrasiewicz 		goto error_free;
272800a2430fSAndrzej Pietrasiewicz 
272900a2430fSAndrzej Pietrasiewicz 	/* Done! */
273000a2430fSAndrzej Pietrasiewicz 	ffs->stringtabs = stringtabs;
273100a2430fSAndrzej Pietrasiewicz 	ffs->raw_strings = _data;
273200a2430fSAndrzej Pietrasiewicz 
273300a2430fSAndrzej Pietrasiewicz 	return 0;
273400a2430fSAndrzej Pietrasiewicz 
273500a2430fSAndrzej Pietrasiewicz error_free:
273600a2430fSAndrzej Pietrasiewicz 	kfree(stringtabs);
273700a2430fSAndrzej Pietrasiewicz error:
273800a2430fSAndrzej Pietrasiewicz 	kfree(_data);
273900a2430fSAndrzej Pietrasiewicz 	return -EINVAL;
274000a2430fSAndrzej Pietrasiewicz }
274100a2430fSAndrzej Pietrasiewicz 
274200a2430fSAndrzej Pietrasiewicz 
274300a2430fSAndrzej Pietrasiewicz /* Events handling and management *******************************************/
274400a2430fSAndrzej Pietrasiewicz 
274500a2430fSAndrzej Pietrasiewicz static void __ffs_event_add(struct ffs_data *ffs,
274600a2430fSAndrzej Pietrasiewicz 			    enum usb_functionfs_event_type type)
274700a2430fSAndrzej Pietrasiewicz {
274800a2430fSAndrzej Pietrasiewicz 	enum usb_functionfs_event_type rem_type1, rem_type2 = type;
274900a2430fSAndrzej Pietrasiewicz 	int neg = 0;
275000a2430fSAndrzej Pietrasiewicz 
275100a2430fSAndrzej Pietrasiewicz 	/*
275200a2430fSAndrzej Pietrasiewicz 	 * Abort any unhandled setup
275300a2430fSAndrzej Pietrasiewicz 	 *
275400a2430fSAndrzej Pietrasiewicz 	 * We do not need to worry about some cmpxchg() changing value
275500a2430fSAndrzej Pietrasiewicz 	 * of ffs->setup_state without holding the lock because when
275600a2430fSAndrzej Pietrasiewicz 	 * state is FFS_SETUP_PENDING cmpxchg() in several places in
275700a2430fSAndrzej Pietrasiewicz 	 * the source does nothing.
275800a2430fSAndrzej Pietrasiewicz 	 */
275900a2430fSAndrzej Pietrasiewicz 	if (ffs->setup_state == FFS_SETUP_PENDING)
276000a2430fSAndrzej Pietrasiewicz 		ffs->setup_state = FFS_SETUP_CANCELLED;
276100a2430fSAndrzej Pietrasiewicz 
276267913bbdSMichal Nazarewicz 	/*
276367913bbdSMichal Nazarewicz 	 * Logic of this function guarantees that there are at most four pending
276467913bbdSMichal Nazarewicz 	 * evens on ffs->ev.types queue.  This is important because the queue
276567913bbdSMichal Nazarewicz 	 * has space for four elements only and __ffs_ep0_read_events function
276667913bbdSMichal Nazarewicz 	 * depends on that limit as well.  If more event types are added, those
276767913bbdSMichal Nazarewicz 	 * limits have to be revisited or guaranteed to still hold.
276867913bbdSMichal Nazarewicz 	 */
276900a2430fSAndrzej Pietrasiewicz 	switch (type) {
277000a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_RESUME:
277100a2430fSAndrzej Pietrasiewicz 		rem_type2 = FUNCTIONFS_SUSPEND;
2772a74005abSGustavo A. R. Silva 		fallthrough;
277300a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_SUSPEND:
277400a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_SETUP:
277500a2430fSAndrzej Pietrasiewicz 		rem_type1 = type;
277600a2430fSAndrzej Pietrasiewicz 		/* Discard all similar events */
277700a2430fSAndrzej Pietrasiewicz 		break;
277800a2430fSAndrzej Pietrasiewicz 
277900a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_BIND:
278000a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_UNBIND:
278100a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_DISABLE:
278200a2430fSAndrzej Pietrasiewicz 	case FUNCTIONFS_ENABLE:
278300a2430fSAndrzej Pietrasiewicz 		/* Discard everything other then power management. */
278400a2430fSAndrzej Pietrasiewicz 		rem_type1 = FUNCTIONFS_SUSPEND;
278500a2430fSAndrzej Pietrasiewicz 		rem_type2 = FUNCTIONFS_RESUME;
278600a2430fSAndrzej Pietrasiewicz 		neg = 1;
278700a2430fSAndrzej Pietrasiewicz 		break;
278800a2430fSAndrzej Pietrasiewicz 
278900a2430fSAndrzej Pietrasiewicz 	default:
2790fe00bcbfSMichal Nazarewicz 		WARN(1, "%d: unknown event, this should not happen\n", type);
2791fe00bcbfSMichal Nazarewicz 		return;
279200a2430fSAndrzej Pietrasiewicz 	}
279300a2430fSAndrzej Pietrasiewicz 
279400a2430fSAndrzej Pietrasiewicz 	{
279500a2430fSAndrzej Pietrasiewicz 		u8 *ev  = ffs->ev.types, *out = ev;
279600a2430fSAndrzej Pietrasiewicz 		unsigned n = ffs->ev.count;
279700a2430fSAndrzej Pietrasiewicz 		for (; n; --n, ++ev)
279800a2430fSAndrzej Pietrasiewicz 			if ((*ev == rem_type1 || *ev == rem_type2) == neg)
279900a2430fSAndrzej Pietrasiewicz 				*out++ = *ev;
280000a2430fSAndrzej Pietrasiewicz 			else
280100a2430fSAndrzej Pietrasiewicz 				pr_vdebug("purging event %d\n", *ev);
280200a2430fSAndrzej Pietrasiewicz 		ffs->ev.count = out - ffs->ev.types;
280300a2430fSAndrzej Pietrasiewicz 	}
280400a2430fSAndrzej Pietrasiewicz 
280500a2430fSAndrzej Pietrasiewicz 	pr_vdebug("adding event %d\n", type);
280600a2430fSAndrzej Pietrasiewicz 	ffs->ev.types[ffs->ev.count++] = type;
280700a2430fSAndrzej Pietrasiewicz 	wake_up_locked(&ffs->ev.waitq);
28085e33f6fdSRobert Baldyga 	if (ffs->ffs_eventfd)
28095e33f6fdSRobert Baldyga 		eventfd_signal(ffs->ffs_eventfd, 1);
281000a2430fSAndrzej Pietrasiewicz }
281100a2430fSAndrzej Pietrasiewicz 
281200a2430fSAndrzej Pietrasiewicz static void ffs_event_add(struct ffs_data *ffs,
281300a2430fSAndrzej Pietrasiewicz 			  enum usb_functionfs_event_type type)
281400a2430fSAndrzej Pietrasiewicz {
281500a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
281600a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
281700a2430fSAndrzej Pietrasiewicz 	__ffs_event_add(ffs, type);
281800a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
281900a2430fSAndrzej Pietrasiewicz }
282000a2430fSAndrzej Pietrasiewicz 
282100a2430fSAndrzej Pietrasiewicz /* Bind/unbind USB function hooks *******************************************/
282200a2430fSAndrzej Pietrasiewicz 
28236d5c1c77SRobert Baldyga static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
28246d5c1c77SRobert Baldyga {
28256d5c1c77SRobert Baldyga 	int i;
28266d5c1c77SRobert Baldyga 
28276d5c1c77SRobert Baldyga 	for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
28286d5c1c77SRobert Baldyga 		if (ffs->eps_addrmap[i] == endpoint_address)
28296d5c1c77SRobert Baldyga 			return i;
28306d5c1c77SRobert Baldyga 	return -ENOENT;
28316d5c1c77SRobert Baldyga }
28326d5c1c77SRobert Baldyga 
283300a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
283400a2430fSAndrzej Pietrasiewicz 				    struct usb_descriptor_header *desc,
283500a2430fSAndrzej Pietrasiewicz 				    void *priv)
283600a2430fSAndrzej Pietrasiewicz {
283700a2430fSAndrzej Pietrasiewicz 	struct usb_endpoint_descriptor *ds = (void *)desc;
283800a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = priv;
283900a2430fSAndrzej Pietrasiewicz 	struct ffs_ep *ffs_ep;
284085b06f5eSDan Carpenter 	unsigned ep_desc_id;
284185b06f5eSDan Carpenter 	int idx;
284200a2430fSAndrzej Pietrasiewicz 	static const char *speed_names[] = { "full", "high", "super" };
284300a2430fSAndrzej Pietrasiewicz 
284400a2430fSAndrzej Pietrasiewicz 	if (type != FFS_DESCRIPTOR)
284500a2430fSAndrzej Pietrasiewicz 		return 0;
284600a2430fSAndrzej Pietrasiewicz 
284700a2430fSAndrzej Pietrasiewicz 	/*
284800a2430fSAndrzej Pietrasiewicz 	 * If ss_descriptors is not NULL, we are reading super speed
284900a2430fSAndrzej Pietrasiewicz 	 * descriptors; if hs_descriptors is not NULL, we are reading high
285000a2430fSAndrzej Pietrasiewicz 	 * speed descriptors; otherwise, we are reading full speed
285100a2430fSAndrzej Pietrasiewicz 	 * descriptors.
285200a2430fSAndrzej Pietrasiewicz 	 */
285300a2430fSAndrzej Pietrasiewicz 	if (func->function.ss_descriptors) {
285400a2430fSAndrzej Pietrasiewicz 		ep_desc_id = 2;
285500a2430fSAndrzej Pietrasiewicz 		func->function.ss_descriptors[(long)valuep] = desc;
285600a2430fSAndrzej Pietrasiewicz 	} else if (func->function.hs_descriptors) {
285700a2430fSAndrzej Pietrasiewicz 		ep_desc_id = 1;
285800a2430fSAndrzej Pietrasiewicz 		func->function.hs_descriptors[(long)valuep] = desc;
285900a2430fSAndrzej Pietrasiewicz 	} else {
286000a2430fSAndrzej Pietrasiewicz 		ep_desc_id = 0;
286100a2430fSAndrzej Pietrasiewicz 		func->function.fs_descriptors[(long)valuep]    = desc;
286200a2430fSAndrzej Pietrasiewicz 	}
286300a2430fSAndrzej Pietrasiewicz 
286400a2430fSAndrzej Pietrasiewicz 	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
286500a2430fSAndrzej Pietrasiewicz 		return 0;
286600a2430fSAndrzej Pietrasiewicz 
28676d5c1c77SRobert Baldyga 	idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
28686d5c1c77SRobert Baldyga 	if (idx < 0)
28696d5c1c77SRobert Baldyga 		return idx;
28706d5c1c77SRobert Baldyga 
287100a2430fSAndrzej Pietrasiewicz 	ffs_ep = func->eps + idx;
287200a2430fSAndrzej Pietrasiewicz 
28738704fd73SGreg Kroah-Hartman 	if (ffs_ep->descs[ep_desc_id]) {
287400a2430fSAndrzej Pietrasiewicz 		pr_err("two %sspeed descriptors for EP %d\n",
287500a2430fSAndrzej Pietrasiewicz 			  speed_names[ep_desc_id],
287600a2430fSAndrzej Pietrasiewicz 			  ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
287700a2430fSAndrzej Pietrasiewicz 		return -EINVAL;
287800a2430fSAndrzej Pietrasiewicz 	}
287900a2430fSAndrzej Pietrasiewicz 	ffs_ep->descs[ep_desc_id] = ds;
288000a2430fSAndrzej Pietrasiewicz 
288100a2430fSAndrzej Pietrasiewicz 	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
288200a2430fSAndrzej Pietrasiewicz 	if (ffs_ep->ep) {
288300a2430fSAndrzej Pietrasiewicz 		ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
288400a2430fSAndrzej Pietrasiewicz 		if (!ds->wMaxPacketSize)
288500a2430fSAndrzej Pietrasiewicz 			ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
288600a2430fSAndrzej Pietrasiewicz 	} else {
288700a2430fSAndrzej Pietrasiewicz 		struct usb_request *req;
288800a2430fSAndrzej Pietrasiewicz 		struct usb_ep *ep;
28891b0bf88fSRobert Baldyga 		u8 bEndpointAddress;
2890bdcc03ceSAndrzej Pietrasiewicz 		u16 wMaxPacketSize;
289100a2430fSAndrzej Pietrasiewicz 
28921b0bf88fSRobert Baldyga 		/*
28931b0bf88fSRobert Baldyga 		 * We back up bEndpointAddress because autoconfig overwrites
28941b0bf88fSRobert Baldyga 		 * it with physical endpoint address.
28951b0bf88fSRobert Baldyga 		 */
28961b0bf88fSRobert Baldyga 		bEndpointAddress = ds->bEndpointAddress;
2897bdcc03ceSAndrzej Pietrasiewicz 		/*
2898bdcc03ceSAndrzej Pietrasiewicz 		 * We back up wMaxPacketSize because autoconfig treats
2899bdcc03ceSAndrzej Pietrasiewicz 		 * endpoint descriptors as if they were full speed.
2900bdcc03ceSAndrzej Pietrasiewicz 		 */
2901bdcc03ceSAndrzej Pietrasiewicz 		wMaxPacketSize = ds->wMaxPacketSize;
290200a2430fSAndrzej Pietrasiewicz 		pr_vdebug("autoconfig\n");
290300a2430fSAndrzej Pietrasiewicz 		ep = usb_ep_autoconfig(func->gadget, ds);
29048704fd73SGreg Kroah-Hartman 		if (!ep)
290500a2430fSAndrzej Pietrasiewicz 			return -ENOTSUPP;
290600a2430fSAndrzej Pietrasiewicz 		ep->driver_data = func->eps + idx;
290700a2430fSAndrzej Pietrasiewicz 
290800a2430fSAndrzej Pietrasiewicz 		req = usb_ep_alloc_request(ep, GFP_KERNEL);
29098704fd73SGreg Kroah-Hartman 		if (!req)
291000a2430fSAndrzej Pietrasiewicz 			return -ENOMEM;
291100a2430fSAndrzej Pietrasiewicz 
291200a2430fSAndrzej Pietrasiewicz 		ffs_ep->ep  = ep;
291300a2430fSAndrzej Pietrasiewicz 		ffs_ep->req = req;
291400a2430fSAndrzej Pietrasiewicz 		func->eps_revmap[ds->bEndpointAddress &
291500a2430fSAndrzej Pietrasiewicz 				 USB_ENDPOINT_NUMBER_MASK] = idx + 1;
29161b0bf88fSRobert Baldyga 		/*
29171b0bf88fSRobert Baldyga 		 * If we use virtual address mapping, we restore
29181b0bf88fSRobert Baldyga 		 * original bEndpointAddress value.
29191b0bf88fSRobert Baldyga 		 */
29201b0bf88fSRobert Baldyga 		if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
29211b0bf88fSRobert Baldyga 			ds->bEndpointAddress = bEndpointAddress;
2922bdcc03ceSAndrzej Pietrasiewicz 		/*
2923bdcc03ceSAndrzej Pietrasiewicz 		 * Restore wMaxPacketSize which was potentially
2924bdcc03ceSAndrzej Pietrasiewicz 		 * overwritten by autoconfig.
2925bdcc03ceSAndrzej Pietrasiewicz 		 */
2926bdcc03ceSAndrzej Pietrasiewicz 		ds->wMaxPacketSize = wMaxPacketSize;
292700a2430fSAndrzej Pietrasiewicz 	}
292800a2430fSAndrzej Pietrasiewicz 	ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
292900a2430fSAndrzej Pietrasiewicz 
293000a2430fSAndrzej Pietrasiewicz 	return 0;
293100a2430fSAndrzej Pietrasiewicz }
293200a2430fSAndrzej Pietrasiewicz 
293300a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
293400a2430fSAndrzej Pietrasiewicz 				   struct usb_descriptor_header *desc,
293500a2430fSAndrzej Pietrasiewicz 				   void *priv)
293600a2430fSAndrzej Pietrasiewicz {
293700a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = priv;
293800a2430fSAndrzej Pietrasiewicz 	unsigned idx;
293900a2430fSAndrzej Pietrasiewicz 	u8 newValue;
294000a2430fSAndrzej Pietrasiewicz 
294100a2430fSAndrzej Pietrasiewicz 	switch (type) {
294200a2430fSAndrzej Pietrasiewicz 	default:
294300a2430fSAndrzej Pietrasiewicz 	case FFS_DESCRIPTOR:
294400a2430fSAndrzej Pietrasiewicz 		/* Handled in previous pass by __ffs_func_bind_do_descs() */
294500a2430fSAndrzej Pietrasiewicz 		return 0;
294600a2430fSAndrzej Pietrasiewicz 
294700a2430fSAndrzej Pietrasiewicz 	case FFS_INTERFACE:
294800a2430fSAndrzej Pietrasiewicz 		idx = *valuep;
294900a2430fSAndrzej Pietrasiewicz 		if (func->interfaces_nums[idx] < 0) {
295000a2430fSAndrzej Pietrasiewicz 			int id = usb_interface_id(func->conf, &func->function);
29518704fd73SGreg Kroah-Hartman 			if (id < 0)
295200a2430fSAndrzej Pietrasiewicz 				return id;
295300a2430fSAndrzej Pietrasiewicz 			func->interfaces_nums[idx] = id;
295400a2430fSAndrzej Pietrasiewicz 		}
295500a2430fSAndrzej Pietrasiewicz 		newValue = func->interfaces_nums[idx];
295600a2430fSAndrzej Pietrasiewicz 		break;
295700a2430fSAndrzej Pietrasiewicz 
295800a2430fSAndrzej Pietrasiewicz 	case FFS_STRING:
295900a2430fSAndrzej Pietrasiewicz 		/* String' IDs are allocated when fsf_data is bound to cdev */
296000a2430fSAndrzej Pietrasiewicz 		newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
296100a2430fSAndrzej Pietrasiewicz 		break;
296200a2430fSAndrzej Pietrasiewicz 
296300a2430fSAndrzej Pietrasiewicz 	case FFS_ENDPOINT:
296400a2430fSAndrzej Pietrasiewicz 		/*
296500a2430fSAndrzej Pietrasiewicz 		 * USB_DT_ENDPOINT are handled in
296600a2430fSAndrzej Pietrasiewicz 		 * __ffs_func_bind_do_descs().
296700a2430fSAndrzej Pietrasiewicz 		 */
296800a2430fSAndrzej Pietrasiewicz 		if (desc->bDescriptorType == USB_DT_ENDPOINT)
296900a2430fSAndrzej Pietrasiewicz 			return 0;
297000a2430fSAndrzej Pietrasiewicz 
297100a2430fSAndrzej Pietrasiewicz 		idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
29728704fd73SGreg Kroah-Hartman 		if (!func->eps[idx].ep)
297300a2430fSAndrzej Pietrasiewicz 			return -EINVAL;
297400a2430fSAndrzej Pietrasiewicz 
297500a2430fSAndrzej Pietrasiewicz 		{
297600a2430fSAndrzej Pietrasiewicz 			struct usb_endpoint_descriptor **descs;
297700a2430fSAndrzej Pietrasiewicz 			descs = func->eps[idx].descs;
297800a2430fSAndrzej Pietrasiewicz 			newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
297900a2430fSAndrzej Pietrasiewicz 		}
298000a2430fSAndrzej Pietrasiewicz 		break;
298100a2430fSAndrzej Pietrasiewicz 	}
298200a2430fSAndrzej Pietrasiewicz 
298300a2430fSAndrzej Pietrasiewicz 	pr_vdebug("%02x -> %02x\n", *valuep, newValue);
298400a2430fSAndrzej Pietrasiewicz 	*valuep = newValue;
298500a2430fSAndrzej Pietrasiewicz 	return 0;
298600a2430fSAndrzej Pietrasiewicz }
298700a2430fSAndrzej Pietrasiewicz 
298800a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
298900a2430fSAndrzej Pietrasiewicz 				      struct usb_os_desc_header *h, void *data,
299000a2430fSAndrzej Pietrasiewicz 				      unsigned len, void *priv)
299100a2430fSAndrzej Pietrasiewicz {
299200a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = priv;
299300a2430fSAndrzej Pietrasiewicz 	u8 length = 0;
299400a2430fSAndrzej Pietrasiewicz 
299500a2430fSAndrzej Pietrasiewicz 	switch (type) {
299600a2430fSAndrzej Pietrasiewicz 	case FFS_OS_DESC_EXT_COMPAT: {
299700a2430fSAndrzej Pietrasiewicz 		struct usb_ext_compat_desc *desc = data;
299800a2430fSAndrzej Pietrasiewicz 		struct usb_os_desc_table *t;
299900a2430fSAndrzej Pietrasiewicz 
300000a2430fSAndrzej Pietrasiewicz 		t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
300100a2430fSAndrzej Pietrasiewicz 		t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
300200a2430fSAndrzej Pietrasiewicz 		memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID,
300300a2430fSAndrzej Pietrasiewicz 		       ARRAY_SIZE(desc->CompatibleID) +
300400a2430fSAndrzej Pietrasiewicz 		       ARRAY_SIZE(desc->SubCompatibleID));
300500a2430fSAndrzej Pietrasiewicz 		length = sizeof(*desc);
300600a2430fSAndrzej Pietrasiewicz 	}
300700a2430fSAndrzej Pietrasiewicz 		break;
300800a2430fSAndrzej Pietrasiewicz 	case FFS_OS_DESC_EXT_PROP: {
300900a2430fSAndrzej Pietrasiewicz 		struct usb_ext_prop_desc *desc = data;
301000a2430fSAndrzej Pietrasiewicz 		struct usb_os_desc_table *t;
301100a2430fSAndrzej Pietrasiewicz 		struct usb_os_desc_ext_prop *ext_prop;
301200a2430fSAndrzej Pietrasiewicz 		char *ext_prop_name;
301300a2430fSAndrzej Pietrasiewicz 		char *ext_prop_data;
301400a2430fSAndrzej Pietrasiewicz 
301500a2430fSAndrzej Pietrasiewicz 		t = &func->function.os_desc_table[h->interface];
301600a2430fSAndrzej Pietrasiewicz 		t->if_id = func->interfaces_nums[h->interface];
301700a2430fSAndrzej Pietrasiewicz 
301800a2430fSAndrzej Pietrasiewicz 		ext_prop = func->ffs->ms_os_descs_ext_prop_avail;
301900a2430fSAndrzej Pietrasiewicz 		func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop);
302000a2430fSAndrzej Pietrasiewicz 
302100a2430fSAndrzej Pietrasiewicz 		ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
302200a2430fSAndrzej Pietrasiewicz 		ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
3023c40619bbSVincent Pelletier 		ext_prop->data_len = le32_to_cpu(*(__le32 *)
302400a2430fSAndrzej Pietrasiewicz 			usb_ext_prop_data_len_ptr(data, ext_prop->name_len));
302500a2430fSAndrzej Pietrasiewicz 		length = ext_prop->name_len + ext_prop->data_len + 14;
302600a2430fSAndrzej Pietrasiewicz 
302700a2430fSAndrzej Pietrasiewicz 		ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail;
302800a2430fSAndrzej Pietrasiewicz 		func->ffs->ms_os_descs_ext_prop_name_avail +=
302900a2430fSAndrzej Pietrasiewicz 			ext_prop->name_len;
303000a2430fSAndrzej Pietrasiewicz 
303100a2430fSAndrzej Pietrasiewicz 		ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
303200a2430fSAndrzej Pietrasiewicz 		func->ffs->ms_os_descs_ext_prop_data_avail +=
303300a2430fSAndrzej Pietrasiewicz 			ext_prop->data_len;
303400a2430fSAndrzej Pietrasiewicz 		memcpy(ext_prop_data,
303500a2430fSAndrzej Pietrasiewicz 		       usb_ext_prop_data_ptr(data, ext_prop->name_len),
303600a2430fSAndrzej Pietrasiewicz 		       ext_prop->data_len);
303700a2430fSAndrzej Pietrasiewicz 		/* unicode data reported to the host as "WCHAR"s */
303800a2430fSAndrzej Pietrasiewicz 		switch (ext_prop->type) {
303900a2430fSAndrzej Pietrasiewicz 		case USB_EXT_PROP_UNICODE:
304000a2430fSAndrzej Pietrasiewicz 		case USB_EXT_PROP_UNICODE_ENV:
304100a2430fSAndrzej Pietrasiewicz 		case USB_EXT_PROP_UNICODE_LINK:
304200a2430fSAndrzej Pietrasiewicz 		case USB_EXT_PROP_UNICODE_MULTI:
304300a2430fSAndrzej Pietrasiewicz 			ext_prop->data_len *= 2;
304400a2430fSAndrzej Pietrasiewicz 			break;
304500a2430fSAndrzej Pietrasiewicz 		}
304600a2430fSAndrzej Pietrasiewicz 		ext_prop->data = ext_prop_data;
304700a2430fSAndrzej Pietrasiewicz 
304800a2430fSAndrzej Pietrasiewicz 		memcpy(ext_prop_name, usb_ext_prop_name_ptr(data),
304900a2430fSAndrzej Pietrasiewicz 		       ext_prop->name_len);
305000a2430fSAndrzej Pietrasiewicz 		/* property name reported to the host as "WCHAR"s */
305100a2430fSAndrzej Pietrasiewicz 		ext_prop->name_len *= 2;
305200a2430fSAndrzej Pietrasiewicz 		ext_prop->name = ext_prop_name;
305300a2430fSAndrzej Pietrasiewicz 
305400a2430fSAndrzej Pietrasiewicz 		t->os_desc->ext_prop_len +=
305500a2430fSAndrzej Pietrasiewicz 			ext_prop->name_len + ext_prop->data_len + 14;
305600a2430fSAndrzej Pietrasiewicz 		++t->os_desc->ext_prop_count;
305700a2430fSAndrzej Pietrasiewicz 		list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop);
305800a2430fSAndrzej Pietrasiewicz 	}
305900a2430fSAndrzej Pietrasiewicz 		break;
306000a2430fSAndrzej Pietrasiewicz 	default:
306100a2430fSAndrzej Pietrasiewicz 		pr_vdebug("unknown descriptor: %d\n", type);
306200a2430fSAndrzej Pietrasiewicz 	}
306300a2430fSAndrzej Pietrasiewicz 
306400a2430fSAndrzej Pietrasiewicz 	return length;
306500a2430fSAndrzej Pietrasiewicz }
306600a2430fSAndrzej Pietrasiewicz 
306700a2430fSAndrzej Pietrasiewicz static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
306800a2430fSAndrzej Pietrasiewicz 						struct usb_configuration *c)
306900a2430fSAndrzej Pietrasiewicz {
307000a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
307100a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *ffs_opts =
307200a2430fSAndrzej Pietrasiewicz 		container_of(f->fi, struct f_fs_opts, func_inst);
3073ecfbd7b9SAndrew Gabbasov 	struct ffs_data *ffs_data;
307400a2430fSAndrzej Pietrasiewicz 	int ret;
307500a2430fSAndrzej Pietrasiewicz 
307600a2430fSAndrzej Pietrasiewicz 	ENTER();
307700a2430fSAndrzej Pietrasiewicz 
307800a2430fSAndrzej Pietrasiewicz 	/*
307900a2430fSAndrzej Pietrasiewicz 	 * Legacy gadget triggers binding in functionfs_ready_callback,
308000a2430fSAndrzej Pietrasiewicz 	 * which already uses locking; taking the same lock here would
308100a2430fSAndrzej Pietrasiewicz 	 * cause a deadlock.
308200a2430fSAndrzej Pietrasiewicz 	 *
308300a2430fSAndrzej Pietrasiewicz 	 * Configfs-enabled gadgets however do need ffs_dev_lock.
308400a2430fSAndrzej Pietrasiewicz 	 */
308500a2430fSAndrzej Pietrasiewicz 	if (!ffs_opts->no_configfs)
308600a2430fSAndrzej Pietrasiewicz 		ffs_dev_lock();
308700a2430fSAndrzej Pietrasiewicz 	ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
3088ecfbd7b9SAndrew Gabbasov 	ffs_data = ffs_opts->dev->ffs_data;
308900a2430fSAndrzej Pietrasiewicz 	if (!ffs_opts->no_configfs)
309000a2430fSAndrzej Pietrasiewicz 		ffs_dev_unlock();
309100a2430fSAndrzej Pietrasiewicz 	if (ret)
309200a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(ret);
309300a2430fSAndrzej Pietrasiewicz 
3094ecfbd7b9SAndrew Gabbasov 	func->ffs = ffs_data;
309500a2430fSAndrzej Pietrasiewicz 	func->conf = c;
309600a2430fSAndrzej Pietrasiewicz 	func->gadget = c->cdev->gadget;
309700a2430fSAndrzej Pietrasiewicz 
309800a2430fSAndrzej Pietrasiewicz 	/*
309900a2430fSAndrzej Pietrasiewicz 	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
310000a2430fSAndrzej Pietrasiewicz 	 * configurations are bound in sequence with list_for_each_entry,
310100a2430fSAndrzej Pietrasiewicz 	 * in each configuration its functions are bound in sequence
310200a2430fSAndrzej Pietrasiewicz 	 * with list_for_each_entry, so we assume no race condition
310300a2430fSAndrzej Pietrasiewicz 	 * with regard to ffs_opts->bound access
310400a2430fSAndrzej Pietrasiewicz 	 */
310500a2430fSAndrzej Pietrasiewicz 	if (!ffs_opts->refcnt) {
310600a2430fSAndrzej Pietrasiewicz 		ret = functionfs_bind(func->ffs, c->cdev);
310700a2430fSAndrzej Pietrasiewicz 		if (ret)
310800a2430fSAndrzej Pietrasiewicz 			return ERR_PTR(ret);
310900a2430fSAndrzej Pietrasiewicz 	}
311000a2430fSAndrzej Pietrasiewicz 	ffs_opts->refcnt++;
311100a2430fSAndrzej Pietrasiewicz 	func->function.strings = func->ffs->stringtabs;
311200a2430fSAndrzej Pietrasiewicz 
311300a2430fSAndrzej Pietrasiewicz 	return ffs_opts;
311400a2430fSAndrzej Pietrasiewicz }
311500a2430fSAndrzej Pietrasiewicz 
311600a2430fSAndrzej Pietrasiewicz static int _ffs_func_bind(struct usb_configuration *c,
311700a2430fSAndrzej Pietrasiewicz 			  struct usb_function *f)
311800a2430fSAndrzej Pietrasiewicz {
311900a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
312000a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = func->ffs;
312100a2430fSAndrzej Pietrasiewicz 
312200a2430fSAndrzej Pietrasiewicz 	const int full = !!func->ffs->fs_descs_count;
31236cf439e0SJack Pham 	const int high = !!func->ffs->hs_descs_count;
31246cf439e0SJack Pham 	const int super = !!func->ffs->ss_descs_count;
312500a2430fSAndrzej Pietrasiewicz 
312600a2430fSAndrzej Pietrasiewicz 	int fs_len, hs_len, ss_len, ret, i;
31270015f915SDan Carpenter 	struct ffs_ep *eps_ptr;
312800a2430fSAndrzej Pietrasiewicz 
312900a2430fSAndrzej Pietrasiewicz 	/* Make it a single chunk, less management later on */
313000a2430fSAndrzej Pietrasiewicz 	vla_group(d);
313100a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count);
313200a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs,
313300a2430fSAndrzej Pietrasiewicz 		full ? ffs->fs_descs_count + 1 : 0);
313400a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
313500a2430fSAndrzej Pietrasiewicz 		high ? ffs->hs_descs_count + 1 : 0);
313600a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
313700a2430fSAndrzej Pietrasiewicz 		super ? ffs->ss_descs_count + 1 : 0);
313800a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, short, inums, ffs->interfaces_count);
313900a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table,
314000a2430fSAndrzej Pietrasiewicz 			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
314100a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, char[16], ext_compat,
314200a2430fSAndrzej Pietrasiewicz 			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
314300a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_os_desc, os_desc,
314400a2430fSAndrzej Pietrasiewicz 			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
314500a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop,
314600a2430fSAndrzej Pietrasiewicz 			 ffs->ms_os_descs_ext_prop_count);
314700a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, char, ext_prop_name,
314800a2430fSAndrzej Pietrasiewicz 			 ffs->ms_os_descs_ext_prop_name_len);
314900a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, char, ext_prop_data,
315000a2430fSAndrzej Pietrasiewicz 			 ffs->ms_os_descs_ext_prop_data_len);
315100a2430fSAndrzej Pietrasiewicz 	vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
315200a2430fSAndrzej Pietrasiewicz 	char *vlabuf;
315300a2430fSAndrzej Pietrasiewicz 
315400a2430fSAndrzej Pietrasiewicz 	ENTER();
315500a2430fSAndrzej Pietrasiewicz 
315600a2430fSAndrzej Pietrasiewicz 	/* Has descriptors only for speeds gadget does not support */
31578704fd73SGreg Kroah-Hartman 	if (!(full | high | super))
315800a2430fSAndrzej Pietrasiewicz 		return -ENOTSUPP;
315900a2430fSAndrzej Pietrasiewicz 
316000a2430fSAndrzej Pietrasiewicz 	/* Allocate a single chunk, less management later on */
316100a2430fSAndrzej Pietrasiewicz 	vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL);
31628704fd73SGreg Kroah-Hartman 	if (!vlabuf)
316300a2430fSAndrzej Pietrasiewicz 		return -ENOMEM;
316400a2430fSAndrzej Pietrasiewicz 
316500a2430fSAndrzej Pietrasiewicz 	ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
316600a2430fSAndrzej Pietrasiewicz 	ffs->ms_os_descs_ext_prop_name_avail =
316700a2430fSAndrzej Pietrasiewicz 		vla_ptr(vlabuf, d, ext_prop_name);
316800a2430fSAndrzej Pietrasiewicz 	ffs->ms_os_descs_ext_prop_data_avail =
316900a2430fSAndrzej Pietrasiewicz 		vla_ptr(vlabuf, d, ext_prop_data);
317000a2430fSAndrzej Pietrasiewicz 
317100a2430fSAndrzej Pietrasiewicz 	/* Copy descriptors  */
317200a2430fSAndrzej Pietrasiewicz 	memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
317300a2430fSAndrzej Pietrasiewicz 	       ffs->raw_descs_length);
317400a2430fSAndrzej Pietrasiewicz 
317500a2430fSAndrzej Pietrasiewicz 	memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
31760015f915SDan Carpenter 	eps_ptr = vla_ptr(vlabuf, d, eps);
31770015f915SDan Carpenter 	for (i = 0; i < ffs->eps_count; i++)
31780015f915SDan Carpenter 		eps_ptr[i].num = -1;
317900a2430fSAndrzej Pietrasiewicz 
318000a2430fSAndrzej Pietrasiewicz 	/* Save pointers
318100a2430fSAndrzej Pietrasiewicz 	 * d_eps == vlabuf, func->eps used to kfree vlabuf later
318200a2430fSAndrzej Pietrasiewicz 	*/
318300a2430fSAndrzej Pietrasiewicz 	func->eps             = vla_ptr(vlabuf, d, eps);
318400a2430fSAndrzej Pietrasiewicz 	func->interfaces_nums = vla_ptr(vlabuf, d, inums);
318500a2430fSAndrzej Pietrasiewicz 
318600a2430fSAndrzej Pietrasiewicz 	/*
318700a2430fSAndrzej Pietrasiewicz 	 * Go through all the endpoint descriptors and allocate
318800a2430fSAndrzej Pietrasiewicz 	 * endpoints first, so that later we can rewrite the endpoint
318900a2430fSAndrzej Pietrasiewicz 	 * numbers without worrying that it may be described later on.
319000a2430fSAndrzej Pietrasiewicz 	 */
31918704fd73SGreg Kroah-Hartman 	if (full) {
319200a2430fSAndrzej Pietrasiewicz 		func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
319300a2430fSAndrzej Pietrasiewicz 		fs_len = ffs_do_descs(ffs->fs_descs_count,
319400a2430fSAndrzej Pietrasiewicz 				      vla_ptr(vlabuf, d, raw_descs),
319500a2430fSAndrzej Pietrasiewicz 				      d_raw_descs__sz,
319600a2430fSAndrzej Pietrasiewicz 				      __ffs_func_bind_do_descs, func);
31978704fd73SGreg Kroah-Hartman 		if (fs_len < 0) {
319800a2430fSAndrzej Pietrasiewicz 			ret = fs_len;
319900a2430fSAndrzej Pietrasiewicz 			goto error;
320000a2430fSAndrzej Pietrasiewicz 		}
320100a2430fSAndrzej Pietrasiewicz 	} else {
320200a2430fSAndrzej Pietrasiewicz 		fs_len = 0;
320300a2430fSAndrzej Pietrasiewicz 	}
320400a2430fSAndrzej Pietrasiewicz 
32058704fd73SGreg Kroah-Hartman 	if (high) {
320600a2430fSAndrzej Pietrasiewicz 		func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
320700a2430fSAndrzej Pietrasiewicz 		hs_len = ffs_do_descs(ffs->hs_descs_count,
320800a2430fSAndrzej Pietrasiewicz 				      vla_ptr(vlabuf, d, raw_descs) + fs_len,
320900a2430fSAndrzej Pietrasiewicz 				      d_raw_descs__sz - fs_len,
321000a2430fSAndrzej Pietrasiewicz 				      __ffs_func_bind_do_descs, func);
32118704fd73SGreg Kroah-Hartman 		if (hs_len < 0) {
321200a2430fSAndrzej Pietrasiewicz 			ret = hs_len;
321300a2430fSAndrzej Pietrasiewicz 			goto error;
321400a2430fSAndrzej Pietrasiewicz 		}
321500a2430fSAndrzej Pietrasiewicz 	} else {
321600a2430fSAndrzej Pietrasiewicz 		hs_len = 0;
321700a2430fSAndrzej Pietrasiewicz 	}
321800a2430fSAndrzej Pietrasiewicz 
32198704fd73SGreg Kroah-Hartman 	if (super) {
3220a353397bSJack Pham 		func->function.ss_descriptors = func->function.ssp_descriptors =
3221a353397bSJack Pham 			vla_ptr(vlabuf, d, ss_descs);
322200a2430fSAndrzej Pietrasiewicz 		ss_len = ffs_do_descs(ffs->ss_descs_count,
322300a2430fSAndrzej Pietrasiewicz 				vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
322400a2430fSAndrzej Pietrasiewicz 				d_raw_descs__sz - fs_len - hs_len,
322500a2430fSAndrzej Pietrasiewicz 				__ffs_func_bind_do_descs, func);
32268704fd73SGreg Kroah-Hartman 		if (ss_len < 0) {
322700a2430fSAndrzej Pietrasiewicz 			ret = ss_len;
322800a2430fSAndrzej Pietrasiewicz 			goto error;
322900a2430fSAndrzej Pietrasiewicz 		}
323000a2430fSAndrzej Pietrasiewicz 	} else {
323100a2430fSAndrzej Pietrasiewicz 		ss_len = 0;
323200a2430fSAndrzej Pietrasiewicz 	}
323300a2430fSAndrzej Pietrasiewicz 
323400a2430fSAndrzej Pietrasiewicz 	/*
323500a2430fSAndrzej Pietrasiewicz 	 * Now handle interface numbers allocation and interface and
323600a2430fSAndrzej Pietrasiewicz 	 * endpoint numbers rewriting.  We can do that in one go
323700a2430fSAndrzej Pietrasiewicz 	 * now.
323800a2430fSAndrzej Pietrasiewicz 	 */
323900a2430fSAndrzej Pietrasiewicz 	ret = ffs_do_descs(ffs->fs_descs_count +
324000a2430fSAndrzej Pietrasiewicz 			   (high ? ffs->hs_descs_count : 0) +
324100a2430fSAndrzej Pietrasiewicz 			   (super ? ffs->ss_descs_count : 0),
324200a2430fSAndrzej Pietrasiewicz 			   vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
324300a2430fSAndrzej Pietrasiewicz 			   __ffs_func_bind_do_nums, func);
32448704fd73SGreg Kroah-Hartman 	if (ret < 0)
324500a2430fSAndrzej Pietrasiewicz 		goto error;
324600a2430fSAndrzej Pietrasiewicz 
324700a2430fSAndrzej Pietrasiewicz 	func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
3248c6010c8bSJim Lin 	if (c->cdev->use_os_string) {
324900a2430fSAndrzej Pietrasiewicz 		for (i = 0; i < ffs->interfaces_count; ++i) {
325000a2430fSAndrzej Pietrasiewicz 			struct usb_os_desc *desc;
325100a2430fSAndrzej Pietrasiewicz 
325200a2430fSAndrzej Pietrasiewicz 			desc = func->function.os_desc_table[i].os_desc =
325300a2430fSAndrzej Pietrasiewicz 				vla_ptr(vlabuf, d, os_desc) +
325400a2430fSAndrzej Pietrasiewicz 				i * sizeof(struct usb_os_desc);
325500a2430fSAndrzej Pietrasiewicz 			desc->ext_compat_id =
325600a2430fSAndrzej Pietrasiewicz 				vla_ptr(vlabuf, d, ext_compat) + i * 16;
325700a2430fSAndrzej Pietrasiewicz 			INIT_LIST_HEAD(&desc->ext_prop);
325800a2430fSAndrzej Pietrasiewicz 		}
325900a2430fSAndrzej Pietrasiewicz 		ret = ffs_do_os_descs(ffs->ms_os_descs_count,
326000a2430fSAndrzej Pietrasiewicz 				      vla_ptr(vlabuf, d, raw_descs) +
326100a2430fSAndrzej Pietrasiewicz 				      fs_len + hs_len + ss_len,
3262c6010c8bSJim Lin 				      d_raw_descs__sz - fs_len - hs_len -
3263c6010c8bSJim Lin 				      ss_len,
326400a2430fSAndrzej Pietrasiewicz 				      __ffs_func_bind_do_os_desc, func);
32658704fd73SGreg Kroah-Hartman 		if (ret < 0)
326600a2430fSAndrzej Pietrasiewicz 			goto error;
3267c6010c8bSJim Lin 	}
326800a2430fSAndrzej Pietrasiewicz 	func->function.os_desc_n =
326900a2430fSAndrzej Pietrasiewicz 		c->cdev->use_os_string ? ffs->interfaces_count : 0;
327000a2430fSAndrzej Pietrasiewicz 
327100a2430fSAndrzej Pietrasiewicz 	/* And we're done */
327200a2430fSAndrzej Pietrasiewicz 	ffs_event_add(ffs, FUNCTIONFS_BIND);
327300a2430fSAndrzej Pietrasiewicz 	return 0;
327400a2430fSAndrzej Pietrasiewicz 
327500a2430fSAndrzej Pietrasiewicz error:
327600a2430fSAndrzej Pietrasiewicz 	/* XXX Do we need to release all claimed endpoints here? */
327700a2430fSAndrzej Pietrasiewicz 	return ret;
327800a2430fSAndrzej Pietrasiewicz }
327900a2430fSAndrzej Pietrasiewicz 
328000a2430fSAndrzej Pietrasiewicz static int ffs_func_bind(struct usb_configuration *c,
328100a2430fSAndrzej Pietrasiewicz 			 struct usb_function *f)
328200a2430fSAndrzej Pietrasiewicz {
328300a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c);
328455d81121SRobert Baldyga 	struct ffs_function *func = ffs_func_from_usb(f);
328555d81121SRobert Baldyga 	int ret;
328600a2430fSAndrzej Pietrasiewicz 
328700a2430fSAndrzej Pietrasiewicz 	if (IS_ERR(ffs_opts))
328800a2430fSAndrzej Pietrasiewicz 		return PTR_ERR(ffs_opts);
328900a2430fSAndrzej Pietrasiewicz 
329055d81121SRobert Baldyga 	ret = _ffs_func_bind(c, f);
329155d81121SRobert Baldyga 	if (ret && !--ffs_opts->refcnt)
329255d81121SRobert Baldyga 		functionfs_unbind(func->ffs);
329355d81121SRobert Baldyga 
329455d81121SRobert Baldyga 	return ret;
329500a2430fSAndrzej Pietrasiewicz }
329600a2430fSAndrzej Pietrasiewicz 
329700a2430fSAndrzej Pietrasiewicz 
329800a2430fSAndrzej Pietrasiewicz /* Other USB function hooks *************************************************/
329900a2430fSAndrzej Pietrasiewicz 
330018d6b32fSRobert Baldyga static void ffs_reset_work(struct work_struct *work)
330118d6b32fSRobert Baldyga {
330218d6b32fSRobert Baldyga 	struct ffs_data *ffs = container_of(work,
330318d6b32fSRobert Baldyga 		struct ffs_data, reset_work);
330418d6b32fSRobert Baldyga 	ffs_data_reset(ffs);
330518d6b32fSRobert Baldyga }
330618d6b32fSRobert Baldyga 
330700a2430fSAndrzej Pietrasiewicz static int ffs_func_set_alt(struct usb_function *f,
330800a2430fSAndrzej Pietrasiewicz 			    unsigned interface, unsigned alt)
330900a2430fSAndrzej Pietrasiewicz {
331000a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
331100a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = func->ffs;
331200a2430fSAndrzej Pietrasiewicz 	int ret = 0, intf;
331300a2430fSAndrzej Pietrasiewicz 
331400a2430fSAndrzej Pietrasiewicz 	if (alt != (unsigned)-1) {
331500a2430fSAndrzej Pietrasiewicz 		intf = ffs_func_revmap_intf(func, interface);
33168704fd73SGreg Kroah-Hartman 		if (intf < 0)
331700a2430fSAndrzej Pietrasiewicz 			return intf;
331800a2430fSAndrzej Pietrasiewicz 	}
331900a2430fSAndrzej Pietrasiewicz 
332000a2430fSAndrzej Pietrasiewicz 	if (ffs->func)
332100a2430fSAndrzej Pietrasiewicz 		ffs_func_eps_disable(ffs->func);
332200a2430fSAndrzej Pietrasiewicz 
332318d6b32fSRobert Baldyga 	if (ffs->state == FFS_DEACTIVATED) {
332418d6b32fSRobert Baldyga 		ffs->state = FFS_CLOSING;
332518d6b32fSRobert Baldyga 		INIT_WORK(&ffs->reset_work, ffs_reset_work);
332618d6b32fSRobert Baldyga 		schedule_work(&ffs->reset_work);
332718d6b32fSRobert Baldyga 		return -ENODEV;
332818d6b32fSRobert Baldyga 	}
332918d6b32fSRobert Baldyga 
333000a2430fSAndrzej Pietrasiewicz 	if (ffs->state != FFS_ACTIVE)
333100a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
333200a2430fSAndrzej Pietrasiewicz 
333300a2430fSAndrzej Pietrasiewicz 	if (alt == (unsigned)-1) {
333400a2430fSAndrzej Pietrasiewicz 		ffs->func = NULL;
333500a2430fSAndrzej Pietrasiewicz 		ffs_event_add(ffs, FUNCTIONFS_DISABLE);
333600a2430fSAndrzej Pietrasiewicz 		return 0;
333700a2430fSAndrzej Pietrasiewicz 	}
333800a2430fSAndrzej Pietrasiewicz 
333900a2430fSAndrzej Pietrasiewicz 	ffs->func = func;
334000a2430fSAndrzej Pietrasiewicz 	ret = ffs_func_eps_enable(func);
33418704fd73SGreg Kroah-Hartman 	if (ret >= 0)
334200a2430fSAndrzej Pietrasiewicz 		ffs_event_add(ffs, FUNCTIONFS_ENABLE);
334300a2430fSAndrzej Pietrasiewicz 	return ret;
334400a2430fSAndrzej Pietrasiewicz }
334500a2430fSAndrzej Pietrasiewicz 
334600a2430fSAndrzej Pietrasiewicz static void ffs_func_disable(struct usb_function *f)
334700a2430fSAndrzej Pietrasiewicz {
334800a2430fSAndrzej Pietrasiewicz 	ffs_func_set_alt(f, 0, (unsigned)-1);
334900a2430fSAndrzej Pietrasiewicz }
335000a2430fSAndrzej Pietrasiewicz 
335100a2430fSAndrzej Pietrasiewicz static int ffs_func_setup(struct usb_function *f,
335200a2430fSAndrzej Pietrasiewicz 			  const struct usb_ctrlrequest *creq)
335300a2430fSAndrzej Pietrasiewicz {
335400a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
335500a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = func->ffs;
335600a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
335700a2430fSAndrzej Pietrasiewicz 	int ret;
335800a2430fSAndrzej Pietrasiewicz 
335900a2430fSAndrzej Pietrasiewicz 	ENTER();
336000a2430fSAndrzej Pietrasiewicz 
336100a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
336200a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->bRequest     = %02x\n", creq->bRequest);
336300a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->wValue       = %04x\n", le16_to_cpu(creq->wValue));
336400a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->wIndex       = %04x\n", le16_to_cpu(creq->wIndex));
336500a2430fSAndrzej Pietrasiewicz 	pr_vdebug("creq->wLength      = %04x\n", le16_to_cpu(creq->wLength));
336600a2430fSAndrzej Pietrasiewicz 
336700a2430fSAndrzej Pietrasiewicz 	/*
336800a2430fSAndrzej Pietrasiewicz 	 * Most requests directed to interface go through here
336900a2430fSAndrzej Pietrasiewicz 	 * (notable exceptions are set/get interface) so we need to
337000a2430fSAndrzej Pietrasiewicz 	 * handle them.  All other either handled by composite or
337100a2430fSAndrzej Pietrasiewicz 	 * passed to usb_configuration->setup() (if one is set).  No
337200a2430fSAndrzej Pietrasiewicz 	 * matter, we will handle requests directed to endpoint here
337354dfce6dSFelix Hädicke 	 * as well (as it's straightforward).  Other request recipient
337454dfce6dSFelix Hädicke 	 * types are only handled when the user flag FUNCTIONFS_ALL_CTRL_RECIP
337554dfce6dSFelix Hädicke 	 * is being used.
337600a2430fSAndrzej Pietrasiewicz 	 */
337700a2430fSAndrzej Pietrasiewicz 	if (ffs->state != FFS_ACTIVE)
337800a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
337900a2430fSAndrzej Pietrasiewicz 
338000a2430fSAndrzej Pietrasiewicz 	switch (creq->bRequestType & USB_RECIP_MASK) {
338100a2430fSAndrzej Pietrasiewicz 	case USB_RECIP_INTERFACE:
338200a2430fSAndrzej Pietrasiewicz 		ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
33838704fd73SGreg Kroah-Hartman 		if (ret < 0)
338400a2430fSAndrzej Pietrasiewicz 			return ret;
338500a2430fSAndrzej Pietrasiewicz 		break;
338600a2430fSAndrzej Pietrasiewicz 
338700a2430fSAndrzej Pietrasiewicz 	case USB_RECIP_ENDPOINT:
338800a2430fSAndrzej Pietrasiewicz 		ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
33898704fd73SGreg Kroah-Hartman 		if (ret < 0)
339000a2430fSAndrzej Pietrasiewicz 			return ret;
33911b0bf88fSRobert Baldyga 		if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
33921b0bf88fSRobert Baldyga 			ret = func->ffs->eps_addrmap[ret];
339300a2430fSAndrzej Pietrasiewicz 		break;
339400a2430fSAndrzej Pietrasiewicz 
339500a2430fSAndrzej Pietrasiewicz 	default:
339654dfce6dSFelix Hädicke 		if (func->ffs->user_flags & FUNCTIONFS_ALL_CTRL_RECIP)
339754dfce6dSFelix Hädicke 			ret = le16_to_cpu(creq->wIndex);
339854dfce6dSFelix Hädicke 		else
339900a2430fSAndrzej Pietrasiewicz 			return -EOPNOTSUPP;
340000a2430fSAndrzej Pietrasiewicz 	}
340100a2430fSAndrzej Pietrasiewicz 
340200a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
340300a2430fSAndrzej Pietrasiewicz 	ffs->ev.setup = *creq;
340400a2430fSAndrzej Pietrasiewicz 	ffs->ev.setup.wIndex = cpu_to_le16(ret);
340500a2430fSAndrzej Pietrasiewicz 	__ffs_event_add(ffs, FUNCTIONFS_SETUP);
340600a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
340700a2430fSAndrzej Pietrasiewicz 
34084d644abfSJerry Zhang 	return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
340900a2430fSAndrzej Pietrasiewicz }
341000a2430fSAndrzej Pietrasiewicz 
341154dfce6dSFelix Hädicke static bool ffs_func_req_match(struct usb_function *f,
34121a00b457SFelix Hädicke 			       const struct usb_ctrlrequest *creq,
34131a00b457SFelix Hädicke 			       bool config0)
341454dfce6dSFelix Hädicke {
341554dfce6dSFelix Hädicke 	struct ffs_function *func = ffs_func_from_usb(f);
341654dfce6dSFelix Hädicke 
34174368c28aSFelix Hädicke 	if (config0 && !(func->ffs->user_flags & FUNCTIONFS_CONFIG0_SETUP))
34181a00b457SFelix Hädicke 		return false;
34191a00b457SFelix Hädicke 
342054dfce6dSFelix Hädicke 	switch (creq->bRequestType & USB_RECIP_MASK) {
342154dfce6dSFelix Hädicke 	case USB_RECIP_INTERFACE:
342205e78c69SFelix Hädicke 		return (ffs_func_revmap_intf(func,
342305e78c69SFelix Hädicke 					     le16_to_cpu(creq->wIndex)) >= 0);
342454dfce6dSFelix Hädicke 	case USB_RECIP_ENDPOINT:
342505e78c69SFelix Hädicke 		return (ffs_func_revmap_ep(func,
342605e78c69SFelix Hädicke 					   le16_to_cpu(creq->wIndex)) >= 0);
342754dfce6dSFelix Hädicke 	default:
342854dfce6dSFelix Hädicke 		return (bool) (func->ffs->user_flags &
342954dfce6dSFelix Hädicke 			       FUNCTIONFS_ALL_CTRL_RECIP);
343054dfce6dSFelix Hädicke 	}
343154dfce6dSFelix Hädicke }
343254dfce6dSFelix Hädicke 
343300a2430fSAndrzej Pietrasiewicz static void ffs_func_suspend(struct usb_function *f)
343400a2430fSAndrzej Pietrasiewicz {
343500a2430fSAndrzej Pietrasiewicz 	ENTER();
343600a2430fSAndrzej Pietrasiewicz 	ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
343700a2430fSAndrzej Pietrasiewicz }
343800a2430fSAndrzej Pietrasiewicz 
343900a2430fSAndrzej Pietrasiewicz static void ffs_func_resume(struct usb_function *f)
344000a2430fSAndrzej Pietrasiewicz {
344100a2430fSAndrzej Pietrasiewicz 	ENTER();
344200a2430fSAndrzej Pietrasiewicz 	ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
344300a2430fSAndrzej Pietrasiewicz }
344400a2430fSAndrzej Pietrasiewicz 
344500a2430fSAndrzej Pietrasiewicz 
344600a2430fSAndrzej Pietrasiewicz /* Endpoint and interface numbers reverse mapping ***************************/
344700a2430fSAndrzej Pietrasiewicz 
344800a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
344900a2430fSAndrzej Pietrasiewicz {
345000a2430fSAndrzej Pietrasiewicz 	num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
345100a2430fSAndrzej Pietrasiewicz 	return num ? num : -EDOM;
345200a2430fSAndrzej Pietrasiewicz }
345300a2430fSAndrzej Pietrasiewicz 
345400a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
345500a2430fSAndrzej Pietrasiewicz {
345600a2430fSAndrzej Pietrasiewicz 	short *nums = func->interfaces_nums;
345700a2430fSAndrzej Pietrasiewicz 	unsigned count = func->ffs->interfaces_count;
345800a2430fSAndrzej Pietrasiewicz 
345900a2430fSAndrzej Pietrasiewicz 	for (; count; --count, ++nums) {
346000a2430fSAndrzej Pietrasiewicz 		if (*nums >= 0 && *nums == intf)
346100a2430fSAndrzej Pietrasiewicz 			return nums - func->interfaces_nums;
346200a2430fSAndrzej Pietrasiewicz 	}
346300a2430fSAndrzej Pietrasiewicz 
346400a2430fSAndrzej Pietrasiewicz 	return -EDOM;
346500a2430fSAndrzej Pietrasiewicz }
346600a2430fSAndrzej Pietrasiewicz 
346700a2430fSAndrzej Pietrasiewicz 
346800a2430fSAndrzej Pietrasiewicz /* Devices management *******************************************************/
346900a2430fSAndrzej Pietrasiewicz 
347000a2430fSAndrzej Pietrasiewicz static LIST_HEAD(ffs_devices);
347100a2430fSAndrzej Pietrasiewicz 
347200a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_do_find_dev(const char *name)
347300a2430fSAndrzej Pietrasiewicz {
347400a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
347500a2430fSAndrzej Pietrasiewicz 
3476ea920bb4SMichal Nazarewicz 	if (!name)
3477ea920bb4SMichal Nazarewicz 		return NULL;
3478ea920bb4SMichal Nazarewicz 
347900a2430fSAndrzej Pietrasiewicz 	list_for_each_entry(dev, &ffs_devices, entry) {
348000a2430fSAndrzej Pietrasiewicz 		if (strcmp(dev->name, name) == 0)
348100a2430fSAndrzej Pietrasiewicz 			return dev;
348200a2430fSAndrzej Pietrasiewicz 	}
348300a2430fSAndrzej Pietrasiewicz 
348400a2430fSAndrzej Pietrasiewicz 	return NULL;
348500a2430fSAndrzej Pietrasiewicz }
348600a2430fSAndrzej Pietrasiewicz 
348700a2430fSAndrzej Pietrasiewicz /*
348800a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
348900a2430fSAndrzej Pietrasiewicz  */
349000a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_get_single_dev(void)
349100a2430fSAndrzej Pietrasiewicz {
349200a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
349300a2430fSAndrzej Pietrasiewicz 
349400a2430fSAndrzej Pietrasiewicz 	if (list_is_singular(&ffs_devices)) {
349500a2430fSAndrzej Pietrasiewicz 		dev = list_first_entry(&ffs_devices, struct ffs_dev, entry);
349600a2430fSAndrzej Pietrasiewicz 		if (dev->single)
349700a2430fSAndrzej Pietrasiewicz 			return dev;
349800a2430fSAndrzej Pietrasiewicz 	}
349900a2430fSAndrzej Pietrasiewicz 
350000a2430fSAndrzej Pietrasiewicz 	return NULL;
350100a2430fSAndrzej Pietrasiewicz }
350200a2430fSAndrzej Pietrasiewicz 
350300a2430fSAndrzej Pietrasiewicz /*
350400a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
350500a2430fSAndrzej Pietrasiewicz  */
350600a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_find_dev(const char *name)
350700a2430fSAndrzej Pietrasiewicz {
350800a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
350900a2430fSAndrzej Pietrasiewicz 
351000a2430fSAndrzej Pietrasiewicz 	dev = _ffs_get_single_dev();
351100a2430fSAndrzej Pietrasiewicz 	if (dev)
351200a2430fSAndrzej Pietrasiewicz 		return dev;
351300a2430fSAndrzej Pietrasiewicz 
351400a2430fSAndrzej Pietrasiewicz 	return _ffs_do_find_dev(name);
351500a2430fSAndrzej Pietrasiewicz }
351600a2430fSAndrzej Pietrasiewicz 
351700a2430fSAndrzej Pietrasiewicz /* Configfs support *********************************************************/
351800a2430fSAndrzej Pietrasiewicz 
351900a2430fSAndrzej Pietrasiewicz static inline struct f_fs_opts *to_ffs_opts(struct config_item *item)
352000a2430fSAndrzej Pietrasiewicz {
352100a2430fSAndrzej Pietrasiewicz 	return container_of(to_config_group(item), struct f_fs_opts,
352200a2430fSAndrzej Pietrasiewicz 			    func_inst.group);
352300a2430fSAndrzej Pietrasiewicz }
352400a2430fSAndrzej Pietrasiewicz 
352500a2430fSAndrzej Pietrasiewicz static void ffs_attr_release(struct config_item *item)
352600a2430fSAndrzej Pietrasiewicz {
352700a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts = to_ffs_opts(item);
352800a2430fSAndrzej Pietrasiewicz 
352900a2430fSAndrzej Pietrasiewicz 	usb_put_function_instance(&opts->func_inst);
353000a2430fSAndrzej Pietrasiewicz }
353100a2430fSAndrzej Pietrasiewicz 
353200a2430fSAndrzej Pietrasiewicz static struct configfs_item_operations ffs_item_ops = {
353300a2430fSAndrzej Pietrasiewicz 	.release	= ffs_attr_release,
353400a2430fSAndrzej Pietrasiewicz };
353500a2430fSAndrzej Pietrasiewicz 
353697363902SBhumika Goyal static const struct config_item_type ffs_func_type = {
353700a2430fSAndrzej Pietrasiewicz 	.ct_item_ops	= &ffs_item_ops,
353800a2430fSAndrzej Pietrasiewicz 	.ct_owner	= THIS_MODULE,
353900a2430fSAndrzej Pietrasiewicz };
354000a2430fSAndrzej Pietrasiewicz 
354100a2430fSAndrzej Pietrasiewicz 
354200a2430fSAndrzej Pietrasiewicz /* Function registration interface ******************************************/
354300a2430fSAndrzej Pietrasiewicz 
354400a2430fSAndrzej Pietrasiewicz static void ffs_free_inst(struct usb_function_instance *f)
354500a2430fSAndrzej Pietrasiewicz {
354600a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts;
354700a2430fSAndrzej Pietrasiewicz 
354800a2430fSAndrzej Pietrasiewicz 	opts = to_f_fs_opts(f);
3549ecfbd7b9SAndrew Gabbasov 	ffs_release_dev(opts->dev);
355000a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
355100a2430fSAndrzej Pietrasiewicz 	_ffs_free_dev(opts->dev);
355200a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
355300a2430fSAndrzej Pietrasiewicz 	kfree(opts);
355400a2430fSAndrzej Pietrasiewicz }
355500a2430fSAndrzej Pietrasiewicz 
355600a2430fSAndrzej Pietrasiewicz static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
355700a2430fSAndrzej Pietrasiewicz {
3558c593642cSPankaj Bharadiya 	if (strlen(name) >= sizeof_field(struct ffs_dev, name))
355900a2430fSAndrzej Pietrasiewicz 		return -ENAMETOOLONG;
3560ea920bb4SMichal Nazarewicz 	return ffs_name_dev(to_f_fs_opts(fi)->dev, name);
356100a2430fSAndrzej Pietrasiewicz }
356200a2430fSAndrzej Pietrasiewicz 
356300a2430fSAndrzej Pietrasiewicz static struct usb_function_instance *ffs_alloc_inst(void)
356400a2430fSAndrzej Pietrasiewicz {
356500a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts;
356600a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
356700a2430fSAndrzej Pietrasiewicz 
356800a2430fSAndrzej Pietrasiewicz 	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
356900a2430fSAndrzej Pietrasiewicz 	if (!opts)
357000a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
357100a2430fSAndrzej Pietrasiewicz 
357200a2430fSAndrzej Pietrasiewicz 	opts->func_inst.set_inst_name = ffs_set_inst_name;
357300a2430fSAndrzej Pietrasiewicz 	opts->func_inst.free_func_inst = ffs_free_inst;
357400a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
357500a2430fSAndrzej Pietrasiewicz 	dev = _ffs_alloc_dev();
357600a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
357700a2430fSAndrzej Pietrasiewicz 	if (IS_ERR(dev)) {
357800a2430fSAndrzej Pietrasiewicz 		kfree(opts);
357900a2430fSAndrzej Pietrasiewicz 		return ERR_CAST(dev);
358000a2430fSAndrzej Pietrasiewicz 	}
358100a2430fSAndrzej Pietrasiewicz 	opts->dev = dev;
358200a2430fSAndrzej Pietrasiewicz 	dev->opts = opts;
358300a2430fSAndrzej Pietrasiewicz 
358400a2430fSAndrzej Pietrasiewicz 	config_group_init_type_name(&opts->func_inst.group, "",
358500a2430fSAndrzej Pietrasiewicz 				    &ffs_func_type);
358600a2430fSAndrzej Pietrasiewicz 	return &opts->func_inst;
358700a2430fSAndrzej Pietrasiewicz }
358800a2430fSAndrzej Pietrasiewicz 
358900a2430fSAndrzej Pietrasiewicz static void ffs_free(struct usb_function *f)
359000a2430fSAndrzej Pietrasiewicz {
359100a2430fSAndrzej Pietrasiewicz 	kfree(ffs_func_from_usb(f));
359200a2430fSAndrzej Pietrasiewicz }
359300a2430fSAndrzej Pietrasiewicz 
359400a2430fSAndrzej Pietrasiewicz static void ffs_func_unbind(struct usb_configuration *c,
359500a2430fSAndrzej Pietrasiewicz 			    struct usb_function *f)
359600a2430fSAndrzej Pietrasiewicz {
359700a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func = ffs_func_from_usb(f);
359800a2430fSAndrzej Pietrasiewicz 	struct ffs_data *ffs = func->ffs;
359900a2430fSAndrzej Pietrasiewicz 	struct f_fs_opts *opts =
360000a2430fSAndrzej Pietrasiewicz 		container_of(f->fi, struct f_fs_opts, func_inst);
360100a2430fSAndrzej Pietrasiewicz 	struct ffs_ep *ep = func->eps;
360200a2430fSAndrzej Pietrasiewicz 	unsigned count = ffs->eps_count;
360300a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
360400a2430fSAndrzej Pietrasiewicz 
360500a2430fSAndrzej Pietrasiewicz 	ENTER();
360600a2430fSAndrzej Pietrasiewicz 	if (ffs->func == func) {
360700a2430fSAndrzej Pietrasiewicz 		ffs_func_eps_disable(func);
360800a2430fSAndrzej Pietrasiewicz 		ffs->func = NULL;
360900a2430fSAndrzej Pietrasiewicz 	}
361000a2430fSAndrzej Pietrasiewicz 
36116fc1db5eSWesley Cheng 	/* Drain any pending AIO completions */
36126fc1db5eSWesley Cheng 	drain_workqueue(ffs->io_completion_wq);
36136fc1db5eSWesley Cheng 
361400a2430fSAndrzej Pietrasiewicz 	if (!--opts->refcnt)
361500a2430fSAndrzej Pietrasiewicz 		functionfs_unbind(ffs);
361600a2430fSAndrzej Pietrasiewicz 
361700a2430fSAndrzej Pietrasiewicz 	/* cleanup after autoconfig */
361800a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&func->ffs->eps_lock, flags);
361908f37148SVincent Pelletier 	while (count--) {
362000a2430fSAndrzej Pietrasiewicz 		if (ep->ep && ep->req)
362100a2430fSAndrzej Pietrasiewicz 			usb_ep_free_request(ep->ep, ep->req);
362200a2430fSAndrzej Pietrasiewicz 		ep->req = NULL;
362300a2430fSAndrzej Pietrasiewicz 		++ep;
362408f37148SVincent Pelletier 	}
362500a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
362600a2430fSAndrzej Pietrasiewicz 	kfree(func->eps);
362700a2430fSAndrzej Pietrasiewicz 	func->eps = NULL;
362800a2430fSAndrzej Pietrasiewicz 	/*
362900a2430fSAndrzej Pietrasiewicz 	 * eps, descriptors and interfaces_nums are allocated in the
363000a2430fSAndrzej Pietrasiewicz 	 * same chunk so only one free is required.
363100a2430fSAndrzej Pietrasiewicz 	 */
363200a2430fSAndrzej Pietrasiewicz 	func->function.fs_descriptors = NULL;
363300a2430fSAndrzej Pietrasiewicz 	func->function.hs_descriptors = NULL;
363400a2430fSAndrzej Pietrasiewicz 	func->function.ss_descriptors = NULL;
3635a353397bSJack Pham 	func->function.ssp_descriptors = NULL;
363600a2430fSAndrzej Pietrasiewicz 	func->interfaces_nums = NULL;
363700a2430fSAndrzej Pietrasiewicz 
363800a2430fSAndrzej Pietrasiewicz 	ffs_event_add(ffs, FUNCTIONFS_UNBIND);
363900a2430fSAndrzej Pietrasiewicz }
364000a2430fSAndrzej Pietrasiewicz 
364100a2430fSAndrzej Pietrasiewicz static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
364200a2430fSAndrzej Pietrasiewicz {
364300a2430fSAndrzej Pietrasiewicz 	struct ffs_function *func;
364400a2430fSAndrzej Pietrasiewicz 
364500a2430fSAndrzej Pietrasiewicz 	ENTER();
364600a2430fSAndrzej Pietrasiewicz 
364700a2430fSAndrzej Pietrasiewicz 	func = kzalloc(sizeof(*func), GFP_KERNEL);
36488704fd73SGreg Kroah-Hartman 	if (!func)
364900a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
365000a2430fSAndrzej Pietrasiewicz 
365100a2430fSAndrzej Pietrasiewicz 	func->function.name    = "Function FS Gadget";
365200a2430fSAndrzej Pietrasiewicz 
365300a2430fSAndrzej Pietrasiewicz 	func->function.bind    = ffs_func_bind;
365400a2430fSAndrzej Pietrasiewicz 	func->function.unbind  = ffs_func_unbind;
365500a2430fSAndrzej Pietrasiewicz 	func->function.set_alt = ffs_func_set_alt;
365600a2430fSAndrzej Pietrasiewicz 	func->function.disable = ffs_func_disable;
365700a2430fSAndrzej Pietrasiewicz 	func->function.setup   = ffs_func_setup;
365854dfce6dSFelix Hädicke 	func->function.req_match = ffs_func_req_match;
365900a2430fSAndrzej Pietrasiewicz 	func->function.suspend = ffs_func_suspend;
366000a2430fSAndrzej Pietrasiewicz 	func->function.resume  = ffs_func_resume;
366100a2430fSAndrzej Pietrasiewicz 	func->function.free_func = ffs_free;
366200a2430fSAndrzej Pietrasiewicz 
366300a2430fSAndrzej Pietrasiewicz 	return &func->function;
366400a2430fSAndrzej Pietrasiewicz }
366500a2430fSAndrzej Pietrasiewicz 
366600a2430fSAndrzej Pietrasiewicz /*
366700a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
366800a2430fSAndrzej Pietrasiewicz  */
366900a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_alloc_dev(void)
367000a2430fSAndrzej Pietrasiewicz {
367100a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *dev;
367200a2430fSAndrzej Pietrasiewicz 	int ret;
367300a2430fSAndrzej Pietrasiewicz 
367400a2430fSAndrzej Pietrasiewicz 	if (_ffs_get_single_dev())
367500a2430fSAndrzej Pietrasiewicz 			return ERR_PTR(-EBUSY);
367600a2430fSAndrzej Pietrasiewicz 
367700a2430fSAndrzej Pietrasiewicz 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
367800a2430fSAndrzej Pietrasiewicz 	if (!dev)
367900a2430fSAndrzej Pietrasiewicz 		return ERR_PTR(-ENOMEM);
368000a2430fSAndrzej Pietrasiewicz 
368100a2430fSAndrzej Pietrasiewicz 	if (list_empty(&ffs_devices)) {
368200a2430fSAndrzej Pietrasiewicz 		ret = functionfs_init();
368300a2430fSAndrzej Pietrasiewicz 		if (ret) {
368400a2430fSAndrzej Pietrasiewicz 			kfree(dev);
368500a2430fSAndrzej Pietrasiewicz 			return ERR_PTR(ret);
368600a2430fSAndrzej Pietrasiewicz 		}
368700a2430fSAndrzej Pietrasiewicz 	}
368800a2430fSAndrzej Pietrasiewicz 
368900a2430fSAndrzej Pietrasiewicz 	list_add(&dev->entry, &ffs_devices);
369000a2430fSAndrzej Pietrasiewicz 
369100a2430fSAndrzej Pietrasiewicz 	return dev;
369200a2430fSAndrzej Pietrasiewicz }
369300a2430fSAndrzej Pietrasiewicz 
369400a2430fSAndrzej Pietrasiewicz int ffs_name_dev(struct ffs_dev *dev, const char *name)
369500a2430fSAndrzej Pietrasiewicz {
3696ea920bb4SMichal Nazarewicz 	struct ffs_dev *existing;
3697ea920bb4SMichal Nazarewicz 	int ret = 0;
369800a2430fSAndrzej Pietrasiewicz 
369900a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
3700ea920bb4SMichal Nazarewicz 
3701ea920bb4SMichal Nazarewicz 	existing = _ffs_do_find_dev(name);
3702ea920bb4SMichal Nazarewicz 	if (!existing)
3703*b7db5733SWolfram Sang 		strscpy(dev->name, name, ARRAY_SIZE(dev->name));
3704ea920bb4SMichal Nazarewicz 	else if (existing != dev)
3705ea920bb4SMichal Nazarewicz 		ret = -EBUSY;
3706ea920bb4SMichal Nazarewicz 
370700a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
370800a2430fSAndrzej Pietrasiewicz 
370900a2430fSAndrzej Pietrasiewicz 	return ret;
371000a2430fSAndrzej Pietrasiewicz }
371100a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_name_dev);
371200a2430fSAndrzej Pietrasiewicz 
371300a2430fSAndrzej Pietrasiewicz int ffs_single_dev(struct ffs_dev *dev)
371400a2430fSAndrzej Pietrasiewicz {
371500a2430fSAndrzej Pietrasiewicz 	int ret;
371600a2430fSAndrzej Pietrasiewicz 
371700a2430fSAndrzej Pietrasiewicz 	ret = 0;
371800a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
371900a2430fSAndrzej Pietrasiewicz 
372000a2430fSAndrzej Pietrasiewicz 	if (!list_is_singular(&ffs_devices))
372100a2430fSAndrzej Pietrasiewicz 		ret = -EBUSY;
372200a2430fSAndrzej Pietrasiewicz 	else
372300a2430fSAndrzej Pietrasiewicz 		dev->single = true;
372400a2430fSAndrzej Pietrasiewicz 
372500a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
372600a2430fSAndrzej Pietrasiewicz 	return ret;
372700a2430fSAndrzej Pietrasiewicz }
372800a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_single_dev);
372900a2430fSAndrzej Pietrasiewicz 
373000a2430fSAndrzej Pietrasiewicz /*
373100a2430fSAndrzej Pietrasiewicz  * ffs_lock must be taken by the caller of this function
373200a2430fSAndrzej Pietrasiewicz  */
373300a2430fSAndrzej Pietrasiewicz static void _ffs_free_dev(struct ffs_dev *dev)
373400a2430fSAndrzej Pietrasiewicz {
373500a2430fSAndrzej Pietrasiewicz 	list_del(&dev->entry);
37363262ad82SJim Baxter 
373700a2430fSAndrzej Pietrasiewicz 	kfree(dev);
373800a2430fSAndrzej Pietrasiewicz 	if (list_empty(&ffs_devices))
373900a2430fSAndrzej Pietrasiewicz 		functionfs_cleanup();
374000a2430fSAndrzej Pietrasiewicz }
374100a2430fSAndrzej Pietrasiewicz 
3742ecfbd7b9SAndrew Gabbasov static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
374300a2430fSAndrzej Pietrasiewicz {
3744ecfbd7b9SAndrew Gabbasov 	int ret = 0;
374500a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *ffs_dev;
374600a2430fSAndrzej Pietrasiewicz 
374700a2430fSAndrzej Pietrasiewicz 	ENTER();
374800a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
374900a2430fSAndrzej Pietrasiewicz 
375000a2430fSAndrzej Pietrasiewicz 	ffs_dev = _ffs_find_dev(dev_name);
3751ecfbd7b9SAndrew Gabbasov 	if (!ffs_dev) {
3752ecfbd7b9SAndrew Gabbasov 		ret = -ENOENT;
3753ecfbd7b9SAndrew Gabbasov 	} else if (ffs_dev->mounted) {
3754ecfbd7b9SAndrew Gabbasov 		ret = -EBUSY;
3755ecfbd7b9SAndrew Gabbasov 	} else if (ffs_dev->ffs_acquire_dev_callback &&
3756ecfbd7b9SAndrew Gabbasov 		   ffs_dev->ffs_acquire_dev_callback(ffs_dev)) {
3757ecfbd7b9SAndrew Gabbasov 		ret = -ENOENT;
3758ecfbd7b9SAndrew Gabbasov 	} else {
375900a2430fSAndrzej Pietrasiewicz 		ffs_dev->mounted = true;
3760ecfbd7b9SAndrew Gabbasov 		ffs_dev->ffs_data = ffs_data;
3761ecfbd7b9SAndrew Gabbasov 		ffs_data->private_data = ffs_dev;
376200a2430fSAndrzej Pietrasiewicz 	}
376300a2430fSAndrzej Pietrasiewicz 
3764ecfbd7b9SAndrew Gabbasov 	ffs_dev_unlock();
3765ecfbd7b9SAndrew Gabbasov 	return ret;
3766ecfbd7b9SAndrew Gabbasov }
376700a2430fSAndrzej Pietrasiewicz 
3768ecfbd7b9SAndrew Gabbasov static void ffs_release_dev(struct ffs_dev *ffs_dev)
3769ecfbd7b9SAndrew Gabbasov {
377000a2430fSAndrzej Pietrasiewicz 	ENTER();
377100a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
377200a2430fSAndrzej Pietrasiewicz 
3773ecfbd7b9SAndrew Gabbasov 	if (ffs_dev && ffs_dev->mounted) {
377400a2430fSAndrzej Pietrasiewicz 		ffs_dev->mounted = false;
3775ecfbd7b9SAndrew Gabbasov 		if (ffs_dev->ffs_data) {
3776ecfbd7b9SAndrew Gabbasov 			ffs_dev->ffs_data->private_data = NULL;
3777ecfbd7b9SAndrew Gabbasov 			ffs_dev->ffs_data = NULL;
3778ecfbd7b9SAndrew Gabbasov 		}
377900a2430fSAndrzej Pietrasiewicz 
378000a2430fSAndrzej Pietrasiewicz 		if (ffs_dev->ffs_release_dev_callback)
378100a2430fSAndrzej Pietrasiewicz 			ffs_dev->ffs_release_dev_callback(ffs_dev);
378200a2430fSAndrzej Pietrasiewicz 	}
378300a2430fSAndrzej Pietrasiewicz 
378400a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
378500a2430fSAndrzej Pietrasiewicz }
378600a2430fSAndrzej Pietrasiewicz 
378700a2430fSAndrzej Pietrasiewicz static int ffs_ready(struct ffs_data *ffs)
378800a2430fSAndrzej Pietrasiewicz {
378900a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *ffs_obj;
379000a2430fSAndrzej Pietrasiewicz 	int ret = 0;
379100a2430fSAndrzej Pietrasiewicz 
379200a2430fSAndrzej Pietrasiewicz 	ENTER();
379300a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
379400a2430fSAndrzej Pietrasiewicz 
379500a2430fSAndrzej Pietrasiewicz 	ffs_obj = ffs->private_data;
379600a2430fSAndrzej Pietrasiewicz 	if (!ffs_obj) {
379700a2430fSAndrzej Pietrasiewicz 		ret = -EINVAL;
379800a2430fSAndrzej Pietrasiewicz 		goto done;
379900a2430fSAndrzej Pietrasiewicz 	}
380000a2430fSAndrzej Pietrasiewicz 	if (WARN_ON(ffs_obj->desc_ready)) {
380100a2430fSAndrzej Pietrasiewicz 		ret = -EBUSY;
380200a2430fSAndrzej Pietrasiewicz 		goto done;
380300a2430fSAndrzej Pietrasiewicz 	}
380400a2430fSAndrzej Pietrasiewicz 
380500a2430fSAndrzej Pietrasiewicz 	ffs_obj->desc_ready = true;
380600a2430fSAndrzej Pietrasiewicz 
380749a79d8bSKrzysztof Opasiak 	if (ffs_obj->ffs_ready_callback) {
380800a2430fSAndrzej Pietrasiewicz 		ret = ffs_obj->ffs_ready_callback(ffs);
380949a79d8bSKrzysztof Opasiak 		if (ret)
381049a79d8bSKrzysztof Opasiak 			goto done;
381149a79d8bSKrzysztof Opasiak 	}
381200a2430fSAndrzej Pietrasiewicz 
381349a79d8bSKrzysztof Opasiak 	set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
381400a2430fSAndrzej Pietrasiewicz done:
381500a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
381600a2430fSAndrzej Pietrasiewicz 	return ret;
381700a2430fSAndrzej Pietrasiewicz }
381800a2430fSAndrzej Pietrasiewicz 
381900a2430fSAndrzej Pietrasiewicz static void ffs_closed(struct ffs_data *ffs)
382000a2430fSAndrzej Pietrasiewicz {
382100a2430fSAndrzej Pietrasiewicz 	struct ffs_dev *ffs_obj;
3822f14e9ad1SRui Miguel Silva 	struct f_fs_opts *opts;
3823b3ce3ce0SBaolin Wang 	struct config_item *ci;
382400a2430fSAndrzej Pietrasiewicz 
382500a2430fSAndrzej Pietrasiewicz 	ENTER();
382600a2430fSAndrzej Pietrasiewicz 	ffs_dev_lock();
382700a2430fSAndrzej Pietrasiewicz 
382800a2430fSAndrzej Pietrasiewicz 	ffs_obj = ffs->private_data;
382900a2430fSAndrzej Pietrasiewicz 	if (!ffs_obj)
383000a2430fSAndrzej Pietrasiewicz 		goto done;
383100a2430fSAndrzej Pietrasiewicz 
383200a2430fSAndrzej Pietrasiewicz 	ffs_obj->desc_ready = false;
383300a2430fSAndrzej Pietrasiewicz 
383449a79d8bSKrzysztof Opasiak 	if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
383549a79d8bSKrzysztof Opasiak 	    ffs_obj->ffs_closed_callback)
383600a2430fSAndrzej Pietrasiewicz 		ffs_obj->ffs_closed_callback(ffs);
383700a2430fSAndrzej Pietrasiewicz 
3838f14e9ad1SRui Miguel Silva 	if (ffs_obj->opts)
3839f14e9ad1SRui Miguel Silva 		opts = ffs_obj->opts;
3840f14e9ad1SRui Miguel Silva 	else
3841f14e9ad1SRui Miguel Silva 		goto done;
3842f14e9ad1SRui Miguel Silva 
3843f14e9ad1SRui Miguel Silva 	if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent
38442c935bc5SPeter Zijlstra 	    || !kref_read(&opts->func_inst.group.cg_item.ci_kref))
384500a2430fSAndrzej Pietrasiewicz 		goto done;
384600a2430fSAndrzej Pietrasiewicz 
3847b3ce3ce0SBaolin Wang 	ci = opts->func_inst.group.cg_item.ci_parent->ci_parent;
3848b3ce3ce0SBaolin Wang 	ffs_dev_unlock();
3849b3ce3ce0SBaolin Wang 
3850ce5bf9a5SHemant Kumar 	if (test_bit(FFS_FL_BOUND, &ffs->flags))
3851b3ce3ce0SBaolin Wang 		unregister_gadget_item(ci);
3852b3ce3ce0SBaolin Wang 	return;
385300a2430fSAndrzej Pietrasiewicz done:
385400a2430fSAndrzej Pietrasiewicz 	ffs_dev_unlock();
385500a2430fSAndrzej Pietrasiewicz }
385600a2430fSAndrzej Pietrasiewicz 
385700a2430fSAndrzej Pietrasiewicz /* Misc helper functions ****************************************************/
385800a2430fSAndrzej Pietrasiewicz 
385900a2430fSAndrzej Pietrasiewicz static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
386000a2430fSAndrzej Pietrasiewicz {
386100a2430fSAndrzej Pietrasiewicz 	return nonblock
38628704fd73SGreg Kroah-Hartman 		? mutex_trylock(mutex) ? 0 : -EAGAIN
386300a2430fSAndrzej Pietrasiewicz 		: mutex_lock_interruptible(mutex);
386400a2430fSAndrzej Pietrasiewicz }
386500a2430fSAndrzej Pietrasiewicz 
386600a2430fSAndrzej Pietrasiewicz static char *ffs_prepare_buffer(const char __user *buf, size_t len)
386700a2430fSAndrzej Pietrasiewicz {
386800a2430fSAndrzej Pietrasiewicz 	char *data;
386900a2430fSAndrzej Pietrasiewicz 
38708704fd73SGreg Kroah-Hartman 	if (!len)
387100a2430fSAndrzej Pietrasiewicz 		return NULL;
387200a2430fSAndrzej Pietrasiewicz 
387342343207Skernel test robot 	data = memdup_user(buf, len);
387442343207Skernel test robot 	if (IS_ERR(data))
387590059e93SSalah Triki 		return data;
387600a2430fSAndrzej Pietrasiewicz 
387700a2430fSAndrzej Pietrasiewicz 	pr_vdebug("Buffer from user space:\n");
387800a2430fSAndrzej Pietrasiewicz 	ffs_dump_mem("", data, len);
387900a2430fSAndrzej Pietrasiewicz 
388000a2430fSAndrzej Pietrasiewicz 	return data;
388100a2430fSAndrzej Pietrasiewicz }
388200a2430fSAndrzej Pietrasiewicz 
388300a2430fSAndrzej Pietrasiewicz DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
388400a2430fSAndrzej Pietrasiewicz MODULE_LICENSE("GPL");
388500a2430fSAndrzej Pietrasiewicz MODULE_AUTHOR("Michal Nazarewicz");
3886