162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * f_fs.c -- user mode file system API for USB composite function controllers
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2010 Samsung Electronics
662306a36Sopenharmony_ci * Author: Michal Nazarewicz <mina86@mina86.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based on inode.c (GadgetFS) which was:
962306a36Sopenharmony_ci * Copyright (C) 2003-2004 David Brownell
1062306a36Sopenharmony_ci * Copyright (C) 2003 Agilent Technologies
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/* #define DEBUG */
1462306a36Sopenharmony_ci/* #define VERBOSE_DEBUG */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/export.h>
1762306a36Sopenharmony_ci#include <linux/hid.h>
1862306a36Sopenharmony_ci#include <linux/miscdevice.h>
1962306a36Sopenharmony_ci#include <linux/usb/functionfs.h>
2062306a36Sopenharmony_ci#include <linux/kfifo.h>
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci#include <linux/poll.h>
2362306a36Sopenharmony_ci#include <linux/eventfd.h>
2462306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2562306a36Sopenharmony_ci#include <linux/usb/cdc.h>
2662306a36Sopenharmony_ci#include <linux/interrupt.h>
2762306a36Sopenharmony_ci#include "u_generic.h"
2862306a36Sopenharmony_ci#include "u_f.h"
2962306a36Sopenharmony_ci#include "u_os_desc.h"
3062306a36Sopenharmony_ci#include "configfs.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define FUNCTIONFS_MAGIC    0xa647361 /* Chosen by a honest dice roll ;) */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Reference counter handling */
3562306a36Sopenharmony_cistatic void ffs_data_get(struct ffs_data *ffs);
3662306a36Sopenharmony_cistatic void ffs_data_put(struct ffs_data *ffs);
3762306a36Sopenharmony_ci/* Creates new ffs_data object. */
3862306a36Sopenharmony_cistatic struct ffs_data *__must_check ffs_data_new(const char *dev_name)
3962306a36Sopenharmony_ci    __attribute__((malloc));
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* Called with ffs->mutex held; take over ownership of data. */
4262306a36Sopenharmony_cistatic int __must_check
4362306a36Sopenharmony_ci__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
4462306a36Sopenharmony_cistatic int __must_check
4562306a36Sopenharmony_ci__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* The function structure ***************************************************/
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistruct ffs_ep;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistruct ffs_function {
5262306a36Sopenharmony_ci    struct usb_configuration    *conf;
5362306a36Sopenharmony_ci    struct usb_gadget        *gadget;
5462306a36Sopenharmony_ci    struct ffs_data            *ffs;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci    struct ffs_ep            *eps;
5762306a36Sopenharmony_ci    u8                eps_revmap[16];
5862306a36Sopenharmony_ci    short                *interfaces_nums;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci    struct usb_function        function;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_cistatic struct ffs_function *ffs_func_from_usb(struct usb_function *f)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci    return container_of(f, struct ffs_function, function);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_cistatic inline enum ffs_setup_state ffs_setup_state_clear_cancelled(struct ffs_data *ffs)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci    return (enum ffs_setup_state)
6962306a36Sopenharmony_ci        cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_cistatic void ffs_func_eps_disable(struct ffs_function *func);
7262306a36Sopenharmony_cistatic int __must_check ffs_func_eps_enable(struct ffs_function *func);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int ffs_func_bind(struct usb_configuration *,
7562306a36Sopenharmony_ci             struct usb_function *);
7662306a36Sopenharmony_cistatic int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
7762306a36Sopenharmony_cistatic void ffs_func_disable(struct usb_function *);
7862306a36Sopenharmony_cistatic int ffs_func_setup(struct usb_function *,
7962306a36Sopenharmony_ci              const struct usb_ctrlrequest *);
8062306a36Sopenharmony_cistatic bool ffs_func_req_match(struct usb_function *,
8162306a36Sopenharmony_ci                   const struct usb_ctrlrequest *,
8262306a36Sopenharmony_ci                   bool config0);
8362306a36Sopenharmony_cistatic void ffs_func_suspend(struct usb_function *);
8462306a36Sopenharmony_cistatic void ffs_func_resume(struct usb_function *);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
8762306a36Sopenharmony_cistatic int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* The endpoints structures *************************************************/
9062306a36Sopenharmony_cistruct ffs_ep {
9162306a36Sopenharmony_ci    struct usb_ep            *ep;    /* P: ffs->eps_lock */
9262306a36Sopenharmony_ci    struct usb_request        *req;    /* P: epfile->mutex */
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci    /* [0]: full speed, [1]: high speed, [2]: super speed */
9562306a36Sopenharmony_ci    struct usb_endpoint_descriptor    *descs[3];
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci    u8                num;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci    int                status;    /* P: epfile->mutex */
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct ffs_epfile {
10362306a36Sopenharmony_ci    /* Protects ep->ep and ep->req. */
10462306a36Sopenharmony_ci    struct mutex            mutex;
10562306a36Sopenharmony_ci    struct list_head         memory_list;
10662306a36Sopenharmony_ci    struct ffs_data            *ffs;
10762306a36Sopenharmony_ci    struct ffs_ep            *ep;    /* P: ffs->eps_lock */
10862306a36Sopenharmony_ci    /*
10962306a36Sopenharmony_ci     * Buffer for holding data from partial reads which may happen since
11062306a36Sopenharmony_ci     * we’re rounding user read requests to a multiple of a max packet size.
11162306a36Sopenharmony_ci     *
11262306a36Sopenharmony_ci     * The pointer is initialised with NULL value and may be set by
11362306a36Sopenharmony_ci     * __ffs_epfile_read_data function to point to a temporary buffer.
11462306a36Sopenharmony_ci     *
11562306a36Sopenharmony_ci     * In normal operation, calls to __ffs_epfile_read_buffered will consume
11662306a36Sopenharmony_ci     * data from said buffer and eventually free it.  Importantly, while the
11762306a36Sopenharmony_ci     * function is using the buffer, it sets the pointer to NULL.  This is
11862306a36Sopenharmony_ci     * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered
11962306a36Sopenharmony_ci     * can never run concurrently (they are synchronised by epfile->mutex)
12062306a36Sopenharmony_ci     * so the latter will not assign a new value to the pointer.
12162306a36Sopenharmony_ci     *
12262306a36Sopenharmony_ci     * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is
12362306a36Sopenharmony_ci     * valid) and sets the pointer to READ_BUFFER_DROP value.  This special
12462306a36Sopenharmony_ci     * value is crux of the synchronisation between ffs_func_eps_disable and
12562306a36Sopenharmony_ci     * __ffs_epfile_read_data.
12662306a36Sopenharmony_ci     *
12762306a36Sopenharmony_ci     * Once __ffs_epfile_read_data is about to finish it will try to set the
12862306a36Sopenharmony_ci     * pointer back to its old value (as described above), but seeing as the
12962306a36Sopenharmony_ci     * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free
13062306a36Sopenharmony_ci     * the buffer.
13162306a36Sopenharmony_ci     *
13262306a36Sopenharmony_ci     * == State transitions ==
13362306a36Sopenharmony_ci     *
13462306a36Sopenharmony_ci     * • ptr == NULL:  (initial state)
13562306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP
13662306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffered:    nop
13762306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf
13862306a36Sopenharmony_ci     *   ◦ reading finishes:              n/a, not in ‘and reading’ state
13962306a36Sopenharmony_ci     * • ptr == DROP:
14062306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffer_free: nop
14162306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffered:    go to ptr == NULL
14262306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop
14362306a36Sopenharmony_ci     *   ◦ reading finishes:              n/a, not in ‘and reading’ state
14462306a36Sopenharmony_ci     * • ptr == buf:
14562306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP
14662306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffered:    go to ptr == NULL and reading
14762306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_data:        n/a, __ffs_epfile_read_buffered
14862306a36Sopenharmony_ci     *                                    is always called first
14962306a36Sopenharmony_ci     *   ◦ reading finishes:              n/a, not in ‘and reading’ state
15062306a36Sopenharmony_ci     * • ptr == NULL and reading:
15162306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading
15262306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffered:    n/a, mutex is held
15362306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_data:        n/a, mutex is held
15462306a36Sopenharmony_ci     *   ◦ reading finishes and …
15562306a36Sopenharmony_ci     *     … all data read:               free buf, go to ptr == NULL
15662306a36Sopenharmony_ci     *     … otherwise:                   go to ptr == buf and reading
15762306a36Sopenharmony_ci     * • ptr == DROP and reading:
15862306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffer_free: nop
15962306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_buffered:    n/a, mutex is held
16062306a36Sopenharmony_ci     *   ◦ __ffs_epfile_read_data:        n/a, mutex is held
16162306a36Sopenharmony_ci     *   ◦ reading finishes:              free buf, go to ptr == DROP
16262306a36Sopenharmony_ci     */
16362306a36Sopenharmony_ci    struct ffs_buffer        *read_buffer;
16462306a36Sopenharmony_ci#define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN))
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci    char                name[MAX_NAMELEN];
16762306a36Sopenharmony_ci    dev_t                devno;
16862306a36Sopenharmony_ci    struct cdev         cdev;
16962306a36Sopenharmony_ci    struct device         *device;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci    unsigned char            in;    /* P: ffs->eps_lock */
17262306a36Sopenharmony_ci    unsigned char            isoc;    /* P: ffs->eps_lock */
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci    struct kfifo        reqEventFifo;
17562306a36Sopenharmony_ci    wait_queue_head_t   wait_que;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci    unsigned char            _pad;
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistruct ffs_buffer {
18162306a36Sopenharmony_ci    size_t length;
18262306a36Sopenharmony_ci    char *data;
18362306a36Sopenharmony_ci    char storage[];
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/*  ffs_io_data structure ***************************************************/
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistruct ffs_io_data {
18962306a36Sopenharmony_ci    uint32_t aio;
19062306a36Sopenharmony_ci    uint32_t read;
19162306a36Sopenharmony_ci    uint32_t len;
19262306a36Sopenharmony_ci    uint32_t timeout;
19362306a36Sopenharmony_ci    uint64_t buf;
19462306a36Sopenharmony_ci    uint32_t actual;
19562306a36Sopenharmony_ci    int      status;
19662306a36Sopenharmony_ci    struct tasklet_struct task;
19762306a36Sopenharmony_ci    struct usb_ep *ep;
19862306a36Sopenharmony_ci    struct usb_request *req;
19962306a36Sopenharmony_ci    struct ffs_epfile *epfile;
20062306a36Sopenharmony_ci    struct ffs_data *ffs;
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistruct ffs_desc_helper {
20462306a36Sopenharmony_ci    struct ffs_data *ffs;
20562306a36Sopenharmony_ci    unsigned interfaces_count;
20662306a36Sopenharmony_ci    unsigned eps_count;
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int  __must_check ffs_epfiles_create(struct ffs_data *ffs);
21062306a36Sopenharmony_cistatic void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/* Devices management *******************************************************/
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciDEFINE_MUTEX(ffs_lock_adapter);
21562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ffs_lock_adapter);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic struct ffs_dev *_ffs_find_dev(const char *name);
21862306a36Sopenharmony_cistatic struct ffs_dev *_ffs_alloc_dev(void);
21962306a36Sopenharmony_cistatic void _ffs_free_dev(struct ffs_dev *dev);
22062306a36Sopenharmony_cistatic void *ffs_acquire_dev(const char *dev_name);
22162306a36Sopenharmony_cistatic void ffs_release_dev(struct ffs_data *ffs_data);
22262306a36Sopenharmony_cistatic int ffs_ready(struct ffs_data *ffs);
22362306a36Sopenharmony_cistatic void ffs_closed(struct ffs_data *ffs);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* Misc helper functions ****************************************************/
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
22862306a36Sopenharmony_ci    __attribute__((warn_unused_result, nonnull));
22962306a36Sopenharmony_cistatic char *ffs_prepare_buffer(const char __user *buf, size_t len)
23062306a36Sopenharmony_ci    __attribute__((warn_unused_result, nonnull));
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistruct class *ffs_class;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic char *ffs_devnode(const struct device *dev, umode_t *mode)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci    if (mode)
23762306a36Sopenharmony_ci        *mode = 0666;
23862306a36Sopenharmony_ci    return kasprintf(GFP_KERNEL, "functionfs/%s", dev_name(dev));
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/* Control file aka ep0 *****************************************************/
24262306a36Sopenharmony_cistatic struct ffs_memory *generic_find_ep0_memory_area(struct ffs_data *ffs, uint64_t buf, uint32_t len)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci    struct ffs_memory *ffsm = NULL;
24562306a36Sopenharmony_ci    struct ffs_memory *iter = NULL;
24662306a36Sopenharmony_ci    uint64_t buf_start = buf;
24762306a36Sopenharmony_ci    unsigned long flags;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci    spin_lock_irqsave(&ffs->mem_lock, flags);
25062306a36Sopenharmony_ci    list_for_each_entry(iter, &ffs->memory_list, memlist) {
25162306a36Sopenharmony_ci        if (buf_start >= iter->vm_start &&
25262306a36Sopenharmony_ci            buf_start < iter->vm_start + iter->size) {
25362306a36Sopenharmony_ci            if (len <= iter->vm_start + iter->size - buf_start) {
25462306a36Sopenharmony_ci                ffsm = iter;
25562306a36Sopenharmony_ci                break;
25662306a36Sopenharmony_ci            }
25762306a36Sopenharmony_ci        }
25862306a36Sopenharmony_ci    }
25962306a36Sopenharmony_ci    spin_unlock_irqrestore(&ffs->mem_lock, flags);
26062306a36Sopenharmony_ci    return ffsm;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci    struct ffs_data *ffs = req->context;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci    complete(&ffs->ep0req_completion);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci    ffs->setup_state = FFS_NO_SETUP;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void ffs_ep0_async_io_complete(struct usb_ep *_ep, struct usb_request *req)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci    struct ffs_io_data *io_data = req->context;
27562306a36Sopenharmony_ci    struct ffs_data *ffs = io_data->ffs;
27662306a36Sopenharmony_ci    ENTER();
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci    io_data->status = io_data->req->status;
27962306a36Sopenharmony_ci    io_data->actual = io_data->req->actual;
28062306a36Sopenharmony_ci    kfifo_in(&ffs->reqEventFifo, &io_data->buf, sizeof(struct UsbFnReqEvent));
28162306a36Sopenharmony_ci    wake_up_all(&ffs->wait_que);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci    list_del(&req->list);
28462306a36Sopenharmony_ci    usb_ep_free_request(io_data->ep, io_data->req);
28562306a36Sopenharmony_ci    kfree(io_data);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
29062306a36Sopenharmony_ci    __releases(&ffs->ev.waitq.lock)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci    struct usb_request *req = ffs->ep0req;
29362306a36Sopenharmony_ci    int ret;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci    req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci    spin_unlock_irq(&ffs->ev.waitq.lock);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci    req->buf      = data;
30062306a36Sopenharmony_ci    req->length   = len;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci    /*
30362306a36Sopenharmony_ci     * UDC layer requires to provide a buffer even for ZLP, but should
30462306a36Sopenharmony_ci     * not use it at all. Let's provide some poisoned pointer to catch
30562306a36Sopenharmony_ci     * possible bug in the driver.
30662306a36Sopenharmony_ci     */
30762306a36Sopenharmony_ci    if (req->buf == NULL)
30862306a36Sopenharmony_ci        req->buf = (void *)0xDEADBABE;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci    reinit_completion(&ffs->ep0req_completion);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci    ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
31362306a36Sopenharmony_ci    if (unlikely(ret < 0))
31462306a36Sopenharmony_ci        return ret;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci    ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
31762306a36Sopenharmony_ci    if (unlikely(ret)) {
31862306a36Sopenharmony_ci        usb_ep_dequeue(ffs->gadget->ep0, req);
31962306a36Sopenharmony_ci        return -EINTR;
32062306a36Sopenharmony_ci    }
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci    ffs->setup_state = FFS_NO_SETUP;
32362306a36Sopenharmony_ci    return req->status ? req->status : req->actual;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic int __ffs_ep0_stall(struct ffs_data *ffs)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci    if (ffs->ev.can_stall) {
32962306a36Sopenharmony_ci        pr_vdebug("ep0 stall\n");
33062306a36Sopenharmony_ci        usb_ep_set_halt(ffs->gadget->ep0);
33162306a36Sopenharmony_ci        ffs->setup_state = FFS_NO_SETUP;
33262306a36Sopenharmony_ci        return -EL2HLT;
33362306a36Sopenharmony_ci    } else {
33462306a36Sopenharmony_ci        pr_debug("bogus ep0 stall!\n");
33562306a36Sopenharmony_ci        return -ESRCH;
33662306a36Sopenharmony_ci    }
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic ssize_t ffs_ep0_write(struct file *file, const char __user *buf, size_t len, loff_t *ptr)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci    struct ffs_data *ffs = file->private_data;
34262306a36Sopenharmony_ci    ssize_t ret;
34362306a36Sopenharmony_ci    char *data = NULL;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci    ENTER();
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci    /* Fast check if setup was canceled */
34862306a36Sopenharmony_ci    if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
34962306a36Sopenharmony_ci        return -EIDRM;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci    /* Acquire mutex */
35262306a36Sopenharmony_ci    ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
35362306a36Sopenharmony_ci    if (unlikely(ret < 0))
35462306a36Sopenharmony_ci        return ret;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci    /* Check state */
35762306a36Sopenharmony_ci    switch (ffs->state) {
35862306a36Sopenharmony_ci    case FFS_READ_DESCRIPTORS:
35962306a36Sopenharmony_ci    case FFS_READ_STRINGS:
36062306a36Sopenharmony_ci        /* Copy data */
36162306a36Sopenharmony_ci        if (unlikely(len < 16)) {
36262306a36Sopenharmony_ci            ret = -EINVAL;
36362306a36Sopenharmony_ci            break;
36462306a36Sopenharmony_ci        }
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci        data = ffs_prepare_buffer(buf, len);
36762306a36Sopenharmony_ci        if (IS_ERR(data)) {
36862306a36Sopenharmony_ci            ret = PTR_ERR(data);
36962306a36Sopenharmony_ci            break;
37062306a36Sopenharmony_ci        }
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci        /* Handle data */
37362306a36Sopenharmony_ci        if (ffs->state == FFS_READ_DESCRIPTORS) {
37462306a36Sopenharmony_ci            pr_info("read descriptors\n");
37562306a36Sopenharmony_ci            ret = __ffs_data_got_descs(ffs, data, len);
37662306a36Sopenharmony_ci            if (unlikely(ret < 0))
37762306a36Sopenharmony_ci                break;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci            ffs->state = FFS_READ_STRINGS;
38062306a36Sopenharmony_ci            ret = len;
38162306a36Sopenharmony_ci        } else {
38262306a36Sopenharmony_ci            pr_info("read strings\n");
38362306a36Sopenharmony_ci            ret = __ffs_data_got_strings(ffs, data, len);
38462306a36Sopenharmony_ci            if (unlikely(ret < 0))
38562306a36Sopenharmony_ci                break;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci            ret = ffs_epfiles_create(ffs);
38862306a36Sopenharmony_ci            if (unlikely(ret)) {
38962306a36Sopenharmony_ci                ffs->state = FFS_CLOSING;
39062306a36Sopenharmony_ci                break;
39162306a36Sopenharmony_ci            }
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci            ffs->state = FFS_ACTIVE;
39462306a36Sopenharmony_ci            mutex_unlock(&ffs->mutex);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci            ret = ffs_ready(ffs);
39762306a36Sopenharmony_ci            if (unlikely(ret < 0)) {
39862306a36Sopenharmony_ci                ffs->state = FFS_CLOSING;
39962306a36Sopenharmony_ci                return ret;
40062306a36Sopenharmony_ci            }
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci            return len;
40362306a36Sopenharmony_ci        }
40462306a36Sopenharmony_ci        break;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci    case FFS_ACTIVE:
40762306a36Sopenharmony_ci        data = NULL;
40862306a36Sopenharmony_ci        /*
40962306a36Sopenharmony_ci         * We're called from user space, we can use _irq
41062306a36Sopenharmony_ci         * rather then _irqsave
41162306a36Sopenharmony_ci         */
41262306a36Sopenharmony_ci        spin_lock_irq(&ffs->ev.waitq.lock);
41362306a36Sopenharmony_ci        switch (ffs_setup_state_clear_cancelled(ffs)) {
41462306a36Sopenharmony_ci        case FFS_SETUP_CANCELLED:
41562306a36Sopenharmony_ci            ret = -EIDRM;
41662306a36Sopenharmony_ci            goto done_spin;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci        case FFS_NO_SETUP:
41962306a36Sopenharmony_ci            ret = -ESRCH;
42062306a36Sopenharmony_ci            goto done_spin;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci        case FFS_SETUP_PENDING:
42362306a36Sopenharmony_ci            break;
42462306a36Sopenharmony_ci        }
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci        /* FFS_SETUP_PENDING */
42762306a36Sopenharmony_ci        if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
42862306a36Sopenharmony_ci            spin_unlock_irq(&ffs->ev.waitq.lock);
42962306a36Sopenharmony_ci            ret = __ffs_ep0_stall(ffs);
43062306a36Sopenharmony_ci            break;
43162306a36Sopenharmony_ci        }
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci        /* FFS_SETUP_PENDING and not stall */
43462306a36Sopenharmony_ci        len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci        spin_unlock_irq(&ffs->ev.waitq.lock);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci        data = ffs_prepare_buffer(buf, len);
43962306a36Sopenharmony_ci        if (IS_ERR(data)) {
44062306a36Sopenharmony_ci            ret = PTR_ERR(data);
44162306a36Sopenharmony_ci            break;
44262306a36Sopenharmony_ci        }
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci        spin_lock_irq(&ffs->ev.waitq.lock);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci        /*
44762306a36Sopenharmony_ci         * We are guaranteed to be still in FFS_ACTIVE state
44862306a36Sopenharmony_ci         * but the state of setup could have changed from
44962306a36Sopenharmony_ci         * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need
45062306a36Sopenharmony_ci         * to check for that.  If that happened we copied data
45162306a36Sopenharmony_ci         * from user space in vain but it's unlikely.
45262306a36Sopenharmony_ci         *
45362306a36Sopenharmony_ci         * For sure we are not in FFS_NO_SETUP since this is
45462306a36Sopenharmony_ci         * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
45562306a36Sopenharmony_ci         * transition can be performed and it's protected by
45662306a36Sopenharmony_ci         * mutex.
45762306a36Sopenharmony_ci         */
45862306a36Sopenharmony_ci        if (ffs_setup_state_clear_cancelled(ffs) ==
45962306a36Sopenharmony_ci                FFS_SETUP_CANCELLED) {
46062306a36Sopenharmony_ci                ret = -EIDRM;
46162306a36Sopenharmony_cidone_spin:
46262306a36Sopenharmony_ci            spin_unlock_irq(&ffs->ev.waitq.lock);
46362306a36Sopenharmony_ci        } else {
46462306a36Sopenharmony_ci            /* unlocks spinlock */
46562306a36Sopenharmony_ci            ret = __ffs_ep0_queue_wait(ffs, data, len);
46662306a36Sopenharmony_ci        }
46762306a36Sopenharmony_ci        kfree(data);
46862306a36Sopenharmony_ci        break;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci    default:
47162306a36Sopenharmony_ci        ret = -EBADFD;
47262306a36Sopenharmony_ci        break;
47362306a36Sopenharmony_ci    }
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci    mutex_unlock(&ffs->mutex);
47662306a36Sopenharmony_ci    return ret;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
48062306a36Sopenharmony_cistatic ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, size_t n)
48162306a36Sopenharmony_ci    __releases(&ffs->ev.waitq.lock)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci    /*
48462306a36Sopenharmony_ci     * n cannot be bigger than ffs->ev.count, which cannot be bigger than
48562306a36Sopenharmony_ci     * size of ffs->ev.types array (which is four) so that's how much space
48662306a36Sopenharmony_ci     * we reserve.
48762306a36Sopenharmony_ci     */
48862306a36Sopenharmony_ci    struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
48962306a36Sopenharmony_ci    const size_t size = n * sizeof *events;
49062306a36Sopenharmony_ci    unsigned i = 0;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci    memset(events, 0, size);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci    do {
49562306a36Sopenharmony_ci        events[i].type = ffs->ev.types[i];
49662306a36Sopenharmony_ci        if (events[i].type == FUNCTIONFS_SETUP) {
49762306a36Sopenharmony_ci            events[i].u.setup = ffs->ev.setup;
49862306a36Sopenharmony_ci            ffs->setup_state = FFS_SETUP_PENDING;
49962306a36Sopenharmony_ci        }
50062306a36Sopenharmony_ci    } while (++i < n);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci    ffs->ev.count -= n;
50362306a36Sopenharmony_ci    if (ffs->ev.count)
50462306a36Sopenharmony_ci        memmove(ffs->ev.types, ffs->ev.types + n, ffs->ev.count * sizeof *ffs->ev.types);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci    spin_unlock_irq(&ffs->ev.waitq.lock);
50762306a36Sopenharmony_ci    mutex_unlock(&ffs->mutex);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci    return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic ssize_t ffs_ep0_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci    struct ffs_data *ffs = file->private_data;
51562306a36Sopenharmony_ci    char *data = NULL;
51662306a36Sopenharmony_ci    size_t n;
51762306a36Sopenharmony_ci    int ret;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci    ENTER();
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci    /* Fast check if setup was canceled */
52262306a36Sopenharmony_ci    if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
52362306a36Sopenharmony_ci        return -EIDRM;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci    /* Acquire mutex */
52662306a36Sopenharmony_ci    ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
52762306a36Sopenharmony_ci    if (unlikely(ret < 0))
52862306a36Sopenharmony_ci        return ret;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci    /* Check state */
53162306a36Sopenharmony_ci    if (ffs->state != FFS_ACTIVE) {
53262306a36Sopenharmony_ci        ret = -EBADFD;
53362306a36Sopenharmony_ci        goto done_mutex;
53462306a36Sopenharmony_ci    }
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci    /*
53762306a36Sopenharmony_ci     * We're called from user space, we can use _irq rather then
53862306a36Sopenharmony_ci     * _irqsave
53962306a36Sopenharmony_ci     */
54062306a36Sopenharmony_ci    spin_lock_irq(&ffs->ev.waitq.lock);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci    switch (ffs_setup_state_clear_cancelled(ffs)) {
54362306a36Sopenharmony_ci    case FFS_SETUP_CANCELLED:
54462306a36Sopenharmony_ci        ret = -EIDRM;
54562306a36Sopenharmony_ci        break;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci    case FFS_NO_SETUP:
54862306a36Sopenharmony_ci        n = len / sizeof(struct usb_functionfs_event);
54962306a36Sopenharmony_ci        if (unlikely(!n)) {
55062306a36Sopenharmony_ci            ret = -EINVAL;
55162306a36Sopenharmony_ci            break;
55262306a36Sopenharmony_ci        }
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci        if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
55562306a36Sopenharmony_ci            ret = -EAGAIN;
55662306a36Sopenharmony_ci            break;
55762306a36Sopenharmony_ci        }
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci        if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
56062306a36Sopenharmony_ci                            ffs->ev.count)) {
56162306a36Sopenharmony_ci            ret = -EINTR;
56262306a36Sopenharmony_ci            break;
56362306a36Sopenharmony_ci        }
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci        /* unlocks spinlock */
56662306a36Sopenharmony_ci        return __ffs_ep0_read_events(ffs, buf,
56762306a36Sopenharmony_ci                         min(n, (size_t)ffs->ev.count));
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci    case FFS_SETUP_PENDING:
57062306a36Sopenharmony_ci        if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
57162306a36Sopenharmony_ci            spin_unlock_irq(&ffs->ev.waitq.lock);
57262306a36Sopenharmony_ci            ret = __ffs_ep0_stall(ffs);
57362306a36Sopenharmony_ci            goto done_mutex;
57462306a36Sopenharmony_ci        }
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci        len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci        spin_unlock_irq(&ffs->ev.waitq.lock);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci        if (likely(len)) {
58162306a36Sopenharmony_ci            data = kmalloc(len, GFP_KERNEL);
58262306a36Sopenharmony_ci            if (unlikely(!data)) {
58362306a36Sopenharmony_ci                ret = -ENOMEM;
58462306a36Sopenharmony_ci                goto done_mutex;
58562306a36Sopenharmony_ci            }
58662306a36Sopenharmony_ci        }
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci        spin_lock_irq(&ffs->ev.waitq.lock);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci        /* See ffs_ep0_write() */
59162306a36Sopenharmony_ci        if (ffs_setup_state_clear_cancelled(ffs) ==
59262306a36Sopenharmony_ci            FFS_SETUP_CANCELLED) {
59362306a36Sopenharmony_ci            ret = -EIDRM;
59462306a36Sopenharmony_ci            break;
59562306a36Sopenharmony_ci        }
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci        /* unlocks spinlock */
59862306a36Sopenharmony_ci        ret = __ffs_ep0_queue_wait(ffs, data, len);
59962306a36Sopenharmony_ci        if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len)))
60062306a36Sopenharmony_ci            ret = -EFAULT;
60162306a36Sopenharmony_ci        goto done_mutex;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci    default:
60462306a36Sopenharmony_ci        ret = -EBADFD;
60562306a36Sopenharmony_ci        break;
60662306a36Sopenharmony_ci    }
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci    spin_unlock_irq(&ffs->ev.waitq.lock);
60962306a36Sopenharmony_cidone_mutex:
61062306a36Sopenharmony_ci    mutex_unlock(&ffs->mutex);
61162306a36Sopenharmony_ci    kfree(data);
61262306a36Sopenharmony_ci    return ret;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic int ffs_ep0_open(struct inode *inode, struct file *file)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci    struct ffs_data *ffs  = container_of(inode->i_cdev, struct ffs_data, cdev);
61862306a36Sopenharmony_ci    ENTER();
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci    if (unlikely(ffs->state == FFS_CLOSING))
62162306a36Sopenharmony_ci        return -EBUSY;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci    file->private_data = ffs;
62462306a36Sopenharmony_ci    return 0;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic int ffs_ep0_release(struct inode *inode, struct file *file)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci    ENTER();
63062306a36Sopenharmony_ci    return 0;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic ssize_t ffs_ep0_iorw(struct file *file, struct ffs_io_data *io_data)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci    struct ffs_data *ffs = file->private_data;
63662306a36Sopenharmony_ci    struct usb_request *req = NULL;
63762306a36Sopenharmony_ci    ssize_t ret, data_len = io_data->len;
63862306a36Sopenharmony_ci    bool interrupted = false;
63962306a36Sopenharmony_ci    struct ffs_memory *ffsm = NULL;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci    /* Are we still active? */
64262306a36Sopenharmony_ci    if (WARN_ON(ffs->state != FFS_ACTIVE))
64362306a36Sopenharmony_ci        return -ENODEV;
64462306a36Sopenharmony_ci    ffsm = generic_find_ep0_memory_area(ffs, io_data->buf, data_len);
64562306a36Sopenharmony_ci    if (ffsm == NULL)
64662306a36Sopenharmony_ci    {
64762306a36Sopenharmony_ci        return -ENODEV;
64862306a36Sopenharmony_ci    }
64962306a36Sopenharmony_ci    if (!io_data->aio) {
65062306a36Sopenharmony_ci        reinit_completion(&ffs->ep0req_completion);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci        req = ffs->ep0req;
65362306a36Sopenharmony_ci        req->buf      = (void *)(ffsm->mem + io_data->buf - ffsm->vm_start);
65462306a36Sopenharmony_ci        req->length   = data_len;
65562306a36Sopenharmony_ci        req->complete = ffs_ep0_complete;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci        ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
65862306a36Sopenharmony_ci        if (unlikely(ret < 0))
65962306a36Sopenharmony_ci            goto error;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci        if (io_data->timeout > 0) {
66262306a36Sopenharmony_ci            ret = wait_for_completion_interruptible_timeout(&ffs->ep0req_completion, io_data->timeout);
66362306a36Sopenharmony_ci            if (ret < 0) {
66462306a36Sopenharmony_ci                /*
66562306a36Sopenharmony_ci                 * To avoid race condition with ffs_epfile_io_complete,
66662306a36Sopenharmony_ci                 * dequeue the request first then check
66762306a36Sopenharmony_ci                 * status. usb_ep_dequeue API should guarantee no race
66862306a36Sopenharmony_ci                 * condition with req->complete callback.
66962306a36Sopenharmony_ci                 */
67062306a36Sopenharmony_ci                usb_ep_dequeue(ffs->gadget->ep0, req);
67162306a36Sopenharmony_ci                wait_for_completion(&ffs->ep0req_completion);
67262306a36Sopenharmony_ci                interrupted = req->status < 0;
67362306a36Sopenharmony_ci            } else if (ret == 0) {
67462306a36Sopenharmony_ci                ret = -EBUSY;
67562306a36Sopenharmony_ci                usb_ep_dequeue(ffs->gadget->ep0, req);
67662306a36Sopenharmony_ci                wait_for_completion(&ffs->ep0req_completion);
67762306a36Sopenharmony_ci                goto error;
67862306a36Sopenharmony_ci            }
67962306a36Sopenharmony_ci        } else {
68062306a36Sopenharmony_ci            ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
68162306a36Sopenharmony_ci            if (ret < 0) {
68262306a36Sopenharmony_ci                usb_ep_dequeue(ffs->gadget->ep0, req);
68362306a36Sopenharmony_ci                wait_for_completion(&ffs->ep0req_completion);
68462306a36Sopenharmony_ci                interrupted = req->status < 0;
68562306a36Sopenharmony_ci            }
68662306a36Sopenharmony_ci        }
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci        if (interrupted) {
68962306a36Sopenharmony_ci            ret = -EINTR;
69062306a36Sopenharmony_ci        } else {
69162306a36Sopenharmony_ci            ret = req->actual;
69262306a36Sopenharmony_ci        }
69362306a36Sopenharmony_ci        goto error;
69462306a36Sopenharmony_ci    }
69562306a36Sopenharmony_ci    else if (!(req = usb_ep_alloc_request(ffs->gadget->ep0, GFP_ATOMIC))) {
69662306a36Sopenharmony_ci        ret = -ENOMEM;
69762306a36Sopenharmony_ci    }
69862306a36Sopenharmony_ci    else {
69962306a36Sopenharmony_ci        req->buf     = (void *)(ffsm->mem + io_data->buf - ffsm->vm_start);
70062306a36Sopenharmony_ci        req->length   = data_len;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci        io_data->ep = ffs->gadget->ep0;
70362306a36Sopenharmony_ci        io_data->req = req;
70462306a36Sopenharmony_ci        io_data->ffs = ffs;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci        req->context  = io_data;
70762306a36Sopenharmony_ci        req->complete = ffs_ep0_async_io_complete;
70862306a36Sopenharmony_ci        list_add(&req->list, &ffs->ep0req->list);
70962306a36Sopenharmony_ci        ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
71062306a36Sopenharmony_ci        if (unlikely(ret)) {
71162306a36Sopenharmony_ci            usb_ep_free_request(ffs->gadget->ep0, req);
71262306a36Sopenharmony_ci            goto error;
71362306a36Sopenharmony_ci        }
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci        ret = -EIOCBQUEUED;
71662306a36Sopenharmony_ci    }
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cierror:
71962306a36Sopenharmony_ci    return ret;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci    struct ffs_data *ffs = file->private_data;
72562306a36Sopenharmony_ci    long ret = 0;
72662306a36Sopenharmony_ci    unsigned int copied = 0;
72762306a36Sopenharmony_ci    struct ffs_memory *ffsm = NULL;
72862306a36Sopenharmony_ci    struct generic_memory mem;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci    ENTER();
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci    switch (code) {
73362306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_QUEUE_INIT:
73462306a36Sopenharmony_ci        ret = kfifo_alloc(&ffs->reqEventFifo, MAX_REQUEST * sizeof(struct UsbFnReqEvent), GFP_KERNEL);
73562306a36Sopenharmony_ci        break;
73662306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_QUEUE_DEL:
73762306a36Sopenharmony_ci        kfifo_free(&ffs->reqEventFifo);
73862306a36Sopenharmony_ci        break;
73962306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_RELEASE_BUF:
74062306a36Sopenharmony_ci        if (copy_from_user(&mem, (void __user *)value, sizeof(mem)))
74162306a36Sopenharmony_ci        {
74262306a36Sopenharmony_ci            pr_info("copy from user failed\n");
74362306a36Sopenharmony_ci            return -EFAULT;
74462306a36Sopenharmony_ci        }
74562306a36Sopenharmony_ci        ffsm = generic_find_ep0_memory_area(ffs, mem.buf, mem.size);
74662306a36Sopenharmony_ci        if (ffsm == NULL)
74762306a36Sopenharmony_ci        {
74862306a36Sopenharmony_ci            return -EFAULT;
74962306a36Sopenharmony_ci        }
75062306a36Sopenharmony_ci        list_del(&ffsm->memlist);
75162306a36Sopenharmony_ci        kfree((void *)ffsm->mem);
75262306a36Sopenharmony_ci        kfree(ffsm);
75362306a36Sopenharmony_ci        break;
75462306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_READ:
75562306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_WRITE:
75662306a36Sopenharmony_ci    {
75762306a36Sopenharmony_ci        struct IoData myIoData;
75862306a36Sopenharmony_ci        struct ffs_io_data io_data, *p = &io_data;
75962306a36Sopenharmony_ci        ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
76062306a36Sopenharmony_ci        if (unlikely(ret)) {
76162306a36Sopenharmony_ci            return -EFAULT;
76262306a36Sopenharmony_ci        }
76362306a36Sopenharmony_ci        if (myIoData.aio) {
76462306a36Sopenharmony_ci            p = kmalloc(sizeof(io_data), GFP_KERNEL);
76562306a36Sopenharmony_ci            if (unlikely(!p))
76662306a36Sopenharmony_ci                return -ENOMEM;
76762306a36Sopenharmony_ci        } else {
76862306a36Sopenharmony_ci            memset(p, 0, sizeof(*p));
76962306a36Sopenharmony_ci        }
77062306a36Sopenharmony_ci        memcpy(p, &myIoData, sizeof(struct IoData));
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci        ret = ffs_ep0_iorw(file, p);
77362306a36Sopenharmony_ci        if (ret == -EIOCBQUEUED) {
77462306a36Sopenharmony_ci            return 0;
77562306a36Sopenharmony_ci        }
77662306a36Sopenharmony_ci        if (p->aio)
77762306a36Sopenharmony_ci            kfree(p);
77862306a36Sopenharmony_ci        return ret;
77962306a36Sopenharmony_ci    }
78062306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_RW_CANCEL:
78162306a36Sopenharmony_ci    {
78262306a36Sopenharmony_ci        struct usb_request *req;
78362306a36Sopenharmony_ci        struct IoData myIoData;
78462306a36Sopenharmony_ci        ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
78562306a36Sopenharmony_ci        if (unlikely(ret)) {
78662306a36Sopenharmony_ci            return -EFAULT;
78762306a36Sopenharmony_ci        }
78862306a36Sopenharmony_ci        ffsm = generic_find_ep0_memory_area(ffs, myIoData.buf, myIoData.len);
78962306a36Sopenharmony_ci        if (ffsm == NULL)
79062306a36Sopenharmony_ci        {
79162306a36Sopenharmony_ci            return -EFAULT;
79262306a36Sopenharmony_ci        }
79362306a36Sopenharmony_ci        list_for_each_entry(req, &ffs->ep0req->list, list) {
79462306a36Sopenharmony_ci            if (req->buf == (void *)(ffsm->mem + myIoData.buf - ffsm->vm_start)) {
79562306a36Sopenharmony_ci                usb_ep_dequeue(ffs->gadget->ep0, req);
79662306a36Sopenharmony_ci                return 0;
79762306a36Sopenharmony_ci            }
79862306a36Sopenharmony_ci        }
79962306a36Sopenharmony_ci        return -EFAULT;
80062306a36Sopenharmony_ci    }
80162306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_GET_REQ_STATUS:
80262306a36Sopenharmony_ci    {
80362306a36Sopenharmony_ci        struct usb_request *req;
80462306a36Sopenharmony_ci        struct IoData myIoData;
80562306a36Sopenharmony_ci        ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
80662306a36Sopenharmony_ci        if (unlikely(ret)) {
80762306a36Sopenharmony_ci            return -EFAULT;
80862306a36Sopenharmony_ci        }
80962306a36Sopenharmony_ci        ffsm = generic_find_ep0_memory_area(ffs, myIoData.buf, myIoData.len);
81062306a36Sopenharmony_ci        if (ffsm == NULL)
81162306a36Sopenharmony_ci        {
81262306a36Sopenharmony_ci            return -EFAULT;
81362306a36Sopenharmony_ci        }
81462306a36Sopenharmony_ci        list_for_each_entry(req, &ffs->ep0req->list, list) {
81562306a36Sopenharmony_ci            if (req->buf == (void *)(ffsm->mem + myIoData.buf - ffsm->vm_start)) {
81662306a36Sopenharmony_ci                return req->status;
81762306a36Sopenharmony_ci            }
81862306a36Sopenharmony_ci        }
81962306a36Sopenharmony_ci        return -EFAULT;
82062306a36Sopenharmony_ci    }
82162306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_GET_EP0_EVENT:
82262306a36Sopenharmony_ci        if (!kfifo_is_empty(&ffs->reqEventFifo)) {
82362306a36Sopenharmony_ci            ret = kfifo_to_user(&ffs->reqEventFifo, (void __user *)value,
82462306a36Sopenharmony_ci            sizeof(struct UsbFnReqEvent), &copied) == 0 ? copied : -1;
82562306a36Sopenharmony_ci            if (ret > 0) {
82662306a36Sopenharmony_ci                ffs->setup_state = FFS_NO_SETUP;
82762306a36Sopenharmony_ci                return ret;
82862306a36Sopenharmony_ci            }
82962306a36Sopenharmony_ci        }
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci        return -EFAULT;
83262306a36Sopenharmony_ci    }
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci    return ret;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
83862306a36Sopenharmony_cistatic long ffs_ep0_compat_ioctl(struct file *file, unsigned code,
83962306a36Sopenharmony_ci        unsigned long value)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci    return ffs_ep0_ioctl(file, code, value);
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci#endif
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic __poll_t ffs_ep0_poll(struct file *file, poll_table *wait)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci    struct ffs_data *ffs = file->private_data;
84862306a36Sopenharmony_ci    __poll_t mask = EPOLLWRNORM;
84962306a36Sopenharmony_ci    int ret;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci    ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
85262306a36Sopenharmony_ci    if (unlikely(ret < 0))
85362306a36Sopenharmony_ci        return mask;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci    switch (ffs->state) {
85662306a36Sopenharmony_ci    case FFS_READ_DESCRIPTORS:
85762306a36Sopenharmony_ci    case FFS_READ_STRINGS:
85862306a36Sopenharmony_ci        mask |= EPOLLOUT;
85962306a36Sopenharmony_ci        break;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci    case FFS_ACTIVE:
86262306a36Sopenharmony_ci        switch (ffs->setup_state) {
86362306a36Sopenharmony_ci        case FFS_NO_SETUP:
86462306a36Sopenharmony_ci            poll_wait(file, &ffs->ev.waitq, wait);
86562306a36Sopenharmony_ci            if (ffs->ev.count)
86662306a36Sopenharmony_ci                mask |= EPOLLIN;
86762306a36Sopenharmony_ci            break;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci        case FFS_SETUP_PENDING:
87062306a36Sopenharmony_ci        case FFS_SETUP_CANCELLED:
87162306a36Sopenharmony_ci            poll_wait(file, &ffs->wait_que, wait);
87262306a36Sopenharmony_ci            if (!kfifo_is_empty(&ffs->reqEventFifo))
87362306a36Sopenharmony_ci            {
87462306a36Sopenharmony_ci                mask |= EPOLLOUT;
87562306a36Sopenharmony_ci            }
87662306a36Sopenharmony_ci            break;
87762306a36Sopenharmony_ci        }
87862306a36Sopenharmony_ci    case FFS_CLOSING:
87962306a36Sopenharmony_ci        break;
88062306a36Sopenharmony_ci    case FFS_DEACTIVATED:
88162306a36Sopenharmony_ci        break;
88262306a36Sopenharmony_ci    }
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci    mutex_unlock(&ffs->mutex);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci    return mask;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic int ffs_ep0_mmap(struct file *file, struct vm_area_struct *vma)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci    struct ffs_data *ffs = file->private_data;
89262306a36Sopenharmony_ci    size_t size = vma->vm_end - vma->vm_start;
89362306a36Sopenharmony_ci    unsigned long flags;
89462306a36Sopenharmony_ci    struct ffs_memory *ffsm = NULL;
89562306a36Sopenharmony_ci    void *virt_mem = NULL;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci    if (ffs == NULL) {
89862306a36Sopenharmony_ci        pr_info("Invalid private parameter!\n");
89962306a36Sopenharmony_ci        return -EINVAL;
90062306a36Sopenharmony_ci    }
90162306a36Sopenharmony_ci    virt_mem = kmalloc(size, GFP_KERNEL);
90262306a36Sopenharmony_ci    if (virt_mem == NULL)
90362306a36Sopenharmony_ci    {
90462306a36Sopenharmony_ci        pr_info("%s alloc memory failed!\n", __FUNCTION__);
90562306a36Sopenharmony_ci        return -ENOMEM;
90662306a36Sopenharmony_ci    }
90762306a36Sopenharmony_ci    ffsm = kmalloc(sizeof(struct ffs_memory), GFP_KERNEL);
90862306a36Sopenharmony_ci    if (ffsm == NULL)
90962306a36Sopenharmony_ci    {
91062306a36Sopenharmony_ci        pr_info("%s alloc memory failed!\n", __FUNCTION__);
91162306a36Sopenharmony_ci        goto error_free_mem;
91262306a36Sopenharmony_ci    }
91362306a36Sopenharmony_ci    if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(virt_mem)>>PAGE_SHIFT,
91462306a36Sopenharmony_ci        vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
91562306a36Sopenharmony_ci        goto error_free_ffsm;
91662306a36Sopenharmony_ci    }
91762306a36Sopenharmony_ci    ffsm->mem      = (uint64_t)virt_mem;
91862306a36Sopenharmony_ci    ffsm->size     = size;
91962306a36Sopenharmony_ci    ffsm->vm_start = vma->vm_start;
92062306a36Sopenharmony_ci    INIT_LIST_HEAD(&ffsm->memlist);
92162306a36Sopenharmony_ci    spin_lock_irqsave(&ffs->mem_lock, flags);
92262306a36Sopenharmony_ci    list_add_tail(&ffsm->memlist, &ffs->memory_list);
92362306a36Sopenharmony_ci    spin_unlock_irqrestore(&ffs->mem_lock, flags);
92462306a36Sopenharmony_ci    return 0;
92562306a36Sopenharmony_cierror_free_ffsm:
92662306a36Sopenharmony_ci    kfree(ffsm);
92762306a36Sopenharmony_cierror_free_mem:
92862306a36Sopenharmony_ci    kfree(virt_mem);
92962306a36Sopenharmony_ci    return -1;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic const struct file_operations ffs_ep0_operations = {
93362306a36Sopenharmony_ci    .owner   = THIS_MODULE,
93462306a36Sopenharmony_ci    .llseek =    no_llseek,
93562306a36Sopenharmony_ci    .open =        ffs_ep0_open,
93662306a36Sopenharmony_ci    .write =    ffs_ep0_write,
93762306a36Sopenharmony_ci    .read =        ffs_ep0_read,
93862306a36Sopenharmony_ci    .release =    ffs_ep0_release,
93962306a36Sopenharmony_ci    .unlocked_ioctl =    ffs_ep0_ioctl,
94062306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
94162306a36Sopenharmony_ci    .compat_ioctl = ffs_ep0_compat_ioctl,
94262306a36Sopenharmony_ci#endif
94362306a36Sopenharmony_ci    .poll =        ffs_ep0_poll,
94462306a36Sopenharmony_ci    .mmap =     ffs_ep0_mmap,
94562306a36Sopenharmony_ci};
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci/* "Normal" endpoints operations ********************************************/
94862306a36Sopenharmony_cistatic struct ffs_memory *generic_find_memory_area(struct ffs_epfile *epfile, uint64_t buf, uint32_t len)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci    struct ffs_memory *ffsm = NULL, *iter = NULL;
95162306a36Sopenharmony_ci    uint64_t buf_start = buf;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci    list_for_each_entry(iter, &epfile->memory_list, memlist) {
95462306a36Sopenharmony_ci        if (buf_start >= iter->vm_start &&
95562306a36Sopenharmony_ci            buf_start < iter->vm_start + iter->size) {
95662306a36Sopenharmony_ci            if (len <= iter->vm_start + iter->size - buf_start) {
95762306a36Sopenharmony_ci                ffsm = iter;
95862306a36Sopenharmony_ci                break;
95962306a36Sopenharmony_ci            }
96062306a36Sopenharmony_ci        }
96162306a36Sopenharmony_ci    }
96262306a36Sopenharmony_ci    return ffsm;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci    ENTER();
96862306a36Sopenharmony_ci    if (likely(req->context)) {
96962306a36Sopenharmony_ci        struct ffs_ep *ep = _ep->driver_data;
97062306a36Sopenharmony_ci        ep->status = req->status ? req->status : req->actual;
97162306a36Sopenharmony_ci        complete(req->context);
97262306a36Sopenharmony_ci    }
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic void epfile_task_proc(unsigned long context)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci    struct ffs_io_data *io_data = (struct ffs_io_data *)context;
97862306a36Sopenharmony_ci    struct ffs_epfile *epfile = io_data->epfile;
97962306a36Sopenharmony_ci    unsigned long flags;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci    spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
98262306a36Sopenharmony_ci    io_data->status = io_data->req->status;
98362306a36Sopenharmony_ci    io_data->actual = io_data->req->actual;
98462306a36Sopenharmony_ci    kfifo_in(&epfile->reqEventFifo, &io_data->buf, sizeof(struct UsbFnReqEvent));
98562306a36Sopenharmony_ci    list_del(&io_data->req->list);
98662306a36Sopenharmony_ci    usb_ep_free_request(io_data->ep, io_data->req);
98762306a36Sopenharmony_ci    kfree(io_data);
98862306a36Sopenharmony_ci    spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
98962306a36Sopenharmony_ci    wake_up_all(&epfile->wait_que);
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic void ffs_epfile_async_io_complete(struct usb_ep *_ep, struct usb_request *req)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci    struct ffs_io_data *io_data = req->context;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci    tasklet_init(&io_data->task, epfile_task_proc, (uintptr_t)io_data);
99762306a36Sopenharmony_ci    tasklet_schedule(&io_data->task);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic int ffs_epfile_open(struct inode *inode, struct file *file)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci    struct ffs_epfile *epfile  = container_of(inode->i_cdev, struct ffs_epfile, cdev);
100462306a36Sopenharmony_ci    ENTER();
100562306a36Sopenharmony_ci    if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
100662306a36Sopenharmony_ci        return -ENODEV;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci    file->private_data = epfile;
100962306a36Sopenharmony_ci    return 0;
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_cistatic int ffs_epfile_release(struct inode *inode, struct file *file)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci    ENTER();
101562306a36Sopenharmony_ci    return 0;
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic int ffs_epfile_mmap(struct file *file, struct vm_area_struct *vma)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci    struct ffs_epfile *epfile = file->private_data;
102162306a36Sopenharmony_ci    size_t size = vma->vm_end - vma->vm_start;
102262306a36Sopenharmony_ci    struct ffs_memory *ffsm = NULL;
102362306a36Sopenharmony_ci    unsigned long flags;
102462306a36Sopenharmony_ci    void *virt_mem = NULL;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci    if (epfile == NULL)
102762306a36Sopenharmony_ci    {
102862306a36Sopenharmony_ci        pr_info("Invalid private parameter!\n");
102962306a36Sopenharmony_ci        return -EINVAL;
103062306a36Sopenharmony_ci    }
103162306a36Sopenharmony_ci    virt_mem = kmalloc(size, GFP_KERNEL);
103262306a36Sopenharmony_ci    if (virt_mem == NULL)
103362306a36Sopenharmony_ci    {
103462306a36Sopenharmony_ci        pr_info("%s alloc memory failed!\n", __FUNCTION__);
103562306a36Sopenharmony_ci        return -ENOMEM;
103662306a36Sopenharmony_ci    }
103762306a36Sopenharmony_ci    ffsm = kmalloc(sizeof(struct ffs_memory), GFP_KERNEL);
103862306a36Sopenharmony_ci    if (ffsm == NULL)
103962306a36Sopenharmony_ci    {
104062306a36Sopenharmony_ci        pr_info("%s alloc memory failed!\n", __FUNCTION__);
104162306a36Sopenharmony_ci        goto error_free_mem;
104262306a36Sopenharmony_ci    }
104362306a36Sopenharmony_ci    if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(virt_mem)>>PAGE_SHIFT,
104462306a36Sopenharmony_ci                vma->vm_end - vma->vm_start, vma->vm_page_prot))
104562306a36Sopenharmony_ci    {
104662306a36Sopenharmony_ci        goto error_free_ffsm;
104762306a36Sopenharmony_ci    }
104862306a36Sopenharmony_ci    ffsm->mem = (uint64_t)virt_mem;
104962306a36Sopenharmony_ci    ffsm->size = size;
105062306a36Sopenharmony_ci    ffsm->vm_start = vma->vm_start;
105162306a36Sopenharmony_ci    INIT_LIST_HEAD(&ffsm->memlist);
105262306a36Sopenharmony_ci    spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
105362306a36Sopenharmony_ci    list_add_tail(&ffsm->memlist, &epfile->memory_list);
105462306a36Sopenharmony_ci    spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci    return 0;
105762306a36Sopenharmony_cierror_free_ffsm:
105862306a36Sopenharmony_ci    kfree(ffsm);
105962306a36Sopenharmony_cierror_free_mem:
106062306a36Sopenharmony_ci    kfree(virt_mem);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci    return -1;
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistatic ssize_t ffs_epfile_iorw(struct file *file, struct ffs_io_data *io_data)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci    struct ffs_epfile *epfile = file->private_data;
106862306a36Sopenharmony_ci    struct usb_request *req = NULL;
106962306a36Sopenharmony_ci    struct ffs_ep *ep = NULL;
107062306a36Sopenharmony_ci    struct ffs_memory *ffsm = NULL;
107162306a36Sopenharmony_ci    ssize_t ret, data_len = -EINVAL;
107262306a36Sopenharmony_ci    int halt;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci    /* Are we still active? */
107562306a36Sopenharmony_ci    if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
107662306a36Sopenharmony_ci        return -ENODEV;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci    /* Wait for endpoint to be enabled */
107962306a36Sopenharmony_ci    ep = epfile->ep;
108062306a36Sopenharmony_ci    if (!ep) {
108162306a36Sopenharmony_ci        if (file->f_flags & O_NONBLOCK)
108262306a36Sopenharmony_ci            return -EAGAIN;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci        ret = wait_event_interruptible(
108562306a36Sopenharmony_ci                epfile->ffs->wait, (ep = epfile->ep));
108662306a36Sopenharmony_ci        if (ret)
108762306a36Sopenharmony_ci            return -EINTR;
108862306a36Sopenharmony_ci    }
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci    /* Do we halt? */
109162306a36Sopenharmony_ci    halt = (!io_data->read == !epfile->in);
109262306a36Sopenharmony_ci    if (halt && epfile->isoc)
109362306a36Sopenharmony_ci        return -EINVAL;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci    /* We will be using request and read_buffer */
109662306a36Sopenharmony_ci    ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
109762306a36Sopenharmony_ci    if (unlikely(ret))
109862306a36Sopenharmony_ci        goto error;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci    /* Allocate & copy */
110162306a36Sopenharmony_ci    if (!halt) {
110262306a36Sopenharmony_ci        struct usb_gadget *gadget;
110362306a36Sopenharmony_ci        /*
110462306a36Sopenharmony_ci         * if we _do_ wait above, the epfile->ffs->gadget might be NULL
110562306a36Sopenharmony_ci         * before the waiting completes, so do not assign to 'gadget'
110662306a36Sopenharmony_ci         * earlier
110762306a36Sopenharmony_ci         */
110862306a36Sopenharmony_ci        gadget = epfile->ffs->gadget;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci        spin_lock_irq(&epfile->ffs->eps_lock);
111162306a36Sopenharmony_ci        /* In the meantime, endpoint got disabled or changed. */
111262306a36Sopenharmony_ci        if (epfile->ep != ep) {
111362306a36Sopenharmony_ci            ret = -ESHUTDOWN;
111462306a36Sopenharmony_ci            goto error_lock;
111562306a36Sopenharmony_ci        }
111662306a36Sopenharmony_ci        data_len = io_data->len;
111762306a36Sopenharmony_ci        /*
111862306a36Sopenharmony_ci         * Controller may require buffer size to be aligned to
111962306a36Sopenharmony_ci         * maxpacketsize of an out endpoint.
112062306a36Sopenharmony_ci         */
112162306a36Sopenharmony_ci        if (io_data->read)
112262306a36Sopenharmony_ci            data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
112362306a36Sopenharmony_ci        spin_unlock_irq(&epfile->ffs->eps_lock);
112462306a36Sopenharmony_ci    }
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci    spin_lock_irq(&epfile->ffs->eps_lock);
112762306a36Sopenharmony_ci    ffsm = generic_find_memory_area(epfile, io_data->buf, io_data->len);
112862306a36Sopenharmony_ci    if (ffsm == NULL)
112962306a36Sopenharmony_ci    {
113062306a36Sopenharmony_ci        return -EFAULT;
113162306a36Sopenharmony_ci    }
113262306a36Sopenharmony_ci    if (epfile->ep != ep) {
113362306a36Sopenharmony_ci        /* In the meantime, endpoint got disabled or changed. */
113462306a36Sopenharmony_ci        ret = -ESHUTDOWN;
113562306a36Sopenharmony_ci    }
113662306a36Sopenharmony_ci    else if (halt) {
113762306a36Sopenharmony_ci        ret = usb_ep_set_halt(ep->ep);
113862306a36Sopenharmony_ci        if (!ret)
113962306a36Sopenharmony_ci            ret = -EBADMSG;
114062306a36Sopenharmony_ci    }
114162306a36Sopenharmony_ci    else if (!io_data->aio) {
114262306a36Sopenharmony_ci        DECLARE_COMPLETION_ONSTACK(done);
114362306a36Sopenharmony_ci        bool interrupted = false;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci        req = ep->req;
114662306a36Sopenharmony_ci        req->buf      = (void *)(ffsm->mem + io_data->buf - ffsm->vm_start);
114762306a36Sopenharmony_ci        req->length   = data_len;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci        req->context  = &done;
115062306a36Sopenharmony_ci        req->complete = ffs_epfile_io_complete;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci        ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
115362306a36Sopenharmony_ci        if (unlikely(ret < 0))
115462306a36Sopenharmony_ci            goto error_lock;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci        spin_unlock_irq(&epfile->ffs->eps_lock);
115762306a36Sopenharmony_ci        if (io_data->timeout > 0) {
115862306a36Sopenharmony_ci            ret = wait_for_completion_interruptible_timeout(&done, io_data->timeout);
115962306a36Sopenharmony_ci            if (ret < 0) {
116062306a36Sopenharmony_ci                /*
116162306a36Sopenharmony_ci                 * To avoid race condition with ffs_epfile_io_complete,
116262306a36Sopenharmony_ci                 * dequeue the request first then check
116362306a36Sopenharmony_ci                 * status. usb_ep_dequeue API should guarantee no race
116462306a36Sopenharmony_ci                 * condition with req->complete callback.
116562306a36Sopenharmony_ci                 */
116662306a36Sopenharmony_ci                usb_ep_dequeue(ep->ep, req);
116762306a36Sopenharmony_ci                wait_for_completion(&done);
116862306a36Sopenharmony_ci                interrupted = ep->status < 0;
116962306a36Sopenharmony_ci            } else if (ret == 0) {
117062306a36Sopenharmony_ci                ret = -EBUSY;
117162306a36Sopenharmony_ci                usb_ep_dequeue(ep->ep, req);
117262306a36Sopenharmony_ci                wait_for_completion(&done);
117362306a36Sopenharmony_ci                goto error_mutex;
117462306a36Sopenharmony_ci            }
117562306a36Sopenharmony_ci        } else {
117662306a36Sopenharmony_ci            ret = wait_for_completion_interruptible(&done);
117762306a36Sopenharmony_ci            if (ret < 0) {
117862306a36Sopenharmony_ci                usb_ep_dequeue(ep->ep, req);
117962306a36Sopenharmony_ci                wait_for_completion(&done);
118062306a36Sopenharmony_ci                interrupted = ep->status < 0;
118162306a36Sopenharmony_ci            }
118262306a36Sopenharmony_ci        }
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci        if (interrupted) {
118562306a36Sopenharmony_ci            ret = -EINTR;
118662306a36Sopenharmony_ci        } else {
118762306a36Sopenharmony_ci            ret = req->actual;
118862306a36Sopenharmony_ci        }
118962306a36Sopenharmony_ci        goto error_mutex;
119062306a36Sopenharmony_ci    }
119162306a36Sopenharmony_ci    else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) {
119262306a36Sopenharmony_ci        ret = -ENOMEM;
119362306a36Sopenharmony_ci    }
119462306a36Sopenharmony_ci    else {
119562306a36Sopenharmony_ci        req->buf     = (void *)(ffsm->mem + io_data->buf - ffsm->vm_start);
119662306a36Sopenharmony_ci        req->length  = data_len;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci        io_data->ep     = ep->ep;
119962306a36Sopenharmony_ci        io_data->req    = req;
120062306a36Sopenharmony_ci        io_data->epfile = epfile;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci        req->context  = io_data;
120362306a36Sopenharmony_ci        req->complete = ffs_epfile_async_io_complete;
120462306a36Sopenharmony_ci        list_add(&req->list, &ep->req->list);
120562306a36Sopenharmony_ci        ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
120662306a36Sopenharmony_ci        if (unlikely(ret)) {
120762306a36Sopenharmony_ci            usb_ep_free_request(ep->ep, req);
120862306a36Sopenharmony_ci            goto error_lock;
120962306a36Sopenharmony_ci        }
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci        ret = -EIOCBQUEUED;
121262306a36Sopenharmony_ci    }
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cierror_lock:
121562306a36Sopenharmony_ci    spin_unlock_irq(&epfile->ffs->eps_lock);
121662306a36Sopenharmony_cierror_mutex:
121762306a36Sopenharmony_ci    mutex_unlock(&epfile->mutex);
121862306a36Sopenharmony_cierror:
121962306a36Sopenharmony_ci    return ret;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic long ffs_epfile_ioctl(struct file *file, unsigned code, unsigned long value)
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci    struct ffs_epfile *epfile = file->private_data;
122562306a36Sopenharmony_ci    struct ffs_ep *ep = epfile->ep;
122662306a36Sopenharmony_ci    int ret = 0;
122762306a36Sopenharmony_ci    struct generic_memory mem;
122862306a36Sopenharmony_ci    struct ffs_memory *ffsm = NULL;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci    ENTER();
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci    if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
123362306a36Sopenharmony_ci        return -ENODEV;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci    spin_lock_irq(&epfile->ffs->eps_lock);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci    switch (code) {
123862306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_QUEUE_INIT:
123962306a36Sopenharmony_ci        ret = kfifo_alloc(&epfile->reqEventFifo, MAX_REQUEST * sizeof(struct UsbFnReqEvent), GFP_KERNEL);
124062306a36Sopenharmony_ci        break;
124162306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_QUEUE_DEL:
124262306a36Sopenharmony_ci        kfifo_free(&epfile->reqEventFifo);
124362306a36Sopenharmony_ci        break;
124462306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_RELEASE_BUF:
124562306a36Sopenharmony_ci        if (copy_from_user(&mem, (void __user *)value, sizeof(mem)))
124662306a36Sopenharmony_ci        {
124762306a36Sopenharmony_ci            pr_info("copy from user failed\n");
124862306a36Sopenharmony_ci            return -EFAULT;
124962306a36Sopenharmony_ci        }
125062306a36Sopenharmony_ci        ffsm = generic_find_memory_area(epfile, mem.buf, mem.size);
125162306a36Sopenharmony_ci        if (ffsm == NULL)
125262306a36Sopenharmony_ci        {
125362306a36Sopenharmony_ci            return -EFAULT;
125462306a36Sopenharmony_ci        }
125562306a36Sopenharmony_ci        list_del(&ffsm->memlist);
125662306a36Sopenharmony_ci        kfree((void *)ffsm->mem);
125762306a36Sopenharmony_ci        kfree(ffsm);
125862306a36Sopenharmony_ci        break;
125962306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_READ:
126062306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_WRITE:
126162306a36Sopenharmony_ci    {
126262306a36Sopenharmony_ci        struct IoData myIoData;
126362306a36Sopenharmony_ci        struct ffs_io_data io_data, *p = &io_data;
126462306a36Sopenharmony_ci        ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
126562306a36Sopenharmony_ci        if (unlikely(ret)) {
126662306a36Sopenharmony_ci            spin_unlock_irq(&epfile->ffs->eps_lock);
126762306a36Sopenharmony_ci            return -EFAULT;
126862306a36Sopenharmony_ci        }
126962306a36Sopenharmony_ci        if (myIoData.aio) {
127062306a36Sopenharmony_ci            p = kmalloc(sizeof(io_data), GFP_KERNEL);
127162306a36Sopenharmony_ci            if (unlikely(!p)) {
127262306a36Sopenharmony_ci                spin_unlock_irq(&epfile->ffs->eps_lock);
127362306a36Sopenharmony_ci                return -ENOMEM;
127462306a36Sopenharmony_ci            }
127562306a36Sopenharmony_ci        } else {
127662306a36Sopenharmony_ci            memset(p,  0, sizeof(*p));
127762306a36Sopenharmony_ci        }
127862306a36Sopenharmony_ci        memcpy(p, &myIoData, sizeof(struct IoData));
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci        spin_unlock_irq(&epfile->ffs->eps_lock);
128162306a36Sopenharmony_ci        ret = ffs_epfile_iorw(file, p);
128262306a36Sopenharmony_ci        if (ret == -EIOCBQUEUED) {
128362306a36Sopenharmony_ci            return 0;
128462306a36Sopenharmony_ci        }
128562306a36Sopenharmony_ci        if (p->aio)
128662306a36Sopenharmony_ci            kfree(p);
128762306a36Sopenharmony_ci        return ret;
128862306a36Sopenharmony_ci    }
128962306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_RW_CANCEL:
129062306a36Sopenharmony_ci    {
129162306a36Sopenharmony_ci        struct usb_request *req;
129262306a36Sopenharmony_ci        struct IoData myIoData;
129362306a36Sopenharmony_ci        if (!ep) {
129462306a36Sopenharmony_ci            spin_unlock_irq(&epfile->ffs->eps_lock);
129562306a36Sopenharmony_ci            return -EFAULT;
129662306a36Sopenharmony_ci        }
129762306a36Sopenharmony_ci        ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
129862306a36Sopenharmony_ci        if (unlikely(ret)) {
129962306a36Sopenharmony_ci            spin_unlock_irq(&epfile->ffs->eps_lock);
130062306a36Sopenharmony_ci            return -EFAULT;
130162306a36Sopenharmony_ci        }
130262306a36Sopenharmony_ci        ffsm = generic_find_memory_area(epfile, myIoData.buf, myIoData.len);
130362306a36Sopenharmony_ci        if (ffsm == NULL)
130462306a36Sopenharmony_ci        {
130562306a36Sopenharmony_ci            return -EFAULT;
130662306a36Sopenharmony_ci        }
130762306a36Sopenharmony_ci        list_for_each_entry(req, &epfile->ep->req->list, list) {
130862306a36Sopenharmony_ci            if (req->buf == (void *)(ffsm->mem + myIoData.buf - ffsm->vm_start)) {
130962306a36Sopenharmony_ci                usb_ep_dequeue(epfile->ep->ep, req);
131062306a36Sopenharmony_ci                spin_unlock_irq(&epfile->ffs->eps_lock);
131162306a36Sopenharmony_ci                return 0;
131262306a36Sopenharmony_ci            }
131362306a36Sopenharmony_ci        }
131462306a36Sopenharmony_ci        spin_unlock_irq(&epfile->ffs->eps_lock);
131562306a36Sopenharmony_ci        return -EFAULT;
131662306a36Sopenharmony_ci    }
131762306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_GET_REQ_STATUS:
131862306a36Sopenharmony_ci    {
131962306a36Sopenharmony_ci        struct usb_request *req;
132062306a36Sopenharmony_ci        struct IoData myIoData;
132162306a36Sopenharmony_ci        if (!ep) {
132262306a36Sopenharmony_ci            spin_unlock_irq(&epfile->ffs->eps_lock);
132362306a36Sopenharmony_ci            return -EFAULT;
132462306a36Sopenharmony_ci        }
132562306a36Sopenharmony_ci        ret = copy_from_user(&myIoData,(void __user *)value, sizeof(struct IoData));
132662306a36Sopenharmony_ci        if (unlikely(ret)) {
132762306a36Sopenharmony_ci            spin_unlock_irq(&epfile->ffs->eps_lock);
132862306a36Sopenharmony_ci            return -EFAULT;
132962306a36Sopenharmony_ci        }
133062306a36Sopenharmony_ci        ffsm = generic_find_memory_area(epfile, myIoData.buf, myIoData.len);
133162306a36Sopenharmony_ci        if (ffsm == NULL)
133262306a36Sopenharmony_ci        {
133362306a36Sopenharmony_ci            return -EFAULT;
133462306a36Sopenharmony_ci        }
133562306a36Sopenharmony_ci        list_for_each_entry(req, &epfile->ep->req->list, list) {
133662306a36Sopenharmony_ci            if (req->buf == (void *)(ffsm->mem + myIoData.buf - ffsm->vm_start)) {
133762306a36Sopenharmony_ci                spin_unlock_irq(&epfile->ffs->eps_lock);
133862306a36Sopenharmony_ci                return req->status;
133962306a36Sopenharmony_ci            }
134062306a36Sopenharmony_ci        }
134162306a36Sopenharmony_ci        spin_unlock_irq(&epfile->ffs->eps_lock);
134262306a36Sopenharmony_ci        return -EFAULT;
134362306a36Sopenharmony_ci    }
134462306a36Sopenharmony_ci    case FUNCTIONFS_FIFO_STATUS:
134562306a36Sopenharmony_ci        ret = usb_ep_fifo_status(epfile->ep->ep);
134662306a36Sopenharmony_ci        break;
134762306a36Sopenharmony_ci    case FUNCTIONFS_FIFO_FLUSH:
134862306a36Sopenharmony_ci        usb_ep_fifo_flush(epfile->ep->ep);
134962306a36Sopenharmony_ci        ret = 0;
135062306a36Sopenharmony_ci        break;
135162306a36Sopenharmony_ci    case FUNCTIONFS_CLEAR_HALT:
135262306a36Sopenharmony_ci        ret = usb_ep_clear_halt(epfile->ep->ep);
135362306a36Sopenharmony_ci        break;
135462306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_REVMAP:
135562306a36Sopenharmony_ci        ret = epfile->ep->num;
135662306a36Sopenharmony_ci        break;
135762306a36Sopenharmony_ci    case FUNCTIONFS_ENDPOINT_DESC:
135862306a36Sopenharmony_ci    {
135962306a36Sopenharmony_ci        int desc_idx;
136062306a36Sopenharmony_ci        int i;
136162306a36Sopenharmony_ci        struct usb_endpoint_descriptor *desc;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci        switch (epfile->ffs->speed) {
136462306a36Sopenharmony_ci        case USB_SPEED_SUPER:
136562306a36Sopenharmony_ci            desc_idx = 2;
136662306a36Sopenharmony_ci            break;
136762306a36Sopenharmony_ci        case USB_SPEED_HIGH:
136862306a36Sopenharmony_ci            desc_idx = 1;
136962306a36Sopenharmony_ci            break;
137062306a36Sopenharmony_ci        default:
137162306a36Sopenharmony_ci            desc_idx = 1;
137262306a36Sopenharmony_ci        }
137362306a36Sopenharmony_ci        for (i = 0; i < epfile->ffs->eps_count; i++) {
137462306a36Sopenharmony_ci            if (epfile->ffs->epfiles + i == epfile)
137562306a36Sopenharmony_ci                break;
137662306a36Sopenharmony_ci        }
137762306a36Sopenharmony_ci        ep = epfile->ffs->eps + i;
137862306a36Sopenharmony_ci        desc = ep->descs[desc_idx];
137962306a36Sopenharmony_ci        spin_unlock_irq(&epfile->ffs->eps_lock);
138062306a36Sopenharmony_ci        ret = copy_to_user((void __user *)value, desc, desc->bLength);
138162306a36Sopenharmony_ci        if (ret)
138262306a36Sopenharmony_ci            ret = -EFAULT;
138362306a36Sopenharmony_ci        return ret;
138462306a36Sopenharmony_ci    }
138562306a36Sopenharmony_ci    default:
138662306a36Sopenharmony_ci        ret = -ENOTTY;
138762306a36Sopenharmony_ci    }
138862306a36Sopenharmony_ci    spin_unlock_irq(&epfile->ffs->eps_lock);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci    return ret;
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic ssize_t ffs_epfile_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci    int status = 0;
139662306a36Sopenharmony_ci    unsigned int copied = 0;
139762306a36Sopenharmony_ci    unsigned long flags;
139862306a36Sopenharmony_ci    struct ffs_epfile *epfile = file->private_data;
139962306a36Sopenharmony_ci    ENTER();
140062306a36Sopenharmony_ci    if (kfifo_is_empty(&epfile->reqEventFifo)) {
140162306a36Sopenharmony_ci        return 0;
140262306a36Sopenharmony_ci    }
140362306a36Sopenharmony_ci    spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
140462306a36Sopenharmony_ci    status = kfifo_to_user(&epfile->reqEventFifo, buf, count, &copied) == 0 ? copied : -1;
140562306a36Sopenharmony_ci    spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci    return status;
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_cistatic ssize_t ffs_epfile_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci    return count;
141362306a36Sopenharmony_ci}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_cistatic unsigned int ffs_epfile_poll(struct file *file, struct poll_table_struct * wait)
141662306a36Sopenharmony_ci{
141762306a36Sopenharmony_ci    unsigned int mask = 0;
141862306a36Sopenharmony_ci    struct ffs_epfile *epfile = file->private_data;
141962306a36Sopenharmony_ci    ENTER();
142062306a36Sopenharmony_ci    poll_wait(file, &epfile->wait_que, wait);
142162306a36Sopenharmony_ci    if (!kfifo_is_empty(&epfile->reqEventFifo)) {
142262306a36Sopenharmony_ci        mask |= POLLIN;
142362306a36Sopenharmony_ci    }
142462306a36Sopenharmony_ci    return mask;
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
142862306a36Sopenharmony_cistatic long ffs_epfile_compat_ioctl(struct file *file, unsigned code,
142962306a36Sopenharmony_ci        unsigned long value)
143062306a36Sopenharmony_ci{
143162306a36Sopenharmony_ci    return ffs_epfile_ioctl(file, code, value);
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci#endif
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_cistatic const struct file_operations ffs_epfile_operations = {
143662306a36Sopenharmony_ci    .owner   = THIS_MODULE,
143762306a36Sopenharmony_ci    .llseek =    no_llseek,
143862306a36Sopenharmony_ci    .mmap = ffs_epfile_mmap,
143962306a36Sopenharmony_ci    .read    = ffs_epfile_read,
144062306a36Sopenharmony_ci    .write   = ffs_epfile_write,
144162306a36Sopenharmony_ci    .poll = ffs_epfile_poll,
144262306a36Sopenharmony_ci    .open =        ffs_epfile_open,
144362306a36Sopenharmony_ci    .release =    ffs_epfile_release,
144462306a36Sopenharmony_ci    .unlocked_ioctl =    ffs_epfile_ioctl,
144562306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
144662306a36Sopenharmony_ci    .compat_ioctl = ffs_epfile_compat_ioctl,
144762306a36Sopenharmony_ci#endif
144862306a36Sopenharmony_ci};
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci/* ffs_data and ffs_function construction and destruction code **************/
145162306a36Sopenharmony_cistatic void ffs_data_clear(struct ffs_data *ffs);
145262306a36Sopenharmony_cistatic void ffs_data_reset(struct ffs_data *ffs);
145362306a36Sopenharmony_cistatic dev_t g_dev;
145462306a36Sopenharmony_ci#define MAX_EP_DEV 10
145562306a36Sopenharmony_cistatic long usbfn_ioctl(struct file *file, unsigned int cmd, unsigned long value)
145662306a36Sopenharmony_ci{
145762306a36Sopenharmony_ci    long ret;
145862306a36Sopenharmony_ci    ENTER();
145962306a36Sopenharmony_ci    switch(cmd)
146062306a36Sopenharmony_ci    {
146162306a36Sopenharmony_ci        case FUNCTIONFS_NEWFN:
146262306a36Sopenharmony_ci        {
146362306a36Sopenharmony_ci            struct ffs_dev *ffs_dev;
146462306a36Sopenharmony_ci            struct ffs_data    *ffs;
146562306a36Sopenharmony_ci            struct FuncNew newfn;
146662306a36Sopenharmony_ci            char nameEp0[MAX_NAMELEN];
146762306a36Sopenharmony_ci            ret = copy_from_user(&newfn, (void __user *)value, sizeof(struct FuncNew ));
146862306a36Sopenharmony_ci            if (unlikely(ret)) {
146962306a36Sopenharmony_ci                return -EFAULT;
147062306a36Sopenharmony_ci            }
147162306a36Sopenharmony_ci            ffs = ffs_data_new(newfn.name);
147262306a36Sopenharmony_ci            if (unlikely(!ffs)) {
147362306a36Sopenharmony_ci                return (-ENOMEM);
147462306a36Sopenharmony_ci            }
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci            if (newfn.nameLen > MAX_NAMELEN) {
147762306a36Sopenharmony_ci                return -EPERM;
147862306a36Sopenharmony_ci            }
147962306a36Sopenharmony_ci            memcpy(ffs->dev_name, newfn.name, newfn.nameLen);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci            if (unlikely(!ffs->dev_name)) {
148262306a36Sopenharmony_ci                ffs_data_put(ffs);
148362306a36Sopenharmony_ci                return (-ENOMEM);
148462306a36Sopenharmony_ci            }
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci            if (sprintf(nameEp0, "%s.ep%u", ffs->dev_name, 0) < 0) {
148762306a36Sopenharmony_ci                ffs_data_put(ffs);
148862306a36Sopenharmony_ci                return -EFAULT;
148962306a36Sopenharmony_ci            }
149062306a36Sopenharmony_ci            ffs_dev = ffs_acquire_dev(newfn.name);
149162306a36Sopenharmony_ci            if (IS_ERR(ffs_dev)) {
149262306a36Sopenharmony_ci                ffs_data_put(ffs);
149362306a36Sopenharmony_ci                return (-ENODEV);
149462306a36Sopenharmony_ci            }
149562306a36Sopenharmony_ci            ffs->private_data = ffs_dev;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci            ret = alloc_chrdev_region(&g_dev, 0, MAX_EP_DEV, nameEp0);
149862306a36Sopenharmony_ci            if (ret < 0) {
149962306a36Sopenharmony_ci                ffs_release_dev(ffs);
150062306a36Sopenharmony_ci                ffs_data_put(ffs);
150162306a36Sopenharmony_ci                return -EBUSY;
150262306a36Sopenharmony_ci            }
150362306a36Sopenharmony_ci            cdev_init(&ffs->cdev, &ffs_ep0_operations);
150462306a36Sopenharmony_ci            ffs->devno = MKDEV(MAJOR(g_dev), 0);
150562306a36Sopenharmony_ci            ret = cdev_add(&ffs->cdev, ffs->devno, 1);
150662306a36Sopenharmony_ci            if (ret) {
150762306a36Sopenharmony_ci                ffs_release_dev(ffs);
150862306a36Sopenharmony_ci                ffs_data_put(ffs);
150962306a36Sopenharmony_ci                return -EBUSY;
151062306a36Sopenharmony_ci            }
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci            ffs->fn_device = device_create(ffs_class, NULL, ffs->devno, NULL, nameEp0);
151362306a36Sopenharmony_ci            if (IS_ERR(ffs->fn_device)) {
151462306a36Sopenharmony_ci                cdev_del(&ffs->cdev);
151562306a36Sopenharmony_ci                ffs_release_dev(ffs);
151662306a36Sopenharmony_ci                ffs_data_put(ffs);
151762306a36Sopenharmony_ci                return -EBUSY;
151862306a36Sopenharmony_ci            }
151962306a36Sopenharmony_ci            return 0;
152062306a36Sopenharmony_ci        }
152162306a36Sopenharmony_ci        case FUNCTIONFS_DELFN:
152262306a36Sopenharmony_ci        {
152362306a36Sopenharmony_ci            struct FuncNew newfn;
152462306a36Sopenharmony_ci            struct ffs_data    *ffs;
152562306a36Sopenharmony_ci            struct ffs_dev *ffs_dev;
152662306a36Sopenharmony_ci            ret = copy_from_user(&newfn, (void __user *)value, sizeof(struct FuncNew ));
152762306a36Sopenharmony_ci            if (unlikely(ret)) {
152862306a36Sopenharmony_ci                return -EFAULT;
152962306a36Sopenharmony_ci            }
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci            ffs_dev = _ffs_find_dev(newfn.name);
153262306a36Sopenharmony_ci            if (IS_ERR(ffs_dev)) {
153362306a36Sopenharmony_ci                return -EFAULT;
153462306a36Sopenharmony_ci            }
153562306a36Sopenharmony_ci            ffs = ffs_dev->ffs_data;
153662306a36Sopenharmony_ci            device_destroy(ffs_class, ffs->devno);
153762306a36Sopenharmony_ci            cdev_del(&ffs->cdev);
153862306a36Sopenharmony_ci            unregister_chrdev_region(g_dev, MAX_EP_DEV);
153962306a36Sopenharmony_ci            ffs_release_dev(ffs);
154062306a36Sopenharmony_ci            ffs_data_clear(ffs);
154162306a36Sopenharmony_ci            destroy_workqueue(ffs->io_completion_wq);
154262306a36Sopenharmony_ci            kfree(ffs);
154362306a36Sopenharmony_ci            return 0;
154462306a36Sopenharmony_ci        }
154562306a36Sopenharmony_ci        default:
154662306a36Sopenharmony_ci            ret = -ENOTTY;
154762306a36Sopenharmony_ci        }
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci    return ret;
155062306a36Sopenharmony_ci}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_cistatic int usbfn_open(struct inode *inode, struct file *file)
155362306a36Sopenharmony_ci{
155462306a36Sopenharmony_ci    return 0;
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_cistatic int usbfn_release(struct inode *inode, struct file *file)
155862306a36Sopenharmony_ci{
155962306a36Sopenharmony_ci    return 0;
156062306a36Sopenharmony_ci}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_cistatic struct file_operations usbfn_fops = {
156362306a36Sopenharmony_ci    .owner   = THIS_MODULE,
156462306a36Sopenharmony_ci    .unlocked_ioctl   = usbfn_ioctl,
156562306a36Sopenharmony_ci    .open    = usbfn_open,
156662306a36Sopenharmony_ci    .release = usbfn_release,
156762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
156862306a36Sopenharmony_ci    .compat_ioctl = usbfn_ioctl,
156962306a36Sopenharmony_ci#endif
157062306a36Sopenharmony_ci};
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic struct miscdevice usbfn_misc = {
157362306a36Sopenharmony_ci    .minor = MISC_DYNAMIC_MINOR,
157462306a36Sopenharmony_ci    .name = "usbfn",
157562306a36Sopenharmony_ci    .fops = &usbfn_fops,
157662306a36Sopenharmony_ci};
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci/* Driver's main init/cleanup functions *************************************/
157962306a36Sopenharmony_cistatic int functionfs_init(void)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci    int ret;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci    ENTER();
158462306a36Sopenharmony_ci    ret = misc_register(&usbfn_misc);
158562306a36Sopenharmony_ci    if (likely(!ret))
158662306a36Sopenharmony_ci        pr_info("file system registered\n");
158762306a36Sopenharmony_ci    else
158862306a36Sopenharmony_ci        pr_err("failed registering file system (%d)\n", ret);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci    //ffs_class = class_create(THIS_MODULE, "functionfs");
159162306a36Sopenharmony_ci    ffs_class = class_create("functionfs");
159262306a36Sopenharmony_ci    if (IS_ERR(ffs_class))
159362306a36Sopenharmony_ci        return PTR_ERR(ffs_class);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci    ffs_class->devnode = ffs_devnode;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci    return ret;
159862306a36Sopenharmony_ci}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_cistatic void functionfs_cleanup(void)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci    ENTER();
160362306a36Sopenharmony_ci    class_destroy(ffs_class);
160462306a36Sopenharmony_ci    misc_deregister(&usbfn_misc);
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_cistatic void ffs_data_get(struct ffs_data *ffs)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci    ENTER();
161062306a36Sopenharmony_ci    refcount_inc(&ffs->ref);
161162306a36Sopenharmony_ci}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_cistatic void ffs_data_put(struct ffs_data *ffs)
161462306a36Sopenharmony_ci{
161562306a36Sopenharmony_ci    ENTER();
161662306a36Sopenharmony_ci    if (unlikely(refcount_dec_and_test(&ffs->ref))) {
161762306a36Sopenharmony_ci        pr_info("%s(): freeing\n", __func__);
161862306a36Sopenharmony_ci        ffs_data_clear(ffs);
161962306a36Sopenharmony_ci        BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
162062306a36Sopenharmony_ci#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
162162306a36Sopenharmony_ci            swait_active(&ffs->ep0req_completion.wait) ||
162262306a36Sopenharmony_ci#else
162362306a36Sopenharmony_ci            waitqueue_active(&ffs->ep0req_completion.wait) ||
162462306a36Sopenharmony_ci#endif
162562306a36Sopenharmony_ci               waitqueue_active(&ffs->wait) ||
162662306a36Sopenharmony_ci               waitqueue_active(&ffs->wait_que));
162762306a36Sopenharmony_ci        destroy_workqueue(ffs->io_completion_wq);
162862306a36Sopenharmony_ci        kfree(ffs);
162962306a36Sopenharmony_ci    }
163062306a36Sopenharmony_ci}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_cistatic struct ffs_data *ffs_data_new(const char *dev_name)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci    struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
163562306a36Sopenharmony_ci    if (unlikely(!ffs))
163662306a36Sopenharmony_ci        return NULL;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci    ENTER();
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci    ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
164162306a36Sopenharmony_ci    if (!ffs->io_completion_wq) {
164262306a36Sopenharmony_ci        kfree(ffs);
164362306a36Sopenharmony_ci        return NULL;
164462306a36Sopenharmony_ci    }
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci    refcount_set(&ffs->ref, 1);
164762306a36Sopenharmony_ci    atomic_set(&ffs->opened, 0);
164862306a36Sopenharmony_ci    ffs->state = FFS_READ_DESCRIPTORS;
164962306a36Sopenharmony_ci    mutex_init(&ffs->mutex);
165062306a36Sopenharmony_ci    spin_lock_init(&ffs->eps_lock);
165162306a36Sopenharmony_ci    spin_lock_init(&ffs->mem_lock);
165262306a36Sopenharmony_ci    init_waitqueue_head(&ffs->ev.waitq);
165362306a36Sopenharmony_ci    init_waitqueue_head(&ffs->wait);
165462306a36Sopenharmony_ci    init_waitqueue_head(&ffs->wait_que);
165562306a36Sopenharmony_ci    init_completion(&ffs->ep0req_completion);
165662306a36Sopenharmony_ci    INIT_LIST_HEAD(&ffs->memory_list);
165762306a36Sopenharmony_ci    ffs->ev.can_stall = 1;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci    return ffs;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic void ffs_data_clear(struct ffs_data *ffs)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci    ENTER();
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci    ffs_closed(ffs);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci    BUG_ON(ffs->gadget);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci    if (ffs->epfiles)
167162306a36Sopenharmony_ci        ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci    if (ffs->ffs_eventfd)
167462306a36Sopenharmony_ci        eventfd_ctx_put(ffs->ffs_eventfd);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci    kfree(ffs->raw_descs_data);
167762306a36Sopenharmony_ci    kfree(ffs->raw_strings);
167862306a36Sopenharmony_ci    kfree(ffs->stringtabs);
167962306a36Sopenharmony_ci}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_cistatic void ffs_data_reset(struct ffs_data *ffs)
168262306a36Sopenharmony_ci{
168362306a36Sopenharmony_ci    ENTER();
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci    ffs_data_clear(ffs);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci    ffs->epfiles = NULL;
168862306a36Sopenharmony_ci    ffs->raw_descs_data = NULL;
168962306a36Sopenharmony_ci    ffs->raw_descs = NULL;
169062306a36Sopenharmony_ci    ffs->raw_strings = NULL;
169162306a36Sopenharmony_ci    ffs->stringtabs = NULL;
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci    ffs->raw_descs_length = 0;
169462306a36Sopenharmony_ci    ffs->fs_descs_count = 0;
169562306a36Sopenharmony_ci    ffs->hs_descs_count = 0;
169662306a36Sopenharmony_ci    ffs->ss_descs_count = 0;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci    ffs->strings_count = 0;
169962306a36Sopenharmony_ci    ffs->interfaces_count = 0;
170062306a36Sopenharmony_ci    ffs->eps_count = 0;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci    ffs->ev.count = 0;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci    ffs->state = FFS_READ_DESCRIPTORS;
170562306a36Sopenharmony_ci    ffs->setup_state = FFS_NO_SETUP;
170662306a36Sopenharmony_ci    ffs->flags = 0;
170762306a36Sopenharmony_ci}
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_cistatic int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci    struct usb_gadget_strings **lang;
171262306a36Sopenharmony_ci    int first_id;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci    ENTER();
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci    if (WARN_ON(ffs->state != FFS_ACTIVE
171762306a36Sopenharmony_ci         || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
171862306a36Sopenharmony_ci        return -EBADFD;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci    first_id = usb_string_ids_n(cdev, ffs->strings_count);
172162306a36Sopenharmony_ci    if (unlikely(first_id < 0))
172262306a36Sopenharmony_ci        return first_id;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci    ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
172562306a36Sopenharmony_ci    if (unlikely(!ffs->ep0req))
172662306a36Sopenharmony_ci        return -ENOMEM;
172762306a36Sopenharmony_ci    ffs->ep0req->complete = ffs_ep0_complete;
172862306a36Sopenharmony_ci    ffs->ep0req->context = ffs;
172962306a36Sopenharmony_ci    INIT_LIST_HEAD(&ffs->ep0req->list);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci    lang = ffs->stringtabs;
173262306a36Sopenharmony_ci    if (lang) {
173362306a36Sopenharmony_ci        for (; *lang; ++lang) {
173462306a36Sopenharmony_ci            struct usb_string *str = (*lang)->strings;
173562306a36Sopenharmony_ci            int id = first_id;
173662306a36Sopenharmony_ci            for (; str->s; ++id, ++str)
173762306a36Sopenharmony_ci                str->id = id;
173862306a36Sopenharmony_ci        }
173962306a36Sopenharmony_ci    }
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci    ffs->gadget = cdev->gadget;
174262306a36Sopenharmony_ci    ffs->speed = cdev->gadget->speed;
174362306a36Sopenharmony_ci    ffs_data_get(ffs);
174462306a36Sopenharmony_ci    return 0;
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_cistatic void functionfs_unbind(struct ffs_data *ffs)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci    ENTER();
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci    if (!WARN_ON(!ffs->gadget)) {
175262306a36Sopenharmony_ci        usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
175362306a36Sopenharmony_ci        ffs->ep0req = NULL;
175462306a36Sopenharmony_ci        ffs->gadget = NULL;
175562306a36Sopenharmony_ci        clear_bit(FFS_FL_BOUND, &ffs->flags);
175662306a36Sopenharmony_ci        ffs_data_put(ffs);
175762306a36Sopenharmony_ci    }
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cistatic int ffs_epfiles_create(struct ffs_data *ffs)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci    struct ffs_epfile *epfile = NULL, *epfiles = NULL;
176362306a36Sopenharmony_ci    unsigned int i, count ,ret;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci    ENTER();
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci    count = ffs->eps_count;
176862306a36Sopenharmony_ci    epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
176962306a36Sopenharmony_ci    if (!epfiles)
177062306a36Sopenharmony_ci        return -ENOMEM;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci    epfile = epfiles;
177362306a36Sopenharmony_ci    for (i = 1; i <= count; ++i, ++epfile) {
177462306a36Sopenharmony_ci        epfile->ffs = ffs;
177562306a36Sopenharmony_ci        mutex_init(&epfile->mutex);
177662306a36Sopenharmony_ci        INIT_LIST_HEAD(&epfile->memory_list);
177762306a36Sopenharmony_ci        init_waitqueue_head(&epfile->wait_que);
177862306a36Sopenharmony_ci        if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) {
177962306a36Sopenharmony_ci            if (sprintf(epfile->name, "%s.ep%02x", ffs->dev_name, ffs->eps_addrmap[i]) < 0) {
178062306a36Sopenharmony_ci                return -EFAULT;
178162306a36Sopenharmony_ci            }
178262306a36Sopenharmony_ci        } else {
178362306a36Sopenharmony_ci            if (sprintf(epfile->name, "%s.ep%u", ffs->dev_name, i) < 0) {
178462306a36Sopenharmony_ci                return -EFAULT;
178562306a36Sopenharmony_ci            }
178662306a36Sopenharmony_ci        }
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci        cdev_init(&epfile->cdev, &ffs_epfile_operations);
178962306a36Sopenharmony_ci        epfile->devno=MKDEV(MAJOR(ffs->devno), i);
179062306a36Sopenharmony_ci        ret = cdev_add(&epfile->cdev, epfile->devno, 1);
179162306a36Sopenharmony_ci        if (ret)
179262306a36Sopenharmony_ci        {
179362306a36Sopenharmony_ci            ffs_epfiles_destroy(epfiles, i - 1);
179462306a36Sopenharmony_ci            return -EBUSY;
179562306a36Sopenharmony_ci        }
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci        epfile->device = device_create(ffs_class, NULL, epfile->devno, NULL, epfile->name);
179862306a36Sopenharmony_ci        if (IS_ERR(epfile->device))
179962306a36Sopenharmony_ci        {
180062306a36Sopenharmony_ci            cdev_del(&epfile->cdev);
180162306a36Sopenharmony_ci            ffs_epfiles_destroy(epfiles, i - 1);
180262306a36Sopenharmony_ci            return -EBUSY;
180362306a36Sopenharmony_ci        }
180462306a36Sopenharmony_ci    }
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci    ffs->epfiles = epfiles;
180762306a36Sopenharmony_ci    return 0;
180862306a36Sopenharmony_ci}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cistatic void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
181162306a36Sopenharmony_ci{
181262306a36Sopenharmony_ci    struct ffs_epfile *epfile = epfiles;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci    ENTER();
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci    for (; count; --count, ++epfile) {
181762306a36Sopenharmony_ci        BUG_ON(mutex_is_locked(&epfile->mutex));
181862306a36Sopenharmony_ci        device_destroy(ffs_class, epfile->devno);
181962306a36Sopenharmony_ci        cdev_del(&epfile->cdev);
182062306a36Sopenharmony_ci    }
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci    kfree(epfiles);
182362306a36Sopenharmony_ci}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_cistatic void ffs_func_eps_disable(struct ffs_function *func)
182662306a36Sopenharmony_ci{
182762306a36Sopenharmony_ci    struct ffs_ep *ep         = func->eps;
182862306a36Sopenharmony_ci    struct ffs_epfile *epfile = func->ffs->epfiles;
182962306a36Sopenharmony_ci    unsigned count            = func->ffs->eps_count;
183062306a36Sopenharmony_ci    unsigned long flags;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci    spin_lock_irqsave(&func->ffs->eps_lock, flags);
183362306a36Sopenharmony_ci    while (count--) {
183462306a36Sopenharmony_ci        /* pending requests get nuked */
183562306a36Sopenharmony_ci        if (likely(ep->ep))
183662306a36Sopenharmony_ci            usb_ep_disable(ep->ep);
183762306a36Sopenharmony_ci        ++ep;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci        if (epfile) {
184062306a36Sopenharmony_ci            epfile->ep = NULL;
184162306a36Sopenharmony_ci            ++epfile;
184262306a36Sopenharmony_ci        }
184362306a36Sopenharmony_ci    }
184462306a36Sopenharmony_ci    spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
184562306a36Sopenharmony_ci}
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_cistatic int ffs_func_eps_enable(struct ffs_function *func)
184862306a36Sopenharmony_ci{
184962306a36Sopenharmony_ci    struct ffs_data *ffs      = func->ffs;
185062306a36Sopenharmony_ci    struct ffs_ep *ep         = func->eps;
185162306a36Sopenharmony_ci    struct ffs_epfile *epfile = ffs->epfiles;
185262306a36Sopenharmony_ci    unsigned count            = ffs->eps_count;
185362306a36Sopenharmony_ci    unsigned long flags;
185462306a36Sopenharmony_ci    int ret = 0;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci    spin_lock_irqsave(&func->ffs->eps_lock, flags);
185762306a36Sopenharmony_ci    while(count--) {
185862306a36Sopenharmony_ci        ep->ep->driver_data = ep;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci        ret = config_ep_by_speed(func->gadget, &func->function, ep->ep);
186162306a36Sopenharmony_ci        if (ret) {
186262306a36Sopenharmony_ci            pr_err("%s: config_ep_by_speed(%s) returned %d\n",
186362306a36Sopenharmony_ci                    __func__, ep->ep->name, ret);
186462306a36Sopenharmony_ci            break;
186562306a36Sopenharmony_ci        }
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci        ret = usb_ep_enable(ep->ep);
186862306a36Sopenharmony_ci        if (likely(!ret)) {
186962306a36Sopenharmony_ci            epfile->ep = ep;
187062306a36Sopenharmony_ci            epfile->in = usb_endpoint_dir_in(ep->ep->desc);
187162306a36Sopenharmony_ci            epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
187262306a36Sopenharmony_ci        } else {
187362306a36Sopenharmony_ci            break;
187462306a36Sopenharmony_ci        }
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci        ++ep;
187762306a36Sopenharmony_ci        ++epfile;
187862306a36Sopenharmony_ci    }
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci    wake_up_interruptible(&ffs->wait);
188162306a36Sopenharmony_ci    spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci    return ret;
188462306a36Sopenharmony_ci}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci/* Parsing and building descriptors and strings *****************************/
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci/*
188962306a36Sopenharmony_ci * This validates if data pointed by data is a valid USB descriptor as
189062306a36Sopenharmony_ci * well as record how many interfaces, endpoints and strings are
189162306a36Sopenharmony_ci * required by given configuration.  Returns address after the
189262306a36Sopenharmony_ci * descriptor or NULL if data is invalid.
189362306a36Sopenharmony_ci */
189462306a36Sopenharmony_cienum ffs_entity_type {
189562306a36Sopenharmony_ci    FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
189662306a36Sopenharmony_ci};
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_cienum ffs_os_desc_type {
189962306a36Sopenharmony_ci    FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP
190062306a36Sopenharmony_ci};
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_citypedef int (*ffs_entity_callback)(enum ffs_entity_type entity, u8 *valuep,
190362306a36Sopenharmony_ci                struct usb_descriptor_header *desc,
190462306a36Sopenharmony_ci                void *priv);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_citypedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
190762306a36Sopenharmony_ci                struct usb_os_desc_header *h, void *data,
190862306a36Sopenharmony_ci                unsigned len, void *priv);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_cistatic int __must_check ffs_do_single_desc(char *data, unsigned len,
191162306a36Sopenharmony_ci                ffs_entity_callback entity,
191262306a36Sopenharmony_ci                void *priv)
191362306a36Sopenharmony_ci{
191462306a36Sopenharmony_ci    struct usb_descriptor_header *_ds = (void *)data;
191562306a36Sopenharmony_ci    u8 length;
191662306a36Sopenharmony_ci    int ret;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci    ENTER();
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci    /* At least two bytes are required: length and type */
192162306a36Sopenharmony_ci    if (len < 2) {
192262306a36Sopenharmony_ci        pr_vdebug("descriptor too short\n");
192362306a36Sopenharmony_ci        return -EINVAL;
192462306a36Sopenharmony_ci    }
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci    /* If we have at least as many bytes as the descriptor takes? */
192762306a36Sopenharmony_ci    length = _ds->bLength;
192862306a36Sopenharmony_ci    if (len < length) {
192962306a36Sopenharmony_ci        pr_vdebug("descriptor longer then available data\n");
193062306a36Sopenharmony_ci        return -EINVAL;
193162306a36Sopenharmony_ci    }
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci#define __entity_check_INTERFACE(val)  1
193462306a36Sopenharmony_ci#define __entity_check_STRING(val)     (val)
193562306a36Sopenharmony_ci#define __entity_check_ENDPOINT(val)   ((val) & USB_ENDPOINT_NUMBER_MASK)
193662306a36Sopenharmony_ci#define __entity(type, val) do {                    \
193762306a36Sopenharmony_ci        pr_vdebug("entity " #type "(%02x)\n", (val));        \
193862306a36Sopenharmony_ci        if (unlikely(!__entity_check_ ##type(val))) {        \
193962306a36Sopenharmony_ci            pr_vdebug("invalid entity's value\n");        \
194062306a36Sopenharmony_ci            return -EINVAL;                    \
194162306a36Sopenharmony_ci        }                            \
194262306a36Sopenharmony_ci        ret = entity(FFS_ ##type, &val, _ds, priv);        \
194362306a36Sopenharmony_ci        if (unlikely(ret < 0)) {                \
194462306a36Sopenharmony_ci            pr_debug("entity " #type "(%02x); ret = %d\n",    \
194562306a36Sopenharmony_ci                 (val), ret);                \
194662306a36Sopenharmony_ci            return ret;                    \
194762306a36Sopenharmony_ci        }                            \
194862306a36Sopenharmony_ci    } while (0)
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci    /* Parse descriptor depending on type. */
195162306a36Sopenharmony_ci    switch (_ds->bDescriptorType) {
195262306a36Sopenharmony_ci    case USB_DT_DEVICE:
195362306a36Sopenharmony_ci    case USB_DT_CONFIG:
195462306a36Sopenharmony_ci    case USB_DT_STRING:
195562306a36Sopenharmony_ci    case USB_DT_DEVICE_QUALIFIER:
195662306a36Sopenharmony_ci        /* function can't have any of those */
195762306a36Sopenharmony_ci        pr_vdebug("descriptor reserved for gadget: %d\n",
195862306a36Sopenharmony_ci              _ds->bDescriptorType);
195962306a36Sopenharmony_ci        return -EINVAL;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci    case USB_DT_INTERFACE: {
196262306a36Sopenharmony_ci        struct usb_interface_descriptor *ds = (void *)_ds;
196362306a36Sopenharmony_ci        pr_vdebug("interface descriptor\n");
196462306a36Sopenharmony_ci        if (length != sizeof *ds)
196562306a36Sopenharmony_ci            goto inv_length;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci        __entity(INTERFACE, ds->bInterfaceNumber);
196862306a36Sopenharmony_ci        if (ds->iInterface)
196962306a36Sopenharmony_ci            __entity(STRING, ds->iInterface);
197062306a36Sopenharmony_ci    }
197162306a36Sopenharmony_ci        break;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci    case USB_DT_ENDPOINT: {
197462306a36Sopenharmony_ci        struct usb_endpoint_descriptor *ds = (void *)_ds;
197562306a36Sopenharmony_ci        pr_vdebug("endpoint descriptor\n");
197662306a36Sopenharmony_ci        if (length != USB_DT_ENDPOINT_SIZE &&
197762306a36Sopenharmony_ci            length != USB_DT_ENDPOINT_AUDIO_SIZE)
197862306a36Sopenharmony_ci            goto inv_length;
197962306a36Sopenharmony_ci        __entity(ENDPOINT, ds->bEndpointAddress);
198062306a36Sopenharmony_ci    }
198162306a36Sopenharmony_ci        break;
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci    case HID_DT_HID:
198462306a36Sopenharmony_ci        pr_vdebug("hid descriptor\n");
198562306a36Sopenharmony_ci        if (length != sizeof(struct hid_descriptor))
198662306a36Sopenharmony_ci            goto inv_length;
198762306a36Sopenharmony_ci        break;
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci    case USB_DT_OTG:
199062306a36Sopenharmony_ci        if (length != sizeof(struct usb_otg_descriptor))
199162306a36Sopenharmony_ci            goto inv_length;
199262306a36Sopenharmony_ci        break;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci    case USB_DT_INTERFACE_ASSOCIATION: {
199562306a36Sopenharmony_ci        struct usb_interface_assoc_descriptor *ds = (void *)_ds;
199662306a36Sopenharmony_ci        pr_vdebug("interface association descriptor\n");
199762306a36Sopenharmony_ci        if (length != sizeof *ds)
199862306a36Sopenharmony_ci            goto inv_length;
199962306a36Sopenharmony_ci        if (ds->iFunction)
200062306a36Sopenharmony_ci            __entity(STRING, ds->iFunction);
200162306a36Sopenharmony_ci    }
200262306a36Sopenharmony_ci        break;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci    case USB_DT_SS_ENDPOINT_COMP:
200562306a36Sopenharmony_ci        pr_vdebug("EP SS companion descriptor\n");
200662306a36Sopenharmony_ci        if (length != sizeof(struct usb_ss_ep_comp_descriptor))
200762306a36Sopenharmony_ci            goto inv_length;
200862306a36Sopenharmony_ci        break;
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci    case USB_DT_OTHER_SPEED_CONFIG:
201162306a36Sopenharmony_ci    case USB_DT_INTERFACE_POWER:
201262306a36Sopenharmony_ci    case USB_DT_DEBUG:
201362306a36Sopenharmony_ci    case USB_DT_SECURITY:
201462306a36Sopenharmony_ci    case USB_DT_CS_RADIO_CONTROL:
201562306a36Sopenharmony_ci        pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
201662306a36Sopenharmony_ci        break;
201762306a36Sopenharmony_ci    default:
201862306a36Sopenharmony_ci        /* We should never be here */
201962306a36Sopenharmony_ci        pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
202062306a36Sopenharmony_ci        break;
202162306a36Sopenharmony_ciinv_length:
202262306a36Sopenharmony_ci        pr_vdebug("invalid length: %d (descriptor %d)\n",
202362306a36Sopenharmony_ci              _ds->bLength, _ds->bDescriptorType);
202462306a36Sopenharmony_ci        return -EINVAL;
202562306a36Sopenharmony_ci    }
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci#undef __entity
202862306a36Sopenharmony_ci#undef __entity_check_DESCRIPTOR
202962306a36Sopenharmony_ci#undef __entity_check_INTERFACE
203062306a36Sopenharmony_ci#undef __entity_check_STRING
203162306a36Sopenharmony_ci#undef __entity_check_ENDPOINT
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci    return length;
203462306a36Sopenharmony_ci}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_cistatic int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
203762306a36Sopenharmony_ci                ffs_entity_callback entity, void *priv)
203862306a36Sopenharmony_ci{
203962306a36Sopenharmony_ci    const unsigned _len = len;
204062306a36Sopenharmony_ci    uintptr_t num = 0;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci    ENTER();
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci    for (;;) {
204562306a36Sopenharmony_ci        int ret;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci        if (num == count)
204862306a36Sopenharmony_ci            data = NULL;
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci        /* Record "descriptor" entity */
205162306a36Sopenharmony_ci        ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
205262306a36Sopenharmony_ci        if (unlikely(ret < 0)) {
205362306a36Sopenharmony_ci            pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
205462306a36Sopenharmony_ci                 num, ret);
205562306a36Sopenharmony_ci            return ret;
205662306a36Sopenharmony_ci        }
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci        if (!data)
205962306a36Sopenharmony_ci            return _len - len;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci        ret = ffs_do_single_desc(data, len, entity, priv);
206262306a36Sopenharmony_ci        if (unlikely(ret < 0)) {
206362306a36Sopenharmony_ci            pr_debug("%s returns %d\n", __func__, ret);
206462306a36Sopenharmony_ci            return ret;
206562306a36Sopenharmony_ci        }
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci        len -= ret;
206862306a36Sopenharmony_ci        data += ret;
206962306a36Sopenharmony_ci        ++num;
207062306a36Sopenharmony_ci    }
207162306a36Sopenharmony_ci}
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_cistatic int __ffs_data_do_entity(enum ffs_entity_type type,
207462306a36Sopenharmony_ci                u8 *valuep, struct usb_descriptor_header *desc,
207562306a36Sopenharmony_ci                void *priv)
207662306a36Sopenharmony_ci{
207762306a36Sopenharmony_ci    struct ffs_desc_helper *helper = priv;
207862306a36Sopenharmony_ci    struct usb_endpoint_descriptor *d = NULL;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci    ENTER();
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci    switch (type) {
208362306a36Sopenharmony_ci    case FFS_DESCRIPTOR:
208462306a36Sopenharmony_ci        break;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci    case FFS_INTERFACE:
208762306a36Sopenharmony_ci        /*
208862306a36Sopenharmony_ci         * Interfaces are indexed from zero so if we
208962306a36Sopenharmony_ci         * encountered interface "n" then there are at least
209062306a36Sopenharmony_ci         * "n+1" interfaces.
209162306a36Sopenharmony_ci         */
209262306a36Sopenharmony_ci        if (*valuep >= helper->interfaces_count)
209362306a36Sopenharmony_ci            helper->interfaces_count = *valuep + 1;
209462306a36Sopenharmony_ci        break;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci    case FFS_STRING:
209762306a36Sopenharmony_ci        /*
209862306a36Sopenharmony_ci         * Strings are indexed from 1 (0 is reserved
209962306a36Sopenharmony_ci         * for languages list)
210062306a36Sopenharmony_ci         */
210162306a36Sopenharmony_ci        if (*valuep > helper->ffs->strings_count)
210262306a36Sopenharmony_ci            helper->ffs->strings_count = *valuep;
210362306a36Sopenharmony_ci        break;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci    case FFS_ENDPOINT:
210662306a36Sopenharmony_ci        d = (void *)desc;
210762306a36Sopenharmony_ci        helper->eps_count++;
210862306a36Sopenharmony_ci        if (helper->eps_count >= FFS_MAX_EPS_COUNT)
210962306a36Sopenharmony_ci            return -EINVAL;
211062306a36Sopenharmony_ci        /* Check if descriptors for any speed were already parsed */
211162306a36Sopenharmony_ci        if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
211262306a36Sopenharmony_ci            helper->ffs->eps_addrmap[helper->eps_count] =
211362306a36Sopenharmony_ci                d->bEndpointAddress;
211462306a36Sopenharmony_ci        else if (helper->ffs->eps_addrmap[helper->eps_count] !=
211562306a36Sopenharmony_ci                d->bEndpointAddress)
211662306a36Sopenharmony_ci            return -EINVAL;
211762306a36Sopenharmony_ci        break;
211862306a36Sopenharmony_ci    }
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci    return 0;
212162306a36Sopenharmony_ci}
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_cistatic int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
212462306a36Sopenharmony_ci                struct usb_os_desc_header *desc)
212562306a36Sopenharmony_ci{
212662306a36Sopenharmony_ci    u16 bcd_version = le16_to_cpu(desc->bcdVersion);
212762306a36Sopenharmony_ci    u16 w_index = le16_to_cpu(desc->wIndex);
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci    if (bcd_version != 1) {
213062306a36Sopenharmony_ci        pr_vdebug("unsupported os descriptors version: %d",
213162306a36Sopenharmony_ci              bcd_version);
213262306a36Sopenharmony_ci        return -EINVAL;
213362306a36Sopenharmony_ci    }
213462306a36Sopenharmony_ci    switch (w_index) {
213562306a36Sopenharmony_ci    case 0x4:
213662306a36Sopenharmony_ci        *next_type = FFS_OS_DESC_EXT_COMPAT;
213762306a36Sopenharmony_ci        break;
213862306a36Sopenharmony_ci    case 0x5:
213962306a36Sopenharmony_ci        *next_type = FFS_OS_DESC_EXT_PROP;
214062306a36Sopenharmony_ci        break;
214162306a36Sopenharmony_ci    default:
214262306a36Sopenharmony_ci        pr_vdebug("unsupported os descriptor type: %d", w_index);
214362306a36Sopenharmony_ci        return -EINVAL;
214462306a36Sopenharmony_ci    }
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci    return sizeof(*desc);
214762306a36Sopenharmony_ci}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci/*
215062306a36Sopenharmony_ci * Process all extended compatibility/extended property descriptors
215162306a36Sopenharmony_ci * of a feature descriptor
215262306a36Sopenharmony_ci */
215362306a36Sopenharmony_cistatic int __must_check ffs_do_single_os_desc(char *data, unsigned len,
215462306a36Sopenharmony_ci                enum ffs_os_desc_type type,
215562306a36Sopenharmony_ci                u16 feature_count,
215662306a36Sopenharmony_ci                ffs_os_desc_callback entity,
215762306a36Sopenharmony_ci                void *priv,
215862306a36Sopenharmony_ci                struct usb_os_desc_header *h)
215962306a36Sopenharmony_ci{
216062306a36Sopenharmony_ci    int ret;
216162306a36Sopenharmony_ci    const unsigned _len = len;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci    ENTER();
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci    /* loop over all ext compat/ext prop descriptors */
216662306a36Sopenharmony_ci    while (feature_count--) {
216762306a36Sopenharmony_ci        ret = entity(type, h, data, len, priv);
216862306a36Sopenharmony_ci        if (unlikely(ret < 0)) {
216962306a36Sopenharmony_ci            pr_debug("bad OS descriptor, type: %d\n", type);
217062306a36Sopenharmony_ci            return ret;
217162306a36Sopenharmony_ci        }
217262306a36Sopenharmony_ci        data += ret;
217362306a36Sopenharmony_ci        len -= ret;
217462306a36Sopenharmony_ci    }
217562306a36Sopenharmony_ci    return _len - len;
217662306a36Sopenharmony_ci}
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci/* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */
217962306a36Sopenharmony_cistatic int __must_check ffs_do_os_descs(unsigned count,
218062306a36Sopenharmony_ci                char *data, unsigned len,
218162306a36Sopenharmony_ci                ffs_os_desc_callback entity, void *priv)
218262306a36Sopenharmony_ci{
218362306a36Sopenharmony_ci    const unsigned _len = len;
218462306a36Sopenharmony_ci    unsigned long num = 0;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci    ENTER();
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci    for (num = 0; num < count; ++num) {
218962306a36Sopenharmony_ci        int ret;
219062306a36Sopenharmony_ci        enum ffs_os_desc_type type;
219162306a36Sopenharmony_ci        u16 feature_count;
219262306a36Sopenharmony_ci        struct usb_os_desc_header *desc = (void *)data;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci        if (len < sizeof(*desc))
219562306a36Sopenharmony_ci            return -EINVAL;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci        /*
219862306a36Sopenharmony_ci         * Record "descriptor" entity.
219962306a36Sopenharmony_ci         * Process dwLength, bcdVersion, wIndex, get b/wCount.
220062306a36Sopenharmony_ci         * Move the data pointer to the beginning of extended
220162306a36Sopenharmony_ci         * compatibilities proper or extended properties proper
220262306a36Sopenharmony_ci         * portions of the data
220362306a36Sopenharmony_ci         */
220462306a36Sopenharmony_ci        if (le32_to_cpu(desc->dwLength) > len)
220562306a36Sopenharmony_ci            return -EINVAL;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci        ret = __ffs_do_os_desc_header(&type, desc);
220862306a36Sopenharmony_ci        if (unlikely(ret < 0)) {
220962306a36Sopenharmony_ci            pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
221062306a36Sopenharmony_ci                 num, ret);
221162306a36Sopenharmony_ci            return ret;
221262306a36Sopenharmony_ci        }
221362306a36Sopenharmony_ci        /*
221462306a36Sopenharmony_ci         * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??"
221562306a36Sopenharmony_ci         */
221662306a36Sopenharmony_ci        feature_count = le16_to_cpu(desc->wCount);
221762306a36Sopenharmony_ci        if (type == FFS_OS_DESC_EXT_COMPAT &&
221862306a36Sopenharmony_ci            (feature_count > 255 || desc->Reserved))
221962306a36Sopenharmony_ci                return -EINVAL;
222062306a36Sopenharmony_ci        len -= ret;
222162306a36Sopenharmony_ci        data += ret;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci        /*
222462306a36Sopenharmony_ci         * Process all function/property descriptors
222562306a36Sopenharmony_ci         * of this Feature Descriptor
222662306a36Sopenharmony_ci         */
222762306a36Sopenharmony_ci        ret = ffs_do_single_os_desc(data, len, type,
222862306a36Sopenharmony_ci                        feature_count, entity, priv, desc);
222962306a36Sopenharmony_ci        if (unlikely(ret < 0)) {
223062306a36Sopenharmony_ci            pr_debug("%s returns %d\n", __func__, ret);
223162306a36Sopenharmony_ci            return ret;
223262306a36Sopenharmony_ci        }
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci        len -= ret;
223562306a36Sopenharmony_ci        data += ret;
223662306a36Sopenharmony_ci    }
223762306a36Sopenharmony_ci    return _len - len;
223862306a36Sopenharmony_ci}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci/**
224162306a36Sopenharmony_ci * Validate contents of the buffer from userspace related to OS descriptors.
224262306a36Sopenharmony_ci */
224362306a36Sopenharmony_cistatic int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
224462306a36Sopenharmony_ci                 struct usb_os_desc_header *h, void *data,
224562306a36Sopenharmony_ci                 unsigned len, void *priv)
224662306a36Sopenharmony_ci{
224762306a36Sopenharmony_ci    struct ffs_data *ffs = priv;
224862306a36Sopenharmony_ci    u8 length;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci    ENTER();
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci    switch (type) {
225362306a36Sopenharmony_ci    case FFS_OS_DESC_EXT_COMPAT: {
225462306a36Sopenharmony_ci        struct usb_ext_compat_desc *d = data;
225562306a36Sopenharmony_ci        int i;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci        if (len < sizeof(*d) ||
225862306a36Sopenharmony_ci            d->bFirstInterfaceNumber >= ffs->interfaces_count)
225962306a36Sopenharmony_ci            return -EINVAL;
226062306a36Sopenharmony_ci        if (d->Reserved1 != 1) {
226162306a36Sopenharmony_ci            /*
226262306a36Sopenharmony_ci             * According to the spec, Reserved1 must be set to 1
226362306a36Sopenharmony_ci             * but older kernels incorrectly rejected non-zero
226462306a36Sopenharmony_ci             * values.  We fix it here to avoid returning EINVAL
226562306a36Sopenharmony_ci             * in response to values we used to accept.
226662306a36Sopenharmony_ci             */
226762306a36Sopenharmony_ci            pr_debug("usb_ext_compat_desc::Reserved1 forced to 1\n");
226862306a36Sopenharmony_ci            d->Reserved1 = 1;
226962306a36Sopenharmony_ci        }
227062306a36Sopenharmony_ci        for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
227162306a36Sopenharmony_ci            if (d->Reserved2[i])
227262306a36Sopenharmony_ci                return -EINVAL;
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci        length = sizeof(struct usb_ext_compat_desc);
227562306a36Sopenharmony_ci    }
227662306a36Sopenharmony_ci        break;
227762306a36Sopenharmony_ci    case FFS_OS_DESC_EXT_PROP: {
227862306a36Sopenharmony_ci        struct usb_ext_prop_desc *d = data;
227962306a36Sopenharmony_ci        u32 type, pdl;
228062306a36Sopenharmony_ci        u16 pnl;
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci        if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
228362306a36Sopenharmony_ci            return -EINVAL;
228462306a36Sopenharmony_ci        length = le32_to_cpu(d->dwSize);
228562306a36Sopenharmony_ci        if (len < length)
228662306a36Sopenharmony_ci            return -EINVAL;
228762306a36Sopenharmony_ci        type = le32_to_cpu(d->dwPropertyDataType);
228862306a36Sopenharmony_ci        if (type < USB_EXT_PROP_UNICODE ||
228962306a36Sopenharmony_ci            type > USB_EXT_PROP_UNICODE_MULTI) {
229062306a36Sopenharmony_ci            pr_vdebug("unsupported os descriptor property type: %d",
229162306a36Sopenharmony_ci                  type);
229262306a36Sopenharmony_ci            return -EINVAL;
229362306a36Sopenharmony_ci        }
229462306a36Sopenharmony_ci        pnl = le16_to_cpu(d->wPropertyNameLength);
229562306a36Sopenharmony_ci        if (length < 14 + pnl) {
229662306a36Sopenharmony_ci            pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n",
229762306a36Sopenharmony_ci                  length, pnl, type);
229862306a36Sopenharmony_ci            return -EINVAL;
229962306a36Sopenharmony_ci        }
230062306a36Sopenharmony_ci        pdl = le32_to_cpu(*(__le32 *)((u8 *)data + 10 + pnl));
230162306a36Sopenharmony_ci        if (length != 14 + pnl + pdl) {
230262306a36Sopenharmony_ci            pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
230362306a36Sopenharmony_ci                  length, pnl, pdl, type);
230462306a36Sopenharmony_ci            return -EINVAL;
230562306a36Sopenharmony_ci        }
230662306a36Sopenharmony_ci        ++ffs->ms_os_descs_ext_prop_count;
230762306a36Sopenharmony_ci        /* property name reported to the host as "WCHAR"s */
230862306a36Sopenharmony_ci        ffs->ms_os_descs_ext_prop_name_len += pnl * 2;
230962306a36Sopenharmony_ci        ffs->ms_os_descs_ext_prop_data_len += pdl;
231062306a36Sopenharmony_ci    }
231162306a36Sopenharmony_ci        break;
231262306a36Sopenharmony_ci    default:
231362306a36Sopenharmony_ci        pr_vdebug("unknown descriptor: %d\n", type);
231462306a36Sopenharmony_ci        return -EINVAL;
231562306a36Sopenharmony_ci    }
231662306a36Sopenharmony_ci    return length;
231762306a36Sopenharmony_ci}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_cistatic int __ffs_data_got_descs(struct ffs_data *ffs,
232062306a36Sopenharmony_ci                char *const _data, size_t len)
232162306a36Sopenharmony_ci{
232262306a36Sopenharmony_ci    char *data = _data, *raw_descs = NULL;
232362306a36Sopenharmony_ci    unsigned os_descs_count = 0, counts[3], flags;
232462306a36Sopenharmony_ci    int ret = -EINVAL, i;
232562306a36Sopenharmony_ci    struct ffs_desc_helper helper;
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci    ENTER();
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci    if (get_unaligned_le32(data + 4) != len)
233062306a36Sopenharmony_ci        goto error;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci    switch (get_unaligned_le32(data)) {
233362306a36Sopenharmony_ci    case FUNCTIONFS_DESCRIPTORS_MAGIC:
233462306a36Sopenharmony_ci        flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
233562306a36Sopenharmony_ci        data += 8;
233662306a36Sopenharmony_ci        len  -= 8;
233762306a36Sopenharmony_ci        break;
233862306a36Sopenharmony_ci    case FUNCTIONFS_DESCRIPTORS_MAGIC_V2:
233962306a36Sopenharmony_ci        flags = get_unaligned_le32(data + 8);
234062306a36Sopenharmony_ci        ffs->user_flags = flags;
234162306a36Sopenharmony_ci        if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
234262306a36Sopenharmony_ci                  FUNCTIONFS_HAS_HS_DESC |
234362306a36Sopenharmony_ci                  FUNCTIONFS_HAS_SS_DESC |
234462306a36Sopenharmony_ci                  FUNCTIONFS_HAS_MS_OS_DESC |
234562306a36Sopenharmony_ci                  FUNCTIONFS_VIRTUAL_ADDR |
234662306a36Sopenharmony_ci                  FUNCTIONFS_EVENTFD |
234762306a36Sopenharmony_ci                  FUNCTIONFS_ALL_CTRL_RECIP |
234862306a36Sopenharmony_ci                  FUNCTIONFS_CONFIG0_SETUP)) {
234962306a36Sopenharmony_ci            ret = -ENOSYS;
235062306a36Sopenharmony_ci            goto error;
235162306a36Sopenharmony_ci        }
235262306a36Sopenharmony_ci        data += 12;
235362306a36Sopenharmony_ci        len  -= 12;
235462306a36Sopenharmony_ci        break;
235562306a36Sopenharmony_ci    default:
235662306a36Sopenharmony_ci        goto error;
235762306a36Sopenharmony_ci    }
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci    if (flags & FUNCTIONFS_EVENTFD) {
236062306a36Sopenharmony_ci        if (len < 4)
236162306a36Sopenharmony_ci            goto error;
236262306a36Sopenharmony_ci        ffs->ffs_eventfd =
236362306a36Sopenharmony_ci            eventfd_ctx_fdget((int)get_unaligned_le32(data));
236462306a36Sopenharmony_ci        if (IS_ERR(ffs->ffs_eventfd)) {
236562306a36Sopenharmony_ci            ret = PTR_ERR(ffs->ffs_eventfd);
236662306a36Sopenharmony_ci            ffs->ffs_eventfd = NULL;
236762306a36Sopenharmony_ci            goto error;
236862306a36Sopenharmony_ci        }
236962306a36Sopenharmony_ci        data += 4;
237062306a36Sopenharmony_ci        len  -= 4;
237162306a36Sopenharmony_ci    }
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci    /* Read fs_count, hs_count and ss_count (if present) */
237462306a36Sopenharmony_ci    for (i = 0; i < 3; ++i) {
237562306a36Sopenharmony_ci        if (!(flags & (1 << i))) {
237662306a36Sopenharmony_ci            counts[i] = 0;
237762306a36Sopenharmony_ci        } else if (len < 4) {
237862306a36Sopenharmony_ci            goto error;
237962306a36Sopenharmony_ci        } else {
238062306a36Sopenharmony_ci            counts[i] = get_unaligned_le32(data);
238162306a36Sopenharmony_ci            data += 4;
238262306a36Sopenharmony_ci            len  -= 4;
238362306a36Sopenharmony_ci        }
238462306a36Sopenharmony_ci    }
238562306a36Sopenharmony_ci    if (flags & (1 << i)) {
238662306a36Sopenharmony_ci        if (len < 4) {
238762306a36Sopenharmony_ci            goto error;
238862306a36Sopenharmony_ci        }
238962306a36Sopenharmony_ci        os_descs_count = get_unaligned_le32(data);
239062306a36Sopenharmony_ci        data += 4;
239162306a36Sopenharmony_ci        len -= 4;
239262306a36Sopenharmony_ci    }
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci    /* Read descriptors */
239562306a36Sopenharmony_ci    raw_descs = data;
239662306a36Sopenharmony_ci    helper.ffs = ffs;
239762306a36Sopenharmony_ci    for (i = 0; i < 3; ++i) {
239862306a36Sopenharmony_ci        if (!counts[i])
239962306a36Sopenharmony_ci            continue;
240062306a36Sopenharmony_ci        helper.interfaces_count = 0;
240162306a36Sopenharmony_ci        helper.eps_count = 0;
240262306a36Sopenharmony_ci        ret = ffs_do_descs(counts[i], data, len,
240362306a36Sopenharmony_ci                   __ffs_data_do_entity, &helper);
240462306a36Sopenharmony_ci        if (ret < 0)
240562306a36Sopenharmony_ci            goto error;
240662306a36Sopenharmony_ci        if (!ffs->eps_count && !ffs->interfaces_count) {
240762306a36Sopenharmony_ci            ffs->eps_count = helper.eps_count;
240862306a36Sopenharmony_ci            ffs->interfaces_count = helper.interfaces_count;
240962306a36Sopenharmony_ci        } else {
241062306a36Sopenharmony_ci            if (ffs->eps_count != helper.eps_count) {
241162306a36Sopenharmony_ci                ret = -EINVAL;
241262306a36Sopenharmony_ci                goto error;
241362306a36Sopenharmony_ci            }
241462306a36Sopenharmony_ci            if (ffs->interfaces_count != helper.interfaces_count) {
241562306a36Sopenharmony_ci                ret = -EINVAL;
241662306a36Sopenharmony_ci                goto error;
241762306a36Sopenharmony_ci            }
241862306a36Sopenharmony_ci        }
241962306a36Sopenharmony_ci        data += ret;
242062306a36Sopenharmony_ci        len  -= ret;
242162306a36Sopenharmony_ci    }
242262306a36Sopenharmony_ci    if (os_descs_count) {
242362306a36Sopenharmony_ci        ret = ffs_do_os_descs(os_descs_count, data, len,
242462306a36Sopenharmony_ci                      __ffs_data_do_os_desc, ffs);
242562306a36Sopenharmony_ci        if (ret < 0)
242662306a36Sopenharmony_ci            goto error;
242762306a36Sopenharmony_ci        data += ret;
242862306a36Sopenharmony_ci        len -= ret;
242962306a36Sopenharmony_ci    }
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci    if (raw_descs == data || len) {
243262306a36Sopenharmony_ci        ret = -EINVAL;
243362306a36Sopenharmony_ci        goto error;
243462306a36Sopenharmony_ci    }
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci    ffs->raw_descs_data    = _data;
243762306a36Sopenharmony_ci    ffs->raw_descs        = raw_descs;
243862306a36Sopenharmony_ci    ffs->raw_descs_length    = data - raw_descs;
243962306a36Sopenharmony_ci    ffs->fs_descs_count    = counts[0];
244062306a36Sopenharmony_ci    ffs->hs_descs_count    = counts[1];
244162306a36Sopenharmony_ci    ffs->ss_descs_count    = counts[2];
244262306a36Sopenharmony_ci    ffs->ms_os_descs_count    = os_descs_count;
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci    return 0;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_cierror:
244762306a36Sopenharmony_ci    kfree(_data);
244862306a36Sopenharmony_ci    return ret;
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_cistatic int __ffs_data_got_strings(struct ffs_data *ffs,
245262306a36Sopenharmony_ci                char *const _data, size_t len)
245362306a36Sopenharmony_ci{
245462306a36Sopenharmony_ci    u32 str_count, needed_count, lang_count;
245562306a36Sopenharmony_ci    struct usb_gadget_strings **stringtabs = NULL, *t = NULL;
245662306a36Sopenharmony_ci    const char *data = _data;
245762306a36Sopenharmony_ci    struct usb_string *s = NULL;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci    ENTER();
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci    if (unlikely(len < 16 ||
246262306a36Sopenharmony_ci             get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
246362306a36Sopenharmony_ci             get_unaligned_le32(data + 4) != len))
246462306a36Sopenharmony_ci        goto error;
246562306a36Sopenharmony_ci    str_count  = get_unaligned_le32(data + 8);
246662306a36Sopenharmony_ci    lang_count = get_unaligned_le32(data + 12);
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci    /* if one is zero the other must be zero */
246962306a36Sopenharmony_ci    if (unlikely(!str_count != !lang_count))
247062306a36Sopenharmony_ci        goto error;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci    /* Do we have at least as many strings as descriptors need? */
247362306a36Sopenharmony_ci    needed_count = ffs->strings_count;
247462306a36Sopenharmony_ci    if (unlikely(str_count < needed_count))
247562306a36Sopenharmony_ci        goto error;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci    /*
247862306a36Sopenharmony_ci     * If we don't need any strings just return and free all
247962306a36Sopenharmony_ci     * memory.
248062306a36Sopenharmony_ci     */
248162306a36Sopenharmony_ci    if (!needed_count) {
248262306a36Sopenharmony_ci        kfree(_data);
248362306a36Sopenharmony_ci        return 0;
248462306a36Sopenharmony_ci    }
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci    /* Allocate everything in one chunk so there's less maintenance. */
248762306a36Sopenharmony_ci    {
248862306a36Sopenharmony_ci        unsigned i = 0;
248962306a36Sopenharmony_ci        vla_group(d);
249062306a36Sopenharmony_ci        vla_item(d, struct usb_gadget_strings *, stringtabs,
249162306a36Sopenharmony_ci            lang_count + 1);
249262306a36Sopenharmony_ci        vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
249362306a36Sopenharmony_ci        vla_item(d, struct usb_string, strings,
249462306a36Sopenharmony_ci            lang_count*(needed_count+1));
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci        char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci        if (unlikely(!vlabuf)) {
249962306a36Sopenharmony_ci            kfree(_data);
250062306a36Sopenharmony_ci            return -ENOMEM;
250162306a36Sopenharmony_ci        }
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci        /* Initialize the VLA pointers */
250462306a36Sopenharmony_ci        stringtabs = vla_ptr(vlabuf, d, stringtabs);
250562306a36Sopenharmony_ci        t = vla_ptr(vlabuf, d, stringtab);
250662306a36Sopenharmony_ci        i = lang_count;
250762306a36Sopenharmony_ci        do {
250862306a36Sopenharmony_ci            *stringtabs++ = t++;
250962306a36Sopenharmony_ci        } while (--i);
251062306a36Sopenharmony_ci        *stringtabs = NULL;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci        /* stringtabs = vlabuf = d_stringtabs for later kfree */
251362306a36Sopenharmony_ci        stringtabs = vla_ptr(vlabuf, d, stringtabs);
251462306a36Sopenharmony_ci        t = vla_ptr(vlabuf, d, stringtab);
251562306a36Sopenharmony_ci        s = vla_ptr(vlabuf, d, strings);
251662306a36Sopenharmony_ci    }
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci    /* For each language */
251962306a36Sopenharmony_ci    data += 16;
252062306a36Sopenharmony_ci    len -= 16;
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci    do { /* lang_count > 0 so we can use do-while */
252362306a36Sopenharmony_ci        unsigned needed = needed_count;
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci        if (unlikely(len < 3))
252662306a36Sopenharmony_ci            goto error_free;
252762306a36Sopenharmony_ci        t->language = get_unaligned_le16(data);
252862306a36Sopenharmony_ci        t->strings  = s;
252962306a36Sopenharmony_ci        ++t;
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci        data += 2;
253262306a36Sopenharmony_ci        len -= 2;
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci        /* For each string */
253562306a36Sopenharmony_ci        do { /* str_count > 0 so we can use do-while */
253662306a36Sopenharmony_ci            size_t length = strnlen(data, len);
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci            if (unlikely(length == len))
253962306a36Sopenharmony_ci                goto error_free;
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci            /*
254262306a36Sopenharmony_ci             * User may provide more strings then we need,
254362306a36Sopenharmony_ci             * if that's the case we simply ignore the
254462306a36Sopenharmony_ci             * rest
254562306a36Sopenharmony_ci             */
254662306a36Sopenharmony_ci            if (likely(needed)) {
254762306a36Sopenharmony_ci                /*
254862306a36Sopenharmony_ci                 * s->id will be set while adding
254962306a36Sopenharmony_ci                 * function to configuration so for
255062306a36Sopenharmony_ci                 * now just leave garbage here.
255162306a36Sopenharmony_ci                 */
255262306a36Sopenharmony_ci                s->s = data;
255362306a36Sopenharmony_ci                --needed;
255462306a36Sopenharmony_ci                ++s;
255562306a36Sopenharmony_ci            }
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci            data += length + 1;
255862306a36Sopenharmony_ci            len -= length + 1;
255962306a36Sopenharmony_ci        } while (--str_count);
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci        s->id = 0;   /* terminator */
256262306a36Sopenharmony_ci        s->s = NULL;
256362306a36Sopenharmony_ci        ++s;
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci    } while (--lang_count);
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci    /* Some garbage left? */
256862306a36Sopenharmony_ci    if (unlikely(len))
256962306a36Sopenharmony_ci        goto error_free;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci    /* Done! */
257262306a36Sopenharmony_ci    ffs->stringtabs = stringtabs;
257362306a36Sopenharmony_ci    ffs->raw_strings = _data;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci    return 0;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_cierror_free:
257862306a36Sopenharmony_ci    kfree(stringtabs);
257962306a36Sopenharmony_cierror:
258062306a36Sopenharmony_ci    kfree(_data);
258162306a36Sopenharmony_ci    return -EINVAL;
258262306a36Sopenharmony_ci}
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci/* Events handling and management *******************************************/
258562306a36Sopenharmony_cistatic void __ffs_event_add(struct ffs_data *ffs,
258662306a36Sopenharmony_ci                enum usb_functionfs_event_type type)
258762306a36Sopenharmony_ci{
258862306a36Sopenharmony_ci    enum usb_functionfs_event_type rem_type1, rem_type2 = type;
258962306a36Sopenharmony_ci    int neg = 0;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci    /*
259262306a36Sopenharmony_ci     * Abort any unhandled setup
259362306a36Sopenharmony_ci     *
259462306a36Sopenharmony_ci     * We do not need to worry about some cmpxchg() changing value
259562306a36Sopenharmony_ci     * of ffs->setup_state without holding the lock because when
259662306a36Sopenharmony_ci     * state is FFS_SETUP_PENDING cmpxchg() in several places in
259762306a36Sopenharmony_ci     * the source does nothing.
259862306a36Sopenharmony_ci     */
259962306a36Sopenharmony_ci    if (ffs->setup_state == FFS_SETUP_PENDING)
260062306a36Sopenharmony_ci        ffs->setup_state = FFS_SETUP_CANCELLED;
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci    /*
260362306a36Sopenharmony_ci     * Logic of this function guarantees that there are at most four pending
260462306a36Sopenharmony_ci     * evens on ffs->ev.types queue.  This is important because the queue
260562306a36Sopenharmony_ci     * has space for four elements only and __ffs_ep0_read_events function
260662306a36Sopenharmony_ci     * depends on that limit as well.  If more event types are added, those
260762306a36Sopenharmony_ci     * limits have to be revisited or guaranteed to still hold.
260862306a36Sopenharmony_ci     */
260962306a36Sopenharmony_ci    switch (type) {
261062306a36Sopenharmony_ci    case FUNCTIONFS_RESUME:
261162306a36Sopenharmony_ci        rem_type2 = FUNCTIONFS_SUSPEND;
261262306a36Sopenharmony_ci        /* FALL THROUGH */
261362306a36Sopenharmony_ci    case FUNCTIONFS_SUSPEND:
261462306a36Sopenharmony_ci    case FUNCTIONFS_SETUP:
261562306a36Sopenharmony_ci        rem_type1 = type;
261662306a36Sopenharmony_ci        /* Discard all similar events */
261762306a36Sopenharmony_ci        break;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci    case FUNCTIONFS_BIND:
262062306a36Sopenharmony_ci    case FUNCTIONFS_UNBIND:
262162306a36Sopenharmony_ci    case FUNCTIONFS_DISABLE:
262262306a36Sopenharmony_ci    case FUNCTIONFS_ENABLE:
262362306a36Sopenharmony_ci        /* Discard everything other then power management. */
262462306a36Sopenharmony_ci        rem_type1 = FUNCTIONFS_SUSPEND;
262562306a36Sopenharmony_ci        rem_type2 = FUNCTIONFS_RESUME;
262662306a36Sopenharmony_ci        neg = 1;
262762306a36Sopenharmony_ci        break;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci    default:
263062306a36Sopenharmony_ci        WARN(1, "%d: unknown event, this should not happen\n", type);
263162306a36Sopenharmony_ci        return;
263262306a36Sopenharmony_ci    }
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci    {
263562306a36Sopenharmony_ci        u8 *ev  = ffs->ev.types, *out = ev;
263662306a36Sopenharmony_ci        unsigned n = ffs->ev.count;
263762306a36Sopenharmony_ci        for (; n; --n, ++ev)
263862306a36Sopenharmony_ci            if ((*ev == rem_type1 || *ev == rem_type2) == neg)
263962306a36Sopenharmony_ci                *out++ = *ev;
264062306a36Sopenharmony_ci            else
264162306a36Sopenharmony_ci                pr_vdebug("purging event %d\n", *ev);
264262306a36Sopenharmony_ci        ffs->ev.count = out - ffs->ev.types;
264362306a36Sopenharmony_ci    }
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci    pr_vdebug("adding event %d\n", type);
264662306a36Sopenharmony_ci    ffs->ev.types[ffs->ev.count++] = type;
264762306a36Sopenharmony_ci    wake_up_locked(&ffs->ev.waitq);
264862306a36Sopenharmony_ci    if (ffs->ffs_eventfd)
264962306a36Sopenharmony_ci        eventfd_signal(ffs->ffs_eventfd, 1);
265062306a36Sopenharmony_ci}
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_cistatic void ffs_event_add(struct ffs_data *ffs,
265362306a36Sopenharmony_ci              enum usb_functionfs_event_type type)
265462306a36Sopenharmony_ci{
265562306a36Sopenharmony_ci    unsigned long flags;
265662306a36Sopenharmony_ci    spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
265762306a36Sopenharmony_ci    __ffs_event_add(ffs, type);
265862306a36Sopenharmony_ci    spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
265962306a36Sopenharmony_ci}
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci/* Bind/unbind USB function hooks *******************************************/
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_cistatic int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
266462306a36Sopenharmony_ci{
266562306a36Sopenharmony_ci    int i;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci    for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
266862306a36Sopenharmony_ci        if (ffs->eps_addrmap[i] == endpoint_address)
266962306a36Sopenharmony_ci            return i;
267062306a36Sopenharmony_ci    return -ENOENT;
267162306a36Sopenharmony_ci}
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_cistatic int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
267462306a36Sopenharmony_ci                struct usb_descriptor_header *desc,
267562306a36Sopenharmony_ci                void *priv)
267662306a36Sopenharmony_ci{
267762306a36Sopenharmony_ci    struct usb_endpoint_descriptor *ds = (void *)desc;
267862306a36Sopenharmony_ci    struct ffs_function *func = priv;
267962306a36Sopenharmony_ci    struct ffs_ep *ffs_ep = NULL;
268062306a36Sopenharmony_ci    unsigned ep_desc_id;
268162306a36Sopenharmony_ci    int idx;
268262306a36Sopenharmony_ci    static const char *speed_names[] = { "full", "high", "super" };
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci    if (type != FFS_DESCRIPTOR)
268562306a36Sopenharmony_ci        return 0;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci    /*
268862306a36Sopenharmony_ci     * If ss_descriptors is not NULL, we are reading super speed
268962306a36Sopenharmony_ci     * descriptors; if hs_descriptors is not NULL, we are reading high
269062306a36Sopenharmony_ci     * speed descriptors; otherwise, we are reading full speed
269162306a36Sopenharmony_ci     * descriptors.
269262306a36Sopenharmony_ci     */
269362306a36Sopenharmony_ci    if (func->function.ss_descriptors) {
269462306a36Sopenharmony_ci        ep_desc_id = 2;
269562306a36Sopenharmony_ci        func->function.ss_descriptors[(uintptr_t)valuep] = desc;
269662306a36Sopenharmony_ci    } else if (func->function.hs_descriptors) {
269762306a36Sopenharmony_ci        ep_desc_id = 1;
269862306a36Sopenharmony_ci        func->function.hs_descriptors[(uintptr_t)valuep] = desc;
269962306a36Sopenharmony_ci    } else {
270062306a36Sopenharmony_ci        ep_desc_id = 0;
270162306a36Sopenharmony_ci        func->function.fs_descriptors[(uintptr_t)valuep]    = desc;
270262306a36Sopenharmony_ci    }
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci    if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
270562306a36Sopenharmony_ci        return 0;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci    idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
270862306a36Sopenharmony_ci    if (idx < 0)
270962306a36Sopenharmony_ci        return idx;
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci    ffs_ep = func->eps + idx;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci    if (unlikely(ffs_ep->descs[ep_desc_id])) {
271462306a36Sopenharmony_ci        pr_err("two %sspeed descriptors for EP %d\n",
271562306a36Sopenharmony_ci              speed_names[ep_desc_id],
271662306a36Sopenharmony_ci              ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
271762306a36Sopenharmony_ci        return -EINVAL;
271862306a36Sopenharmony_ci    }
271962306a36Sopenharmony_ci    ffs_ep->descs[ep_desc_id] = ds;
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci    ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
272262306a36Sopenharmony_ci    if (ffs_ep->ep) {
272362306a36Sopenharmony_ci        ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
272462306a36Sopenharmony_ci        if (!ds->wMaxPacketSize)
272562306a36Sopenharmony_ci            ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
272662306a36Sopenharmony_ci    } else {
272762306a36Sopenharmony_ci        struct usb_request *req = NULL;
272862306a36Sopenharmony_ci        struct usb_ep *ep = NULL;
272962306a36Sopenharmony_ci        u8 bEndpointAddress;
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci        /*
273262306a36Sopenharmony_ci         * We back up bEndpointAddress because autoconfig overwrites
273362306a36Sopenharmony_ci         * it with physical endpoint address.
273462306a36Sopenharmony_ci         */
273562306a36Sopenharmony_ci        bEndpointAddress = ds->bEndpointAddress;
273662306a36Sopenharmony_ci        pr_vdebug("autoconfig\n");
273762306a36Sopenharmony_ci        ep = usb_ep_autoconfig(func->gadget, ds);
273862306a36Sopenharmony_ci        if (unlikely(!ep))
273962306a36Sopenharmony_ci            return -ENOTSUPP;
274062306a36Sopenharmony_ci        ep->driver_data = func->eps + idx;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci        req = usb_ep_alloc_request(ep, GFP_KERNEL);
274362306a36Sopenharmony_ci        if (unlikely(!req))
274462306a36Sopenharmony_ci            return -ENOMEM;
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci        ffs_ep->ep  = ep;
274762306a36Sopenharmony_ci        ffs_ep->req = req;
274862306a36Sopenharmony_ci            INIT_LIST_HEAD(&ffs_ep->req->list);
274962306a36Sopenharmony_ci        func->eps_revmap[ds->bEndpointAddress &
275062306a36Sopenharmony_ci                 USB_ENDPOINT_NUMBER_MASK] = idx + 1;
275162306a36Sopenharmony_ci        /*
275262306a36Sopenharmony_ci         * If we use virtual address mapping, we restore
275362306a36Sopenharmony_ci         * original bEndpointAddress value.
275462306a36Sopenharmony_ci         */
275562306a36Sopenharmony_ci        if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
275662306a36Sopenharmony_ci            ds->bEndpointAddress = bEndpointAddress;
275762306a36Sopenharmony_ci    }
275862306a36Sopenharmony_ci    ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci    return 0;
276162306a36Sopenharmony_ci}
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_cistatic int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
276462306a36Sopenharmony_ci                struct usb_descriptor_header *desc,
276562306a36Sopenharmony_ci                void *priv)
276662306a36Sopenharmony_ci{
276762306a36Sopenharmony_ci    struct ffs_function *func = priv;
276862306a36Sopenharmony_ci    unsigned idx;
276962306a36Sopenharmony_ci    u8 newValue;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci    switch (type) {
277262306a36Sopenharmony_ci    default:
277362306a36Sopenharmony_ci    case FFS_DESCRIPTOR:
277462306a36Sopenharmony_ci        /* Handled in previous pass by __ffs_func_bind_do_descs() */
277562306a36Sopenharmony_ci        return 0;
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci    case FFS_INTERFACE:
277862306a36Sopenharmony_ci        idx = *valuep;
277962306a36Sopenharmony_ci        if (func->interfaces_nums[idx] < 0) {
278062306a36Sopenharmony_ci            int id = usb_interface_id(func->conf, &func->function);
278162306a36Sopenharmony_ci            if (unlikely(id < 0))
278262306a36Sopenharmony_ci                return id;
278362306a36Sopenharmony_ci            func->interfaces_nums[idx] = id;
278462306a36Sopenharmony_ci        }
278562306a36Sopenharmony_ci        newValue = func->interfaces_nums[idx];
278662306a36Sopenharmony_ci        break;
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci    case FFS_STRING:
278962306a36Sopenharmony_ci        /* String' IDs are allocated when fsf_data is bound to cdev */
279062306a36Sopenharmony_ci        newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
279162306a36Sopenharmony_ci        break;
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci    case FFS_ENDPOINT:
279462306a36Sopenharmony_ci        /*
279562306a36Sopenharmony_ci         * USB_DT_ENDPOINT are handled in
279662306a36Sopenharmony_ci         * __ffs_func_bind_do_descs().
279762306a36Sopenharmony_ci         */
279862306a36Sopenharmony_ci        if (desc->bDescriptorType == USB_DT_ENDPOINT)
279962306a36Sopenharmony_ci            return 0;
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci        idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
280262306a36Sopenharmony_ci        if (unlikely(!func->eps[idx].ep))
280362306a36Sopenharmony_ci            return -EINVAL;
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci        {
280662306a36Sopenharmony_ci            struct usb_endpoint_descriptor **descs;
280762306a36Sopenharmony_ci            descs = func->eps[idx].descs;
280862306a36Sopenharmony_ci            newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
280962306a36Sopenharmony_ci        }
281062306a36Sopenharmony_ci        break;
281162306a36Sopenharmony_ci    }
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci    pr_vdebug("%02x -> %02x\n", *valuep, newValue);
281462306a36Sopenharmony_ci    *valuep = newValue;
281562306a36Sopenharmony_ci    return 0;
281662306a36Sopenharmony_ci}
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_cistatic int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
281962306a36Sopenharmony_ci                struct usb_os_desc_header *h, void *data,
282062306a36Sopenharmony_ci                unsigned len, void *priv)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci    struct ffs_function *func = priv;
282362306a36Sopenharmony_ci    u8 length = 0;
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci    switch (type) {
282662306a36Sopenharmony_ci    case FFS_OS_DESC_EXT_COMPAT: {
282762306a36Sopenharmony_ci        struct usb_ext_compat_desc *desc = data;
282862306a36Sopenharmony_ci        struct usb_os_desc_table *t;
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci        t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
283162306a36Sopenharmony_ci        t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
283262306a36Sopenharmony_ci        memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID,
283362306a36Sopenharmony_ci            ARRAY_SIZE(desc->CompatibleID) + ARRAY_SIZE(desc->SubCompatibleID));
283462306a36Sopenharmony_ci        length = sizeof(*desc);
283562306a36Sopenharmony_ci    }
283662306a36Sopenharmony_ci        break;
283762306a36Sopenharmony_ci    case FFS_OS_DESC_EXT_PROP: {
283862306a36Sopenharmony_ci        struct usb_ext_prop_desc *desc = data;
283962306a36Sopenharmony_ci        struct usb_os_desc_table *t;
284062306a36Sopenharmony_ci        struct usb_os_desc_ext_prop *ext_prop;
284162306a36Sopenharmony_ci        char *ext_prop_name;
284262306a36Sopenharmony_ci        char *ext_prop_data;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci        t = &func->function.os_desc_table[h->interface];
284562306a36Sopenharmony_ci        t->if_id = func->interfaces_nums[h->interface];
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci        ext_prop = func->ffs->ms_os_descs_ext_prop_avail;
284862306a36Sopenharmony_ci        func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop);
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci        ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
285162306a36Sopenharmony_ci        ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
285262306a36Sopenharmony_ci        ext_prop->data_len = le32_to_cpu(*(__le32 *)
285362306a36Sopenharmony_ci            usb_ext_prop_data_len_ptr(data, ext_prop->name_len));
285462306a36Sopenharmony_ci        length = ext_prop->name_len + ext_prop->data_len + 14;
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci        ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail;
285762306a36Sopenharmony_ci        func->ffs->ms_os_descs_ext_prop_name_avail +=
285862306a36Sopenharmony_ci            ext_prop->name_len;
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci        ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
286162306a36Sopenharmony_ci        func->ffs->ms_os_descs_ext_prop_data_avail +=
286262306a36Sopenharmony_ci            ext_prop->data_len;
286362306a36Sopenharmony_ci        memcpy(ext_prop_data, usb_ext_prop_data_ptr(data, ext_prop->name_len),
286462306a36Sopenharmony_ci            ext_prop->data_len);
286562306a36Sopenharmony_ci        /* unicode data reported to the host as "WCHAR"s */
286662306a36Sopenharmony_ci        switch (ext_prop->type) {
286762306a36Sopenharmony_ci        case USB_EXT_PROP_UNICODE:
286862306a36Sopenharmony_ci        case USB_EXT_PROP_UNICODE_ENV:
286962306a36Sopenharmony_ci        case USB_EXT_PROP_UNICODE_LINK:
287062306a36Sopenharmony_ci        case USB_EXT_PROP_UNICODE_MULTI:
287162306a36Sopenharmony_ci            ext_prop->data_len *= 2;
287262306a36Sopenharmony_ci            break;
287362306a36Sopenharmony_ci        }
287462306a36Sopenharmony_ci        ext_prop->data = ext_prop_data;
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci        memcpy(ext_prop_name, usb_ext_prop_name_ptr(data),
287762306a36Sopenharmony_ci            ext_prop->name_len);
287862306a36Sopenharmony_ci		/* property name reported to the host as "WCHAR"s */
287962306a36Sopenharmony_ci        ext_prop->name_len *= 2;
288062306a36Sopenharmony_ci        ext_prop->name = ext_prop_name;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci        t->os_desc->ext_prop_len +=
288362306a36Sopenharmony_ci            ext_prop->name_len + ext_prop->data_len + 14;
288462306a36Sopenharmony_ci        ++t->os_desc->ext_prop_count;
288562306a36Sopenharmony_ci        list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop);
288662306a36Sopenharmony_ci    }
288762306a36Sopenharmony_ci        break;
288862306a36Sopenharmony_ci    default:
288962306a36Sopenharmony_ci        pr_vdebug("unknown descriptor: %d\n", type);
289062306a36Sopenharmony_ci    }
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci    return length;
289362306a36Sopenharmony_ci}
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_cistatic inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
289662306a36Sopenharmony_ci                struct usb_configuration *c)
289762306a36Sopenharmony_ci{
289862306a36Sopenharmony_ci    struct ffs_function *func = ffs_func_from_usb(f);
289962306a36Sopenharmony_ci    struct f_fs_opts *ffs_opts =
290062306a36Sopenharmony_ci        container_of(f->fi, struct f_fs_opts, func_inst);
290162306a36Sopenharmony_ci    int ret;
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci    ENTER();
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci    /*
290662306a36Sopenharmony_ci     * Legacy gadget triggers binding in functionfs_ready_callback,
290762306a36Sopenharmony_ci     * which already uses locking; taking the same lock here would
290862306a36Sopenharmony_ci     * cause a deadlock.
290962306a36Sopenharmony_ci     *
291062306a36Sopenharmony_ci     * Configfs-enabled gadgets however do need ffs_dev_lock.
291162306a36Sopenharmony_ci     */
291262306a36Sopenharmony_ci    if (!ffs_opts->no_configfs)
291362306a36Sopenharmony_ci        ffs_dev_lock();
291462306a36Sopenharmony_ci    ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
291562306a36Sopenharmony_ci    func->ffs = ffs_opts->dev->ffs_data;
291662306a36Sopenharmony_ci    if (!ffs_opts->no_configfs)
291762306a36Sopenharmony_ci        ffs_dev_unlock();
291862306a36Sopenharmony_ci    if (ret)
291962306a36Sopenharmony_ci        return ERR_PTR(ret);
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci    func->conf = c;
292262306a36Sopenharmony_ci    func->gadget = c->cdev->gadget;
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci    /*
292562306a36Sopenharmony_ci     * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
292662306a36Sopenharmony_ci     * configurations are bound in sequence with list_for_each_entry,
292762306a36Sopenharmony_ci     * in each configuration its functions are bound in sequence
292862306a36Sopenharmony_ci     * with list_for_each_entry, so we assume no race condition
292962306a36Sopenharmony_ci     * with regard to ffs_opts->bound access
293062306a36Sopenharmony_ci     */
293162306a36Sopenharmony_ci    if (!ffs_opts->refcnt) {
293262306a36Sopenharmony_ci        ret = functionfs_bind(func->ffs, c->cdev);
293362306a36Sopenharmony_ci        if (ret)
293462306a36Sopenharmony_ci            return ERR_PTR(ret);
293562306a36Sopenharmony_ci    }
293662306a36Sopenharmony_ci    ffs_opts->refcnt++;
293762306a36Sopenharmony_ci    func->function.strings = func->ffs->stringtabs;
293862306a36Sopenharmony_ci
293962306a36Sopenharmony_ci    return ffs_opts;
294062306a36Sopenharmony_ci}
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_cistatic int _ffs_func_bind(struct usb_configuration *c, struct usb_function *f)
294362306a36Sopenharmony_ci{
294462306a36Sopenharmony_ci    struct ffs_function *func = ffs_func_from_usb(f);
294562306a36Sopenharmony_ci    struct ffs_data *ffs = func->ffs;
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci    const int full = !!func->ffs->fs_descs_count;
294862306a36Sopenharmony_ci    const int high = !!func->ffs->hs_descs_count;
294962306a36Sopenharmony_ci    const int super = !!func->ffs->ss_descs_count;
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ci    int fs_len, hs_len, ss_len, ret, i;
295262306a36Sopenharmony_ci    struct ffs_ep *eps_ptr = NULL;
295362306a36Sopenharmony_ci    struct usb_descriptor_header *des_head = NULL;
295462306a36Sopenharmony_ci    struct usb_interface_descriptor *intf_ctl = NULL;
295562306a36Sopenharmony_ci    struct usb_interface_descriptor *intf_data = NULL;
295662306a36Sopenharmony_ci    /* Make it a single chunk, less management later on */
295762306a36Sopenharmony_ci    vla_group(d);
295862306a36Sopenharmony_ci    vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count);
295962306a36Sopenharmony_ci    vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs,
296062306a36Sopenharmony_ci        full ? ffs->fs_descs_count + 1 : 0);
296162306a36Sopenharmony_ci    vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
296262306a36Sopenharmony_ci        high ? ffs->hs_descs_count + 1 : 0);
296362306a36Sopenharmony_ci    vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
296462306a36Sopenharmony_ci        super ? ffs->ss_descs_count + 1 : 0);
296562306a36Sopenharmony_ci    vla_item_with_sz(d, short, inums, ffs->interfaces_count);
296662306a36Sopenharmony_ci    vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table,
296762306a36Sopenharmony_ci             c->cdev->use_os_string ? ffs->interfaces_count : 0);
296862306a36Sopenharmony_ci    vla_item_with_sz(d, char[16], ext_compat,
296962306a36Sopenharmony_ci             c->cdev->use_os_string ? ffs->interfaces_count : 0);
297062306a36Sopenharmony_ci    vla_item_with_sz(d, struct usb_os_desc, os_desc,
297162306a36Sopenharmony_ci             c->cdev->use_os_string ? ffs->interfaces_count : 0);
297262306a36Sopenharmony_ci    vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop,
297362306a36Sopenharmony_ci             ffs->ms_os_descs_ext_prop_count);
297462306a36Sopenharmony_ci    vla_item_with_sz(d, char, ext_prop_name,
297562306a36Sopenharmony_ci             ffs->ms_os_descs_ext_prop_name_len);
297662306a36Sopenharmony_ci    vla_item_with_sz(d, char, ext_prop_data,
297762306a36Sopenharmony_ci             ffs->ms_os_descs_ext_prop_data_len);
297862306a36Sopenharmony_ci    vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
297962306a36Sopenharmony_ci    char *vlabuf = NULL;
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci    ENTER();
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci    /* Has descriptors only for speeds gadget does not support */
298462306a36Sopenharmony_ci    if (unlikely(!(full | high | super)))
298562306a36Sopenharmony_ci        return -ENOTSUPP;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci    /* Allocate a single chunk, less management later on */
298862306a36Sopenharmony_ci    vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL);
298962306a36Sopenharmony_ci    if (unlikely(!vlabuf))
299062306a36Sopenharmony_ci        return -ENOMEM;
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci    ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
299362306a36Sopenharmony_ci    ffs->ms_os_descs_ext_prop_name_avail =
299462306a36Sopenharmony_ci        vla_ptr(vlabuf, d, ext_prop_name);
299562306a36Sopenharmony_ci    ffs->ms_os_descs_ext_prop_data_avail =
299662306a36Sopenharmony_ci        vla_ptr(vlabuf, d, ext_prop_data);
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci    /* Copy descriptors  */
299962306a36Sopenharmony_ci    memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, ffs->raw_descs_length);
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci    memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci    eps_ptr = vla_ptr(vlabuf, d, eps);
300462306a36Sopenharmony_ci    for (i = 0; i < ffs->eps_count; i++)
300562306a36Sopenharmony_ci        eps_ptr[i].num = -1;
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci    /* Save pointers
300862306a36Sopenharmony_ci     * d_eps == vlabuf, func->eps used to kfree vlabuf later
300962306a36Sopenharmony_ci    */
301062306a36Sopenharmony_ci    func->eps             = vla_ptr(vlabuf, d, eps);
301162306a36Sopenharmony_ci    func->interfaces_nums = vla_ptr(vlabuf, d, inums);
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci    /*
301462306a36Sopenharmony_ci     * Go through all the endpoint descriptors and allocate
301562306a36Sopenharmony_ci     * endpoints first, so that later we can rewrite the endpoint
301662306a36Sopenharmony_ci     * numbers without worrying that it may be described later on.
301762306a36Sopenharmony_ci     */
301862306a36Sopenharmony_ci    if (likely(full)) {
301962306a36Sopenharmony_ci        func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
302062306a36Sopenharmony_ci        fs_len = ffs_do_descs(ffs->fs_descs_count,
302162306a36Sopenharmony_ci                      vla_ptr(vlabuf, d, raw_descs),
302262306a36Sopenharmony_ci                      d_raw_descs__sz,
302362306a36Sopenharmony_ci                      __ffs_func_bind_do_descs, func);
302462306a36Sopenharmony_ci        if (unlikely(fs_len < 0)) {
302562306a36Sopenharmony_ci            ret = fs_len;
302662306a36Sopenharmony_ci            goto error;
302762306a36Sopenharmony_ci        }
302862306a36Sopenharmony_ci    } else {
302962306a36Sopenharmony_ci        fs_len = 0;
303062306a36Sopenharmony_ci    }
303162306a36Sopenharmony_ci    if (likely(high)) {
303262306a36Sopenharmony_ci        func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
303362306a36Sopenharmony_ci        hs_len = ffs_do_descs(ffs->hs_descs_count,
303462306a36Sopenharmony_ci                      vla_ptr(vlabuf, d, raw_descs) + fs_len,
303562306a36Sopenharmony_ci                      d_raw_descs__sz - fs_len,
303662306a36Sopenharmony_ci                      __ffs_func_bind_do_descs, func);
303762306a36Sopenharmony_ci        if (unlikely(hs_len < 0)) {
303862306a36Sopenharmony_ci            ret = hs_len;
303962306a36Sopenharmony_ci            goto error;
304062306a36Sopenharmony_ci        }
304162306a36Sopenharmony_ci    } else {
304262306a36Sopenharmony_ci        hs_len = 0;
304362306a36Sopenharmony_ci    }
304462306a36Sopenharmony_ci    if (likely(super)) {
304562306a36Sopenharmony_ci        func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
304662306a36Sopenharmony_ci        ss_len = ffs_do_descs(ffs->ss_descs_count,
304762306a36Sopenharmony_ci                vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
304862306a36Sopenharmony_ci                d_raw_descs__sz - fs_len - hs_len,
304962306a36Sopenharmony_ci                __ffs_func_bind_do_descs, func);
305062306a36Sopenharmony_ci        if (unlikely(ss_len < 0)) {
305162306a36Sopenharmony_ci            ret = ss_len;
305262306a36Sopenharmony_ci            goto error;
305362306a36Sopenharmony_ci        }
305462306a36Sopenharmony_ci    } else {
305562306a36Sopenharmony_ci        ss_len = 0;
305662306a36Sopenharmony_ci    }
305762306a36Sopenharmony_ci    /*
305862306a36Sopenharmony_ci     * Now handle interface numbers allocation and interface and
305962306a36Sopenharmony_ci     * endpoint numbers rewriting.  We can do that in one go
306062306a36Sopenharmony_ci     * now.
306162306a36Sopenharmony_ci     */
306262306a36Sopenharmony_ci    ret = ffs_do_descs(ffs->fs_descs_count +
306362306a36Sopenharmony_ci               (high ? ffs->hs_descs_count : 0) +
306462306a36Sopenharmony_ci               (super ? ffs->ss_descs_count : 0),
306562306a36Sopenharmony_ci               vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
306662306a36Sopenharmony_ci               __ffs_func_bind_do_nums, func);
306762306a36Sopenharmony_ci    if (unlikely(ret < 0))
306862306a36Sopenharmony_ci        goto error;
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci    func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
307162306a36Sopenharmony_ci    if (c->cdev->use_os_string) {
307262306a36Sopenharmony_ci        for (i = 0; i < ffs->interfaces_count; ++i) {
307362306a36Sopenharmony_ci            struct usb_os_desc *desc;
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci            desc = func->function.os_desc_table[i].os_desc =
307662306a36Sopenharmony_ci                vla_ptr(vlabuf, d, os_desc) +
307762306a36Sopenharmony_ci                i * sizeof(struct usb_os_desc);
307862306a36Sopenharmony_ci            desc->ext_compat_id =
307962306a36Sopenharmony_ci                vla_ptr(vlabuf, d, ext_compat) + i * 16;
308062306a36Sopenharmony_ci            INIT_LIST_HEAD(&desc->ext_prop);
308162306a36Sopenharmony_ci        }
308262306a36Sopenharmony_ci        ret = ffs_do_os_descs(ffs->ms_os_descs_count,
308362306a36Sopenharmony_ci                      vla_ptr(vlabuf, d, raw_descs) +
308462306a36Sopenharmony_ci                      fs_len + hs_len + ss_len,
308562306a36Sopenharmony_ci                      d_raw_descs__sz - fs_len - hs_len -
308662306a36Sopenharmony_ci                      ss_len,
308762306a36Sopenharmony_ci                      __ffs_func_bind_do_os_desc, func);
308862306a36Sopenharmony_ci        if (unlikely(ret < 0))
308962306a36Sopenharmony_ci            goto error;
309062306a36Sopenharmony_ci    }
309162306a36Sopenharmony_ci    func->function.os_desc_n =
309262306a36Sopenharmony_ci        c->cdev->use_os_string ? ffs->interfaces_count : 0;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci    for (i = 0; i< func->ffs->fs_descs_count; i++) {
309562306a36Sopenharmony_ci        des_head = func->function.fs_descriptors[i];
309662306a36Sopenharmony_ci        if (des_head->bDescriptorType == USB_DT_INTERFACE) {
309762306a36Sopenharmony_ci            struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)des_head;
309862306a36Sopenharmony_ci            if (intf->bNumEndpoints > 0) {
309962306a36Sopenharmony_ci                if (intf_ctl == NULL) {
310062306a36Sopenharmony_ci                    intf_ctl = intf;
310162306a36Sopenharmony_ci                } else {
310262306a36Sopenharmony_ci                    intf_data = intf;
310362306a36Sopenharmony_ci                    break;
310462306a36Sopenharmony_ci                }
310562306a36Sopenharmony_ci            }
310662306a36Sopenharmony_ci        }
310762306a36Sopenharmony_ci    }
310862306a36Sopenharmony_ci    for (i = 0; i< func->ffs->fs_descs_count; i++) {
310962306a36Sopenharmony_ci        des_head = func->function.fs_descriptors[i];
311062306a36Sopenharmony_ci        if (des_head->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) {
311162306a36Sopenharmony_ci            struct usb_interface_assoc_descriptor *a_dec = (struct usb_interface_assoc_descriptor *)des_head;
311262306a36Sopenharmony_ci            a_dec->bFirstInterface = intf_ctl->bInterfaceNumber;
311362306a36Sopenharmony_ci        } else if (des_head->bDescriptorType == USB_DT_CS_INTERFACE) {
311462306a36Sopenharmony_ci            struct usb_cdc_header_desc *cs_des = (struct usb_cdc_header_desc *)des_head;
311562306a36Sopenharmony_ci            if (cs_des->bDescriptorSubType == USB_CDC_CALL_MANAGEMENT_TYPE) {
311662306a36Sopenharmony_ci                struct usb_cdc_call_mgmt_descriptor *mgmt_des = (struct usb_cdc_call_mgmt_descriptor *)des_head;
311762306a36Sopenharmony_ci                mgmt_des->bDataInterface = intf_data->bInterfaceNumber;
311862306a36Sopenharmony_ci            } else if (cs_des->bDescriptorSubType == USB_CDC_UNION_TYPE) {
311962306a36Sopenharmony_ci                struct usb_cdc_union_desc *union_des = (struct usb_cdc_union_desc *)des_head;
312062306a36Sopenharmony_ci                union_des->bMasterInterface0 = intf_ctl->bInterfaceNumber;
312162306a36Sopenharmony_ci                union_des->bSlaveInterface0 = intf_data->bInterfaceNumber;
312262306a36Sopenharmony_ci            } else if (cs_des->bDescriptorSubType == USB_CDC_ETHERNET_TYPE) {
312362306a36Sopenharmony_ci                struct usb_cdc_ether_desc *ether_des = (struct usb_cdc_ether_desc *)des_head;
312462306a36Sopenharmony_ci                ether_des->iMACAddress = intf_ctl->iInterface + 1;
312562306a36Sopenharmony_ci            }
312662306a36Sopenharmony_ci        }
312762306a36Sopenharmony_ci    }
312862306a36Sopenharmony_ci    for (i = 0; i< func->ffs->hs_descs_count; i++) {
312962306a36Sopenharmony_ci        des_head = func->function.hs_descriptors[i];
313062306a36Sopenharmony_ci        if (des_head->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) {
313162306a36Sopenharmony_ci            struct usb_interface_assoc_descriptor *a_dec = (struct usb_interface_assoc_descriptor *)des_head;
313262306a36Sopenharmony_ci            a_dec->bFirstInterface = intf_ctl->bInterfaceNumber;
313362306a36Sopenharmony_ci        } else if (des_head->bDescriptorType == USB_DT_CS_INTERFACE) {
313462306a36Sopenharmony_ci            struct usb_cdc_header_desc *cs_des = (struct usb_cdc_header_desc *)des_head;
313562306a36Sopenharmony_ci            if (cs_des->bDescriptorSubType == USB_CDC_CALL_MANAGEMENT_TYPE) {
313662306a36Sopenharmony_ci                struct usb_cdc_call_mgmt_descriptor *mgmt_des = (struct usb_cdc_call_mgmt_descriptor *)des_head;
313762306a36Sopenharmony_ci                mgmt_des->bDataInterface = intf_data->bInterfaceNumber;
313862306a36Sopenharmony_ci            } else if (cs_des->bDescriptorSubType == USB_CDC_UNION_TYPE) {
313962306a36Sopenharmony_ci                struct usb_cdc_union_desc *union_des = (struct usb_cdc_union_desc *)des_head;
314062306a36Sopenharmony_ci                union_des->bMasterInterface0 = intf_ctl->bInterfaceNumber;
314162306a36Sopenharmony_ci                union_des->bSlaveInterface0 = intf_data->bInterfaceNumber;
314262306a36Sopenharmony_ci            } else if (cs_des->bDescriptorSubType == USB_CDC_ETHERNET_TYPE) {
314362306a36Sopenharmony_ci                struct usb_cdc_ether_desc *ether_des = (struct usb_cdc_ether_desc *)des_head;
314462306a36Sopenharmony_ci                ether_des->iMACAddress = intf_ctl->iInterface + 1;
314562306a36Sopenharmony_ci            }
314662306a36Sopenharmony_ci        }
314762306a36Sopenharmony_ci    }
314862306a36Sopenharmony_ci    for (i = 0; i< func->ffs->ss_descs_count; i++) {
314962306a36Sopenharmony_ci        des_head = func->function.ss_descriptors[i];
315062306a36Sopenharmony_ci        if (des_head->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) {
315162306a36Sopenharmony_ci            struct usb_interface_assoc_descriptor *a_dec = (struct usb_interface_assoc_descriptor *)des_head;
315262306a36Sopenharmony_ci            a_dec->bFirstInterface = intf_ctl->bInterfaceNumber;
315362306a36Sopenharmony_ci        } else if (des_head->bDescriptorType == USB_DT_CS_INTERFACE) {
315462306a36Sopenharmony_ci            struct usb_cdc_header_desc *cs_des = (struct usb_cdc_header_desc *)des_head;
315562306a36Sopenharmony_ci            if (cs_des->bDescriptorSubType == USB_CDC_CALL_MANAGEMENT_TYPE) {
315662306a36Sopenharmony_ci                struct usb_cdc_call_mgmt_descriptor *mgmt_des = (struct usb_cdc_call_mgmt_descriptor *)des_head;
315762306a36Sopenharmony_ci                mgmt_des->bDataInterface = intf_data->bInterfaceNumber;
315862306a36Sopenharmony_ci            } else if (cs_des->bDescriptorSubType == USB_CDC_UNION_TYPE) {
315962306a36Sopenharmony_ci                struct usb_cdc_union_desc *union_des = (struct usb_cdc_union_desc *)des_head;
316062306a36Sopenharmony_ci                union_des->bMasterInterface0 = intf_ctl->bInterfaceNumber;
316162306a36Sopenharmony_ci                union_des->bSlaveInterface0 = intf_data->bInterfaceNumber;
316262306a36Sopenharmony_ci            } else if (cs_des->bDescriptorSubType == USB_CDC_ETHERNET_TYPE) {
316362306a36Sopenharmony_ci                struct usb_cdc_ether_desc *ether_des = (struct usb_cdc_ether_desc *)des_head;
316462306a36Sopenharmony_ci                ether_des->iMACAddress = intf_ctl->iInterface + 1;
316562306a36Sopenharmony_ci            }
316662306a36Sopenharmony_ci        }
316762306a36Sopenharmony_ci    }
316862306a36Sopenharmony_ci    /* And we're done */
316962306a36Sopenharmony_ci    ffs->eps = func->eps;
317062306a36Sopenharmony_ci    ffs_event_add(ffs, FUNCTIONFS_BIND);
317162306a36Sopenharmony_ci    return 0;
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_cierror:
317462306a36Sopenharmony_ci    /* XXX Do we need to release all claimed endpoints here? */
317562306a36Sopenharmony_ci    return ret;
317662306a36Sopenharmony_ci}
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_cistatic int ffs_func_bind(struct usb_configuration *c, struct usb_function *f)
317962306a36Sopenharmony_ci{
318062306a36Sopenharmony_ci    struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c);
318162306a36Sopenharmony_ci    struct ffs_function *func = ffs_func_from_usb(f);
318262306a36Sopenharmony_ci    int ret;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci    if (IS_ERR(ffs_opts))
318562306a36Sopenharmony_ci        return PTR_ERR(ffs_opts);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci    ret = _ffs_func_bind(c, f);
318862306a36Sopenharmony_ci    if (ret && !--ffs_opts->refcnt)
318962306a36Sopenharmony_ci        functionfs_unbind(func->ffs);
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci    return ret;
319262306a36Sopenharmony_ci}
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci/* Other USB function hooks *************************************************/
319562306a36Sopenharmony_cistatic void ffs_reset_work(struct work_struct *work)
319662306a36Sopenharmony_ci{
319762306a36Sopenharmony_ci    struct ffs_data *ffs = container_of(work,
319862306a36Sopenharmony_ci        struct ffs_data, reset_work);
319962306a36Sopenharmony_ci    ffs_data_reset(ffs);
320062306a36Sopenharmony_ci}
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_cistatic int ffs_func_set_alt(struct usb_function *f,
320362306a36Sopenharmony_ci                unsigned interface, unsigned alt)
320462306a36Sopenharmony_ci{
320562306a36Sopenharmony_ci    struct ffs_function *func = ffs_func_from_usb(f);
320662306a36Sopenharmony_ci    struct ffs_data *ffs = func->ffs;
320762306a36Sopenharmony_ci    int ret = 0, intf;
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci    if (alt != (unsigned)-1) {
321062306a36Sopenharmony_ci        intf = ffs_func_revmap_intf(func, interface);
321162306a36Sopenharmony_ci        if (unlikely(intf < 0))
321262306a36Sopenharmony_ci            return intf;
321362306a36Sopenharmony_ci    }
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci    if (ffs->func)
321662306a36Sopenharmony_ci        ffs_func_eps_disable(ffs->func);
321762306a36Sopenharmony_ci
321862306a36Sopenharmony_ci    if (ffs->state == FFS_DEACTIVATED) {
321962306a36Sopenharmony_ci        ffs->state = FFS_CLOSING;
322062306a36Sopenharmony_ci        INIT_WORK(&ffs->reset_work, ffs_reset_work);
322162306a36Sopenharmony_ci        schedule_work(&ffs->reset_work);
322262306a36Sopenharmony_ci        return -ENODEV;
322362306a36Sopenharmony_ci    }
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci    if (ffs->state != FFS_ACTIVE)
322662306a36Sopenharmony_ci        return -ENODEV;
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci    if (alt == (unsigned)-1) {
322962306a36Sopenharmony_ci        ffs->func = NULL;
323062306a36Sopenharmony_ci        ffs_event_add(ffs, FUNCTIONFS_DISABLE);
323162306a36Sopenharmony_ci        return 0;
323262306a36Sopenharmony_ci    }
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci    ffs->func = func;
323562306a36Sopenharmony_ci    ret = ffs_func_eps_enable(func);
323662306a36Sopenharmony_ci    if (likely(ret >= 0))
323762306a36Sopenharmony_ci        ffs_event_add(ffs, FUNCTIONFS_ENABLE);
323862306a36Sopenharmony_ci    return ret;
323962306a36Sopenharmony_ci}
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_cistatic void ffs_func_disable(struct usb_function *f)
324262306a36Sopenharmony_ci{
324362306a36Sopenharmony_ci    ffs_func_set_alt(f, 0, (unsigned)-1);
324462306a36Sopenharmony_ci}
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_cistatic int ffs_func_setup(struct usb_function *f, const struct usb_ctrlrequest *creq)
324762306a36Sopenharmony_ci{
324862306a36Sopenharmony_ci    struct ffs_function *func = ffs_func_from_usb(f);
324962306a36Sopenharmony_ci    struct ffs_data *ffs = func->ffs;
325062306a36Sopenharmony_ci    unsigned long flags;
325162306a36Sopenharmony_ci    int ret;
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci    ENTER();
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci    pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
325662306a36Sopenharmony_ci    pr_vdebug("creq->bRequest     = %02x\n", creq->bRequest);
325762306a36Sopenharmony_ci    pr_vdebug("creq->wValue       = %04x\n", le16_to_cpu(creq->wValue));
325862306a36Sopenharmony_ci    pr_vdebug("creq->wIndex       = %04x\n", le16_to_cpu(creq->wIndex));
325962306a36Sopenharmony_ci    pr_vdebug("creq->wLength      = %04x\n", le16_to_cpu(creq->wLength));
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci    /*
326262306a36Sopenharmony_ci     * Most requests directed to interface go through here
326362306a36Sopenharmony_ci     * (notable exceptions are set/get interface) so we need to
326462306a36Sopenharmony_ci     * handle them.  All other either handled by composite or
326562306a36Sopenharmony_ci     * passed to usb_configuration->setup() (if one is set).  No
326662306a36Sopenharmony_ci     * matter, we will handle requests directed to endpoint here
326762306a36Sopenharmony_ci     * as well (as it's straightforward).  Other request recipient
326862306a36Sopenharmony_ci     * types are only handled when the user flag FUNCTIONFS_ALL_CTRL_RECIP
326962306a36Sopenharmony_ci     * is being used.
327062306a36Sopenharmony_ci     */
327162306a36Sopenharmony_ci    if (ffs->state != FFS_ACTIVE)
327262306a36Sopenharmony_ci        return -ENODEV;
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci    switch (creq->bRequestType & USB_RECIP_MASK) {
327562306a36Sopenharmony_ci    case USB_RECIP_INTERFACE:
327662306a36Sopenharmony_ci        ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
327762306a36Sopenharmony_ci        if (unlikely(ret < 0))
327862306a36Sopenharmony_ci            return ret;
327962306a36Sopenharmony_ci        break;
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci    case USB_RECIP_ENDPOINT:
328262306a36Sopenharmony_ci        ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
328362306a36Sopenharmony_ci        if (unlikely(ret < 0))
328462306a36Sopenharmony_ci            return ret;
328562306a36Sopenharmony_ci        if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
328662306a36Sopenharmony_ci            ret = func->ffs->eps_addrmap[ret];
328762306a36Sopenharmony_ci        break;
328862306a36Sopenharmony_ci
328962306a36Sopenharmony_ci    default:
329062306a36Sopenharmony_ci        if (func->ffs->user_flags & FUNCTIONFS_ALL_CTRL_RECIP)
329162306a36Sopenharmony_ci            ret = le16_to_cpu(creq->wIndex);
329262306a36Sopenharmony_ci        else
329362306a36Sopenharmony_ci            return -EOPNOTSUPP;
329462306a36Sopenharmony_ci    }
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci    spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
329762306a36Sopenharmony_ci    ffs->ev.setup = *creq;
329862306a36Sopenharmony_ci    ffs->ev.setup.wIndex = cpu_to_le16(ret);
329962306a36Sopenharmony_ci    __ffs_event_add(ffs, FUNCTIONFS_SETUP);
330062306a36Sopenharmony_ci    spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci    return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
330362306a36Sopenharmony_ci}
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_cistatic bool ffs_func_req_match(struct usb_function *f,
330662306a36Sopenharmony_ci                const struct usb_ctrlrequest *creq,
330762306a36Sopenharmony_ci                bool config0)
330862306a36Sopenharmony_ci{
330962306a36Sopenharmony_ci    struct ffs_function *func = ffs_func_from_usb(f);
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci    if (config0 && !(func->ffs->user_flags & FUNCTIONFS_CONFIG0_SETUP))
331262306a36Sopenharmony_ci        return false;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci    switch (creq->bRequestType & USB_RECIP_MASK) {
331562306a36Sopenharmony_ci    case USB_RECIP_INTERFACE:
331662306a36Sopenharmony_ci        return (ffs_func_revmap_intf(func,
331762306a36Sopenharmony_ci                         le16_to_cpu(creq->wIndex)) >= 0);
331862306a36Sopenharmony_ci    case USB_RECIP_ENDPOINT:
331962306a36Sopenharmony_ci        return (ffs_func_revmap_ep(func,
332062306a36Sopenharmony_ci                       le16_to_cpu(creq->wIndex)) >= 0);
332162306a36Sopenharmony_ci    default:
332262306a36Sopenharmony_ci        return (bool) (func->ffs->user_flags &
332362306a36Sopenharmony_ci                   FUNCTIONFS_ALL_CTRL_RECIP);
332462306a36Sopenharmony_ci    }
332562306a36Sopenharmony_ci}
332662306a36Sopenharmony_ci
332762306a36Sopenharmony_cistatic void ffs_func_suspend(struct usb_function *f)
332862306a36Sopenharmony_ci{
332962306a36Sopenharmony_ci    ENTER();
333062306a36Sopenharmony_ci    ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
333162306a36Sopenharmony_ci}
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_cistatic void ffs_func_resume(struct usb_function *f)
333462306a36Sopenharmony_ci{
333562306a36Sopenharmony_ci    ENTER();
333662306a36Sopenharmony_ci    ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
333762306a36Sopenharmony_ci}
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci/* Endpoint and interface numbers reverse mapping ***************************/
334062306a36Sopenharmony_cistatic int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
334162306a36Sopenharmony_ci{
334262306a36Sopenharmony_ci    num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
334362306a36Sopenharmony_ci    return num ? num : -EDOM;
334462306a36Sopenharmony_ci}
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_cistatic int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
334762306a36Sopenharmony_ci{
334862306a36Sopenharmony_ci    short *nums = func->interfaces_nums;
334962306a36Sopenharmony_ci    unsigned count = func->ffs->interfaces_count;
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci    for (; count; --count, ++nums) {
335262306a36Sopenharmony_ci        if (*nums >= 0 && *nums == intf)
335362306a36Sopenharmony_ci            return nums - func->interfaces_nums;
335462306a36Sopenharmony_ci    }
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci    return -EDOM;
335762306a36Sopenharmony_ci}
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci/* Devices management *******************************************************/
336062306a36Sopenharmony_cistatic LIST_HEAD(ffs_devices);
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_cistatic struct ffs_dev *_ffs_do_find_dev(const char *name)
336362306a36Sopenharmony_ci{
336462306a36Sopenharmony_ci    struct ffs_dev *dev = NULL;
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci    if (!name)
336762306a36Sopenharmony_ci        return NULL;
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci    list_for_each_entry(dev, &ffs_devices, entry) {
337062306a36Sopenharmony_ci        if (!dev->name)
337162306a36Sopenharmony_ci            return NULL;
337262306a36Sopenharmony_ci        if (strcmp(dev->name, name) == 0)
337362306a36Sopenharmony_ci            return dev;
337462306a36Sopenharmony_ci    }
337562306a36Sopenharmony_ci
337662306a36Sopenharmony_ci    return NULL;
337762306a36Sopenharmony_ci}
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci/*
338062306a36Sopenharmony_ci * ffs_lock must be taken by the caller of this function
338162306a36Sopenharmony_ci */
338262306a36Sopenharmony_cistatic struct ffs_dev *_ffs_get_single_dev(void)
338362306a36Sopenharmony_ci{
338462306a36Sopenharmony_ci    struct ffs_dev *dev = NULL;
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci    if (list_is_singular(&ffs_devices)) {
338762306a36Sopenharmony_ci        dev = list_first_entry(&ffs_devices, struct ffs_dev, entry);
338862306a36Sopenharmony_ci        if (dev->single)
338962306a36Sopenharmony_ci            return dev;
339062306a36Sopenharmony_ci    }
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci    return NULL;
339362306a36Sopenharmony_ci}
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci/*
339662306a36Sopenharmony_ci * ffs_lock must be taken by the caller of this function
339762306a36Sopenharmony_ci */
339862306a36Sopenharmony_cistatic struct ffs_dev *_ffs_find_dev(const char *name)
339962306a36Sopenharmony_ci{
340062306a36Sopenharmony_ci    struct ffs_dev *dev;
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci    dev = _ffs_get_single_dev();
340362306a36Sopenharmony_ci    if (dev)
340462306a36Sopenharmony_ci        return dev;
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci    return _ffs_do_find_dev(name);
340762306a36Sopenharmony_ci}
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci/* Configfs support *********************************************************/
341062306a36Sopenharmony_cistatic inline struct f_fs_opts *to_ffs_opts(struct config_item *item)
341162306a36Sopenharmony_ci{
341262306a36Sopenharmony_ci    return container_of(to_config_group(item), struct f_fs_opts,
341362306a36Sopenharmony_ci                func_inst.group);
341462306a36Sopenharmony_ci}
341562306a36Sopenharmony_ci
341662306a36Sopenharmony_cistatic void ffs_attr_release(struct config_item *item)
341762306a36Sopenharmony_ci{
341862306a36Sopenharmony_ci    struct f_fs_opts *opts = to_ffs_opts(item);
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci    usb_put_function_instance(&opts->func_inst);
342162306a36Sopenharmony_ci}
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_cistatic struct configfs_item_operations ffs_item_ops = {
342462306a36Sopenharmony_ci    .release    = ffs_attr_release,
342562306a36Sopenharmony_ci};
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_cistatic const struct config_item_type ffs_func_type = {
342862306a36Sopenharmony_ci    .ct_item_ops    = &ffs_item_ops,
342962306a36Sopenharmony_ci    .ct_owner    = THIS_MODULE,
343062306a36Sopenharmony_ci};
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci/* Function registration interface ******************************************/
343362306a36Sopenharmony_cistatic void ffs_free_inst(struct usb_function_instance *f)
343462306a36Sopenharmony_ci{
343562306a36Sopenharmony_ci    struct f_fs_opts *opts;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci    opts = to_f_fs_opts(f);
343862306a36Sopenharmony_ci    ffs_dev_lock();
343962306a36Sopenharmony_ci    _ffs_free_dev(opts->dev);
344062306a36Sopenharmony_ci    ffs_dev_unlock();
344162306a36Sopenharmony_ci    kfree(opts);
344262306a36Sopenharmony_ci}
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_cistatic int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
344562306a36Sopenharmony_ci{
344662306a36Sopenharmony_ci    char name_dev[MAX_NAMELEN] = {0};
344762306a36Sopenharmony_ci    if (snprintf(name_dev, MAX_NAMELEN - 1, "%s.%s", FUNCTION_GENERIC, name) < 0) {
344862306a36Sopenharmony_ci        return -EFAULT;
344962306a36Sopenharmony_ci    }
345062306a36Sopenharmony_ci    if (strlen(name_dev) >= sizeof_field(struct ffs_dev, name))
345162306a36Sopenharmony_ci        return -ENAMETOOLONG;
345262306a36Sopenharmony_ci    return ffs_name_dev_adapter(to_f_fs_opts(fi)->dev, name_dev);
345362306a36Sopenharmony_ci}
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_cistatic struct usb_function_instance *ffs_alloc_inst(void)
345662306a36Sopenharmony_ci{
345762306a36Sopenharmony_ci    struct f_fs_opts *opts = NULL;
345862306a36Sopenharmony_ci    struct ffs_dev *dev = NULL;
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci    opts = kzalloc(sizeof(*opts), GFP_KERNEL);
346162306a36Sopenharmony_ci    if (!opts)
346262306a36Sopenharmony_ci        return ERR_PTR(-ENOMEM);
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci    opts->func_inst.set_inst_name = ffs_set_inst_name;
346562306a36Sopenharmony_ci    opts->func_inst.free_func_inst = ffs_free_inst;
346662306a36Sopenharmony_ci    ffs_dev_lock();
346762306a36Sopenharmony_ci    dev = _ffs_alloc_dev();
346862306a36Sopenharmony_ci    ffs_dev_unlock();
346962306a36Sopenharmony_ci    if (IS_ERR(dev)) {
347062306a36Sopenharmony_ci        kfree(opts);
347162306a36Sopenharmony_ci        return ERR_CAST(dev);
347262306a36Sopenharmony_ci    }
347362306a36Sopenharmony_ci    opts->dev = dev;
347462306a36Sopenharmony_ci    dev->opts = opts;
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci    config_group_init_type_name(&opts->func_inst.group, "",
347762306a36Sopenharmony_ci                    &ffs_func_type);
347862306a36Sopenharmony_ci    return &opts->func_inst;
347962306a36Sopenharmony_ci}
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_cistatic void ffs_free(struct usb_function *f)
348262306a36Sopenharmony_ci{
348362306a36Sopenharmony_ci    kfree(ffs_func_from_usb(f));
348462306a36Sopenharmony_ci}
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_cistatic void ffs_func_unbind(struct usb_configuration *c,
348762306a36Sopenharmony_ci                struct usb_function *f)
348862306a36Sopenharmony_ci{
348962306a36Sopenharmony_ci    struct ffs_function *func = ffs_func_from_usb(f);
349062306a36Sopenharmony_ci    struct ffs_data *ffs = func->ffs;
349162306a36Sopenharmony_ci    struct f_fs_opts *opts =
349262306a36Sopenharmony_ci        container_of(f->fi, struct f_fs_opts, func_inst);
349362306a36Sopenharmony_ci    struct ffs_ep *ep = func->eps;
349462306a36Sopenharmony_ci    unsigned count = ffs->eps_count;
349562306a36Sopenharmony_ci    unsigned long flags;
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci    ENTER();
349862306a36Sopenharmony_ci    if (ffs->func == func) {
349962306a36Sopenharmony_ci        ffs_func_eps_disable(func);
350062306a36Sopenharmony_ci        ffs->func = NULL;
350162306a36Sopenharmony_ci    }
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci    if (!--opts->refcnt)
350462306a36Sopenharmony_ci        functionfs_unbind(ffs);
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci    /* cleanup after autoconfig */
350762306a36Sopenharmony_ci    spin_lock_irqsave(&func->ffs->eps_lock, flags);
350862306a36Sopenharmony_ci    while (count--) {
350962306a36Sopenharmony_ci        if (ep->ep && ep->req)
351062306a36Sopenharmony_ci            usb_ep_free_request(ep->ep, ep->req);
351162306a36Sopenharmony_ci        ep->req = NULL;
351262306a36Sopenharmony_ci        ++ep;
351362306a36Sopenharmony_ci    }
351462306a36Sopenharmony_ci    spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
351562306a36Sopenharmony_ci    kfree(func->eps);
351662306a36Sopenharmony_ci    func->eps = NULL;
351762306a36Sopenharmony_ci    /*
351862306a36Sopenharmony_ci     * eps, descriptors and interfaces_nums are allocated in the
351962306a36Sopenharmony_ci     * same chunk so only one free is required.
352062306a36Sopenharmony_ci     */
352162306a36Sopenharmony_ci    func->function.fs_descriptors = NULL;
352262306a36Sopenharmony_ci    func->function.hs_descriptors = NULL;
352362306a36Sopenharmony_ci    func->function.ss_descriptors = NULL;
352462306a36Sopenharmony_ci    func->interfaces_nums = NULL;
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci    ffs_event_add(ffs, FUNCTIONFS_UNBIND);
352762306a36Sopenharmony_ci}
352862306a36Sopenharmony_ci
352962306a36Sopenharmony_cistatic int ffs_func_get_alt(struct usb_function *f, unsigned intf)
353062306a36Sopenharmony_ci{
353162306a36Sopenharmony_ci    if (intf == 0)
353262306a36Sopenharmony_ci        return 0;
353362306a36Sopenharmony_ci    return 1;
353462306a36Sopenharmony_ci}
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_cistatic struct usb_function *ffs_alloc(struct usb_function_instance *fi)
353762306a36Sopenharmony_ci{
353862306a36Sopenharmony_ci    struct ffs_function *func = NULL;
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci    ENTER();
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci    func = kzalloc(sizeof(*func), GFP_KERNEL);
354362306a36Sopenharmony_ci    if (unlikely(!func))
354462306a36Sopenharmony_ci        return ERR_PTR(-ENOMEM);
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci    func->function.name    = "FunctionFS Adapter";
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci    func->function.bind    = ffs_func_bind;
354962306a36Sopenharmony_ci    func->function.unbind  = ffs_func_unbind;
355062306a36Sopenharmony_ci    func->function.set_alt = ffs_func_set_alt;
355162306a36Sopenharmony_ci    func->function.get_alt = ffs_func_get_alt;
355262306a36Sopenharmony_ci    func->function.disable = ffs_func_disable;
355362306a36Sopenharmony_ci    func->function.setup   = ffs_func_setup;
355462306a36Sopenharmony_ci    func->function.req_match = ffs_func_req_match;
355562306a36Sopenharmony_ci    func->function.suspend = ffs_func_suspend;
355662306a36Sopenharmony_ci    func->function.resume  = ffs_func_resume;
355762306a36Sopenharmony_ci    func->function.free_func = ffs_free;
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_ci    return &func->function;
356062306a36Sopenharmony_ci}
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci/*
356362306a36Sopenharmony_ci * ffs_lock must be taken by the caller of this function
356462306a36Sopenharmony_ci */
356562306a36Sopenharmony_cistatic struct ffs_dev *_ffs_alloc_dev(void)
356662306a36Sopenharmony_ci{
356762306a36Sopenharmony_ci    struct ffs_dev *dev = NULL;
356862306a36Sopenharmony_ci    int ret;
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci    if (_ffs_get_single_dev())
357162306a36Sopenharmony_ci            return ERR_PTR(-EBUSY);
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
357462306a36Sopenharmony_ci    if (!dev)
357562306a36Sopenharmony_ci        return ERR_PTR(-ENOMEM);
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci    if (list_empty(&ffs_devices)) {
357862306a36Sopenharmony_ci        ret = functionfs_init();
357962306a36Sopenharmony_ci        if (ret) {
358062306a36Sopenharmony_ci            kfree(dev);
358162306a36Sopenharmony_ci            return ERR_PTR(ret);
358262306a36Sopenharmony_ci        }
358362306a36Sopenharmony_ci    }
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_ci    list_add(&dev->entry, &ffs_devices);
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci    return dev;
358862306a36Sopenharmony_ci}
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ciint ffs_name_dev_adapter(struct ffs_dev *dev, const char *name)
359162306a36Sopenharmony_ci{
359262306a36Sopenharmony_ci    struct ffs_dev *existing = NULL;
359362306a36Sopenharmony_ci    int ret = 0;
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci    ffs_dev_lock();
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci    existing = _ffs_do_find_dev(name);
359862306a36Sopenharmony_ci    if (!existing)
359962306a36Sopenharmony_ci        strlcpy(dev->name, name, ARRAY_SIZE(dev->name));
360062306a36Sopenharmony_ci    else if (existing != dev)
360162306a36Sopenharmony_ci        ret = -EBUSY;
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci    ffs_dev_unlock();
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci    return ret;
360662306a36Sopenharmony_ci}
360762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ffs_name_dev_adapter);
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ciint ffs_single_dev_adapter(struct ffs_dev *dev)
361062306a36Sopenharmony_ci{
361162306a36Sopenharmony_ci    int ret;
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci    ret = 0;
361462306a36Sopenharmony_ci    ffs_dev_lock();
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ci    if (!list_is_singular(&ffs_devices))
361762306a36Sopenharmony_ci        ret = -EBUSY;
361862306a36Sopenharmony_ci    else
361962306a36Sopenharmony_ci        dev->single = true;
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci    ffs_dev_unlock();
362262306a36Sopenharmony_ci    return ret;
362362306a36Sopenharmony_ci}
362462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ffs_single_dev_adapter);
362562306a36Sopenharmony_ci/*
362662306a36Sopenharmony_ci * ffs_lock must be taken by the caller of this function
362762306a36Sopenharmony_ci */
362862306a36Sopenharmony_cistatic void _ffs_free_dev(struct ffs_dev *dev)
362962306a36Sopenharmony_ci{
363062306a36Sopenharmony_ci    list_del(&dev->entry);
363162306a36Sopenharmony_ci
363262306a36Sopenharmony_ci    /* Clear the private_data pointer to stop incorrect dev access */
363362306a36Sopenharmony_ci    if (dev->ffs_data)
363462306a36Sopenharmony_ci        dev->ffs_data->private_data = NULL;
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci    kfree(dev);
363762306a36Sopenharmony_ci    if (list_empty(&ffs_devices))
363862306a36Sopenharmony_ci        functionfs_cleanup();
363962306a36Sopenharmony_ci}
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_cistatic void *ffs_acquire_dev(const char *dev_name)
364262306a36Sopenharmony_ci{
364362306a36Sopenharmony_ci    struct ffs_dev *ffs_dev = NULL;
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci    ENTER();
364662306a36Sopenharmony_ci    ffs_dev_lock();
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci    ffs_dev = _ffs_find_dev(dev_name);
364962306a36Sopenharmony_ci    if (!ffs_dev)
365062306a36Sopenharmony_ci        ffs_dev = ERR_PTR(-ENOENT);
365162306a36Sopenharmony_ci    else if (ffs_dev->mounted)
365262306a36Sopenharmony_ci        ffs_dev = ERR_PTR(-EBUSY);
365362306a36Sopenharmony_ci    else if (ffs_dev->ffs_acquire_dev_callback &&
365462306a36Sopenharmony_ci        ffs_dev->ffs_acquire_dev_callback(ffs_dev))
365562306a36Sopenharmony_ci        ffs_dev = ERR_PTR(-ENOENT);
365662306a36Sopenharmony_ci    else
365762306a36Sopenharmony_ci        ffs_dev->mounted = true;
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci    ffs_dev_unlock();
366062306a36Sopenharmony_ci    return ffs_dev;
366162306a36Sopenharmony_ci}
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_cistatic void ffs_release_dev(struct ffs_data *ffs_data)
366462306a36Sopenharmony_ci{
366562306a36Sopenharmony_ci    struct ffs_dev *ffs_dev = NULL;
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci    ENTER();
366862306a36Sopenharmony_ci    ffs_dev_lock();
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci    ffs_dev = ffs_data->private_data;
367162306a36Sopenharmony_ci    if (ffs_dev) {
367262306a36Sopenharmony_ci        ffs_dev->mounted = false;
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_ci        if (ffs_dev->ffs_release_dev_callback)
367562306a36Sopenharmony_ci            ffs_dev->ffs_release_dev_callback(ffs_dev);
367662306a36Sopenharmony_ci    }
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci    ffs_dev_unlock();
367962306a36Sopenharmony_ci}
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_cistatic int ffs_ready(struct ffs_data *ffs)
368262306a36Sopenharmony_ci{
368362306a36Sopenharmony_ci    struct ffs_dev *ffs_obj = NULL;
368462306a36Sopenharmony_ci    int ret = 0;
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci    ENTER();
368762306a36Sopenharmony_ci    ffs_dev_lock();
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci    ffs_obj = ffs->private_data;
369062306a36Sopenharmony_ci    if (!ffs_obj) {
369162306a36Sopenharmony_ci        ret = -EINVAL;
369262306a36Sopenharmony_ci        goto done;
369362306a36Sopenharmony_ci    }
369462306a36Sopenharmony_ci    if (WARN_ON(ffs_obj->desc_ready)) {
369562306a36Sopenharmony_ci        ret = -EBUSY;
369662306a36Sopenharmony_ci        goto done;
369762306a36Sopenharmony_ci    }
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci    ffs_obj->desc_ready = true;
370062306a36Sopenharmony_ci    ffs_obj->ffs_data = ffs;
370162306a36Sopenharmony_ci
370262306a36Sopenharmony_ci    if (ffs_obj->ffs_ready_callback) {
370362306a36Sopenharmony_ci        ret = ffs_obj->ffs_ready_callback(ffs);
370462306a36Sopenharmony_ci        if (ret)
370562306a36Sopenharmony_ci            goto done;
370662306a36Sopenharmony_ci    }
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci    set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
370962306a36Sopenharmony_cidone:
371062306a36Sopenharmony_ci    ffs_dev_unlock();
371162306a36Sopenharmony_ci    return ret;
371262306a36Sopenharmony_ci}
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_cistatic void ffs_closed(struct ffs_data *ffs)
371562306a36Sopenharmony_ci{
371662306a36Sopenharmony_ci    struct ffs_dev *ffs_obj = NULL;
371762306a36Sopenharmony_ci    struct f_fs_opts *opts = NULL;
371862306a36Sopenharmony_ci    struct config_item *ci = NULL;
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci    ENTER();
372162306a36Sopenharmony_ci    ffs_dev_lock();
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci    ffs_obj = ffs->private_data;
372462306a36Sopenharmony_ci    if (!ffs_obj)
372562306a36Sopenharmony_ci        goto done;
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_ci    ffs_obj->desc_ready = false;
372862306a36Sopenharmony_ci    ffs_obj->ffs_data = NULL;
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci    if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
373162306a36Sopenharmony_ci        ffs_obj->ffs_closed_callback)
373262306a36Sopenharmony_ci        ffs_obj->ffs_closed_callback(ffs);
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci    if (ffs_obj->opts)
373562306a36Sopenharmony_ci        opts = ffs_obj->opts;
373662306a36Sopenharmony_ci    else
373762306a36Sopenharmony_ci        goto done;
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci    if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent
374062306a36Sopenharmony_ci        || !kref_read(&opts->func_inst.group.cg_item.ci_kref))
374162306a36Sopenharmony_ci        goto done;
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci    ci = opts->func_inst.group.cg_item.ci_parent->ci_parent;
374462306a36Sopenharmony_ci    ffs_dev_unlock();
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci    if (test_bit(FFS_FL_BOUND, &ffs->flags))
374762306a36Sopenharmony_ci        unregister_gadget_item(ci);
374862306a36Sopenharmony_ci    return;
374962306a36Sopenharmony_cidone:
375062306a36Sopenharmony_ci    ffs_dev_unlock();
375162306a36Sopenharmony_ci}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci/* Misc helper functions ****************************************************/
375462306a36Sopenharmony_cistatic int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
375562306a36Sopenharmony_ci{
375662306a36Sopenharmony_ci    return nonblock
375762306a36Sopenharmony_ci        ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN
375862306a36Sopenharmony_ci        : mutex_lock_interruptible(mutex);
375962306a36Sopenharmony_ci}
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_cistatic char *ffs_prepare_buffer(const char __user *buf, size_t len)
376262306a36Sopenharmony_ci{
376362306a36Sopenharmony_ci    char *data = NULL;
376462306a36Sopenharmony_ci
376562306a36Sopenharmony_ci    if (unlikely(!len))
376662306a36Sopenharmony_ci        return NULL;
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci    data = kmalloc(len, GFP_KERNEL);
376962306a36Sopenharmony_ci    if (unlikely(!data))
377062306a36Sopenharmony_ci        return ERR_PTR(-ENOMEM);
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_ci    if (unlikely(copy_from_user(data, buf, len))) {
377362306a36Sopenharmony_ci        kfree(data);
377462306a36Sopenharmony_ci        return ERR_PTR(-EFAULT);
377562306a36Sopenharmony_ci    }
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci    pr_vdebug("Buffer from user space:\n");
377862306a36Sopenharmony_ci    ffs_dump_mem("", data, len);
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci    return data;
378162306a36Sopenharmony_ci}
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ciDECLARE_USB_FUNCTION_INIT(f_generic, ffs_alloc_inst, ffs_alloc);
378462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3785