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> 2000a2430fSAndrzej Pietrasiewicz #include <linux/hid.h> 2100a2430fSAndrzej Pietrasiewicz #include <linux/module.h> 22174cd4b1SIngo Molnar #include <linux/sched/signal.h> 23e2e40f2cSChristoph Hellwig #include <linux/uio.h> 2400a2430fSAndrzej Pietrasiewicz #include <asm/unaligned.h> 2500a2430fSAndrzej Pietrasiewicz 2600a2430fSAndrzej Pietrasiewicz #include <linux/usb/composite.h> 2700a2430fSAndrzej Pietrasiewicz #include <linux/usb/functionfs.h> 2800a2430fSAndrzej Pietrasiewicz 2900a2430fSAndrzej Pietrasiewicz #include <linux/aio.h> 3000a2430fSAndrzej Pietrasiewicz #include <linux/mmu_context.h> 3100a2430fSAndrzej Pietrasiewicz #include <linux/poll.h> 325e33f6fdSRobert Baldyga #include <linux/eventfd.h> 3300a2430fSAndrzej Pietrasiewicz 3400a2430fSAndrzej Pietrasiewicz #include "u_fs.h" 3500a2430fSAndrzej Pietrasiewicz #include "u_f.h" 3600a2430fSAndrzej Pietrasiewicz #include "u_os_desc.h" 3700a2430fSAndrzej Pietrasiewicz #include "configfs.h" 3800a2430fSAndrzej Pietrasiewicz 3900a2430fSAndrzej Pietrasiewicz #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ 4000a2430fSAndrzej Pietrasiewicz 4100a2430fSAndrzej Pietrasiewicz /* Reference counter handling */ 4200a2430fSAndrzej Pietrasiewicz static void ffs_data_get(struct ffs_data *ffs); 4300a2430fSAndrzej Pietrasiewicz static void ffs_data_put(struct ffs_data *ffs); 4400a2430fSAndrzej Pietrasiewicz /* Creates new ffs_data object. */ 45addfc582SJohn Keeping static struct ffs_data *__must_check ffs_data_new(const char *dev_name) 46addfc582SJohn Keeping __attribute__((malloc)); 4700a2430fSAndrzej Pietrasiewicz 4800a2430fSAndrzej Pietrasiewicz /* Opened counter handling. */ 4900a2430fSAndrzej Pietrasiewicz static void ffs_data_opened(struct ffs_data *ffs); 5000a2430fSAndrzej Pietrasiewicz static void ffs_data_closed(struct ffs_data *ffs); 5100a2430fSAndrzej Pietrasiewicz 5200a2430fSAndrzej Pietrasiewicz /* Called with ffs->mutex held; take over ownership of data. */ 5300a2430fSAndrzej Pietrasiewicz static int __must_check 5400a2430fSAndrzej Pietrasiewicz __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); 5500a2430fSAndrzej Pietrasiewicz static int __must_check 5600a2430fSAndrzej Pietrasiewicz __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); 5700a2430fSAndrzej Pietrasiewicz 5800a2430fSAndrzej Pietrasiewicz 5900a2430fSAndrzej Pietrasiewicz /* The function structure ***************************************************/ 6000a2430fSAndrzej Pietrasiewicz 6100a2430fSAndrzej Pietrasiewicz struct ffs_ep; 6200a2430fSAndrzej Pietrasiewicz 6300a2430fSAndrzej Pietrasiewicz struct ffs_function { 6400a2430fSAndrzej Pietrasiewicz struct usb_configuration *conf; 6500a2430fSAndrzej Pietrasiewicz struct usb_gadget *gadget; 6600a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs; 6700a2430fSAndrzej Pietrasiewicz 6800a2430fSAndrzej Pietrasiewicz struct ffs_ep *eps; 6900a2430fSAndrzej Pietrasiewicz u8 eps_revmap[16]; 7000a2430fSAndrzej Pietrasiewicz short *interfaces_nums; 7100a2430fSAndrzej Pietrasiewicz 7200a2430fSAndrzej Pietrasiewicz struct usb_function function; 7300a2430fSAndrzej Pietrasiewicz }; 7400a2430fSAndrzej Pietrasiewicz 7500a2430fSAndrzej Pietrasiewicz 7600a2430fSAndrzej Pietrasiewicz static struct ffs_function *ffs_func_from_usb(struct usb_function *f) 7700a2430fSAndrzej Pietrasiewicz { 7800a2430fSAndrzej Pietrasiewicz return container_of(f, struct ffs_function, function); 7900a2430fSAndrzej Pietrasiewicz } 8000a2430fSAndrzej Pietrasiewicz 8100a2430fSAndrzej Pietrasiewicz 8200a2430fSAndrzej Pietrasiewicz static inline enum ffs_setup_state 8300a2430fSAndrzej Pietrasiewicz ffs_setup_state_clear_cancelled(struct ffs_data *ffs) 8400a2430fSAndrzej Pietrasiewicz { 8500a2430fSAndrzej Pietrasiewicz return (enum ffs_setup_state) 8600a2430fSAndrzej Pietrasiewicz cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP); 8700a2430fSAndrzej Pietrasiewicz } 8800a2430fSAndrzej Pietrasiewicz 8900a2430fSAndrzej Pietrasiewicz 9000a2430fSAndrzej Pietrasiewicz static void ffs_func_eps_disable(struct ffs_function *func); 9100a2430fSAndrzej Pietrasiewicz static int __must_check ffs_func_eps_enable(struct ffs_function *func); 9200a2430fSAndrzej Pietrasiewicz 9300a2430fSAndrzej Pietrasiewicz static int ffs_func_bind(struct usb_configuration *, 9400a2430fSAndrzej Pietrasiewicz struct usb_function *); 9500a2430fSAndrzej Pietrasiewicz static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); 9600a2430fSAndrzej Pietrasiewicz static void ffs_func_disable(struct usb_function *); 9700a2430fSAndrzej Pietrasiewicz static int ffs_func_setup(struct usb_function *, 9800a2430fSAndrzej Pietrasiewicz const struct usb_ctrlrequest *); 9954dfce6dSFelix Hädicke static bool ffs_func_req_match(struct usb_function *, 1001a00b457SFelix Hädicke const struct usb_ctrlrequest *, 1011a00b457SFelix Hädicke bool config0); 10200a2430fSAndrzej Pietrasiewicz static void ffs_func_suspend(struct usb_function *); 10300a2430fSAndrzej Pietrasiewicz static void ffs_func_resume(struct usb_function *); 10400a2430fSAndrzej Pietrasiewicz 10500a2430fSAndrzej Pietrasiewicz 10600a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_ep(struct ffs_function *func, u8 num); 10700a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf); 10800a2430fSAndrzej Pietrasiewicz 10900a2430fSAndrzej Pietrasiewicz 11000a2430fSAndrzej Pietrasiewicz /* The endpoints structures *************************************************/ 11100a2430fSAndrzej Pietrasiewicz 11200a2430fSAndrzej Pietrasiewicz struct ffs_ep { 11300a2430fSAndrzej Pietrasiewicz struct usb_ep *ep; /* P: ffs->eps_lock */ 11400a2430fSAndrzej Pietrasiewicz struct usb_request *req; /* P: epfile->mutex */ 11500a2430fSAndrzej Pietrasiewicz 11600a2430fSAndrzej Pietrasiewicz /* [0]: full speed, [1]: high speed, [2]: super speed */ 11700a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *descs[3]; 11800a2430fSAndrzej Pietrasiewicz 11900a2430fSAndrzej Pietrasiewicz u8 num; 12000a2430fSAndrzej Pietrasiewicz 12100a2430fSAndrzej Pietrasiewicz int status; /* P: epfile->mutex */ 12200a2430fSAndrzej Pietrasiewicz }; 12300a2430fSAndrzej Pietrasiewicz 12400a2430fSAndrzej Pietrasiewicz struct ffs_epfile { 12500a2430fSAndrzej Pietrasiewicz /* Protects ep->ep and ep->req. */ 12600a2430fSAndrzej Pietrasiewicz struct mutex mutex; 12700a2430fSAndrzej Pietrasiewicz 12800a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs; 12900a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep; /* P: ffs->eps_lock */ 13000a2430fSAndrzej Pietrasiewicz 13100a2430fSAndrzej Pietrasiewicz struct dentry *dentry; 13200a2430fSAndrzej Pietrasiewicz 1339353afbbSMichal Nazarewicz /* 1349353afbbSMichal Nazarewicz * Buffer for holding data from partial reads which may happen since 1359353afbbSMichal Nazarewicz * we’re rounding user read requests to a multiple of a max packet size. 136a9e6f83cSMichal Nazarewicz * 137a9e6f83cSMichal Nazarewicz * The pointer is initialised with NULL value and may be set by 138a9e6f83cSMichal Nazarewicz * __ffs_epfile_read_data function to point to a temporary buffer. 139a9e6f83cSMichal Nazarewicz * 140a9e6f83cSMichal Nazarewicz * In normal operation, calls to __ffs_epfile_read_buffered will consume 141a9e6f83cSMichal Nazarewicz * data from said buffer and eventually free it. Importantly, while the 142a9e6f83cSMichal Nazarewicz * function is using the buffer, it sets the pointer to NULL. This is 143a9e6f83cSMichal Nazarewicz * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered 144a9e6f83cSMichal Nazarewicz * can never run concurrently (they are synchronised by epfile->mutex) 145a9e6f83cSMichal Nazarewicz * so the latter will not assign a new value to the pointer. 146a9e6f83cSMichal Nazarewicz * 147a9e6f83cSMichal Nazarewicz * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is 148a9e6f83cSMichal Nazarewicz * valid) and sets the pointer to READ_BUFFER_DROP value. This special 149a9e6f83cSMichal Nazarewicz * value is crux of the synchronisation between ffs_func_eps_disable and 150a9e6f83cSMichal Nazarewicz * __ffs_epfile_read_data. 151a9e6f83cSMichal Nazarewicz * 152a9e6f83cSMichal Nazarewicz * Once __ffs_epfile_read_data is about to finish it will try to set the 153a9e6f83cSMichal Nazarewicz * pointer back to its old value (as described above), but seeing as the 154a9e6f83cSMichal Nazarewicz * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free 155a9e6f83cSMichal Nazarewicz * the buffer. 156a9e6f83cSMichal Nazarewicz * 157a9e6f83cSMichal Nazarewicz * == State transitions == 158a9e6f83cSMichal Nazarewicz * 159a9e6f83cSMichal Nazarewicz * • ptr == NULL: (initial state) 160a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP 161a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffered: nop 162a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf 163a9e6f83cSMichal Nazarewicz * ◦ reading finishes: n/a, not in ‘and reading’ state 164a9e6f83cSMichal Nazarewicz * • ptr == DROP: 165a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffer_free: nop 166a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffered: go to ptr == NULL 167a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop 168a9e6f83cSMichal Nazarewicz * ◦ reading finishes: n/a, not in ‘and reading’ state 169a9e6f83cSMichal Nazarewicz * • ptr == buf: 170a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP 171a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffered: go to ptr == NULL and reading 172a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered 173a9e6f83cSMichal Nazarewicz * is always called first 174a9e6f83cSMichal Nazarewicz * ◦ reading finishes: n/a, not in ‘and reading’ state 175a9e6f83cSMichal Nazarewicz * • ptr == NULL and reading: 176a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading 177a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffered: n/a, mutex is held 178a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_data: n/a, mutex is held 179a9e6f83cSMichal Nazarewicz * ◦ reading finishes and … 180a9e6f83cSMichal Nazarewicz * … all data read: free buf, go to ptr == NULL 181a9e6f83cSMichal Nazarewicz * … otherwise: go to ptr == buf and reading 182a9e6f83cSMichal Nazarewicz * • ptr == DROP and reading: 183a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffer_free: nop 184a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_buffered: n/a, mutex is held 185a9e6f83cSMichal Nazarewicz * ◦ __ffs_epfile_read_data: n/a, mutex is held 186a9e6f83cSMichal Nazarewicz * ◦ reading finishes: free buf, go to ptr == DROP 1879353afbbSMichal Nazarewicz */ 188a9e6f83cSMichal Nazarewicz struct ffs_buffer *read_buffer; 189a9e6f83cSMichal Nazarewicz #define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN)) 1909353afbbSMichal Nazarewicz 19100a2430fSAndrzej Pietrasiewicz char name[5]; 19200a2430fSAndrzej Pietrasiewicz 19300a2430fSAndrzej Pietrasiewicz unsigned char in; /* P: ffs->eps_lock */ 19400a2430fSAndrzej Pietrasiewicz unsigned char isoc; /* P: ffs->eps_lock */ 19500a2430fSAndrzej Pietrasiewicz 19600a2430fSAndrzej Pietrasiewicz unsigned char _pad; 19700a2430fSAndrzej Pietrasiewicz }; 19800a2430fSAndrzej Pietrasiewicz 1999353afbbSMichal Nazarewicz struct ffs_buffer { 2009353afbbSMichal Nazarewicz size_t length; 2019353afbbSMichal Nazarewicz char *data; 2029353afbbSMichal Nazarewicz char storage[]; 2039353afbbSMichal Nazarewicz }; 2049353afbbSMichal Nazarewicz 20500a2430fSAndrzej Pietrasiewicz /* ffs_io_data structure ***************************************************/ 20600a2430fSAndrzej Pietrasiewicz 20700a2430fSAndrzej Pietrasiewicz struct ffs_io_data { 20800a2430fSAndrzej Pietrasiewicz bool aio; 20900a2430fSAndrzej Pietrasiewicz bool read; 21000a2430fSAndrzej Pietrasiewicz 21100a2430fSAndrzej Pietrasiewicz struct kiocb *kiocb; 212c993c39bSAl Viro struct iov_iter data; 213c993c39bSAl Viro const void *to_free; 214c993c39bSAl Viro char *buf; 21500a2430fSAndrzej Pietrasiewicz 21600a2430fSAndrzej Pietrasiewicz struct mm_struct *mm; 21700a2430fSAndrzej Pietrasiewicz struct work_struct work; 21800a2430fSAndrzej Pietrasiewicz 21900a2430fSAndrzej Pietrasiewicz struct usb_ep *ep; 22000a2430fSAndrzej Pietrasiewicz struct usb_request *req; 2215e33f6fdSRobert Baldyga 2225e33f6fdSRobert Baldyga struct ffs_data *ffs; 22300a2430fSAndrzej Pietrasiewicz }; 22400a2430fSAndrzej Pietrasiewicz 2256d5c1c77SRobert Baldyga struct ffs_desc_helper { 2266d5c1c77SRobert Baldyga struct ffs_data *ffs; 2276d5c1c77SRobert Baldyga unsigned interfaces_count; 2286d5c1c77SRobert Baldyga unsigned eps_count; 2296d5c1c77SRobert Baldyga }; 2306d5c1c77SRobert Baldyga 23100a2430fSAndrzej Pietrasiewicz static int __must_check ffs_epfiles_create(struct ffs_data *ffs); 23200a2430fSAndrzej Pietrasiewicz static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); 23300a2430fSAndrzej Pietrasiewicz 2341bb27cacSAl Viro static struct dentry * 23500a2430fSAndrzej Pietrasiewicz ffs_sb_create_file(struct super_block *sb, const char *name, void *data, 2361bb27cacSAl Viro const struct file_operations *fops); 23700a2430fSAndrzej Pietrasiewicz 23800a2430fSAndrzej Pietrasiewicz /* Devices management *******************************************************/ 23900a2430fSAndrzej Pietrasiewicz 24000a2430fSAndrzej Pietrasiewicz DEFINE_MUTEX(ffs_lock); 24100a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_lock); 24200a2430fSAndrzej Pietrasiewicz 24300a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_find_dev(const char *name); 24400a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_alloc_dev(void); 24500a2430fSAndrzej Pietrasiewicz static void _ffs_free_dev(struct ffs_dev *dev); 24600a2430fSAndrzej Pietrasiewicz static void *ffs_acquire_dev(const char *dev_name); 24700a2430fSAndrzej Pietrasiewicz static void ffs_release_dev(struct ffs_data *ffs_data); 24800a2430fSAndrzej Pietrasiewicz static int ffs_ready(struct ffs_data *ffs); 24900a2430fSAndrzej Pietrasiewicz static void ffs_closed(struct ffs_data *ffs); 25000a2430fSAndrzej Pietrasiewicz 25100a2430fSAndrzej Pietrasiewicz /* Misc helper functions ****************************************************/ 25200a2430fSAndrzej Pietrasiewicz 25300a2430fSAndrzej Pietrasiewicz static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) 25400a2430fSAndrzej Pietrasiewicz __attribute__((warn_unused_result, nonnull)); 25500a2430fSAndrzej Pietrasiewicz static char *ffs_prepare_buffer(const char __user *buf, size_t len) 25600a2430fSAndrzej Pietrasiewicz __attribute__((warn_unused_result, nonnull)); 25700a2430fSAndrzej Pietrasiewicz 25800a2430fSAndrzej Pietrasiewicz 25900a2430fSAndrzej Pietrasiewicz /* Control file aka ep0 *****************************************************/ 26000a2430fSAndrzej Pietrasiewicz 26100a2430fSAndrzej Pietrasiewicz static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req) 26200a2430fSAndrzej Pietrasiewicz { 26300a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = req->context; 26400a2430fSAndrzej Pietrasiewicz 2655bdcde90SDaniel Wagner complete(&ffs->ep0req_completion); 26600a2430fSAndrzej Pietrasiewicz } 26700a2430fSAndrzej Pietrasiewicz 26800a2430fSAndrzej Pietrasiewicz static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) 269c40619bbSVincent Pelletier __releases(&ffs->ev.waitq.lock) 27000a2430fSAndrzej Pietrasiewicz { 27100a2430fSAndrzej Pietrasiewicz struct usb_request *req = ffs->ep0req; 27200a2430fSAndrzej Pietrasiewicz int ret; 27300a2430fSAndrzej Pietrasiewicz 27400a2430fSAndrzej Pietrasiewicz req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); 27500a2430fSAndrzej Pietrasiewicz 27600a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 27700a2430fSAndrzej Pietrasiewicz 27800a2430fSAndrzej Pietrasiewicz req->buf = data; 27900a2430fSAndrzej Pietrasiewicz req->length = len; 28000a2430fSAndrzej Pietrasiewicz 28100a2430fSAndrzej Pietrasiewicz /* 28200a2430fSAndrzej Pietrasiewicz * UDC layer requires to provide a buffer even for ZLP, but should 28300a2430fSAndrzej Pietrasiewicz * not use it at all. Let's provide some poisoned pointer to catch 28400a2430fSAndrzej Pietrasiewicz * possible bug in the driver. 28500a2430fSAndrzej Pietrasiewicz */ 28600a2430fSAndrzej Pietrasiewicz if (req->buf == NULL) 28700a2430fSAndrzej Pietrasiewicz req->buf = (void *)0xDEADBABE; 28800a2430fSAndrzej Pietrasiewicz 28900a2430fSAndrzej Pietrasiewicz reinit_completion(&ffs->ep0req_completion); 29000a2430fSAndrzej Pietrasiewicz 29100a2430fSAndrzej Pietrasiewicz ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); 29200a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 29300a2430fSAndrzej Pietrasiewicz return ret; 29400a2430fSAndrzej Pietrasiewicz 29500a2430fSAndrzej Pietrasiewicz ret = wait_for_completion_interruptible(&ffs->ep0req_completion); 29600a2430fSAndrzej Pietrasiewicz if (unlikely(ret)) { 29700a2430fSAndrzej Pietrasiewicz usb_ep_dequeue(ffs->gadget->ep0, req); 29800a2430fSAndrzej Pietrasiewicz return -EINTR; 29900a2430fSAndrzej Pietrasiewicz } 30000a2430fSAndrzej Pietrasiewicz 30100a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_NO_SETUP; 30200a2430fSAndrzej Pietrasiewicz return req->status ? req->status : req->actual; 30300a2430fSAndrzej Pietrasiewicz } 30400a2430fSAndrzej Pietrasiewicz 30500a2430fSAndrzej Pietrasiewicz static int __ffs_ep0_stall(struct ffs_data *ffs) 30600a2430fSAndrzej Pietrasiewicz { 30700a2430fSAndrzej Pietrasiewicz if (ffs->ev.can_stall) { 30800a2430fSAndrzej Pietrasiewicz pr_vdebug("ep0 stall\n"); 30900a2430fSAndrzej Pietrasiewicz usb_ep_set_halt(ffs->gadget->ep0); 31000a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_NO_SETUP; 31100a2430fSAndrzej Pietrasiewicz return -EL2HLT; 31200a2430fSAndrzej Pietrasiewicz } else { 31300a2430fSAndrzej Pietrasiewicz pr_debug("bogus ep0 stall!\n"); 31400a2430fSAndrzej Pietrasiewicz return -ESRCH; 31500a2430fSAndrzej Pietrasiewicz } 31600a2430fSAndrzej Pietrasiewicz } 31700a2430fSAndrzej Pietrasiewicz 31800a2430fSAndrzej Pietrasiewicz static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, 31900a2430fSAndrzej Pietrasiewicz size_t len, loff_t *ptr) 32000a2430fSAndrzej Pietrasiewicz { 32100a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 32200a2430fSAndrzej Pietrasiewicz ssize_t ret; 32300a2430fSAndrzej Pietrasiewicz char *data; 32400a2430fSAndrzej Pietrasiewicz 32500a2430fSAndrzej Pietrasiewicz ENTER(); 32600a2430fSAndrzej Pietrasiewicz 32700a2430fSAndrzej Pietrasiewicz /* Fast check if setup was canceled */ 32800a2430fSAndrzej Pietrasiewicz if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) 32900a2430fSAndrzej Pietrasiewicz return -EIDRM; 33000a2430fSAndrzej Pietrasiewicz 33100a2430fSAndrzej Pietrasiewicz /* Acquire mutex */ 33200a2430fSAndrzej Pietrasiewicz ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); 33300a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 33400a2430fSAndrzej Pietrasiewicz return ret; 33500a2430fSAndrzej Pietrasiewicz 33600a2430fSAndrzej Pietrasiewicz /* Check state */ 33700a2430fSAndrzej Pietrasiewicz switch (ffs->state) { 33800a2430fSAndrzej Pietrasiewicz case FFS_READ_DESCRIPTORS: 33900a2430fSAndrzej Pietrasiewicz case FFS_READ_STRINGS: 34000a2430fSAndrzej Pietrasiewicz /* Copy data */ 34100a2430fSAndrzej Pietrasiewicz if (unlikely(len < 16)) { 34200a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 34300a2430fSAndrzej Pietrasiewicz break; 34400a2430fSAndrzej Pietrasiewicz } 34500a2430fSAndrzej Pietrasiewicz 34600a2430fSAndrzej Pietrasiewicz data = ffs_prepare_buffer(buf, len); 34700a2430fSAndrzej Pietrasiewicz if (IS_ERR(data)) { 34800a2430fSAndrzej Pietrasiewicz ret = PTR_ERR(data); 34900a2430fSAndrzej Pietrasiewicz break; 35000a2430fSAndrzej Pietrasiewicz } 35100a2430fSAndrzej Pietrasiewicz 35200a2430fSAndrzej Pietrasiewicz /* Handle data */ 35300a2430fSAndrzej Pietrasiewicz if (ffs->state == FFS_READ_DESCRIPTORS) { 35400a2430fSAndrzej Pietrasiewicz pr_info("read descriptors\n"); 35500a2430fSAndrzej Pietrasiewicz ret = __ffs_data_got_descs(ffs, data, len); 35600a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 35700a2430fSAndrzej Pietrasiewicz break; 35800a2430fSAndrzej Pietrasiewicz 35900a2430fSAndrzej Pietrasiewicz ffs->state = FFS_READ_STRINGS; 36000a2430fSAndrzej Pietrasiewicz ret = len; 36100a2430fSAndrzej Pietrasiewicz } else { 36200a2430fSAndrzej Pietrasiewicz pr_info("read strings\n"); 36300a2430fSAndrzej Pietrasiewicz ret = __ffs_data_got_strings(ffs, data, len); 36400a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 36500a2430fSAndrzej Pietrasiewicz break; 36600a2430fSAndrzej Pietrasiewicz 36700a2430fSAndrzej Pietrasiewicz ret = ffs_epfiles_create(ffs); 36800a2430fSAndrzej Pietrasiewicz if (unlikely(ret)) { 36900a2430fSAndrzej Pietrasiewicz ffs->state = FFS_CLOSING; 37000a2430fSAndrzej Pietrasiewicz break; 37100a2430fSAndrzej Pietrasiewicz } 37200a2430fSAndrzej Pietrasiewicz 37300a2430fSAndrzej Pietrasiewicz ffs->state = FFS_ACTIVE; 37400a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 37500a2430fSAndrzej Pietrasiewicz 37600a2430fSAndrzej Pietrasiewicz ret = ffs_ready(ffs); 37700a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 37800a2430fSAndrzej Pietrasiewicz ffs->state = FFS_CLOSING; 37900a2430fSAndrzej Pietrasiewicz return ret; 38000a2430fSAndrzej Pietrasiewicz } 38100a2430fSAndrzej Pietrasiewicz 38200a2430fSAndrzej Pietrasiewicz return len; 38300a2430fSAndrzej Pietrasiewicz } 38400a2430fSAndrzej Pietrasiewicz break; 38500a2430fSAndrzej Pietrasiewicz 38600a2430fSAndrzej Pietrasiewicz case FFS_ACTIVE: 38700a2430fSAndrzej Pietrasiewicz data = NULL; 38800a2430fSAndrzej Pietrasiewicz /* 38900a2430fSAndrzej Pietrasiewicz * We're called from user space, we can use _irq 39000a2430fSAndrzej Pietrasiewicz * rather then _irqsave 39100a2430fSAndrzej Pietrasiewicz */ 39200a2430fSAndrzej Pietrasiewicz spin_lock_irq(&ffs->ev.waitq.lock); 39300a2430fSAndrzej Pietrasiewicz switch (ffs_setup_state_clear_cancelled(ffs)) { 39400a2430fSAndrzej Pietrasiewicz case FFS_SETUP_CANCELLED: 39500a2430fSAndrzej Pietrasiewicz ret = -EIDRM; 39600a2430fSAndrzej Pietrasiewicz goto done_spin; 39700a2430fSAndrzej Pietrasiewicz 39800a2430fSAndrzej Pietrasiewicz case FFS_NO_SETUP: 39900a2430fSAndrzej Pietrasiewicz ret = -ESRCH; 40000a2430fSAndrzej Pietrasiewicz goto done_spin; 40100a2430fSAndrzej Pietrasiewicz 40200a2430fSAndrzej Pietrasiewicz case FFS_SETUP_PENDING: 40300a2430fSAndrzej Pietrasiewicz break; 40400a2430fSAndrzej Pietrasiewicz } 40500a2430fSAndrzej Pietrasiewicz 40600a2430fSAndrzej Pietrasiewicz /* FFS_SETUP_PENDING */ 40700a2430fSAndrzej Pietrasiewicz if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) { 40800a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 40900a2430fSAndrzej Pietrasiewicz ret = __ffs_ep0_stall(ffs); 41000a2430fSAndrzej Pietrasiewicz break; 41100a2430fSAndrzej Pietrasiewicz } 41200a2430fSAndrzej Pietrasiewicz 41300a2430fSAndrzej Pietrasiewicz /* FFS_SETUP_PENDING and not stall */ 41400a2430fSAndrzej Pietrasiewicz len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); 41500a2430fSAndrzej Pietrasiewicz 41600a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 41700a2430fSAndrzej Pietrasiewicz 41800a2430fSAndrzej Pietrasiewicz data = ffs_prepare_buffer(buf, len); 41900a2430fSAndrzej Pietrasiewicz if (IS_ERR(data)) { 42000a2430fSAndrzej Pietrasiewicz ret = PTR_ERR(data); 42100a2430fSAndrzej Pietrasiewicz break; 42200a2430fSAndrzej Pietrasiewicz } 42300a2430fSAndrzej Pietrasiewicz 42400a2430fSAndrzej Pietrasiewicz spin_lock_irq(&ffs->ev.waitq.lock); 42500a2430fSAndrzej Pietrasiewicz 42600a2430fSAndrzej Pietrasiewicz /* 42700a2430fSAndrzej Pietrasiewicz * We are guaranteed to be still in FFS_ACTIVE state 42800a2430fSAndrzej Pietrasiewicz * but the state of setup could have changed from 42900a2430fSAndrzej Pietrasiewicz * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need 43000a2430fSAndrzej Pietrasiewicz * to check for that. If that happened we copied data 43100a2430fSAndrzej Pietrasiewicz * from user space in vain but it's unlikely. 43200a2430fSAndrzej Pietrasiewicz * 43300a2430fSAndrzej Pietrasiewicz * For sure we are not in FFS_NO_SETUP since this is 43400a2430fSAndrzej Pietrasiewicz * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP 43500a2430fSAndrzej Pietrasiewicz * transition can be performed and it's protected by 43600a2430fSAndrzej Pietrasiewicz * mutex. 43700a2430fSAndrzej Pietrasiewicz */ 43800a2430fSAndrzej Pietrasiewicz if (ffs_setup_state_clear_cancelled(ffs) == 43900a2430fSAndrzej Pietrasiewicz FFS_SETUP_CANCELLED) { 44000a2430fSAndrzej Pietrasiewicz ret = -EIDRM; 44100a2430fSAndrzej Pietrasiewicz done_spin: 44200a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 44300a2430fSAndrzej Pietrasiewicz } else { 44400a2430fSAndrzej Pietrasiewicz /* unlocks spinlock */ 44500a2430fSAndrzej Pietrasiewicz ret = __ffs_ep0_queue_wait(ffs, data, len); 44600a2430fSAndrzej Pietrasiewicz } 44700a2430fSAndrzej Pietrasiewicz kfree(data); 44800a2430fSAndrzej Pietrasiewicz break; 44900a2430fSAndrzej Pietrasiewicz 45000a2430fSAndrzej Pietrasiewicz default: 45100a2430fSAndrzej Pietrasiewicz ret = -EBADFD; 45200a2430fSAndrzej Pietrasiewicz break; 45300a2430fSAndrzej Pietrasiewicz } 45400a2430fSAndrzej Pietrasiewicz 45500a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 45600a2430fSAndrzej Pietrasiewicz return ret; 45700a2430fSAndrzej Pietrasiewicz } 45800a2430fSAndrzej Pietrasiewicz 45967913bbdSMichal Nazarewicz /* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */ 46000a2430fSAndrzej Pietrasiewicz static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, 46100a2430fSAndrzej Pietrasiewicz size_t n) 462c40619bbSVincent Pelletier __releases(&ffs->ev.waitq.lock) 46300a2430fSAndrzej Pietrasiewicz { 46400a2430fSAndrzej Pietrasiewicz /* 46567913bbdSMichal Nazarewicz * n cannot be bigger than ffs->ev.count, which cannot be bigger than 46667913bbdSMichal Nazarewicz * size of ffs->ev.types array (which is four) so that's how much space 46767913bbdSMichal Nazarewicz * we reserve. 46800a2430fSAndrzej Pietrasiewicz */ 46967913bbdSMichal Nazarewicz struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)]; 47067913bbdSMichal Nazarewicz const size_t size = n * sizeof *events; 47100a2430fSAndrzej Pietrasiewicz unsigned i = 0; 47200a2430fSAndrzej Pietrasiewicz 47367913bbdSMichal Nazarewicz memset(events, 0, size); 47400a2430fSAndrzej Pietrasiewicz 47500a2430fSAndrzej Pietrasiewicz do { 47600a2430fSAndrzej Pietrasiewicz events[i].type = ffs->ev.types[i]; 47700a2430fSAndrzej Pietrasiewicz if (events[i].type == FUNCTIONFS_SETUP) { 47800a2430fSAndrzej Pietrasiewicz events[i].u.setup = ffs->ev.setup; 47900a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_SETUP_PENDING; 48000a2430fSAndrzej Pietrasiewicz } 48100a2430fSAndrzej Pietrasiewicz } while (++i < n); 48200a2430fSAndrzej Pietrasiewicz 48300a2430fSAndrzej Pietrasiewicz ffs->ev.count -= n; 48467913bbdSMichal Nazarewicz if (ffs->ev.count) 48500a2430fSAndrzej Pietrasiewicz memmove(ffs->ev.types, ffs->ev.types + n, 48600a2430fSAndrzej Pietrasiewicz ffs->ev.count * sizeof *ffs->ev.types); 48700a2430fSAndrzej Pietrasiewicz 48800a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 48900a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 49000a2430fSAndrzej Pietrasiewicz 4917fe9a937SDaniel Walter return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size; 49200a2430fSAndrzej Pietrasiewicz } 49300a2430fSAndrzej Pietrasiewicz 49400a2430fSAndrzej Pietrasiewicz static ssize_t ffs_ep0_read(struct file *file, char __user *buf, 49500a2430fSAndrzej Pietrasiewicz size_t len, loff_t *ptr) 49600a2430fSAndrzej Pietrasiewicz { 49700a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 49800a2430fSAndrzej Pietrasiewicz char *data = NULL; 49900a2430fSAndrzej Pietrasiewicz size_t n; 50000a2430fSAndrzej Pietrasiewicz int ret; 50100a2430fSAndrzej Pietrasiewicz 50200a2430fSAndrzej Pietrasiewicz ENTER(); 50300a2430fSAndrzej Pietrasiewicz 50400a2430fSAndrzej Pietrasiewicz /* Fast check if setup was canceled */ 50500a2430fSAndrzej Pietrasiewicz if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) 50600a2430fSAndrzej Pietrasiewicz return -EIDRM; 50700a2430fSAndrzej Pietrasiewicz 50800a2430fSAndrzej Pietrasiewicz /* Acquire mutex */ 50900a2430fSAndrzej Pietrasiewicz ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); 51000a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 51100a2430fSAndrzej Pietrasiewicz return ret; 51200a2430fSAndrzej Pietrasiewicz 51300a2430fSAndrzej Pietrasiewicz /* Check state */ 51400a2430fSAndrzej Pietrasiewicz if (ffs->state != FFS_ACTIVE) { 51500a2430fSAndrzej Pietrasiewicz ret = -EBADFD; 51600a2430fSAndrzej Pietrasiewicz goto done_mutex; 51700a2430fSAndrzej Pietrasiewicz } 51800a2430fSAndrzej Pietrasiewicz 51900a2430fSAndrzej Pietrasiewicz /* 52000a2430fSAndrzej Pietrasiewicz * We're called from user space, we can use _irq rather then 52100a2430fSAndrzej Pietrasiewicz * _irqsave 52200a2430fSAndrzej Pietrasiewicz */ 52300a2430fSAndrzej Pietrasiewicz spin_lock_irq(&ffs->ev.waitq.lock); 52400a2430fSAndrzej Pietrasiewicz 52500a2430fSAndrzej Pietrasiewicz switch (ffs_setup_state_clear_cancelled(ffs)) { 52600a2430fSAndrzej Pietrasiewicz case FFS_SETUP_CANCELLED: 52700a2430fSAndrzej Pietrasiewicz ret = -EIDRM; 52800a2430fSAndrzej Pietrasiewicz break; 52900a2430fSAndrzej Pietrasiewicz 53000a2430fSAndrzej Pietrasiewicz case FFS_NO_SETUP: 53100a2430fSAndrzej Pietrasiewicz n = len / sizeof(struct usb_functionfs_event); 53200a2430fSAndrzej Pietrasiewicz if (unlikely(!n)) { 53300a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 53400a2430fSAndrzej Pietrasiewicz break; 53500a2430fSAndrzej Pietrasiewicz } 53600a2430fSAndrzej Pietrasiewicz 53700a2430fSAndrzej Pietrasiewicz if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) { 53800a2430fSAndrzej Pietrasiewicz ret = -EAGAIN; 53900a2430fSAndrzej Pietrasiewicz break; 54000a2430fSAndrzej Pietrasiewicz } 54100a2430fSAndrzej Pietrasiewicz 54200a2430fSAndrzej Pietrasiewicz if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq, 54300a2430fSAndrzej Pietrasiewicz ffs->ev.count)) { 54400a2430fSAndrzej Pietrasiewicz ret = -EINTR; 54500a2430fSAndrzej Pietrasiewicz break; 54600a2430fSAndrzej Pietrasiewicz } 54700a2430fSAndrzej Pietrasiewicz 548c40619bbSVincent Pelletier /* unlocks spinlock */ 54900a2430fSAndrzej Pietrasiewicz return __ffs_ep0_read_events(ffs, buf, 55000a2430fSAndrzej Pietrasiewicz min(n, (size_t)ffs->ev.count)); 55100a2430fSAndrzej Pietrasiewicz 55200a2430fSAndrzej Pietrasiewicz case FFS_SETUP_PENDING: 55300a2430fSAndrzej Pietrasiewicz if (ffs->ev.setup.bRequestType & USB_DIR_IN) { 55400a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 55500a2430fSAndrzej Pietrasiewicz ret = __ffs_ep0_stall(ffs); 55600a2430fSAndrzej Pietrasiewicz goto done_mutex; 55700a2430fSAndrzej Pietrasiewicz } 55800a2430fSAndrzej Pietrasiewicz 55900a2430fSAndrzej Pietrasiewicz len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); 56000a2430fSAndrzej Pietrasiewicz 56100a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 56200a2430fSAndrzej Pietrasiewicz 56300a2430fSAndrzej Pietrasiewicz if (likely(len)) { 56400a2430fSAndrzej Pietrasiewicz data = kmalloc(len, GFP_KERNEL); 56500a2430fSAndrzej Pietrasiewicz if (unlikely(!data)) { 56600a2430fSAndrzej Pietrasiewicz ret = -ENOMEM; 56700a2430fSAndrzej Pietrasiewicz goto done_mutex; 56800a2430fSAndrzej Pietrasiewicz } 56900a2430fSAndrzej Pietrasiewicz } 57000a2430fSAndrzej Pietrasiewicz 57100a2430fSAndrzej Pietrasiewicz spin_lock_irq(&ffs->ev.waitq.lock); 57200a2430fSAndrzej Pietrasiewicz 57300a2430fSAndrzej Pietrasiewicz /* See ffs_ep0_write() */ 57400a2430fSAndrzej Pietrasiewicz if (ffs_setup_state_clear_cancelled(ffs) == 57500a2430fSAndrzej Pietrasiewicz FFS_SETUP_CANCELLED) { 57600a2430fSAndrzej Pietrasiewicz ret = -EIDRM; 57700a2430fSAndrzej Pietrasiewicz break; 57800a2430fSAndrzej Pietrasiewicz } 57900a2430fSAndrzej Pietrasiewicz 58000a2430fSAndrzej Pietrasiewicz /* unlocks spinlock */ 58100a2430fSAndrzej Pietrasiewicz ret = __ffs_ep0_queue_wait(ffs, data, len); 5827fe9a937SDaniel Walter if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len))) 58300a2430fSAndrzej Pietrasiewicz ret = -EFAULT; 58400a2430fSAndrzej Pietrasiewicz goto done_mutex; 58500a2430fSAndrzej Pietrasiewicz 58600a2430fSAndrzej Pietrasiewicz default: 58700a2430fSAndrzej Pietrasiewicz ret = -EBADFD; 58800a2430fSAndrzej Pietrasiewicz break; 58900a2430fSAndrzej Pietrasiewicz } 59000a2430fSAndrzej Pietrasiewicz 59100a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 59200a2430fSAndrzej Pietrasiewicz done_mutex: 59300a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 59400a2430fSAndrzej Pietrasiewicz kfree(data); 59500a2430fSAndrzej Pietrasiewicz return ret; 59600a2430fSAndrzej Pietrasiewicz } 59700a2430fSAndrzej Pietrasiewicz 59800a2430fSAndrzej Pietrasiewicz static int ffs_ep0_open(struct inode *inode, struct file *file) 59900a2430fSAndrzej Pietrasiewicz { 60000a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = inode->i_private; 60100a2430fSAndrzej Pietrasiewicz 60200a2430fSAndrzej Pietrasiewicz ENTER(); 60300a2430fSAndrzej Pietrasiewicz 60400a2430fSAndrzej Pietrasiewicz if (unlikely(ffs->state == FFS_CLOSING)) 60500a2430fSAndrzej Pietrasiewicz return -EBUSY; 60600a2430fSAndrzej Pietrasiewicz 60700a2430fSAndrzej Pietrasiewicz file->private_data = ffs; 60800a2430fSAndrzej Pietrasiewicz ffs_data_opened(ffs); 60900a2430fSAndrzej Pietrasiewicz 61000a2430fSAndrzej Pietrasiewicz return 0; 61100a2430fSAndrzej Pietrasiewicz } 61200a2430fSAndrzej Pietrasiewicz 61300a2430fSAndrzej Pietrasiewicz static int ffs_ep0_release(struct inode *inode, struct file *file) 61400a2430fSAndrzej Pietrasiewicz { 61500a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 61600a2430fSAndrzej Pietrasiewicz 61700a2430fSAndrzej Pietrasiewicz ENTER(); 61800a2430fSAndrzej Pietrasiewicz 61900a2430fSAndrzej Pietrasiewicz ffs_data_closed(ffs); 62000a2430fSAndrzej Pietrasiewicz 62100a2430fSAndrzej Pietrasiewicz return 0; 62200a2430fSAndrzej Pietrasiewicz } 62300a2430fSAndrzej Pietrasiewicz 62400a2430fSAndrzej Pietrasiewicz static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) 62500a2430fSAndrzej Pietrasiewicz { 62600a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 62700a2430fSAndrzej Pietrasiewicz struct usb_gadget *gadget = ffs->gadget; 62800a2430fSAndrzej Pietrasiewicz long ret; 62900a2430fSAndrzej Pietrasiewicz 63000a2430fSAndrzej Pietrasiewicz ENTER(); 63100a2430fSAndrzej Pietrasiewicz 63200a2430fSAndrzej Pietrasiewicz if (code == FUNCTIONFS_INTERFACE_REVMAP) { 63300a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs->func; 63400a2430fSAndrzej Pietrasiewicz ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; 63500a2430fSAndrzej Pietrasiewicz } else if (gadget && gadget->ops->ioctl) { 63600a2430fSAndrzej Pietrasiewicz ret = gadget->ops->ioctl(gadget, code, value); 63700a2430fSAndrzej Pietrasiewicz } else { 63800a2430fSAndrzej Pietrasiewicz ret = -ENOTTY; 63900a2430fSAndrzej Pietrasiewicz } 64000a2430fSAndrzej Pietrasiewicz 64100a2430fSAndrzej Pietrasiewicz return ret; 64200a2430fSAndrzej Pietrasiewicz } 64300a2430fSAndrzej Pietrasiewicz 644afc9a42bSAl Viro static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait) 64500a2430fSAndrzej Pietrasiewicz { 64600a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 647a9a08845SLinus Torvalds __poll_t mask = EPOLLWRNORM; 64800a2430fSAndrzej Pietrasiewicz int ret; 64900a2430fSAndrzej Pietrasiewicz 65000a2430fSAndrzej Pietrasiewicz poll_wait(file, &ffs->ev.waitq, wait); 65100a2430fSAndrzej Pietrasiewicz 65200a2430fSAndrzej Pietrasiewicz ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); 65300a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 65400a2430fSAndrzej Pietrasiewicz return mask; 65500a2430fSAndrzej Pietrasiewicz 65600a2430fSAndrzej Pietrasiewicz switch (ffs->state) { 65700a2430fSAndrzej Pietrasiewicz case FFS_READ_DESCRIPTORS: 65800a2430fSAndrzej Pietrasiewicz case FFS_READ_STRINGS: 659a9a08845SLinus Torvalds mask |= EPOLLOUT; 66000a2430fSAndrzej Pietrasiewicz break; 66100a2430fSAndrzej Pietrasiewicz 66200a2430fSAndrzej Pietrasiewicz case FFS_ACTIVE: 66300a2430fSAndrzej Pietrasiewicz switch (ffs->setup_state) { 66400a2430fSAndrzej Pietrasiewicz case FFS_NO_SETUP: 66500a2430fSAndrzej Pietrasiewicz if (ffs->ev.count) 666a9a08845SLinus Torvalds mask |= EPOLLIN; 66700a2430fSAndrzej Pietrasiewicz break; 66800a2430fSAndrzej Pietrasiewicz 66900a2430fSAndrzej Pietrasiewicz case FFS_SETUP_PENDING: 67000a2430fSAndrzej Pietrasiewicz case FFS_SETUP_CANCELLED: 671a9a08845SLinus Torvalds mask |= (EPOLLIN | EPOLLOUT); 67200a2430fSAndrzej Pietrasiewicz break; 67300a2430fSAndrzej Pietrasiewicz } 67400a2430fSAndrzej Pietrasiewicz case FFS_CLOSING: 67500a2430fSAndrzej Pietrasiewicz break; 67618d6b32fSRobert Baldyga case FFS_DEACTIVATED: 67718d6b32fSRobert Baldyga break; 67800a2430fSAndrzej Pietrasiewicz } 67900a2430fSAndrzej Pietrasiewicz 68000a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 68100a2430fSAndrzej Pietrasiewicz 68200a2430fSAndrzej Pietrasiewicz return mask; 68300a2430fSAndrzej Pietrasiewicz } 68400a2430fSAndrzej Pietrasiewicz 68500a2430fSAndrzej Pietrasiewicz static const struct file_operations ffs_ep0_operations = { 68600a2430fSAndrzej Pietrasiewicz .llseek = no_llseek, 68700a2430fSAndrzej Pietrasiewicz 68800a2430fSAndrzej Pietrasiewicz .open = ffs_ep0_open, 68900a2430fSAndrzej Pietrasiewicz .write = ffs_ep0_write, 69000a2430fSAndrzej Pietrasiewicz .read = ffs_ep0_read, 69100a2430fSAndrzej Pietrasiewicz .release = ffs_ep0_release, 69200a2430fSAndrzej Pietrasiewicz .unlocked_ioctl = ffs_ep0_ioctl, 69300a2430fSAndrzej Pietrasiewicz .poll = ffs_ep0_poll, 69400a2430fSAndrzej Pietrasiewicz }; 69500a2430fSAndrzej Pietrasiewicz 69600a2430fSAndrzej Pietrasiewicz 69700a2430fSAndrzej Pietrasiewicz /* "Normal" endpoints operations ********************************************/ 69800a2430fSAndrzej Pietrasiewicz 69900a2430fSAndrzej Pietrasiewicz static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) 70000a2430fSAndrzej Pietrasiewicz { 70100a2430fSAndrzej Pietrasiewicz ENTER(); 70200a2430fSAndrzej Pietrasiewicz if (likely(req->context)) { 70300a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep = _ep->driver_data; 70400a2430fSAndrzej Pietrasiewicz ep->status = req->status ? req->status : req->actual; 70500a2430fSAndrzej Pietrasiewicz complete(req->context); 70600a2430fSAndrzej Pietrasiewicz } 70700a2430fSAndrzej Pietrasiewicz } 70800a2430fSAndrzej Pietrasiewicz 709c662a31bSMichal Nazarewicz static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) 710c662a31bSMichal Nazarewicz { 711c662a31bSMichal Nazarewicz ssize_t ret = copy_to_iter(data, data_len, iter); 712c662a31bSMichal Nazarewicz if (likely(ret == data_len)) 713c662a31bSMichal Nazarewicz return ret; 714c662a31bSMichal Nazarewicz 715c662a31bSMichal Nazarewicz if (unlikely(iov_iter_count(iter))) 716c662a31bSMichal Nazarewicz return -EFAULT; 717c662a31bSMichal Nazarewicz 718c662a31bSMichal Nazarewicz /* 719c662a31bSMichal Nazarewicz * Dear user space developer! 720c662a31bSMichal Nazarewicz * 721c662a31bSMichal Nazarewicz * TL;DR: To stop getting below error message in your kernel log, change 722c662a31bSMichal Nazarewicz * user space code using functionfs to align read buffers to a max 723c662a31bSMichal Nazarewicz * packet size. 724c662a31bSMichal Nazarewicz * 725c662a31bSMichal Nazarewicz * Some UDCs (e.g. dwc3) require request sizes to be a multiple of a max 726c662a31bSMichal Nazarewicz * packet size. When unaligned buffer is passed to functionfs, it 727c662a31bSMichal Nazarewicz * internally uses a larger, aligned buffer so that such UDCs are happy. 728c662a31bSMichal Nazarewicz * 729c662a31bSMichal Nazarewicz * Unfortunately, this means that host may send more data than was 730c662a31bSMichal Nazarewicz * requested in read(2) system call. f_fs doesn’t know what to do with 731c662a31bSMichal Nazarewicz * that excess data so it simply drops it. 732c662a31bSMichal Nazarewicz * 733c662a31bSMichal Nazarewicz * Was the buffer aligned in the first place, no such problem would 734c662a31bSMichal Nazarewicz * happen. 735c662a31bSMichal Nazarewicz * 7369353afbbSMichal Nazarewicz * Data may be dropped only in AIO reads. Synchronous reads are handled 7379353afbbSMichal Nazarewicz * by splitting a request into multiple parts. This splitting may still 7389353afbbSMichal Nazarewicz * be a problem though so it’s likely best to align the buffer 7399353afbbSMichal Nazarewicz * regardless of it being AIO or not.. 7409353afbbSMichal Nazarewicz * 741c662a31bSMichal Nazarewicz * This only affects OUT endpoints, i.e. reading data with a read(2), 742c662a31bSMichal Nazarewicz * aio_read(2) etc. system calls. Writing data to an IN endpoint is not 743c662a31bSMichal Nazarewicz * affected. 744c662a31bSMichal Nazarewicz */ 745c662a31bSMichal Nazarewicz pr_err("functionfs read size %d > requested size %zd, dropping excess data. " 746c662a31bSMichal Nazarewicz "Align read buffer size to max packet size to avoid the problem.\n", 747c662a31bSMichal Nazarewicz data_len, ret); 748c662a31bSMichal Nazarewicz 749c662a31bSMichal Nazarewicz return ret; 750c662a31bSMichal Nazarewicz } 751c662a31bSMichal Nazarewicz 75200a2430fSAndrzej Pietrasiewicz static void ffs_user_copy_worker(struct work_struct *work) 75300a2430fSAndrzej Pietrasiewicz { 75400a2430fSAndrzej Pietrasiewicz struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, 75500a2430fSAndrzej Pietrasiewicz work); 75600a2430fSAndrzej Pietrasiewicz int ret = io_data->req->status ? io_data->req->status : 75700a2430fSAndrzej Pietrasiewicz io_data->req->actual; 75838740a5bSLars-Peter Clausen bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD; 75900a2430fSAndrzej Pietrasiewicz 76000a2430fSAndrzej Pietrasiewicz if (io_data->read && ret > 0) { 7614058ebf3SLars-Peter Clausen mm_segment_t oldfs = get_fs(); 7624058ebf3SLars-Peter Clausen 7634058ebf3SLars-Peter Clausen set_fs(USER_DS); 76400a2430fSAndrzej Pietrasiewicz use_mm(io_data->mm); 765c662a31bSMichal Nazarewicz ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data); 76600a2430fSAndrzej Pietrasiewicz unuse_mm(io_data->mm); 7674058ebf3SLars-Peter Clausen set_fs(oldfs); 76800a2430fSAndrzej Pietrasiewicz } 76900a2430fSAndrzej Pietrasiewicz 77004b2fa9fSChristoph Hellwig io_data->kiocb->ki_complete(io_data->kiocb, ret, ret); 77100a2430fSAndrzej Pietrasiewicz 77238740a5bSLars-Peter Clausen if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd) 7735e33f6fdSRobert Baldyga eventfd_signal(io_data->ffs->ffs_eventfd, 1); 7745e33f6fdSRobert Baldyga 77500a2430fSAndrzej Pietrasiewicz usb_ep_free_request(io_data->ep, io_data->req); 77600a2430fSAndrzej Pietrasiewicz 77700a2430fSAndrzej Pietrasiewicz if (io_data->read) 778c993c39bSAl Viro kfree(io_data->to_free); 77900a2430fSAndrzej Pietrasiewicz kfree(io_data->buf); 78000a2430fSAndrzej Pietrasiewicz kfree(io_data); 78100a2430fSAndrzej Pietrasiewicz } 78200a2430fSAndrzej Pietrasiewicz 78300a2430fSAndrzej Pietrasiewicz static void ffs_epfile_async_io_complete(struct usb_ep *_ep, 78400a2430fSAndrzej Pietrasiewicz struct usb_request *req) 78500a2430fSAndrzej Pietrasiewicz { 78600a2430fSAndrzej Pietrasiewicz struct ffs_io_data *io_data = req->context; 787addfc582SJohn Keeping struct ffs_data *ffs = io_data->ffs; 78800a2430fSAndrzej Pietrasiewicz 78900a2430fSAndrzej Pietrasiewicz ENTER(); 79000a2430fSAndrzej Pietrasiewicz 79100a2430fSAndrzej Pietrasiewicz INIT_WORK(&io_data->work, ffs_user_copy_worker); 792addfc582SJohn Keeping queue_work(ffs->io_completion_wq, &io_data->work); 79300a2430fSAndrzej Pietrasiewicz } 79400a2430fSAndrzej Pietrasiewicz 795a9e6f83cSMichal Nazarewicz static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile) 796a9e6f83cSMichal Nazarewicz { 797a9e6f83cSMichal Nazarewicz /* 798a9e6f83cSMichal Nazarewicz * See comment in struct ffs_epfile for full read_buffer pointer 799a9e6f83cSMichal Nazarewicz * synchronisation story. 800a9e6f83cSMichal Nazarewicz */ 801a9e6f83cSMichal Nazarewicz struct ffs_buffer *buf = xchg(&epfile->read_buffer, READ_BUFFER_DROP); 802a9e6f83cSMichal Nazarewicz if (buf && buf != READ_BUFFER_DROP) 803a9e6f83cSMichal Nazarewicz kfree(buf); 804a9e6f83cSMichal Nazarewicz } 805a9e6f83cSMichal Nazarewicz 8069353afbbSMichal Nazarewicz /* Assumes epfile->mutex is held. */ 8079353afbbSMichal Nazarewicz static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, 8089353afbbSMichal Nazarewicz struct iov_iter *iter) 8099353afbbSMichal Nazarewicz { 810a9e6f83cSMichal Nazarewicz /* 811a9e6f83cSMichal Nazarewicz * Null out epfile->read_buffer so ffs_func_eps_disable does not free 812a9e6f83cSMichal Nazarewicz * the buffer while we are using it. See comment in struct ffs_epfile 813a9e6f83cSMichal Nazarewicz * for full read_buffer pointer synchronisation story. 814a9e6f83cSMichal Nazarewicz */ 815a9e6f83cSMichal Nazarewicz struct ffs_buffer *buf = xchg(&epfile->read_buffer, NULL); 8169353afbbSMichal Nazarewicz ssize_t ret; 817a9e6f83cSMichal Nazarewicz if (!buf || buf == READ_BUFFER_DROP) 8189353afbbSMichal Nazarewicz return 0; 8199353afbbSMichal Nazarewicz 8209353afbbSMichal Nazarewicz ret = copy_to_iter(buf->data, buf->length, iter); 8219353afbbSMichal Nazarewicz if (buf->length == ret) { 8229353afbbSMichal Nazarewicz kfree(buf); 823a9e6f83cSMichal Nazarewicz return ret; 824a9e6f83cSMichal Nazarewicz } 825a9e6f83cSMichal Nazarewicz 826a9e6f83cSMichal Nazarewicz if (unlikely(iov_iter_count(iter))) { 8279353afbbSMichal Nazarewicz ret = -EFAULT; 8289353afbbSMichal Nazarewicz } else { 8299353afbbSMichal Nazarewicz buf->length -= ret; 8309353afbbSMichal Nazarewicz buf->data += ret; 8319353afbbSMichal Nazarewicz } 832a9e6f83cSMichal Nazarewicz 833a9e6f83cSMichal Nazarewicz if (cmpxchg(&epfile->read_buffer, NULL, buf)) 834a9e6f83cSMichal Nazarewicz kfree(buf); 835a9e6f83cSMichal Nazarewicz 8369353afbbSMichal Nazarewicz return ret; 8379353afbbSMichal Nazarewicz } 8389353afbbSMichal Nazarewicz 8399353afbbSMichal Nazarewicz /* Assumes epfile->mutex is held. */ 8409353afbbSMichal Nazarewicz static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, 8419353afbbSMichal Nazarewicz void *data, int data_len, 8429353afbbSMichal Nazarewicz struct iov_iter *iter) 8439353afbbSMichal Nazarewicz { 8449353afbbSMichal Nazarewicz struct ffs_buffer *buf; 8459353afbbSMichal Nazarewicz 8469353afbbSMichal Nazarewicz ssize_t ret = copy_to_iter(data, data_len, iter); 8479353afbbSMichal Nazarewicz if (likely(data_len == ret)) 8489353afbbSMichal Nazarewicz return ret; 8499353afbbSMichal Nazarewicz 8509353afbbSMichal Nazarewicz if (unlikely(iov_iter_count(iter))) 8519353afbbSMichal Nazarewicz return -EFAULT; 8529353afbbSMichal Nazarewicz 8539353afbbSMichal Nazarewicz /* See ffs_copy_to_iter for more context. */ 8549353afbbSMichal Nazarewicz pr_warn("functionfs read size %d > requested size %zd, splitting request into multiple reads.", 8559353afbbSMichal Nazarewicz data_len, ret); 8569353afbbSMichal Nazarewicz 8579353afbbSMichal Nazarewicz data_len -= ret; 8589353afbbSMichal Nazarewicz buf = kmalloc(sizeof(*buf) + data_len, GFP_KERNEL); 85944963d64SDan Carpenter if (!buf) 86044963d64SDan Carpenter return -ENOMEM; 8619353afbbSMichal Nazarewicz buf->length = data_len; 8629353afbbSMichal Nazarewicz buf->data = buf->storage; 8639353afbbSMichal Nazarewicz memcpy(buf->storage, data + ret, data_len); 864a9e6f83cSMichal Nazarewicz 865a9e6f83cSMichal Nazarewicz /* 866a9e6f83cSMichal Nazarewicz * At this point read_buffer is NULL or READ_BUFFER_DROP (if 867a9e6f83cSMichal Nazarewicz * ffs_func_eps_disable has been called in the meanwhile). See comment 868a9e6f83cSMichal Nazarewicz * in struct ffs_epfile for full read_buffer pointer synchronisation 869a9e6f83cSMichal Nazarewicz * story. 870a9e6f83cSMichal Nazarewicz */ 871a9e6f83cSMichal Nazarewicz if (unlikely(cmpxchg(&epfile->read_buffer, NULL, buf))) 872a9e6f83cSMichal Nazarewicz kfree(buf); 8739353afbbSMichal Nazarewicz 8749353afbbSMichal Nazarewicz return ret; 8759353afbbSMichal Nazarewicz } 8769353afbbSMichal Nazarewicz 87700a2430fSAndrzej Pietrasiewicz static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) 87800a2430fSAndrzej Pietrasiewicz { 87900a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = file->private_data; 880ae76e134SMichal Nazarewicz struct usb_request *req; 88100a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep; 88200a2430fSAndrzej Pietrasiewicz char *data = NULL; 883c0d31b3cSDavid Cohen ssize_t ret, data_len = -EINVAL; 88400a2430fSAndrzej Pietrasiewicz int halt; 88500a2430fSAndrzej Pietrasiewicz 88600a2430fSAndrzej Pietrasiewicz /* Are we still active? */ 887b3591f67SMichal Nazarewicz if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) 888b3591f67SMichal Nazarewicz return -ENODEV; 88900a2430fSAndrzej Pietrasiewicz 89000a2430fSAndrzej Pietrasiewicz /* Wait for endpoint to be enabled */ 89100a2430fSAndrzej Pietrasiewicz ep = epfile->ep; 89200a2430fSAndrzej Pietrasiewicz if (!ep) { 893b3591f67SMichal Nazarewicz if (file->f_flags & O_NONBLOCK) 894b3591f67SMichal Nazarewicz return -EAGAIN; 89500a2430fSAndrzej Pietrasiewicz 896e16828cfSJerry Zhang ret = wait_event_interruptible( 897e16828cfSJerry Zhang epfile->ffs->wait, (ep = epfile->ep)); 898b3591f67SMichal Nazarewicz if (ret) 899b3591f67SMichal Nazarewicz return -EINTR; 90000a2430fSAndrzej Pietrasiewicz } 90100a2430fSAndrzej Pietrasiewicz 90200a2430fSAndrzej Pietrasiewicz /* Do we halt? */ 90300a2430fSAndrzej Pietrasiewicz halt = (!io_data->read == !epfile->in); 904b3591f67SMichal Nazarewicz if (halt && epfile->isoc) 905b3591f67SMichal Nazarewicz return -EINVAL; 90600a2430fSAndrzej Pietrasiewicz 9079353afbbSMichal Nazarewicz /* We will be using request and read_buffer */ 9089353afbbSMichal Nazarewicz ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); 9099353afbbSMichal Nazarewicz if (unlikely(ret)) 9109353afbbSMichal Nazarewicz goto error; 9119353afbbSMichal Nazarewicz 91200a2430fSAndrzej Pietrasiewicz /* Allocate & copy */ 91300a2430fSAndrzej Pietrasiewicz if (!halt) { 9149353afbbSMichal Nazarewicz struct usb_gadget *gadget; 9159353afbbSMichal Nazarewicz 9169353afbbSMichal Nazarewicz /* 9179353afbbSMichal Nazarewicz * Do we have buffered data from previous partial read? Check 9189353afbbSMichal Nazarewicz * that for synchronous case only because we do not have 9199353afbbSMichal Nazarewicz * facility to ‘wake up’ a pending asynchronous read and push 9209353afbbSMichal Nazarewicz * buffered data to it which we would need to make things behave 9219353afbbSMichal Nazarewicz * consistently. 9229353afbbSMichal Nazarewicz */ 9239353afbbSMichal Nazarewicz if (!io_data->aio && io_data->read) { 9249353afbbSMichal Nazarewicz ret = __ffs_epfile_read_buffered(epfile, &io_data->data); 9259353afbbSMichal Nazarewicz if (ret) 9269353afbbSMichal Nazarewicz goto error_mutex; 9279353afbbSMichal Nazarewicz } 9289353afbbSMichal Nazarewicz 92900a2430fSAndrzej Pietrasiewicz /* 93000a2430fSAndrzej Pietrasiewicz * if we _do_ wait above, the epfile->ffs->gadget might be NULL 931ae76e134SMichal Nazarewicz * before the waiting completes, so do not assign to 'gadget' 932ae76e134SMichal Nazarewicz * earlier 93300a2430fSAndrzej Pietrasiewicz */ 9349353afbbSMichal Nazarewicz gadget = epfile->ffs->gadget; 93500a2430fSAndrzej Pietrasiewicz 93600a2430fSAndrzej Pietrasiewicz spin_lock_irq(&epfile->ffs->eps_lock); 93700a2430fSAndrzej Pietrasiewicz /* In the meantime, endpoint got disabled or changed. */ 93800a2430fSAndrzej Pietrasiewicz if (epfile->ep != ep) { 9399353afbbSMichal Nazarewicz ret = -ESHUTDOWN; 9409353afbbSMichal Nazarewicz goto error_lock; 94100a2430fSAndrzej Pietrasiewicz } 942c993c39bSAl Viro data_len = iov_iter_count(&io_data->data); 94300a2430fSAndrzej Pietrasiewicz /* 94400a2430fSAndrzej Pietrasiewicz * Controller may require buffer size to be aligned to 94500a2430fSAndrzej Pietrasiewicz * maxpacketsize of an out endpoint. 94600a2430fSAndrzej Pietrasiewicz */ 947c993c39bSAl Viro if (io_data->read) 948c993c39bSAl Viro data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); 94900a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 95000a2430fSAndrzej Pietrasiewicz 95100a2430fSAndrzej Pietrasiewicz data = kmalloc(data_len, GFP_KERNEL); 9529353afbbSMichal Nazarewicz if (unlikely(!data)) { 9539353afbbSMichal Nazarewicz ret = -ENOMEM; 9549353afbbSMichal Nazarewicz goto error_mutex; 9559353afbbSMichal Nazarewicz } 9569353afbbSMichal Nazarewicz if (!io_data->read && 957cbbd26b8SAl Viro !copy_from_iter_full(data, data_len, &io_data->data)) { 95800a2430fSAndrzej Pietrasiewicz ret = -EFAULT; 9599353afbbSMichal Nazarewicz goto error_mutex; 96000a2430fSAndrzej Pietrasiewicz } 96100a2430fSAndrzej Pietrasiewicz } 96200a2430fSAndrzej Pietrasiewicz 96300a2430fSAndrzej Pietrasiewicz spin_lock_irq(&epfile->ffs->eps_lock); 96400a2430fSAndrzej Pietrasiewicz 96500a2430fSAndrzej Pietrasiewicz if (epfile->ep != ep) { 96600a2430fSAndrzej Pietrasiewicz /* In the meantime, endpoint got disabled or changed. */ 96700a2430fSAndrzej Pietrasiewicz ret = -ESHUTDOWN; 96800a2430fSAndrzej Pietrasiewicz } else if (halt) { 969cdff9f8eSJerry Zhang ret = usb_ep_set_halt(ep->ep); 970cdff9f8eSJerry Zhang if (!ret) 97100a2430fSAndrzej Pietrasiewicz ret = -EBADMSG; 972ae76e134SMichal Nazarewicz } else if (unlikely(data_len == -EINVAL)) { 973c0d31b3cSDavid Cohen /* 974c0d31b3cSDavid Cohen * Sanity Check: even though data_len can't be used 975c0d31b3cSDavid Cohen * uninitialized at the time I write this comment, some 976c0d31b3cSDavid Cohen * compilers complain about this situation. 977c0d31b3cSDavid Cohen * In order to keep the code clean from warnings, data_len is 978c0d31b3cSDavid Cohen * being initialized to -EINVAL during its declaration, which 979c0d31b3cSDavid Cohen * means we can't rely on compiler anymore to warn no future 980c0d31b3cSDavid Cohen * changes won't result in data_len being used uninitialized. 981c0d31b3cSDavid Cohen * For such reason, we're adding this redundant sanity check 982c0d31b3cSDavid Cohen * here. 983c0d31b3cSDavid Cohen */ 984c0d31b3cSDavid Cohen WARN(1, "%s: data_len == -EINVAL\n", __func__); 985c0d31b3cSDavid Cohen ret = -EINVAL; 986ae76e134SMichal Nazarewicz } else if (!io_data->aio) { 987ae76e134SMichal Nazarewicz DECLARE_COMPLETION_ONSTACK(done); 988ef150884SDu, Changbin bool interrupted = false; 989ae76e134SMichal Nazarewicz 990ae76e134SMichal Nazarewicz req = ep->req; 991ae76e134SMichal Nazarewicz req->buf = data; 992ae76e134SMichal Nazarewicz req->length = data_len; 993ae76e134SMichal Nazarewicz 994ae76e134SMichal Nazarewicz req->context = &done; 995ae76e134SMichal Nazarewicz req->complete = ffs_epfile_io_complete; 996ae76e134SMichal Nazarewicz 997ae76e134SMichal Nazarewicz ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); 998ae76e134SMichal Nazarewicz if (unlikely(ret < 0)) 999c0d31b3cSDavid Cohen goto error_lock; 1000ae76e134SMichal Nazarewicz 1001ae76e134SMichal Nazarewicz spin_unlock_irq(&epfile->ffs->eps_lock); 1002ae76e134SMichal Nazarewicz 1003ae76e134SMichal Nazarewicz if (unlikely(wait_for_completion_interruptible(&done))) { 1004ef150884SDu, Changbin /* 1005ef150884SDu, Changbin * To avoid race condition with ffs_epfile_io_complete, 1006ef150884SDu, Changbin * dequeue the request first then check 1007ef150884SDu, Changbin * status. usb_ep_dequeue API should guarantee no race 1008ef150884SDu, Changbin * condition with req->complete callback. 1009ef150884SDu, Changbin */ 1010ae76e134SMichal Nazarewicz usb_ep_dequeue(ep->ep, req); 1011ef150884SDu, Changbin interrupted = ep->status < 0; 1012c0d31b3cSDavid Cohen } 1013c0d31b3cSDavid Cohen 1014c662a31bSMichal Nazarewicz if (interrupted) 1015c662a31bSMichal Nazarewicz ret = -EINTR; 1016c662a31bSMichal Nazarewicz else if (io_data->read && ep->status > 0) 10179353afbbSMichal Nazarewicz ret = __ffs_epfile_read_data(epfile, data, ep->status, 1018c662a31bSMichal Nazarewicz &io_data->data); 1019c662a31bSMichal Nazarewicz else 1020c662a31bSMichal Nazarewicz ret = ep->status; 1021ae76e134SMichal Nazarewicz goto error_mutex; 102230bf90ccSVincent Pelletier } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) { 10233163c79eSMichal Nazarewicz ret = -ENOMEM; 1024ae76e134SMichal Nazarewicz } else { 102500a2430fSAndrzej Pietrasiewicz req->buf = data; 1026c0d31b3cSDavid Cohen req->length = data_len; 102700a2430fSAndrzej Pietrasiewicz 102800a2430fSAndrzej Pietrasiewicz io_data->buf = data; 102900a2430fSAndrzej Pietrasiewicz io_data->ep = ep->ep; 103000a2430fSAndrzej Pietrasiewicz io_data->req = req; 10315e33f6fdSRobert Baldyga io_data->ffs = epfile->ffs; 103200a2430fSAndrzej Pietrasiewicz 103300a2430fSAndrzej Pietrasiewicz req->context = io_data; 103400a2430fSAndrzej Pietrasiewicz req->complete = ffs_epfile_async_io_complete; 103500a2430fSAndrzej Pietrasiewicz 103600a2430fSAndrzej Pietrasiewicz ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); 103700a2430fSAndrzej Pietrasiewicz if (unlikely(ret)) { 103800a2430fSAndrzej Pietrasiewicz usb_ep_free_request(ep->ep, req); 103900a2430fSAndrzej Pietrasiewicz goto error_lock; 104000a2430fSAndrzej Pietrasiewicz } 1041ae76e134SMichal Nazarewicz 104200a2430fSAndrzej Pietrasiewicz ret = -EIOCBQUEUED; 104300a2430fSAndrzej Pietrasiewicz /* 1044ae76e134SMichal Nazarewicz * Do not kfree the buffer in this function. It will be freed 1045ae76e134SMichal Nazarewicz * by ffs_user_copy_worker. 104600a2430fSAndrzej Pietrasiewicz */ 1047ae76e134SMichal Nazarewicz data = NULL; 104800a2430fSAndrzej Pietrasiewicz } 104900a2430fSAndrzej Pietrasiewicz 105000a2430fSAndrzej Pietrasiewicz error_lock: 105100a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 1052ae76e134SMichal Nazarewicz error_mutex: 105300a2430fSAndrzej Pietrasiewicz mutex_unlock(&epfile->mutex); 105400a2430fSAndrzej Pietrasiewicz error: 105500a2430fSAndrzej Pietrasiewicz kfree(data); 105600a2430fSAndrzej Pietrasiewicz return ret; 105700a2430fSAndrzej Pietrasiewicz } 105800a2430fSAndrzej Pietrasiewicz 105900a2430fSAndrzej Pietrasiewicz static int 106000a2430fSAndrzej Pietrasiewicz ffs_epfile_open(struct inode *inode, struct file *file) 106100a2430fSAndrzej Pietrasiewicz { 106200a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = inode->i_private; 106300a2430fSAndrzej Pietrasiewicz 106400a2430fSAndrzej Pietrasiewicz ENTER(); 106500a2430fSAndrzej Pietrasiewicz 106600a2430fSAndrzej Pietrasiewicz if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) 106700a2430fSAndrzej Pietrasiewicz return -ENODEV; 106800a2430fSAndrzej Pietrasiewicz 106900a2430fSAndrzej Pietrasiewicz file->private_data = epfile; 107000a2430fSAndrzej Pietrasiewicz ffs_data_opened(epfile->ffs); 107100a2430fSAndrzej Pietrasiewicz 107200a2430fSAndrzej Pietrasiewicz return 0; 107300a2430fSAndrzej Pietrasiewicz } 107400a2430fSAndrzej Pietrasiewicz 107500a2430fSAndrzej Pietrasiewicz static int ffs_aio_cancel(struct kiocb *kiocb) 107600a2430fSAndrzej Pietrasiewicz { 107700a2430fSAndrzej Pietrasiewicz struct ffs_io_data *io_data = kiocb->private; 107800a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = kiocb->ki_filp->private_data; 107900a2430fSAndrzej Pietrasiewicz int value; 108000a2430fSAndrzej Pietrasiewicz 108100a2430fSAndrzej Pietrasiewicz ENTER(); 108200a2430fSAndrzej Pietrasiewicz 108300a2430fSAndrzej Pietrasiewicz spin_lock_irq(&epfile->ffs->eps_lock); 108400a2430fSAndrzej Pietrasiewicz 108500a2430fSAndrzej Pietrasiewicz if (likely(io_data && io_data->ep && io_data->req)) 108600a2430fSAndrzej Pietrasiewicz value = usb_ep_dequeue(io_data->ep, io_data->req); 108700a2430fSAndrzej Pietrasiewicz else 108800a2430fSAndrzej Pietrasiewicz value = -EINVAL; 108900a2430fSAndrzej Pietrasiewicz 109000a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 109100a2430fSAndrzej Pietrasiewicz 109200a2430fSAndrzej Pietrasiewicz return value; 109300a2430fSAndrzej Pietrasiewicz } 109400a2430fSAndrzej Pietrasiewicz 109570e60d91SAl Viro static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) 109600a2430fSAndrzej Pietrasiewicz { 109770e60d91SAl Viro struct ffs_io_data io_data, *p = &io_data; 1098de2080d4SAl Viro ssize_t res; 109900a2430fSAndrzej Pietrasiewicz 110000a2430fSAndrzej Pietrasiewicz ENTER(); 110100a2430fSAndrzej Pietrasiewicz 110270e60d91SAl Viro if (!is_sync_kiocb(kiocb)) { 110370e60d91SAl Viro p = kmalloc(sizeof(io_data), GFP_KERNEL); 110470e60d91SAl Viro if (unlikely(!p)) 110500a2430fSAndrzej Pietrasiewicz return -ENOMEM; 110670e60d91SAl Viro p->aio = true; 110770e60d91SAl Viro } else { 110870e60d91SAl Viro p->aio = false; 110970e60d91SAl Viro } 111000a2430fSAndrzej Pietrasiewicz 111170e60d91SAl Viro p->read = false; 111270e60d91SAl Viro p->kiocb = kiocb; 111370e60d91SAl Viro p->data = *from; 111470e60d91SAl Viro p->mm = current->mm; 111500a2430fSAndrzej Pietrasiewicz 111670e60d91SAl Viro kiocb->private = p; 111700a2430fSAndrzej Pietrasiewicz 11184088acf1SRui Miguel Silva if (p->aio) 111900a2430fSAndrzej Pietrasiewicz kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); 112000a2430fSAndrzej Pietrasiewicz 112170e60d91SAl Viro res = ffs_epfile_io(kiocb->ki_filp, p); 112270e60d91SAl Viro if (res == -EIOCBQUEUED) 112370e60d91SAl Viro return res; 112470e60d91SAl Viro if (p->aio) 112570e60d91SAl Viro kfree(p); 112670e60d91SAl Viro else 112770e60d91SAl Viro *from = p->data; 1128de2080d4SAl Viro return res; 112900a2430fSAndrzej Pietrasiewicz } 113000a2430fSAndrzej Pietrasiewicz 113170e60d91SAl Viro static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) 113200a2430fSAndrzej Pietrasiewicz { 113370e60d91SAl Viro struct ffs_io_data io_data, *p = &io_data; 1134de2080d4SAl Viro ssize_t res; 113500a2430fSAndrzej Pietrasiewicz 113600a2430fSAndrzej Pietrasiewicz ENTER(); 113700a2430fSAndrzej Pietrasiewicz 113870e60d91SAl Viro if (!is_sync_kiocb(kiocb)) { 113970e60d91SAl Viro p = kmalloc(sizeof(io_data), GFP_KERNEL); 114070e60d91SAl Viro if (unlikely(!p)) 114100a2430fSAndrzej Pietrasiewicz return -ENOMEM; 114270e60d91SAl Viro p->aio = true; 114370e60d91SAl Viro } else { 114470e60d91SAl Viro p->aio = false; 114500a2430fSAndrzej Pietrasiewicz } 114600a2430fSAndrzej Pietrasiewicz 114770e60d91SAl Viro p->read = true; 114870e60d91SAl Viro p->kiocb = kiocb; 114970e60d91SAl Viro if (p->aio) { 115070e60d91SAl Viro p->to_free = dup_iter(&p->data, to, GFP_KERNEL); 115170e60d91SAl Viro if (!p->to_free) { 115270e60d91SAl Viro kfree(p); 115370e60d91SAl Viro return -ENOMEM; 115470e60d91SAl Viro } 115570e60d91SAl Viro } else { 115670e60d91SAl Viro p->data = *to; 115770e60d91SAl Viro p->to_free = NULL; 115870e60d91SAl Viro } 115970e60d91SAl Viro p->mm = current->mm; 116000a2430fSAndrzej Pietrasiewicz 116170e60d91SAl Viro kiocb->private = p; 116200a2430fSAndrzej Pietrasiewicz 11634088acf1SRui Miguel Silva if (p->aio) 116400a2430fSAndrzej Pietrasiewicz kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); 116500a2430fSAndrzej Pietrasiewicz 116670e60d91SAl Viro res = ffs_epfile_io(kiocb->ki_filp, p); 116770e60d91SAl Viro if (res == -EIOCBQUEUED) 116870e60d91SAl Viro return res; 116970e60d91SAl Viro 117070e60d91SAl Viro if (p->aio) { 117170e60d91SAl Viro kfree(p->to_free); 117270e60d91SAl Viro kfree(p); 117370e60d91SAl Viro } else { 117470e60d91SAl Viro *to = p->data; 1175de2080d4SAl Viro } 1176de2080d4SAl Viro return res; 117700a2430fSAndrzej Pietrasiewicz } 117800a2430fSAndrzej Pietrasiewicz 117900a2430fSAndrzej Pietrasiewicz static int 118000a2430fSAndrzej Pietrasiewicz ffs_epfile_release(struct inode *inode, struct file *file) 118100a2430fSAndrzej Pietrasiewicz { 118200a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = inode->i_private; 118300a2430fSAndrzej Pietrasiewicz 118400a2430fSAndrzej Pietrasiewicz ENTER(); 118500a2430fSAndrzej Pietrasiewicz 1186a9e6f83cSMichal Nazarewicz __ffs_epfile_read_buffer_free(epfile); 118700a2430fSAndrzej Pietrasiewicz ffs_data_closed(epfile->ffs); 118800a2430fSAndrzej Pietrasiewicz 118900a2430fSAndrzej Pietrasiewicz return 0; 119000a2430fSAndrzej Pietrasiewicz } 119100a2430fSAndrzej Pietrasiewicz 119200a2430fSAndrzej Pietrasiewicz static long ffs_epfile_ioctl(struct file *file, unsigned code, 119300a2430fSAndrzej Pietrasiewicz unsigned long value) 119400a2430fSAndrzej Pietrasiewicz { 119500a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = file->private_data; 1196222155deSJerry Zhang struct ffs_ep *ep; 119700a2430fSAndrzej Pietrasiewicz int ret; 119800a2430fSAndrzej Pietrasiewicz 119900a2430fSAndrzej Pietrasiewicz ENTER(); 120000a2430fSAndrzej Pietrasiewicz 120100a2430fSAndrzej Pietrasiewicz if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) 120200a2430fSAndrzej Pietrasiewicz return -ENODEV; 120300a2430fSAndrzej Pietrasiewicz 1204222155deSJerry Zhang /* Wait for endpoint to be enabled */ 1205222155deSJerry Zhang ep = epfile->ep; 1206222155deSJerry Zhang if (!ep) { 1207222155deSJerry Zhang if (file->f_flags & O_NONBLOCK) 1208222155deSJerry Zhang return -EAGAIN; 1209222155deSJerry Zhang 1210e16828cfSJerry Zhang ret = wait_event_interruptible( 1211e16828cfSJerry Zhang epfile->ffs->wait, (ep = epfile->ep)); 1212222155deSJerry Zhang if (ret) 1213222155deSJerry Zhang return -EINTR; 1214222155deSJerry Zhang } 1215222155deSJerry Zhang 121600a2430fSAndrzej Pietrasiewicz spin_lock_irq(&epfile->ffs->eps_lock); 1217222155deSJerry Zhang 1218222155deSJerry Zhang /* In the meantime, endpoint got disabled or changed. */ 1219222155deSJerry Zhang if (epfile->ep != ep) { 1220222155deSJerry Zhang spin_unlock_irq(&epfile->ffs->eps_lock); 1221222155deSJerry Zhang return -ESHUTDOWN; 1222222155deSJerry Zhang } 1223222155deSJerry Zhang 122400a2430fSAndrzej Pietrasiewicz switch (code) { 122500a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_FIFO_STATUS: 122600a2430fSAndrzej Pietrasiewicz ret = usb_ep_fifo_status(epfile->ep->ep); 122700a2430fSAndrzej Pietrasiewicz break; 122800a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_FIFO_FLUSH: 122900a2430fSAndrzej Pietrasiewicz usb_ep_fifo_flush(epfile->ep->ep); 123000a2430fSAndrzej Pietrasiewicz ret = 0; 123100a2430fSAndrzej Pietrasiewicz break; 123200a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_CLEAR_HALT: 123300a2430fSAndrzej Pietrasiewicz ret = usb_ep_clear_halt(epfile->ep->ep); 123400a2430fSAndrzej Pietrasiewicz break; 123500a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_ENDPOINT_REVMAP: 123600a2430fSAndrzej Pietrasiewicz ret = epfile->ep->num; 123700a2430fSAndrzej Pietrasiewicz break; 1238c559a353SRobert Baldyga case FUNCTIONFS_ENDPOINT_DESC: 1239c559a353SRobert Baldyga { 1240c559a353SRobert Baldyga int desc_idx; 1241c559a353SRobert Baldyga struct usb_endpoint_descriptor *desc; 1242c559a353SRobert Baldyga 1243c559a353SRobert Baldyga switch (epfile->ffs->gadget->speed) { 1244c559a353SRobert Baldyga case USB_SPEED_SUPER: 1245c559a353SRobert Baldyga desc_idx = 2; 1246c559a353SRobert Baldyga break; 1247c559a353SRobert Baldyga case USB_SPEED_HIGH: 1248c559a353SRobert Baldyga desc_idx = 1; 1249c559a353SRobert Baldyga break; 1250c559a353SRobert Baldyga default: 1251c559a353SRobert Baldyga desc_idx = 0; 1252c559a353SRobert Baldyga } 1253c559a353SRobert Baldyga desc = epfile->ep->descs[desc_idx]; 1254c559a353SRobert Baldyga 1255c559a353SRobert Baldyga spin_unlock_irq(&epfile->ffs->eps_lock); 1256c40619bbSVincent Pelletier ret = copy_to_user((void __user *)value, desc, desc->bLength); 1257c559a353SRobert Baldyga if (ret) 1258c559a353SRobert Baldyga ret = -EFAULT; 1259c559a353SRobert Baldyga return ret; 1260c559a353SRobert Baldyga } 126100a2430fSAndrzej Pietrasiewicz default: 126200a2430fSAndrzej Pietrasiewicz ret = -ENOTTY; 126300a2430fSAndrzej Pietrasiewicz } 126400a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 126500a2430fSAndrzej Pietrasiewicz 126600a2430fSAndrzej Pietrasiewicz return ret; 126700a2430fSAndrzej Pietrasiewicz } 126800a2430fSAndrzej Pietrasiewicz 12696819e323SJerry Zhang #ifdef CONFIG_COMPAT 12706819e323SJerry Zhang static long ffs_epfile_compat_ioctl(struct file *file, unsigned code, 12716819e323SJerry Zhang unsigned long value) 12726819e323SJerry Zhang { 12736819e323SJerry Zhang return ffs_epfile_ioctl(file, code, value); 12746819e323SJerry Zhang } 12756819e323SJerry Zhang #endif 12766819e323SJerry Zhang 127700a2430fSAndrzej Pietrasiewicz static const struct file_operations ffs_epfile_operations = { 127800a2430fSAndrzej Pietrasiewicz .llseek = no_llseek, 127900a2430fSAndrzej Pietrasiewicz 128000a2430fSAndrzej Pietrasiewicz .open = ffs_epfile_open, 128170e60d91SAl Viro .write_iter = ffs_epfile_write_iter, 128270e60d91SAl Viro .read_iter = ffs_epfile_read_iter, 128300a2430fSAndrzej Pietrasiewicz .release = ffs_epfile_release, 128400a2430fSAndrzej Pietrasiewicz .unlocked_ioctl = ffs_epfile_ioctl, 12856819e323SJerry Zhang #ifdef CONFIG_COMPAT 12866819e323SJerry Zhang .compat_ioctl = ffs_epfile_compat_ioctl, 12876819e323SJerry Zhang #endif 128800a2430fSAndrzej Pietrasiewicz }; 128900a2430fSAndrzej Pietrasiewicz 129000a2430fSAndrzej Pietrasiewicz 129100a2430fSAndrzej Pietrasiewicz /* File system and super block operations ***********************************/ 129200a2430fSAndrzej Pietrasiewicz 129300a2430fSAndrzej Pietrasiewicz /* 129400a2430fSAndrzej Pietrasiewicz * Mounting the file system creates a controller file, used first for 129500a2430fSAndrzej Pietrasiewicz * function configuration then later for event monitoring. 129600a2430fSAndrzej Pietrasiewicz */ 129700a2430fSAndrzej Pietrasiewicz 129800a2430fSAndrzej Pietrasiewicz static struct inode *__must_check 129900a2430fSAndrzej Pietrasiewicz ffs_sb_make_inode(struct super_block *sb, void *data, 130000a2430fSAndrzej Pietrasiewicz const struct file_operations *fops, 130100a2430fSAndrzej Pietrasiewicz const struct inode_operations *iops, 130200a2430fSAndrzej Pietrasiewicz struct ffs_file_perms *perms) 130300a2430fSAndrzej Pietrasiewicz { 130400a2430fSAndrzej Pietrasiewicz struct inode *inode; 130500a2430fSAndrzej Pietrasiewicz 130600a2430fSAndrzej Pietrasiewicz ENTER(); 130700a2430fSAndrzej Pietrasiewicz 130800a2430fSAndrzej Pietrasiewicz inode = new_inode(sb); 130900a2430fSAndrzej Pietrasiewicz 131000a2430fSAndrzej Pietrasiewicz if (likely(inode)) { 1311078cd827SDeepa Dinamani struct timespec ts = current_time(inode); 131200a2430fSAndrzej Pietrasiewicz 131300a2430fSAndrzej Pietrasiewicz inode->i_ino = get_next_ino(); 131400a2430fSAndrzej Pietrasiewicz inode->i_mode = perms->mode; 131500a2430fSAndrzej Pietrasiewicz inode->i_uid = perms->uid; 131600a2430fSAndrzej Pietrasiewicz inode->i_gid = perms->gid; 1317078cd827SDeepa Dinamani inode->i_atime = ts; 1318078cd827SDeepa Dinamani inode->i_mtime = ts; 1319078cd827SDeepa Dinamani inode->i_ctime = ts; 132000a2430fSAndrzej Pietrasiewicz inode->i_private = data; 132100a2430fSAndrzej Pietrasiewicz if (fops) 132200a2430fSAndrzej Pietrasiewicz inode->i_fop = fops; 132300a2430fSAndrzej Pietrasiewicz if (iops) 132400a2430fSAndrzej Pietrasiewicz inode->i_op = iops; 132500a2430fSAndrzej Pietrasiewicz } 132600a2430fSAndrzej Pietrasiewicz 132700a2430fSAndrzej Pietrasiewicz return inode; 132800a2430fSAndrzej Pietrasiewicz } 132900a2430fSAndrzej Pietrasiewicz 133000a2430fSAndrzej Pietrasiewicz /* Create "regular" file */ 13311bb27cacSAl Viro static struct dentry *ffs_sb_create_file(struct super_block *sb, 133200a2430fSAndrzej Pietrasiewicz const char *name, void *data, 13331bb27cacSAl Viro const struct file_operations *fops) 133400a2430fSAndrzej Pietrasiewicz { 133500a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = sb->s_fs_info; 133600a2430fSAndrzej Pietrasiewicz struct dentry *dentry; 133700a2430fSAndrzej Pietrasiewicz struct inode *inode; 133800a2430fSAndrzej Pietrasiewicz 133900a2430fSAndrzej Pietrasiewicz ENTER(); 134000a2430fSAndrzej Pietrasiewicz 134100a2430fSAndrzej Pietrasiewicz dentry = d_alloc_name(sb->s_root, name); 134200a2430fSAndrzej Pietrasiewicz if (unlikely(!dentry)) 134300a2430fSAndrzej Pietrasiewicz return NULL; 134400a2430fSAndrzej Pietrasiewicz 134500a2430fSAndrzej Pietrasiewicz inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms); 134600a2430fSAndrzej Pietrasiewicz if (unlikely(!inode)) { 134700a2430fSAndrzej Pietrasiewicz dput(dentry); 134800a2430fSAndrzej Pietrasiewicz return NULL; 134900a2430fSAndrzej Pietrasiewicz } 135000a2430fSAndrzej Pietrasiewicz 135100a2430fSAndrzej Pietrasiewicz d_add(dentry, inode); 13521bb27cacSAl Viro return dentry; 135300a2430fSAndrzej Pietrasiewicz } 135400a2430fSAndrzej Pietrasiewicz 135500a2430fSAndrzej Pietrasiewicz /* Super block */ 135600a2430fSAndrzej Pietrasiewicz static const struct super_operations ffs_sb_operations = { 135700a2430fSAndrzej Pietrasiewicz .statfs = simple_statfs, 135800a2430fSAndrzej Pietrasiewicz .drop_inode = generic_delete_inode, 135900a2430fSAndrzej Pietrasiewicz }; 136000a2430fSAndrzej Pietrasiewicz 136100a2430fSAndrzej Pietrasiewicz struct ffs_sb_fill_data { 136200a2430fSAndrzej Pietrasiewicz struct ffs_file_perms perms; 136300a2430fSAndrzej Pietrasiewicz umode_t root_mode; 136400a2430fSAndrzej Pietrasiewicz const char *dev_name; 136518d6b32fSRobert Baldyga bool no_disconnect; 136600a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs_data; 136700a2430fSAndrzej Pietrasiewicz }; 136800a2430fSAndrzej Pietrasiewicz 136900a2430fSAndrzej Pietrasiewicz static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) 137000a2430fSAndrzej Pietrasiewicz { 137100a2430fSAndrzej Pietrasiewicz struct ffs_sb_fill_data *data = _data; 137200a2430fSAndrzej Pietrasiewicz struct inode *inode; 137300a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = data->ffs_data; 137400a2430fSAndrzej Pietrasiewicz 137500a2430fSAndrzej Pietrasiewicz ENTER(); 137600a2430fSAndrzej Pietrasiewicz 137700a2430fSAndrzej Pietrasiewicz ffs->sb = sb; 137800a2430fSAndrzej Pietrasiewicz data->ffs_data = NULL; 137900a2430fSAndrzej Pietrasiewicz sb->s_fs_info = ffs; 138009cbfeafSKirill A. Shutemov sb->s_blocksize = PAGE_SIZE; 138109cbfeafSKirill A. Shutemov sb->s_blocksize_bits = PAGE_SHIFT; 138200a2430fSAndrzej Pietrasiewicz sb->s_magic = FUNCTIONFS_MAGIC; 138300a2430fSAndrzej Pietrasiewicz sb->s_op = &ffs_sb_operations; 138400a2430fSAndrzej Pietrasiewicz sb->s_time_gran = 1; 138500a2430fSAndrzej Pietrasiewicz 138600a2430fSAndrzej Pietrasiewicz /* Root inode */ 138700a2430fSAndrzej Pietrasiewicz data->perms.mode = data->root_mode; 138800a2430fSAndrzej Pietrasiewicz inode = ffs_sb_make_inode(sb, NULL, 138900a2430fSAndrzej Pietrasiewicz &simple_dir_operations, 139000a2430fSAndrzej Pietrasiewicz &simple_dir_inode_operations, 139100a2430fSAndrzej Pietrasiewicz &data->perms); 139200a2430fSAndrzej Pietrasiewicz sb->s_root = d_make_root(inode); 139300a2430fSAndrzej Pietrasiewicz if (unlikely(!sb->s_root)) 139400a2430fSAndrzej Pietrasiewicz return -ENOMEM; 139500a2430fSAndrzej Pietrasiewicz 139600a2430fSAndrzej Pietrasiewicz /* EP0 file */ 139700a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, 13981bb27cacSAl Viro &ffs_ep0_operations))) 139900a2430fSAndrzej Pietrasiewicz return -ENOMEM; 140000a2430fSAndrzej Pietrasiewicz 140100a2430fSAndrzej Pietrasiewicz return 0; 140200a2430fSAndrzej Pietrasiewicz } 140300a2430fSAndrzej Pietrasiewicz 140400a2430fSAndrzej Pietrasiewicz static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) 140500a2430fSAndrzej Pietrasiewicz { 140600a2430fSAndrzej Pietrasiewicz ENTER(); 140700a2430fSAndrzej Pietrasiewicz 140800a2430fSAndrzej Pietrasiewicz if (!opts || !*opts) 140900a2430fSAndrzej Pietrasiewicz return 0; 141000a2430fSAndrzej Pietrasiewicz 141100a2430fSAndrzej Pietrasiewicz for (;;) { 141200a2430fSAndrzej Pietrasiewicz unsigned long value; 141300a2430fSAndrzej Pietrasiewicz char *eq, *comma; 141400a2430fSAndrzej Pietrasiewicz 141500a2430fSAndrzej Pietrasiewicz /* Option limit */ 141600a2430fSAndrzej Pietrasiewicz comma = strchr(opts, ','); 141700a2430fSAndrzej Pietrasiewicz if (comma) 141800a2430fSAndrzej Pietrasiewicz *comma = 0; 141900a2430fSAndrzej Pietrasiewicz 142000a2430fSAndrzej Pietrasiewicz /* Value limit */ 142100a2430fSAndrzej Pietrasiewicz eq = strchr(opts, '='); 142200a2430fSAndrzej Pietrasiewicz if (unlikely(!eq)) { 142300a2430fSAndrzej Pietrasiewicz pr_err("'=' missing in %s\n", opts); 142400a2430fSAndrzej Pietrasiewicz return -EINVAL; 142500a2430fSAndrzej Pietrasiewicz } 142600a2430fSAndrzej Pietrasiewicz *eq = 0; 142700a2430fSAndrzej Pietrasiewicz 142800a2430fSAndrzej Pietrasiewicz /* Parse value */ 142900a2430fSAndrzej Pietrasiewicz if (kstrtoul(eq + 1, 0, &value)) { 143000a2430fSAndrzej Pietrasiewicz pr_err("%s: invalid value: %s\n", opts, eq + 1); 143100a2430fSAndrzej Pietrasiewicz return -EINVAL; 143200a2430fSAndrzej Pietrasiewicz } 143300a2430fSAndrzej Pietrasiewicz 143400a2430fSAndrzej Pietrasiewicz /* Interpret option */ 143500a2430fSAndrzej Pietrasiewicz switch (eq - opts) { 143618d6b32fSRobert Baldyga case 13: 143718d6b32fSRobert Baldyga if (!memcmp(opts, "no_disconnect", 13)) 143818d6b32fSRobert Baldyga data->no_disconnect = !!value; 143918d6b32fSRobert Baldyga else 144018d6b32fSRobert Baldyga goto invalid; 144118d6b32fSRobert Baldyga break; 144200a2430fSAndrzej Pietrasiewicz case 5: 144300a2430fSAndrzej Pietrasiewicz if (!memcmp(opts, "rmode", 5)) 144400a2430fSAndrzej Pietrasiewicz data->root_mode = (value & 0555) | S_IFDIR; 144500a2430fSAndrzej Pietrasiewicz else if (!memcmp(opts, "fmode", 5)) 144600a2430fSAndrzej Pietrasiewicz data->perms.mode = (value & 0666) | S_IFREG; 144700a2430fSAndrzej Pietrasiewicz else 144800a2430fSAndrzej Pietrasiewicz goto invalid; 144900a2430fSAndrzej Pietrasiewicz break; 145000a2430fSAndrzej Pietrasiewicz 145100a2430fSAndrzej Pietrasiewicz case 4: 145200a2430fSAndrzej Pietrasiewicz if (!memcmp(opts, "mode", 4)) { 145300a2430fSAndrzej Pietrasiewicz data->root_mode = (value & 0555) | S_IFDIR; 145400a2430fSAndrzej Pietrasiewicz data->perms.mode = (value & 0666) | S_IFREG; 145500a2430fSAndrzej Pietrasiewicz } else { 145600a2430fSAndrzej Pietrasiewicz goto invalid; 145700a2430fSAndrzej Pietrasiewicz } 145800a2430fSAndrzej Pietrasiewicz break; 145900a2430fSAndrzej Pietrasiewicz 146000a2430fSAndrzej Pietrasiewicz case 3: 146100a2430fSAndrzej Pietrasiewicz if (!memcmp(opts, "uid", 3)) { 146200a2430fSAndrzej Pietrasiewicz data->perms.uid = make_kuid(current_user_ns(), value); 146300a2430fSAndrzej Pietrasiewicz if (!uid_valid(data->perms.uid)) { 146400a2430fSAndrzej Pietrasiewicz pr_err("%s: unmapped value: %lu\n", opts, value); 146500a2430fSAndrzej Pietrasiewicz return -EINVAL; 146600a2430fSAndrzej Pietrasiewicz } 146700a2430fSAndrzej Pietrasiewicz } else if (!memcmp(opts, "gid", 3)) { 146800a2430fSAndrzej Pietrasiewicz data->perms.gid = make_kgid(current_user_ns(), value); 146900a2430fSAndrzej Pietrasiewicz if (!gid_valid(data->perms.gid)) { 147000a2430fSAndrzej Pietrasiewicz pr_err("%s: unmapped value: %lu\n", opts, value); 147100a2430fSAndrzej Pietrasiewicz return -EINVAL; 147200a2430fSAndrzej Pietrasiewicz } 147300a2430fSAndrzej Pietrasiewicz } else { 147400a2430fSAndrzej Pietrasiewicz goto invalid; 147500a2430fSAndrzej Pietrasiewicz } 147600a2430fSAndrzej Pietrasiewicz break; 147700a2430fSAndrzej Pietrasiewicz 147800a2430fSAndrzej Pietrasiewicz default: 147900a2430fSAndrzej Pietrasiewicz invalid: 148000a2430fSAndrzej Pietrasiewicz pr_err("%s: invalid option\n", opts); 148100a2430fSAndrzej Pietrasiewicz return -EINVAL; 148200a2430fSAndrzej Pietrasiewicz } 148300a2430fSAndrzej Pietrasiewicz 148400a2430fSAndrzej Pietrasiewicz /* Next iteration */ 148500a2430fSAndrzej Pietrasiewicz if (!comma) 148600a2430fSAndrzej Pietrasiewicz break; 148700a2430fSAndrzej Pietrasiewicz opts = comma + 1; 148800a2430fSAndrzej Pietrasiewicz } 148900a2430fSAndrzej Pietrasiewicz 149000a2430fSAndrzej Pietrasiewicz return 0; 149100a2430fSAndrzej Pietrasiewicz } 149200a2430fSAndrzej Pietrasiewicz 149300a2430fSAndrzej Pietrasiewicz /* "mount -t functionfs dev_name /dev/function" ends up here */ 149400a2430fSAndrzej Pietrasiewicz 149500a2430fSAndrzej Pietrasiewicz static struct dentry * 149600a2430fSAndrzej Pietrasiewicz ffs_fs_mount(struct file_system_type *t, int flags, 149700a2430fSAndrzej Pietrasiewicz const char *dev_name, void *opts) 149800a2430fSAndrzej Pietrasiewicz { 149900a2430fSAndrzej Pietrasiewicz struct ffs_sb_fill_data data = { 150000a2430fSAndrzej Pietrasiewicz .perms = { 150100a2430fSAndrzej Pietrasiewicz .mode = S_IFREG | 0600, 150200a2430fSAndrzej Pietrasiewicz .uid = GLOBAL_ROOT_UID, 150300a2430fSAndrzej Pietrasiewicz .gid = GLOBAL_ROOT_GID, 150400a2430fSAndrzej Pietrasiewicz }, 150500a2430fSAndrzej Pietrasiewicz .root_mode = S_IFDIR | 0500, 150618d6b32fSRobert Baldyga .no_disconnect = false, 150700a2430fSAndrzej Pietrasiewicz }; 150800a2430fSAndrzej Pietrasiewicz struct dentry *rv; 150900a2430fSAndrzej Pietrasiewicz int ret; 151000a2430fSAndrzej Pietrasiewicz void *ffs_dev; 151100a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs; 151200a2430fSAndrzej Pietrasiewicz 151300a2430fSAndrzej Pietrasiewicz ENTER(); 151400a2430fSAndrzej Pietrasiewicz 151500a2430fSAndrzej Pietrasiewicz ret = ffs_fs_parse_opts(&data, opts); 151600a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 151700a2430fSAndrzej Pietrasiewicz return ERR_PTR(ret); 151800a2430fSAndrzej Pietrasiewicz 1519addfc582SJohn Keeping ffs = ffs_data_new(dev_name); 152000a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs)) 152100a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 152200a2430fSAndrzej Pietrasiewicz ffs->file_perms = data.perms; 152318d6b32fSRobert Baldyga ffs->no_disconnect = data.no_disconnect; 152400a2430fSAndrzej Pietrasiewicz 152500a2430fSAndrzej Pietrasiewicz ffs->dev_name = kstrdup(dev_name, GFP_KERNEL); 152600a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs->dev_name)) { 152700a2430fSAndrzej Pietrasiewicz ffs_data_put(ffs); 152800a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 152900a2430fSAndrzej Pietrasiewicz } 153000a2430fSAndrzej Pietrasiewicz 153100a2430fSAndrzej Pietrasiewicz ffs_dev = ffs_acquire_dev(dev_name); 153200a2430fSAndrzej Pietrasiewicz if (IS_ERR(ffs_dev)) { 153300a2430fSAndrzej Pietrasiewicz ffs_data_put(ffs); 153400a2430fSAndrzej Pietrasiewicz return ERR_CAST(ffs_dev); 153500a2430fSAndrzej Pietrasiewicz } 153600a2430fSAndrzej Pietrasiewicz ffs->private_data = ffs_dev; 153700a2430fSAndrzej Pietrasiewicz data.ffs_data = ffs; 153800a2430fSAndrzej Pietrasiewicz 153900a2430fSAndrzej Pietrasiewicz rv = mount_nodev(t, flags, &data, ffs_sb_fill); 154000a2430fSAndrzej Pietrasiewicz if (IS_ERR(rv) && data.ffs_data) { 154100a2430fSAndrzej Pietrasiewicz ffs_release_dev(data.ffs_data); 154200a2430fSAndrzej Pietrasiewicz ffs_data_put(data.ffs_data); 154300a2430fSAndrzej Pietrasiewicz } 154400a2430fSAndrzej Pietrasiewicz return rv; 154500a2430fSAndrzej Pietrasiewicz } 154600a2430fSAndrzej Pietrasiewicz 154700a2430fSAndrzej Pietrasiewicz static void 154800a2430fSAndrzej Pietrasiewicz ffs_fs_kill_sb(struct super_block *sb) 154900a2430fSAndrzej Pietrasiewicz { 155000a2430fSAndrzej Pietrasiewicz ENTER(); 155100a2430fSAndrzej Pietrasiewicz 155200a2430fSAndrzej Pietrasiewicz kill_litter_super(sb); 155300a2430fSAndrzej Pietrasiewicz if (sb->s_fs_info) { 155400a2430fSAndrzej Pietrasiewicz ffs_release_dev(sb->s_fs_info); 155518d6b32fSRobert Baldyga ffs_data_closed(sb->s_fs_info); 155600a2430fSAndrzej Pietrasiewicz } 155700a2430fSAndrzej Pietrasiewicz } 155800a2430fSAndrzej Pietrasiewicz 155900a2430fSAndrzej Pietrasiewicz static struct file_system_type ffs_fs_type = { 156000a2430fSAndrzej Pietrasiewicz .owner = THIS_MODULE, 156100a2430fSAndrzej Pietrasiewicz .name = "functionfs", 156200a2430fSAndrzej Pietrasiewicz .mount = ffs_fs_mount, 156300a2430fSAndrzej Pietrasiewicz .kill_sb = ffs_fs_kill_sb, 156400a2430fSAndrzej Pietrasiewicz }; 156500a2430fSAndrzej Pietrasiewicz MODULE_ALIAS_FS("functionfs"); 156600a2430fSAndrzej Pietrasiewicz 156700a2430fSAndrzej Pietrasiewicz 156800a2430fSAndrzej Pietrasiewicz /* Driver's main init/cleanup functions *************************************/ 156900a2430fSAndrzej Pietrasiewicz 157000a2430fSAndrzej Pietrasiewicz static int functionfs_init(void) 157100a2430fSAndrzej Pietrasiewicz { 157200a2430fSAndrzej Pietrasiewicz int ret; 157300a2430fSAndrzej Pietrasiewicz 157400a2430fSAndrzej Pietrasiewicz ENTER(); 157500a2430fSAndrzej Pietrasiewicz 157600a2430fSAndrzej Pietrasiewicz ret = register_filesystem(&ffs_fs_type); 157700a2430fSAndrzej Pietrasiewicz if (likely(!ret)) 157800a2430fSAndrzej Pietrasiewicz pr_info("file system registered\n"); 157900a2430fSAndrzej Pietrasiewicz else 158000a2430fSAndrzej Pietrasiewicz pr_err("failed registering file system (%d)\n", ret); 158100a2430fSAndrzej Pietrasiewicz 158200a2430fSAndrzej Pietrasiewicz return ret; 158300a2430fSAndrzej Pietrasiewicz } 158400a2430fSAndrzej Pietrasiewicz 158500a2430fSAndrzej Pietrasiewicz static void functionfs_cleanup(void) 158600a2430fSAndrzej Pietrasiewicz { 158700a2430fSAndrzej Pietrasiewicz ENTER(); 158800a2430fSAndrzej Pietrasiewicz 158900a2430fSAndrzej Pietrasiewicz pr_info("unloading\n"); 159000a2430fSAndrzej Pietrasiewicz unregister_filesystem(&ffs_fs_type); 159100a2430fSAndrzej Pietrasiewicz } 159200a2430fSAndrzej Pietrasiewicz 159300a2430fSAndrzej Pietrasiewicz 159400a2430fSAndrzej Pietrasiewicz /* ffs_data and ffs_function construction and destruction code **************/ 159500a2430fSAndrzej Pietrasiewicz 159600a2430fSAndrzej Pietrasiewicz static void ffs_data_clear(struct ffs_data *ffs); 159700a2430fSAndrzej Pietrasiewicz static void ffs_data_reset(struct ffs_data *ffs); 159800a2430fSAndrzej Pietrasiewicz 159900a2430fSAndrzej Pietrasiewicz static void ffs_data_get(struct ffs_data *ffs) 160000a2430fSAndrzej Pietrasiewicz { 160100a2430fSAndrzej Pietrasiewicz ENTER(); 160200a2430fSAndrzej Pietrasiewicz 160343938613SElena Reshetova refcount_inc(&ffs->ref); 160400a2430fSAndrzej Pietrasiewicz } 160500a2430fSAndrzej Pietrasiewicz 160600a2430fSAndrzej Pietrasiewicz static void ffs_data_opened(struct ffs_data *ffs) 160700a2430fSAndrzej Pietrasiewicz { 160800a2430fSAndrzej Pietrasiewicz ENTER(); 160900a2430fSAndrzej Pietrasiewicz 161043938613SElena Reshetova refcount_inc(&ffs->ref); 161118d6b32fSRobert Baldyga if (atomic_add_return(1, &ffs->opened) == 1 && 161218d6b32fSRobert Baldyga ffs->state == FFS_DEACTIVATED) { 161318d6b32fSRobert Baldyga ffs->state = FFS_CLOSING; 161418d6b32fSRobert Baldyga ffs_data_reset(ffs); 161518d6b32fSRobert Baldyga } 161600a2430fSAndrzej Pietrasiewicz } 161700a2430fSAndrzej Pietrasiewicz 161800a2430fSAndrzej Pietrasiewicz static void ffs_data_put(struct ffs_data *ffs) 161900a2430fSAndrzej Pietrasiewicz { 162000a2430fSAndrzej Pietrasiewicz ENTER(); 162100a2430fSAndrzej Pietrasiewicz 162243938613SElena Reshetova if (unlikely(refcount_dec_and_test(&ffs->ref))) { 162300a2430fSAndrzej Pietrasiewicz pr_info("%s(): freeing\n", __func__); 162400a2430fSAndrzej Pietrasiewicz ffs_data_clear(ffs); 162500a2430fSAndrzej Pietrasiewicz BUG_ON(waitqueue_active(&ffs->ev.waitq) || 1626e16828cfSJerry Zhang waitqueue_active(&ffs->ep0req_completion.wait) || 1627e16828cfSJerry Zhang waitqueue_active(&ffs->wait)); 1628addfc582SJohn Keeping destroy_workqueue(ffs->io_completion_wq); 162900a2430fSAndrzej Pietrasiewicz kfree(ffs->dev_name); 163000a2430fSAndrzej Pietrasiewicz kfree(ffs); 163100a2430fSAndrzej Pietrasiewicz } 163200a2430fSAndrzej Pietrasiewicz } 163300a2430fSAndrzej Pietrasiewicz 163400a2430fSAndrzej Pietrasiewicz static void ffs_data_closed(struct ffs_data *ffs) 163500a2430fSAndrzej Pietrasiewicz { 163600a2430fSAndrzej Pietrasiewicz ENTER(); 163700a2430fSAndrzej Pietrasiewicz 163800a2430fSAndrzej Pietrasiewicz if (atomic_dec_and_test(&ffs->opened)) { 163918d6b32fSRobert Baldyga if (ffs->no_disconnect) { 164018d6b32fSRobert Baldyga ffs->state = FFS_DEACTIVATED; 164118d6b32fSRobert Baldyga if (ffs->epfiles) { 164218d6b32fSRobert Baldyga ffs_epfiles_destroy(ffs->epfiles, 164318d6b32fSRobert Baldyga ffs->eps_count); 164418d6b32fSRobert Baldyga ffs->epfiles = NULL; 164518d6b32fSRobert Baldyga } 164618d6b32fSRobert Baldyga if (ffs->setup_state == FFS_SETUP_PENDING) 164718d6b32fSRobert Baldyga __ffs_ep0_stall(ffs); 164818d6b32fSRobert Baldyga } else { 164918d6b32fSRobert Baldyga ffs->state = FFS_CLOSING; 165018d6b32fSRobert Baldyga ffs_data_reset(ffs); 165118d6b32fSRobert Baldyga } 165218d6b32fSRobert Baldyga } 165318d6b32fSRobert Baldyga if (atomic_read(&ffs->opened) < 0) { 165400a2430fSAndrzej Pietrasiewicz ffs->state = FFS_CLOSING; 165500a2430fSAndrzej Pietrasiewicz ffs_data_reset(ffs); 165600a2430fSAndrzej Pietrasiewicz } 165700a2430fSAndrzej Pietrasiewicz 165800a2430fSAndrzej Pietrasiewicz ffs_data_put(ffs); 165900a2430fSAndrzej Pietrasiewicz } 166000a2430fSAndrzej Pietrasiewicz 1661addfc582SJohn Keeping static struct ffs_data *ffs_data_new(const char *dev_name) 166200a2430fSAndrzej Pietrasiewicz { 166300a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL); 166400a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs)) 166500a2430fSAndrzej Pietrasiewicz return NULL; 166600a2430fSAndrzej Pietrasiewicz 166700a2430fSAndrzej Pietrasiewicz ENTER(); 166800a2430fSAndrzej Pietrasiewicz 1669addfc582SJohn Keeping ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name); 1670addfc582SJohn Keeping if (!ffs->io_completion_wq) { 1671addfc582SJohn Keeping kfree(ffs); 1672addfc582SJohn Keeping return NULL; 1673addfc582SJohn Keeping } 1674addfc582SJohn Keeping 167543938613SElena Reshetova refcount_set(&ffs->ref, 1); 167600a2430fSAndrzej Pietrasiewicz atomic_set(&ffs->opened, 0); 167700a2430fSAndrzej Pietrasiewicz ffs->state = FFS_READ_DESCRIPTORS; 167800a2430fSAndrzej Pietrasiewicz mutex_init(&ffs->mutex); 167900a2430fSAndrzej Pietrasiewicz spin_lock_init(&ffs->eps_lock); 168000a2430fSAndrzej Pietrasiewicz init_waitqueue_head(&ffs->ev.waitq); 1681e16828cfSJerry Zhang init_waitqueue_head(&ffs->wait); 168200a2430fSAndrzej Pietrasiewicz init_completion(&ffs->ep0req_completion); 168300a2430fSAndrzej Pietrasiewicz 168400a2430fSAndrzej Pietrasiewicz /* XXX REVISIT need to update it in some places, or do we? */ 168500a2430fSAndrzej Pietrasiewicz ffs->ev.can_stall = 1; 168600a2430fSAndrzej Pietrasiewicz 168700a2430fSAndrzej Pietrasiewicz return ffs; 168800a2430fSAndrzej Pietrasiewicz } 168900a2430fSAndrzej Pietrasiewicz 169000a2430fSAndrzej Pietrasiewicz static void ffs_data_clear(struct ffs_data *ffs) 169100a2430fSAndrzej Pietrasiewicz { 169200a2430fSAndrzej Pietrasiewicz ENTER(); 169300a2430fSAndrzej Pietrasiewicz 169400a2430fSAndrzej Pietrasiewicz ffs_closed(ffs); 169500a2430fSAndrzej Pietrasiewicz 169600a2430fSAndrzej Pietrasiewicz BUG_ON(ffs->gadget); 169700a2430fSAndrzej Pietrasiewicz 169800a2430fSAndrzej Pietrasiewicz if (ffs->epfiles) 169900a2430fSAndrzej Pietrasiewicz ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); 170000a2430fSAndrzej Pietrasiewicz 17015e33f6fdSRobert Baldyga if (ffs->ffs_eventfd) 17025e33f6fdSRobert Baldyga eventfd_ctx_put(ffs->ffs_eventfd); 17035e33f6fdSRobert Baldyga 170400a2430fSAndrzej Pietrasiewicz kfree(ffs->raw_descs_data); 170500a2430fSAndrzej Pietrasiewicz kfree(ffs->raw_strings); 170600a2430fSAndrzej Pietrasiewicz kfree(ffs->stringtabs); 170700a2430fSAndrzej Pietrasiewicz } 170800a2430fSAndrzej Pietrasiewicz 170900a2430fSAndrzej Pietrasiewicz static void ffs_data_reset(struct ffs_data *ffs) 171000a2430fSAndrzej Pietrasiewicz { 171100a2430fSAndrzej Pietrasiewicz ENTER(); 171200a2430fSAndrzej Pietrasiewicz 171300a2430fSAndrzej Pietrasiewicz ffs_data_clear(ffs); 171400a2430fSAndrzej Pietrasiewicz 171500a2430fSAndrzej Pietrasiewicz ffs->epfiles = NULL; 171600a2430fSAndrzej Pietrasiewicz ffs->raw_descs_data = NULL; 171700a2430fSAndrzej Pietrasiewicz ffs->raw_descs = NULL; 171800a2430fSAndrzej Pietrasiewicz ffs->raw_strings = NULL; 171900a2430fSAndrzej Pietrasiewicz ffs->stringtabs = NULL; 172000a2430fSAndrzej Pietrasiewicz 172100a2430fSAndrzej Pietrasiewicz ffs->raw_descs_length = 0; 172200a2430fSAndrzej Pietrasiewicz ffs->fs_descs_count = 0; 172300a2430fSAndrzej Pietrasiewicz ffs->hs_descs_count = 0; 172400a2430fSAndrzej Pietrasiewicz ffs->ss_descs_count = 0; 172500a2430fSAndrzej Pietrasiewicz 172600a2430fSAndrzej Pietrasiewicz ffs->strings_count = 0; 172700a2430fSAndrzej Pietrasiewicz ffs->interfaces_count = 0; 172800a2430fSAndrzej Pietrasiewicz ffs->eps_count = 0; 172900a2430fSAndrzej Pietrasiewicz 173000a2430fSAndrzej Pietrasiewicz ffs->ev.count = 0; 173100a2430fSAndrzej Pietrasiewicz 173200a2430fSAndrzej Pietrasiewicz ffs->state = FFS_READ_DESCRIPTORS; 173300a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_NO_SETUP; 173400a2430fSAndrzej Pietrasiewicz ffs->flags = 0; 173500a2430fSAndrzej Pietrasiewicz } 173600a2430fSAndrzej Pietrasiewicz 173700a2430fSAndrzej Pietrasiewicz 173800a2430fSAndrzej Pietrasiewicz static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) 173900a2430fSAndrzej Pietrasiewicz { 174000a2430fSAndrzej Pietrasiewicz struct usb_gadget_strings **lang; 174100a2430fSAndrzej Pietrasiewicz int first_id; 174200a2430fSAndrzej Pietrasiewicz 174300a2430fSAndrzej Pietrasiewicz ENTER(); 174400a2430fSAndrzej Pietrasiewicz 174500a2430fSAndrzej Pietrasiewicz if (WARN_ON(ffs->state != FFS_ACTIVE 174600a2430fSAndrzej Pietrasiewicz || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) 174700a2430fSAndrzej Pietrasiewicz return -EBADFD; 174800a2430fSAndrzej Pietrasiewicz 174900a2430fSAndrzej Pietrasiewicz first_id = usb_string_ids_n(cdev, ffs->strings_count); 175000a2430fSAndrzej Pietrasiewicz if (unlikely(first_id < 0)) 175100a2430fSAndrzej Pietrasiewicz return first_id; 175200a2430fSAndrzej Pietrasiewicz 175300a2430fSAndrzej Pietrasiewicz ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); 175400a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs->ep0req)) 175500a2430fSAndrzej Pietrasiewicz return -ENOMEM; 175600a2430fSAndrzej Pietrasiewicz ffs->ep0req->complete = ffs_ep0_complete; 175700a2430fSAndrzej Pietrasiewicz ffs->ep0req->context = ffs; 175800a2430fSAndrzej Pietrasiewicz 175900a2430fSAndrzej Pietrasiewicz lang = ffs->stringtabs; 176061fe2d75SGreg Kroah-Hartman if (lang) { 176161fe2d75SGreg Kroah-Hartman for (; *lang; ++lang) { 176200a2430fSAndrzej Pietrasiewicz struct usb_string *str = (*lang)->strings; 176300a2430fSAndrzej Pietrasiewicz int id = first_id; 176400a2430fSAndrzej Pietrasiewicz for (; str->s; ++id, ++str) 176500a2430fSAndrzej Pietrasiewicz str->id = id; 176600a2430fSAndrzej Pietrasiewicz } 176761fe2d75SGreg Kroah-Hartman } 176800a2430fSAndrzej Pietrasiewicz 176900a2430fSAndrzej Pietrasiewicz ffs->gadget = cdev->gadget; 177000a2430fSAndrzej Pietrasiewicz ffs_data_get(ffs); 177100a2430fSAndrzej Pietrasiewicz return 0; 177200a2430fSAndrzej Pietrasiewicz } 177300a2430fSAndrzej Pietrasiewicz 177400a2430fSAndrzej Pietrasiewicz static void functionfs_unbind(struct ffs_data *ffs) 177500a2430fSAndrzej Pietrasiewicz { 177600a2430fSAndrzej Pietrasiewicz ENTER(); 177700a2430fSAndrzej Pietrasiewicz 177800a2430fSAndrzej Pietrasiewicz if (!WARN_ON(!ffs->gadget)) { 177900a2430fSAndrzej Pietrasiewicz usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req); 178000a2430fSAndrzej Pietrasiewicz ffs->ep0req = NULL; 178100a2430fSAndrzej Pietrasiewicz ffs->gadget = NULL; 178200a2430fSAndrzej Pietrasiewicz clear_bit(FFS_FL_BOUND, &ffs->flags); 178300a2430fSAndrzej Pietrasiewicz ffs_data_put(ffs); 178400a2430fSAndrzej Pietrasiewicz } 178500a2430fSAndrzej Pietrasiewicz } 178600a2430fSAndrzej Pietrasiewicz 178700a2430fSAndrzej Pietrasiewicz static int ffs_epfiles_create(struct ffs_data *ffs) 178800a2430fSAndrzej Pietrasiewicz { 178900a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile, *epfiles; 179000a2430fSAndrzej Pietrasiewicz unsigned i, count; 179100a2430fSAndrzej Pietrasiewicz 179200a2430fSAndrzej Pietrasiewicz ENTER(); 179300a2430fSAndrzej Pietrasiewicz 179400a2430fSAndrzej Pietrasiewicz count = ffs->eps_count; 179500a2430fSAndrzej Pietrasiewicz epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); 179600a2430fSAndrzej Pietrasiewicz if (!epfiles) 179700a2430fSAndrzej Pietrasiewicz return -ENOMEM; 179800a2430fSAndrzej Pietrasiewicz 179900a2430fSAndrzej Pietrasiewicz epfile = epfiles; 180000a2430fSAndrzej Pietrasiewicz for (i = 1; i <= count; ++i, ++epfile) { 180100a2430fSAndrzej Pietrasiewicz epfile->ffs = ffs; 180200a2430fSAndrzej Pietrasiewicz mutex_init(&epfile->mutex); 18031b0bf88fSRobert Baldyga if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) 1804acba23feSMario Schuknecht sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]); 18051b0bf88fSRobert Baldyga else 1806acba23feSMario Schuknecht sprintf(epfile->name, "ep%u", i); 1807acba23feSMario Schuknecht epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name, 18081bb27cacSAl Viro epfile, 18091bb27cacSAl Viro &ffs_epfile_operations); 18101bb27cacSAl Viro if (unlikely(!epfile->dentry)) { 181100a2430fSAndrzej Pietrasiewicz ffs_epfiles_destroy(epfiles, i - 1); 181200a2430fSAndrzej Pietrasiewicz return -ENOMEM; 181300a2430fSAndrzej Pietrasiewicz } 181400a2430fSAndrzej Pietrasiewicz } 181500a2430fSAndrzej Pietrasiewicz 181600a2430fSAndrzej Pietrasiewicz ffs->epfiles = epfiles; 181700a2430fSAndrzej Pietrasiewicz return 0; 181800a2430fSAndrzej Pietrasiewicz } 181900a2430fSAndrzej Pietrasiewicz 182000a2430fSAndrzej Pietrasiewicz static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) 182100a2430fSAndrzej Pietrasiewicz { 182200a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = epfiles; 182300a2430fSAndrzej Pietrasiewicz 182400a2430fSAndrzej Pietrasiewicz ENTER(); 182500a2430fSAndrzej Pietrasiewicz 182600a2430fSAndrzej Pietrasiewicz for (; count; --count, ++epfile) { 1827e16828cfSJerry Zhang BUG_ON(mutex_is_locked(&epfile->mutex)); 182800a2430fSAndrzej Pietrasiewicz if (epfile->dentry) { 182900a2430fSAndrzej Pietrasiewicz d_delete(epfile->dentry); 183000a2430fSAndrzej Pietrasiewicz dput(epfile->dentry); 183100a2430fSAndrzej Pietrasiewicz epfile->dentry = NULL; 183200a2430fSAndrzej Pietrasiewicz } 183300a2430fSAndrzej Pietrasiewicz } 183400a2430fSAndrzej Pietrasiewicz 183500a2430fSAndrzej Pietrasiewicz kfree(epfiles); 183600a2430fSAndrzej Pietrasiewicz } 183700a2430fSAndrzej Pietrasiewicz 183800a2430fSAndrzej Pietrasiewicz static void ffs_func_eps_disable(struct ffs_function *func) 183900a2430fSAndrzej Pietrasiewicz { 184000a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep = func->eps; 184100a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = func->ffs->epfiles; 184200a2430fSAndrzej Pietrasiewicz unsigned count = func->ffs->eps_count; 184300a2430fSAndrzej Pietrasiewicz unsigned long flags; 184400a2430fSAndrzej Pietrasiewicz 18459353afbbSMichal Nazarewicz spin_lock_irqsave(&func->ffs->eps_lock, flags); 184608f37148SVincent Pelletier while (count--) { 184700a2430fSAndrzej Pietrasiewicz /* pending requests get nuked */ 184800a2430fSAndrzej Pietrasiewicz if (likely(ep->ep)) 184900a2430fSAndrzej Pietrasiewicz usb_ep_disable(ep->ep); 185000a2430fSAndrzej Pietrasiewicz ++ep; 185118d6b32fSRobert Baldyga 185218d6b32fSRobert Baldyga if (epfile) { 1853a9e6f83cSMichal Nazarewicz epfile->ep = NULL; 1854a9e6f83cSMichal Nazarewicz __ffs_epfile_read_buffer_free(epfile); 185500a2430fSAndrzej Pietrasiewicz ++epfile; 185618d6b32fSRobert Baldyga } 185708f37148SVincent Pelletier } 1858a9e6f83cSMichal Nazarewicz spin_unlock_irqrestore(&func->ffs->eps_lock, flags); 185900a2430fSAndrzej Pietrasiewicz } 186000a2430fSAndrzej Pietrasiewicz 186100a2430fSAndrzej Pietrasiewicz static int ffs_func_eps_enable(struct ffs_function *func) 186200a2430fSAndrzej Pietrasiewicz { 186300a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 186400a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep = func->eps; 186500a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = ffs->epfiles; 186600a2430fSAndrzej Pietrasiewicz unsigned count = ffs->eps_count; 186700a2430fSAndrzej Pietrasiewicz unsigned long flags; 186800a2430fSAndrzej Pietrasiewicz int ret = 0; 186900a2430fSAndrzej Pietrasiewicz 187000a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&func->ffs->eps_lock, flags); 187108f37148SVincent Pelletier while(count--) { 187200a2430fSAndrzej Pietrasiewicz ep->ep->driver_data = ep; 18732bfa0719SFelipe Balbi 1874675272d0SJack Pham ret = config_ep_by_speed(func->gadget, &func->function, ep->ep); 1875675272d0SJack Pham if (ret) { 1876675272d0SJack Pham pr_err("%s: config_ep_by_speed(%s) returned %d\n", 1877675272d0SJack Pham __func__, ep->ep->name, ret); 1878675272d0SJack Pham break; 1879b7f73850SWilliam Wu } 18802bfa0719SFelipe Balbi 188100a2430fSAndrzej Pietrasiewicz ret = usb_ep_enable(ep->ep); 188200a2430fSAndrzej Pietrasiewicz if (likely(!ret)) { 188300a2430fSAndrzej Pietrasiewicz epfile->ep = ep; 1884675272d0SJack Pham epfile->in = usb_endpoint_dir_in(ep->ep->desc); 1885675272d0SJack Pham epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc); 188600a2430fSAndrzej Pietrasiewicz } else { 188700a2430fSAndrzej Pietrasiewicz break; 188800a2430fSAndrzej Pietrasiewicz } 188900a2430fSAndrzej Pietrasiewicz 189000a2430fSAndrzej Pietrasiewicz ++ep; 189100a2430fSAndrzej Pietrasiewicz ++epfile; 189208f37148SVincent Pelletier } 1893e16828cfSJerry Zhang 1894e16828cfSJerry Zhang wake_up_interruptible(&ffs->wait); 189500a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&func->ffs->eps_lock, flags); 189600a2430fSAndrzej Pietrasiewicz 189700a2430fSAndrzej Pietrasiewicz return ret; 189800a2430fSAndrzej Pietrasiewicz } 189900a2430fSAndrzej Pietrasiewicz 190000a2430fSAndrzej Pietrasiewicz 190100a2430fSAndrzej Pietrasiewicz /* Parsing and building descriptors and strings *****************************/ 190200a2430fSAndrzej Pietrasiewicz 190300a2430fSAndrzej Pietrasiewicz /* 190400a2430fSAndrzej Pietrasiewicz * This validates if data pointed by data is a valid USB descriptor as 190500a2430fSAndrzej Pietrasiewicz * well as record how many interfaces, endpoints and strings are 190600a2430fSAndrzej Pietrasiewicz * required by given configuration. Returns address after the 190700a2430fSAndrzej Pietrasiewicz * descriptor or NULL if data is invalid. 190800a2430fSAndrzej Pietrasiewicz */ 190900a2430fSAndrzej Pietrasiewicz 191000a2430fSAndrzej Pietrasiewicz enum ffs_entity_type { 191100a2430fSAndrzej Pietrasiewicz FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT 191200a2430fSAndrzej Pietrasiewicz }; 191300a2430fSAndrzej Pietrasiewicz 191400a2430fSAndrzej Pietrasiewicz enum ffs_os_desc_type { 191500a2430fSAndrzej Pietrasiewicz FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP 191600a2430fSAndrzej Pietrasiewicz }; 191700a2430fSAndrzej Pietrasiewicz 191800a2430fSAndrzej Pietrasiewicz typedef int (*ffs_entity_callback)(enum ffs_entity_type entity, 191900a2430fSAndrzej Pietrasiewicz u8 *valuep, 192000a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *desc, 192100a2430fSAndrzej Pietrasiewicz void *priv); 192200a2430fSAndrzej Pietrasiewicz 192300a2430fSAndrzej Pietrasiewicz typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity, 192400a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *h, void *data, 192500a2430fSAndrzej Pietrasiewicz unsigned len, void *priv); 192600a2430fSAndrzej Pietrasiewicz 192700a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_single_desc(char *data, unsigned len, 192800a2430fSAndrzej Pietrasiewicz ffs_entity_callback entity, 192900a2430fSAndrzej Pietrasiewicz void *priv) 193000a2430fSAndrzej Pietrasiewicz { 193100a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *_ds = (void *)data; 193200a2430fSAndrzej Pietrasiewicz u8 length; 193300a2430fSAndrzej Pietrasiewicz int ret; 193400a2430fSAndrzej Pietrasiewicz 193500a2430fSAndrzej Pietrasiewicz ENTER(); 193600a2430fSAndrzej Pietrasiewicz 193700a2430fSAndrzej Pietrasiewicz /* At least two bytes are required: length and type */ 193800a2430fSAndrzej Pietrasiewicz if (len < 2) { 193900a2430fSAndrzej Pietrasiewicz pr_vdebug("descriptor too short\n"); 194000a2430fSAndrzej Pietrasiewicz return -EINVAL; 194100a2430fSAndrzej Pietrasiewicz } 194200a2430fSAndrzej Pietrasiewicz 194300a2430fSAndrzej Pietrasiewicz /* If we have at least as many bytes as the descriptor takes? */ 194400a2430fSAndrzej Pietrasiewicz length = _ds->bLength; 194500a2430fSAndrzej Pietrasiewicz if (len < length) { 194600a2430fSAndrzej Pietrasiewicz pr_vdebug("descriptor longer then available data\n"); 194700a2430fSAndrzej Pietrasiewicz return -EINVAL; 194800a2430fSAndrzej Pietrasiewicz } 194900a2430fSAndrzej Pietrasiewicz 195000a2430fSAndrzej Pietrasiewicz #define __entity_check_INTERFACE(val) 1 195100a2430fSAndrzej Pietrasiewicz #define __entity_check_STRING(val) (val) 195200a2430fSAndrzej Pietrasiewicz #define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK) 195300a2430fSAndrzej Pietrasiewicz #define __entity(type, val) do { \ 195400a2430fSAndrzej Pietrasiewicz pr_vdebug("entity " #type "(%02x)\n", (val)); \ 195500a2430fSAndrzej Pietrasiewicz if (unlikely(!__entity_check_ ##type(val))) { \ 195600a2430fSAndrzej Pietrasiewicz pr_vdebug("invalid entity's value\n"); \ 195700a2430fSAndrzej Pietrasiewicz return -EINVAL; \ 195800a2430fSAndrzej Pietrasiewicz } \ 195900a2430fSAndrzej Pietrasiewicz ret = entity(FFS_ ##type, &val, _ds, priv); \ 196000a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { \ 196100a2430fSAndrzej Pietrasiewicz pr_debug("entity " #type "(%02x); ret = %d\n", \ 196200a2430fSAndrzej Pietrasiewicz (val), ret); \ 196300a2430fSAndrzej Pietrasiewicz return ret; \ 196400a2430fSAndrzej Pietrasiewicz } \ 196500a2430fSAndrzej Pietrasiewicz } while (0) 196600a2430fSAndrzej Pietrasiewicz 196700a2430fSAndrzej Pietrasiewicz /* Parse descriptor depending on type. */ 196800a2430fSAndrzej Pietrasiewicz switch (_ds->bDescriptorType) { 196900a2430fSAndrzej Pietrasiewicz case USB_DT_DEVICE: 197000a2430fSAndrzej Pietrasiewicz case USB_DT_CONFIG: 197100a2430fSAndrzej Pietrasiewicz case USB_DT_STRING: 197200a2430fSAndrzej Pietrasiewicz case USB_DT_DEVICE_QUALIFIER: 197300a2430fSAndrzej Pietrasiewicz /* function can't have any of those */ 197400a2430fSAndrzej Pietrasiewicz pr_vdebug("descriptor reserved for gadget: %d\n", 197500a2430fSAndrzej Pietrasiewicz _ds->bDescriptorType); 197600a2430fSAndrzej Pietrasiewicz return -EINVAL; 197700a2430fSAndrzej Pietrasiewicz 197800a2430fSAndrzej Pietrasiewicz case USB_DT_INTERFACE: { 197900a2430fSAndrzej Pietrasiewicz struct usb_interface_descriptor *ds = (void *)_ds; 198000a2430fSAndrzej Pietrasiewicz pr_vdebug("interface descriptor\n"); 198100a2430fSAndrzej Pietrasiewicz if (length != sizeof *ds) 198200a2430fSAndrzej Pietrasiewicz goto inv_length; 198300a2430fSAndrzej Pietrasiewicz 198400a2430fSAndrzej Pietrasiewicz __entity(INTERFACE, ds->bInterfaceNumber); 198500a2430fSAndrzej Pietrasiewicz if (ds->iInterface) 198600a2430fSAndrzej Pietrasiewicz __entity(STRING, ds->iInterface); 198700a2430fSAndrzej Pietrasiewicz } 198800a2430fSAndrzej Pietrasiewicz break; 198900a2430fSAndrzej Pietrasiewicz 199000a2430fSAndrzej Pietrasiewicz case USB_DT_ENDPOINT: { 199100a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *ds = (void *)_ds; 199200a2430fSAndrzej Pietrasiewicz pr_vdebug("endpoint descriptor\n"); 199300a2430fSAndrzej Pietrasiewicz if (length != USB_DT_ENDPOINT_SIZE && 199400a2430fSAndrzej Pietrasiewicz length != USB_DT_ENDPOINT_AUDIO_SIZE) 199500a2430fSAndrzej Pietrasiewicz goto inv_length; 199600a2430fSAndrzej Pietrasiewicz __entity(ENDPOINT, ds->bEndpointAddress); 199700a2430fSAndrzej Pietrasiewicz } 199800a2430fSAndrzej Pietrasiewicz break; 199900a2430fSAndrzej Pietrasiewicz 200000a2430fSAndrzej Pietrasiewicz case HID_DT_HID: 200100a2430fSAndrzej Pietrasiewicz pr_vdebug("hid descriptor\n"); 200200a2430fSAndrzej Pietrasiewicz if (length != sizeof(struct hid_descriptor)) 200300a2430fSAndrzej Pietrasiewicz goto inv_length; 200400a2430fSAndrzej Pietrasiewicz break; 200500a2430fSAndrzej Pietrasiewicz 200600a2430fSAndrzej Pietrasiewicz case USB_DT_OTG: 200700a2430fSAndrzej Pietrasiewicz if (length != sizeof(struct usb_otg_descriptor)) 200800a2430fSAndrzej Pietrasiewicz goto inv_length; 200900a2430fSAndrzej Pietrasiewicz break; 201000a2430fSAndrzej Pietrasiewicz 201100a2430fSAndrzej Pietrasiewicz case USB_DT_INTERFACE_ASSOCIATION: { 201200a2430fSAndrzej Pietrasiewicz struct usb_interface_assoc_descriptor *ds = (void *)_ds; 201300a2430fSAndrzej Pietrasiewicz pr_vdebug("interface association descriptor\n"); 201400a2430fSAndrzej Pietrasiewicz if (length != sizeof *ds) 201500a2430fSAndrzej Pietrasiewicz goto inv_length; 201600a2430fSAndrzej Pietrasiewicz if (ds->iFunction) 201700a2430fSAndrzej Pietrasiewicz __entity(STRING, ds->iFunction); 201800a2430fSAndrzej Pietrasiewicz } 201900a2430fSAndrzej Pietrasiewicz break; 202000a2430fSAndrzej Pietrasiewicz 202100a2430fSAndrzej Pietrasiewicz case USB_DT_SS_ENDPOINT_COMP: 202200a2430fSAndrzej Pietrasiewicz pr_vdebug("EP SS companion descriptor\n"); 202300a2430fSAndrzej Pietrasiewicz if (length != sizeof(struct usb_ss_ep_comp_descriptor)) 202400a2430fSAndrzej Pietrasiewicz goto inv_length; 202500a2430fSAndrzej Pietrasiewicz break; 202600a2430fSAndrzej Pietrasiewicz 202700a2430fSAndrzej Pietrasiewicz case USB_DT_OTHER_SPEED_CONFIG: 202800a2430fSAndrzej Pietrasiewicz case USB_DT_INTERFACE_POWER: 202900a2430fSAndrzej Pietrasiewicz case USB_DT_DEBUG: 203000a2430fSAndrzej Pietrasiewicz case USB_DT_SECURITY: 203100a2430fSAndrzej Pietrasiewicz case USB_DT_CS_RADIO_CONTROL: 203200a2430fSAndrzej Pietrasiewicz /* TODO */ 203300a2430fSAndrzej Pietrasiewicz pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType); 203400a2430fSAndrzej Pietrasiewicz return -EINVAL; 203500a2430fSAndrzej Pietrasiewicz 203600a2430fSAndrzej Pietrasiewicz default: 203700a2430fSAndrzej Pietrasiewicz /* We should never be here */ 203800a2430fSAndrzej Pietrasiewicz pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType); 203900a2430fSAndrzej Pietrasiewicz return -EINVAL; 204000a2430fSAndrzej Pietrasiewicz 204100a2430fSAndrzej Pietrasiewicz inv_length: 204200a2430fSAndrzej Pietrasiewicz pr_vdebug("invalid length: %d (descriptor %d)\n", 204300a2430fSAndrzej Pietrasiewicz _ds->bLength, _ds->bDescriptorType); 204400a2430fSAndrzej Pietrasiewicz return -EINVAL; 204500a2430fSAndrzej Pietrasiewicz } 204600a2430fSAndrzej Pietrasiewicz 204700a2430fSAndrzej Pietrasiewicz #undef __entity 204800a2430fSAndrzej Pietrasiewicz #undef __entity_check_DESCRIPTOR 204900a2430fSAndrzej Pietrasiewicz #undef __entity_check_INTERFACE 205000a2430fSAndrzej Pietrasiewicz #undef __entity_check_STRING 205100a2430fSAndrzej Pietrasiewicz #undef __entity_check_ENDPOINT 205200a2430fSAndrzej Pietrasiewicz 205300a2430fSAndrzej Pietrasiewicz return length; 205400a2430fSAndrzej Pietrasiewicz } 205500a2430fSAndrzej Pietrasiewicz 205600a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, 205700a2430fSAndrzej Pietrasiewicz ffs_entity_callback entity, void *priv) 205800a2430fSAndrzej Pietrasiewicz { 205900a2430fSAndrzej Pietrasiewicz const unsigned _len = len; 206000a2430fSAndrzej Pietrasiewicz unsigned long num = 0; 206100a2430fSAndrzej Pietrasiewicz 206200a2430fSAndrzej Pietrasiewicz ENTER(); 206300a2430fSAndrzej Pietrasiewicz 206400a2430fSAndrzej Pietrasiewicz for (;;) { 206500a2430fSAndrzej Pietrasiewicz int ret; 206600a2430fSAndrzej Pietrasiewicz 206700a2430fSAndrzej Pietrasiewicz if (num == count) 206800a2430fSAndrzej Pietrasiewicz data = NULL; 206900a2430fSAndrzej Pietrasiewicz 207000a2430fSAndrzej Pietrasiewicz /* Record "descriptor" entity */ 207100a2430fSAndrzej Pietrasiewicz ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv); 207200a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 207300a2430fSAndrzej Pietrasiewicz pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n", 207400a2430fSAndrzej Pietrasiewicz num, ret); 207500a2430fSAndrzej Pietrasiewicz return ret; 207600a2430fSAndrzej Pietrasiewicz } 207700a2430fSAndrzej Pietrasiewicz 207800a2430fSAndrzej Pietrasiewicz if (!data) 207900a2430fSAndrzej Pietrasiewicz return _len - len; 208000a2430fSAndrzej Pietrasiewicz 208100a2430fSAndrzej Pietrasiewicz ret = ffs_do_single_desc(data, len, entity, priv); 208200a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 208300a2430fSAndrzej Pietrasiewicz pr_debug("%s returns %d\n", __func__, ret); 208400a2430fSAndrzej Pietrasiewicz return ret; 208500a2430fSAndrzej Pietrasiewicz } 208600a2430fSAndrzej Pietrasiewicz 208700a2430fSAndrzej Pietrasiewicz len -= ret; 208800a2430fSAndrzej Pietrasiewicz data += ret; 208900a2430fSAndrzej Pietrasiewicz ++num; 209000a2430fSAndrzej Pietrasiewicz } 209100a2430fSAndrzej Pietrasiewicz } 209200a2430fSAndrzej Pietrasiewicz 209300a2430fSAndrzej Pietrasiewicz static int __ffs_data_do_entity(enum ffs_entity_type type, 209400a2430fSAndrzej Pietrasiewicz u8 *valuep, struct usb_descriptor_header *desc, 209500a2430fSAndrzej Pietrasiewicz void *priv) 209600a2430fSAndrzej Pietrasiewicz { 20976d5c1c77SRobert Baldyga struct ffs_desc_helper *helper = priv; 20986d5c1c77SRobert Baldyga struct usb_endpoint_descriptor *d; 209900a2430fSAndrzej Pietrasiewicz 210000a2430fSAndrzej Pietrasiewicz ENTER(); 210100a2430fSAndrzej Pietrasiewicz 210200a2430fSAndrzej Pietrasiewicz switch (type) { 210300a2430fSAndrzej Pietrasiewicz case FFS_DESCRIPTOR: 210400a2430fSAndrzej Pietrasiewicz break; 210500a2430fSAndrzej Pietrasiewicz 210600a2430fSAndrzej Pietrasiewicz case FFS_INTERFACE: 210700a2430fSAndrzej Pietrasiewicz /* 210800a2430fSAndrzej Pietrasiewicz * Interfaces are indexed from zero so if we 210900a2430fSAndrzej Pietrasiewicz * encountered interface "n" then there are at least 211000a2430fSAndrzej Pietrasiewicz * "n+1" interfaces. 211100a2430fSAndrzej Pietrasiewicz */ 21126d5c1c77SRobert Baldyga if (*valuep >= helper->interfaces_count) 21136d5c1c77SRobert Baldyga helper->interfaces_count = *valuep + 1; 211400a2430fSAndrzej Pietrasiewicz break; 211500a2430fSAndrzej Pietrasiewicz 211600a2430fSAndrzej Pietrasiewicz case FFS_STRING: 211700a2430fSAndrzej Pietrasiewicz /* 211896a420d2SVincent Pelletier * Strings are indexed from 1 (0 is reserved 211996a420d2SVincent Pelletier * for languages list) 212000a2430fSAndrzej Pietrasiewicz */ 21216d5c1c77SRobert Baldyga if (*valuep > helper->ffs->strings_count) 21226d5c1c77SRobert Baldyga helper->ffs->strings_count = *valuep; 212300a2430fSAndrzej Pietrasiewicz break; 212400a2430fSAndrzej Pietrasiewicz 212500a2430fSAndrzej Pietrasiewicz case FFS_ENDPOINT: 21266d5c1c77SRobert Baldyga d = (void *)desc; 21276d5c1c77SRobert Baldyga helper->eps_count++; 212841dc9ac1SVincent Pelletier if (helper->eps_count >= FFS_MAX_EPS_COUNT) 21296d5c1c77SRobert Baldyga return -EINVAL; 21306d5c1c77SRobert Baldyga /* Check if descriptors for any speed were already parsed */ 21316d5c1c77SRobert Baldyga if (!helper->ffs->eps_count && !helper->ffs->interfaces_count) 21326d5c1c77SRobert Baldyga helper->ffs->eps_addrmap[helper->eps_count] = 21336d5c1c77SRobert Baldyga d->bEndpointAddress; 21346d5c1c77SRobert Baldyga else if (helper->ffs->eps_addrmap[helper->eps_count] != 21356d5c1c77SRobert Baldyga d->bEndpointAddress) 21366d5c1c77SRobert Baldyga return -EINVAL; 213700a2430fSAndrzej Pietrasiewicz break; 213800a2430fSAndrzej Pietrasiewicz } 213900a2430fSAndrzej Pietrasiewicz 214000a2430fSAndrzej Pietrasiewicz return 0; 214100a2430fSAndrzej Pietrasiewicz } 214200a2430fSAndrzej Pietrasiewicz 214300a2430fSAndrzej Pietrasiewicz static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, 214400a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *desc) 214500a2430fSAndrzej Pietrasiewicz { 214600a2430fSAndrzej Pietrasiewicz u16 bcd_version = le16_to_cpu(desc->bcdVersion); 214700a2430fSAndrzej Pietrasiewicz u16 w_index = le16_to_cpu(desc->wIndex); 214800a2430fSAndrzej Pietrasiewicz 214900a2430fSAndrzej Pietrasiewicz if (bcd_version != 1) { 215000a2430fSAndrzej Pietrasiewicz pr_vdebug("unsupported os descriptors version: %d", 215100a2430fSAndrzej Pietrasiewicz bcd_version); 215200a2430fSAndrzej Pietrasiewicz return -EINVAL; 215300a2430fSAndrzej Pietrasiewicz } 215400a2430fSAndrzej Pietrasiewicz switch (w_index) { 215500a2430fSAndrzej Pietrasiewicz case 0x4: 215600a2430fSAndrzej Pietrasiewicz *next_type = FFS_OS_DESC_EXT_COMPAT; 215700a2430fSAndrzej Pietrasiewicz break; 215800a2430fSAndrzej Pietrasiewicz case 0x5: 215900a2430fSAndrzej Pietrasiewicz *next_type = FFS_OS_DESC_EXT_PROP; 216000a2430fSAndrzej Pietrasiewicz break; 216100a2430fSAndrzej Pietrasiewicz default: 216200a2430fSAndrzej Pietrasiewicz pr_vdebug("unsupported os descriptor type: %d", w_index); 216300a2430fSAndrzej Pietrasiewicz return -EINVAL; 216400a2430fSAndrzej Pietrasiewicz } 216500a2430fSAndrzej Pietrasiewicz 216600a2430fSAndrzej Pietrasiewicz return sizeof(*desc); 216700a2430fSAndrzej Pietrasiewicz } 216800a2430fSAndrzej Pietrasiewicz 216900a2430fSAndrzej Pietrasiewicz /* 217000a2430fSAndrzej Pietrasiewicz * Process all extended compatibility/extended property descriptors 217100a2430fSAndrzej Pietrasiewicz * of a feature descriptor 217200a2430fSAndrzej Pietrasiewicz */ 217300a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_single_os_desc(char *data, unsigned len, 217400a2430fSAndrzej Pietrasiewicz enum ffs_os_desc_type type, 217500a2430fSAndrzej Pietrasiewicz u16 feature_count, 217600a2430fSAndrzej Pietrasiewicz ffs_os_desc_callback entity, 217700a2430fSAndrzej Pietrasiewicz void *priv, 217800a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *h) 217900a2430fSAndrzej Pietrasiewicz { 218000a2430fSAndrzej Pietrasiewicz int ret; 218100a2430fSAndrzej Pietrasiewicz const unsigned _len = len; 218200a2430fSAndrzej Pietrasiewicz 218300a2430fSAndrzej Pietrasiewicz ENTER(); 218400a2430fSAndrzej Pietrasiewicz 218500a2430fSAndrzej Pietrasiewicz /* loop over all ext compat/ext prop descriptors */ 218600a2430fSAndrzej Pietrasiewicz while (feature_count--) { 218700a2430fSAndrzej Pietrasiewicz ret = entity(type, h, data, len, priv); 218800a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 218900a2430fSAndrzej Pietrasiewicz pr_debug("bad OS descriptor, type: %d\n", type); 219000a2430fSAndrzej Pietrasiewicz return ret; 219100a2430fSAndrzej Pietrasiewicz } 219200a2430fSAndrzej Pietrasiewicz data += ret; 219300a2430fSAndrzej Pietrasiewicz len -= ret; 219400a2430fSAndrzej Pietrasiewicz } 219500a2430fSAndrzej Pietrasiewicz return _len - len; 219600a2430fSAndrzej Pietrasiewicz } 219700a2430fSAndrzej Pietrasiewicz 219800a2430fSAndrzej Pietrasiewicz /* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */ 219900a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_os_descs(unsigned count, 220000a2430fSAndrzej Pietrasiewicz char *data, unsigned len, 220100a2430fSAndrzej Pietrasiewicz ffs_os_desc_callback entity, void *priv) 220200a2430fSAndrzej Pietrasiewicz { 220300a2430fSAndrzej Pietrasiewicz const unsigned _len = len; 220400a2430fSAndrzej Pietrasiewicz unsigned long num = 0; 220500a2430fSAndrzej Pietrasiewicz 220600a2430fSAndrzej Pietrasiewicz ENTER(); 220700a2430fSAndrzej Pietrasiewicz 220800a2430fSAndrzej Pietrasiewicz for (num = 0; num < count; ++num) { 220900a2430fSAndrzej Pietrasiewicz int ret; 221000a2430fSAndrzej Pietrasiewicz enum ffs_os_desc_type type; 221100a2430fSAndrzej Pietrasiewicz u16 feature_count; 221200a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *desc = (void *)data; 221300a2430fSAndrzej Pietrasiewicz 221400a2430fSAndrzej Pietrasiewicz if (len < sizeof(*desc)) 221500a2430fSAndrzej Pietrasiewicz return -EINVAL; 221600a2430fSAndrzej Pietrasiewicz 221700a2430fSAndrzej Pietrasiewicz /* 221800a2430fSAndrzej Pietrasiewicz * Record "descriptor" entity. 221900a2430fSAndrzej Pietrasiewicz * Process dwLength, bcdVersion, wIndex, get b/wCount. 222000a2430fSAndrzej Pietrasiewicz * Move the data pointer to the beginning of extended 222100a2430fSAndrzej Pietrasiewicz * compatibilities proper or extended properties proper 222200a2430fSAndrzej Pietrasiewicz * portions of the data 222300a2430fSAndrzej Pietrasiewicz */ 222400a2430fSAndrzej Pietrasiewicz if (le32_to_cpu(desc->dwLength) > len) 222500a2430fSAndrzej Pietrasiewicz return -EINVAL; 222600a2430fSAndrzej Pietrasiewicz 222700a2430fSAndrzej Pietrasiewicz ret = __ffs_do_os_desc_header(&type, desc); 222800a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 222900a2430fSAndrzej Pietrasiewicz pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n", 223000a2430fSAndrzej Pietrasiewicz num, ret); 223100a2430fSAndrzej Pietrasiewicz return ret; 223200a2430fSAndrzej Pietrasiewicz } 223300a2430fSAndrzej Pietrasiewicz /* 223400a2430fSAndrzej Pietrasiewicz * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??" 223500a2430fSAndrzej Pietrasiewicz */ 223600a2430fSAndrzej Pietrasiewicz feature_count = le16_to_cpu(desc->wCount); 223700a2430fSAndrzej Pietrasiewicz if (type == FFS_OS_DESC_EXT_COMPAT && 223800a2430fSAndrzej Pietrasiewicz (feature_count > 255 || desc->Reserved)) 223900a2430fSAndrzej Pietrasiewicz return -EINVAL; 224000a2430fSAndrzej Pietrasiewicz len -= ret; 224100a2430fSAndrzej Pietrasiewicz data += ret; 224200a2430fSAndrzej Pietrasiewicz 224300a2430fSAndrzej Pietrasiewicz /* 224400a2430fSAndrzej Pietrasiewicz * Process all function/property descriptors 224500a2430fSAndrzej Pietrasiewicz * of this Feature Descriptor 224600a2430fSAndrzej Pietrasiewicz */ 224700a2430fSAndrzej Pietrasiewicz ret = ffs_do_single_os_desc(data, len, type, 224800a2430fSAndrzej Pietrasiewicz feature_count, entity, priv, desc); 224900a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 225000a2430fSAndrzej Pietrasiewicz pr_debug("%s returns %d\n", __func__, ret); 225100a2430fSAndrzej Pietrasiewicz return ret; 225200a2430fSAndrzej Pietrasiewicz } 225300a2430fSAndrzej Pietrasiewicz 225400a2430fSAndrzej Pietrasiewicz len -= ret; 225500a2430fSAndrzej Pietrasiewicz data += ret; 225600a2430fSAndrzej Pietrasiewicz } 225700a2430fSAndrzej Pietrasiewicz return _len - len; 225800a2430fSAndrzej Pietrasiewicz } 225900a2430fSAndrzej Pietrasiewicz 226000a2430fSAndrzej Pietrasiewicz /** 226100a2430fSAndrzej Pietrasiewicz * Validate contents of the buffer from userspace related to OS descriptors. 226200a2430fSAndrzej Pietrasiewicz */ 226300a2430fSAndrzej Pietrasiewicz static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, 226400a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *h, void *data, 226500a2430fSAndrzej Pietrasiewicz unsigned len, void *priv) 226600a2430fSAndrzej Pietrasiewicz { 226700a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = priv; 226800a2430fSAndrzej Pietrasiewicz u8 length; 226900a2430fSAndrzej Pietrasiewicz 227000a2430fSAndrzej Pietrasiewicz ENTER(); 227100a2430fSAndrzej Pietrasiewicz 227200a2430fSAndrzej Pietrasiewicz switch (type) { 227300a2430fSAndrzej Pietrasiewicz case FFS_OS_DESC_EXT_COMPAT: { 227400a2430fSAndrzej Pietrasiewicz struct usb_ext_compat_desc *d = data; 227500a2430fSAndrzej Pietrasiewicz int i; 227600a2430fSAndrzej Pietrasiewicz 227700a2430fSAndrzej Pietrasiewicz if (len < sizeof(*d) || 2278a3acc696SJohn Keeping d->bFirstInterfaceNumber >= ffs->interfaces_count) 227900a2430fSAndrzej Pietrasiewicz return -EINVAL; 2280a3acc696SJohn Keeping if (d->Reserved1 != 1) { 2281a3acc696SJohn Keeping /* 2282a3acc696SJohn Keeping * According to the spec, Reserved1 must be set to 1 2283a3acc696SJohn Keeping * but older kernels incorrectly rejected non-zero 2284a3acc696SJohn Keeping * values. We fix it here to avoid returning EINVAL 2285a3acc696SJohn Keeping * in response to values we used to accept. 2286a3acc696SJohn Keeping */ 2287a3acc696SJohn Keeping pr_debug("usb_ext_compat_desc::Reserved1 forced to 1\n"); 2288a3acc696SJohn Keeping d->Reserved1 = 1; 2289a3acc696SJohn Keeping } 229000a2430fSAndrzej Pietrasiewicz for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) 229100a2430fSAndrzej Pietrasiewicz if (d->Reserved2[i]) 229200a2430fSAndrzej Pietrasiewicz return -EINVAL; 229300a2430fSAndrzej Pietrasiewicz 229400a2430fSAndrzej Pietrasiewicz length = sizeof(struct usb_ext_compat_desc); 229500a2430fSAndrzej Pietrasiewicz } 229600a2430fSAndrzej Pietrasiewicz break; 229700a2430fSAndrzej Pietrasiewicz case FFS_OS_DESC_EXT_PROP: { 229800a2430fSAndrzej Pietrasiewicz struct usb_ext_prop_desc *d = data; 229900a2430fSAndrzej Pietrasiewicz u32 type, pdl; 230000a2430fSAndrzej Pietrasiewicz u16 pnl; 230100a2430fSAndrzej Pietrasiewicz 230200a2430fSAndrzej Pietrasiewicz if (len < sizeof(*d) || h->interface >= ffs->interfaces_count) 230300a2430fSAndrzej Pietrasiewicz return -EINVAL; 230400a2430fSAndrzej Pietrasiewicz length = le32_to_cpu(d->dwSize); 230583e526f2SVincent Pelletier if (len < length) 230683e526f2SVincent Pelletier return -EINVAL; 230700a2430fSAndrzej Pietrasiewicz type = le32_to_cpu(d->dwPropertyDataType); 230800a2430fSAndrzej Pietrasiewicz if (type < USB_EXT_PROP_UNICODE || 230900a2430fSAndrzej Pietrasiewicz type > USB_EXT_PROP_UNICODE_MULTI) { 231000a2430fSAndrzej Pietrasiewicz pr_vdebug("unsupported os descriptor property type: %d", 231100a2430fSAndrzej Pietrasiewicz type); 231200a2430fSAndrzej Pietrasiewicz return -EINVAL; 231300a2430fSAndrzej Pietrasiewicz } 231400a2430fSAndrzej Pietrasiewicz pnl = le16_to_cpu(d->wPropertyNameLength); 231583e526f2SVincent Pelletier if (length < 14 + pnl) { 231683e526f2SVincent Pelletier pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n", 231783e526f2SVincent Pelletier length, pnl, type); 231883e526f2SVincent Pelletier return -EINVAL; 231983e526f2SVincent Pelletier } 2320c40619bbSVincent Pelletier pdl = le32_to_cpu(*(__le32 *)((u8 *)data + 10 + pnl)); 232100a2430fSAndrzej Pietrasiewicz if (length != 14 + pnl + pdl) { 232200a2430fSAndrzej Pietrasiewicz pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n", 232300a2430fSAndrzej Pietrasiewicz length, pnl, pdl, type); 232400a2430fSAndrzej Pietrasiewicz return -EINVAL; 232500a2430fSAndrzej Pietrasiewicz } 232600a2430fSAndrzej Pietrasiewicz ++ffs->ms_os_descs_ext_prop_count; 232700a2430fSAndrzej Pietrasiewicz /* property name reported to the host as "WCHAR"s */ 232800a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_name_len += pnl * 2; 232900a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_data_len += pdl; 233000a2430fSAndrzej Pietrasiewicz } 233100a2430fSAndrzej Pietrasiewicz break; 233200a2430fSAndrzej Pietrasiewicz default: 233300a2430fSAndrzej Pietrasiewicz pr_vdebug("unknown descriptor: %d\n", type); 233400a2430fSAndrzej Pietrasiewicz return -EINVAL; 233500a2430fSAndrzej Pietrasiewicz } 233600a2430fSAndrzej Pietrasiewicz return length; 233700a2430fSAndrzej Pietrasiewicz } 233800a2430fSAndrzej Pietrasiewicz 233900a2430fSAndrzej Pietrasiewicz static int __ffs_data_got_descs(struct ffs_data *ffs, 234000a2430fSAndrzej Pietrasiewicz char *const _data, size_t len) 234100a2430fSAndrzej Pietrasiewicz { 234200a2430fSAndrzej Pietrasiewicz char *data = _data, *raw_descs; 234300a2430fSAndrzej Pietrasiewicz unsigned os_descs_count = 0, counts[3], flags; 234400a2430fSAndrzej Pietrasiewicz int ret = -EINVAL, i; 23456d5c1c77SRobert Baldyga struct ffs_desc_helper helper; 234600a2430fSAndrzej Pietrasiewicz 234700a2430fSAndrzej Pietrasiewicz ENTER(); 234800a2430fSAndrzej Pietrasiewicz 234900a2430fSAndrzej Pietrasiewicz if (get_unaligned_le32(data + 4) != len) 235000a2430fSAndrzej Pietrasiewicz goto error; 235100a2430fSAndrzej Pietrasiewicz 235200a2430fSAndrzej Pietrasiewicz switch (get_unaligned_le32(data)) { 235300a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_DESCRIPTORS_MAGIC: 235400a2430fSAndrzej Pietrasiewicz flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; 235500a2430fSAndrzej Pietrasiewicz data += 8; 235600a2430fSAndrzej Pietrasiewicz len -= 8; 235700a2430fSAndrzej Pietrasiewicz break; 235800a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_DESCRIPTORS_MAGIC_V2: 235900a2430fSAndrzej Pietrasiewicz flags = get_unaligned_le32(data + 8); 23601b0bf88fSRobert Baldyga ffs->user_flags = flags; 236100a2430fSAndrzej Pietrasiewicz if (flags & ~(FUNCTIONFS_HAS_FS_DESC | 236200a2430fSAndrzej Pietrasiewicz FUNCTIONFS_HAS_HS_DESC | 236300a2430fSAndrzej Pietrasiewicz FUNCTIONFS_HAS_SS_DESC | 23641b0bf88fSRobert Baldyga FUNCTIONFS_HAS_MS_OS_DESC | 23655e33f6fdSRobert Baldyga FUNCTIONFS_VIRTUAL_ADDR | 236654dfce6dSFelix Hädicke FUNCTIONFS_EVENTFD | 23674368c28aSFelix Hädicke FUNCTIONFS_ALL_CTRL_RECIP | 23684368c28aSFelix Hädicke FUNCTIONFS_CONFIG0_SETUP)) { 236900a2430fSAndrzej Pietrasiewicz ret = -ENOSYS; 237000a2430fSAndrzej Pietrasiewicz goto error; 237100a2430fSAndrzej Pietrasiewicz } 237200a2430fSAndrzej Pietrasiewicz data += 12; 237300a2430fSAndrzej Pietrasiewicz len -= 12; 237400a2430fSAndrzej Pietrasiewicz break; 237500a2430fSAndrzej Pietrasiewicz default: 237600a2430fSAndrzej Pietrasiewicz goto error; 237700a2430fSAndrzej Pietrasiewicz } 237800a2430fSAndrzej Pietrasiewicz 23795e33f6fdSRobert Baldyga if (flags & FUNCTIONFS_EVENTFD) { 23805e33f6fdSRobert Baldyga if (len < 4) 23815e33f6fdSRobert Baldyga goto error; 23825e33f6fdSRobert Baldyga ffs->ffs_eventfd = 23835e33f6fdSRobert Baldyga eventfd_ctx_fdget((int)get_unaligned_le32(data)); 23845e33f6fdSRobert Baldyga if (IS_ERR(ffs->ffs_eventfd)) { 23855e33f6fdSRobert Baldyga ret = PTR_ERR(ffs->ffs_eventfd); 23865e33f6fdSRobert Baldyga ffs->ffs_eventfd = NULL; 23875e33f6fdSRobert Baldyga goto error; 23885e33f6fdSRobert Baldyga } 23895e33f6fdSRobert Baldyga data += 4; 23905e33f6fdSRobert Baldyga len -= 4; 23915e33f6fdSRobert Baldyga } 23925e33f6fdSRobert Baldyga 239300a2430fSAndrzej Pietrasiewicz /* Read fs_count, hs_count and ss_count (if present) */ 239400a2430fSAndrzej Pietrasiewicz for (i = 0; i < 3; ++i) { 239500a2430fSAndrzej Pietrasiewicz if (!(flags & (1 << i))) { 239600a2430fSAndrzej Pietrasiewicz counts[i] = 0; 239700a2430fSAndrzej Pietrasiewicz } else if (len < 4) { 239800a2430fSAndrzej Pietrasiewicz goto error; 239900a2430fSAndrzej Pietrasiewicz } else { 240000a2430fSAndrzej Pietrasiewicz counts[i] = get_unaligned_le32(data); 240100a2430fSAndrzej Pietrasiewicz data += 4; 240200a2430fSAndrzej Pietrasiewicz len -= 4; 240300a2430fSAndrzej Pietrasiewicz } 240400a2430fSAndrzej Pietrasiewicz } 240500a2430fSAndrzej Pietrasiewicz if (flags & (1 << i)) { 240683e526f2SVincent Pelletier if (len < 4) { 240783e526f2SVincent Pelletier goto error; 240883e526f2SVincent Pelletier } 240900a2430fSAndrzej Pietrasiewicz os_descs_count = get_unaligned_le32(data); 241000a2430fSAndrzej Pietrasiewicz data += 4; 241100a2430fSAndrzej Pietrasiewicz len -= 4; 241200a2430fSAndrzej Pietrasiewicz }; 241300a2430fSAndrzej Pietrasiewicz 241400a2430fSAndrzej Pietrasiewicz /* Read descriptors */ 241500a2430fSAndrzej Pietrasiewicz raw_descs = data; 24166d5c1c77SRobert Baldyga helper.ffs = ffs; 241700a2430fSAndrzej Pietrasiewicz for (i = 0; i < 3; ++i) { 241800a2430fSAndrzej Pietrasiewicz if (!counts[i]) 241900a2430fSAndrzej Pietrasiewicz continue; 24206d5c1c77SRobert Baldyga helper.interfaces_count = 0; 24216d5c1c77SRobert Baldyga helper.eps_count = 0; 242200a2430fSAndrzej Pietrasiewicz ret = ffs_do_descs(counts[i], data, len, 24236d5c1c77SRobert Baldyga __ffs_data_do_entity, &helper); 242400a2430fSAndrzej Pietrasiewicz if (ret < 0) 242500a2430fSAndrzej Pietrasiewicz goto error; 24266d5c1c77SRobert Baldyga if (!ffs->eps_count && !ffs->interfaces_count) { 24276d5c1c77SRobert Baldyga ffs->eps_count = helper.eps_count; 24286d5c1c77SRobert Baldyga ffs->interfaces_count = helper.interfaces_count; 24296d5c1c77SRobert Baldyga } else { 24306d5c1c77SRobert Baldyga if (ffs->eps_count != helper.eps_count) { 24316d5c1c77SRobert Baldyga ret = -EINVAL; 24326d5c1c77SRobert Baldyga goto error; 24336d5c1c77SRobert Baldyga } 24346d5c1c77SRobert Baldyga if (ffs->interfaces_count != helper.interfaces_count) { 24356d5c1c77SRobert Baldyga ret = -EINVAL; 24366d5c1c77SRobert Baldyga goto error; 24376d5c1c77SRobert Baldyga } 24386d5c1c77SRobert Baldyga } 243900a2430fSAndrzej Pietrasiewicz data += ret; 244000a2430fSAndrzej Pietrasiewicz len -= ret; 244100a2430fSAndrzej Pietrasiewicz } 244200a2430fSAndrzej Pietrasiewicz if (os_descs_count) { 244300a2430fSAndrzej Pietrasiewicz ret = ffs_do_os_descs(os_descs_count, data, len, 244400a2430fSAndrzej Pietrasiewicz __ffs_data_do_os_desc, ffs); 244500a2430fSAndrzej Pietrasiewicz if (ret < 0) 244600a2430fSAndrzej Pietrasiewicz goto error; 244700a2430fSAndrzej Pietrasiewicz data += ret; 244800a2430fSAndrzej Pietrasiewicz len -= ret; 244900a2430fSAndrzej Pietrasiewicz } 245000a2430fSAndrzej Pietrasiewicz 245100a2430fSAndrzej Pietrasiewicz if (raw_descs == data || len) { 245200a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 245300a2430fSAndrzej Pietrasiewicz goto error; 245400a2430fSAndrzej Pietrasiewicz } 245500a2430fSAndrzej Pietrasiewicz 245600a2430fSAndrzej Pietrasiewicz ffs->raw_descs_data = _data; 245700a2430fSAndrzej Pietrasiewicz ffs->raw_descs = raw_descs; 245800a2430fSAndrzej Pietrasiewicz ffs->raw_descs_length = data - raw_descs; 245900a2430fSAndrzej Pietrasiewicz ffs->fs_descs_count = counts[0]; 246000a2430fSAndrzej Pietrasiewicz ffs->hs_descs_count = counts[1]; 246100a2430fSAndrzej Pietrasiewicz ffs->ss_descs_count = counts[2]; 246200a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_count = os_descs_count; 246300a2430fSAndrzej Pietrasiewicz 246400a2430fSAndrzej Pietrasiewicz return 0; 246500a2430fSAndrzej Pietrasiewicz 246600a2430fSAndrzej Pietrasiewicz error: 246700a2430fSAndrzej Pietrasiewicz kfree(_data); 246800a2430fSAndrzej Pietrasiewicz return ret; 246900a2430fSAndrzej Pietrasiewicz } 247000a2430fSAndrzej Pietrasiewicz 247100a2430fSAndrzej Pietrasiewicz static int __ffs_data_got_strings(struct ffs_data *ffs, 247200a2430fSAndrzej Pietrasiewicz char *const _data, size_t len) 247300a2430fSAndrzej Pietrasiewicz { 247400a2430fSAndrzej Pietrasiewicz u32 str_count, needed_count, lang_count; 247500a2430fSAndrzej Pietrasiewicz struct usb_gadget_strings **stringtabs, *t; 247600a2430fSAndrzej Pietrasiewicz const char *data = _data; 2477872ce511SMichal Nazarewicz struct usb_string *s; 247800a2430fSAndrzej Pietrasiewicz 247900a2430fSAndrzej Pietrasiewicz ENTER(); 248000a2430fSAndrzej Pietrasiewicz 248183e526f2SVincent Pelletier if (unlikely(len < 16 || 248283e526f2SVincent Pelletier get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || 248300a2430fSAndrzej Pietrasiewicz get_unaligned_le32(data + 4) != len)) 248400a2430fSAndrzej Pietrasiewicz goto error; 248500a2430fSAndrzej Pietrasiewicz str_count = get_unaligned_le32(data + 8); 248600a2430fSAndrzej Pietrasiewicz lang_count = get_unaligned_le32(data + 12); 248700a2430fSAndrzej Pietrasiewicz 248800a2430fSAndrzej Pietrasiewicz /* if one is zero the other must be zero */ 248900a2430fSAndrzej Pietrasiewicz if (unlikely(!str_count != !lang_count)) 249000a2430fSAndrzej Pietrasiewicz goto error; 249100a2430fSAndrzej Pietrasiewicz 249200a2430fSAndrzej Pietrasiewicz /* Do we have at least as many strings as descriptors need? */ 249300a2430fSAndrzej Pietrasiewicz needed_count = ffs->strings_count; 249400a2430fSAndrzej Pietrasiewicz if (unlikely(str_count < needed_count)) 249500a2430fSAndrzej Pietrasiewicz goto error; 249600a2430fSAndrzej Pietrasiewicz 249700a2430fSAndrzej Pietrasiewicz /* 249800a2430fSAndrzej Pietrasiewicz * If we don't need any strings just return and free all 249900a2430fSAndrzej Pietrasiewicz * memory. 250000a2430fSAndrzej Pietrasiewicz */ 250100a2430fSAndrzej Pietrasiewicz if (!needed_count) { 250200a2430fSAndrzej Pietrasiewicz kfree(_data); 250300a2430fSAndrzej Pietrasiewicz return 0; 250400a2430fSAndrzej Pietrasiewicz } 250500a2430fSAndrzej Pietrasiewicz 250600a2430fSAndrzej Pietrasiewicz /* Allocate everything in one chunk so there's less maintenance. */ 250700a2430fSAndrzej Pietrasiewicz { 250800a2430fSAndrzej Pietrasiewicz unsigned i = 0; 250900a2430fSAndrzej Pietrasiewicz vla_group(d); 251000a2430fSAndrzej Pietrasiewicz vla_item(d, struct usb_gadget_strings *, stringtabs, 251100a2430fSAndrzej Pietrasiewicz lang_count + 1); 251200a2430fSAndrzej Pietrasiewicz vla_item(d, struct usb_gadget_strings, stringtab, lang_count); 251300a2430fSAndrzej Pietrasiewicz vla_item(d, struct usb_string, strings, 251400a2430fSAndrzej Pietrasiewicz lang_count*(needed_count+1)); 251500a2430fSAndrzej Pietrasiewicz 251600a2430fSAndrzej Pietrasiewicz char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); 251700a2430fSAndrzej Pietrasiewicz 251800a2430fSAndrzej Pietrasiewicz if (unlikely(!vlabuf)) { 251900a2430fSAndrzej Pietrasiewicz kfree(_data); 252000a2430fSAndrzej Pietrasiewicz return -ENOMEM; 252100a2430fSAndrzej Pietrasiewicz } 252200a2430fSAndrzej Pietrasiewicz 252300a2430fSAndrzej Pietrasiewicz /* Initialize the VLA pointers */ 252400a2430fSAndrzej Pietrasiewicz stringtabs = vla_ptr(vlabuf, d, stringtabs); 252500a2430fSAndrzej Pietrasiewicz t = vla_ptr(vlabuf, d, stringtab); 252600a2430fSAndrzej Pietrasiewicz i = lang_count; 252700a2430fSAndrzej Pietrasiewicz do { 252800a2430fSAndrzej Pietrasiewicz *stringtabs++ = t++; 252900a2430fSAndrzej Pietrasiewicz } while (--i); 253000a2430fSAndrzej Pietrasiewicz *stringtabs = NULL; 253100a2430fSAndrzej Pietrasiewicz 253200a2430fSAndrzej Pietrasiewicz /* stringtabs = vlabuf = d_stringtabs for later kfree */ 253300a2430fSAndrzej Pietrasiewicz stringtabs = vla_ptr(vlabuf, d, stringtabs); 253400a2430fSAndrzej Pietrasiewicz t = vla_ptr(vlabuf, d, stringtab); 253500a2430fSAndrzej Pietrasiewicz s = vla_ptr(vlabuf, d, strings); 253600a2430fSAndrzej Pietrasiewicz } 253700a2430fSAndrzej Pietrasiewicz 253800a2430fSAndrzej Pietrasiewicz /* For each language */ 253900a2430fSAndrzej Pietrasiewicz data += 16; 254000a2430fSAndrzej Pietrasiewicz len -= 16; 254100a2430fSAndrzej Pietrasiewicz 254200a2430fSAndrzej Pietrasiewicz do { /* lang_count > 0 so we can use do-while */ 254300a2430fSAndrzej Pietrasiewicz unsigned needed = needed_count; 254400a2430fSAndrzej Pietrasiewicz 254500a2430fSAndrzej Pietrasiewicz if (unlikely(len < 3)) 254600a2430fSAndrzej Pietrasiewicz goto error_free; 254700a2430fSAndrzej Pietrasiewicz t->language = get_unaligned_le16(data); 254800a2430fSAndrzej Pietrasiewicz t->strings = s; 254900a2430fSAndrzej Pietrasiewicz ++t; 255000a2430fSAndrzej Pietrasiewicz 255100a2430fSAndrzej Pietrasiewicz data += 2; 255200a2430fSAndrzej Pietrasiewicz len -= 2; 255300a2430fSAndrzej Pietrasiewicz 255400a2430fSAndrzej Pietrasiewicz /* For each string */ 255500a2430fSAndrzej Pietrasiewicz do { /* str_count > 0 so we can use do-while */ 255600a2430fSAndrzej Pietrasiewicz size_t length = strnlen(data, len); 255700a2430fSAndrzej Pietrasiewicz 255800a2430fSAndrzej Pietrasiewicz if (unlikely(length == len)) 255900a2430fSAndrzej Pietrasiewicz goto error_free; 256000a2430fSAndrzej Pietrasiewicz 256100a2430fSAndrzej Pietrasiewicz /* 256200a2430fSAndrzej Pietrasiewicz * User may provide more strings then we need, 256300a2430fSAndrzej Pietrasiewicz * if that's the case we simply ignore the 256400a2430fSAndrzej Pietrasiewicz * rest 256500a2430fSAndrzej Pietrasiewicz */ 256600a2430fSAndrzej Pietrasiewicz if (likely(needed)) { 256700a2430fSAndrzej Pietrasiewicz /* 256800a2430fSAndrzej Pietrasiewicz * s->id will be set while adding 256900a2430fSAndrzej Pietrasiewicz * function to configuration so for 257000a2430fSAndrzej Pietrasiewicz * now just leave garbage here. 257100a2430fSAndrzej Pietrasiewicz */ 257200a2430fSAndrzej Pietrasiewicz s->s = data; 257300a2430fSAndrzej Pietrasiewicz --needed; 257400a2430fSAndrzej Pietrasiewicz ++s; 257500a2430fSAndrzej Pietrasiewicz } 257600a2430fSAndrzej Pietrasiewicz 257700a2430fSAndrzej Pietrasiewicz data += length + 1; 257800a2430fSAndrzej Pietrasiewicz len -= length + 1; 257900a2430fSAndrzej Pietrasiewicz } while (--str_count); 258000a2430fSAndrzej Pietrasiewicz 258100a2430fSAndrzej Pietrasiewicz s->id = 0; /* terminator */ 258200a2430fSAndrzej Pietrasiewicz s->s = NULL; 258300a2430fSAndrzej Pietrasiewicz ++s; 258400a2430fSAndrzej Pietrasiewicz 258500a2430fSAndrzej Pietrasiewicz } while (--lang_count); 258600a2430fSAndrzej Pietrasiewicz 258700a2430fSAndrzej Pietrasiewicz /* Some garbage left? */ 258800a2430fSAndrzej Pietrasiewicz if (unlikely(len)) 258900a2430fSAndrzej Pietrasiewicz goto error_free; 259000a2430fSAndrzej Pietrasiewicz 259100a2430fSAndrzej Pietrasiewicz /* Done! */ 259200a2430fSAndrzej Pietrasiewicz ffs->stringtabs = stringtabs; 259300a2430fSAndrzej Pietrasiewicz ffs->raw_strings = _data; 259400a2430fSAndrzej Pietrasiewicz 259500a2430fSAndrzej Pietrasiewicz return 0; 259600a2430fSAndrzej Pietrasiewicz 259700a2430fSAndrzej Pietrasiewicz error_free: 259800a2430fSAndrzej Pietrasiewicz kfree(stringtabs); 259900a2430fSAndrzej Pietrasiewicz error: 260000a2430fSAndrzej Pietrasiewicz kfree(_data); 260100a2430fSAndrzej Pietrasiewicz return -EINVAL; 260200a2430fSAndrzej Pietrasiewicz } 260300a2430fSAndrzej Pietrasiewicz 260400a2430fSAndrzej Pietrasiewicz 260500a2430fSAndrzej Pietrasiewicz /* Events handling and management *******************************************/ 260600a2430fSAndrzej Pietrasiewicz 260700a2430fSAndrzej Pietrasiewicz static void __ffs_event_add(struct ffs_data *ffs, 260800a2430fSAndrzej Pietrasiewicz enum usb_functionfs_event_type type) 260900a2430fSAndrzej Pietrasiewicz { 261000a2430fSAndrzej Pietrasiewicz enum usb_functionfs_event_type rem_type1, rem_type2 = type; 261100a2430fSAndrzej Pietrasiewicz int neg = 0; 261200a2430fSAndrzej Pietrasiewicz 261300a2430fSAndrzej Pietrasiewicz /* 261400a2430fSAndrzej Pietrasiewicz * Abort any unhandled setup 261500a2430fSAndrzej Pietrasiewicz * 261600a2430fSAndrzej Pietrasiewicz * We do not need to worry about some cmpxchg() changing value 261700a2430fSAndrzej Pietrasiewicz * of ffs->setup_state without holding the lock because when 261800a2430fSAndrzej Pietrasiewicz * state is FFS_SETUP_PENDING cmpxchg() in several places in 261900a2430fSAndrzej Pietrasiewicz * the source does nothing. 262000a2430fSAndrzej Pietrasiewicz */ 262100a2430fSAndrzej Pietrasiewicz if (ffs->setup_state == FFS_SETUP_PENDING) 262200a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_SETUP_CANCELLED; 262300a2430fSAndrzej Pietrasiewicz 262467913bbdSMichal Nazarewicz /* 262567913bbdSMichal Nazarewicz * Logic of this function guarantees that there are at most four pending 262667913bbdSMichal Nazarewicz * evens on ffs->ev.types queue. This is important because the queue 262767913bbdSMichal Nazarewicz * has space for four elements only and __ffs_ep0_read_events function 262867913bbdSMichal Nazarewicz * depends on that limit as well. If more event types are added, those 262967913bbdSMichal Nazarewicz * limits have to be revisited or guaranteed to still hold. 263067913bbdSMichal Nazarewicz */ 263100a2430fSAndrzej Pietrasiewicz switch (type) { 263200a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_RESUME: 263300a2430fSAndrzej Pietrasiewicz rem_type2 = FUNCTIONFS_SUSPEND; 263400a2430fSAndrzej Pietrasiewicz /* FALL THROUGH */ 263500a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_SUSPEND: 263600a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_SETUP: 263700a2430fSAndrzej Pietrasiewicz rem_type1 = type; 263800a2430fSAndrzej Pietrasiewicz /* Discard all similar events */ 263900a2430fSAndrzej Pietrasiewicz break; 264000a2430fSAndrzej Pietrasiewicz 264100a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_BIND: 264200a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_UNBIND: 264300a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_DISABLE: 264400a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_ENABLE: 264500a2430fSAndrzej Pietrasiewicz /* Discard everything other then power management. */ 264600a2430fSAndrzej Pietrasiewicz rem_type1 = FUNCTIONFS_SUSPEND; 264700a2430fSAndrzej Pietrasiewicz rem_type2 = FUNCTIONFS_RESUME; 264800a2430fSAndrzej Pietrasiewicz neg = 1; 264900a2430fSAndrzej Pietrasiewicz break; 265000a2430fSAndrzej Pietrasiewicz 265100a2430fSAndrzej Pietrasiewicz default: 2652fe00bcbfSMichal Nazarewicz WARN(1, "%d: unknown event, this should not happen\n", type); 2653fe00bcbfSMichal Nazarewicz return; 265400a2430fSAndrzej Pietrasiewicz } 265500a2430fSAndrzej Pietrasiewicz 265600a2430fSAndrzej Pietrasiewicz { 265700a2430fSAndrzej Pietrasiewicz u8 *ev = ffs->ev.types, *out = ev; 265800a2430fSAndrzej Pietrasiewicz unsigned n = ffs->ev.count; 265900a2430fSAndrzej Pietrasiewicz for (; n; --n, ++ev) 266000a2430fSAndrzej Pietrasiewicz if ((*ev == rem_type1 || *ev == rem_type2) == neg) 266100a2430fSAndrzej Pietrasiewicz *out++ = *ev; 266200a2430fSAndrzej Pietrasiewicz else 266300a2430fSAndrzej Pietrasiewicz pr_vdebug("purging event %d\n", *ev); 266400a2430fSAndrzej Pietrasiewicz ffs->ev.count = out - ffs->ev.types; 266500a2430fSAndrzej Pietrasiewicz } 266600a2430fSAndrzej Pietrasiewicz 266700a2430fSAndrzej Pietrasiewicz pr_vdebug("adding event %d\n", type); 266800a2430fSAndrzej Pietrasiewicz ffs->ev.types[ffs->ev.count++] = type; 266900a2430fSAndrzej Pietrasiewicz wake_up_locked(&ffs->ev.waitq); 26705e33f6fdSRobert Baldyga if (ffs->ffs_eventfd) 26715e33f6fdSRobert Baldyga eventfd_signal(ffs->ffs_eventfd, 1); 267200a2430fSAndrzej Pietrasiewicz } 267300a2430fSAndrzej Pietrasiewicz 267400a2430fSAndrzej Pietrasiewicz static void ffs_event_add(struct ffs_data *ffs, 267500a2430fSAndrzej Pietrasiewicz enum usb_functionfs_event_type type) 267600a2430fSAndrzej Pietrasiewicz { 267700a2430fSAndrzej Pietrasiewicz unsigned long flags; 267800a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&ffs->ev.waitq.lock, flags); 267900a2430fSAndrzej Pietrasiewicz __ffs_event_add(ffs, type); 268000a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); 268100a2430fSAndrzej Pietrasiewicz } 268200a2430fSAndrzej Pietrasiewicz 268300a2430fSAndrzej Pietrasiewicz /* Bind/unbind USB function hooks *******************************************/ 268400a2430fSAndrzej Pietrasiewicz 26856d5c1c77SRobert Baldyga static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address) 26866d5c1c77SRobert Baldyga { 26876d5c1c77SRobert Baldyga int i; 26886d5c1c77SRobert Baldyga 26896d5c1c77SRobert Baldyga for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i) 26906d5c1c77SRobert Baldyga if (ffs->eps_addrmap[i] == endpoint_address) 26916d5c1c77SRobert Baldyga return i; 26926d5c1c77SRobert Baldyga return -ENOENT; 26936d5c1c77SRobert Baldyga } 26946d5c1c77SRobert Baldyga 269500a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, 269600a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *desc, 269700a2430fSAndrzej Pietrasiewicz void *priv) 269800a2430fSAndrzej Pietrasiewicz { 269900a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *ds = (void *)desc; 270000a2430fSAndrzej Pietrasiewicz struct ffs_function *func = priv; 270100a2430fSAndrzej Pietrasiewicz struct ffs_ep *ffs_ep; 270285b06f5eSDan Carpenter unsigned ep_desc_id; 270385b06f5eSDan Carpenter int idx; 270400a2430fSAndrzej Pietrasiewicz static const char *speed_names[] = { "full", "high", "super" }; 270500a2430fSAndrzej Pietrasiewicz 270600a2430fSAndrzej Pietrasiewicz if (type != FFS_DESCRIPTOR) 270700a2430fSAndrzej Pietrasiewicz return 0; 270800a2430fSAndrzej Pietrasiewicz 270900a2430fSAndrzej Pietrasiewicz /* 271000a2430fSAndrzej Pietrasiewicz * If ss_descriptors is not NULL, we are reading super speed 271100a2430fSAndrzej Pietrasiewicz * descriptors; if hs_descriptors is not NULL, we are reading high 271200a2430fSAndrzej Pietrasiewicz * speed descriptors; otherwise, we are reading full speed 271300a2430fSAndrzej Pietrasiewicz * descriptors. 271400a2430fSAndrzej Pietrasiewicz */ 271500a2430fSAndrzej Pietrasiewicz if (func->function.ss_descriptors) { 271600a2430fSAndrzej Pietrasiewicz ep_desc_id = 2; 271700a2430fSAndrzej Pietrasiewicz func->function.ss_descriptors[(long)valuep] = desc; 271800a2430fSAndrzej Pietrasiewicz } else if (func->function.hs_descriptors) { 271900a2430fSAndrzej Pietrasiewicz ep_desc_id = 1; 272000a2430fSAndrzej Pietrasiewicz func->function.hs_descriptors[(long)valuep] = desc; 272100a2430fSAndrzej Pietrasiewicz } else { 272200a2430fSAndrzej Pietrasiewicz ep_desc_id = 0; 272300a2430fSAndrzej Pietrasiewicz func->function.fs_descriptors[(long)valuep] = desc; 272400a2430fSAndrzej Pietrasiewicz } 272500a2430fSAndrzej Pietrasiewicz 272600a2430fSAndrzej Pietrasiewicz if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) 272700a2430fSAndrzej Pietrasiewicz return 0; 272800a2430fSAndrzej Pietrasiewicz 27296d5c1c77SRobert Baldyga idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1; 27306d5c1c77SRobert Baldyga if (idx < 0) 27316d5c1c77SRobert Baldyga return idx; 27326d5c1c77SRobert Baldyga 273300a2430fSAndrzej Pietrasiewicz ffs_ep = func->eps + idx; 273400a2430fSAndrzej Pietrasiewicz 273500a2430fSAndrzej Pietrasiewicz if (unlikely(ffs_ep->descs[ep_desc_id])) { 273600a2430fSAndrzej Pietrasiewicz pr_err("two %sspeed descriptors for EP %d\n", 273700a2430fSAndrzej Pietrasiewicz speed_names[ep_desc_id], 273800a2430fSAndrzej Pietrasiewicz ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 273900a2430fSAndrzej Pietrasiewicz return -EINVAL; 274000a2430fSAndrzej Pietrasiewicz } 274100a2430fSAndrzej Pietrasiewicz ffs_ep->descs[ep_desc_id] = ds; 274200a2430fSAndrzej Pietrasiewicz 274300a2430fSAndrzej Pietrasiewicz ffs_dump_mem(": Original ep desc", ds, ds->bLength); 274400a2430fSAndrzej Pietrasiewicz if (ffs_ep->ep) { 274500a2430fSAndrzej Pietrasiewicz ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress; 274600a2430fSAndrzej Pietrasiewicz if (!ds->wMaxPacketSize) 274700a2430fSAndrzej Pietrasiewicz ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize; 274800a2430fSAndrzej Pietrasiewicz } else { 274900a2430fSAndrzej Pietrasiewicz struct usb_request *req; 275000a2430fSAndrzej Pietrasiewicz struct usb_ep *ep; 27511b0bf88fSRobert Baldyga u8 bEndpointAddress; 275200a2430fSAndrzej Pietrasiewicz 27531b0bf88fSRobert Baldyga /* 27541b0bf88fSRobert Baldyga * We back up bEndpointAddress because autoconfig overwrites 27551b0bf88fSRobert Baldyga * it with physical endpoint address. 27561b0bf88fSRobert Baldyga */ 27571b0bf88fSRobert Baldyga bEndpointAddress = ds->bEndpointAddress; 275800a2430fSAndrzej Pietrasiewicz pr_vdebug("autoconfig\n"); 275900a2430fSAndrzej Pietrasiewicz ep = usb_ep_autoconfig(func->gadget, ds); 276000a2430fSAndrzej Pietrasiewicz if (unlikely(!ep)) 276100a2430fSAndrzej Pietrasiewicz return -ENOTSUPP; 276200a2430fSAndrzej Pietrasiewicz ep->driver_data = func->eps + idx; 276300a2430fSAndrzej Pietrasiewicz 276400a2430fSAndrzej Pietrasiewicz req = usb_ep_alloc_request(ep, GFP_KERNEL); 276500a2430fSAndrzej Pietrasiewicz if (unlikely(!req)) 276600a2430fSAndrzej Pietrasiewicz return -ENOMEM; 276700a2430fSAndrzej Pietrasiewicz 276800a2430fSAndrzej Pietrasiewicz ffs_ep->ep = ep; 276900a2430fSAndrzej Pietrasiewicz ffs_ep->req = req; 277000a2430fSAndrzej Pietrasiewicz func->eps_revmap[ds->bEndpointAddress & 277100a2430fSAndrzej Pietrasiewicz USB_ENDPOINT_NUMBER_MASK] = idx + 1; 27721b0bf88fSRobert Baldyga /* 27731b0bf88fSRobert Baldyga * If we use virtual address mapping, we restore 27741b0bf88fSRobert Baldyga * original bEndpointAddress value. 27751b0bf88fSRobert Baldyga */ 27761b0bf88fSRobert Baldyga if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) 27771b0bf88fSRobert Baldyga ds->bEndpointAddress = bEndpointAddress; 277800a2430fSAndrzej Pietrasiewicz } 277900a2430fSAndrzej Pietrasiewicz ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); 278000a2430fSAndrzej Pietrasiewicz 278100a2430fSAndrzej Pietrasiewicz return 0; 278200a2430fSAndrzej Pietrasiewicz } 278300a2430fSAndrzej Pietrasiewicz 278400a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, 278500a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *desc, 278600a2430fSAndrzej Pietrasiewicz void *priv) 278700a2430fSAndrzej Pietrasiewicz { 278800a2430fSAndrzej Pietrasiewicz struct ffs_function *func = priv; 278900a2430fSAndrzej Pietrasiewicz unsigned idx; 279000a2430fSAndrzej Pietrasiewicz u8 newValue; 279100a2430fSAndrzej Pietrasiewicz 279200a2430fSAndrzej Pietrasiewicz switch (type) { 279300a2430fSAndrzej Pietrasiewicz default: 279400a2430fSAndrzej Pietrasiewicz case FFS_DESCRIPTOR: 279500a2430fSAndrzej Pietrasiewicz /* Handled in previous pass by __ffs_func_bind_do_descs() */ 279600a2430fSAndrzej Pietrasiewicz return 0; 279700a2430fSAndrzej Pietrasiewicz 279800a2430fSAndrzej Pietrasiewicz case FFS_INTERFACE: 279900a2430fSAndrzej Pietrasiewicz idx = *valuep; 280000a2430fSAndrzej Pietrasiewicz if (func->interfaces_nums[idx] < 0) { 280100a2430fSAndrzej Pietrasiewicz int id = usb_interface_id(func->conf, &func->function); 280200a2430fSAndrzej Pietrasiewicz if (unlikely(id < 0)) 280300a2430fSAndrzej Pietrasiewicz return id; 280400a2430fSAndrzej Pietrasiewicz func->interfaces_nums[idx] = id; 280500a2430fSAndrzej Pietrasiewicz } 280600a2430fSAndrzej Pietrasiewicz newValue = func->interfaces_nums[idx]; 280700a2430fSAndrzej Pietrasiewicz break; 280800a2430fSAndrzej Pietrasiewicz 280900a2430fSAndrzej Pietrasiewicz case FFS_STRING: 281000a2430fSAndrzej Pietrasiewicz /* String' IDs are allocated when fsf_data is bound to cdev */ 281100a2430fSAndrzej Pietrasiewicz newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id; 281200a2430fSAndrzej Pietrasiewicz break; 281300a2430fSAndrzej Pietrasiewicz 281400a2430fSAndrzej Pietrasiewicz case FFS_ENDPOINT: 281500a2430fSAndrzej Pietrasiewicz /* 281600a2430fSAndrzej Pietrasiewicz * USB_DT_ENDPOINT are handled in 281700a2430fSAndrzej Pietrasiewicz * __ffs_func_bind_do_descs(). 281800a2430fSAndrzej Pietrasiewicz */ 281900a2430fSAndrzej Pietrasiewicz if (desc->bDescriptorType == USB_DT_ENDPOINT) 282000a2430fSAndrzej Pietrasiewicz return 0; 282100a2430fSAndrzej Pietrasiewicz 282200a2430fSAndrzej Pietrasiewicz idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1; 282300a2430fSAndrzej Pietrasiewicz if (unlikely(!func->eps[idx].ep)) 282400a2430fSAndrzej Pietrasiewicz return -EINVAL; 282500a2430fSAndrzej Pietrasiewicz 282600a2430fSAndrzej Pietrasiewicz { 282700a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor **descs; 282800a2430fSAndrzej Pietrasiewicz descs = func->eps[idx].descs; 282900a2430fSAndrzej Pietrasiewicz newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress; 283000a2430fSAndrzej Pietrasiewicz } 283100a2430fSAndrzej Pietrasiewicz break; 283200a2430fSAndrzej Pietrasiewicz } 283300a2430fSAndrzej Pietrasiewicz 283400a2430fSAndrzej Pietrasiewicz pr_vdebug("%02x -> %02x\n", *valuep, newValue); 283500a2430fSAndrzej Pietrasiewicz *valuep = newValue; 283600a2430fSAndrzej Pietrasiewicz return 0; 283700a2430fSAndrzej Pietrasiewicz } 283800a2430fSAndrzej Pietrasiewicz 283900a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type, 284000a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *h, void *data, 284100a2430fSAndrzej Pietrasiewicz unsigned len, void *priv) 284200a2430fSAndrzej Pietrasiewicz { 284300a2430fSAndrzej Pietrasiewicz struct ffs_function *func = priv; 284400a2430fSAndrzej Pietrasiewicz u8 length = 0; 284500a2430fSAndrzej Pietrasiewicz 284600a2430fSAndrzej Pietrasiewicz switch (type) { 284700a2430fSAndrzej Pietrasiewicz case FFS_OS_DESC_EXT_COMPAT: { 284800a2430fSAndrzej Pietrasiewicz struct usb_ext_compat_desc *desc = data; 284900a2430fSAndrzej Pietrasiewicz struct usb_os_desc_table *t; 285000a2430fSAndrzej Pietrasiewicz 285100a2430fSAndrzej Pietrasiewicz t = &func->function.os_desc_table[desc->bFirstInterfaceNumber]; 285200a2430fSAndrzej Pietrasiewicz t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber]; 285300a2430fSAndrzej Pietrasiewicz memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID, 285400a2430fSAndrzej Pietrasiewicz ARRAY_SIZE(desc->CompatibleID) + 285500a2430fSAndrzej Pietrasiewicz ARRAY_SIZE(desc->SubCompatibleID)); 285600a2430fSAndrzej Pietrasiewicz length = sizeof(*desc); 285700a2430fSAndrzej Pietrasiewicz } 285800a2430fSAndrzej Pietrasiewicz break; 285900a2430fSAndrzej Pietrasiewicz case FFS_OS_DESC_EXT_PROP: { 286000a2430fSAndrzej Pietrasiewicz struct usb_ext_prop_desc *desc = data; 286100a2430fSAndrzej Pietrasiewicz struct usb_os_desc_table *t; 286200a2430fSAndrzej Pietrasiewicz struct usb_os_desc_ext_prop *ext_prop; 286300a2430fSAndrzej Pietrasiewicz char *ext_prop_name; 286400a2430fSAndrzej Pietrasiewicz char *ext_prop_data; 286500a2430fSAndrzej Pietrasiewicz 286600a2430fSAndrzej Pietrasiewicz t = &func->function.os_desc_table[h->interface]; 286700a2430fSAndrzej Pietrasiewicz t->if_id = func->interfaces_nums[h->interface]; 286800a2430fSAndrzej Pietrasiewicz 286900a2430fSAndrzej Pietrasiewicz ext_prop = func->ffs->ms_os_descs_ext_prop_avail; 287000a2430fSAndrzej Pietrasiewicz func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop); 287100a2430fSAndrzej Pietrasiewicz 287200a2430fSAndrzej Pietrasiewicz ext_prop->type = le32_to_cpu(desc->dwPropertyDataType); 287300a2430fSAndrzej Pietrasiewicz ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength); 2874c40619bbSVincent Pelletier ext_prop->data_len = le32_to_cpu(*(__le32 *) 287500a2430fSAndrzej Pietrasiewicz usb_ext_prop_data_len_ptr(data, ext_prop->name_len)); 287600a2430fSAndrzej Pietrasiewicz length = ext_prop->name_len + ext_prop->data_len + 14; 287700a2430fSAndrzej Pietrasiewicz 287800a2430fSAndrzej Pietrasiewicz ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail; 287900a2430fSAndrzej Pietrasiewicz func->ffs->ms_os_descs_ext_prop_name_avail += 288000a2430fSAndrzej Pietrasiewicz ext_prop->name_len; 288100a2430fSAndrzej Pietrasiewicz 288200a2430fSAndrzej Pietrasiewicz ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail; 288300a2430fSAndrzej Pietrasiewicz func->ffs->ms_os_descs_ext_prop_data_avail += 288400a2430fSAndrzej Pietrasiewicz ext_prop->data_len; 288500a2430fSAndrzej Pietrasiewicz memcpy(ext_prop_data, 288600a2430fSAndrzej Pietrasiewicz usb_ext_prop_data_ptr(data, ext_prop->name_len), 288700a2430fSAndrzej Pietrasiewicz ext_prop->data_len); 288800a2430fSAndrzej Pietrasiewicz /* unicode data reported to the host as "WCHAR"s */ 288900a2430fSAndrzej Pietrasiewicz switch (ext_prop->type) { 289000a2430fSAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE: 289100a2430fSAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE_ENV: 289200a2430fSAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE_LINK: 289300a2430fSAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE_MULTI: 289400a2430fSAndrzej Pietrasiewicz ext_prop->data_len *= 2; 289500a2430fSAndrzej Pietrasiewicz break; 289600a2430fSAndrzej Pietrasiewicz } 289700a2430fSAndrzej Pietrasiewicz ext_prop->data = ext_prop_data; 289800a2430fSAndrzej Pietrasiewicz 289900a2430fSAndrzej Pietrasiewicz memcpy(ext_prop_name, usb_ext_prop_name_ptr(data), 290000a2430fSAndrzej Pietrasiewicz ext_prop->name_len); 290100a2430fSAndrzej Pietrasiewicz /* property name reported to the host as "WCHAR"s */ 290200a2430fSAndrzej Pietrasiewicz ext_prop->name_len *= 2; 290300a2430fSAndrzej Pietrasiewicz ext_prop->name = ext_prop_name; 290400a2430fSAndrzej Pietrasiewicz 290500a2430fSAndrzej Pietrasiewicz t->os_desc->ext_prop_len += 290600a2430fSAndrzej Pietrasiewicz ext_prop->name_len + ext_prop->data_len + 14; 290700a2430fSAndrzej Pietrasiewicz ++t->os_desc->ext_prop_count; 290800a2430fSAndrzej Pietrasiewicz list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop); 290900a2430fSAndrzej Pietrasiewicz } 291000a2430fSAndrzej Pietrasiewicz break; 291100a2430fSAndrzej Pietrasiewicz default: 291200a2430fSAndrzej Pietrasiewicz pr_vdebug("unknown descriptor: %d\n", type); 291300a2430fSAndrzej Pietrasiewicz } 291400a2430fSAndrzej Pietrasiewicz 291500a2430fSAndrzej Pietrasiewicz return length; 291600a2430fSAndrzej Pietrasiewicz } 291700a2430fSAndrzej Pietrasiewicz 291800a2430fSAndrzej Pietrasiewicz static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, 291900a2430fSAndrzej Pietrasiewicz struct usb_configuration *c) 292000a2430fSAndrzej Pietrasiewicz { 292100a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 292200a2430fSAndrzej Pietrasiewicz struct f_fs_opts *ffs_opts = 292300a2430fSAndrzej Pietrasiewicz container_of(f->fi, struct f_fs_opts, func_inst); 292400a2430fSAndrzej Pietrasiewicz int ret; 292500a2430fSAndrzej Pietrasiewicz 292600a2430fSAndrzej Pietrasiewicz ENTER(); 292700a2430fSAndrzej Pietrasiewicz 292800a2430fSAndrzej Pietrasiewicz /* 292900a2430fSAndrzej Pietrasiewicz * Legacy gadget triggers binding in functionfs_ready_callback, 293000a2430fSAndrzej Pietrasiewicz * which already uses locking; taking the same lock here would 293100a2430fSAndrzej Pietrasiewicz * cause a deadlock. 293200a2430fSAndrzej Pietrasiewicz * 293300a2430fSAndrzej Pietrasiewicz * Configfs-enabled gadgets however do need ffs_dev_lock. 293400a2430fSAndrzej Pietrasiewicz */ 293500a2430fSAndrzej Pietrasiewicz if (!ffs_opts->no_configfs) 293600a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 293700a2430fSAndrzej Pietrasiewicz ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV; 293800a2430fSAndrzej Pietrasiewicz func->ffs = ffs_opts->dev->ffs_data; 293900a2430fSAndrzej Pietrasiewicz if (!ffs_opts->no_configfs) 294000a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 294100a2430fSAndrzej Pietrasiewicz if (ret) 294200a2430fSAndrzej Pietrasiewicz return ERR_PTR(ret); 294300a2430fSAndrzej Pietrasiewicz 294400a2430fSAndrzej Pietrasiewicz func->conf = c; 294500a2430fSAndrzej Pietrasiewicz func->gadget = c->cdev->gadget; 294600a2430fSAndrzej Pietrasiewicz 294700a2430fSAndrzej Pietrasiewicz /* 294800a2430fSAndrzej Pietrasiewicz * in drivers/usb/gadget/configfs.c:configfs_composite_bind() 294900a2430fSAndrzej Pietrasiewicz * configurations are bound in sequence with list_for_each_entry, 295000a2430fSAndrzej Pietrasiewicz * in each configuration its functions are bound in sequence 295100a2430fSAndrzej Pietrasiewicz * with list_for_each_entry, so we assume no race condition 295200a2430fSAndrzej Pietrasiewicz * with regard to ffs_opts->bound access 295300a2430fSAndrzej Pietrasiewicz */ 295400a2430fSAndrzej Pietrasiewicz if (!ffs_opts->refcnt) { 295500a2430fSAndrzej Pietrasiewicz ret = functionfs_bind(func->ffs, c->cdev); 295600a2430fSAndrzej Pietrasiewicz if (ret) 295700a2430fSAndrzej Pietrasiewicz return ERR_PTR(ret); 295800a2430fSAndrzej Pietrasiewicz } 295900a2430fSAndrzej Pietrasiewicz ffs_opts->refcnt++; 296000a2430fSAndrzej Pietrasiewicz func->function.strings = func->ffs->stringtabs; 296100a2430fSAndrzej Pietrasiewicz 296200a2430fSAndrzej Pietrasiewicz return ffs_opts; 296300a2430fSAndrzej Pietrasiewicz } 296400a2430fSAndrzej Pietrasiewicz 296500a2430fSAndrzej Pietrasiewicz static int _ffs_func_bind(struct usb_configuration *c, 296600a2430fSAndrzej Pietrasiewicz struct usb_function *f) 296700a2430fSAndrzej Pietrasiewicz { 296800a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 296900a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 297000a2430fSAndrzej Pietrasiewicz 297100a2430fSAndrzej Pietrasiewicz const int full = !!func->ffs->fs_descs_count; 29726cf439e0SJack Pham const int high = !!func->ffs->hs_descs_count; 29736cf439e0SJack Pham const int super = !!func->ffs->ss_descs_count; 297400a2430fSAndrzej Pietrasiewicz 297500a2430fSAndrzej Pietrasiewicz int fs_len, hs_len, ss_len, ret, i; 29760015f915SDan Carpenter struct ffs_ep *eps_ptr; 297700a2430fSAndrzej Pietrasiewicz 297800a2430fSAndrzej Pietrasiewicz /* Make it a single chunk, less management later on */ 297900a2430fSAndrzej Pietrasiewicz vla_group(d); 298000a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count); 298100a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs, 298200a2430fSAndrzej Pietrasiewicz full ? ffs->fs_descs_count + 1 : 0); 298300a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs, 298400a2430fSAndrzej Pietrasiewicz high ? ffs->hs_descs_count + 1 : 0); 298500a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, 298600a2430fSAndrzej Pietrasiewicz super ? ffs->ss_descs_count + 1 : 0); 298700a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, short, inums, ffs->interfaces_count); 298800a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table, 298900a2430fSAndrzej Pietrasiewicz c->cdev->use_os_string ? ffs->interfaces_count : 0); 299000a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, char[16], ext_compat, 299100a2430fSAndrzej Pietrasiewicz c->cdev->use_os_string ? ffs->interfaces_count : 0); 299200a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_os_desc, os_desc, 299300a2430fSAndrzej Pietrasiewicz c->cdev->use_os_string ? ffs->interfaces_count : 0); 299400a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop, 299500a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_count); 299600a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, char, ext_prop_name, 299700a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_name_len); 299800a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, char, ext_prop_data, 299900a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_data_len); 300000a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); 300100a2430fSAndrzej Pietrasiewicz char *vlabuf; 300200a2430fSAndrzej Pietrasiewicz 300300a2430fSAndrzej Pietrasiewicz ENTER(); 300400a2430fSAndrzej Pietrasiewicz 300500a2430fSAndrzej Pietrasiewicz /* Has descriptors only for speeds gadget does not support */ 300600a2430fSAndrzej Pietrasiewicz if (unlikely(!(full | high | super))) 300700a2430fSAndrzej Pietrasiewicz return -ENOTSUPP; 300800a2430fSAndrzej Pietrasiewicz 300900a2430fSAndrzej Pietrasiewicz /* Allocate a single chunk, less management later on */ 301000a2430fSAndrzej Pietrasiewicz vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL); 301100a2430fSAndrzej Pietrasiewicz if (unlikely(!vlabuf)) 301200a2430fSAndrzej Pietrasiewicz return -ENOMEM; 301300a2430fSAndrzej Pietrasiewicz 301400a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop); 301500a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_name_avail = 301600a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, ext_prop_name); 301700a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_data_avail = 301800a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, ext_prop_data); 301900a2430fSAndrzej Pietrasiewicz 302000a2430fSAndrzej Pietrasiewicz /* Copy descriptors */ 302100a2430fSAndrzej Pietrasiewicz memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, 302200a2430fSAndrzej Pietrasiewicz ffs->raw_descs_length); 302300a2430fSAndrzej Pietrasiewicz 302400a2430fSAndrzej Pietrasiewicz memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); 30250015f915SDan Carpenter eps_ptr = vla_ptr(vlabuf, d, eps); 30260015f915SDan Carpenter for (i = 0; i < ffs->eps_count; i++) 30270015f915SDan Carpenter eps_ptr[i].num = -1; 302800a2430fSAndrzej Pietrasiewicz 302900a2430fSAndrzej Pietrasiewicz /* Save pointers 303000a2430fSAndrzej Pietrasiewicz * d_eps == vlabuf, func->eps used to kfree vlabuf later 303100a2430fSAndrzej Pietrasiewicz */ 303200a2430fSAndrzej Pietrasiewicz func->eps = vla_ptr(vlabuf, d, eps); 303300a2430fSAndrzej Pietrasiewicz func->interfaces_nums = vla_ptr(vlabuf, d, inums); 303400a2430fSAndrzej Pietrasiewicz 303500a2430fSAndrzej Pietrasiewicz /* 303600a2430fSAndrzej Pietrasiewicz * Go through all the endpoint descriptors and allocate 303700a2430fSAndrzej Pietrasiewicz * endpoints first, so that later we can rewrite the endpoint 303800a2430fSAndrzej Pietrasiewicz * numbers without worrying that it may be described later on. 303900a2430fSAndrzej Pietrasiewicz */ 304000a2430fSAndrzej Pietrasiewicz if (likely(full)) { 304100a2430fSAndrzej Pietrasiewicz func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); 304200a2430fSAndrzej Pietrasiewicz fs_len = ffs_do_descs(ffs->fs_descs_count, 304300a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs), 304400a2430fSAndrzej Pietrasiewicz d_raw_descs__sz, 304500a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_descs, func); 304600a2430fSAndrzej Pietrasiewicz if (unlikely(fs_len < 0)) { 304700a2430fSAndrzej Pietrasiewicz ret = fs_len; 304800a2430fSAndrzej Pietrasiewicz goto error; 304900a2430fSAndrzej Pietrasiewicz } 305000a2430fSAndrzej Pietrasiewicz } else { 305100a2430fSAndrzej Pietrasiewicz fs_len = 0; 305200a2430fSAndrzej Pietrasiewicz } 305300a2430fSAndrzej Pietrasiewicz 305400a2430fSAndrzej Pietrasiewicz if (likely(high)) { 305500a2430fSAndrzej Pietrasiewicz func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); 305600a2430fSAndrzej Pietrasiewicz hs_len = ffs_do_descs(ffs->hs_descs_count, 305700a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs) + fs_len, 305800a2430fSAndrzej Pietrasiewicz d_raw_descs__sz - fs_len, 305900a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_descs, func); 306000a2430fSAndrzej Pietrasiewicz if (unlikely(hs_len < 0)) { 306100a2430fSAndrzej Pietrasiewicz ret = hs_len; 306200a2430fSAndrzej Pietrasiewicz goto error; 306300a2430fSAndrzej Pietrasiewicz } 306400a2430fSAndrzej Pietrasiewicz } else { 306500a2430fSAndrzej Pietrasiewicz hs_len = 0; 306600a2430fSAndrzej Pietrasiewicz } 306700a2430fSAndrzej Pietrasiewicz 306800a2430fSAndrzej Pietrasiewicz if (likely(super)) { 306900a2430fSAndrzej Pietrasiewicz func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs); 307000a2430fSAndrzej Pietrasiewicz ss_len = ffs_do_descs(ffs->ss_descs_count, 307100a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, 307200a2430fSAndrzej Pietrasiewicz d_raw_descs__sz - fs_len - hs_len, 307300a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_descs, func); 307400a2430fSAndrzej Pietrasiewicz if (unlikely(ss_len < 0)) { 307500a2430fSAndrzej Pietrasiewicz ret = ss_len; 307600a2430fSAndrzej Pietrasiewicz goto error; 307700a2430fSAndrzej Pietrasiewicz } 307800a2430fSAndrzej Pietrasiewicz } else { 307900a2430fSAndrzej Pietrasiewicz ss_len = 0; 308000a2430fSAndrzej Pietrasiewicz } 308100a2430fSAndrzej Pietrasiewicz 308200a2430fSAndrzej Pietrasiewicz /* 308300a2430fSAndrzej Pietrasiewicz * Now handle interface numbers allocation and interface and 308400a2430fSAndrzej Pietrasiewicz * endpoint numbers rewriting. We can do that in one go 308500a2430fSAndrzej Pietrasiewicz * now. 308600a2430fSAndrzej Pietrasiewicz */ 308700a2430fSAndrzej Pietrasiewicz ret = ffs_do_descs(ffs->fs_descs_count + 308800a2430fSAndrzej Pietrasiewicz (high ? ffs->hs_descs_count : 0) + 308900a2430fSAndrzej Pietrasiewicz (super ? ffs->ss_descs_count : 0), 309000a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz, 309100a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_nums, func); 309200a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 309300a2430fSAndrzej Pietrasiewicz goto error; 309400a2430fSAndrzej Pietrasiewicz 309500a2430fSAndrzej Pietrasiewicz func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table); 3096c6010c8bSJim Lin if (c->cdev->use_os_string) { 309700a2430fSAndrzej Pietrasiewicz for (i = 0; i < ffs->interfaces_count; ++i) { 309800a2430fSAndrzej Pietrasiewicz struct usb_os_desc *desc; 309900a2430fSAndrzej Pietrasiewicz 310000a2430fSAndrzej Pietrasiewicz desc = func->function.os_desc_table[i].os_desc = 310100a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, os_desc) + 310200a2430fSAndrzej Pietrasiewicz i * sizeof(struct usb_os_desc); 310300a2430fSAndrzej Pietrasiewicz desc->ext_compat_id = 310400a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, ext_compat) + i * 16; 310500a2430fSAndrzej Pietrasiewicz INIT_LIST_HEAD(&desc->ext_prop); 310600a2430fSAndrzej Pietrasiewicz } 310700a2430fSAndrzej Pietrasiewicz ret = ffs_do_os_descs(ffs->ms_os_descs_count, 310800a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs) + 310900a2430fSAndrzej Pietrasiewicz fs_len + hs_len + ss_len, 3110c6010c8bSJim Lin d_raw_descs__sz - fs_len - hs_len - 3111c6010c8bSJim Lin ss_len, 311200a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_os_desc, func); 311300a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 311400a2430fSAndrzej Pietrasiewicz goto error; 3115c6010c8bSJim Lin } 311600a2430fSAndrzej Pietrasiewicz func->function.os_desc_n = 311700a2430fSAndrzej Pietrasiewicz c->cdev->use_os_string ? ffs->interfaces_count : 0; 311800a2430fSAndrzej Pietrasiewicz 311900a2430fSAndrzej Pietrasiewicz /* And we're done */ 312000a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs, FUNCTIONFS_BIND); 312100a2430fSAndrzej Pietrasiewicz return 0; 312200a2430fSAndrzej Pietrasiewicz 312300a2430fSAndrzej Pietrasiewicz error: 312400a2430fSAndrzej Pietrasiewicz /* XXX Do we need to release all claimed endpoints here? */ 312500a2430fSAndrzej Pietrasiewicz return ret; 312600a2430fSAndrzej Pietrasiewicz } 312700a2430fSAndrzej Pietrasiewicz 312800a2430fSAndrzej Pietrasiewicz static int ffs_func_bind(struct usb_configuration *c, 312900a2430fSAndrzej Pietrasiewicz struct usb_function *f) 313000a2430fSAndrzej Pietrasiewicz { 313100a2430fSAndrzej Pietrasiewicz struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); 313255d81121SRobert Baldyga struct ffs_function *func = ffs_func_from_usb(f); 313355d81121SRobert Baldyga int ret; 313400a2430fSAndrzej Pietrasiewicz 313500a2430fSAndrzej Pietrasiewicz if (IS_ERR(ffs_opts)) 313600a2430fSAndrzej Pietrasiewicz return PTR_ERR(ffs_opts); 313700a2430fSAndrzej Pietrasiewicz 313855d81121SRobert Baldyga ret = _ffs_func_bind(c, f); 313955d81121SRobert Baldyga if (ret && !--ffs_opts->refcnt) 314055d81121SRobert Baldyga functionfs_unbind(func->ffs); 314155d81121SRobert Baldyga 314255d81121SRobert Baldyga return ret; 314300a2430fSAndrzej Pietrasiewicz } 314400a2430fSAndrzej Pietrasiewicz 314500a2430fSAndrzej Pietrasiewicz 314600a2430fSAndrzej Pietrasiewicz /* Other USB function hooks *************************************************/ 314700a2430fSAndrzej Pietrasiewicz 314818d6b32fSRobert Baldyga static void ffs_reset_work(struct work_struct *work) 314918d6b32fSRobert Baldyga { 315018d6b32fSRobert Baldyga struct ffs_data *ffs = container_of(work, 315118d6b32fSRobert Baldyga struct ffs_data, reset_work); 315218d6b32fSRobert Baldyga ffs_data_reset(ffs); 315318d6b32fSRobert Baldyga } 315418d6b32fSRobert Baldyga 315500a2430fSAndrzej Pietrasiewicz static int ffs_func_set_alt(struct usb_function *f, 315600a2430fSAndrzej Pietrasiewicz unsigned interface, unsigned alt) 315700a2430fSAndrzej Pietrasiewicz { 315800a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 315900a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 316000a2430fSAndrzej Pietrasiewicz int ret = 0, intf; 316100a2430fSAndrzej Pietrasiewicz 316200a2430fSAndrzej Pietrasiewicz if (alt != (unsigned)-1) { 316300a2430fSAndrzej Pietrasiewicz intf = ffs_func_revmap_intf(func, interface); 316400a2430fSAndrzej Pietrasiewicz if (unlikely(intf < 0)) 316500a2430fSAndrzej Pietrasiewicz return intf; 316600a2430fSAndrzej Pietrasiewicz } 316700a2430fSAndrzej Pietrasiewicz 316800a2430fSAndrzej Pietrasiewicz if (ffs->func) 316900a2430fSAndrzej Pietrasiewicz ffs_func_eps_disable(ffs->func); 317000a2430fSAndrzej Pietrasiewicz 317118d6b32fSRobert Baldyga if (ffs->state == FFS_DEACTIVATED) { 317218d6b32fSRobert Baldyga ffs->state = FFS_CLOSING; 317318d6b32fSRobert Baldyga INIT_WORK(&ffs->reset_work, ffs_reset_work); 317418d6b32fSRobert Baldyga schedule_work(&ffs->reset_work); 317518d6b32fSRobert Baldyga return -ENODEV; 317618d6b32fSRobert Baldyga } 317718d6b32fSRobert Baldyga 317800a2430fSAndrzej Pietrasiewicz if (ffs->state != FFS_ACTIVE) 317900a2430fSAndrzej Pietrasiewicz return -ENODEV; 318000a2430fSAndrzej Pietrasiewicz 318100a2430fSAndrzej Pietrasiewicz if (alt == (unsigned)-1) { 318200a2430fSAndrzej Pietrasiewicz ffs->func = NULL; 318300a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs, FUNCTIONFS_DISABLE); 318400a2430fSAndrzej Pietrasiewicz return 0; 318500a2430fSAndrzej Pietrasiewicz } 318600a2430fSAndrzej Pietrasiewicz 318700a2430fSAndrzej Pietrasiewicz ffs->func = func; 318800a2430fSAndrzej Pietrasiewicz ret = ffs_func_eps_enable(func); 318900a2430fSAndrzej Pietrasiewicz if (likely(ret >= 0)) 319000a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs, FUNCTIONFS_ENABLE); 319100a2430fSAndrzej Pietrasiewicz return ret; 319200a2430fSAndrzej Pietrasiewicz } 319300a2430fSAndrzej Pietrasiewicz 319400a2430fSAndrzej Pietrasiewicz static void ffs_func_disable(struct usb_function *f) 319500a2430fSAndrzej Pietrasiewicz { 319600a2430fSAndrzej Pietrasiewicz ffs_func_set_alt(f, 0, (unsigned)-1); 319700a2430fSAndrzej Pietrasiewicz } 319800a2430fSAndrzej Pietrasiewicz 319900a2430fSAndrzej Pietrasiewicz static int ffs_func_setup(struct usb_function *f, 320000a2430fSAndrzej Pietrasiewicz const struct usb_ctrlrequest *creq) 320100a2430fSAndrzej Pietrasiewicz { 320200a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 320300a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 320400a2430fSAndrzej Pietrasiewicz unsigned long flags; 320500a2430fSAndrzej Pietrasiewicz int ret; 320600a2430fSAndrzej Pietrasiewicz 320700a2430fSAndrzej Pietrasiewicz ENTER(); 320800a2430fSAndrzej Pietrasiewicz 320900a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); 321000a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); 321100a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); 321200a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex)); 321300a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength)); 321400a2430fSAndrzej Pietrasiewicz 321500a2430fSAndrzej Pietrasiewicz /* 321600a2430fSAndrzej Pietrasiewicz * Most requests directed to interface go through here 321700a2430fSAndrzej Pietrasiewicz * (notable exceptions are set/get interface) so we need to 321800a2430fSAndrzej Pietrasiewicz * handle them. All other either handled by composite or 321900a2430fSAndrzej Pietrasiewicz * passed to usb_configuration->setup() (if one is set). No 322000a2430fSAndrzej Pietrasiewicz * matter, we will handle requests directed to endpoint here 322154dfce6dSFelix Hädicke * as well (as it's straightforward). Other request recipient 322254dfce6dSFelix Hädicke * types are only handled when the user flag FUNCTIONFS_ALL_CTRL_RECIP 322354dfce6dSFelix Hädicke * is being used. 322400a2430fSAndrzej Pietrasiewicz */ 322500a2430fSAndrzej Pietrasiewicz if (ffs->state != FFS_ACTIVE) 322600a2430fSAndrzej Pietrasiewicz return -ENODEV; 322700a2430fSAndrzej Pietrasiewicz 322800a2430fSAndrzej Pietrasiewicz switch (creq->bRequestType & USB_RECIP_MASK) { 322900a2430fSAndrzej Pietrasiewicz case USB_RECIP_INTERFACE: 323000a2430fSAndrzej Pietrasiewicz ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex)); 323100a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 323200a2430fSAndrzej Pietrasiewicz return ret; 323300a2430fSAndrzej Pietrasiewicz break; 323400a2430fSAndrzej Pietrasiewicz 323500a2430fSAndrzej Pietrasiewicz case USB_RECIP_ENDPOINT: 323600a2430fSAndrzej Pietrasiewicz ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex)); 323700a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 323800a2430fSAndrzej Pietrasiewicz return ret; 32391b0bf88fSRobert Baldyga if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) 32401b0bf88fSRobert Baldyga ret = func->ffs->eps_addrmap[ret]; 324100a2430fSAndrzej Pietrasiewicz break; 324200a2430fSAndrzej Pietrasiewicz 324300a2430fSAndrzej Pietrasiewicz default: 324454dfce6dSFelix Hädicke if (func->ffs->user_flags & FUNCTIONFS_ALL_CTRL_RECIP) 324554dfce6dSFelix Hädicke ret = le16_to_cpu(creq->wIndex); 324654dfce6dSFelix Hädicke else 324700a2430fSAndrzej Pietrasiewicz return -EOPNOTSUPP; 324800a2430fSAndrzej Pietrasiewicz } 324900a2430fSAndrzej Pietrasiewicz 325000a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&ffs->ev.waitq.lock, flags); 325100a2430fSAndrzej Pietrasiewicz ffs->ev.setup = *creq; 325200a2430fSAndrzej Pietrasiewicz ffs->ev.setup.wIndex = cpu_to_le16(ret); 325300a2430fSAndrzej Pietrasiewicz __ffs_event_add(ffs, FUNCTIONFS_SETUP); 325400a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); 325500a2430fSAndrzej Pietrasiewicz 3256946ef68aSLars-Peter Clausen return USB_GADGET_DELAYED_STATUS; 325700a2430fSAndrzej Pietrasiewicz } 325800a2430fSAndrzej Pietrasiewicz 325954dfce6dSFelix Hädicke static bool ffs_func_req_match(struct usb_function *f, 32601a00b457SFelix Hädicke const struct usb_ctrlrequest *creq, 32611a00b457SFelix Hädicke bool config0) 326254dfce6dSFelix Hädicke { 326354dfce6dSFelix Hädicke struct ffs_function *func = ffs_func_from_usb(f); 326454dfce6dSFelix Hädicke 32654368c28aSFelix Hädicke if (config0 && !(func->ffs->user_flags & FUNCTIONFS_CONFIG0_SETUP)) 32661a00b457SFelix Hädicke return false; 32671a00b457SFelix Hädicke 326854dfce6dSFelix Hädicke switch (creq->bRequestType & USB_RECIP_MASK) { 326954dfce6dSFelix Hädicke case USB_RECIP_INTERFACE: 327005e78c69SFelix Hädicke return (ffs_func_revmap_intf(func, 327105e78c69SFelix Hädicke le16_to_cpu(creq->wIndex)) >= 0); 327254dfce6dSFelix Hädicke case USB_RECIP_ENDPOINT: 327305e78c69SFelix Hädicke return (ffs_func_revmap_ep(func, 327405e78c69SFelix Hädicke le16_to_cpu(creq->wIndex)) >= 0); 327554dfce6dSFelix Hädicke default: 327654dfce6dSFelix Hädicke return (bool) (func->ffs->user_flags & 327754dfce6dSFelix Hädicke FUNCTIONFS_ALL_CTRL_RECIP); 327854dfce6dSFelix Hädicke } 327954dfce6dSFelix Hädicke } 328054dfce6dSFelix Hädicke 328100a2430fSAndrzej Pietrasiewicz static void ffs_func_suspend(struct usb_function *f) 328200a2430fSAndrzej Pietrasiewicz { 328300a2430fSAndrzej Pietrasiewicz ENTER(); 328400a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); 328500a2430fSAndrzej Pietrasiewicz } 328600a2430fSAndrzej Pietrasiewicz 328700a2430fSAndrzej Pietrasiewicz static void ffs_func_resume(struct usb_function *f) 328800a2430fSAndrzej Pietrasiewicz { 328900a2430fSAndrzej Pietrasiewicz ENTER(); 329000a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); 329100a2430fSAndrzej Pietrasiewicz } 329200a2430fSAndrzej Pietrasiewicz 329300a2430fSAndrzej Pietrasiewicz 329400a2430fSAndrzej Pietrasiewicz /* Endpoint and interface numbers reverse mapping ***************************/ 329500a2430fSAndrzej Pietrasiewicz 329600a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_ep(struct ffs_function *func, u8 num) 329700a2430fSAndrzej Pietrasiewicz { 329800a2430fSAndrzej Pietrasiewicz num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK]; 329900a2430fSAndrzej Pietrasiewicz return num ? num : -EDOM; 330000a2430fSAndrzej Pietrasiewicz } 330100a2430fSAndrzej Pietrasiewicz 330200a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf) 330300a2430fSAndrzej Pietrasiewicz { 330400a2430fSAndrzej Pietrasiewicz short *nums = func->interfaces_nums; 330500a2430fSAndrzej Pietrasiewicz unsigned count = func->ffs->interfaces_count; 330600a2430fSAndrzej Pietrasiewicz 330700a2430fSAndrzej Pietrasiewicz for (; count; --count, ++nums) { 330800a2430fSAndrzej Pietrasiewicz if (*nums >= 0 && *nums == intf) 330900a2430fSAndrzej Pietrasiewicz return nums - func->interfaces_nums; 331000a2430fSAndrzej Pietrasiewicz } 331100a2430fSAndrzej Pietrasiewicz 331200a2430fSAndrzej Pietrasiewicz return -EDOM; 331300a2430fSAndrzej Pietrasiewicz } 331400a2430fSAndrzej Pietrasiewicz 331500a2430fSAndrzej Pietrasiewicz 331600a2430fSAndrzej Pietrasiewicz /* Devices management *******************************************************/ 331700a2430fSAndrzej Pietrasiewicz 331800a2430fSAndrzej Pietrasiewicz static LIST_HEAD(ffs_devices); 331900a2430fSAndrzej Pietrasiewicz 332000a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_do_find_dev(const char *name) 332100a2430fSAndrzej Pietrasiewicz { 332200a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 332300a2430fSAndrzej Pietrasiewicz 3324ea920bb4SMichal Nazarewicz if (!name) 3325ea920bb4SMichal Nazarewicz return NULL; 3326ea920bb4SMichal Nazarewicz 332700a2430fSAndrzej Pietrasiewicz list_for_each_entry(dev, &ffs_devices, entry) { 332800a2430fSAndrzej Pietrasiewicz if (strcmp(dev->name, name) == 0) 332900a2430fSAndrzej Pietrasiewicz return dev; 333000a2430fSAndrzej Pietrasiewicz } 333100a2430fSAndrzej Pietrasiewicz 333200a2430fSAndrzej Pietrasiewicz return NULL; 333300a2430fSAndrzej Pietrasiewicz } 333400a2430fSAndrzej Pietrasiewicz 333500a2430fSAndrzej Pietrasiewicz /* 333600a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 333700a2430fSAndrzej Pietrasiewicz */ 333800a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_get_single_dev(void) 333900a2430fSAndrzej Pietrasiewicz { 334000a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 334100a2430fSAndrzej Pietrasiewicz 334200a2430fSAndrzej Pietrasiewicz if (list_is_singular(&ffs_devices)) { 334300a2430fSAndrzej Pietrasiewicz dev = list_first_entry(&ffs_devices, struct ffs_dev, entry); 334400a2430fSAndrzej Pietrasiewicz if (dev->single) 334500a2430fSAndrzej Pietrasiewicz return dev; 334600a2430fSAndrzej Pietrasiewicz } 334700a2430fSAndrzej Pietrasiewicz 334800a2430fSAndrzej Pietrasiewicz return NULL; 334900a2430fSAndrzej Pietrasiewicz } 335000a2430fSAndrzej Pietrasiewicz 335100a2430fSAndrzej Pietrasiewicz /* 335200a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 335300a2430fSAndrzej Pietrasiewicz */ 335400a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_find_dev(const char *name) 335500a2430fSAndrzej Pietrasiewicz { 335600a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 335700a2430fSAndrzej Pietrasiewicz 335800a2430fSAndrzej Pietrasiewicz dev = _ffs_get_single_dev(); 335900a2430fSAndrzej Pietrasiewicz if (dev) 336000a2430fSAndrzej Pietrasiewicz return dev; 336100a2430fSAndrzej Pietrasiewicz 336200a2430fSAndrzej Pietrasiewicz return _ffs_do_find_dev(name); 336300a2430fSAndrzej Pietrasiewicz } 336400a2430fSAndrzej Pietrasiewicz 336500a2430fSAndrzej Pietrasiewicz /* Configfs support *********************************************************/ 336600a2430fSAndrzej Pietrasiewicz 336700a2430fSAndrzej Pietrasiewicz static inline struct f_fs_opts *to_ffs_opts(struct config_item *item) 336800a2430fSAndrzej Pietrasiewicz { 336900a2430fSAndrzej Pietrasiewicz return container_of(to_config_group(item), struct f_fs_opts, 337000a2430fSAndrzej Pietrasiewicz func_inst.group); 337100a2430fSAndrzej Pietrasiewicz } 337200a2430fSAndrzej Pietrasiewicz 337300a2430fSAndrzej Pietrasiewicz static void ffs_attr_release(struct config_item *item) 337400a2430fSAndrzej Pietrasiewicz { 337500a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts = to_ffs_opts(item); 337600a2430fSAndrzej Pietrasiewicz 337700a2430fSAndrzej Pietrasiewicz usb_put_function_instance(&opts->func_inst); 337800a2430fSAndrzej Pietrasiewicz } 337900a2430fSAndrzej Pietrasiewicz 338000a2430fSAndrzej Pietrasiewicz static struct configfs_item_operations ffs_item_ops = { 338100a2430fSAndrzej Pietrasiewicz .release = ffs_attr_release, 338200a2430fSAndrzej Pietrasiewicz }; 338300a2430fSAndrzej Pietrasiewicz 338497363902SBhumika Goyal static const struct config_item_type ffs_func_type = { 338500a2430fSAndrzej Pietrasiewicz .ct_item_ops = &ffs_item_ops, 338600a2430fSAndrzej Pietrasiewicz .ct_owner = THIS_MODULE, 338700a2430fSAndrzej Pietrasiewicz }; 338800a2430fSAndrzej Pietrasiewicz 338900a2430fSAndrzej Pietrasiewicz 339000a2430fSAndrzej Pietrasiewicz /* Function registration interface ******************************************/ 339100a2430fSAndrzej Pietrasiewicz 339200a2430fSAndrzej Pietrasiewicz static void ffs_free_inst(struct usb_function_instance *f) 339300a2430fSAndrzej Pietrasiewicz { 339400a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts; 339500a2430fSAndrzej Pietrasiewicz 339600a2430fSAndrzej Pietrasiewicz opts = to_f_fs_opts(f); 339700a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 339800a2430fSAndrzej Pietrasiewicz _ffs_free_dev(opts->dev); 339900a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 340000a2430fSAndrzej Pietrasiewicz kfree(opts); 340100a2430fSAndrzej Pietrasiewicz } 340200a2430fSAndrzej Pietrasiewicz 340300a2430fSAndrzej Pietrasiewicz static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) 340400a2430fSAndrzej Pietrasiewicz { 3405ea920bb4SMichal Nazarewicz if (strlen(name) >= FIELD_SIZEOF(struct ffs_dev, name)) 340600a2430fSAndrzej Pietrasiewicz return -ENAMETOOLONG; 3407ea920bb4SMichal Nazarewicz return ffs_name_dev(to_f_fs_opts(fi)->dev, name); 340800a2430fSAndrzej Pietrasiewicz } 340900a2430fSAndrzej Pietrasiewicz 341000a2430fSAndrzej Pietrasiewicz static struct usb_function_instance *ffs_alloc_inst(void) 341100a2430fSAndrzej Pietrasiewicz { 341200a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts; 341300a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 341400a2430fSAndrzej Pietrasiewicz 341500a2430fSAndrzej Pietrasiewicz opts = kzalloc(sizeof(*opts), GFP_KERNEL); 341600a2430fSAndrzej Pietrasiewicz if (!opts) 341700a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 341800a2430fSAndrzej Pietrasiewicz 341900a2430fSAndrzej Pietrasiewicz opts->func_inst.set_inst_name = ffs_set_inst_name; 342000a2430fSAndrzej Pietrasiewicz opts->func_inst.free_func_inst = ffs_free_inst; 342100a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 342200a2430fSAndrzej Pietrasiewicz dev = _ffs_alloc_dev(); 342300a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 342400a2430fSAndrzej Pietrasiewicz if (IS_ERR(dev)) { 342500a2430fSAndrzej Pietrasiewicz kfree(opts); 342600a2430fSAndrzej Pietrasiewicz return ERR_CAST(dev); 342700a2430fSAndrzej Pietrasiewicz } 342800a2430fSAndrzej Pietrasiewicz opts->dev = dev; 342900a2430fSAndrzej Pietrasiewicz dev->opts = opts; 343000a2430fSAndrzej Pietrasiewicz 343100a2430fSAndrzej Pietrasiewicz config_group_init_type_name(&opts->func_inst.group, "", 343200a2430fSAndrzej Pietrasiewicz &ffs_func_type); 343300a2430fSAndrzej Pietrasiewicz return &opts->func_inst; 343400a2430fSAndrzej Pietrasiewicz } 343500a2430fSAndrzej Pietrasiewicz 343600a2430fSAndrzej Pietrasiewicz static void ffs_free(struct usb_function *f) 343700a2430fSAndrzej Pietrasiewicz { 343800a2430fSAndrzej Pietrasiewicz kfree(ffs_func_from_usb(f)); 343900a2430fSAndrzej Pietrasiewicz } 344000a2430fSAndrzej Pietrasiewicz 344100a2430fSAndrzej Pietrasiewicz static void ffs_func_unbind(struct usb_configuration *c, 344200a2430fSAndrzej Pietrasiewicz struct usb_function *f) 344300a2430fSAndrzej Pietrasiewicz { 344400a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 344500a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 344600a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts = 344700a2430fSAndrzej Pietrasiewicz container_of(f->fi, struct f_fs_opts, func_inst); 344800a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep = func->eps; 344900a2430fSAndrzej Pietrasiewicz unsigned count = ffs->eps_count; 345000a2430fSAndrzej Pietrasiewicz unsigned long flags; 345100a2430fSAndrzej Pietrasiewicz 345200a2430fSAndrzej Pietrasiewicz ENTER(); 345300a2430fSAndrzej Pietrasiewicz if (ffs->func == func) { 345400a2430fSAndrzej Pietrasiewicz ffs_func_eps_disable(func); 345500a2430fSAndrzej Pietrasiewicz ffs->func = NULL; 345600a2430fSAndrzej Pietrasiewicz } 345700a2430fSAndrzej Pietrasiewicz 345800a2430fSAndrzej Pietrasiewicz if (!--opts->refcnt) 345900a2430fSAndrzej Pietrasiewicz functionfs_unbind(ffs); 346000a2430fSAndrzej Pietrasiewicz 346100a2430fSAndrzej Pietrasiewicz /* cleanup after autoconfig */ 346200a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&func->ffs->eps_lock, flags); 346308f37148SVincent Pelletier while (count--) { 346400a2430fSAndrzej Pietrasiewicz if (ep->ep && ep->req) 346500a2430fSAndrzej Pietrasiewicz usb_ep_free_request(ep->ep, ep->req); 346600a2430fSAndrzej Pietrasiewicz ep->req = NULL; 346700a2430fSAndrzej Pietrasiewicz ++ep; 346808f37148SVincent Pelletier } 346900a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&func->ffs->eps_lock, flags); 347000a2430fSAndrzej Pietrasiewicz kfree(func->eps); 347100a2430fSAndrzej Pietrasiewicz func->eps = NULL; 347200a2430fSAndrzej Pietrasiewicz /* 347300a2430fSAndrzej Pietrasiewicz * eps, descriptors and interfaces_nums are allocated in the 347400a2430fSAndrzej Pietrasiewicz * same chunk so only one free is required. 347500a2430fSAndrzej Pietrasiewicz */ 347600a2430fSAndrzej Pietrasiewicz func->function.fs_descriptors = NULL; 347700a2430fSAndrzej Pietrasiewicz func->function.hs_descriptors = NULL; 347800a2430fSAndrzej Pietrasiewicz func->function.ss_descriptors = NULL; 347900a2430fSAndrzej Pietrasiewicz func->interfaces_nums = NULL; 348000a2430fSAndrzej Pietrasiewicz 348100a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs, FUNCTIONFS_UNBIND); 348200a2430fSAndrzej Pietrasiewicz } 348300a2430fSAndrzej Pietrasiewicz 348400a2430fSAndrzej Pietrasiewicz static struct usb_function *ffs_alloc(struct usb_function_instance *fi) 348500a2430fSAndrzej Pietrasiewicz { 348600a2430fSAndrzej Pietrasiewicz struct ffs_function *func; 348700a2430fSAndrzej Pietrasiewicz 348800a2430fSAndrzej Pietrasiewicz ENTER(); 348900a2430fSAndrzej Pietrasiewicz 349000a2430fSAndrzej Pietrasiewicz func = kzalloc(sizeof(*func), GFP_KERNEL); 349100a2430fSAndrzej Pietrasiewicz if (unlikely(!func)) 349200a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 349300a2430fSAndrzej Pietrasiewicz 349400a2430fSAndrzej Pietrasiewicz func->function.name = "Function FS Gadget"; 349500a2430fSAndrzej Pietrasiewicz 349600a2430fSAndrzej Pietrasiewicz func->function.bind = ffs_func_bind; 349700a2430fSAndrzej Pietrasiewicz func->function.unbind = ffs_func_unbind; 349800a2430fSAndrzej Pietrasiewicz func->function.set_alt = ffs_func_set_alt; 349900a2430fSAndrzej Pietrasiewicz func->function.disable = ffs_func_disable; 350000a2430fSAndrzej Pietrasiewicz func->function.setup = ffs_func_setup; 350154dfce6dSFelix Hädicke func->function.req_match = ffs_func_req_match; 350200a2430fSAndrzej Pietrasiewicz func->function.suspend = ffs_func_suspend; 350300a2430fSAndrzej Pietrasiewicz func->function.resume = ffs_func_resume; 350400a2430fSAndrzej Pietrasiewicz func->function.free_func = ffs_free; 350500a2430fSAndrzej Pietrasiewicz 350600a2430fSAndrzej Pietrasiewicz return &func->function; 350700a2430fSAndrzej Pietrasiewicz } 350800a2430fSAndrzej Pietrasiewicz 350900a2430fSAndrzej Pietrasiewicz /* 351000a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 351100a2430fSAndrzej Pietrasiewicz */ 351200a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_alloc_dev(void) 351300a2430fSAndrzej Pietrasiewicz { 351400a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 351500a2430fSAndrzej Pietrasiewicz int ret; 351600a2430fSAndrzej Pietrasiewicz 351700a2430fSAndrzej Pietrasiewicz if (_ffs_get_single_dev()) 351800a2430fSAndrzej Pietrasiewicz return ERR_PTR(-EBUSY); 351900a2430fSAndrzej Pietrasiewicz 352000a2430fSAndrzej Pietrasiewicz dev = kzalloc(sizeof(*dev), GFP_KERNEL); 352100a2430fSAndrzej Pietrasiewicz if (!dev) 352200a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 352300a2430fSAndrzej Pietrasiewicz 352400a2430fSAndrzej Pietrasiewicz if (list_empty(&ffs_devices)) { 352500a2430fSAndrzej Pietrasiewicz ret = functionfs_init(); 352600a2430fSAndrzej Pietrasiewicz if (ret) { 352700a2430fSAndrzej Pietrasiewicz kfree(dev); 352800a2430fSAndrzej Pietrasiewicz return ERR_PTR(ret); 352900a2430fSAndrzej Pietrasiewicz } 353000a2430fSAndrzej Pietrasiewicz } 353100a2430fSAndrzej Pietrasiewicz 353200a2430fSAndrzej Pietrasiewicz list_add(&dev->entry, &ffs_devices); 353300a2430fSAndrzej Pietrasiewicz 353400a2430fSAndrzej Pietrasiewicz return dev; 353500a2430fSAndrzej Pietrasiewicz } 353600a2430fSAndrzej Pietrasiewicz 353700a2430fSAndrzej Pietrasiewicz int ffs_name_dev(struct ffs_dev *dev, const char *name) 353800a2430fSAndrzej Pietrasiewicz { 3539ea920bb4SMichal Nazarewicz struct ffs_dev *existing; 3540ea920bb4SMichal Nazarewicz int ret = 0; 354100a2430fSAndrzej Pietrasiewicz 354200a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 3543ea920bb4SMichal Nazarewicz 3544ea920bb4SMichal Nazarewicz existing = _ffs_do_find_dev(name); 3545ea920bb4SMichal Nazarewicz if (!existing) 3546ea920bb4SMichal Nazarewicz strlcpy(dev->name, name, ARRAY_SIZE(dev->name)); 3547ea920bb4SMichal Nazarewicz else if (existing != dev) 3548ea920bb4SMichal Nazarewicz ret = -EBUSY; 3549ea920bb4SMichal Nazarewicz 355000a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 355100a2430fSAndrzej Pietrasiewicz 355200a2430fSAndrzej Pietrasiewicz return ret; 355300a2430fSAndrzej Pietrasiewicz } 355400a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_name_dev); 355500a2430fSAndrzej Pietrasiewicz 355600a2430fSAndrzej Pietrasiewicz int ffs_single_dev(struct ffs_dev *dev) 355700a2430fSAndrzej Pietrasiewicz { 355800a2430fSAndrzej Pietrasiewicz int ret; 355900a2430fSAndrzej Pietrasiewicz 356000a2430fSAndrzej Pietrasiewicz ret = 0; 356100a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 356200a2430fSAndrzej Pietrasiewicz 356300a2430fSAndrzej Pietrasiewicz if (!list_is_singular(&ffs_devices)) 356400a2430fSAndrzej Pietrasiewicz ret = -EBUSY; 356500a2430fSAndrzej Pietrasiewicz else 356600a2430fSAndrzej Pietrasiewicz dev->single = true; 356700a2430fSAndrzej Pietrasiewicz 356800a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 356900a2430fSAndrzej Pietrasiewicz return ret; 357000a2430fSAndrzej Pietrasiewicz } 357100a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_single_dev); 357200a2430fSAndrzej Pietrasiewicz 357300a2430fSAndrzej Pietrasiewicz /* 357400a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 357500a2430fSAndrzej Pietrasiewicz */ 357600a2430fSAndrzej Pietrasiewicz static void _ffs_free_dev(struct ffs_dev *dev) 357700a2430fSAndrzej Pietrasiewicz { 357800a2430fSAndrzej Pietrasiewicz list_del(&dev->entry); 35793262ad82SJim Baxter 35803262ad82SJim Baxter /* Clear the private_data pointer to stop incorrect dev access */ 35813262ad82SJim Baxter if (dev->ffs_data) 35823262ad82SJim Baxter dev->ffs_data->private_data = NULL; 35833262ad82SJim Baxter 358400a2430fSAndrzej Pietrasiewicz kfree(dev); 358500a2430fSAndrzej Pietrasiewicz if (list_empty(&ffs_devices)) 358600a2430fSAndrzej Pietrasiewicz functionfs_cleanup(); 358700a2430fSAndrzej Pietrasiewicz } 358800a2430fSAndrzej Pietrasiewicz 358900a2430fSAndrzej Pietrasiewicz static void *ffs_acquire_dev(const char *dev_name) 359000a2430fSAndrzej Pietrasiewicz { 359100a2430fSAndrzej Pietrasiewicz struct ffs_dev *ffs_dev; 359200a2430fSAndrzej Pietrasiewicz 359300a2430fSAndrzej Pietrasiewicz ENTER(); 359400a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 359500a2430fSAndrzej Pietrasiewicz 359600a2430fSAndrzej Pietrasiewicz ffs_dev = _ffs_find_dev(dev_name); 359700a2430fSAndrzej Pietrasiewicz if (!ffs_dev) 359800a2430fSAndrzej Pietrasiewicz ffs_dev = ERR_PTR(-ENOENT); 359900a2430fSAndrzej Pietrasiewicz else if (ffs_dev->mounted) 360000a2430fSAndrzej Pietrasiewicz ffs_dev = ERR_PTR(-EBUSY); 360100a2430fSAndrzej Pietrasiewicz else if (ffs_dev->ffs_acquire_dev_callback && 360200a2430fSAndrzej Pietrasiewicz ffs_dev->ffs_acquire_dev_callback(ffs_dev)) 360300a2430fSAndrzej Pietrasiewicz ffs_dev = ERR_PTR(-ENOENT); 360400a2430fSAndrzej Pietrasiewicz else 360500a2430fSAndrzej Pietrasiewicz ffs_dev->mounted = true; 360600a2430fSAndrzej Pietrasiewicz 360700a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 360800a2430fSAndrzej Pietrasiewicz return ffs_dev; 360900a2430fSAndrzej Pietrasiewicz } 361000a2430fSAndrzej Pietrasiewicz 361100a2430fSAndrzej Pietrasiewicz static void ffs_release_dev(struct ffs_data *ffs_data) 361200a2430fSAndrzej Pietrasiewicz { 361300a2430fSAndrzej Pietrasiewicz struct ffs_dev *ffs_dev; 361400a2430fSAndrzej Pietrasiewicz 361500a2430fSAndrzej Pietrasiewicz ENTER(); 361600a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 361700a2430fSAndrzej Pietrasiewicz 361800a2430fSAndrzej Pietrasiewicz ffs_dev = ffs_data->private_data; 361900a2430fSAndrzej Pietrasiewicz if (ffs_dev) { 362000a2430fSAndrzej Pietrasiewicz ffs_dev->mounted = false; 362100a2430fSAndrzej Pietrasiewicz 362200a2430fSAndrzej Pietrasiewicz if (ffs_dev->ffs_release_dev_callback) 362300a2430fSAndrzej Pietrasiewicz ffs_dev->ffs_release_dev_callback(ffs_dev); 362400a2430fSAndrzej Pietrasiewicz } 362500a2430fSAndrzej Pietrasiewicz 362600a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 362700a2430fSAndrzej Pietrasiewicz } 362800a2430fSAndrzej Pietrasiewicz 362900a2430fSAndrzej Pietrasiewicz static int ffs_ready(struct ffs_data *ffs) 363000a2430fSAndrzej Pietrasiewicz { 363100a2430fSAndrzej Pietrasiewicz struct ffs_dev *ffs_obj; 363200a2430fSAndrzej Pietrasiewicz int ret = 0; 363300a2430fSAndrzej Pietrasiewicz 363400a2430fSAndrzej Pietrasiewicz ENTER(); 363500a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 363600a2430fSAndrzej Pietrasiewicz 363700a2430fSAndrzej Pietrasiewicz ffs_obj = ffs->private_data; 363800a2430fSAndrzej Pietrasiewicz if (!ffs_obj) { 363900a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 364000a2430fSAndrzej Pietrasiewicz goto done; 364100a2430fSAndrzej Pietrasiewicz } 364200a2430fSAndrzej Pietrasiewicz if (WARN_ON(ffs_obj->desc_ready)) { 364300a2430fSAndrzej Pietrasiewicz ret = -EBUSY; 364400a2430fSAndrzej Pietrasiewicz goto done; 364500a2430fSAndrzej Pietrasiewicz } 364600a2430fSAndrzej Pietrasiewicz 364700a2430fSAndrzej Pietrasiewicz ffs_obj->desc_ready = true; 364800a2430fSAndrzej Pietrasiewicz ffs_obj->ffs_data = ffs; 364900a2430fSAndrzej Pietrasiewicz 365049a79d8bSKrzysztof Opasiak if (ffs_obj->ffs_ready_callback) { 365100a2430fSAndrzej Pietrasiewicz ret = ffs_obj->ffs_ready_callback(ffs); 365249a79d8bSKrzysztof Opasiak if (ret) 365349a79d8bSKrzysztof Opasiak goto done; 365449a79d8bSKrzysztof Opasiak } 365500a2430fSAndrzej Pietrasiewicz 365649a79d8bSKrzysztof Opasiak set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags); 365700a2430fSAndrzej Pietrasiewicz done: 365800a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 365900a2430fSAndrzej Pietrasiewicz return ret; 366000a2430fSAndrzej Pietrasiewicz } 366100a2430fSAndrzej Pietrasiewicz 366200a2430fSAndrzej Pietrasiewicz static void ffs_closed(struct ffs_data *ffs) 366300a2430fSAndrzej Pietrasiewicz { 366400a2430fSAndrzej Pietrasiewicz struct ffs_dev *ffs_obj; 3665f14e9ad1SRui Miguel Silva struct f_fs_opts *opts; 3666b3ce3ce0SBaolin Wang struct config_item *ci; 366700a2430fSAndrzej Pietrasiewicz 366800a2430fSAndrzej Pietrasiewicz ENTER(); 366900a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 367000a2430fSAndrzej Pietrasiewicz 367100a2430fSAndrzej Pietrasiewicz ffs_obj = ffs->private_data; 367200a2430fSAndrzej Pietrasiewicz if (!ffs_obj) 367300a2430fSAndrzej Pietrasiewicz goto done; 367400a2430fSAndrzej Pietrasiewicz 367500a2430fSAndrzej Pietrasiewicz ffs_obj->desc_ready = false; 3676cdafb6d8SAndrew Gabbasov ffs_obj->ffs_data = NULL; 367700a2430fSAndrzej Pietrasiewicz 367849a79d8bSKrzysztof Opasiak if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) && 367949a79d8bSKrzysztof Opasiak ffs_obj->ffs_closed_callback) 368000a2430fSAndrzej Pietrasiewicz ffs_obj->ffs_closed_callback(ffs); 368100a2430fSAndrzej Pietrasiewicz 3682f14e9ad1SRui Miguel Silva if (ffs_obj->opts) 3683f14e9ad1SRui Miguel Silva opts = ffs_obj->opts; 3684f14e9ad1SRui Miguel Silva else 3685f14e9ad1SRui Miguel Silva goto done; 3686f14e9ad1SRui Miguel Silva 3687f14e9ad1SRui Miguel Silva if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent 36882c935bc5SPeter Zijlstra || !kref_read(&opts->func_inst.group.cg_item.ci_kref)) 368900a2430fSAndrzej Pietrasiewicz goto done; 369000a2430fSAndrzej Pietrasiewicz 3691b3ce3ce0SBaolin Wang ci = opts->func_inst.group.cg_item.ci_parent->ci_parent; 3692b3ce3ce0SBaolin Wang ffs_dev_unlock(); 3693b3ce3ce0SBaolin Wang 3694ce5bf9a5SHemant Kumar if (test_bit(FFS_FL_BOUND, &ffs->flags)) 3695b3ce3ce0SBaolin Wang unregister_gadget_item(ci); 3696b3ce3ce0SBaolin Wang return; 369700a2430fSAndrzej Pietrasiewicz done: 369800a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 369900a2430fSAndrzej Pietrasiewicz } 370000a2430fSAndrzej Pietrasiewicz 370100a2430fSAndrzej Pietrasiewicz /* Misc helper functions ****************************************************/ 370200a2430fSAndrzej Pietrasiewicz 370300a2430fSAndrzej Pietrasiewicz static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) 370400a2430fSAndrzej Pietrasiewicz { 370500a2430fSAndrzej Pietrasiewicz return nonblock 370600a2430fSAndrzej Pietrasiewicz ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN 370700a2430fSAndrzej Pietrasiewicz : mutex_lock_interruptible(mutex); 370800a2430fSAndrzej Pietrasiewicz } 370900a2430fSAndrzej Pietrasiewicz 371000a2430fSAndrzej Pietrasiewicz static char *ffs_prepare_buffer(const char __user *buf, size_t len) 371100a2430fSAndrzej Pietrasiewicz { 371200a2430fSAndrzej Pietrasiewicz char *data; 371300a2430fSAndrzej Pietrasiewicz 371400a2430fSAndrzej Pietrasiewicz if (unlikely(!len)) 371500a2430fSAndrzej Pietrasiewicz return NULL; 371600a2430fSAndrzej Pietrasiewicz 371700a2430fSAndrzej Pietrasiewicz data = kmalloc(len, GFP_KERNEL); 371800a2430fSAndrzej Pietrasiewicz if (unlikely(!data)) 371900a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 372000a2430fSAndrzej Pietrasiewicz 37217fe9a937SDaniel Walter if (unlikely(copy_from_user(data, buf, len))) { 372200a2430fSAndrzej Pietrasiewicz kfree(data); 372300a2430fSAndrzej Pietrasiewicz return ERR_PTR(-EFAULT); 372400a2430fSAndrzej Pietrasiewicz } 372500a2430fSAndrzej Pietrasiewicz 372600a2430fSAndrzej Pietrasiewicz pr_vdebug("Buffer from user space:\n"); 372700a2430fSAndrzej Pietrasiewicz ffs_dump_mem("", data, len); 372800a2430fSAndrzej Pietrasiewicz 372900a2430fSAndrzej Pietrasiewicz return data; 373000a2430fSAndrzej Pietrasiewicz } 373100a2430fSAndrzej Pietrasiewicz 373200a2430fSAndrzej Pietrasiewicz DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); 373300a2430fSAndrzej Pietrasiewicz MODULE_LICENSE("GPL"); 373400a2430fSAndrzej Pietrasiewicz MODULE_AUTHOR("Michal Nazarewicz"); 3735