// SPDX-License-Identifier: GPL-2.0+/* * f_fs.c -- user mode file system API for USB composite function controllers * * Copyright (C) 2010 Samsung Electronics * Author: Michal Nazarewicz <mina86@mina86.com> * * Based on inode.c (GadgetFS) which was: * Copyright (C) 2003-2004 David Brownell * Copyright (C) 2003 Agilent Technologies */ /* #define DEBUG *//* #define VERBOSE_DEBUG */ #include <linux/blkdev.h>#include <linux/dma-buf.h>#include <linux/dma-fence.h>#include <linux/dma-resv.h>#include <linux/pagemap.h>#include <linux/export.h>#include <linux/fs_parser.h>#include <linux/hid.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/scatterlist.h>#include <linux/sched/signal.h>#include <linux/uio.h>#include <linux/vmalloc.h>#include <linux/unaligned.h> #include <linux/usb/ccid.h>#include <linux/usb/composite.h>#include <linux/usb/functionfs.h>#include <linux/usb/func_utils.h> #include <linux/aio.h>#include <linux/kthread.h>#include <linux/poll.h>#include <linux/eventfd.h> #include "u_fs.h"#include "u_os_desc.h"#include "configfs.h" #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */#define MAX_ALT_SETTINGS 2 /* Allow up to 2 alt settings to be set. */ #define DMABUF_ENQUEUE_TIMEOUT_MS 5000 MODULE_IMPORT_NS("DMA_BUF"); /* Reference counter handling */static void ffs_data_get(struct ffs_data *ffs);static void ffs_data_put(struct ffs_data *ffs);/* Creates new ffs_data object. */static struct ffs_data *__must_check ffs_data_new(const char *dev_name) __attribute__((malloc)); /* Opened counter handling. */static void ffs_data_closed(struct ffs_data *ffs); /* Called with ffs->mutex held; take over ownership of data. */static int __must_check__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);static int __must_check__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); /* The function structure ***************************************************/ struct ffs_ep; struct ffs_function { struct usb_configuration *conf; struct usb_gadget *gadget; struct ffs_data *ffs; struct ffs_ep *eps; u8 eps_revmap[16]; short *interfaces_nums; struct usb_function function; int cur_alt[MAX_CONFIG_INTERFACES];}; static struct ffs_function *ffs_func_from_usb(struct usb_function *f){ return container_of(f, struct ffs_function, function);} static inline enum ffs_setup_stateffs_setup_state_clear_cancelled(struct ffs_data *ffs){ return (enum ffs_setup_state) cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP);} static void ffs_func_eps_disable(struct ffs_function *func);static int __must_check ffs_func_eps_enable(struct ffs_function *func); static int ffs_func_bind(struct usb_configuration *, struct usb_function *);static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);static int ffs_func_get_alt(struct usb_function *f, unsigned int intf);static void ffs_func_disable(struct usb_function *);static int ffs_func_setup(struct usb_function *, const struct usb_ctrlrequest *);static bool ffs_func_req_match(struct usb_function *, const struct usb_ctrlrequest *, bool config0);static void ffs_func_suspend(struct usb_function *);static void ffs_func_resume(struct usb_function *); static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf); /* The endpoints structures *************************************************/ struct ffs_ep { struct usb_ep *ep; /* P: ffs->eps_lock */ struct usb_request *req; /* P: epfile->mutex */ /* [0]: full speed, [1]: high speed, [2]: super speed */ struct usb_endpoint_descriptor *descs[3]; u8 num;}; struct ffs_dmabuf_priv { struct list_head entry; struct kref ref; struct ffs_data *ffs; struct dma_buf_attachment *attach; struct sg_table *sgt; enum dma_data_direction dir; spinlock_t lock; u64 context; struct usb_request *req; /* P: ffs->eps_lock */ struct usb_ep *ep; /* P: ffs->eps_lock */}; struct ffs_dma_fence { struct dma_fence base; struct ffs_dmabuf_priv *priv; struct work_struct work; struct usb_ep *ep; struct usb_request *req;}; struct ffs_epfile { /* Protects ep->ep and ep->req. */ struct mutex mutex; struct ffs_data *ffs; struct ffs_ep *ep; /* P: ffs->eps_lock */ struct ffs_epfile *epfile_in; /* P: ffs->eps_lock */ struct ffs_epfile *epfile_out; /* P: ffs->eps_lock */ /* * Buffer for holding data from partial reads which may happen since * we’re rounding user read requests to a multiple of a max packet size. * * The pointer is initialised with NULL value and may be set by * __ffs_epfile_read_data function to point to a temporary buffer. * * In normal operation, calls to __ffs_epfile_read_buffered will consume * data from said buffer and eventually free it. Importantly, while the * function is using the buffer, it sets the pointer to NULL. This is * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered * can never run concurrently (they are synchronised by epfile->mutex) * so the latter will not assign a new value to the pointer. * * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is * valid) and sets the pointer to READ_BUFFER_DROP value. This special * value is crux of the synchronisation between ffs_func_eps_disable and * __ffs_epfile_read_data. * * Once __ffs_epfile_read_data is about to finish it will try to set the * pointer back to its old value (as described above), but seeing as the * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free * the buffer. * * == State transitions == * * • ptr == NULL: (initial state) * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP * ◦ __ffs_epfile_read_buffered: nop * ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == DROP: * ◦ __ffs_epfile_read_buffer_free: nop * ◦ __ffs_epfile_read_buffered: go to ptr == NULL * ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == buf: * ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP * ◦ __ffs_epfile_read_buffered: go to ptr == NULL and reading * ◦ __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered * is always called first * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == NULL and reading: * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading * ◦ __ffs_epfile_read_buffered: n/a, mutex is held * ◦ __ffs_epfile_read_data: n/a, mutex is held * ◦ reading finishes and … * … all data read: free buf, go to ptr == NULL * … otherwise: go to ptr == buf and reading * • ptr == DROP and reading: * ◦ __ffs_epfile_read_buffer_free: nop * ◦ __ffs_epfile_read_buffered: n/a, mutex is held * ◦ __ffs_epfile_read_data: n/a, mutex is held * ◦ reading finishes: free buf, go to ptr == DROP */ struct ffs_buffer *read_buffer;#define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN)) char name[8]; unsigned char in; /* P: ffs->eps_lock */ unsigned char isoc; /* P: ffs->eps_lock */ u8 zlp_enabled; /* P: ffs->eps_lock */ bool is_rw_proxy; /* Protects dmabufs */ struct mutex dmabufs_mutex; struct list_head dmabufs; /* P: dmabufs_mutex */ atomic_t seqno;}; struct ffs_buffer { size_t length; char *data; char storage[] __counted_by(length);}; /* ffs_io_data structure ***************************************************/ struct ffs_io_data { bool aio; bool read; struct kiocb *kiocb; struct iov_iter data; const void *to_free; char *buf; struct mm_struct *mm; struct work_struct work; struct usb_ep *ep; struct usb_request *req; struct sg_table sgt; bool use_sg; struct ffs_data *ffs; int status; struct completion done;}; struct ffs_desc_helper { struct ffs_data *ffs; unsigned interfaces_count; unsigned eps_count;}; static int __must_check ffs_epfiles_create(struct ffs_data *ffs);static void ffs_epfiles_destroy(struct super_block *sb, struct ffs_epfile *epfiles, unsigned count); static int ffs_sb_create_file(struct super_block *sb, const char *name, void *data, const struct file_operations *fops); /* Devices management *******************************************************/ DEFINE_MUTEX(ffs_lock);EXPORT_SYMBOL_GPL(ffs_lock); static struct ffs_dev *_ffs_find_dev(const char *name);static struct ffs_dev *_ffs_alloc_dev(void);static void _ffs_free_dev(struct ffs_dev *dev);static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);static void ffs_release_dev(struct ffs_dev *ffs_dev);static int ffs_ready(struct ffs_data *ffs);static void ffs_closed(struct ffs_data *ffs);static void ffs_reset_work(struct work_struct *work); /* Misc helper functions ****************************************************/ static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) __attribute__((warn_unused_result, nonnull));static char *ffs_prepare_buffer(const char __user *buf, size_t len) __attribute__((warn_unused_result, nonnull)); /* Control file aka ep0 *****************************************************/ static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req){ struct ffs_data *ffs = req->context; complete(&ffs->ep0req_completion);} static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) __releases(&ffs->ev.waitq.lock){ struct usb_request *req = ffs->ep0req; int ret; if (!req) { spin_unlock_irq(&ffs->ev.waitq.lock); return -EINVAL; } req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); spin_unlock_irq(&ffs->ev.waitq.lock); req->buf = data; req->length = len; /* * UDC layer requires to provide a buffer even for ZLP, but should * not use it at all. Let's provide some poisoned pointer to catch * possible bug in the driver. */ if (req->buf == NULL) req->buf = (void *)0xDEADBABE; reinit_completion(&ffs->ep0req_completion); ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); if (ret < 0) return ret; ret = wait_for_completion_interruptible(&ffs->ep0req_completion); if (ret) { usb_ep_dequeue(ffs->gadget->ep0, req); return -EINTR; } ffs->setup_state = FFS_NO_SETUP; return req->status ? req->status : req->actual;} static int __ffs_ep0_stall(struct ffs_data *ffs){ if (ffs->ev.can_stall) { pr_vdebug("ep0 stall\n"); usb_ep_set_halt(ffs->gadget->ep0); ffs->setup_state = FFS_NO_SETUP; return -EL2HLT; } else { pr_debug("bogus ep0 stall!\n"); return -ESRCH; }} static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, size_t len, loff_t *ptr){ struct ffs_data *ffs = file->private_data; ssize_t ret; char *data; /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; /* Acquire mutex */ ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); if (ret < 0) return ret; /* Check state */ switch (ffs->state) { case FFS_READ_DESCRIPTORS: case FFS_READ_STRINGS: /* Copy data */ if (len < 16) { ret = -EINVAL; break; } data = ffs_prepare_buffer(buf, len); if (IS_ERR(data)) { ret = PTR_ERR(data); break; } /* Handle data */ if (ffs->state == FFS_READ_DESCRIPTORS) { pr_info("read descriptors\n"); ret = __ffs_data_got_descs(ffs, data, len); if (ret < 0) break; ffs->state = FFS_READ_STRINGS; ret = len; } else { pr_info("read strings\n"); ret = __ffs_data_got_strings(ffs, data, len); if (ret < 0) break; ret = ffs_epfiles_create(ffs); if (ret) { ffs->state = FFS_CLOSING; break; } ffs->state = FFS_ACTIVE; mutex_unlock(&ffs->mutex); ret = ffs_ready(ffs); if (ret < 0) { ffs->state = FFS_CLOSING; return ret; } return len; } break; case FFS_ACTIVE: data = NULL; /* * We're called from user space, we can use _irq * rather then _irqsave */ spin_lock_irq(&ffs->ev.waitq.lock); switch (ffs_setup_state_clear_cancelled(ffs)) { case FFS_SETUP_CANCELLED: ret = -EIDRM; goto done_spin; case FFS_NO_SETUP: ret = -ESRCH; goto done_spin; case FFS_SETUP_PENDING: break; } /* FFS_SETUP_PENDING */ if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) { spin_unlock_irq(&ffs->ev.waitq.lock); ret = __ffs_ep0_stall(ffs); break; } /* FFS_SETUP_PENDING and not stall */ len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength)); spin_unlock_irq(&ffs->ev.waitq.lock); data = ffs_prepare_buffer(buf, len); if (IS_ERR(data)) { ret = PTR_ERR(data); break; } spin_lock_irq(&ffs->ev.waitq.lock); /* * We are guaranteed to be still in FFS_ACTIVE state * but the state of setup could have changed from * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need * to check for that. If that happened we copied data * from user space in vain but it's unlikely. * * For sure we are not in FFS_NO_SETUP since this is * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP * transition can be performed and it's protected by * mutex. */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) { ret = -EIDRM;done_spin: spin_unlock_irq(&ffs->ev.waitq.lock); } else { /* unlocks spinlock */ ret = __ffs_ep0_queue_wait(ffs, data, len); } kfree(data); break; default: ret = -EBADFD; break;Lines 1–500 of 4470. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * f_fs.c -- user mode file system API for USB composite function controllers * * Copyright (C) 2010 Samsung Electronics * Author: Michal Nazarewicz <mina86@mina86.com> * * Based on inode.c (GadgetFS) which was: * Copyright (C) 2003-2004 David Brownell * Copyright (C) 2003 Agilent Technologies */ /* #define DEBUG */ /* #define VERBOSE_DEBUG */ #include <linux/blkdev.h> #include <linux/dma-buf.h> #include <linux/dma-fence.h> #include <linux/dma-resv.h> #include <linux/pagemap.h> #include <linux/export.h> #include <linux/fs_parser.h> #include <linux/hid.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/scatterlist.h> #include <linux/sched/signal.h> #include <linux/uio.h> #include <linux/vmalloc.h> #include <linux/unaligned.h> #include <linux/usb/ccid.h> #include <linux/usb/composite.h> #include <linux/usb/functionfs.h> #include <linux/usb/func_utils.h> #include <linux/aio.h> #include <linux/kthread.h> #include <linux/poll.h> #include <linux/eventfd.h> #include "u_fs.h" #include "u_os_desc.h" #include "configfs.h" #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ #define MAX_ALT_SETTINGS 2 /* Allow up to 2 alt settings to be set. */ #define DMABUF_ENQUEUE_TIMEOUT_MS 5000 MODULE_IMPORT_NS("DMA_BUF"); /* Reference counter handling */ static void ffs_data_get(struct ffs_data *ffs); static void ffs_data_put(struct ffs_data *ffs); /* Creates new ffs_data object. */ static struct ffs_data *__must_check ffs_data_new(const char *dev_name) __attribute__((malloc)); /* Opened counter handling. */ static void ffs_data_closed(struct ffs_data *ffs); /* Called with ffs->mutex held; take over ownership of data. */ static int __must_check __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); static int __must_check __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); /* The function structure ***************************************************/ struct ffs_ep; struct ffs_function { struct usb_configuration *conf; struct usb_gadget *gadget; struct ffs_data *ffs; struct ffs_ep *eps; u8 eps_revmap[16]; short *interfaces_nums; struct usb_function function; int cur_alt[MAX_CONFIG_INTERFACES]; }; static struct ffs_function *ffs_func_from_usb(struct usb_function *f) { return container_of(f, struct ffs_function, function); } static inline enum ffs_setup_state ffs_setup_state_clear_cancelled(struct ffs_data *ffs) { return (enum ffs_setup_state) cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP); } static void ffs_func_eps_disable(struct ffs_function *func); static int __must_check ffs_func_eps_enable(struct ffs_function *func); static int ffs_func_bind(struct usb_configuration *, struct usb_function *); static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); static int ffs_func_get_alt(struct usb_function *f, unsigned int intf); static void ffs_func_disable(struct usb_function *); static int ffs_func_setup(struct usb_function *, const struct usb_ctrlrequest *); static bool ffs_func_req_match(struct usb_function *, const struct usb_ctrlrequest *, bool config0); static void ffs_func_suspend(struct usb_function *); static void ffs_func_resume(struct usb_function *); static int ffs_func_revmap_ep(struct ffs_function *func, u8 num); static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf); /* The endpoints structures *************************************************/ struct ffs_ep { struct usb_ep *ep; /* P: ffs->eps_lock */ struct usb_request *req; /* P: epfile->mutex */ /* [0]: full speed, [1]: high speed, [2]: super speed */ struct usb_endpoint_descriptor *descs[3]; u8 num; }; struct ffs_dmabuf_priv { struct list_head entry; struct kref ref; struct ffs_data *ffs; struct dma_buf_attachment *attach; struct sg_table *sgt; enum dma_data_direction dir; spinlock_t lock; u64 context; struct usb_request *req; /* P: ffs->eps_lock */ struct usb_ep *ep; /* P: ffs->eps_lock */ }; struct ffs_dma_fence { struct dma_fence base; struct ffs_dmabuf_priv *priv; struct work_struct work; struct usb_ep *ep; struct usb_request *req; }; struct ffs_epfile { /* Protects ep->ep and ep->req. */ struct mutex mutex; struct ffs_data *ffs; struct ffs_ep *ep; /* P: ffs->eps_lock */ struct ffs_epfile *epfile_in; /* P: ffs->eps_lock */ struct ffs_epfile *epfile_out; /* P: ffs->eps_lock */ /* * Buffer for holding data from partial reads which may happen since * we’re rounding user read requests to a multiple of a max packet size. * * The pointer is initialised with NULL value and may be set by * __ffs_epfile_read_data function to point to a temporary buffer. * * In normal operation, calls to __ffs_epfile_read_buffered will consume * data from said buffer and eventually free it. Importantly, while the * function is using the buffer, it sets the pointer to NULL. This is * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered * can never run concurrently (they are synchronised by epfile->mutex) * so the latter will not assign a new value to the pointer. * * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is * valid) and sets the pointer to READ_BUFFER_DROP value. This special * value is crux of the synchronisation between ffs_func_eps_disable and * __ffs_epfile_read_data. * * Once __ffs_epfile_read_data is about to finish it will try to set the * pointer back to its old value (as described above), but seeing as the * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free * the buffer. * * == State transitions == * * • ptr == NULL: (initial state) * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP * ◦ __ffs_epfile_read_buffered: nop * ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == DROP: * ◦ __ffs_epfile_read_buffer_free: nop * ◦ __ffs_epfile_read_buffered: go to ptr == NULL * ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == buf: * ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP * ◦ __ffs_epfile_read_buffered: go to ptr == NULL and reading * ◦ __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered * is always called first * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == NULL and reading: * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading * ◦ __ffs_epfile_read_buffered: n/a, mutex is held * ◦ __ffs_epfile_read_data: n/a, mutex is held * ◦ reading finishes and … * … all data read: free buf, go to ptr == NULL * … otherwise: go to ptr == buf and reading * • ptr == DROP and reading: * ◦ __ffs_epfile_read_buffer_free: nop * ◦ __ffs_epfile_read_buffered: n/a, mutex is held * ◦ __ffs_epfile_read_data: n/a, mutex is held * ◦ reading finishes: free buf, go to ptr == DROP */ struct ffs_buffer *read_buffer; #define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN)) char name[8]; unsigned char in; /* P: ffs->eps_lock */ unsigned char isoc; /* P: ffs->eps_lock */ u8 zlp_enabled; /* P: ffs->eps_lock */ bool is_rw_proxy; /* Protects dmabufs */ struct mutex dmabufs_mutex; struct list_head dmabufs; /* P: dmabufs_mutex */ atomic_t seqno; }; struct ffs_buffer { size_t length; char *data; char storage[] __counted_by(length); }; /* ffs_io_data structure ***************************************************/ struct ffs_io_data { bool aio; bool read; struct kiocb *kiocb; struct iov_iter data; const void *to_free; char *buf; struct mm_struct *mm; struct work_struct work; struct usb_ep *ep; struct usb_request *req; struct sg_table sgt; bool use_sg; struct ffs_data *ffs; int status; struct completion done; }; struct ffs_desc_helper { struct ffs_data *ffs; unsigned interfaces_count; unsigned eps_count; }; static int __must_check ffs_epfiles_create(struct ffs_data *ffs); static void ffs_epfiles_destroy(struct super_block *sb, struct ffs_epfile *epfiles, unsigned count); static int ffs_sb_create_file(struct super_block *sb, const char *name, void *data, const struct file_operations *fops); /* Devices management *******************************************************/ DEFINE_MUTEX(ffs_lock); EXPORT_SYMBOL_GPL(ffs_lock); static struct ffs_dev *_ffs_find_dev(const char *name); static struct ffs_dev *_ffs_alloc_dev(void); static void _ffs_free_dev(struct ffs_dev *dev); static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data); static void ffs_release_dev(struct ffs_dev *ffs_dev); static int ffs_ready(struct ffs_data *ffs); static void ffs_closed(struct ffs_data *ffs); static void ffs_reset_work(struct work_struct *work); /* Misc helper functions ****************************************************/ static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) __attribute__((warn_unused_result, nonnull)); static char *ffs_prepare_buffer(const char __user *buf, size_t len) __attribute__((warn_unused_result, nonnull)); /* Control file aka ep0 *****************************************************/ static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req) { struct ffs_data *ffs = req->context; complete(&ffs->ep0req_completion); } static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) __releases(&ffs->ev.waitq.lock) { struct usb_request *req = ffs->ep0req; int ret; if (!req) { spin_unlock_irq(&ffs->ev.waitq.lock); return -EINVAL; } req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); spin_unlock_irq(&ffs->ev.waitq.lock); req->buf = data; req->length = len; /* * UDC layer requires to provide a buffer even for ZLP, but should * not use it at all. Let's provide some poisoned pointer to catch * possible bug in the driver. */ if (req->buf == NULL) req->buf = (void *)0xDEADBABE; reinit_completion(&ffs->ep0req_completion); ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); if (ret < 0) return ret; ret = wait_for_completion_interruptible(&ffs->ep0req_completion); if (ret) { usb_ep_dequeue(ffs->gadget->ep0, req); return -EINTR; } ffs->setup_state = FFS_NO_SETUP; return req->status ? req->status : req->actual; } static int __ffs_ep0_stall(struct ffs_data *ffs) { if (ffs->ev.can_stall) { pr_vdebug("ep0 stall\n"); usb_ep_set_halt(ffs->gadget->ep0); ffs->setup_state = FFS_NO_SETUP; return -EL2HLT; } else { pr_debug("bogus ep0 stall!\n"); return -ESRCH; } } static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, size_t len, loff_t *ptr) { struct ffs_data *ffs = file->private_data; ssize_t ret; char *data; /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; /* Acquire mutex */ ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); if (ret < 0) return ret; /* Check state */ switch (ffs->state) { case FFS_READ_DESCRIPTORS: case FFS_READ_STRINGS: /* Copy data */ if (len < 16) { ret = -EINVAL; break; } data = ffs_prepare_buffer(buf, len); if (IS_ERR(data)) { ret = PTR_ERR(data); break; } /* Handle data */ if (ffs->state == FFS_READ_DESCRIPTORS) { pr_info("read descriptors\n"); ret = __ffs_data_got_descs(ffs, data, len); if (ret < 0) break; ffs->state = FFS_READ_STRINGS; ret = len; } else { pr_info("read strings\n"); ret = __ffs_data_got_strings(ffs, data, len); if (ret < 0) break; ret = ffs_epfiles_create(ffs); if (ret) { ffs->state = FFS_CLOSING; break; } ffs->state = FFS_ACTIVE; mutex_unlock(&ffs->mutex); ret = ffs_ready(ffs); if (ret < 0) { ffs->state = FFS_CLOSING; return ret; } return len; } break; case FFS_ACTIVE: data = NULL; /* * We're called from user space, we can use _irq * rather then _irqsave */ spin_lock_irq(&ffs->ev.waitq.lock); switch (ffs_setup_state_clear_cancelled(ffs)) { case FFS_SETUP_CANCELLED: ret = -EIDRM; goto done_spin; case FFS_NO_SETUP: ret = -ESRCH; goto done_spin; case FFS_SETUP_PENDING: break; } /* FFS_SETUP_PENDING */ if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) { spin_unlock_irq(&ffs->ev.waitq.lock); ret = __ffs_ep0_stall(ffs); break; } /* FFS_SETUP_PENDING and not stall */ len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength)); spin_unlock_irq(&ffs->ev.waitq.lock); data = ffs_prepare_buffer(buf, len); if (IS_ERR(data)) { ret = PTR_ERR(data); break; } spin_lock_irq(&ffs->ev.waitq.lock); /* * We are guaranteed to be still in FFS_ACTIVE state * but the state of setup could have changed from * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need * to check for that. If that happened we copied data * from user space in vain but it's unlikely. * * For sure we are not in FFS_NO_SETUP since this is * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP * transition can be performed and it's protected by * mutex. */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) { ret = -EIDRM; done_spin: spin_unlock_irq(&ffs->ev.waitq.lock); } else { /* unlocks spinlock */ ret = __ffs_ep0_queue_wait(ffs, data, len); } kfree(data); break; default: ret = -EBADFD; break;