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