100a2430fSAndrzej Pietrasiewicz /* 200a2430fSAndrzej Pietrasiewicz * f_fs.c -- user mode file system API for USB composite function controllers 300a2430fSAndrzej Pietrasiewicz * 400a2430fSAndrzej Pietrasiewicz * Copyright (C) 2010 Samsung Electronics 500a2430fSAndrzej Pietrasiewicz * Author: Michal Nazarewicz <mina86@mina86.com> 600a2430fSAndrzej Pietrasiewicz * 700a2430fSAndrzej Pietrasiewicz * Based on inode.c (GadgetFS) which was: 800a2430fSAndrzej Pietrasiewicz * Copyright (C) 2003-2004 David Brownell 900a2430fSAndrzej Pietrasiewicz * Copyright (C) 2003 Agilent Technologies 1000a2430fSAndrzej Pietrasiewicz * 1100a2430fSAndrzej Pietrasiewicz * This program is free software; you can redistribute it and/or modify 1200a2430fSAndrzej Pietrasiewicz * it under the terms of the GNU General Public License as published by 1300a2430fSAndrzej Pietrasiewicz * the Free Software Foundation; either version 2 of the License, or 1400a2430fSAndrzej Pietrasiewicz * (at your option) any later version. 1500a2430fSAndrzej Pietrasiewicz */ 1600a2430fSAndrzej Pietrasiewicz 1700a2430fSAndrzej Pietrasiewicz 1800a2430fSAndrzej Pietrasiewicz /* #define DEBUG */ 1900a2430fSAndrzej Pietrasiewicz /* #define VERBOSE_DEBUG */ 2000a2430fSAndrzej Pietrasiewicz 2100a2430fSAndrzej Pietrasiewicz #include <linux/blkdev.h> 2200a2430fSAndrzej Pietrasiewicz #include <linux/pagemap.h> 2300a2430fSAndrzej Pietrasiewicz #include <linux/export.h> 2400a2430fSAndrzej Pietrasiewicz #include <linux/hid.h> 2500a2430fSAndrzej Pietrasiewicz #include <linux/module.h> 26e2e40f2cSChristoph Hellwig #include <linux/uio.h> 2700a2430fSAndrzej Pietrasiewicz #include <asm/unaligned.h> 2800a2430fSAndrzej Pietrasiewicz 2900a2430fSAndrzej Pietrasiewicz #include <linux/usb/composite.h> 3000a2430fSAndrzej Pietrasiewicz #include <linux/usb/functionfs.h> 3100a2430fSAndrzej Pietrasiewicz 3200a2430fSAndrzej Pietrasiewicz #include <linux/aio.h> 3300a2430fSAndrzej Pietrasiewicz #include <linux/mmu_context.h> 3400a2430fSAndrzej Pietrasiewicz #include <linux/poll.h> 355e33f6fdSRobert Baldyga #include <linux/eventfd.h> 3600a2430fSAndrzej Pietrasiewicz 3700a2430fSAndrzej Pietrasiewicz #include "u_fs.h" 3800a2430fSAndrzej Pietrasiewicz #include "u_f.h" 3900a2430fSAndrzej Pietrasiewicz #include "u_os_desc.h" 4000a2430fSAndrzej Pietrasiewicz #include "configfs.h" 4100a2430fSAndrzej Pietrasiewicz 4200a2430fSAndrzej Pietrasiewicz #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ 4300a2430fSAndrzej Pietrasiewicz 4400a2430fSAndrzej Pietrasiewicz /* Reference counter handling */ 4500a2430fSAndrzej Pietrasiewicz static void ffs_data_get(struct ffs_data *ffs); 4600a2430fSAndrzej Pietrasiewicz static void ffs_data_put(struct ffs_data *ffs); 4700a2430fSAndrzej Pietrasiewicz /* Creates new ffs_data object. */ 4800a2430fSAndrzej Pietrasiewicz static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc)); 4900a2430fSAndrzej Pietrasiewicz 5000a2430fSAndrzej Pietrasiewicz /* Opened counter handling. */ 5100a2430fSAndrzej Pietrasiewicz static void ffs_data_opened(struct ffs_data *ffs); 5200a2430fSAndrzej Pietrasiewicz static void ffs_data_closed(struct ffs_data *ffs); 5300a2430fSAndrzej Pietrasiewicz 5400a2430fSAndrzej Pietrasiewicz /* Called with ffs->mutex held; take over ownership of data. */ 5500a2430fSAndrzej Pietrasiewicz static int __must_check 5600a2430fSAndrzej Pietrasiewicz __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); 5700a2430fSAndrzej Pietrasiewicz static int __must_check 5800a2430fSAndrzej Pietrasiewicz __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); 5900a2430fSAndrzej Pietrasiewicz 6000a2430fSAndrzej Pietrasiewicz 6100a2430fSAndrzej Pietrasiewicz /* The function structure ***************************************************/ 6200a2430fSAndrzej Pietrasiewicz 6300a2430fSAndrzej Pietrasiewicz struct ffs_ep; 6400a2430fSAndrzej Pietrasiewicz 6500a2430fSAndrzej Pietrasiewicz struct ffs_function { 6600a2430fSAndrzej Pietrasiewicz struct usb_configuration *conf; 6700a2430fSAndrzej Pietrasiewicz struct usb_gadget *gadget; 6800a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs; 6900a2430fSAndrzej Pietrasiewicz 7000a2430fSAndrzej Pietrasiewicz struct ffs_ep *eps; 7100a2430fSAndrzej Pietrasiewicz u8 eps_revmap[16]; 7200a2430fSAndrzej Pietrasiewicz short *interfaces_nums; 7300a2430fSAndrzej Pietrasiewicz 7400a2430fSAndrzej Pietrasiewicz struct usb_function function; 7500a2430fSAndrzej Pietrasiewicz }; 7600a2430fSAndrzej Pietrasiewicz 7700a2430fSAndrzej Pietrasiewicz 7800a2430fSAndrzej Pietrasiewicz static struct ffs_function *ffs_func_from_usb(struct usb_function *f) 7900a2430fSAndrzej Pietrasiewicz { 8000a2430fSAndrzej Pietrasiewicz return container_of(f, struct ffs_function, function); 8100a2430fSAndrzej Pietrasiewicz } 8200a2430fSAndrzej Pietrasiewicz 8300a2430fSAndrzej Pietrasiewicz 8400a2430fSAndrzej Pietrasiewicz static inline enum ffs_setup_state 8500a2430fSAndrzej Pietrasiewicz ffs_setup_state_clear_cancelled(struct ffs_data *ffs) 8600a2430fSAndrzej Pietrasiewicz { 8700a2430fSAndrzej Pietrasiewicz return (enum ffs_setup_state) 8800a2430fSAndrzej Pietrasiewicz cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP); 8900a2430fSAndrzej Pietrasiewicz } 9000a2430fSAndrzej Pietrasiewicz 9100a2430fSAndrzej Pietrasiewicz 9200a2430fSAndrzej Pietrasiewicz static void ffs_func_eps_disable(struct ffs_function *func); 9300a2430fSAndrzej Pietrasiewicz static int __must_check ffs_func_eps_enable(struct ffs_function *func); 9400a2430fSAndrzej Pietrasiewicz 9500a2430fSAndrzej Pietrasiewicz static int ffs_func_bind(struct usb_configuration *, 9600a2430fSAndrzej Pietrasiewicz struct usb_function *); 9700a2430fSAndrzej Pietrasiewicz static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); 9800a2430fSAndrzej Pietrasiewicz static void ffs_func_disable(struct usb_function *); 9900a2430fSAndrzej Pietrasiewicz static int ffs_func_setup(struct usb_function *, 10000a2430fSAndrzej Pietrasiewicz const struct usb_ctrlrequest *); 10100a2430fSAndrzej Pietrasiewicz static void ffs_func_suspend(struct usb_function *); 10200a2430fSAndrzej Pietrasiewicz static void ffs_func_resume(struct usb_function *); 10300a2430fSAndrzej Pietrasiewicz 10400a2430fSAndrzej Pietrasiewicz 10500a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_ep(struct ffs_function *func, u8 num); 10600a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf); 10700a2430fSAndrzej Pietrasiewicz 10800a2430fSAndrzej Pietrasiewicz 10900a2430fSAndrzej Pietrasiewicz /* The endpoints structures *************************************************/ 11000a2430fSAndrzej Pietrasiewicz 11100a2430fSAndrzej Pietrasiewicz struct ffs_ep { 11200a2430fSAndrzej Pietrasiewicz struct usb_ep *ep; /* P: ffs->eps_lock */ 11300a2430fSAndrzej Pietrasiewicz struct usb_request *req; /* P: epfile->mutex */ 11400a2430fSAndrzej Pietrasiewicz 11500a2430fSAndrzej Pietrasiewicz /* [0]: full speed, [1]: high speed, [2]: super speed */ 11600a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *descs[3]; 11700a2430fSAndrzej Pietrasiewicz 11800a2430fSAndrzej Pietrasiewicz u8 num; 11900a2430fSAndrzej Pietrasiewicz 12000a2430fSAndrzej Pietrasiewicz int status; /* P: epfile->mutex */ 12100a2430fSAndrzej Pietrasiewicz }; 12200a2430fSAndrzej Pietrasiewicz 12300a2430fSAndrzej Pietrasiewicz struct ffs_epfile { 12400a2430fSAndrzej Pietrasiewicz /* Protects ep->ep and ep->req. */ 12500a2430fSAndrzej Pietrasiewicz struct mutex mutex; 12600a2430fSAndrzej Pietrasiewicz wait_queue_head_t wait; 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 13300a2430fSAndrzej Pietrasiewicz char name[5]; 13400a2430fSAndrzej Pietrasiewicz 13500a2430fSAndrzej Pietrasiewicz unsigned char in; /* P: ffs->eps_lock */ 13600a2430fSAndrzej Pietrasiewicz unsigned char isoc; /* P: ffs->eps_lock */ 13700a2430fSAndrzej Pietrasiewicz 13800a2430fSAndrzej Pietrasiewicz unsigned char _pad; 13900a2430fSAndrzej Pietrasiewicz }; 14000a2430fSAndrzej Pietrasiewicz 14100a2430fSAndrzej Pietrasiewicz /* ffs_io_data structure ***************************************************/ 14200a2430fSAndrzej Pietrasiewicz 14300a2430fSAndrzej Pietrasiewicz struct ffs_io_data { 14400a2430fSAndrzej Pietrasiewicz bool aio; 14500a2430fSAndrzej Pietrasiewicz bool read; 14600a2430fSAndrzej Pietrasiewicz 14700a2430fSAndrzej Pietrasiewicz struct kiocb *kiocb; 148c993c39bSAl Viro struct iov_iter data; 149c993c39bSAl Viro const void *to_free; 150c993c39bSAl Viro char *buf; 15100a2430fSAndrzej Pietrasiewicz 15200a2430fSAndrzej Pietrasiewicz struct mm_struct *mm; 15300a2430fSAndrzej Pietrasiewicz struct work_struct work; 15400a2430fSAndrzej Pietrasiewicz 15500a2430fSAndrzej Pietrasiewicz struct usb_ep *ep; 15600a2430fSAndrzej Pietrasiewicz struct usb_request *req; 1575e33f6fdSRobert Baldyga 1585e33f6fdSRobert Baldyga struct ffs_data *ffs; 15900a2430fSAndrzej Pietrasiewicz }; 16000a2430fSAndrzej Pietrasiewicz 1616d5c1c77SRobert Baldyga struct ffs_desc_helper { 1626d5c1c77SRobert Baldyga struct ffs_data *ffs; 1636d5c1c77SRobert Baldyga unsigned interfaces_count; 1646d5c1c77SRobert Baldyga unsigned eps_count; 1656d5c1c77SRobert Baldyga }; 1666d5c1c77SRobert Baldyga 16700a2430fSAndrzej Pietrasiewicz static int __must_check ffs_epfiles_create(struct ffs_data *ffs); 16800a2430fSAndrzej Pietrasiewicz static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); 16900a2430fSAndrzej Pietrasiewicz 1701bb27cacSAl Viro static struct dentry * 17100a2430fSAndrzej Pietrasiewicz ffs_sb_create_file(struct super_block *sb, const char *name, void *data, 1721bb27cacSAl Viro const struct file_operations *fops); 17300a2430fSAndrzej Pietrasiewicz 17400a2430fSAndrzej Pietrasiewicz /* Devices management *******************************************************/ 17500a2430fSAndrzej Pietrasiewicz 17600a2430fSAndrzej Pietrasiewicz DEFINE_MUTEX(ffs_lock); 17700a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_lock); 17800a2430fSAndrzej Pietrasiewicz 17900a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_find_dev(const char *name); 18000a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_alloc_dev(void); 18100a2430fSAndrzej Pietrasiewicz static int _ffs_name_dev(struct ffs_dev *dev, const char *name); 18200a2430fSAndrzej Pietrasiewicz static void _ffs_free_dev(struct ffs_dev *dev); 18300a2430fSAndrzej Pietrasiewicz static void *ffs_acquire_dev(const char *dev_name); 18400a2430fSAndrzej Pietrasiewicz static void ffs_release_dev(struct ffs_data *ffs_data); 18500a2430fSAndrzej Pietrasiewicz static int ffs_ready(struct ffs_data *ffs); 18600a2430fSAndrzej Pietrasiewicz static void ffs_closed(struct ffs_data *ffs); 18700a2430fSAndrzej Pietrasiewicz 18800a2430fSAndrzej Pietrasiewicz /* Misc helper functions ****************************************************/ 18900a2430fSAndrzej Pietrasiewicz 19000a2430fSAndrzej Pietrasiewicz static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) 19100a2430fSAndrzej Pietrasiewicz __attribute__((warn_unused_result, nonnull)); 19200a2430fSAndrzej Pietrasiewicz static char *ffs_prepare_buffer(const char __user *buf, size_t len) 19300a2430fSAndrzej Pietrasiewicz __attribute__((warn_unused_result, nonnull)); 19400a2430fSAndrzej Pietrasiewicz 19500a2430fSAndrzej Pietrasiewicz 19600a2430fSAndrzej Pietrasiewicz /* Control file aka ep0 *****************************************************/ 19700a2430fSAndrzej Pietrasiewicz 19800a2430fSAndrzej Pietrasiewicz static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req) 19900a2430fSAndrzej Pietrasiewicz { 20000a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = req->context; 20100a2430fSAndrzej Pietrasiewicz 20200a2430fSAndrzej Pietrasiewicz complete_all(&ffs->ep0req_completion); 20300a2430fSAndrzej Pietrasiewicz } 20400a2430fSAndrzej Pietrasiewicz 20500a2430fSAndrzej Pietrasiewicz static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) 20600a2430fSAndrzej Pietrasiewicz { 20700a2430fSAndrzej Pietrasiewicz struct usb_request *req = ffs->ep0req; 20800a2430fSAndrzej Pietrasiewicz int ret; 20900a2430fSAndrzej Pietrasiewicz 21000a2430fSAndrzej Pietrasiewicz req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); 21100a2430fSAndrzej Pietrasiewicz 21200a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 21300a2430fSAndrzej Pietrasiewicz 21400a2430fSAndrzej Pietrasiewicz req->buf = data; 21500a2430fSAndrzej Pietrasiewicz req->length = len; 21600a2430fSAndrzej Pietrasiewicz 21700a2430fSAndrzej Pietrasiewicz /* 21800a2430fSAndrzej Pietrasiewicz * UDC layer requires to provide a buffer even for ZLP, but should 21900a2430fSAndrzej Pietrasiewicz * not use it at all. Let's provide some poisoned pointer to catch 22000a2430fSAndrzej Pietrasiewicz * possible bug in the driver. 22100a2430fSAndrzej Pietrasiewicz */ 22200a2430fSAndrzej Pietrasiewicz if (req->buf == NULL) 22300a2430fSAndrzej Pietrasiewicz req->buf = (void *)0xDEADBABE; 22400a2430fSAndrzej Pietrasiewicz 22500a2430fSAndrzej Pietrasiewicz reinit_completion(&ffs->ep0req_completion); 22600a2430fSAndrzej Pietrasiewicz 22700a2430fSAndrzej Pietrasiewicz ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); 22800a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 22900a2430fSAndrzej Pietrasiewicz return ret; 23000a2430fSAndrzej Pietrasiewicz 23100a2430fSAndrzej Pietrasiewicz ret = wait_for_completion_interruptible(&ffs->ep0req_completion); 23200a2430fSAndrzej Pietrasiewicz if (unlikely(ret)) { 23300a2430fSAndrzej Pietrasiewicz usb_ep_dequeue(ffs->gadget->ep0, req); 23400a2430fSAndrzej Pietrasiewicz return -EINTR; 23500a2430fSAndrzej Pietrasiewicz } 23600a2430fSAndrzej Pietrasiewicz 23700a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_NO_SETUP; 23800a2430fSAndrzej Pietrasiewicz return req->status ? req->status : req->actual; 23900a2430fSAndrzej Pietrasiewicz } 24000a2430fSAndrzej Pietrasiewicz 24100a2430fSAndrzej Pietrasiewicz static int __ffs_ep0_stall(struct ffs_data *ffs) 24200a2430fSAndrzej Pietrasiewicz { 24300a2430fSAndrzej Pietrasiewicz if (ffs->ev.can_stall) { 24400a2430fSAndrzej Pietrasiewicz pr_vdebug("ep0 stall\n"); 24500a2430fSAndrzej Pietrasiewicz usb_ep_set_halt(ffs->gadget->ep0); 24600a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_NO_SETUP; 24700a2430fSAndrzej Pietrasiewicz return -EL2HLT; 24800a2430fSAndrzej Pietrasiewicz } else { 24900a2430fSAndrzej Pietrasiewicz pr_debug("bogus ep0 stall!\n"); 25000a2430fSAndrzej Pietrasiewicz return -ESRCH; 25100a2430fSAndrzej Pietrasiewicz } 25200a2430fSAndrzej Pietrasiewicz } 25300a2430fSAndrzej Pietrasiewicz 25400a2430fSAndrzej Pietrasiewicz static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, 25500a2430fSAndrzej Pietrasiewicz size_t len, loff_t *ptr) 25600a2430fSAndrzej Pietrasiewicz { 25700a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 25800a2430fSAndrzej Pietrasiewicz ssize_t ret; 25900a2430fSAndrzej Pietrasiewicz char *data; 26000a2430fSAndrzej Pietrasiewicz 26100a2430fSAndrzej Pietrasiewicz ENTER(); 26200a2430fSAndrzej Pietrasiewicz 26300a2430fSAndrzej Pietrasiewicz /* Fast check if setup was canceled */ 26400a2430fSAndrzej Pietrasiewicz if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) 26500a2430fSAndrzej Pietrasiewicz return -EIDRM; 26600a2430fSAndrzej Pietrasiewicz 26700a2430fSAndrzej Pietrasiewicz /* Acquire mutex */ 26800a2430fSAndrzej Pietrasiewicz ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); 26900a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 27000a2430fSAndrzej Pietrasiewicz return ret; 27100a2430fSAndrzej Pietrasiewicz 27200a2430fSAndrzej Pietrasiewicz /* Check state */ 27300a2430fSAndrzej Pietrasiewicz switch (ffs->state) { 27400a2430fSAndrzej Pietrasiewicz case FFS_READ_DESCRIPTORS: 27500a2430fSAndrzej Pietrasiewicz case FFS_READ_STRINGS: 27600a2430fSAndrzej Pietrasiewicz /* Copy data */ 27700a2430fSAndrzej Pietrasiewicz if (unlikely(len < 16)) { 27800a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 27900a2430fSAndrzej Pietrasiewicz break; 28000a2430fSAndrzej Pietrasiewicz } 28100a2430fSAndrzej Pietrasiewicz 28200a2430fSAndrzej Pietrasiewicz data = ffs_prepare_buffer(buf, len); 28300a2430fSAndrzej Pietrasiewicz if (IS_ERR(data)) { 28400a2430fSAndrzej Pietrasiewicz ret = PTR_ERR(data); 28500a2430fSAndrzej Pietrasiewicz break; 28600a2430fSAndrzej Pietrasiewicz } 28700a2430fSAndrzej Pietrasiewicz 28800a2430fSAndrzej Pietrasiewicz /* Handle data */ 28900a2430fSAndrzej Pietrasiewicz if (ffs->state == FFS_READ_DESCRIPTORS) { 29000a2430fSAndrzej Pietrasiewicz pr_info("read descriptors\n"); 29100a2430fSAndrzej Pietrasiewicz ret = __ffs_data_got_descs(ffs, data, len); 29200a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 29300a2430fSAndrzej Pietrasiewicz break; 29400a2430fSAndrzej Pietrasiewicz 29500a2430fSAndrzej Pietrasiewicz ffs->state = FFS_READ_STRINGS; 29600a2430fSAndrzej Pietrasiewicz ret = len; 29700a2430fSAndrzej Pietrasiewicz } else { 29800a2430fSAndrzej Pietrasiewicz pr_info("read strings\n"); 29900a2430fSAndrzej Pietrasiewicz ret = __ffs_data_got_strings(ffs, data, len); 30000a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 30100a2430fSAndrzej Pietrasiewicz break; 30200a2430fSAndrzej Pietrasiewicz 30300a2430fSAndrzej Pietrasiewicz ret = ffs_epfiles_create(ffs); 30400a2430fSAndrzej Pietrasiewicz if (unlikely(ret)) { 30500a2430fSAndrzej Pietrasiewicz ffs->state = FFS_CLOSING; 30600a2430fSAndrzej Pietrasiewicz break; 30700a2430fSAndrzej Pietrasiewicz } 30800a2430fSAndrzej Pietrasiewicz 30900a2430fSAndrzej Pietrasiewicz ffs->state = FFS_ACTIVE; 31000a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 31100a2430fSAndrzej Pietrasiewicz 31200a2430fSAndrzej Pietrasiewicz ret = ffs_ready(ffs); 31300a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 31400a2430fSAndrzej Pietrasiewicz ffs->state = FFS_CLOSING; 31500a2430fSAndrzej Pietrasiewicz return ret; 31600a2430fSAndrzej Pietrasiewicz } 31700a2430fSAndrzej Pietrasiewicz 31800a2430fSAndrzej Pietrasiewicz return len; 31900a2430fSAndrzej Pietrasiewicz } 32000a2430fSAndrzej Pietrasiewicz break; 32100a2430fSAndrzej Pietrasiewicz 32200a2430fSAndrzej Pietrasiewicz case FFS_ACTIVE: 32300a2430fSAndrzej Pietrasiewicz data = NULL; 32400a2430fSAndrzej Pietrasiewicz /* 32500a2430fSAndrzej Pietrasiewicz * We're called from user space, we can use _irq 32600a2430fSAndrzej Pietrasiewicz * rather then _irqsave 32700a2430fSAndrzej Pietrasiewicz */ 32800a2430fSAndrzej Pietrasiewicz spin_lock_irq(&ffs->ev.waitq.lock); 32900a2430fSAndrzej Pietrasiewicz switch (ffs_setup_state_clear_cancelled(ffs)) { 33000a2430fSAndrzej Pietrasiewicz case FFS_SETUP_CANCELLED: 33100a2430fSAndrzej Pietrasiewicz ret = -EIDRM; 33200a2430fSAndrzej Pietrasiewicz goto done_spin; 33300a2430fSAndrzej Pietrasiewicz 33400a2430fSAndrzej Pietrasiewicz case FFS_NO_SETUP: 33500a2430fSAndrzej Pietrasiewicz ret = -ESRCH; 33600a2430fSAndrzej Pietrasiewicz goto done_spin; 33700a2430fSAndrzej Pietrasiewicz 33800a2430fSAndrzej Pietrasiewicz case FFS_SETUP_PENDING: 33900a2430fSAndrzej Pietrasiewicz break; 34000a2430fSAndrzej Pietrasiewicz } 34100a2430fSAndrzej Pietrasiewicz 34200a2430fSAndrzej Pietrasiewicz /* FFS_SETUP_PENDING */ 34300a2430fSAndrzej Pietrasiewicz if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) { 34400a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 34500a2430fSAndrzej Pietrasiewicz ret = __ffs_ep0_stall(ffs); 34600a2430fSAndrzej Pietrasiewicz break; 34700a2430fSAndrzej Pietrasiewicz } 34800a2430fSAndrzej Pietrasiewicz 34900a2430fSAndrzej Pietrasiewicz /* FFS_SETUP_PENDING and not stall */ 35000a2430fSAndrzej Pietrasiewicz len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); 35100a2430fSAndrzej Pietrasiewicz 35200a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 35300a2430fSAndrzej Pietrasiewicz 35400a2430fSAndrzej Pietrasiewicz data = ffs_prepare_buffer(buf, len); 35500a2430fSAndrzej Pietrasiewicz if (IS_ERR(data)) { 35600a2430fSAndrzej Pietrasiewicz ret = PTR_ERR(data); 35700a2430fSAndrzej Pietrasiewicz break; 35800a2430fSAndrzej Pietrasiewicz } 35900a2430fSAndrzej Pietrasiewicz 36000a2430fSAndrzej Pietrasiewicz spin_lock_irq(&ffs->ev.waitq.lock); 36100a2430fSAndrzej Pietrasiewicz 36200a2430fSAndrzej Pietrasiewicz /* 36300a2430fSAndrzej Pietrasiewicz * We are guaranteed to be still in FFS_ACTIVE state 36400a2430fSAndrzej Pietrasiewicz * but the state of setup could have changed from 36500a2430fSAndrzej Pietrasiewicz * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need 36600a2430fSAndrzej Pietrasiewicz * to check for that. If that happened we copied data 36700a2430fSAndrzej Pietrasiewicz * from user space in vain but it's unlikely. 36800a2430fSAndrzej Pietrasiewicz * 36900a2430fSAndrzej Pietrasiewicz * For sure we are not in FFS_NO_SETUP since this is 37000a2430fSAndrzej Pietrasiewicz * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP 37100a2430fSAndrzej Pietrasiewicz * transition can be performed and it's protected by 37200a2430fSAndrzej Pietrasiewicz * mutex. 37300a2430fSAndrzej Pietrasiewicz */ 37400a2430fSAndrzej Pietrasiewicz if (ffs_setup_state_clear_cancelled(ffs) == 37500a2430fSAndrzej Pietrasiewicz FFS_SETUP_CANCELLED) { 37600a2430fSAndrzej Pietrasiewicz ret = -EIDRM; 37700a2430fSAndrzej Pietrasiewicz done_spin: 37800a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 37900a2430fSAndrzej Pietrasiewicz } else { 38000a2430fSAndrzej Pietrasiewicz /* unlocks spinlock */ 38100a2430fSAndrzej Pietrasiewicz ret = __ffs_ep0_queue_wait(ffs, data, len); 38200a2430fSAndrzej Pietrasiewicz } 38300a2430fSAndrzej Pietrasiewicz kfree(data); 38400a2430fSAndrzej Pietrasiewicz break; 38500a2430fSAndrzej Pietrasiewicz 38600a2430fSAndrzej Pietrasiewicz default: 38700a2430fSAndrzej Pietrasiewicz ret = -EBADFD; 38800a2430fSAndrzej Pietrasiewicz break; 38900a2430fSAndrzej Pietrasiewicz } 39000a2430fSAndrzej Pietrasiewicz 39100a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 39200a2430fSAndrzej Pietrasiewicz return ret; 39300a2430fSAndrzej Pietrasiewicz } 39400a2430fSAndrzej Pietrasiewicz 39567913bbdSMichal Nazarewicz /* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */ 39600a2430fSAndrzej Pietrasiewicz static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, 39700a2430fSAndrzej Pietrasiewicz size_t n) 39800a2430fSAndrzej Pietrasiewicz { 39900a2430fSAndrzej Pietrasiewicz /* 40067913bbdSMichal Nazarewicz * n cannot be bigger than ffs->ev.count, which cannot be bigger than 40167913bbdSMichal Nazarewicz * size of ffs->ev.types array (which is four) so that's how much space 40267913bbdSMichal Nazarewicz * we reserve. 40300a2430fSAndrzej Pietrasiewicz */ 40467913bbdSMichal Nazarewicz struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)]; 40567913bbdSMichal Nazarewicz const size_t size = n * sizeof *events; 40600a2430fSAndrzej Pietrasiewicz unsigned i = 0; 40700a2430fSAndrzej Pietrasiewicz 40867913bbdSMichal Nazarewicz memset(events, 0, size); 40900a2430fSAndrzej Pietrasiewicz 41000a2430fSAndrzej Pietrasiewicz do { 41100a2430fSAndrzej Pietrasiewicz events[i].type = ffs->ev.types[i]; 41200a2430fSAndrzej Pietrasiewicz if (events[i].type == FUNCTIONFS_SETUP) { 41300a2430fSAndrzej Pietrasiewicz events[i].u.setup = ffs->ev.setup; 41400a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_SETUP_PENDING; 41500a2430fSAndrzej Pietrasiewicz } 41600a2430fSAndrzej Pietrasiewicz } while (++i < n); 41700a2430fSAndrzej Pietrasiewicz 41800a2430fSAndrzej Pietrasiewicz ffs->ev.count -= n; 41967913bbdSMichal Nazarewicz if (ffs->ev.count) 42000a2430fSAndrzej Pietrasiewicz memmove(ffs->ev.types, ffs->ev.types + n, 42100a2430fSAndrzej Pietrasiewicz ffs->ev.count * sizeof *ffs->ev.types); 42200a2430fSAndrzej Pietrasiewicz 42300a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 42400a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 42500a2430fSAndrzej Pietrasiewicz 4267fe9a937SDaniel Walter return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size; 42700a2430fSAndrzej Pietrasiewicz } 42800a2430fSAndrzej Pietrasiewicz 42900a2430fSAndrzej Pietrasiewicz static ssize_t ffs_ep0_read(struct file *file, char __user *buf, 43000a2430fSAndrzej Pietrasiewicz size_t len, loff_t *ptr) 43100a2430fSAndrzej Pietrasiewicz { 43200a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 43300a2430fSAndrzej Pietrasiewicz char *data = NULL; 43400a2430fSAndrzej Pietrasiewicz size_t n; 43500a2430fSAndrzej Pietrasiewicz int ret; 43600a2430fSAndrzej Pietrasiewicz 43700a2430fSAndrzej Pietrasiewicz ENTER(); 43800a2430fSAndrzej Pietrasiewicz 43900a2430fSAndrzej Pietrasiewicz /* Fast check if setup was canceled */ 44000a2430fSAndrzej Pietrasiewicz if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) 44100a2430fSAndrzej Pietrasiewicz return -EIDRM; 44200a2430fSAndrzej Pietrasiewicz 44300a2430fSAndrzej Pietrasiewicz /* Acquire mutex */ 44400a2430fSAndrzej Pietrasiewicz ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); 44500a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 44600a2430fSAndrzej Pietrasiewicz return ret; 44700a2430fSAndrzej Pietrasiewicz 44800a2430fSAndrzej Pietrasiewicz /* Check state */ 44900a2430fSAndrzej Pietrasiewicz if (ffs->state != FFS_ACTIVE) { 45000a2430fSAndrzej Pietrasiewicz ret = -EBADFD; 45100a2430fSAndrzej Pietrasiewicz goto done_mutex; 45200a2430fSAndrzej Pietrasiewicz } 45300a2430fSAndrzej Pietrasiewicz 45400a2430fSAndrzej Pietrasiewicz /* 45500a2430fSAndrzej Pietrasiewicz * We're called from user space, we can use _irq rather then 45600a2430fSAndrzej Pietrasiewicz * _irqsave 45700a2430fSAndrzej Pietrasiewicz */ 45800a2430fSAndrzej Pietrasiewicz spin_lock_irq(&ffs->ev.waitq.lock); 45900a2430fSAndrzej Pietrasiewicz 46000a2430fSAndrzej Pietrasiewicz switch (ffs_setup_state_clear_cancelled(ffs)) { 46100a2430fSAndrzej Pietrasiewicz case FFS_SETUP_CANCELLED: 46200a2430fSAndrzej Pietrasiewicz ret = -EIDRM; 46300a2430fSAndrzej Pietrasiewicz break; 46400a2430fSAndrzej Pietrasiewicz 46500a2430fSAndrzej Pietrasiewicz case FFS_NO_SETUP: 46600a2430fSAndrzej Pietrasiewicz n = len / sizeof(struct usb_functionfs_event); 46700a2430fSAndrzej Pietrasiewicz if (unlikely(!n)) { 46800a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 46900a2430fSAndrzej Pietrasiewicz break; 47000a2430fSAndrzej Pietrasiewicz } 47100a2430fSAndrzej Pietrasiewicz 47200a2430fSAndrzej Pietrasiewicz if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) { 47300a2430fSAndrzej Pietrasiewicz ret = -EAGAIN; 47400a2430fSAndrzej Pietrasiewicz break; 47500a2430fSAndrzej Pietrasiewicz } 47600a2430fSAndrzej Pietrasiewicz 47700a2430fSAndrzej Pietrasiewicz if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq, 47800a2430fSAndrzej Pietrasiewicz ffs->ev.count)) { 47900a2430fSAndrzej Pietrasiewicz ret = -EINTR; 48000a2430fSAndrzej Pietrasiewicz break; 48100a2430fSAndrzej Pietrasiewicz } 48200a2430fSAndrzej Pietrasiewicz 48300a2430fSAndrzej Pietrasiewicz return __ffs_ep0_read_events(ffs, buf, 48400a2430fSAndrzej Pietrasiewicz min(n, (size_t)ffs->ev.count)); 48500a2430fSAndrzej Pietrasiewicz 48600a2430fSAndrzej Pietrasiewicz case FFS_SETUP_PENDING: 48700a2430fSAndrzej Pietrasiewicz if (ffs->ev.setup.bRequestType & USB_DIR_IN) { 48800a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 48900a2430fSAndrzej Pietrasiewicz ret = __ffs_ep0_stall(ffs); 49000a2430fSAndrzej Pietrasiewicz goto done_mutex; 49100a2430fSAndrzej Pietrasiewicz } 49200a2430fSAndrzej Pietrasiewicz 49300a2430fSAndrzej Pietrasiewicz len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); 49400a2430fSAndrzej Pietrasiewicz 49500a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 49600a2430fSAndrzej Pietrasiewicz 49700a2430fSAndrzej Pietrasiewicz if (likely(len)) { 49800a2430fSAndrzej Pietrasiewicz data = kmalloc(len, GFP_KERNEL); 49900a2430fSAndrzej Pietrasiewicz if (unlikely(!data)) { 50000a2430fSAndrzej Pietrasiewicz ret = -ENOMEM; 50100a2430fSAndrzej Pietrasiewicz goto done_mutex; 50200a2430fSAndrzej Pietrasiewicz } 50300a2430fSAndrzej Pietrasiewicz } 50400a2430fSAndrzej Pietrasiewicz 50500a2430fSAndrzej Pietrasiewicz spin_lock_irq(&ffs->ev.waitq.lock); 50600a2430fSAndrzej Pietrasiewicz 50700a2430fSAndrzej Pietrasiewicz /* See ffs_ep0_write() */ 50800a2430fSAndrzej Pietrasiewicz if (ffs_setup_state_clear_cancelled(ffs) == 50900a2430fSAndrzej Pietrasiewicz FFS_SETUP_CANCELLED) { 51000a2430fSAndrzej Pietrasiewicz ret = -EIDRM; 51100a2430fSAndrzej Pietrasiewicz break; 51200a2430fSAndrzej Pietrasiewicz } 51300a2430fSAndrzej Pietrasiewicz 51400a2430fSAndrzej Pietrasiewicz /* unlocks spinlock */ 51500a2430fSAndrzej Pietrasiewicz ret = __ffs_ep0_queue_wait(ffs, data, len); 5167fe9a937SDaniel Walter if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len))) 51700a2430fSAndrzej Pietrasiewicz ret = -EFAULT; 51800a2430fSAndrzej Pietrasiewicz goto done_mutex; 51900a2430fSAndrzej Pietrasiewicz 52000a2430fSAndrzej Pietrasiewicz default: 52100a2430fSAndrzej Pietrasiewicz ret = -EBADFD; 52200a2430fSAndrzej Pietrasiewicz break; 52300a2430fSAndrzej Pietrasiewicz } 52400a2430fSAndrzej Pietrasiewicz 52500a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&ffs->ev.waitq.lock); 52600a2430fSAndrzej Pietrasiewicz done_mutex: 52700a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 52800a2430fSAndrzej Pietrasiewicz kfree(data); 52900a2430fSAndrzej Pietrasiewicz return ret; 53000a2430fSAndrzej Pietrasiewicz } 53100a2430fSAndrzej Pietrasiewicz 53200a2430fSAndrzej Pietrasiewicz static int ffs_ep0_open(struct inode *inode, struct file *file) 53300a2430fSAndrzej Pietrasiewicz { 53400a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = inode->i_private; 53500a2430fSAndrzej Pietrasiewicz 53600a2430fSAndrzej Pietrasiewicz ENTER(); 53700a2430fSAndrzej Pietrasiewicz 53800a2430fSAndrzej Pietrasiewicz if (unlikely(ffs->state == FFS_CLOSING)) 53900a2430fSAndrzej Pietrasiewicz return -EBUSY; 54000a2430fSAndrzej Pietrasiewicz 54100a2430fSAndrzej Pietrasiewicz file->private_data = ffs; 54200a2430fSAndrzej Pietrasiewicz ffs_data_opened(ffs); 54300a2430fSAndrzej Pietrasiewicz 54400a2430fSAndrzej Pietrasiewicz return 0; 54500a2430fSAndrzej Pietrasiewicz } 54600a2430fSAndrzej Pietrasiewicz 54700a2430fSAndrzej Pietrasiewicz static int ffs_ep0_release(struct inode *inode, struct file *file) 54800a2430fSAndrzej Pietrasiewicz { 54900a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 55000a2430fSAndrzej Pietrasiewicz 55100a2430fSAndrzej Pietrasiewicz ENTER(); 55200a2430fSAndrzej Pietrasiewicz 55300a2430fSAndrzej Pietrasiewicz ffs_data_closed(ffs); 55400a2430fSAndrzej Pietrasiewicz 55500a2430fSAndrzej Pietrasiewicz return 0; 55600a2430fSAndrzej Pietrasiewicz } 55700a2430fSAndrzej Pietrasiewicz 55800a2430fSAndrzej Pietrasiewicz static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) 55900a2430fSAndrzej Pietrasiewicz { 56000a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 56100a2430fSAndrzej Pietrasiewicz struct usb_gadget *gadget = ffs->gadget; 56200a2430fSAndrzej Pietrasiewicz long ret; 56300a2430fSAndrzej Pietrasiewicz 56400a2430fSAndrzej Pietrasiewicz ENTER(); 56500a2430fSAndrzej Pietrasiewicz 56600a2430fSAndrzej Pietrasiewicz if (code == FUNCTIONFS_INTERFACE_REVMAP) { 56700a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs->func; 56800a2430fSAndrzej Pietrasiewicz ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; 56900a2430fSAndrzej Pietrasiewicz } else if (gadget && gadget->ops->ioctl) { 57000a2430fSAndrzej Pietrasiewicz ret = gadget->ops->ioctl(gadget, code, value); 57100a2430fSAndrzej Pietrasiewicz } else { 57200a2430fSAndrzej Pietrasiewicz ret = -ENOTTY; 57300a2430fSAndrzej Pietrasiewicz } 57400a2430fSAndrzej Pietrasiewicz 57500a2430fSAndrzej Pietrasiewicz return ret; 57600a2430fSAndrzej Pietrasiewicz } 57700a2430fSAndrzej Pietrasiewicz 57800a2430fSAndrzej Pietrasiewicz static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) 57900a2430fSAndrzej Pietrasiewicz { 58000a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = file->private_data; 58100a2430fSAndrzej Pietrasiewicz unsigned int mask = POLLWRNORM; 58200a2430fSAndrzej Pietrasiewicz int ret; 58300a2430fSAndrzej Pietrasiewicz 58400a2430fSAndrzej Pietrasiewicz poll_wait(file, &ffs->ev.waitq, wait); 58500a2430fSAndrzej Pietrasiewicz 58600a2430fSAndrzej Pietrasiewicz ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); 58700a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 58800a2430fSAndrzej Pietrasiewicz return mask; 58900a2430fSAndrzej Pietrasiewicz 59000a2430fSAndrzej Pietrasiewicz switch (ffs->state) { 59100a2430fSAndrzej Pietrasiewicz case FFS_READ_DESCRIPTORS: 59200a2430fSAndrzej Pietrasiewicz case FFS_READ_STRINGS: 59300a2430fSAndrzej Pietrasiewicz mask |= POLLOUT; 59400a2430fSAndrzej Pietrasiewicz break; 59500a2430fSAndrzej Pietrasiewicz 59600a2430fSAndrzej Pietrasiewicz case FFS_ACTIVE: 59700a2430fSAndrzej Pietrasiewicz switch (ffs->setup_state) { 59800a2430fSAndrzej Pietrasiewicz case FFS_NO_SETUP: 59900a2430fSAndrzej Pietrasiewicz if (ffs->ev.count) 60000a2430fSAndrzej Pietrasiewicz mask |= POLLIN; 60100a2430fSAndrzej Pietrasiewicz break; 60200a2430fSAndrzej Pietrasiewicz 60300a2430fSAndrzej Pietrasiewicz case FFS_SETUP_PENDING: 60400a2430fSAndrzej Pietrasiewicz case FFS_SETUP_CANCELLED: 60500a2430fSAndrzej Pietrasiewicz mask |= (POLLIN | POLLOUT); 60600a2430fSAndrzej Pietrasiewicz break; 60700a2430fSAndrzej Pietrasiewicz } 60800a2430fSAndrzej Pietrasiewicz case FFS_CLOSING: 60900a2430fSAndrzej Pietrasiewicz break; 61018d6b32fSRobert Baldyga case FFS_DEACTIVATED: 61118d6b32fSRobert Baldyga break; 61200a2430fSAndrzej Pietrasiewicz } 61300a2430fSAndrzej Pietrasiewicz 61400a2430fSAndrzej Pietrasiewicz mutex_unlock(&ffs->mutex); 61500a2430fSAndrzej Pietrasiewicz 61600a2430fSAndrzej Pietrasiewicz return mask; 61700a2430fSAndrzej Pietrasiewicz } 61800a2430fSAndrzej Pietrasiewicz 61900a2430fSAndrzej Pietrasiewicz static const struct file_operations ffs_ep0_operations = { 62000a2430fSAndrzej Pietrasiewicz .llseek = no_llseek, 62100a2430fSAndrzej Pietrasiewicz 62200a2430fSAndrzej Pietrasiewicz .open = ffs_ep0_open, 62300a2430fSAndrzej Pietrasiewicz .write = ffs_ep0_write, 62400a2430fSAndrzej Pietrasiewicz .read = ffs_ep0_read, 62500a2430fSAndrzej Pietrasiewicz .release = ffs_ep0_release, 62600a2430fSAndrzej Pietrasiewicz .unlocked_ioctl = ffs_ep0_ioctl, 62700a2430fSAndrzej Pietrasiewicz .poll = ffs_ep0_poll, 62800a2430fSAndrzej Pietrasiewicz }; 62900a2430fSAndrzej Pietrasiewicz 63000a2430fSAndrzej Pietrasiewicz 63100a2430fSAndrzej Pietrasiewicz /* "Normal" endpoints operations ********************************************/ 63200a2430fSAndrzej Pietrasiewicz 63300a2430fSAndrzej Pietrasiewicz static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) 63400a2430fSAndrzej Pietrasiewicz { 63500a2430fSAndrzej Pietrasiewicz ENTER(); 63600a2430fSAndrzej Pietrasiewicz if (likely(req->context)) { 63700a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep = _ep->driver_data; 63800a2430fSAndrzej Pietrasiewicz ep->status = req->status ? req->status : req->actual; 63900a2430fSAndrzej Pietrasiewicz complete(req->context); 64000a2430fSAndrzej Pietrasiewicz } 64100a2430fSAndrzej Pietrasiewicz } 64200a2430fSAndrzej Pietrasiewicz 64300a2430fSAndrzej Pietrasiewicz static void ffs_user_copy_worker(struct work_struct *work) 64400a2430fSAndrzej Pietrasiewicz { 64500a2430fSAndrzej Pietrasiewicz struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, 64600a2430fSAndrzej Pietrasiewicz work); 64700a2430fSAndrzej Pietrasiewicz int ret = io_data->req->status ? io_data->req->status : 64800a2430fSAndrzej Pietrasiewicz io_data->req->actual; 64900a2430fSAndrzej Pietrasiewicz 65000a2430fSAndrzej Pietrasiewicz if (io_data->read && ret > 0) { 65100a2430fSAndrzej Pietrasiewicz use_mm(io_data->mm); 652c993c39bSAl Viro ret = copy_to_iter(io_data->buf, ret, &io_data->data); 653c993c39bSAl Viro if (iov_iter_count(&io_data->data)) 65400a2430fSAndrzej Pietrasiewicz ret = -EFAULT; 65500a2430fSAndrzej Pietrasiewicz unuse_mm(io_data->mm); 65600a2430fSAndrzej Pietrasiewicz } 65700a2430fSAndrzej Pietrasiewicz 65804b2fa9fSChristoph Hellwig io_data->kiocb->ki_complete(io_data->kiocb, ret, ret); 65900a2430fSAndrzej Pietrasiewicz 66004b2fa9fSChristoph Hellwig if (io_data->ffs->ffs_eventfd && 66104b2fa9fSChristoph Hellwig !(io_data->kiocb->ki_flags & IOCB_EVENTFD)) 6625e33f6fdSRobert Baldyga eventfd_signal(io_data->ffs->ffs_eventfd, 1); 6635e33f6fdSRobert Baldyga 66400a2430fSAndrzej Pietrasiewicz usb_ep_free_request(io_data->ep, io_data->req); 66500a2430fSAndrzej Pietrasiewicz 66600a2430fSAndrzej Pietrasiewicz io_data->kiocb->private = NULL; 66700a2430fSAndrzej Pietrasiewicz if (io_data->read) 668c993c39bSAl Viro kfree(io_data->to_free); 66900a2430fSAndrzej Pietrasiewicz kfree(io_data->buf); 67000a2430fSAndrzej Pietrasiewicz kfree(io_data); 67100a2430fSAndrzej Pietrasiewicz } 67200a2430fSAndrzej Pietrasiewicz 67300a2430fSAndrzej Pietrasiewicz static void ffs_epfile_async_io_complete(struct usb_ep *_ep, 67400a2430fSAndrzej Pietrasiewicz struct usb_request *req) 67500a2430fSAndrzej Pietrasiewicz { 67600a2430fSAndrzej Pietrasiewicz struct ffs_io_data *io_data = req->context; 67700a2430fSAndrzej Pietrasiewicz 67800a2430fSAndrzej Pietrasiewicz ENTER(); 67900a2430fSAndrzej Pietrasiewicz 68000a2430fSAndrzej Pietrasiewicz INIT_WORK(&io_data->work, ffs_user_copy_worker); 68100a2430fSAndrzej Pietrasiewicz schedule_work(&io_data->work); 68200a2430fSAndrzej Pietrasiewicz } 68300a2430fSAndrzej Pietrasiewicz 68400a2430fSAndrzej Pietrasiewicz static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) 68500a2430fSAndrzej Pietrasiewicz { 68600a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = file->private_data; 68700a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep; 68800a2430fSAndrzej Pietrasiewicz char *data = NULL; 689c0d31b3cSDavid Cohen ssize_t ret, data_len = -EINVAL; 69000a2430fSAndrzej Pietrasiewicz int halt; 69100a2430fSAndrzej Pietrasiewicz 69200a2430fSAndrzej Pietrasiewicz /* Are we still active? */ 693b3591f67SMichal Nazarewicz if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) 694b3591f67SMichal Nazarewicz return -ENODEV; 69500a2430fSAndrzej Pietrasiewicz 69600a2430fSAndrzej Pietrasiewicz /* Wait for endpoint to be enabled */ 69700a2430fSAndrzej Pietrasiewicz ep = epfile->ep; 69800a2430fSAndrzej Pietrasiewicz if (!ep) { 699b3591f67SMichal Nazarewicz if (file->f_flags & O_NONBLOCK) 700b3591f67SMichal Nazarewicz return -EAGAIN; 70100a2430fSAndrzej Pietrasiewicz 70200a2430fSAndrzej Pietrasiewicz ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); 703b3591f67SMichal Nazarewicz if (ret) 704b3591f67SMichal Nazarewicz return -EINTR; 70500a2430fSAndrzej Pietrasiewicz } 70600a2430fSAndrzej Pietrasiewicz 70700a2430fSAndrzej Pietrasiewicz /* Do we halt? */ 70800a2430fSAndrzej Pietrasiewicz halt = (!io_data->read == !epfile->in); 709b3591f67SMichal Nazarewicz if (halt && epfile->isoc) 710b3591f67SMichal Nazarewicz return -EINVAL; 71100a2430fSAndrzej Pietrasiewicz 71200a2430fSAndrzej Pietrasiewicz /* Allocate & copy */ 71300a2430fSAndrzej Pietrasiewicz if (!halt) { 71400a2430fSAndrzej Pietrasiewicz /* 71500a2430fSAndrzej Pietrasiewicz * if we _do_ wait above, the epfile->ffs->gadget might be NULL 71600a2430fSAndrzej Pietrasiewicz * before the waiting completes, so do not assign to 'gadget' earlier 71700a2430fSAndrzej Pietrasiewicz */ 71800a2430fSAndrzej Pietrasiewicz struct usb_gadget *gadget = epfile->ffs->gadget; 719c993c39bSAl Viro size_t copied; 72000a2430fSAndrzej Pietrasiewicz 72100a2430fSAndrzej Pietrasiewicz spin_lock_irq(&epfile->ffs->eps_lock); 72200a2430fSAndrzej Pietrasiewicz /* In the meantime, endpoint got disabled or changed. */ 72300a2430fSAndrzej Pietrasiewicz if (epfile->ep != ep) { 72400a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 72500a2430fSAndrzej Pietrasiewicz return -ESHUTDOWN; 72600a2430fSAndrzej Pietrasiewicz } 727c993c39bSAl Viro data_len = iov_iter_count(&io_data->data); 72800a2430fSAndrzej Pietrasiewicz /* 72900a2430fSAndrzej Pietrasiewicz * Controller may require buffer size to be aligned to 73000a2430fSAndrzej Pietrasiewicz * maxpacketsize of an out endpoint. 73100a2430fSAndrzej Pietrasiewicz */ 732c993c39bSAl Viro if (io_data->read) 733c993c39bSAl Viro data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); 73400a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 73500a2430fSAndrzej Pietrasiewicz 73600a2430fSAndrzej Pietrasiewicz data = kmalloc(data_len, GFP_KERNEL); 73700a2430fSAndrzej Pietrasiewicz if (unlikely(!data)) 73800a2430fSAndrzej Pietrasiewicz return -ENOMEM; 739c993c39bSAl Viro if (!io_data->read) { 740c993c39bSAl Viro copied = copy_from_iter(data, data_len, &io_data->data); 741c993c39bSAl Viro if (copied != data_len) { 74200a2430fSAndrzej Pietrasiewicz ret = -EFAULT; 74300a2430fSAndrzej Pietrasiewicz goto error; 74400a2430fSAndrzej Pietrasiewicz } 74500a2430fSAndrzej Pietrasiewicz } 74600a2430fSAndrzej Pietrasiewicz } 74700a2430fSAndrzej Pietrasiewicz 74800a2430fSAndrzej Pietrasiewicz /* We will be using request */ 74900a2430fSAndrzej Pietrasiewicz ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); 75000a2430fSAndrzej Pietrasiewicz if (unlikely(ret)) 75100a2430fSAndrzej Pietrasiewicz goto error; 75200a2430fSAndrzej Pietrasiewicz 75300a2430fSAndrzej Pietrasiewicz spin_lock_irq(&epfile->ffs->eps_lock); 75400a2430fSAndrzej Pietrasiewicz 75500a2430fSAndrzej Pietrasiewicz if (epfile->ep != ep) { 75600a2430fSAndrzej Pietrasiewicz /* In the meantime, endpoint got disabled or changed. */ 75700a2430fSAndrzej Pietrasiewicz ret = -ESHUTDOWN; 7583de4e205SMichal Nazarewicz goto error_lock; 75900a2430fSAndrzej Pietrasiewicz } else if (halt) { 76000a2430fSAndrzej Pietrasiewicz /* Halt */ 76100a2430fSAndrzej Pietrasiewicz if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) 76200a2430fSAndrzej Pietrasiewicz usb_ep_set_halt(ep->ep); 76300a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 76400a2430fSAndrzej Pietrasiewicz ret = -EBADMSG; 76500a2430fSAndrzej Pietrasiewicz } else { 76600a2430fSAndrzej Pietrasiewicz /* Fire the request */ 76700a2430fSAndrzej Pietrasiewicz struct usb_request *req; 76800a2430fSAndrzej Pietrasiewicz 769c0d31b3cSDavid Cohen /* 770c0d31b3cSDavid Cohen * Sanity Check: even though data_len can't be used 771c0d31b3cSDavid Cohen * uninitialized at the time I write this comment, some 772c0d31b3cSDavid Cohen * compilers complain about this situation. 773c0d31b3cSDavid Cohen * In order to keep the code clean from warnings, data_len is 774c0d31b3cSDavid Cohen * being initialized to -EINVAL during its declaration, which 775c0d31b3cSDavid Cohen * means we can't rely on compiler anymore to warn no future 776c0d31b3cSDavid Cohen * changes won't result in data_len being used uninitialized. 777c0d31b3cSDavid Cohen * For such reason, we're adding this redundant sanity check 778c0d31b3cSDavid Cohen * here. 779c0d31b3cSDavid Cohen */ 780c0d31b3cSDavid Cohen if (unlikely(data_len == -EINVAL)) { 781c0d31b3cSDavid Cohen WARN(1, "%s: data_len == -EINVAL\n", __func__); 782c0d31b3cSDavid Cohen ret = -EINVAL; 783c0d31b3cSDavid Cohen goto error_lock; 784c0d31b3cSDavid Cohen } 785c0d31b3cSDavid Cohen 78600a2430fSAndrzej Pietrasiewicz if (io_data->aio) { 78700a2430fSAndrzej Pietrasiewicz req = usb_ep_alloc_request(ep->ep, GFP_KERNEL); 7883163c79eSMichal Nazarewicz if (unlikely(!req)) { 7893163c79eSMichal Nazarewicz ret = -ENOMEM; 79000a2430fSAndrzej Pietrasiewicz goto error_lock; 7913163c79eSMichal Nazarewicz } 79200a2430fSAndrzej Pietrasiewicz 79300a2430fSAndrzej Pietrasiewicz req->buf = data; 794c0d31b3cSDavid Cohen req->length = data_len; 79500a2430fSAndrzej Pietrasiewicz 79600a2430fSAndrzej Pietrasiewicz io_data->buf = data; 79700a2430fSAndrzej Pietrasiewicz io_data->ep = ep->ep; 79800a2430fSAndrzej Pietrasiewicz io_data->req = req; 7995e33f6fdSRobert Baldyga io_data->ffs = epfile->ffs; 80000a2430fSAndrzej Pietrasiewicz 80100a2430fSAndrzej Pietrasiewicz req->context = io_data; 80200a2430fSAndrzej Pietrasiewicz req->complete = ffs_epfile_async_io_complete; 80300a2430fSAndrzej Pietrasiewicz 80400a2430fSAndrzej Pietrasiewicz ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); 80500a2430fSAndrzej Pietrasiewicz if (unlikely(ret)) { 80600a2430fSAndrzej Pietrasiewicz usb_ep_free_request(ep->ep, req); 80700a2430fSAndrzej Pietrasiewicz goto error_lock; 80800a2430fSAndrzej Pietrasiewicz } 80900a2430fSAndrzej Pietrasiewicz ret = -EIOCBQUEUED; 81000a2430fSAndrzej Pietrasiewicz 81100a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 81200a2430fSAndrzej Pietrasiewicz } else { 81300a2430fSAndrzej Pietrasiewicz DECLARE_COMPLETION_ONSTACK(done); 81400a2430fSAndrzej Pietrasiewicz 81500a2430fSAndrzej Pietrasiewicz req = ep->req; 81600a2430fSAndrzej Pietrasiewicz req->buf = data; 817c0d31b3cSDavid Cohen req->length = data_len; 81800a2430fSAndrzej Pietrasiewicz 81900a2430fSAndrzej Pietrasiewicz req->context = &done; 82000a2430fSAndrzej Pietrasiewicz req->complete = ffs_epfile_io_complete; 82100a2430fSAndrzej Pietrasiewicz 82200a2430fSAndrzej Pietrasiewicz ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); 82300a2430fSAndrzej Pietrasiewicz 82400a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 82500a2430fSAndrzej Pietrasiewicz 82600a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 82700a2430fSAndrzej Pietrasiewicz /* nop */ 82800a2430fSAndrzej Pietrasiewicz } else if (unlikely( 82900a2430fSAndrzej Pietrasiewicz wait_for_completion_interruptible(&done))) { 83000a2430fSAndrzej Pietrasiewicz ret = -EINTR; 83100a2430fSAndrzej Pietrasiewicz usb_ep_dequeue(ep->ep, req); 83200a2430fSAndrzej Pietrasiewicz } else { 83300a2430fSAndrzej Pietrasiewicz /* 83400a2430fSAndrzej Pietrasiewicz * XXX We may end up silently droping data 83500a2430fSAndrzej Pietrasiewicz * here. Since data_len (i.e. req->length) may 83600a2430fSAndrzej Pietrasiewicz * be bigger than len (after being rounded up 83700a2430fSAndrzej Pietrasiewicz * to maxpacketsize), we may end up with more 83800a2430fSAndrzej Pietrasiewicz * data then user space has space for. 83900a2430fSAndrzej Pietrasiewicz */ 84000a2430fSAndrzej Pietrasiewicz ret = ep->status; 84100a2430fSAndrzej Pietrasiewicz if (io_data->read && ret > 0) { 842c993c39bSAl Viro ret = copy_to_iter(data, ret, &io_data->data); 843342f39a6SRui Miguel Silva if (!ret) 84400a2430fSAndrzej Pietrasiewicz ret = -EFAULT; 84500a2430fSAndrzej Pietrasiewicz } 84600a2430fSAndrzej Pietrasiewicz } 84700a2430fSAndrzej Pietrasiewicz kfree(data); 84800a2430fSAndrzej Pietrasiewicz } 84900a2430fSAndrzej Pietrasiewicz } 85000a2430fSAndrzej Pietrasiewicz 85100a2430fSAndrzej Pietrasiewicz mutex_unlock(&epfile->mutex); 85200a2430fSAndrzej Pietrasiewicz return ret; 85300a2430fSAndrzej Pietrasiewicz 85400a2430fSAndrzej Pietrasiewicz error_lock: 85500a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 85600a2430fSAndrzej Pietrasiewicz mutex_unlock(&epfile->mutex); 85700a2430fSAndrzej Pietrasiewicz error: 85800a2430fSAndrzej Pietrasiewicz kfree(data); 85900a2430fSAndrzej Pietrasiewicz return ret; 86000a2430fSAndrzej Pietrasiewicz } 86100a2430fSAndrzej Pietrasiewicz 86200a2430fSAndrzej Pietrasiewicz static int 86300a2430fSAndrzej Pietrasiewicz ffs_epfile_open(struct inode *inode, struct file *file) 86400a2430fSAndrzej Pietrasiewicz { 86500a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = inode->i_private; 86600a2430fSAndrzej Pietrasiewicz 86700a2430fSAndrzej Pietrasiewicz ENTER(); 86800a2430fSAndrzej Pietrasiewicz 86900a2430fSAndrzej Pietrasiewicz if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) 87000a2430fSAndrzej Pietrasiewicz return -ENODEV; 87100a2430fSAndrzej Pietrasiewicz 87200a2430fSAndrzej Pietrasiewicz file->private_data = epfile; 87300a2430fSAndrzej Pietrasiewicz ffs_data_opened(epfile->ffs); 87400a2430fSAndrzej Pietrasiewicz 87500a2430fSAndrzej Pietrasiewicz return 0; 87600a2430fSAndrzej Pietrasiewicz } 87700a2430fSAndrzej Pietrasiewicz 87800a2430fSAndrzej Pietrasiewicz static int ffs_aio_cancel(struct kiocb *kiocb) 87900a2430fSAndrzej Pietrasiewicz { 88000a2430fSAndrzej Pietrasiewicz struct ffs_io_data *io_data = kiocb->private; 88100a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = kiocb->ki_filp->private_data; 88200a2430fSAndrzej Pietrasiewicz int value; 88300a2430fSAndrzej Pietrasiewicz 88400a2430fSAndrzej Pietrasiewicz ENTER(); 88500a2430fSAndrzej Pietrasiewicz 88600a2430fSAndrzej Pietrasiewicz spin_lock_irq(&epfile->ffs->eps_lock); 88700a2430fSAndrzej Pietrasiewicz 88800a2430fSAndrzej Pietrasiewicz if (likely(io_data && io_data->ep && io_data->req)) 88900a2430fSAndrzej Pietrasiewicz value = usb_ep_dequeue(io_data->ep, io_data->req); 89000a2430fSAndrzej Pietrasiewicz else 89100a2430fSAndrzej Pietrasiewicz value = -EINVAL; 89200a2430fSAndrzej Pietrasiewicz 89300a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 89400a2430fSAndrzej Pietrasiewicz 89500a2430fSAndrzej Pietrasiewicz return value; 89600a2430fSAndrzej Pietrasiewicz } 89700a2430fSAndrzej Pietrasiewicz 89870e60d91SAl Viro static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) 89900a2430fSAndrzej Pietrasiewicz { 90070e60d91SAl Viro struct ffs_io_data io_data, *p = &io_data; 901de2080d4SAl Viro ssize_t res; 90200a2430fSAndrzej Pietrasiewicz 90300a2430fSAndrzej Pietrasiewicz ENTER(); 90400a2430fSAndrzej Pietrasiewicz 90570e60d91SAl Viro if (!is_sync_kiocb(kiocb)) { 90670e60d91SAl Viro p = kmalloc(sizeof(io_data), GFP_KERNEL); 90770e60d91SAl Viro if (unlikely(!p)) 90800a2430fSAndrzej Pietrasiewicz return -ENOMEM; 90970e60d91SAl Viro p->aio = true; 91070e60d91SAl Viro } else { 91170e60d91SAl Viro p->aio = false; 91270e60d91SAl Viro } 91300a2430fSAndrzej Pietrasiewicz 91470e60d91SAl Viro p->read = false; 91570e60d91SAl Viro p->kiocb = kiocb; 91670e60d91SAl Viro p->data = *from; 91770e60d91SAl Viro p->mm = current->mm; 91800a2430fSAndrzej Pietrasiewicz 91970e60d91SAl Viro kiocb->private = p; 92000a2430fSAndrzej Pietrasiewicz 9214088acf1SRui Miguel Silva if (p->aio) 92200a2430fSAndrzej Pietrasiewicz kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); 92300a2430fSAndrzej Pietrasiewicz 92470e60d91SAl Viro res = ffs_epfile_io(kiocb->ki_filp, p); 92570e60d91SAl Viro if (res == -EIOCBQUEUED) 92670e60d91SAl Viro return res; 92770e60d91SAl Viro if (p->aio) 92870e60d91SAl Viro kfree(p); 92970e60d91SAl Viro else 93070e60d91SAl Viro *from = p->data; 931de2080d4SAl Viro return res; 93200a2430fSAndrzej Pietrasiewicz } 93300a2430fSAndrzej Pietrasiewicz 93470e60d91SAl Viro static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) 93500a2430fSAndrzej Pietrasiewicz { 93670e60d91SAl Viro struct ffs_io_data io_data, *p = &io_data; 937de2080d4SAl Viro ssize_t res; 93800a2430fSAndrzej Pietrasiewicz 93900a2430fSAndrzej Pietrasiewicz ENTER(); 94000a2430fSAndrzej Pietrasiewicz 94170e60d91SAl Viro if (!is_sync_kiocb(kiocb)) { 94270e60d91SAl Viro p = kmalloc(sizeof(io_data), GFP_KERNEL); 94370e60d91SAl Viro if (unlikely(!p)) 94400a2430fSAndrzej Pietrasiewicz return -ENOMEM; 94570e60d91SAl Viro p->aio = true; 94670e60d91SAl Viro } else { 94770e60d91SAl Viro p->aio = false; 94800a2430fSAndrzej Pietrasiewicz } 94900a2430fSAndrzej Pietrasiewicz 95070e60d91SAl Viro p->read = true; 95170e60d91SAl Viro p->kiocb = kiocb; 95270e60d91SAl Viro if (p->aio) { 95370e60d91SAl Viro p->to_free = dup_iter(&p->data, to, GFP_KERNEL); 95470e60d91SAl Viro if (!p->to_free) { 95570e60d91SAl Viro kfree(p); 95670e60d91SAl Viro return -ENOMEM; 95770e60d91SAl Viro } 95870e60d91SAl Viro } else { 95970e60d91SAl Viro p->data = *to; 96070e60d91SAl Viro p->to_free = NULL; 96170e60d91SAl Viro } 96270e60d91SAl Viro p->mm = current->mm; 96300a2430fSAndrzej Pietrasiewicz 96470e60d91SAl Viro kiocb->private = p; 96500a2430fSAndrzej Pietrasiewicz 9664088acf1SRui Miguel Silva if (p->aio) 96700a2430fSAndrzej Pietrasiewicz kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); 96800a2430fSAndrzej Pietrasiewicz 96970e60d91SAl Viro res = ffs_epfile_io(kiocb->ki_filp, p); 97070e60d91SAl Viro if (res == -EIOCBQUEUED) 97170e60d91SAl Viro return res; 97270e60d91SAl Viro 97370e60d91SAl Viro if (p->aio) { 97470e60d91SAl Viro kfree(p->to_free); 97570e60d91SAl Viro kfree(p); 97670e60d91SAl Viro } else { 97770e60d91SAl Viro *to = p->data; 978de2080d4SAl Viro } 979de2080d4SAl Viro return res; 98000a2430fSAndrzej Pietrasiewicz } 98100a2430fSAndrzej Pietrasiewicz 98200a2430fSAndrzej Pietrasiewicz static int 98300a2430fSAndrzej Pietrasiewicz ffs_epfile_release(struct inode *inode, struct file *file) 98400a2430fSAndrzej Pietrasiewicz { 98500a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = inode->i_private; 98600a2430fSAndrzej Pietrasiewicz 98700a2430fSAndrzej Pietrasiewicz ENTER(); 98800a2430fSAndrzej Pietrasiewicz 98900a2430fSAndrzej Pietrasiewicz ffs_data_closed(epfile->ffs); 99000a2430fSAndrzej Pietrasiewicz 99100a2430fSAndrzej Pietrasiewicz return 0; 99200a2430fSAndrzej Pietrasiewicz } 99300a2430fSAndrzej Pietrasiewicz 99400a2430fSAndrzej Pietrasiewicz static long ffs_epfile_ioctl(struct file *file, unsigned code, 99500a2430fSAndrzej Pietrasiewicz unsigned long value) 99600a2430fSAndrzej Pietrasiewicz { 99700a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = file->private_data; 99800a2430fSAndrzej Pietrasiewicz int ret; 99900a2430fSAndrzej Pietrasiewicz 100000a2430fSAndrzej Pietrasiewicz ENTER(); 100100a2430fSAndrzej Pietrasiewicz 100200a2430fSAndrzej Pietrasiewicz if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) 100300a2430fSAndrzej Pietrasiewicz return -ENODEV; 100400a2430fSAndrzej Pietrasiewicz 100500a2430fSAndrzej Pietrasiewicz spin_lock_irq(&epfile->ffs->eps_lock); 100600a2430fSAndrzej Pietrasiewicz if (likely(epfile->ep)) { 100700a2430fSAndrzej Pietrasiewicz switch (code) { 100800a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_FIFO_STATUS: 100900a2430fSAndrzej Pietrasiewicz ret = usb_ep_fifo_status(epfile->ep->ep); 101000a2430fSAndrzej Pietrasiewicz break; 101100a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_FIFO_FLUSH: 101200a2430fSAndrzej Pietrasiewicz usb_ep_fifo_flush(epfile->ep->ep); 101300a2430fSAndrzej Pietrasiewicz ret = 0; 101400a2430fSAndrzej Pietrasiewicz break; 101500a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_CLEAR_HALT: 101600a2430fSAndrzej Pietrasiewicz ret = usb_ep_clear_halt(epfile->ep->ep); 101700a2430fSAndrzej Pietrasiewicz break; 101800a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_ENDPOINT_REVMAP: 101900a2430fSAndrzej Pietrasiewicz ret = epfile->ep->num; 102000a2430fSAndrzej Pietrasiewicz break; 1021c559a353SRobert Baldyga case FUNCTIONFS_ENDPOINT_DESC: 1022c559a353SRobert Baldyga { 1023c559a353SRobert Baldyga int desc_idx; 1024c559a353SRobert Baldyga struct usb_endpoint_descriptor *desc; 1025c559a353SRobert Baldyga 1026c559a353SRobert Baldyga switch (epfile->ffs->gadget->speed) { 1027c559a353SRobert Baldyga case USB_SPEED_SUPER: 1028c559a353SRobert Baldyga desc_idx = 2; 1029c559a353SRobert Baldyga break; 1030c559a353SRobert Baldyga case USB_SPEED_HIGH: 1031c559a353SRobert Baldyga desc_idx = 1; 1032c559a353SRobert Baldyga break; 1033c559a353SRobert Baldyga default: 1034c559a353SRobert Baldyga desc_idx = 0; 1035c559a353SRobert Baldyga } 1036c559a353SRobert Baldyga desc = epfile->ep->descs[desc_idx]; 1037c559a353SRobert Baldyga 1038c559a353SRobert Baldyga spin_unlock_irq(&epfile->ffs->eps_lock); 1039c559a353SRobert Baldyga ret = copy_to_user((void *)value, desc, sizeof(*desc)); 1040c559a353SRobert Baldyga if (ret) 1041c559a353SRobert Baldyga ret = -EFAULT; 1042c559a353SRobert Baldyga return ret; 1043c559a353SRobert Baldyga } 104400a2430fSAndrzej Pietrasiewicz default: 104500a2430fSAndrzej Pietrasiewicz ret = -ENOTTY; 104600a2430fSAndrzej Pietrasiewicz } 104700a2430fSAndrzej Pietrasiewicz } else { 104800a2430fSAndrzej Pietrasiewicz ret = -ENODEV; 104900a2430fSAndrzej Pietrasiewicz } 105000a2430fSAndrzej Pietrasiewicz spin_unlock_irq(&epfile->ffs->eps_lock); 105100a2430fSAndrzej Pietrasiewicz 105200a2430fSAndrzej Pietrasiewicz return ret; 105300a2430fSAndrzej Pietrasiewicz } 105400a2430fSAndrzej Pietrasiewicz 105500a2430fSAndrzej Pietrasiewicz static const struct file_operations ffs_epfile_operations = { 105600a2430fSAndrzej Pietrasiewicz .llseek = no_llseek, 105700a2430fSAndrzej Pietrasiewicz 105800a2430fSAndrzej Pietrasiewicz .open = ffs_epfile_open, 105970e60d91SAl Viro .write_iter = ffs_epfile_write_iter, 106070e60d91SAl Viro .read_iter = ffs_epfile_read_iter, 106100a2430fSAndrzej Pietrasiewicz .release = ffs_epfile_release, 106200a2430fSAndrzej Pietrasiewicz .unlocked_ioctl = ffs_epfile_ioctl, 106300a2430fSAndrzej Pietrasiewicz }; 106400a2430fSAndrzej Pietrasiewicz 106500a2430fSAndrzej Pietrasiewicz 106600a2430fSAndrzej Pietrasiewicz /* File system and super block operations ***********************************/ 106700a2430fSAndrzej Pietrasiewicz 106800a2430fSAndrzej Pietrasiewicz /* 106900a2430fSAndrzej Pietrasiewicz * Mounting the file system creates a controller file, used first for 107000a2430fSAndrzej Pietrasiewicz * function configuration then later for event monitoring. 107100a2430fSAndrzej Pietrasiewicz */ 107200a2430fSAndrzej Pietrasiewicz 107300a2430fSAndrzej Pietrasiewicz static struct inode *__must_check 107400a2430fSAndrzej Pietrasiewicz ffs_sb_make_inode(struct super_block *sb, void *data, 107500a2430fSAndrzej Pietrasiewicz const struct file_operations *fops, 107600a2430fSAndrzej Pietrasiewicz const struct inode_operations *iops, 107700a2430fSAndrzej Pietrasiewicz struct ffs_file_perms *perms) 107800a2430fSAndrzej Pietrasiewicz { 107900a2430fSAndrzej Pietrasiewicz struct inode *inode; 108000a2430fSAndrzej Pietrasiewicz 108100a2430fSAndrzej Pietrasiewicz ENTER(); 108200a2430fSAndrzej Pietrasiewicz 108300a2430fSAndrzej Pietrasiewicz inode = new_inode(sb); 108400a2430fSAndrzej Pietrasiewicz 108500a2430fSAndrzej Pietrasiewicz if (likely(inode)) { 108600a2430fSAndrzej Pietrasiewicz struct timespec current_time = CURRENT_TIME; 108700a2430fSAndrzej Pietrasiewicz 108800a2430fSAndrzej Pietrasiewicz inode->i_ino = get_next_ino(); 108900a2430fSAndrzej Pietrasiewicz inode->i_mode = perms->mode; 109000a2430fSAndrzej Pietrasiewicz inode->i_uid = perms->uid; 109100a2430fSAndrzej Pietrasiewicz inode->i_gid = perms->gid; 109200a2430fSAndrzej Pietrasiewicz inode->i_atime = current_time; 109300a2430fSAndrzej Pietrasiewicz inode->i_mtime = current_time; 109400a2430fSAndrzej Pietrasiewicz inode->i_ctime = current_time; 109500a2430fSAndrzej Pietrasiewicz inode->i_private = data; 109600a2430fSAndrzej Pietrasiewicz if (fops) 109700a2430fSAndrzej Pietrasiewicz inode->i_fop = fops; 109800a2430fSAndrzej Pietrasiewicz if (iops) 109900a2430fSAndrzej Pietrasiewicz inode->i_op = iops; 110000a2430fSAndrzej Pietrasiewicz } 110100a2430fSAndrzej Pietrasiewicz 110200a2430fSAndrzej Pietrasiewicz return inode; 110300a2430fSAndrzej Pietrasiewicz } 110400a2430fSAndrzej Pietrasiewicz 110500a2430fSAndrzej Pietrasiewicz /* Create "regular" file */ 11061bb27cacSAl Viro static struct dentry *ffs_sb_create_file(struct super_block *sb, 110700a2430fSAndrzej Pietrasiewicz const char *name, void *data, 11081bb27cacSAl Viro const struct file_operations *fops) 110900a2430fSAndrzej Pietrasiewicz { 111000a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = sb->s_fs_info; 111100a2430fSAndrzej Pietrasiewicz struct dentry *dentry; 111200a2430fSAndrzej Pietrasiewicz struct inode *inode; 111300a2430fSAndrzej Pietrasiewicz 111400a2430fSAndrzej Pietrasiewicz ENTER(); 111500a2430fSAndrzej Pietrasiewicz 111600a2430fSAndrzej Pietrasiewicz dentry = d_alloc_name(sb->s_root, name); 111700a2430fSAndrzej Pietrasiewicz if (unlikely(!dentry)) 111800a2430fSAndrzej Pietrasiewicz return NULL; 111900a2430fSAndrzej Pietrasiewicz 112000a2430fSAndrzej Pietrasiewicz inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms); 112100a2430fSAndrzej Pietrasiewicz if (unlikely(!inode)) { 112200a2430fSAndrzej Pietrasiewicz dput(dentry); 112300a2430fSAndrzej Pietrasiewicz return NULL; 112400a2430fSAndrzej Pietrasiewicz } 112500a2430fSAndrzej Pietrasiewicz 112600a2430fSAndrzej Pietrasiewicz d_add(dentry, inode); 11271bb27cacSAl Viro return dentry; 112800a2430fSAndrzej Pietrasiewicz } 112900a2430fSAndrzej Pietrasiewicz 113000a2430fSAndrzej Pietrasiewicz /* Super block */ 113100a2430fSAndrzej Pietrasiewicz static const struct super_operations ffs_sb_operations = { 113200a2430fSAndrzej Pietrasiewicz .statfs = simple_statfs, 113300a2430fSAndrzej Pietrasiewicz .drop_inode = generic_delete_inode, 113400a2430fSAndrzej Pietrasiewicz }; 113500a2430fSAndrzej Pietrasiewicz 113600a2430fSAndrzej Pietrasiewicz struct ffs_sb_fill_data { 113700a2430fSAndrzej Pietrasiewicz struct ffs_file_perms perms; 113800a2430fSAndrzej Pietrasiewicz umode_t root_mode; 113900a2430fSAndrzej Pietrasiewicz const char *dev_name; 114018d6b32fSRobert Baldyga bool no_disconnect; 114100a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs_data; 114200a2430fSAndrzej Pietrasiewicz }; 114300a2430fSAndrzej Pietrasiewicz 114400a2430fSAndrzej Pietrasiewicz static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) 114500a2430fSAndrzej Pietrasiewicz { 114600a2430fSAndrzej Pietrasiewicz struct ffs_sb_fill_data *data = _data; 114700a2430fSAndrzej Pietrasiewicz struct inode *inode; 114800a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = data->ffs_data; 114900a2430fSAndrzej Pietrasiewicz 115000a2430fSAndrzej Pietrasiewicz ENTER(); 115100a2430fSAndrzej Pietrasiewicz 115200a2430fSAndrzej Pietrasiewicz ffs->sb = sb; 115300a2430fSAndrzej Pietrasiewicz data->ffs_data = NULL; 115400a2430fSAndrzej Pietrasiewicz sb->s_fs_info = ffs; 115500a2430fSAndrzej Pietrasiewicz sb->s_blocksize = PAGE_CACHE_SIZE; 115600a2430fSAndrzej Pietrasiewicz sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 115700a2430fSAndrzej Pietrasiewicz sb->s_magic = FUNCTIONFS_MAGIC; 115800a2430fSAndrzej Pietrasiewicz sb->s_op = &ffs_sb_operations; 115900a2430fSAndrzej Pietrasiewicz sb->s_time_gran = 1; 116000a2430fSAndrzej Pietrasiewicz 116100a2430fSAndrzej Pietrasiewicz /* Root inode */ 116200a2430fSAndrzej Pietrasiewicz data->perms.mode = data->root_mode; 116300a2430fSAndrzej Pietrasiewicz inode = ffs_sb_make_inode(sb, NULL, 116400a2430fSAndrzej Pietrasiewicz &simple_dir_operations, 116500a2430fSAndrzej Pietrasiewicz &simple_dir_inode_operations, 116600a2430fSAndrzej Pietrasiewicz &data->perms); 116700a2430fSAndrzej Pietrasiewicz sb->s_root = d_make_root(inode); 116800a2430fSAndrzej Pietrasiewicz if (unlikely(!sb->s_root)) 116900a2430fSAndrzej Pietrasiewicz return -ENOMEM; 117000a2430fSAndrzej Pietrasiewicz 117100a2430fSAndrzej Pietrasiewicz /* EP0 file */ 117200a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, 11731bb27cacSAl Viro &ffs_ep0_operations))) 117400a2430fSAndrzej Pietrasiewicz return -ENOMEM; 117500a2430fSAndrzej Pietrasiewicz 117600a2430fSAndrzej Pietrasiewicz return 0; 117700a2430fSAndrzej Pietrasiewicz } 117800a2430fSAndrzej Pietrasiewicz 117900a2430fSAndrzej Pietrasiewicz static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) 118000a2430fSAndrzej Pietrasiewicz { 118100a2430fSAndrzej Pietrasiewicz ENTER(); 118200a2430fSAndrzej Pietrasiewicz 118300a2430fSAndrzej Pietrasiewicz if (!opts || !*opts) 118400a2430fSAndrzej Pietrasiewicz return 0; 118500a2430fSAndrzej Pietrasiewicz 118600a2430fSAndrzej Pietrasiewicz for (;;) { 118700a2430fSAndrzej Pietrasiewicz unsigned long value; 118800a2430fSAndrzej Pietrasiewicz char *eq, *comma; 118900a2430fSAndrzej Pietrasiewicz 119000a2430fSAndrzej Pietrasiewicz /* Option limit */ 119100a2430fSAndrzej Pietrasiewicz comma = strchr(opts, ','); 119200a2430fSAndrzej Pietrasiewicz if (comma) 119300a2430fSAndrzej Pietrasiewicz *comma = 0; 119400a2430fSAndrzej Pietrasiewicz 119500a2430fSAndrzej Pietrasiewicz /* Value limit */ 119600a2430fSAndrzej Pietrasiewicz eq = strchr(opts, '='); 119700a2430fSAndrzej Pietrasiewicz if (unlikely(!eq)) { 119800a2430fSAndrzej Pietrasiewicz pr_err("'=' missing in %s\n", opts); 119900a2430fSAndrzej Pietrasiewicz return -EINVAL; 120000a2430fSAndrzej Pietrasiewicz } 120100a2430fSAndrzej Pietrasiewicz *eq = 0; 120200a2430fSAndrzej Pietrasiewicz 120300a2430fSAndrzej Pietrasiewicz /* Parse value */ 120400a2430fSAndrzej Pietrasiewicz if (kstrtoul(eq + 1, 0, &value)) { 120500a2430fSAndrzej Pietrasiewicz pr_err("%s: invalid value: %s\n", opts, eq + 1); 120600a2430fSAndrzej Pietrasiewicz return -EINVAL; 120700a2430fSAndrzej Pietrasiewicz } 120800a2430fSAndrzej Pietrasiewicz 120900a2430fSAndrzej Pietrasiewicz /* Interpret option */ 121000a2430fSAndrzej Pietrasiewicz switch (eq - opts) { 121118d6b32fSRobert Baldyga case 13: 121218d6b32fSRobert Baldyga if (!memcmp(opts, "no_disconnect", 13)) 121318d6b32fSRobert Baldyga data->no_disconnect = !!value; 121418d6b32fSRobert Baldyga else 121518d6b32fSRobert Baldyga goto invalid; 121618d6b32fSRobert Baldyga break; 121700a2430fSAndrzej Pietrasiewicz case 5: 121800a2430fSAndrzej Pietrasiewicz if (!memcmp(opts, "rmode", 5)) 121900a2430fSAndrzej Pietrasiewicz data->root_mode = (value & 0555) | S_IFDIR; 122000a2430fSAndrzej Pietrasiewicz else if (!memcmp(opts, "fmode", 5)) 122100a2430fSAndrzej Pietrasiewicz data->perms.mode = (value & 0666) | S_IFREG; 122200a2430fSAndrzej Pietrasiewicz else 122300a2430fSAndrzej Pietrasiewicz goto invalid; 122400a2430fSAndrzej Pietrasiewicz break; 122500a2430fSAndrzej Pietrasiewicz 122600a2430fSAndrzej Pietrasiewicz case 4: 122700a2430fSAndrzej Pietrasiewicz if (!memcmp(opts, "mode", 4)) { 122800a2430fSAndrzej Pietrasiewicz data->root_mode = (value & 0555) | S_IFDIR; 122900a2430fSAndrzej Pietrasiewicz data->perms.mode = (value & 0666) | S_IFREG; 123000a2430fSAndrzej Pietrasiewicz } else { 123100a2430fSAndrzej Pietrasiewicz goto invalid; 123200a2430fSAndrzej Pietrasiewicz } 123300a2430fSAndrzej Pietrasiewicz break; 123400a2430fSAndrzej Pietrasiewicz 123500a2430fSAndrzej Pietrasiewicz case 3: 123600a2430fSAndrzej Pietrasiewicz if (!memcmp(opts, "uid", 3)) { 123700a2430fSAndrzej Pietrasiewicz data->perms.uid = make_kuid(current_user_ns(), value); 123800a2430fSAndrzej Pietrasiewicz if (!uid_valid(data->perms.uid)) { 123900a2430fSAndrzej Pietrasiewicz pr_err("%s: unmapped value: %lu\n", opts, value); 124000a2430fSAndrzej Pietrasiewicz return -EINVAL; 124100a2430fSAndrzej Pietrasiewicz } 124200a2430fSAndrzej Pietrasiewicz } else if (!memcmp(opts, "gid", 3)) { 124300a2430fSAndrzej Pietrasiewicz data->perms.gid = make_kgid(current_user_ns(), value); 124400a2430fSAndrzej Pietrasiewicz if (!gid_valid(data->perms.gid)) { 124500a2430fSAndrzej Pietrasiewicz pr_err("%s: unmapped value: %lu\n", opts, value); 124600a2430fSAndrzej Pietrasiewicz return -EINVAL; 124700a2430fSAndrzej Pietrasiewicz } 124800a2430fSAndrzej Pietrasiewicz } else { 124900a2430fSAndrzej Pietrasiewicz goto invalid; 125000a2430fSAndrzej Pietrasiewicz } 125100a2430fSAndrzej Pietrasiewicz break; 125200a2430fSAndrzej Pietrasiewicz 125300a2430fSAndrzej Pietrasiewicz default: 125400a2430fSAndrzej Pietrasiewicz invalid: 125500a2430fSAndrzej Pietrasiewicz pr_err("%s: invalid option\n", opts); 125600a2430fSAndrzej Pietrasiewicz return -EINVAL; 125700a2430fSAndrzej Pietrasiewicz } 125800a2430fSAndrzej Pietrasiewicz 125900a2430fSAndrzej Pietrasiewicz /* Next iteration */ 126000a2430fSAndrzej Pietrasiewicz if (!comma) 126100a2430fSAndrzej Pietrasiewicz break; 126200a2430fSAndrzej Pietrasiewicz opts = comma + 1; 126300a2430fSAndrzej Pietrasiewicz } 126400a2430fSAndrzej Pietrasiewicz 126500a2430fSAndrzej Pietrasiewicz return 0; 126600a2430fSAndrzej Pietrasiewicz } 126700a2430fSAndrzej Pietrasiewicz 126800a2430fSAndrzej Pietrasiewicz /* "mount -t functionfs dev_name /dev/function" ends up here */ 126900a2430fSAndrzej Pietrasiewicz 127000a2430fSAndrzej Pietrasiewicz static struct dentry * 127100a2430fSAndrzej Pietrasiewicz ffs_fs_mount(struct file_system_type *t, int flags, 127200a2430fSAndrzej Pietrasiewicz const char *dev_name, void *opts) 127300a2430fSAndrzej Pietrasiewicz { 127400a2430fSAndrzej Pietrasiewicz struct ffs_sb_fill_data data = { 127500a2430fSAndrzej Pietrasiewicz .perms = { 127600a2430fSAndrzej Pietrasiewicz .mode = S_IFREG | 0600, 127700a2430fSAndrzej Pietrasiewicz .uid = GLOBAL_ROOT_UID, 127800a2430fSAndrzej Pietrasiewicz .gid = GLOBAL_ROOT_GID, 127900a2430fSAndrzej Pietrasiewicz }, 128000a2430fSAndrzej Pietrasiewicz .root_mode = S_IFDIR | 0500, 128118d6b32fSRobert Baldyga .no_disconnect = false, 128200a2430fSAndrzej Pietrasiewicz }; 128300a2430fSAndrzej Pietrasiewicz struct dentry *rv; 128400a2430fSAndrzej Pietrasiewicz int ret; 128500a2430fSAndrzej Pietrasiewicz void *ffs_dev; 128600a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs; 128700a2430fSAndrzej Pietrasiewicz 128800a2430fSAndrzej Pietrasiewicz ENTER(); 128900a2430fSAndrzej Pietrasiewicz 129000a2430fSAndrzej Pietrasiewicz ret = ffs_fs_parse_opts(&data, opts); 129100a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 129200a2430fSAndrzej Pietrasiewicz return ERR_PTR(ret); 129300a2430fSAndrzej Pietrasiewicz 129400a2430fSAndrzej Pietrasiewicz ffs = ffs_data_new(); 129500a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs)) 129600a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 129700a2430fSAndrzej Pietrasiewicz ffs->file_perms = data.perms; 129818d6b32fSRobert Baldyga ffs->no_disconnect = data.no_disconnect; 129900a2430fSAndrzej Pietrasiewicz 130000a2430fSAndrzej Pietrasiewicz ffs->dev_name = kstrdup(dev_name, GFP_KERNEL); 130100a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs->dev_name)) { 130200a2430fSAndrzej Pietrasiewicz ffs_data_put(ffs); 130300a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 130400a2430fSAndrzej Pietrasiewicz } 130500a2430fSAndrzej Pietrasiewicz 130600a2430fSAndrzej Pietrasiewicz ffs_dev = ffs_acquire_dev(dev_name); 130700a2430fSAndrzej Pietrasiewicz if (IS_ERR(ffs_dev)) { 130800a2430fSAndrzej Pietrasiewicz ffs_data_put(ffs); 130900a2430fSAndrzej Pietrasiewicz return ERR_CAST(ffs_dev); 131000a2430fSAndrzej Pietrasiewicz } 131100a2430fSAndrzej Pietrasiewicz ffs->private_data = ffs_dev; 131200a2430fSAndrzej Pietrasiewicz data.ffs_data = ffs; 131300a2430fSAndrzej Pietrasiewicz 131400a2430fSAndrzej Pietrasiewicz rv = mount_nodev(t, flags, &data, ffs_sb_fill); 131500a2430fSAndrzej Pietrasiewicz if (IS_ERR(rv) && data.ffs_data) { 131600a2430fSAndrzej Pietrasiewicz ffs_release_dev(data.ffs_data); 131700a2430fSAndrzej Pietrasiewicz ffs_data_put(data.ffs_data); 131800a2430fSAndrzej Pietrasiewicz } 131900a2430fSAndrzej Pietrasiewicz return rv; 132000a2430fSAndrzej Pietrasiewicz } 132100a2430fSAndrzej Pietrasiewicz 132200a2430fSAndrzej Pietrasiewicz static void 132300a2430fSAndrzej Pietrasiewicz ffs_fs_kill_sb(struct super_block *sb) 132400a2430fSAndrzej Pietrasiewicz { 132500a2430fSAndrzej Pietrasiewicz ENTER(); 132600a2430fSAndrzej Pietrasiewicz 132700a2430fSAndrzej Pietrasiewicz kill_litter_super(sb); 132800a2430fSAndrzej Pietrasiewicz if (sb->s_fs_info) { 132900a2430fSAndrzej Pietrasiewicz ffs_release_dev(sb->s_fs_info); 133018d6b32fSRobert Baldyga ffs_data_closed(sb->s_fs_info); 133100a2430fSAndrzej Pietrasiewicz ffs_data_put(sb->s_fs_info); 133200a2430fSAndrzej Pietrasiewicz } 133300a2430fSAndrzej Pietrasiewicz } 133400a2430fSAndrzej Pietrasiewicz 133500a2430fSAndrzej Pietrasiewicz static struct file_system_type ffs_fs_type = { 133600a2430fSAndrzej Pietrasiewicz .owner = THIS_MODULE, 133700a2430fSAndrzej Pietrasiewicz .name = "functionfs", 133800a2430fSAndrzej Pietrasiewicz .mount = ffs_fs_mount, 133900a2430fSAndrzej Pietrasiewicz .kill_sb = ffs_fs_kill_sb, 134000a2430fSAndrzej Pietrasiewicz }; 134100a2430fSAndrzej Pietrasiewicz MODULE_ALIAS_FS("functionfs"); 134200a2430fSAndrzej Pietrasiewicz 134300a2430fSAndrzej Pietrasiewicz 134400a2430fSAndrzej Pietrasiewicz /* Driver's main init/cleanup functions *************************************/ 134500a2430fSAndrzej Pietrasiewicz 134600a2430fSAndrzej Pietrasiewicz static int functionfs_init(void) 134700a2430fSAndrzej Pietrasiewicz { 134800a2430fSAndrzej Pietrasiewicz int ret; 134900a2430fSAndrzej Pietrasiewicz 135000a2430fSAndrzej Pietrasiewicz ENTER(); 135100a2430fSAndrzej Pietrasiewicz 135200a2430fSAndrzej Pietrasiewicz ret = register_filesystem(&ffs_fs_type); 135300a2430fSAndrzej Pietrasiewicz if (likely(!ret)) 135400a2430fSAndrzej Pietrasiewicz pr_info("file system registered\n"); 135500a2430fSAndrzej Pietrasiewicz else 135600a2430fSAndrzej Pietrasiewicz pr_err("failed registering file system (%d)\n", ret); 135700a2430fSAndrzej Pietrasiewicz 135800a2430fSAndrzej Pietrasiewicz return ret; 135900a2430fSAndrzej Pietrasiewicz } 136000a2430fSAndrzej Pietrasiewicz 136100a2430fSAndrzej Pietrasiewicz static void functionfs_cleanup(void) 136200a2430fSAndrzej Pietrasiewicz { 136300a2430fSAndrzej Pietrasiewicz ENTER(); 136400a2430fSAndrzej Pietrasiewicz 136500a2430fSAndrzej Pietrasiewicz pr_info("unloading\n"); 136600a2430fSAndrzej Pietrasiewicz unregister_filesystem(&ffs_fs_type); 136700a2430fSAndrzej Pietrasiewicz } 136800a2430fSAndrzej Pietrasiewicz 136900a2430fSAndrzej Pietrasiewicz 137000a2430fSAndrzej Pietrasiewicz /* ffs_data and ffs_function construction and destruction code **************/ 137100a2430fSAndrzej Pietrasiewicz 137200a2430fSAndrzej Pietrasiewicz static void ffs_data_clear(struct ffs_data *ffs); 137300a2430fSAndrzej Pietrasiewicz static void ffs_data_reset(struct ffs_data *ffs); 137400a2430fSAndrzej Pietrasiewicz 137500a2430fSAndrzej Pietrasiewicz static void ffs_data_get(struct ffs_data *ffs) 137600a2430fSAndrzej Pietrasiewicz { 137700a2430fSAndrzej Pietrasiewicz ENTER(); 137800a2430fSAndrzej Pietrasiewicz 137900a2430fSAndrzej Pietrasiewicz atomic_inc(&ffs->ref); 138000a2430fSAndrzej Pietrasiewicz } 138100a2430fSAndrzej Pietrasiewicz 138200a2430fSAndrzej Pietrasiewicz static void ffs_data_opened(struct ffs_data *ffs) 138300a2430fSAndrzej Pietrasiewicz { 138400a2430fSAndrzej Pietrasiewicz ENTER(); 138500a2430fSAndrzej Pietrasiewicz 138600a2430fSAndrzej Pietrasiewicz atomic_inc(&ffs->ref); 138718d6b32fSRobert Baldyga if (atomic_add_return(1, &ffs->opened) == 1 && 138818d6b32fSRobert Baldyga ffs->state == FFS_DEACTIVATED) { 138918d6b32fSRobert Baldyga ffs->state = FFS_CLOSING; 139018d6b32fSRobert Baldyga ffs_data_reset(ffs); 139118d6b32fSRobert Baldyga } 139200a2430fSAndrzej Pietrasiewicz } 139300a2430fSAndrzej Pietrasiewicz 139400a2430fSAndrzej Pietrasiewicz static void ffs_data_put(struct ffs_data *ffs) 139500a2430fSAndrzej Pietrasiewicz { 139600a2430fSAndrzej Pietrasiewicz ENTER(); 139700a2430fSAndrzej Pietrasiewicz 139800a2430fSAndrzej Pietrasiewicz if (unlikely(atomic_dec_and_test(&ffs->ref))) { 139900a2430fSAndrzej Pietrasiewicz pr_info("%s(): freeing\n", __func__); 140000a2430fSAndrzej Pietrasiewicz ffs_data_clear(ffs); 140100a2430fSAndrzej Pietrasiewicz BUG_ON(waitqueue_active(&ffs->ev.waitq) || 140200a2430fSAndrzej Pietrasiewicz waitqueue_active(&ffs->ep0req_completion.wait)); 140300a2430fSAndrzej Pietrasiewicz kfree(ffs->dev_name); 140400a2430fSAndrzej Pietrasiewicz kfree(ffs); 140500a2430fSAndrzej Pietrasiewicz } 140600a2430fSAndrzej Pietrasiewicz } 140700a2430fSAndrzej Pietrasiewicz 140800a2430fSAndrzej Pietrasiewicz static void ffs_data_closed(struct ffs_data *ffs) 140900a2430fSAndrzej Pietrasiewicz { 141000a2430fSAndrzej Pietrasiewicz ENTER(); 141100a2430fSAndrzej Pietrasiewicz 141200a2430fSAndrzej Pietrasiewicz if (atomic_dec_and_test(&ffs->opened)) { 141318d6b32fSRobert Baldyga if (ffs->no_disconnect) { 141418d6b32fSRobert Baldyga ffs->state = FFS_DEACTIVATED; 141518d6b32fSRobert Baldyga if (ffs->epfiles) { 141618d6b32fSRobert Baldyga ffs_epfiles_destroy(ffs->epfiles, 141718d6b32fSRobert Baldyga ffs->eps_count); 141818d6b32fSRobert Baldyga ffs->epfiles = NULL; 141918d6b32fSRobert Baldyga } 142018d6b32fSRobert Baldyga if (ffs->setup_state == FFS_SETUP_PENDING) 142118d6b32fSRobert Baldyga __ffs_ep0_stall(ffs); 142218d6b32fSRobert Baldyga } else { 142318d6b32fSRobert Baldyga ffs->state = FFS_CLOSING; 142418d6b32fSRobert Baldyga ffs_data_reset(ffs); 142518d6b32fSRobert Baldyga } 142618d6b32fSRobert Baldyga } 142718d6b32fSRobert Baldyga if (atomic_read(&ffs->opened) < 0) { 142800a2430fSAndrzej Pietrasiewicz ffs->state = FFS_CLOSING; 142900a2430fSAndrzej Pietrasiewicz ffs_data_reset(ffs); 143000a2430fSAndrzej Pietrasiewicz } 143100a2430fSAndrzej Pietrasiewicz 143200a2430fSAndrzej Pietrasiewicz ffs_data_put(ffs); 143300a2430fSAndrzej Pietrasiewicz } 143400a2430fSAndrzej Pietrasiewicz 143500a2430fSAndrzej Pietrasiewicz static struct ffs_data *ffs_data_new(void) 143600a2430fSAndrzej Pietrasiewicz { 143700a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL); 143800a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs)) 143900a2430fSAndrzej Pietrasiewicz return NULL; 144000a2430fSAndrzej Pietrasiewicz 144100a2430fSAndrzej Pietrasiewicz ENTER(); 144200a2430fSAndrzej Pietrasiewicz 144300a2430fSAndrzej Pietrasiewicz atomic_set(&ffs->ref, 1); 144400a2430fSAndrzej Pietrasiewicz atomic_set(&ffs->opened, 0); 144500a2430fSAndrzej Pietrasiewicz ffs->state = FFS_READ_DESCRIPTORS; 144600a2430fSAndrzej Pietrasiewicz mutex_init(&ffs->mutex); 144700a2430fSAndrzej Pietrasiewicz spin_lock_init(&ffs->eps_lock); 144800a2430fSAndrzej Pietrasiewicz init_waitqueue_head(&ffs->ev.waitq); 144900a2430fSAndrzej Pietrasiewicz init_completion(&ffs->ep0req_completion); 145000a2430fSAndrzej Pietrasiewicz 145100a2430fSAndrzej Pietrasiewicz /* XXX REVISIT need to update it in some places, or do we? */ 145200a2430fSAndrzej Pietrasiewicz ffs->ev.can_stall = 1; 145300a2430fSAndrzej Pietrasiewicz 145400a2430fSAndrzej Pietrasiewicz return ffs; 145500a2430fSAndrzej Pietrasiewicz } 145600a2430fSAndrzej Pietrasiewicz 145700a2430fSAndrzej Pietrasiewicz static void ffs_data_clear(struct ffs_data *ffs) 145800a2430fSAndrzej Pietrasiewicz { 145900a2430fSAndrzej Pietrasiewicz ENTER(); 146000a2430fSAndrzej Pietrasiewicz 146100a2430fSAndrzej Pietrasiewicz ffs_closed(ffs); 146200a2430fSAndrzej Pietrasiewicz 146300a2430fSAndrzej Pietrasiewicz BUG_ON(ffs->gadget); 146400a2430fSAndrzej Pietrasiewicz 146500a2430fSAndrzej Pietrasiewicz if (ffs->epfiles) 146600a2430fSAndrzej Pietrasiewicz ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); 146700a2430fSAndrzej Pietrasiewicz 14685e33f6fdSRobert Baldyga if (ffs->ffs_eventfd) 14695e33f6fdSRobert Baldyga eventfd_ctx_put(ffs->ffs_eventfd); 14705e33f6fdSRobert Baldyga 147100a2430fSAndrzej Pietrasiewicz kfree(ffs->raw_descs_data); 147200a2430fSAndrzej Pietrasiewicz kfree(ffs->raw_strings); 147300a2430fSAndrzej Pietrasiewicz kfree(ffs->stringtabs); 147400a2430fSAndrzej Pietrasiewicz } 147500a2430fSAndrzej Pietrasiewicz 147600a2430fSAndrzej Pietrasiewicz static void ffs_data_reset(struct ffs_data *ffs) 147700a2430fSAndrzej Pietrasiewicz { 147800a2430fSAndrzej Pietrasiewicz ENTER(); 147900a2430fSAndrzej Pietrasiewicz 148000a2430fSAndrzej Pietrasiewicz ffs_data_clear(ffs); 148100a2430fSAndrzej Pietrasiewicz 148200a2430fSAndrzej Pietrasiewicz ffs->epfiles = NULL; 148300a2430fSAndrzej Pietrasiewicz ffs->raw_descs_data = NULL; 148400a2430fSAndrzej Pietrasiewicz ffs->raw_descs = NULL; 148500a2430fSAndrzej Pietrasiewicz ffs->raw_strings = NULL; 148600a2430fSAndrzej Pietrasiewicz ffs->stringtabs = NULL; 148700a2430fSAndrzej Pietrasiewicz 148800a2430fSAndrzej Pietrasiewicz ffs->raw_descs_length = 0; 148900a2430fSAndrzej Pietrasiewicz ffs->fs_descs_count = 0; 149000a2430fSAndrzej Pietrasiewicz ffs->hs_descs_count = 0; 149100a2430fSAndrzej Pietrasiewicz ffs->ss_descs_count = 0; 149200a2430fSAndrzej Pietrasiewicz 149300a2430fSAndrzej Pietrasiewicz ffs->strings_count = 0; 149400a2430fSAndrzej Pietrasiewicz ffs->interfaces_count = 0; 149500a2430fSAndrzej Pietrasiewicz ffs->eps_count = 0; 149600a2430fSAndrzej Pietrasiewicz 149700a2430fSAndrzej Pietrasiewicz ffs->ev.count = 0; 149800a2430fSAndrzej Pietrasiewicz 149900a2430fSAndrzej Pietrasiewicz ffs->state = FFS_READ_DESCRIPTORS; 150000a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_NO_SETUP; 150100a2430fSAndrzej Pietrasiewicz ffs->flags = 0; 150200a2430fSAndrzej Pietrasiewicz } 150300a2430fSAndrzej Pietrasiewicz 150400a2430fSAndrzej Pietrasiewicz 150500a2430fSAndrzej Pietrasiewicz static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) 150600a2430fSAndrzej Pietrasiewicz { 150700a2430fSAndrzej Pietrasiewicz struct usb_gadget_strings **lang; 150800a2430fSAndrzej Pietrasiewicz int first_id; 150900a2430fSAndrzej Pietrasiewicz 151000a2430fSAndrzej Pietrasiewicz ENTER(); 151100a2430fSAndrzej Pietrasiewicz 151200a2430fSAndrzej Pietrasiewicz if (WARN_ON(ffs->state != FFS_ACTIVE 151300a2430fSAndrzej Pietrasiewicz || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) 151400a2430fSAndrzej Pietrasiewicz return -EBADFD; 151500a2430fSAndrzej Pietrasiewicz 151600a2430fSAndrzej Pietrasiewicz first_id = usb_string_ids_n(cdev, ffs->strings_count); 151700a2430fSAndrzej Pietrasiewicz if (unlikely(first_id < 0)) 151800a2430fSAndrzej Pietrasiewicz return first_id; 151900a2430fSAndrzej Pietrasiewicz 152000a2430fSAndrzej Pietrasiewicz ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); 152100a2430fSAndrzej Pietrasiewicz if (unlikely(!ffs->ep0req)) 152200a2430fSAndrzej Pietrasiewicz return -ENOMEM; 152300a2430fSAndrzej Pietrasiewicz ffs->ep0req->complete = ffs_ep0_complete; 152400a2430fSAndrzej Pietrasiewicz ffs->ep0req->context = ffs; 152500a2430fSAndrzej Pietrasiewicz 152600a2430fSAndrzej Pietrasiewicz lang = ffs->stringtabs; 152761fe2d75SGreg Kroah-Hartman if (lang) { 152861fe2d75SGreg Kroah-Hartman for (; *lang; ++lang) { 152900a2430fSAndrzej Pietrasiewicz struct usb_string *str = (*lang)->strings; 153000a2430fSAndrzej Pietrasiewicz int id = first_id; 153100a2430fSAndrzej Pietrasiewicz for (; str->s; ++id, ++str) 153200a2430fSAndrzej Pietrasiewicz str->id = id; 153300a2430fSAndrzej Pietrasiewicz } 153461fe2d75SGreg Kroah-Hartman } 153500a2430fSAndrzej Pietrasiewicz 153600a2430fSAndrzej Pietrasiewicz ffs->gadget = cdev->gadget; 153700a2430fSAndrzej Pietrasiewicz ffs_data_get(ffs); 153800a2430fSAndrzej Pietrasiewicz return 0; 153900a2430fSAndrzej Pietrasiewicz } 154000a2430fSAndrzej Pietrasiewicz 154100a2430fSAndrzej Pietrasiewicz static void functionfs_unbind(struct ffs_data *ffs) 154200a2430fSAndrzej Pietrasiewicz { 154300a2430fSAndrzej Pietrasiewicz ENTER(); 154400a2430fSAndrzej Pietrasiewicz 154500a2430fSAndrzej Pietrasiewicz if (!WARN_ON(!ffs->gadget)) { 154600a2430fSAndrzej Pietrasiewicz usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req); 154700a2430fSAndrzej Pietrasiewicz ffs->ep0req = NULL; 154800a2430fSAndrzej Pietrasiewicz ffs->gadget = NULL; 154900a2430fSAndrzej Pietrasiewicz clear_bit(FFS_FL_BOUND, &ffs->flags); 155000a2430fSAndrzej Pietrasiewicz ffs_data_put(ffs); 155100a2430fSAndrzej Pietrasiewicz } 155200a2430fSAndrzej Pietrasiewicz } 155300a2430fSAndrzej Pietrasiewicz 155400a2430fSAndrzej Pietrasiewicz static int ffs_epfiles_create(struct ffs_data *ffs) 155500a2430fSAndrzej Pietrasiewicz { 155600a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile, *epfiles; 155700a2430fSAndrzej Pietrasiewicz unsigned i, count; 155800a2430fSAndrzej Pietrasiewicz 155900a2430fSAndrzej Pietrasiewicz ENTER(); 156000a2430fSAndrzej Pietrasiewicz 156100a2430fSAndrzej Pietrasiewicz count = ffs->eps_count; 156200a2430fSAndrzej Pietrasiewicz epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); 156300a2430fSAndrzej Pietrasiewicz if (!epfiles) 156400a2430fSAndrzej Pietrasiewicz return -ENOMEM; 156500a2430fSAndrzej Pietrasiewicz 156600a2430fSAndrzej Pietrasiewicz epfile = epfiles; 156700a2430fSAndrzej Pietrasiewicz for (i = 1; i <= count; ++i, ++epfile) { 156800a2430fSAndrzej Pietrasiewicz epfile->ffs = ffs; 156900a2430fSAndrzej Pietrasiewicz mutex_init(&epfile->mutex); 157000a2430fSAndrzej Pietrasiewicz init_waitqueue_head(&epfile->wait); 15711b0bf88fSRobert Baldyga if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) 1572acba23feSMario Schuknecht sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]); 15731b0bf88fSRobert Baldyga else 1574acba23feSMario Schuknecht sprintf(epfile->name, "ep%u", i); 1575acba23feSMario Schuknecht epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name, 15761bb27cacSAl Viro epfile, 15771bb27cacSAl Viro &ffs_epfile_operations); 15781bb27cacSAl Viro if (unlikely(!epfile->dentry)) { 157900a2430fSAndrzej Pietrasiewicz ffs_epfiles_destroy(epfiles, i - 1); 158000a2430fSAndrzej Pietrasiewicz return -ENOMEM; 158100a2430fSAndrzej Pietrasiewicz } 158200a2430fSAndrzej Pietrasiewicz } 158300a2430fSAndrzej Pietrasiewicz 158400a2430fSAndrzej Pietrasiewicz ffs->epfiles = epfiles; 158500a2430fSAndrzej Pietrasiewicz return 0; 158600a2430fSAndrzej Pietrasiewicz } 158700a2430fSAndrzej Pietrasiewicz 158800a2430fSAndrzej Pietrasiewicz static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) 158900a2430fSAndrzej Pietrasiewicz { 159000a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = epfiles; 159100a2430fSAndrzej Pietrasiewicz 159200a2430fSAndrzej Pietrasiewicz ENTER(); 159300a2430fSAndrzej Pietrasiewicz 159400a2430fSAndrzej Pietrasiewicz for (; count; --count, ++epfile) { 159500a2430fSAndrzej Pietrasiewicz BUG_ON(mutex_is_locked(&epfile->mutex) || 159600a2430fSAndrzej Pietrasiewicz waitqueue_active(&epfile->wait)); 159700a2430fSAndrzej Pietrasiewicz if (epfile->dentry) { 159800a2430fSAndrzej Pietrasiewicz d_delete(epfile->dentry); 159900a2430fSAndrzej Pietrasiewicz dput(epfile->dentry); 160000a2430fSAndrzej Pietrasiewicz epfile->dentry = NULL; 160100a2430fSAndrzej Pietrasiewicz } 160200a2430fSAndrzej Pietrasiewicz } 160300a2430fSAndrzej Pietrasiewicz 160400a2430fSAndrzej Pietrasiewicz kfree(epfiles); 160500a2430fSAndrzej Pietrasiewicz } 160600a2430fSAndrzej Pietrasiewicz 160700a2430fSAndrzej Pietrasiewicz static void ffs_func_eps_disable(struct ffs_function *func) 160800a2430fSAndrzej Pietrasiewicz { 160900a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep = func->eps; 161000a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = func->ffs->epfiles; 161100a2430fSAndrzej Pietrasiewicz unsigned count = func->ffs->eps_count; 161200a2430fSAndrzej Pietrasiewicz unsigned long flags; 161300a2430fSAndrzej Pietrasiewicz 161400a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&func->ffs->eps_lock, flags); 161500a2430fSAndrzej Pietrasiewicz do { 161600a2430fSAndrzej Pietrasiewicz /* pending requests get nuked */ 161700a2430fSAndrzej Pietrasiewicz if (likely(ep->ep)) 161800a2430fSAndrzej Pietrasiewicz usb_ep_disable(ep->ep); 161900a2430fSAndrzej Pietrasiewicz ++ep; 162018d6b32fSRobert Baldyga 162118d6b32fSRobert Baldyga if (epfile) { 162218d6b32fSRobert Baldyga epfile->ep = NULL; 162300a2430fSAndrzej Pietrasiewicz ++epfile; 162418d6b32fSRobert Baldyga } 162500a2430fSAndrzej Pietrasiewicz } while (--count); 162600a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&func->ffs->eps_lock, flags); 162700a2430fSAndrzej Pietrasiewicz } 162800a2430fSAndrzej Pietrasiewicz 162900a2430fSAndrzej Pietrasiewicz static int ffs_func_eps_enable(struct ffs_function *func) 163000a2430fSAndrzej Pietrasiewicz { 163100a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 163200a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep = func->eps; 163300a2430fSAndrzej Pietrasiewicz struct ffs_epfile *epfile = ffs->epfiles; 163400a2430fSAndrzej Pietrasiewicz unsigned count = ffs->eps_count; 163500a2430fSAndrzej Pietrasiewicz unsigned long flags; 163600a2430fSAndrzej Pietrasiewicz int ret = 0; 163700a2430fSAndrzej Pietrasiewicz 163800a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&func->ffs->eps_lock, flags); 163900a2430fSAndrzej Pietrasiewicz do { 164000a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *ds; 164100a2430fSAndrzej Pietrasiewicz int desc_idx; 164200a2430fSAndrzej Pietrasiewicz 164300a2430fSAndrzej Pietrasiewicz if (ffs->gadget->speed == USB_SPEED_SUPER) 164400a2430fSAndrzej Pietrasiewicz desc_idx = 2; 164500a2430fSAndrzej Pietrasiewicz else if (ffs->gadget->speed == USB_SPEED_HIGH) 164600a2430fSAndrzej Pietrasiewicz desc_idx = 1; 164700a2430fSAndrzej Pietrasiewicz else 164800a2430fSAndrzej Pietrasiewicz desc_idx = 0; 164900a2430fSAndrzej Pietrasiewicz 165000a2430fSAndrzej Pietrasiewicz /* fall-back to lower speed if desc missing for current speed */ 165100a2430fSAndrzej Pietrasiewicz do { 165200a2430fSAndrzej Pietrasiewicz ds = ep->descs[desc_idx]; 165300a2430fSAndrzej Pietrasiewicz } while (!ds && --desc_idx >= 0); 165400a2430fSAndrzej Pietrasiewicz 165500a2430fSAndrzej Pietrasiewicz if (!ds) { 165600a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 165700a2430fSAndrzej Pietrasiewicz break; 165800a2430fSAndrzej Pietrasiewicz } 165900a2430fSAndrzej Pietrasiewicz 166000a2430fSAndrzej Pietrasiewicz ep->ep->driver_data = ep; 166100a2430fSAndrzej Pietrasiewicz ep->ep->desc = ds; 166200a2430fSAndrzej Pietrasiewicz ret = usb_ep_enable(ep->ep); 166300a2430fSAndrzej Pietrasiewicz if (likely(!ret)) { 166400a2430fSAndrzej Pietrasiewicz epfile->ep = ep; 166500a2430fSAndrzej Pietrasiewicz epfile->in = usb_endpoint_dir_in(ds); 166600a2430fSAndrzej Pietrasiewicz epfile->isoc = usb_endpoint_xfer_isoc(ds); 166700a2430fSAndrzej Pietrasiewicz } else { 166800a2430fSAndrzej Pietrasiewicz break; 166900a2430fSAndrzej Pietrasiewicz } 167000a2430fSAndrzej Pietrasiewicz 167100a2430fSAndrzej Pietrasiewicz wake_up(&epfile->wait); 167200a2430fSAndrzej Pietrasiewicz 167300a2430fSAndrzej Pietrasiewicz ++ep; 167400a2430fSAndrzej Pietrasiewicz ++epfile; 167500a2430fSAndrzej Pietrasiewicz } while (--count); 167600a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&func->ffs->eps_lock, flags); 167700a2430fSAndrzej Pietrasiewicz 167800a2430fSAndrzej Pietrasiewicz return ret; 167900a2430fSAndrzej Pietrasiewicz } 168000a2430fSAndrzej Pietrasiewicz 168100a2430fSAndrzej Pietrasiewicz 168200a2430fSAndrzej Pietrasiewicz /* Parsing and building descriptors and strings *****************************/ 168300a2430fSAndrzej Pietrasiewicz 168400a2430fSAndrzej Pietrasiewicz /* 168500a2430fSAndrzej Pietrasiewicz * This validates if data pointed by data is a valid USB descriptor as 168600a2430fSAndrzej Pietrasiewicz * well as record how many interfaces, endpoints and strings are 168700a2430fSAndrzej Pietrasiewicz * required by given configuration. Returns address after the 168800a2430fSAndrzej Pietrasiewicz * descriptor or NULL if data is invalid. 168900a2430fSAndrzej Pietrasiewicz */ 169000a2430fSAndrzej Pietrasiewicz 169100a2430fSAndrzej Pietrasiewicz enum ffs_entity_type { 169200a2430fSAndrzej Pietrasiewicz FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT 169300a2430fSAndrzej Pietrasiewicz }; 169400a2430fSAndrzej Pietrasiewicz 169500a2430fSAndrzej Pietrasiewicz enum ffs_os_desc_type { 169600a2430fSAndrzej Pietrasiewicz FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP 169700a2430fSAndrzej Pietrasiewicz }; 169800a2430fSAndrzej Pietrasiewicz 169900a2430fSAndrzej Pietrasiewicz typedef int (*ffs_entity_callback)(enum ffs_entity_type entity, 170000a2430fSAndrzej Pietrasiewicz u8 *valuep, 170100a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *desc, 170200a2430fSAndrzej Pietrasiewicz void *priv); 170300a2430fSAndrzej Pietrasiewicz 170400a2430fSAndrzej Pietrasiewicz typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity, 170500a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *h, void *data, 170600a2430fSAndrzej Pietrasiewicz unsigned len, void *priv); 170700a2430fSAndrzej Pietrasiewicz 170800a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_single_desc(char *data, unsigned len, 170900a2430fSAndrzej Pietrasiewicz ffs_entity_callback entity, 171000a2430fSAndrzej Pietrasiewicz void *priv) 171100a2430fSAndrzej Pietrasiewicz { 171200a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *_ds = (void *)data; 171300a2430fSAndrzej Pietrasiewicz u8 length; 171400a2430fSAndrzej Pietrasiewicz int ret; 171500a2430fSAndrzej Pietrasiewicz 171600a2430fSAndrzej Pietrasiewicz ENTER(); 171700a2430fSAndrzej Pietrasiewicz 171800a2430fSAndrzej Pietrasiewicz /* At least two bytes are required: length and type */ 171900a2430fSAndrzej Pietrasiewicz if (len < 2) { 172000a2430fSAndrzej Pietrasiewicz pr_vdebug("descriptor too short\n"); 172100a2430fSAndrzej Pietrasiewicz return -EINVAL; 172200a2430fSAndrzej Pietrasiewicz } 172300a2430fSAndrzej Pietrasiewicz 172400a2430fSAndrzej Pietrasiewicz /* If we have at least as many bytes as the descriptor takes? */ 172500a2430fSAndrzej Pietrasiewicz length = _ds->bLength; 172600a2430fSAndrzej Pietrasiewicz if (len < length) { 172700a2430fSAndrzej Pietrasiewicz pr_vdebug("descriptor longer then available data\n"); 172800a2430fSAndrzej Pietrasiewicz return -EINVAL; 172900a2430fSAndrzej Pietrasiewicz } 173000a2430fSAndrzej Pietrasiewicz 173100a2430fSAndrzej Pietrasiewicz #define __entity_check_INTERFACE(val) 1 173200a2430fSAndrzej Pietrasiewicz #define __entity_check_STRING(val) (val) 173300a2430fSAndrzej Pietrasiewicz #define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK) 173400a2430fSAndrzej Pietrasiewicz #define __entity(type, val) do { \ 173500a2430fSAndrzej Pietrasiewicz pr_vdebug("entity " #type "(%02x)\n", (val)); \ 173600a2430fSAndrzej Pietrasiewicz if (unlikely(!__entity_check_ ##type(val))) { \ 173700a2430fSAndrzej Pietrasiewicz pr_vdebug("invalid entity's value\n"); \ 173800a2430fSAndrzej Pietrasiewicz return -EINVAL; \ 173900a2430fSAndrzej Pietrasiewicz } \ 174000a2430fSAndrzej Pietrasiewicz ret = entity(FFS_ ##type, &val, _ds, priv); \ 174100a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { \ 174200a2430fSAndrzej Pietrasiewicz pr_debug("entity " #type "(%02x); ret = %d\n", \ 174300a2430fSAndrzej Pietrasiewicz (val), ret); \ 174400a2430fSAndrzej Pietrasiewicz return ret; \ 174500a2430fSAndrzej Pietrasiewicz } \ 174600a2430fSAndrzej Pietrasiewicz } while (0) 174700a2430fSAndrzej Pietrasiewicz 174800a2430fSAndrzej Pietrasiewicz /* Parse descriptor depending on type. */ 174900a2430fSAndrzej Pietrasiewicz switch (_ds->bDescriptorType) { 175000a2430fSAndrzej Pietrasiewicz case USB_DT_DEVICE: 175100a2430fSAndrzej Pietrasiewicz case USB_DT_CONFIG: 175200a2430fSAndrzej Pietrasiewicz case USB_DT_STRING: 175300a2430fSAndrzej Pietrasiewicz case USB_DT_DEVICE_QUALIFIER: 175400a2430fSAndrzej Pietrasiewicz /* function can't have any of those */ 175500a2430fSAndrzej Pietrasiewicz pr_vdebug("descriptor reserved for gadget: %d\n", 175600a2430fSAndrzej Pietrasiewicz _ds->bDescriptorType); 175700a2430fSAndrzej Pietrasiewicz return -EINVAL; 175800a2430fSAndrzej Pietrasiewicz 175900a2430fSAndrzej Pietrasiewicz case USB_DT_INTERFACE: { 176000a2430fSAndrzej Pietrasiewicz struct usb_interface_descriptor *ds = (void *)_ds; 176100a2430fSAndrzej Pietrasiewicz pr_vdebug("interface descriptor\n"); 176200a2430fSAndrzej Pietrasiewicz if (length != sizeof *ds) 176300a2430fSAndrzej Pietrasiewicz goto inv_length; 176400a2430fSAndrzej Pietrasiewicz 176500a2430fSAndrzej Pietrasiewicz __entity(INTERFACE, ds->bInterfaceNumber); 176600a2430fSAndrzej Pietrasiewicz if (ds->iInterface) 176700a2430fSAndrzej Pietrasiewicz __entity(STRING, ds->iInterface); 176800a2430fSAndrzej Pietrasiewicz } 176900a2430fSAndrzej Pietrasiewicz break; 177000a2430fSAndrzej Pietrasiewicz 177100a2430fSAndrzej Pietrasiewicz case USB_DT_ENDPOINT: { 177200a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *ds = (void *)_ds; 177300a2430fSAndrzej Pietrasiewicz pr_vdebug("endpoint descriptor\n"); 177400a2430fSAndrzej Pietrasiewicz if (length != USB_DT_ENDPOINT_SIZE && 177500a2430fSAndrzej Pietrasiewicz length != USB_DT_ENDPOINT_AUDIO_SIZE) 177600a2430fSAndrzej Pietrasiewicz goto inv_length; 177700a2430fSAndrzej Pietrasiewicz __entity(ENDPOINT, ds->bEndpointAddress); 177800a2430fSAndrzej Pietrasiewicz } 177900a2430fSAndrzej Pietrasiewicz break; 178000a2430fSAndrzej Pietrasiewicz 178100a2430fSAndrzej Pietrasiewicz case HID_DT_HID: 178200a2430fSAndrzej Pietrasiewicz pr_vdebug("hid descriptor\n"); 178300a2430fSAndrzej Pietrasiewicz if (length != sizeof(struct hid_descriptor)) 178400a2430fSAndrzej Pietrasiewicz goto inv_length; 178500a2430fSAndrzej Pietrasiewicz break; 178600a2430fSAndrzej Pietrasiewicz 178700a2430fSAndrzej Pietrasiewicz case USB_DT_OTG: 178800a2430fSAndrzej Pietrasiewicz if (length != sizeof(struct usb_otg_descriptor)) 178900a2430fSAndrzej Pietrasiewicz goto inv_length; 179000a2430fSAndrzej Pietrasiewicz break; 179100a2430fSAndrzej Pietrasiewicz 179200a2430fSAndrzej Pietrasiewicz case USB_DT_INTERFACE_ASSOCIATION: { 179300a2430fSAndrzej Pietrasiewicz struct usb_interface_assoc_descriptor *ds = (void *)_ds; 179400a2430fSAndrzej Pietrasiewicz pr_vdebug("interface association descriptor\n"); 179500a2430fSAndrzej Pietrasiewicz if (length != sizeof *ds) 179600a2430fSAndrzej Pietrasiewicz goto inv_length; 179700a2430fSAndrzej Pietrasiewicz if (ds->iFunction) 179800a2430fSAndrzej Pietrasiewicz __entity(STRING, ds->iFunction); 179900a2430fSAndrzej Pietrasiewicz } 180000a2430fSAndrzej Pietrasiewicz break; 180100a2430fSAndrzej Pietrasiewicz 180200a2430fSAndrzej Pietrasiewicz case USB_DT_SS_ENDPOINT_COMP: 180300a2430fSAndrzej Pietrasiewicz pr_vdebug("EP SS companion descriptor\n"); 180400a2430fSAndrzej Pietrasiewicz if (length != sizeof(struct usb_ss_ep_comp_descriptor)) 180500a2430fSAndrzej Pietrasiewicz goto inv_length; 180600a2430fSAndrzej Pietrasiewicz break; 180700a2430fSAndrzej Pietrasiewicz 180800a2430fSAndrzej Pietrasiewicz case USB_DT_OTHER_SPEED_CONFIG: 180900a2430fSAndrzej Pietrasiewicz case USB_DT_INTERFACE_POWER: 181000a2430fSAndrzej Pietrasiewicz case USB_DT_DEBUG: 181100a2430fSAndrzej Pietrasiewicz case USB_DT_SECURITY: 181200a2430fSAndrzej Pietrasiewicz case USB_DT_CS_RADIO_CONTROL: 181300a2430fSAndrzej Pietrasiewicz /* TODO */ 181400a2430fSAndrzej Pietrasiewicz pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType); 181500a2430fSAndrzej Pietrasiewicz return -EINVAL; 181600a2430fSAndrzej Pietrasiewicz 181700a2430fSAndrzej Pietrasiewicz default: 181800a2430fSAndrzej Pietrasiewicz /* We should never be here */ 181900a2430fSAndrzej Pietrasiewicz pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType); 182000a2430fSAndrzej Pietrasiewicz return -EINVAL; 182100a2430fSAndrzej Pietrasiewicz 182200a2430fSAndrzej Pietrasiewicz inv_length: 182300a2430fSAndrzej Pietrasiewicz pr_vdebug("invalid length: %d (descriptor %d)\n", 182400a2430fSAndrzej Pietrasiewicz _ds->bLength, _ds->bDescriptorType); 182500a2430fSAndrzej Pietrasiewicz return -EINVAL; 182600a2430fSAndrzej Pietrasiewicz } 182700a2430fSAndrzej Pietrasiewicz 182800a2430fSAndrzej Pietrasiewicz #undef __entity 182900a2430fSAndrzej Pietrasiewicz #undef __entity_check_DESCRIPTOR 183000a2430fSAndrzej Pietrasiewicz #undef __entity_check_INTERFACE 183100a2430fSAndrzej Pietrasiewicz #undef __entity_check_STRING 183200a2430fSAndrzej Pietrasiewicz #undef __entity_check_ENDPOINT 183300a2430fSAndrzej Pietrasiewicz 183400a2430fSAndrzej Pietrasiewicz return length; 183500a2430fSAndrzej Pietrasiewicz } 183600a2430fSAndrzej Pietrasiewicz 183700a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, 183800a2430fSAndrzej Pietrasiewicz ffs_entity_callback entity, void *priv) 183900a2430fSAndrzej Pietrasiewicz { 184000a2430fSAndrzej Pietrasiewicz const unsigned _len = len; 184100a2430fSAndrzej Pietrasiewicz unsigned long num = 0; 184200a2430fSAndrzej Pietrasiewicz 184300a2430fSAndrzej Pietrasiewicz ENTER(); 184400a2430fSAndrzej Pietrasiewicz 184500a2430fSAndrzej Pietrasiewicz for (;;) { 184600a2430fSAndrzej Pietrasiewicz int ret; 184700a2430fSAndrzej Pietrasiewicz 184800a2430fSAndrzej Pietrasiewicz if (num == count) 184900a2430fSAndrzej Pietrasiewicz data = NULL; 185000a2430fSAndrzej Pietrasiewicz 185100a2430fSAndrzej Pietrasiewicz /* Record "descriptor" entity */ 185200a2430fSAndrzej Pietrasiewicz ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv); 185300a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 185400a2430fSAndrzej Pietrasiewicz pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n", 185500a2430fSAndrzej Pietrasiewicz num, ret); 185600a2430fSAndrzej Pietrasiewicz return ret; 185700a2430fSAndrzej Pietrasiewicz } 185800a2430fSAndrzej Pietrasiewicz 185900a2430fSAndrzej Pietrasiewicz if (!data) 186000a2430fSAndrzej Pietrasiewicz return _len - len; 186100a2430fSAndrzej Pietrasiewicz 186200a2430fSAndrzej Pietrasiewicz ret = ffs_do_single_desc(data, len, entity, priv); 186300a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 186400a2430fSAndrzej Pietrasiewicz pr_debug("%s returns %d\n", __func__, ret); 186500a2430fSAndrzej Pietrasiewicz return ret; 186600a2430fSAndrzej Pietrasiewicz } 186700a2430fSAndrzej Pietrasiewicz 186800a2430fSAndrzej Pietrasiewicz len -= ret; 186900a2430fSAndrzej Pietrasiewicz data += ret; 187000a2430fSAndrzej Pietrasiewicz ++num; 187100a2430fSAndrzej Pietrasiewicz } 187200a2430fSAndrzej Pietrasiewicz } 187300a2430fSAndrzej Pietrasiewicz 187400a2430fSAndrzej Pietrasiewicz static int __ffs_data_do_entity(enum ffs_entity_type type, 187500a2430fSAndrzej Pietrasiewicz u8 *valuep, struct usb_descriptor_header *desc, 187600a2430fSAndrzej Pietrasiewicz void *priv) 187700a2430fSAndrzej Pietrasiewicz { 18786d5c1c77SRobert Baldyga struct ffs_desc_helper *helper = priv; 18796d5c1c77SRobert Baldyga struct usb_endpoint_descriptor *d; 188000a2430fSAndrzej Pietrasiewicz 188100a2430fSAndrzej Pietrasiewicz ENTER(); 188200a2430fSAndrzej Pietrasiewicz 188300a2430fSAndrzej Pietrasiewicz switch (type) { 188400a2430fSAndrzej Pietrasiewicz case FFS_DESCRIPTOR: 188500a2430fSAndrzej Pietrasiewicz break; 188600a2430fSAndrzej Pietrasiewicz 188700a2430fSAndrzej Pietrasiewicz case FFS_INTERFACE: 188800a2430fSAndrzej Pietrasiewicz /* 188900a2430fSAndrzej Pietrasiewicz * Interfaces are indexed from zero so if we 189000a2430fSAndrzej Pietrasiewicz * encountered interface "n" then there are at least 189100a2430fSAndrzej Pietrasiewicz * "n+1" interfaces. 189200a2430fSAndrzej Pietrasiewicz */ 18936d5c1c77SRobert Baldyga if (*valuep >= helper->interfaces_count) 18946d5c1c77SRobert Baldyga helper->interfaces_count = *valuep + 1; 189500a2430fSAndrzej Pietrasiewicz break; 189600a2430fSAndrzej Pietrasiewicz 189700a2430fSAndrzej Pietrasiewicz case FFS_STRING: 189800a2430fSAndrzej Pietrasiewicz /* 189900a2430fSAndrzej Pietrasiewicz * Strings are indexed from 1 (0 is magic ;) reserved 190000a2430fSAndrzej Pietrasiewicz * for languages list or some such) 190100a2430fSAndrzej Pietrasiewicz */ 19026d5c1c77SRobert Baldyga if (*valuep > helper->ffs->strings_count) 19036d5c1c77SRobert Baldyga helper->ffs->strings_count = *valuep; 190400a2430fSAndrzej Pietrasiewicz break; 190500a2430fSAndrzej Pietrasiewicz 190600a2430fSAndrzej Pietrasiewicz case FFS_ENDPOINT: 19076d5c1c77SRobert Baldyga d = (void *)desc; 19086d5c1c77SRobert Baldyga helper->eps_count++; 19096d5c1c77SRobert Baldyga if (helper->eps_count >= 15) 19106d5c1c77SRobert Baldyga return -EINVAL; 19116d5c1c77SRobert Baldyga /* Check if descriptors for any speed were already parsed */ 19126d5c1c77SRobert Baldyga if (!helper->ffs->eps_count && !helper->ffs->interfaces_count) 19136d5c1c77SRobert Baldyga helper->ffs->eps_addrmap[helper->eps_count] = 19146d5c1c77SRobert Baldyga d->bEndpointAddress; 19156d5c1c77SRobert Baldyga else if (helper->ffs->eps_addrmap[helper->eps_count] != 19166d5c1c77SRobert Baldyga d->bEndpointAddress) 19176d5c1c77SRobert Baldyga return -EINVAL; 191800a2430fSAndrzej Pietrasiewicz break; 191900a2430fSAndrzej Pietrasiewicz } 192000a2430fSAndrzej Pietrasiewicz 192100a2430fSAndrzej Pietrasiewicz return 0; 192200a2430fSAndrzej Pietrasiewicz } 192300a2430fSAndrzej Pietrasiewicz 192400a2430fSAndrzej Pietrasiewicz static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, 192500a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *desc) 192600a2430fSAndrzej Pietrasiewicz { 192700a2430fSAndrzej Pietrasiewicz u16 bcd_version = le16_to_cpu(desc->bcdVersion); 192800a2430fSAndrzej Pietrasiewicz u16 w_index = le16_to_cpu(desc->wIndex); 192900a2430fSAndrzej Pietrasiewicz 193000a2430fSAndrzej Pietrasiewicz if (bcd_version != 1) { 193100a2430fSAndrzej Pietrasiewicz pr_vdebug("unsupported os descriptors version: %d", 193200a2430fSAndrzej Pietrasiewicz bcd_version); 193300a2430fSAndrzej Pietrasiewicz return -EINVAL; 193400a2430fSAndrzej Pietrasiewicz } 193500a2430fSAndrzej Pietrasiewicz switch (w_index) { 193600a2430fSAndrzej Pietrasiewicz case 0x4: 193700a2430fSAndrzej Pietrasiewicz *next_type = FFS_OS_DESC_EXT_COMPAT; 193800a2430fSAndrzej Pietrasiewicz break; 193900a2430fSAndrzej Pietrasiewicz case 0x5: 194000a2430fSAndrzej Pietrasiewicz *next_type = FFS_OS_DESC_EXT_PROP; 194100a2430fSAndrzej Pietrasiewicz break; 194200a2430fSAndrzej Pietrasiewicz default: 194300a2430fSAndrzej Pietrasiewicz pr_vdebug("unsupported os descriptor type: %d", w_index); 194400a2430fSAndrzej Pietrasiewicz return -EINVAL; 194500a2430fSAndrzej Pietrasiewicz } 194600a2430fSAndrzej Pietrasiewicz 194700a2430fSAndrzej Pietrasiewicz return sizeof(*desc); 194800a2430fSAndrzej Pietrasiewicz } 194900a2430fSAndrzej Pietrasiewicz 195000a2430fSAndrzej Pietrasiewicz /* 195100a2430fSAndrzej Pietrasiewicz * Process all extended compatibility/extended property descriptors 195200a2430fSAndrzej Pietrasiewicz * of a feature descriptor 195300a2430fSAndrzej Pietrasiewicz */ 195400a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_single_os_desc(char *data, unsigned len, 195500a2430fSAndrzej Pietrasiewicz enum ffs_os_desc_type type, 195600a2430fSAndrzej Pietrasiewicz u16 feature_count, 195700a2430fSAndrzej Pietrasiewicz ffs_os_desc_callback entity, 195800a2430fSAndrzej Pietrasiewicz void *priv, 195900a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *h) 196000a2430fSAndrzej Pietrasiewicz { 196100a2430fSAndrzej Pietrasiewicz int ret; 196200a2430fSAndrzej Pietrasiewicz const unsigned _len = len; 196300a2430fSAndrzej Pietrasiewicz 196400a2430fSAndrzej Pietrasiewicz ENTER(); 196500a2430fSAndrzej Pietrasiewicz 196600a2430fSAndrzej Pietrasiewicz /* loop over all ext compat/ext prop descriptors */ 196700a2430fSAndrzej Pietrasiewicz while (feature_count--) { 196800a2430fSAndrzej Pietrasiewicz ret = entity(type, h, data, len, priv); 196900a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 197000a2430fSAndrzej Pietrasiewicz pr_debug("bad OS descriptor, type: %d\n", type); 197100a2430fSAndrzej Pietrasiewicz return ret; 197200a2430fSAndrzej Pietrasiewicz } 197300a2430fSAndrzej Pietrasiewicz data += ret; 197400a2430fSAndrzej Pietrasiewicz len -= ret; 197500a2430fSAndrzej Pietrasiewicz } 197600a2430fSAndrzej Pietrasiewicz return _len - len; 197700a2430fSAndrzej Pietrasiewicz } 197800a2430fSAndrzej Pietrasiewicz 197900a2430fSAndrzej Pietrasiewicz /* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */ 198000a2430fSAndrzej Pietrasiewicz static int __must_check ffs_do_os_descs(unsigned count, 198100a2430fSAndrzej Pietrasiewicz char *data, unsigned len, 198200a2430fSAndrzej Pietrasiewicz ffs_os_desc_callback entity, void *priv) 198300a2430fSAndrzej Pietrasiewicz { 198400a2430fSAndrzej Pietrasiewicz const unsigned _len = len; 198500a2430fSAndrzej Pietrasiewicz unsigned long num = 0; 198600a2430fSAndrzej Pietrasiewicz 198700a2430fSAndrzej Pietrasiewicz ENTER(); 198800a2430fSAndrzej Pietrasiewicz 198900a2430fSAndrzej Pietrasiewicz for (num = 0; num < count; ++num) { 199000a2430fSAndrzej Pietrasiewicz int ret; 199100a2430fSAndrzej Pietrasiewicz enum ffs_os_desc_type type; 199200a2430fSAndrzej Pietrasiewicz u16 feature_count; 199300a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *desc = (void *)data; 199400a2430fSAndrzej Pietrasiewicz 199500a2430fSAndrzej Pietrasiewicz if (len < sizeof(*desc)) 199600a2430fSAndrzej Pietrasiewicz return -EINVAL; 199700a2430fSAndrzej Pietrasiewicz 199800a2430fSAndrzej Pietrasiewicz /* 199900a2430fSAndrzej Pietrasiewicz * Record "descriptor" entity. 200000a2430fSAndrzej Pietrasiewicz * Process dwLength, bcdVersion, wIndex, get b/wCount. 200100a2430fSAndrzej Pietrasiewicz * Move the data pointer to the beginning of extended 200200a2430fSAndrzej Pietrasiewicz * compatibilities proper or extended properties proper 200300a2430fSAndrzej Pietrasiewicz * portions of the data 200400a2430fSAndrzej Pietrasiewicz */ 200500a2430fSAndrzej Pietrasiewicz if (le32_to_cpu(desc->dwLength) > len) 200600a2430fSAndrzej Pietrasiewicz return -EINVAL; 200700a2430fSAndrzej Pietrasiewicz 200800a2430fSAndrzej Pietrasiewicz ret = __ffs_do_os_desc_header(&type, desc); 200900a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 201000a2430fSAndrzej Pietrasiewicz pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n", 201100a2430fSAndrzej Pietrasiewicz num, ret); 201200a2430fSAndrzej Pietrasiewicz return ret; 201300a2430fSAndrzej Pietrasiewicz } 201400a2430fSAndrzej Pietrasiewicz /* 201500a2430fSAndrzej Pietrasiewicz * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??" 201600a2430fSAndrzej Pietrasiewicz */ 201700a2430fSAndrzej Pietrasiewicz feature_count = le16_to_cpu(desc->wCount); 201800a2430fSAndrzej Pietrasiewicz if (type == FFS_OS_DESC_EXT_COMPAT && 201900a2430fSAndrzej Pietrasiewicz (feature_count > 255 || desc->Reserved)) 202000a2430fSAndrzej Pietrasiewicz return -EINVAL; 202100a2430fSAndrzej Pietrasiewicz len -= ret; 202200a2430fSAndrzej Pietrasiewicz data += ret; 202300a2430fSAndrzej Pietrasiewicz 202400a2430fSAndrzej Pietrasiewicz /* 202500a2430fSAndrzej Pietrasiewicz * Process all function/property descriptors 202600a2430fSAndrzej Pietrasiewicz * of this Feature Descriptor 202700a2430fSAndrzej Pietrasiewicz */ 202800a2430fSAndrzej Pietrasiewicz ret = ffs_do_single_os_desc(data, len, type, 202900a2430fSAndrzej Pietrasiewicz feature_count, entity, priv, desc); 203000a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) { 203100a2430fSAndrzej Pietrasiewicz pr_debug("%s returns %d\n", __func__, ret); 203200a2430fSAndrzej Pietrasiewicz return ret; 203300a2430fSAndrzej Pietrasiewicz } 203400a2430fSAndrzej Pietrasiewicz 203500a2430fSAndrzej Pietrasiewicz len -= ret; 203600a2430fSAndrzej Pietrasiewicz data += ret; 203700a2430fSAndrzej Pietrasiewicz } 203800a2430fSAndrzej Pietrasiewicz return _len - len; 203900a2430fSAndrzej Pietrasiewicz } 204000a2430fSAndrzej Pietrasiewicz 204100a2430fSAndrzej Pietrasiewicz /** 204200a2430fSAndrzej Pietrasiewicz * Validate contents of the buffer from userspace related to OS descriptors. 204300a2430fSAndrzej Pietrasiewicz */ 204400a2430fSAndrzej Pietrasiewicz static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, 204500a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *h, void *data, 204600a2430fSAndrzej Pietrasiewicz unsigned len, void *priv) 204700a2430fSAndrzej Pietrasiewicz { 204800a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = priv; 204900a2430fSAndrzej Pietrasiewicz u8 length; 205000a2430fSAndrzej Pietrasiewicz 205100a2430fSAndrzej Pietrasiewicz ENTER(); 205200a2430fSAndrzej Pietrasiewicz 205300a2430fSAndrzej Pietrasiewicz switch (type) { 205400a2430fSAndrzej Pietrasiewicz case FFS_OS_DESC_EXT_COMPAT: { 205500a2430fSAndrzej Pietrasiewicz struct usb_ext_compat_desc *d = data; 205600a2430fSAndrzej Pietrasiewicz int i; 205700a2430fSAndrzej Pietrasiewicz 205800a2430fSAndrzej Pietrasiewicz if (len < sizeof(*d) || 205900a2430fSAndrzej Pietrasiewicz d->bFirstInterfaceNumber >= ffs->interfaces_count || 206000a2430fSAndrzej Pietrasiewicz d->Reserved1) 206100a2430fSAndrzej Pietrasiewicz return -EINVAL; 206200a2430fSAndrzej Pietrasiewicz for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) 206300a2430fSAndrzej Pietrasiewicz if (d->Reserved2[i]) 206400a2430fSAndrzej Pietrasiewicz return -EINVAL; 206500a2430fSAndrzej Pietrasiewicz 206600a2430fSAndrzej Pietrasiewicz length = sizeof(struct usb_ext_compat_desc); 206700a2430fSAndrzej Pietrasiewicz } 206800a2430fSAndrzej Pietrasiewicz break; 206900a2430fSAndrzej Pietrasiewicz case FFS_OS_DESC_EXT_PROP: { 207000a2430fSAndrzej Pietrasiewicz struct usb_ext_prop_desc *d = data; 207100a2430fSAndrzej Pietrasiewicz u32 type, pdl; 207200a2430fSAndrzej Pietrasiewicz u16 pnl; 207300a2430fSAndrzej Pietrasiewicz 207400a2430fSAndrzej Pietrasiewicz if (len < sizeof(*d) || h->interface >= ffs->interfaces_count) 207500a2430fSAndrzej Pietrasiewicz return -EINVAL; 207600a2430fSAndrzej Pietrasiewicz length = le32_to_cpu(d->dwSize); 207700a2430fSAndrzej Pietrasiewicz type = le32_to_cpu(d->dwPropertyDataType); 207800a2430fSAndrzej Pietrasiewicz if (type < USB_EXT_PROP_UNICODE || 207900a2430fSAndrzej Pietrasiewicz type > USB_EXT_PROP_UNICODE_MULTI) { 208000a2430fSAndrzej Pietrasiewicz pr_vdebug("unsupported os descriptor property type: %d", 208100a2430fSAndrzej Pietrasiewicz type); 208200a2430fSAndrzej Pietrasiewicz return -EINVAL; 208300a2430fSAndrzej Pietrasiewicz } 208400a2430fSAndrzej Pietrasiewicz pnl = le16_to_cpu(d->wPropertyNameLength); 208500a2430fSAndrzej Pietrasiewicz pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl)); 208600a2430fSAndrzej Pietrasiewicz if (length != 14 + pnl + pdl) { 208700a2430fSAndrzej Pietrasiewicz pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n", 208800a2430fSAndrzej Pietrasiewicz length, pnl, pdl, type); 208900a2430fSAndrzej Pietrasiewicz return -EINVAL; 209000a2430fSAndrzej Pietrasiewicz } 209100a2430fSAndrzej Pietrasiewicz ++ffs->ms_os_descs_ext_prop_count; 209200a2430fSAndrzej Pietrasiewicz /* property name reported to the host as "WCHAR"s */ 209300a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_name_len += pnl * 2; 209400a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_data_len += pdl; 209500a2430fSAndrzej Pietrasiewicz } 209600a2430fSAndrzej Pietrasiewicz break; 209700a2430fSAndrzej Pietrasiewicz default: 209800a2430fSAndrzej Pietrasiewicz pr_vdebug("unknown descriptor: %d\n", type); 209900a2430fSAndrzej Pietrasiewicz return -EINVAL; 210000a2430fSAndrzej Pietrasiewicz } 210100a2430fSAndrzej Pietrasiewicz return length; 210200a2430fSAndrzej Pietrasiewicz } 210300a2430fSAndrzej Pietrasiewicz 210400a2430fSAndrzej Pietrasiewicz static int __ffs_data_got_descs(struct ffs_data *ffs, 210500a2430fSAndrzej Pietrasiewicz char *const _data, size_t len) 210600a2430fSAndrzej Pietrasiewicz { 210700a2430fSAndrzej Pietrasiewicz char *data = _data, *raw_descs; 210800a2430fSAndrzej Pietrasiewicz unsigned os_descs_count = 0, counts[3], flags; 210900a2430fSAndrzej Pietrasiewicz int ret = -EINVAL, i; 21106d5c1c77SRobert Baldyga struct ffs_desc_helper helper; 211100a2430fSAndrzej Pietrasiewicz 211200a2430fSAndrzej Pietrasiewicz ENTER(); 211300a2430fSAndrzej Pietrasiewicz 211400a2430fSAndrzej Pietrasiewicz if (get_unaligned_le32(data + 4) != len) 211500a2430fSAndrzej Pietrasiewicz goto error; 211600a2430fSAndrzej Pietrasiewicz 211700a2430fSAndrzej Pietrasiewicz switch (get_unaligned_le32(data)) { 211800a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_DESCRIPTORS_MAGIC: 211900a2430fSAndrzej Pietrasiewicz flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; 212000a2430fSAndrzej Pietrasiewicz data += 8; 212100a2430fSAndrzej Pietrasiewicz len -= 8; 212200a2430fSAndrzej Pietrasiewicz break; 212300a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_DESCRIPTORS_MAGIC_V2: 212400a2430fSAndrzej Pietrasiewicz flags = get_unaligned_le32(data + 8); 21251b0bf88fSRobert Baldyga ffs->user_flags = flags; 212600a2430fSAndrzej Pietrasiewicz if (flags & ~(FUNCTIONFS_HAS_FS_DESC | 212700a2430fSAndrzej Pietrasiewicz FUNCTIONFS_HAS_HS_DESC | 212800a2430fSAndrzej Pietrasiewicz FUNCTIONFS_HAS_SS_DESC | 21291b0bf88fSRobert Baldyga FUNCTIONFS_HAS_MS_OS_DESC | 21305e33f6fdSRobert Baldyga FUNCTIONFS_VIRTUAL_ADDR | 21315e33f6fdSRobert Baldyga FUNCTIONFS_EVENTFD)) { 213200a2430fSAndrzej Pietrasiewicz ret = -ENOSYS; 213300a2430fSAndrzej Pietrasiewicz goto error; 213400a2430fSAndrzej Pietrasiewicz } 213500a2430fSAndrzej Pietrasiewicz data += 12; 213600a2430fSAndrzej Pietrasiewicz len -= 12; 213700a2430fSAndrzej Pietrasiewicz break; 213800a2430fSAndrzej Pietrasiewicz default: 213900a2430fSAndrzej Pietrasiewicz goto error; 214000a2430fSAndrzej Pietrasiewicz } 214100a2430fSAndrzej Pietrasiewicz 21425e33f6fdSRobert Baldyga if (flags & FUNCTIONFS_EVENTFD) { 21435e33f6fdSRobert Baldyga if (len < 4) 21445e33f6fdSRobert Baldyga goto error; 21455e33f6fdSRobert Baldyga ffs->ffs_eventfd = 21465e33f6fdSRobert Baldyga eventfd_ctx_fdget((int)get_unaligned_le32(data)); 21475e33f6fdSRobert Baldyga if (IS_ERR(ffs->ffs_eventfd)) { 21485e33f6fdSRobert Baldyga ret = PTR_ERR(ffs->ffs_eventfd); 21495e33f6fdSRobert Baldyga ffs->ffs_eventfd = NULL; 21505e33f6fdSRobert Baldyga goto error; 21515e33f6fdSRobert Baldyga } 21525e33f6fdSRobert Baldyga data += 4; 21535e33f6fdSRobert Baldyga len -= 4; 21545e33f6fdSRobert Baldyga } 21555e33f6fdSRobert Baldyga 215600a2430fSAndrzej Pietrasiewicz /* Read fs_count, hs_count and ss_count (if present) */ 215700a2430fSAndrzej Pietrasiewicz for (i = 0; i < 3; ++i) { 215800a2430fSAndrzej Pietrasiewicz if (!(flags & (1 << i))) { 215900a2430fSAndrzej Pietrasiewicz counts[i] = 0; 216000a2430fSAndrzej Pietrasiewicz } else if (len < 4) { 216100a2430fSAndrzej Pietrasiewicz goto error; 216200a2430fSAndrzej Pietrasiewicz } else { 216300a2430fSAndrzej Pietrasiewicz counts[i] = get_unaligned_le32(data); 216400a2430fSAndrzej Pietrasiewicz data += 4; 216500a2430fSAndrzej Pietrasiewicz len -= 4; 216600a2430fSAndrzej Pietrasiewicz } 216700a2430fSAndrzej Pietrasiewicz } 216800a2430fSAndrzej Pietrasiewicz if (flags & (1 << i)) { 216900a2430fSAndrzej Pietrasiewicz os_descs_count = get_unaligned_le32(data); 217000a2430fSAndrzej Pietrasiewicz data += 4; 217100a2430fSAndrzej Pietrasiewicz len -= 4; 217200a2430fSAndrzej Pietrasiewicz }; 217300a2430fSAndrzej Pietrasiewicz 217400a2430fSAndrzej Pietrasiewicz /* Read descriptors */ 217500a2430fSAndrzej Pietrasiewicz raw_descs = data; 21766d5c1c77SRobert Baldyga helper.ffs = ffs; 217700a2430fSAndrzej Pietrasiewicz for (i = 0; i < 3; ++i) { 217800a2430fSAndrzej Pietrasiewicz if (!counts[i]) 217900a2430fSAndrzej Pietrasiewicz continue; 21806d5c1c77SRobert Baldyga helper.interfaces_count = 0; 21816d5c1c77SRobert Baldyga helper.eps_count = 0; 218200a2430fSAndrzej Pietrasiewicz ret = ffs_do_descs(counts[i], data, len, 21836d5c1c77SRobert Baldyga __ffs_data_do_entity, &helper); 218400a2430fSAndrzej Pietrasiewicz if (ret < 0) 218500a2430fSAndrzej Pietrasiewicz goto error; 21866d5c1c77SRobert Baldyga if (!ffs->eps_count && !ffs->interfaces_count) { 21876d5c1c77SRobert Baldyga ffs->eps_count = helper.eps_count; 21886d5c1c77SRobert Baldyga ffs->interfaces_count = helper.interfaces_count; 21896d5c1c77SRobert Baldyga } else { 21906d5c1c77SRobert Baldyga if (ffs->eps_count != helper.eps_count) { 21916d5c1c77SRobert Baldyga ret = -EINVAL; 21926d5c1c77SRobert Baldyga goto error; 21936d5c1c77SRobert Baldyga } 21946d5c1c77SRobert Baldyga if (ffs->interfaces_count != helper.interfaces_count) { 21956d5c1c77SRobert Baldyga ret = -EINVAL; 21966d5c1c77SRobert Baldyga goto error; 21976d5c1c77SRobert Baldyga } 21986d5c1c77SRobert Baldyga } 219900a2430fSAndrzej Pietrasiewicz data += ret; 220000a2430fSAndrzej Pietrasiewicz len -= ret; 220100a2430fSAndrzej Pietrasiewicz } 220200a2430fSAndrzej Pietrasiewicz if (os_descs_count) { 220300a2430fSAndrzej Pietrasiewicz ret = ffs_do_os_descs(os_descs_count, data, len, 220400a2430fSAndrzej Pietrasiewicz __ffs_data_do_os_desc, ffs); 220500a2430fSAndrzej Pietrasiewicz if (ret < 0) 220600a2430fSAndrzej Pietrasiewicz goto error; 220700a2430fSAndrzej Pietrasiewicz data += ret; 220800a2430fSAndrzej Pietrasiewicz len -= ret; 220900a2430fSAndrzej Pietrasiewicz } 221000a2430fSAndrzej Pietrasiewicz 221100a2430fSAndrzej Pietrasiewicz if (raw_descs == data || len) { 221200a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 221300a2430fSAndrzej Pietrasiewicz goto error; 221400a2430fSAndrzej Pietrasiewicz } 221500a2430fSAndrzej Pietrasiewicz 221600a2430fSAndrzej Pietrasiewicz ffs->raw_descs_data = _data; 221700a2430fSAndrzej Pietrasiewicz ffs->raw_descs = raw_descs; 221800a2430fSAndrzej Pietrasiewicz ffs->raw_descs_length = data - raw_descs; 221900a2430fSAndrzej Pietrasiewicz ffs->fs_descs_count = counts[0]; 222000a2430fSAndrzej Pietrasiewicz ffs->hs_descs_count = counts[1]; 222100a2430fSAndrzej Pietrasiewicz ffs->ss_descs_count = counts[2]; 222200a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_count = os_descs_count; 222300a2430fSAndrzej Pietrasiewicz 222400a2430fSAndrzej Pietrasiewicz return 0; 222500a2430fSAndrzej Pietrasiewicz 222600a2430fSAndrzej Pietrasiewicz error: 222700a2430fSAndrzej Pietrasiewicz kfree(_data); 222800a2430fSAndrzej Pietrasiewicz return ret; 222900a2430fSAndrzej Pietrasiewicz } 223000a2430fSAndrzej Pietrasiewicz 223100a2430fSAndrzej Pietrasiewicz static int __ffs_data_got_strings(struct ffs_data *ffs, 223200a2430fSAndrzej Pietrasiewicz char *const _data, size_t len) 223300a2430fSAndrzej Pietrasiewicz { 223400a2430fSAndrzej Pietrasiewicz u32 str_count, needed_count, lang_count; 223500a2430fSAndrzej Pietrasiewicz struct usb_gadget_strings **stringtabs, *t; 223600a2430fSAndrzej Pietrasiewicz struct usb_string *strings, *s; 223700a2430fSAndrzej Pietrasiewicz const char *data = _data; 223800a2430fSAndrzej Pietrasiewicz 223900a2430fSAndrzej Pietrasiewicz ENTER(); 224000a2430fSAndrzej Pietrasiewicz 224100a2430fSAndrzej Pietrasiewicz if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || 224200a2430fSAndrzej Pietrasiewicz get_unaligned_le32(data + 4) != len)) 224300a2430fSAndrzej Pietrasiewicz goto error; 224400a2430fSAndrzej Pietrasiewicz str_count = get_unaligned_le32(data + 8); 224500a2430fSAndrzej Pietrasiewicz lang_count = get_unaligned_le32(data + 12); 224600a2430fSAndrzej Pietrasiewicz 224700a2430fSAndrzej Pietrasiewicz /* if one is zero the other must be zero */ 224800a2430fSAndrzej Pietrasiewicz if (unlikely(!str_count != !lang_count)) 224900a2430fSAndrzej Pietrasiewicz goto error; 225000a2430fSAndrzej Pietrasiewicz 225100a2430fSAndrzej Pietrasiewicz /* Do we have at least as many strings as descriptors need? */ 225200a2430fSAndrzej Pietrasiewicz needed_count = ffs->strings_count; 225300a2430fSAndrzej Pietrasiewicz if (unlikely(str_count < needed_count)) 225400a2430fSAndrzej Pietrasiewicz goto error; 225500a2430fSAndrzej Pietrasiewicz 225600a2430fSAndrzej Pietrasiewicz /* 225700a2430fSAndrzej Pietrasiewicz * If we don't need any strings just return and free all 225800a2430fSAndrzej Pietrasiewicz * memory. 225900a2430fSAndrzej Pietrasiewicz */ 226000a2430fSAndrzej Pietrasiewicz if (!needed_count) { 226100a2430fSAndrzej Pietrasiewicz kfree(_data); 226200a2430fSAndrzej Pietrasiewicz return 0; 226300a2430fSAndrzej Pietrasiewicz } 226400a2430fSAndrzej Pietrasiewicz 226500a2430fSAndrzej Pietrasiewicz /* Allocate everything in one chunk so there's less maintenance. */ 226600a2430fSAndrzej Pietrasiewicz { 226700a2430fSAndrzej Pietrasiewicz unsigned i = 0; 226800a2430fSAndrzej Pietrasiewicz vla_group(d); 226900a2430fSAndrzej Pietrasiewicz vla_item(d, struct usb_gadget_strings *, stringtabs, 227000a2430fSAndrzej Pietrasiewicz lang_count + 1); 227100a2430fSAndrzej Pietrasiewicz vla_item(d, struct usb_gadget_strings, stringtab, lang_count); 227200a2430fSAndrzej Pietrasiewicz vla_item(d, struct usb_string, strings, 227300a2430fSAndrzej Pietrasiewicz lang_count*(needed_count+1)); 227400a2430fSAndrzej Pietrasiewicz 227500a2430fSAndrzej Pietrasiewicz char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); 227600a2430fSAndrzej Pietrasiewicz 227700a2430fSAndrzej Pietrasiewicz if (unlikely(!vlabuf)) { 227800a2430fSAndrzej Pietrasiewicz kfree(_data); 227900a2430fSAndrzej Pietrasiewicz return -ENOMEM; 228000a2430fSAndrzej Pietrasiewicz } 228100a2430fSAndrzej Pietrasiewicz 228200a2430fSAndrzej Pietrasiewicz /* Initialize the VLA pointers */ 228300a2430fSAndrzej Pietrasiewicz stringtabs = vla_ptr(vlabuf, d, stringtabs); 228400a2430fSAndrzej Pietrasiewicz t = vla_ptr(vlabuf, d, stringtab); 228500a2430fSAndrzej Pietrasiewicz i = lang_count; 228600a2430fSAndrzej Pietrasiewicz do { 228700a2430fSAndrzej Pietrasiewicz *stringtabs++ = t++; 228800a2430fSAndrzej Pietrasiewicz } while (--i); 228900a2430fSAndrzej Pietrasiewicz *stringtabs = NULL; 229000a2430fSAndrzej Pietrasiewicz 229100a2430fSAndrzej Pietrasiewicz /* stringtabs = vlabuf = d_stringtabs for later kfree */ 229200a2430fSAndrzej Pietrasiewicz stringtabs = vla_ptr(vlabuf, d, stringtabs); 229300a2430fSAndrzej Pietrasiewicz t = vla_ptr(vlabuf, d, stringtab); 229400a2430fSAndrzej Pietrasiewicz s = vla_ptr(vlabuf, d, strings); 229500a2430fSAndrzej Pietrasiewicz strings = s; 229600a2430fSAndrzej Pietrasiewicz } 229700a2430fSAndrzej Pietrasiewicz 229800a2430fSAndrzej Pietrasiewicz /* For each language */ 229900a2430fSAndrzej Pietrasiewicz data += 16; 230000a2430fSAndrzej Pietrasiewicz len -= 16; 230100a2430fSAndrzej Pietrasiewicz 230200a2430fSAndrzej Pietrasiewicz do { /* lang_count > 0 so we can use do-while */ 230300a2430fSAndrzej Pietrasiewicz unsigned needed = needed_count; 230400a2430fSAndrzej Pietrasiewicz 230500a2430fSAndrzej Pietrasiewicz if (unlikely(len < 3)) 230600a2430fSAndrzej Pietrasiewicz goto error_free; 230700a2430fSAndrzej Pietrasiewicz t->language = get_unaligned_le16(data); 230800a2430fSAndrzej Pietrasiewicz t->strings = s; 230900a2430fSAndrzej Pietrasiewicz ++t; 231000a2430fSAndrzej Pietrasiewicz 231100a2430fSAndrzej Pietrasiewicz data += 2; 231200a2430fSAndrzej Pietrasiewicz len -= 2; 231300a2430fSAndrzej Pietrasiewicz 231400a2430fSAndrzej Pietrasiewicz /* For each string */ 231500a2430fSAndrzej Pietrasiewicz do { /* str_count > 0 so we can use do-while */ 231600a2430fSAndrzej Pietrasiewicz size_t length = strnlen(data, len); 231700a2430fSAndrzej Pietrasiewicz 231800a2430fSAndrzej Pietrasiewicz if (unlikely(length == len)) 231900a2430fSAndrzej Pietrasiewicz goto error_free; 232000a2430fSAndrzej Pietrasiewicz 232100a2430fSAndrzej Pietrasiewicz /* 232200a2430fSAndrzej Pietrasiewicz * User may provide more strings then we need, 232300a2430fSAndrzej Pietrasiewicz * if that's the case we simply ignore the 232400a2430fSAndrzej Pietrasiewicz * rest 232500a2430fSAndrzej Pietrasiewicz */ 232600a2430fSAndrzej Pietrasiewicz if (likely(needed)) { 232700a2430fSAndrzej Pietrasiewicz /* 232800a2430fSAndrzej Pietrasiewicz * s->id will be set while adding 232900a2430fSAndrzej Pietrasiewicz * function to configuration so for 233000a2430fSAndrzej Pietrasiewicz * now just leave garbage here. 233100a2430fSAndrzej Pietrasiewicz */ 233200a2430fSAndrzej Pietrasiewicz s->s = data; 233300a2430fSAndrzej Pietrasiewicz --needed; 233400a2430fSAndrzej Pietrasiewicz ++s; 233500a2430fSAndrzej Pietrasiewicz } 233600a2430fSAndrzej Pietrasiewicz 233700a2430fSAndrzej Pietrasiewicz data += length + 1; 233800a2430fSAndrzej Pietrasiewicz len -= length + 1; 233900a2430fSAndrzej Pietrasiewicz } while (--str_count); 234000a2430fSAndrzej Pietrasiewicz 234100a2430fSAndrzej Pietrasiewicz s->id = 0; /* terminator */ 234200a2430fSAndrzej Pietrasiewicz s->s = NULL; 234300a2430fSAndrzej Pietrasiewicz ++s; 234400a2430fSAndrzej Pietrasiewicz 234500a2430fSAndrzej Pietrasiewicz } while (--lang_count); 234600a2430fSAndrzej Pietrasiewicz 234700a2430fSAndrzej Pietrasiewicz /* Some garbage left? */ 234800a2430fSAndrzej Pietrasiewicz if (unlikely(len)) 234900a2430fSAndrzej Pietrasiewicz goto error_free; 235000a2430fSAndrzej Pietrasiewicz 235100a2430fSAndrzej Pietrasiewicz /* Done! */ 235200a2430fSAndrzej Pietrasiewicz ffs->stringtabs = stringtabs; 235300a2430fSAndrzej Pietrasiewicz ffs->raw_strings = _data; 235400a2430fSAndrzej Pietrasiewicz 235500a2430fSAndrzej Pietrasiewicz return 0; 235600a2430fSAndrzej Pietrasiewicz 235700a2430fSAndrzej Pietrasiewicz error_free: 235800a2430fSAndrzej Pietrasiewicz kfree(stringtabs); 235900a2430fSAndrzej Pietrasiewicz error: 236000a2430fSAndrzej Pietrasiewicz kfree(_data); 236100a2430fSAndrzej Pietrasiewicz return -EINVAL; 236200a2430fSAndrzej Pietrasiewicz } 236300a2430fSAndrzej Pietrasiewicz 236400a2430fSAndrzej Pietrasiewicz 236500a2430fSAndrzej Pietrasiewicz /* Events handling and management *******************************************/ 236600a2430fSAndrzej Pietrasiewicz 236700a2430fSAndrzej Pietrasiewicz static void __ffs_event_add(struct ffs_data *ffs, 236800a2430fSAndrzej Pietrasiewicz enum usb_functionfs_event_type type) 236900a2430fSAndrzej Pietrasiewicz { 237000a2430fSAndrzej Pietrasiewicz enum usb_functionfs_event_type rem_type1, rem_type2 = type; 237100a2430fSAndrzej Pietrasiewicz int neg = 0; 237200a2430fSAndrzej Pietrasiewicz 237300a2430fSAndrzej Pietrasiewicz /* 237400a2430fSAndrzej Pietrasiewicz * Abort any unhandled setup 237500a2430fSAndrzej Pietrasiewicz * 237600a2430fSAndrzej Pietrasiewicz * We do not need to worry about some cmpxchg() changing value 237700a2430fSAndrzej Pietrasiewicz * of ffs->setup_state without holding the lock because when 237800a2430fSAndrzej Pietrasiewicz * state is FFS_SETUP_PENDING cmpxchg() in several places in 237900a2430fSAndrzej Pietrasiewicz * the source does nothing. 238000a2430fSAndrzej Pietrasiewicz */ 238100a2430fSAndrzej Pietrasiewicz if (ffs->setup_state == FFS_SETUP_PENDING) 238200a2430fSAndrzej Pietrasiewicz ffs->setup_state = FFS_SETUP_CANCELLED; 238300a2430fSAndrzej Pietrasiewicz 238467913bbdSMichal Nazarewicz /* 238567913bbdSMichal Nazarewicz * Logic of this function guarantees that there are at most four pending 238667913bbdSMichal Nazarewicz * evens on ffs->ev.types queue. This is important because the queue 238767913bbdSMichal Nazarewicz * has space for four elements only and __ffs_ep0_read_events function 238867913bbdSMichal Nazarewicz * depends on that limit as well. If more event types are added, those 238967913bbdSMichal Nazarewicz * limits have to be revisited or guaranteed to still hold. 239067913bbdSMichal Nazarewicz */ 239100a2430fSAndrzej Pietrasiewicz switch (type) { 239200a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_RESUME: 239300a2430fSAndrzej Pietrasiewicz rem_type2 = FUNCTIONFS_SUSPEND; 239400a2430fSAndrzej Pietrasiewicz /* FALL THROUGH */ 239500a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_SUSPEND: 239600a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_SETUP: 239700a2430fSAndrzej Pietrasiewicz rem_type1 = type; 239800a2430fSAndrzej Pietrasiewicz /* Discard all similar events */ 239900a2430fSAndrzej Pietrasiewicz break; 240000a2430fSAndrzej Pietrasiewicz 240100a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_BIND: 240200a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_UNBIND: 240300a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_DISABLE: 240400a2430fSAndrzej Pietrasiewicz case FUNCTIONFS_ENABLE: 240500a2430fSAndrzej Pietrasiewicz /* Discard everything other then power management. */ 240600a2430fSAndrzej Pietrasiewicz rem_type1 = FUNCTIONFS_SUSPEND; 240700a2430fSAndrzej Pietrasiewicz rem_type2 = FUNCTIONFS_RESUME; 240800a2430fSAndrzej Pietrasiewicz neg = 1; 240900a2430fSAndrzej Pietrasiewicz break; 241000a2430fSAndrzej Pietrasiewicz 241100a2430fSAndrzej Pietrasiewicz default: 2412fe00bcbfSMichal Nazarewicz WARN(1, "%d: unknown event, this should not happen\n", type); 2413fe00bcbfSMichal Nazarewicz return; 241400a2430fSAndrzej Pietrasiewicz } 241500a2430fSAndrzej Pietrasiewicz 241600a2430fSAndrzej Pietrasiewicz { 241700a2430fSAndrzej Pietrasiewicz u8 *ev = ffs->ev.types, *out = ev; 241800a2430fSAndrzej Pietrasiewicz unsigned n = ffs->ev.count; 241900a2430fSAndrzej Pietrasiewicz for (; n; --n, ++ev) 242000a2430fSAndrzej Pietrasiewicz if ((*ev == rem_type1 || *ev == rem_type2) == neg) 242100a2430fSAndrzej Pietrasiewicz *out++ = *ev; 242200a2430fSAndrzej Pietrasiewicz else 242300a2430fSAndrzej Pietrasiewicz pr_vdebug("purging event %d\n", *ev); 242400a2430fSAndrzej Pietrasiewicz ffs->ev.count = out - ffs->ev.types; 242500a2430fSAndrzej Pietrasiewicz } 242600a2430fSAndrzej Pietrasiewicz 242700a2430fSAndrzej Pietrasiewicz pr_vdebug("adding event %d\n", type); 242800a2430fSAndrzej Pietrasiewicz ffs->ev.types[ffs->ev.count++] = type; 242900a2430fSAndrzej Pietrasiewicz wake_up_locked(&ffs->ev.waitq); 24305e33f6fdSRobert Baldyga if (ffs->ffs_eventfd) 24315e33f6fdSRobert Baldyga eventfd_signal(ffs->ffs_eventfd, 1); 243200a2430fSAndrzej Pietrasiewicz } 243300a2430fSAndrzej Pietrasiewicz 243400a2430fSAndrzej Pietrasiewicz static void ffs_event_add(struct ffs_data *ffs, 243500a2430fSAndrzej Pietrasiewicz enum usb_functionfs_event_type type) 243600a2430fSAndrzej Pietrasiewicz { 243700a2430fSAndrzej Pietrasiewicz unsigned long flags; 243800a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&ffs->ev.waitq.lock, flags); 243900a2430fSAndrzej Pietrasiewicz __ffs_event_add(ffs, type); 244000a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); 244100a2430fSAndrzej Pietrasiewicz } 244200a2430fSAndrzej Pietrasiewicz 244300a2430fSAndrzej Pietrasiewicz /* Bind/unbind USB function hooks *******************************************/ 244400a2430fSAndrzej Pietrasiewicz 24456d5c1c77SRobert Baldyga static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address) 24466d5c1c77SRobert Baldyga { 24476d5c1c77SRobert Baldyga int i; 24486d5c1c77SRobert Baldyga 24496d5c1c77SRobert Baldyga for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i) 24506d5c1c77SRobert Baldyga if (ffs->eps_addrmap[i] == endpoint_address) 24516d5c1c77SRobert Baldyga return i; 24526d5c1c77SRobert Baldyga return -ENOENT; 24536d5c1c77SRobert Baldyga } 24546d5c1c77SRobert Baldyga 245500a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, 245600a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *desc, 245700a2430fSAndrzej Pietrasiewicz void *priv) 245800a2430fSAndrzej Pietrasiewicz { 245900a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor *ds = (void *)desc; 246000a2430fSAndrzej Pietrasiewicz struct ffs_function *func = priv; 246100a2430fSAndrzej Pietrasiewicz struct ffs_ep *ffs_ep; 246285b06f5eSDan Carpenter unsigned ep_desc_id; 246385b06f5eSDan Carpenter int idx; 246400a2430fSAndrzej Pietrasiewicz static const char *speed_names[] = { "full", "high", "super" }; 246500a2430fSAndrzej Pietrasiewicz 246600a2430fSAndrzej Pietrasiewicz if (type != FFS_DESCRIPTOR) 246700a2430fSAndrzej Pietrasiewicz return 0; 246800a2430fSAndrzej Pietrasiewicz 246900a2430fSAndrzej Pietrasiewicz /* 247000a2430fSAndrzej Pietrasiewicz * If ss_descriptors is not NULL, we are reading super speed 247100a2430fSAndrzej Pietrasiewicz * descriptors; if hs_descriptors is not NULL, we are reading high 247200a2430fSAndrzej Pietrasiewicz * speed descriptors; otherwise, we are reading full speed 247300a2430fSAndrzej Pietrasiewicz * descriptors. 247400a2430fSAndrzej Pietrasiewicz */ 247500a2430fSAndrzej Pietrasiewicz if (func->function.ss_descriptors) { 247600a2430fSAndrzej Pietrasiewicz ep_desc_id = 2; 247700a2430fSAndrzej Pietrasiewicz func->function.ss_descriptors[(long)valuep] = desc; 247800a2430fSAndrzej Pietrasiewicz } else if (func->function.hs_descriptors) { 247900a2430fSAndrzej Pietrasiewicz ep_desc_id = 1; 248000a2430fSAndrzej Pietrasiewicz func->function.hs_descriptors[(long)valuep] = desc; 248100a2430fSAndrzej Pietrasiewicz } else { 248200a2430fSAndrzej Pietrasiewicz ep_desc_id = 0; 248300a2430fSAndrzej Pietrasiewicz func->function.fs_descriptors[(long)valuep] = desc; 248400a2430fSAndrzej Pietrasiewicz } 248500a2430fSAndrzej Pietrasiewicz 248600a2430fSAndrzej Pietrasiewicz if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) 248700a2430fSAndrzej Pietrasiewicz return 0; 248800a2430fSAndrzej Pietrasiewicz 24896d5c1c77SRobert Baldyga idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1; 24906d5c1c77SRobert Baldyga if (idx < 0) 24916d5c1c77SRobert Baldyga return idx; 24926d5c1c77SRobert Baldyga 249300a2430fSAndrzej Pietrasiewicz ffs_ep = func->eps + idx; 249400a2430fSAndrzej Pietrasiewicz 249500a2430fSAndrzej Pietrasiewicz if (unlikely(ffs_ep->descs[ep_desc_id])) { 249600a2430fSAndrzej Pietrasiewicz pr_err("two %sspeed descriptors for EP %d\n", 249700a2430fSAndrzej Pietrasiewicz speed_names[ep_desc_id], 249800a2430fSAndrzej Pietrasiewicz ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 249900a2430fSAndrzej Pietrasiewicz return -EINVAL; 250000a2430fSAndrzej Pietrasiewicz } 250100a2430fSAndrzej Pietrasiewicz ffs_ep->descs[ep_desc_id] = ds; 250200a2430fSAndrzej Pietrasiewicz 250300a2430fSAndrzej Pietrasiewicz ffs_dump_mem(": Original ep desc", ds, ds->bLength); 250400a2430fSAndrzej Pietrasiewicz if (ffs_ep->ep) { 250500a2430fSAndrzej Pietrasiewicz ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress; 250600a2430fSAndrzej Pietrasiewicz if (!ds->wMaxPacketSize) 250700a2430fSAndrzej Pietrasiewicz ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize; 250800a2430fSAndrzej Pietrasiewicz } else { 250900a2430fSAndrzej Pietrasiewicz struct usb_request *req; 251000a2430fSAndrzej Pietrasiewicz struct usb_ep *ep; 25111b0bf88fSRobert Baldyga u8 bEndpointAddress; 251200a2430fSAndrzej Pietrasiewicz 25131b0bf88fSRobert Baldyga /* 25141b0bf88fSRobert Baldyga * We back up bEndpointAddress because autoconfig overwrites 25151b0bf88fSRobert Baldyga * it with physical endpoint address. 25161b0bf88fSRobert Baldyga */ 25171b0bf88fSRobert Baldyga bEndpointAddress = ds->bEndpointAddress; 251800a2430fSAndrzej Pietrasiewicz pr_vdebug("autoconfig\n"); 251900a2430fSAndrzej Pietrasiewicz ep = usb_ep_autoconfig(func->gadget, ds); 252000a2430fSAndrzej Pietrasiewicz if (unlikely(!ep)) 252100a2430fSAndrzej Pietrasiewicz return -ENOTSUPP; 252200a2430fSAndrzej Pietrasiewicz ep->driver_data = func->eps + idx; 252300a2430fSAndrzej Pietrasiewicz 252400a2430fSAndrzej Pietrasiewicz req = usb_ep_alloc_request(ep, GFP_KERNEL); 252500a2430fSAndrzej Pietrasiewicz if (unlikely(!req)) 252600a2430fSAndrzej Pietrasiewicz return -ENOMEM; 252700a2430fSAndrzej Pietrasiewicz 252800a2430fSAndrzej Pietrasiewicz ffs_ep->ep = ep; 252900a2430fSAndrzej Pietrasiewicz ffs_ep->req = req; 253000a2430fSAndrzej Pietrasiewicz func->eps_revmap[ds->bEndpointAddress & 253100a2430fSAndrzej Pietrasiewicz USB_ENDPOINT_NUMBER_MASK] = idx + 1; 25321b0bf88fSRobert Baldyga /* 25331b0bf88fSRobert Baldyga * If we use virtual address mapping, we restore 25341b0bf88fSRobert Baldyga * original bEndpointAddress value. 25351b0bf88fSRobert Baldyga */ 25361b0bf88fSRobert Baldyga if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) 25371b0bf88fSRobert Baldyga ds->bEndpointAddress = bEndpointAddress; 253800a2430fSAndrzej Pietrasiewicz } 253900a2430fSAndrzej Pietrasiewicz ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); 254000a2430fSAndrzej Pietrasiewicz 254100a2430fSAndrzej Pietrasiewicz return 0; 254200a2430fSAndrzej Pietrasiewicz } 254300a2430fSAndrzej Pietrasiewicz 254400a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, 254500a2430fSAndrzej Pietrasiewicz struct usb_descriptor_header *desc, 254600a2430fSAndrzej Pietrasiewicz void *priv) 254700a2430fSAndrzej Pietrasiewicz { 254800a2430fSAndrzej Pietrasiewicz struct ffs_function *func = priv; 254900a2430fSAndrzej Pietrasiewicz unsigned idx; 255000a2430fSAndrzej Pietrasiewicz u8 newValue; 255100a2430fSAndrzej Pietrasiewicz 255200a2430fSAndrzej Pietrasiewicz switch (type) { 255300a2430fSAndrzej Pietrasiewicz default: 255400a2430fSAndrzej Pietrasiewicz case FFS_DESCRIPTOR: 255500a2430fSAndrzej Pietrasiewicz /* Handled in previous pass by __ffs_func_bind_do_descs() */ 255600a2430fSAndrzej Pietrasiewicz return 0; 255700a2430fSAndrzej Pietrasiewicz 255800a2430fSAndrzej Pietrasiewicz case FFS_INTERFACE: 255900a2430fSAndrzej Pietrasiewicz idx = *valuep; 256000a2430fSAndrzej Pietrasiewicz if (func->interfaces_nums[idx] < 0) { 256100a2430fSAndrzej Pietrasiewicz int id = usb_interface_id(func->conf, &func->function); 256200a2430fSAndrzej Pietrasiewicz if (unlikely(id < 0)) 256300a2430fSAndrzej Pietrasiewicz return id; 256400a2430fSAndrzej Pietrasiewicz func->interfaces_nums[idx] = id; 256500a2430fSAndrzej Pietrasiewicz } 256600a2430fSAndrzej Pietrasiewicz newValue = func->interfaces_nums[idx]; 256700a2430fSAndrzej Pietrasiewicz break; 256800a2430fSAndrzej Pietrasiewicz 256900a2430fSAndrzej Pietrasiewicz case FFS_STRING: 257000a2430fSAndrzej Pietrasiewicz /* String' IDs are allocated when fsf_data is bound to cdev */ 257100a2430fSAndrzej Pietrasiewicz newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id; 257200a2430fSAndrzej Pietrasiewicz break; 257300a2430fSAndrzej Pietrasiewicz 257400a2430fSAndrzej Pietrasiewicz case FFS_ENDPOINT: 257500a2430fSAndrzej Pietrasiewicz /* 257600a2430fSAndrzej Pietrasiewicz * USB_DT_ENDPOINT are handled in 257700a2430fSAndrzej Pietrasiewicz * __ffs_func_bind_do_descs(). 257800a2430fSAndrzej Pietrasiewicz */ 257900a2430fSAndrzej Pietrasiewicz if (desc->bDescriptorType == USB_DT_ENDPOINT) 258000a2430fSAndrzej Pietrasiewicz return 0; 258100a2430fSAndrzej Pietrasiewicz 258200a2430fSAndrzej Pietrasiewicz idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1; 258300a2430fSAndrzej Pietrasiewicz if (unlikely(!func->eps[idx].ep)) 258400a2430fSAndrzej Pietrasiewicz return -EINVAL; 258500a2430fSAndrzej Pietrasiewicz 258600a2430fSAndrzej Pietrasiewicz { 258700a2430fSAndrzej Pietrasiewicz struct usb_endpoint_descriptor **descs; 258800a2430fSAndrzej Pietrasiewicz descs = func->eps[idx].descs; 258900a2430fSAndrzej Pietrasiewicz newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress; 259000a2430fSAndrzej Pietrasiewicz } 259100a2430fSAndrzej Pietrasiewicz break; 259200a2430fSAndrzej Pietrasiewicz } 259300a2430fSAndrzej Pietrasiewicz 259400a2430fSAndrzej Pietrasiewicz pr_vdebug("%02x -> %02x\n", *valuep, newValue); 259500a2430fSAndrzej Pietrasiewicz *valuep = newValue; 259600a2430fSAndrzej Pietrasiewicz return 0; 259700a2430fSAndrzej Pietrasiewicz } 259800a2430fSAndrzej Pietrasiewicz 259900a2430fSAndrzej Pietrasiewicz static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type, 260000a2430fSAndrzej Pietrasiewicz struct usb_os_desc_header *h, void *data, 260100a2430fSAndrzej Pietrasiewicz unsigned len, void *priv) 260200a2430fSAndrzej Pietrasiewicz { 260300a2430fSAndrzej Pietrasiewicz struct ffs_function *func = priv; 260400a2430fSAndrzej Pietrasiewicz u8 length = 0; 260500a2430fSAndrzej Pietrasiewicz 260600a2430fSAndrzej Pietrasiewicz switch (type) { 260700a2430fSAndrzej Pietrasiewicz case FFS_OS_DESC_EXT_COMPAT: { 260800a2430fSAndrzej Pietrasiewicz struct usb_ext_compat_desc *desc = data; 260900a2430fSAndrzej Pietrasiewicz struct usb_os_desc_table *t; 261000a2430fSAndrzej Pietrasiewicz 261100a2430fSAndrzej Pietrasiewicz t = &func->function.os_desc_table[desc->bFirstInterfaceNumber]; 261200a2430fSAndrzej Pietrasiewicz t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber]; 261300a2430fSAndrzej Pietrasiewicz memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID, 261400a2430fSAndrzej Pietrasiewicz ARRAY_SIZE(desc->CompatibleID) + 261500a2430fSAndrzej Pietrasiewicz ARRAY_SIZE(desc->SubCompatibleID)); 261600a2430fSAndrzej Pietrasiewicz length = sizeof(*desc); 261700a2430fSAndrzej Pietrasiewicz } 261800a2430fSAndrzej Pietrasiewicz break; 261900a2430fSAndrzej Pietrasiewicz case FFS_OS_DESC_EXT_PROP: { 262000a2430fSAndrzej Pietrasiewicz struct usb_ext_prop_desc *desc = data; 262100a2430fSAndrzej Pietrasiewicz struct usb_os_desc_table *t; 262200a2430fSAndrzej Pietrasiewicz struct usb_os_desc_ext_prop *ext_prop; 262300a2430fSAndrzej Pietrasiewicz char *ext_prop_name; 262400a2430fSAndrzej Pietrasiewicz char *ext_prop_data; 262500a2430fSAndrzej Pietrasiewicz 262600a2430fSAndrzej Pietrasiewicz t = &func->function.os_desc_table[h->interface]; 262700a2430fSAndrzej Pietrasiewicz t->if_id = func->interfaces_nums[h->interface]; 262800a2430fSAndrzej Pietrasiewicz 262900a2430fSAndrzej Pietrasiewicz ext_prop = func->ffs->ms_os_descs_ext_prop_avail; 263000a2430fSAndrzej Pietrasiewicz func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop); 263100a2430fSAndrzej Pietrasiewicz 263200a2430fSAndrzej Pietrasiewicz ext_prop->type = le32_to_cpu(desc->dwPropertyDataType); 263300a2430fSAndrzej Pietrasiewicz ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength); 263400a2430fSAndrzej Pietrasiewicz ext_prop->data_len = le32_to_cpu(*(u32 *) 263500a2430fSAndrzej Pietrasiewicz usb_ext_prop_data_len_ptr(data, ext_prop->name_len)); 263600a2430fSAndrzej Pietrasiewicz length = ext_prop->name_len + ext_prop->data_len + 14; 263700a2430fSAndrzej Pietrasiewicz 263800a2430fSAndrzej Pietrasiewicz ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail; 263900a2430fSAndrzej Pietrasiewicz func->ffs->ms_os_descs_ext_prop_name_avail += 264000a2430fSAndrzej Pietrasiewicz ext_prop->name_len; 264100a2430fSAndrzej Pietrasiewicz 264200a2430fSAndrzej Pietrasiewicz ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail; 264300a2430fSAndrzej Pietrasiewicz func->ffs->ms_os_descs_ext_prop_data_avail += 264400a2430fSAndrzej Pietrasiewicz ext_prop->data_len; 264500a2430fSAndrzej Pietrasiewicz memcpy(ext_prop_data, 264600a2430fSAndrzej Pietrasiewicz usb_ext_prop_data_ptr(data, ext_prop->name_len), 264700a2430fSAndrzej Pietrasiewicz ext_prop->data_len); 264800a2430fSAndrzej Pietrasiewicz /* unicode data reported to the host as "WCHAR"s */ 264900a2430fSAndrzej Pietrasiewicz switch (ext_prop->type) { 265000a2430fSAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE: 265100a2430fSAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE_ENV: 265200a2430fSAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE_LINK: 265300a2430fSAndrzej Pietrasiewicz case USB_EXT_PROP_UNICODE_MULTI: 265400a2430fSAndrzej Pietrasiewicz ext_prop->data_len *= 2; 265500a2430fSAndrzej Pietrasiewicz break; 265600a2430fSAndrzej Pietrasiewicz } 265700a2430fSAndrzej Pietrasiewicz ext_prop->data = ext_prop_data; 265800a2430fSAndrzej Pietrasiewicz 265900a2430fSAndrzej Pietrasiewicz memcpy(ext_prop_name, usb_ext_prop_name_ptr(data), 266000a2430fSAndrzej Pietrasiewicz ext_prop->name_len); 266100a2430fSAndrzej Pietrasiewicz /* property name reported to the host as "WCHAR"s */ 266200a2430fSAndrzej Pietrasiewicz ext_prop->name_len *= 2; 266300a2430fSAndrzej Pietrasiewicz ext_prop->name = ext_prop_name; 266400a2430fSAndrzej Pietrasiewicz 266500a2430fSAndrzej Pietrasiewicz t->os_desc->ext_prop_len += 266600a2430fSAndrzej Pietrasiewicz ext_prop->name_len + ext_prop->data_len + 14; 266700a2430fSAndrzej Pietrasiewicz ++t->os_desc->ext_prop_count; 266800a2430fSAndrzej Pietrasiewicz list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop); 266900a2430fSAndrzej Pietrasiewicz } 267000a2430fSAndrzej Pietrasiewicz break; 267100a2430fSAndrzej Pietrasiewicz default: 267200a2430fSAndrzej Pietrasiewicz pr_vdebug("unknown descriptor: %d\n", type); 267300a2430fSAndrzej Pietrasiewicz } 267400a2430fSAndrzej Pietrasiewicz 267500a2430fSAndrzej Pietrasiewicz return length; 267600a2430fSAndrzej Pietrasiewicz } 267700a2430fSAndrzej Pietrasiewicz 267800a2430fSAndrzej Pietrasiewicz static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, 267900a2430fSAndrzej Pietrasiewicz struct usb_configuration *c) 268000a2430fSAndrzej Pietrasiewicz { 268100a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 268200a2430fSAndrzej Pietrasiewicz struct f_fs_opts *ffs_opts = 268300a2430fSAndrzej Pietrasiewicz container_of(f->fi, struct f_fs_opts, func_inst); 268400a2430fSAndrzej Pietrasiewicz int ret; 268500a2430fSAndrzej Pietrasiewicz 268600a2430fSAndrzej Pietrasiewicz ENTER(); 268700a2430fSAndrzej Pietrasiewicz 268800a2430fSAndrzej Pietrasiewicz /* 268900a2430fSAndrzej Pietrasiewicz * Legacy gadget triggers binding in functionfs_ready_callback, 269000a2430fSAndrzej Pietrasiewicz * which already uses locking; taking the same lock here would 269100a2430fSAndrzej Pietrasiewicz * cause a deadlock. 269200a2430fSAndrzej Pietrasiewicz * 269300a2430fSAndrzej Pietrasiewicz * Configfs-enabled gadgets however do need ffs_dev_lock. 269400a2430fSAndrzej Pietrasiewicz */ 269500a2430fSAndrzej Pietrasiewicz if (!ffs_opts->no_configfs) 269600a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 269700a2430fSAndrzej Pietrasiewicz ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV; 269800a2430fSAndrzej Pietrasiewicz func->ffs = ffs_opts->dev->ffs_data; 269900a2430fSAndrzej Pietrasiewicz if (!ffs_opts->no_configfs) 270000a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 270100a2430fSAndrzej Pietrasiewicz if (ret) 270200a2430fSAndrzej Pietrasiewicz return ERR_PTR(ret); 270300a2430fSAndrzej Pietrasiewicz 270400a2430fSAndrzej Pietrasiewicz func->conf = c; 270500a2430fSAndrzej Pietrasiewicz func->gadget = c->cdev->gadget; 270600a2430fSAndrzej Pietrasiewicz 270700a2430fSAndrzej Pietrasiewicz /* 270800a2430fSAndrzej Pietrasiewicz * in drivers/usb/gadget/configfs.c:configfs_composite_bind() 270900a2430fSAndrzej Pietrasiewicz * configurations are bound in sequence with list_for_each_entry, 271000a2430fSAndrzej Pietrasiewicz * in each configuration its functions are bound in sequence 271100a2430fSAndrzej Pietrasiewicz * with list_for_each_entry, so we assume no race condition 271200a2430fSAndrzej Pietrasiewicz * with regard to ffs_opts->bound access 271300a2430fSAndrzej Pietrasiewicz */ 271400a2430fSAndrzej Pietrasiewicz if (!ffs_opts->refcnt) { 271500a2430fSAndrzej Pietrasiewicz ret = functionfs_bind(func->ffs, c->cdev); 271600a2430fSAndrzej Pietrasiewicz if (ret) 271700a2430fSAndrzej Pietrasiewicz return ERR_PTR(ret); 271800a2430fSAndrzej Pietrasiewicz } 271900a2430fSAndrzej Pietrasiewicz ffs_opts->refcnt++; 272000a2430fSAndrzej Pietrasiewicz func->function.strings = func->ffs->stringtabs; 272100a2430fSAndrzej Pietrasiewicz 272200a2430fSAndrzej Pietrasiewicz return ffs_opts; 272300a2430fSAndrzej Pietrasiewicz } 272400a2430fSAndrzej Pietrasiewicz 272500a2430fSAndrzej Pietrasiewicz static int _ffs_func_bind(struct usb_configuration *c, 272600a2430fSAndrzej Pietrasiewicz struct usb_function *f) 272700a2430fSAndrzej Pietrasiewicz { 272800a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 272900a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 273000a2430fSAndrzej Pietrasiewicz 273100a2430fSAndrzej Pietrasiewicz const int full = !!func->ffs->fs_descs_count; 273200a2430fSAndrzej Pietrasiewicz const int high = gadget_is_dualspeed(func->gadget) && 273300a2430fSAndrzej Pietrasiewicz func->ffs->hs_descs_count; 273400a2430fSAndrzej Pietrasiewicz const int super = gadget_is_superspeed(func->gadget) && 273500a2430fSAndrzej Pietrasiewicz func->ffs->ss_descs_count; 273600a2430fSAndrzej Pietrasiewicz 273700a2430fSAndrzej Pietrasiewicz int fs_len, hs_len, ss_len, ret, i; 273800a2430fSAndrzej Pietrasiewicz 273900a2430fSAndrzej Pietrasiewicz /* Make it a single chunk, less management later on */ 274000a2430fSAndrzej Pietrasiewicz vla_group(d); 274100a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count); 274200a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs, 274300a2430fSAndrzej Pietrasiewicz full ? ffs->fs_descs_count + 1 : 0); 274400a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs, 274500a2430fSAndrzej Pietrasiewicz high ? ffs->hs_descs_count + 1 : 0); 274600a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, 274700a2430fSAndrzej Pietrasiewicz super ? ffs->ss_descs_count + 1 : 0); 274800a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, short, inums, ffs->interfaces_count); 274900a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table, 275000a2430fSAndrzej Pietrasiewicz c->cdev->use_os_string ? ffs->interfaces_count : 0); 275100a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, char[16], ext_compat, 275200a2430fSAndrzej Pietrasiewicz c->cdev->use_os_string ? ffs->interfaces_count : 0); 275300a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_os_desc, os_desc, 275400a2430fSAndrzej Pietrasiewicz c->cdev->use_os_string ? ffs->interfaces_count : 0); 275500a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop, 275600a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_count); 275700a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, char, ext_prop_name, 275800a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_name_len); 275900a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, char, ext_prop_data, 276000a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_data_len); 276100a2430fSAndrzej Pietrasiewicz vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); 276200a2430fSAndrzej Pietrasiewicz char *vlabuf; 276300a2430fSAndrzej Pietrasiewicz 276400a2430fSAndrzej Pietrasiewicz ENTER(); 276500a2430fSAndrzej Pietrasiewicz 276600a2430fSAndrzej Pietrasiewicz /* Has descriptors only for speeds gadget does not support */ 276700a2430fSAndrzej Pietrasiewicz if (unlikely(!(full | high | super))) 276800a2430fSAndrzej Pietrasiewicz return -ENOTSUPP; 276900a2430fSAndrzej Pietrasiewicz 277000a2430fSAndrzej Pietrasiewicz /* Allocate a single chunk, less management later on */ 277100a2430fSAndrzej Pietrasiewicz vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL); 277200a2430fSAndrzej Pietrasiewicz if (unlikely(!vlabuf)) 277300a2430fSAndrzej Pietrasiewicz return -ENOMEM; 277400a2430fSAndrzej Pietrasiewicz 277500a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop); 277600a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_name_avail = 277700a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, ext_prop_name); 277800a2430fSAndrzej Pietrasiewicz ffs->ms_os_descs_ext_prop_data_avail = 277900a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, ext_prop_data); 278000a2430fSAndrzej Pietrasiewicz 278100a2430fSAndrzej Pietrasiewicz /* Copy descriptors */ 278200a2430fSAndrzej Pietrasiewicz memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, 278300a2430fSAndrzej Pietrasiewicz ffs->raw_descs_length); 278400a2430fSAndrzej Pietrasiewicz 278500a2430fSAndrzej Pietrasiewicz memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); 278600a2430fSAndrzej Pietrasiewicz for (ret = ffs->eps_count; ret; --ret) { 278700a2430fSAndrzej Pietrasiewicz struct ffs_ep *ptr; 278800a2430fSAndrzej Pietrasiewicz 278900a2430fSAndrzej Pietrasiewicz ptr = vla_ptr(vlabuf, d, eps); 279000a2430fSAndrzej Pietrasiewicz ptr[ret].num = -1; 279100a2430fSAndrzej Pietrasiewicz } 279200a2430fSAndrzej Pietrasiewicz 279300a2430fSAndrzej Pietrasiewicz /* Save pointers 279400a2430fSAndrzej Pietrasiewicz * d_eps == vlabuf, func->eps used to kfree vlabuf later 279500a2430fSAndrzej Pietrasiewicz */ 279600a2430fSAndrzej Pietrasiewicz func->eps = vla_ptr(vlabuf, d, eps); 279700a2430fSAndrzej Pietrasiewicz func->interfaces_nums = vla_ptr(vlabuf, d, inums); 279800a2430fSAndrzej Pietrasiewicz 279900a2430fSAndrzej Pietrasiewicz /* 280000a2430fSAndrzej Pietrasiewicz * Go through all the endpoint descriptors and allocate 280100a2430fSAndrzej Pietrasiewicz * endpoints first, so that later we can rewrite the endpoint 280200a2430fSAndrzej Pietrasiewicz * numbers without worrying that it may be described later on. 280300a2430fSAndrzej Pietrasiewicz */ 280400a2430fSAndrzej Pietrasiewicz if (likely(full)) { 280500a2430fSAndrzej Pietrasiewicz func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); 280600a2430fSAndrzej Pietrasiewicz fs_len = ffs_do_descs(ffs->fs_descs_count, 280700a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs), 280800a2430fSAndrzej Pietrasiewicz d_raw_descs__sz, 280900a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_descs, func); 281000a2430fSAndrzej Pietrasiewicz if (unlikely(fs_len < 0)) { 281100a2430fSAndrzej Pietrasiewicz ret = fs_len; 281200a2430fSAndrzej Pietrasiewicz goto error; 281300a2430fSAndrzej Pietrasiewicz } 281400a2430fSAndrzej Pietrasiewicz } else { 281500a2430fSAndrzej Pietrasiewicz fs_len = 0; 281600a2430fSAndrzej Pietrasiewicz } 281700a2430fSAndrzej Pietrasiewicz 281800a2430fSAndrzej Pietrasiewicz if (likely(high)) { 281900a2430fSAndrzej Pietrasiewicz func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); 282000a2430fSAndrzej Pietrasiewicz hs_len = ffs_do_descs(ffs->hs_descs_count, 282100a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs) + fs_len, 282200a2430fSAndrzej Pietrasiewicz d_raw_descs__sz - fs_len, 282300a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_descs, func); 282400a2430fSAndrzej Pietrasiewicz if (unlikely(hs_len < 0)) { 282500a2430fSAndrzej Pietrasiewicz ret = hs_len; 282600a2430fSAndrzej Pietrasiewicz goto error; 282700a2430fSAndrzej Pietrasiewicz } 282800a2430fSAndrzej Pietrasiewicz } else { 282900a2430fSAndrzej Pietrasiewicz hs_len = 0; 283000a2430fSAndrzej Pietrasiewicz } 283100a2430fSAndrzej Pietrasiewicz 283200a2430fSAndrzej Pietrasiewicz if (likely(super)) { 283300a2430fSAndrzej Pietrasiewicz func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs); 283400a2430fSAndrzej Pietrasiewicz ss_len = ffs_do_descs(ffs->ss_descs_count, 283500a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, 283600a2430fSAndrzej Pietrasiewicz d_raw_descs__sz - fs_len - hs_len, 283700a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_descs, func); 283800a2430fSAndrzej Pietrasiewicz if (unlikely(ss_len < 0)) { 283900a2430fSAndrzej Pietrasiewicz ret = ss_len; 284000a2430fSAndrzej Pietrasiewicz goto error; 284100a2430fSAndrzej Pietrasiewicz } 284200a2430fSAndrzej Pietrasiewicz } else { 284300a2430fSAndrzej Pietrasiewicz ss_len = 0; 284400a2430fSAndrzej Pietrasiewicz } 284500a2430fSAndrzej Pietrasiewicz 284600a2430fSAndrzej Pietrasiewicz /* 284700a2430fSAndrzej Pietrasiewicz * Now handle interface numbers allocation and interface and 284800a2430fSAndrzej Pietrasiewicz * endpoint numbers rewriting. We can do that in one go 284900a2430fSAndrzej Pietrasiewicz * now. 285000a2430fSAndrzej Pietrasiewicz */ 285100a2430fSAndrzej Pietrasiewicz ret = ffs_do_descs(ffs->fs_descs_count + 285200a2430fSAndrzej Pietrasiewicz (high ? ffs->hs_descs_count : 0) + 285300a2430fSAndrzej Pietrasiewicz (super ? ffs->ss_descs_count : 0), 285400a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz, 285500a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_nums, func); 285600a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 285700a2430fSAndrzej Pietrasiewicz goto error; 285800a2430fSAndrzej Pietrasiewicz 285900a2430fSAndrzej Pietrasiewicz func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table); 286000a2430fSAndrzej Pietrasiewicz if (c->cdev->use_os_string) 286100a2430fSAndrzej Pietrasiewicz for (i = 0; i < ffs->interfaces_count; ++i) { 286200a2430fSAndrzej Pietrasiewicz struct usb_os_desc *desc; 286300a2430fSAndrzej Pietrasiewicz 286400a2430fSAndrzej Pietrasiewicz desc = func->function.os_desc_table[i].os_desc = 286500a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, os_desc) + 286600a2430fSAndrzej Pietrasiewicz i * sizeof(struct usb_os_desc); 286700a2430fSAndrzej Pietrasiewicz desc->ext_compat_id = 286800a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, ext_compat) + i * 16; 286900a2430fSAndrzej Pietrasiewicz INIT_LIST_HEAD(&desc->ext_prop); 287000a2430fSAndrzej Pietrasiewicz } 287100a2430fSAndrzej Pietrasiewicz ret = ffs_do_os_descs(ffs->ms_os_descs_count, 287200a2430fSAndrzej Pietrasiewicz vla_ptr(vlabuf, d, raw_descs) + 287300a2430fSAndrzej Pietrasiewicz fs_len + hs_len + ss_len, 287400a2430fSAndrzej Pietrasiewicz d_raw_descs__sz - fs_len - hs_len - ss_len, 287500a2430fSAndrzej Pietrasiewicz __ffs_func_bind_do_os_desc, func); 287600a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 287700a2430fSAndrzej Pietrasiewicz goto error; 287800a2430fSAndrzej Pietrasiewicz func->function.os_desc_n = 287900a2430fSAndrzej Pietrasiewicz c->cdev->use_os_string ? ffs->interfaces_count : 0; 288000a2430fSAndrzej Pietrasiewicz 288100a2430fSAndrzej Pietrasiewicz /* And we're done */ 288200a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs, FUNCTIONFS_BIND); 288300a2430fSAndrzej Pietrasiewicz return 0; 288400a2430fSAndrzej Pietrasiewicz 288500a2430fSAndrzej Pietrasiewicz error: 288600a2430fSAndrzej Pietrasiewicz /* XXX Do we need to release all claimed endpoints here? */ 288700a2430fSAndrzej Pietrasiewicz return ret; 288800a2430fSAndrzej Pietrasiewicz } 288900a2430fSAndrzej Pietrasiewicz 289000a2430fSAndrzej Pietrasiewicz static int ffs_func_bind(struct usb_configuration *c, 289100a2430fSAndrzej Pietrasiewicz struct usb_function *f) 289200a2430fSAndrzej Pietrasiewicz { 289300a2430fSAndrzej Pietrasiewicz struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); 289455d81121SRobert Baldyga struct ffs_function *func = ffs_func_from_usb(f); 289555d81121SRobert Baldyga int ret; 289600a2430fSAndrzej Pietrasiewicz 289700a2430fSAndrzej Pietrasiewicz if (IS_ERR(ffs_opts)) 289800a2430fSAndrzej Pietrasiewicz return PTR_ERR(ffs_opts); 289900a2430fSAndrzej Pietrasiewicz 290055d81121SRobert Baldyga ret = _ffs_func_bind(c, f); 290155d81121SRobert Baldyga if (ret && !--ffs_opts->refcnt) 290255d81121SRobert Baldyga functionfs_unbind(func->ffs); 290355d81121SRobert Baldyga 290455d81121SRobert Baldyga return ret; 290500a2430fSAndrzej Pietrasiewicz } 290600a2430fSAndrzej Pietrasiewicz 290700a2430fSAndrzej Pietrasiewicz 290800a2430fSAndrzej Pietrasiewicz /* Other USB function hooks *************************************************/ 290900a2430fSAndrzej Pietrasiewicz 291018d6b32fSRobert Baldyga static void ffs_reset_work(struct work_struct *work) 291118d6b32fSRobert Baldyga { 291218d6b32fSRobert Baldyga struct ffs_data *ffs = container_of(work, 291318d6b32fSRobert Baldyga struct ffs_data, reset_work); 291418d6b32fSRobert Baldyga ffs_data_reset(ffs); 291518d6b32fSRobert Baldyga } 291618d6b32fSRobert Baldyga 291700a2430fSAndrzej Pietrasiewicz static int ffs_func_set_alt(struct usb_function *f, 291800a2430fSAndrzej Pietrasiewicz unsigned interface, unsigned alt) 291900a2430fSAndrzej Pietrasiewicz { 292000a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 292100a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 292200a2430fSAndrzej Pietrasiewicz int ret = 0, intf; 292300a2430fSAndrzej Pietrasiewicz 292400a2430fSAndrzej Pietrasiewicz if (alt != (unsigned)-1) { 292500a2430fSAndrzej Pietrasiewicz intf = ffs_func_revmap_intf(func, interface); 292600a2430fSAndrzej Pietrasiewicz if (unlikely(intf < 0)) 292700a2430fSAndrzej Pietrasiewicz return intf; 292800a2430fSAndrzej Pietrasiewicz } 292900a2430fSAndrzej Pietrasiewicz 293000a2430fSAndrzej Pietrasiewicz if (ffs->func) 293100a2430fSAndrzej Pietrasiewicz ffs_func_eps_disable(ffs->func); 293200a2430fSAndrzej Pietrasiewicz 293318d6b32fSRobert Baldyga if (ffs->state == FFS_DEACTIVATED) { 293418d6b32fSRobert Baldyga ffs->state = FFS_CLOSING; 293518d6b32fSRobert Baldyga INIT_WORK(&ffs->reset_work, ffs_reset_work); 293618d6b32fSRobert Baldyga schedule_work(&ffs->reset_work); 293718d6b32fSRobert Baldyga return -ENODEV; 293818d6b32fSRobert Baldyga } 293918d6b32fSRobert Baldyga 294000a2430fSAndrzej Pietrasiewicz if (ffs->state != FFS_ACTIVE) 294100a2430fSAndrzej Pietrasiewicz return -ENODEV; 294200a2430fSAndrzej Pietrasiewicz 294300a2430fSAndrzej Pietrasiewicz if (alt == (unsigned)-1) { 294400a2430fSAndrzej Pietrasiewicz ffs->func = NULL; 294500a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs, FUNCTIONFS_DISABLE); 294600a2430fSAndrzej Pietrasiewicz return 0; 294700a2430fSAndrzej Pietrasiewicz } 294800a2430fSAndrzej Pietrasiewicz 294900a2430fSAndrzej Pietrasiewicz ffs->func = func; 295000a2430fSAndrzej Pietrasiewicz ret = ffs_func_eps_enable(func); 295100a2430fSAndrzej Pietrasiewicz if (likely(ret >= 0)) 295200a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs, FUNCTIONFS_ENABLE); 295300a2430fSAndrzej Pietrasiewicz return ret; 295400a2430fSAndrzej Pietrasiewicz } 295500a2430fSAndrzej Pietrasiewicz 295600a2430fSAndrzej Pietrasiewicz static void ffs_func_disable(struct usb_function *f) 295700a2430fSAndrzej Pietrasiewicz { 295800a2430fSAndrzej Pietrasiewicz ffs_func_set_alt(f, 0, (unsigned)-1); 295900a2430fSAndrzej Pietrasiewicz } 296000a2430fSAndrzej Pietrasiewicz 296100a2430fSAndrzej Pietrasiewicz static int ffs_func_setup(struct usb_function *f, 296200a2430fSAndrzej Pietrasiewicz const struct usb_ctrlrequest *creq) 296300a2430fSAndrzej Pietrasiewicz { 296400a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 296500a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 296600a2430fSAndrzej Pietrasiewicz unsigned long flags; 296700a2430fSAndrzej Pietrasiewicz int ret; 296800a2430fSAndrzej Pietrasiewicz 296900a2430fSAndrzej Pietrasiewicz ENTER(); 297000a2430fSAndrzej Pietrasiewicz 297100a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); 297200a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); 297300a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); 297400a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex)); 297500a2430fSAndrzej Pietrasiewicz pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength)); 297600a2430fSAndrzej Pietrasiewicz 297700a2430fSAndrzej Pietrasiewicz /* 297800a2430fSAndrzej Pietrasiewicz * Most requests directed to interface go through here 297900a2430fSAndrzej Pietrasiewicz * (notable exceptions are set/get interface) so we need to 298000a2430fSAndrzej Pietrasiewicz * handle them. All other either handled by composite or 298100a2430fSAndrzej Pietrasiewicz * passed to usb_configuration->setup() (if one is set). No 298200a2430fSAndrzej Pietrasiewicz * matter, we will handle requests directed to endpoint here 298300a2430fSAndrzej Pietrasiewicz * as well (as it's straightforward) but what to do with any 298400a2430fSAndrzej Pietrasiewicz * other request? 298500a2430fSAndrzej Pietrasiewicz */ 298600a2430fSAndrzej Pietrasiewicz if (ffs->state != FFS_ACTIVE) 298700a2430fSAndrzej Pietrasiewicz return -ENODEV; 298800a2430fSAndrzej Pietrasiewicz 298900a2430fSAndrzej Pietrasiewicz switch (creq->bRequestType & USB_RECIP_MASK) { 299000a2430fSAndrzej Pietrasiewicz case USB_RECIP_INTERFACE: 299100a2430fSAndrzej Pietrasiewicz ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex)); 299200a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 299300a2430fSAndrzej Pietrasiewicz return ret; 299400a2430fSAndrzej Pietrasiewicz break; 299500a2430fSAndrzej Pietrasiewicz 299600a2430fSAndrzej Pietrasiewicz case USB_RECIP_ENDPOINT: 299700a2430fSAndrzej Pietrasiewicz ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex)); 299800a2430fSAndrzej Pietrasiewicz if (unlikely(ret < 0)) 299900a2430fSAndrzej Pietrasiewicz return ret; 30001b0bf88fSRobert Baldyga if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) 30011b0bf88fSRobert Baldyga ret = func->ffs->eps_addrmap[ret]; 300200a2430fSAndrzej Pietrasiewicz break; 300300a2430fSAndrzej Pietrasiewicz 300400a2430fSAndrzej Pietrasiewicz default: 300500a2430fSAndrzej Pietrasiewicz return -EOPNOTSUPP; 300600a2430fSAndrzej Pietrasiewicz } 300700a2430fSAndrzej Pietrasiewicz 300800a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&ffs->ev.waitq.lock, flags); 300900a2430fSAndrzej Pietrasiewicz ffs->ev.setup = *creq; 301000a2430fSAndrzej Pietrasiewicz ffs->ev.setup.wIndex = cpu_to_le16(ret); 301100a2430fSAndrzej Pietrasiewicz __ffs_event_add(ffs, FUNCTIONFS_SETUP); 301200a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); 301300a2430fSAndrzej Pietrasiewicz 301400a2430fSAndrzej Pietrasiewicz return 0; 301500a2430fSAndrzej Pietrasiewicz } 301600a2430fSAndrzej Pietrasiewicz 301700a2430fSAndrzej Pietrasiewicz static void ffs_func_suspend(struct usb_function *f) 301800a2430fSAndrzej Pietrasiewicz { 301900a2430fSAndrzej Pietrasiewicz ENTER(); 302000a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); 302100a2430fSAndrzej Pietrasiewicz } 302200a2430fSAndrzej Pietrasiewicz 302300a2430fSAndrzej Pietrasiewicz static void ffs_func_resume(struct usb_function *f) 302400a2430fSAndrzej Pietrasiewicz { 302500a2430fSAndrzej Pietrasiewicz ENTER(); 302600a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); 302700a2430fSAndrzej Pietrasiewicz } 302800a2430fSAndrzej Pietrasiewicz 302900a2430fSAndrzej Pietrasiewicz 303000a2430fSAndrzej Pietrasiewicz /* Endpoint and interface numbers reverse mapping ***************************/ 303100a2430fSAndrzej Pietrasiewicz 303200a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_ep(struct ffs_function *func, u8 num) 303300a2430fSAndrzej Pietrasiewicz { 303400a2430fSAndrzej Pietrasiewicz num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK]; 303500a2430fSAndrzej Pietrasiewicz return num ? num : -EDOM; 303600a2430fSAndrzej Pietrasiewicz } 303700a2430fSAndrzej Pietrasiewicz 303800a2430fSAndrzej Pietrasiewicz static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf) 303900a2430fSAndrzej Pietrasiewicz { 304000a2430fSAndrzej Pietrasiewicz short *nums = func->interfaces_nums; 304100a2430fSAndrzej Pietrasiewicz unsigned count = func->ffs->interfaces_count; 304200a2430fSAndrzej Pietrasiewicz 304300a2430fSAndrzej Pietrasiewicz for (; count; --count, ++nums) { 304400a2430fSAndrzej Pietrasiewicz if (*nums >= 0 && *nums == intf) 304500a2430fSAndrzej Pietrasiewicz return nums - func->interfaces_nums; 304600a2430fSAndrzej Pietrasiewicz } 304700a2430fSAndrzej Pietrasiewicz 304800a2430fSAndrzej Pietrasiewicz return -EDOM; 304900a2430fSAndrzej Pietrasiewicz } 305000a2430fSAndrzej Pietrasiewicz 305100a2430fSAndrzej Pietrasiewicz 305200a2430fSAndrzej Pietrasiewicz /* Devices management *******************************************************/ 305300a2430fSAndrzej Pietrasiewicz 305400a2430fSAndrzej Pietrasiewicz static LIST_HEAD(ffs_devices); 305500a2430fSAndrzej Pietrasiewicz 305600a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_do_find_dev(const char *name) 305700a2430fSAndrzej Pietrasiewicz { 305800a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 305900a2430fSAndrzej Pietrasiewicz 306000a2430fSAndrzej Pietrasiewicz list_for_each_entry(dev, &ffs_devices, entry) { 306100a2430fSAndrzej Pietrasiewicz if (!dev->name || !name) 306200a2430fSAndrzej Pietrasiewicz continue; 306300a2430fSAndrzej Pietrasiewicz if (strcmp(dev->name, name) == 0) 306400a2430fSAndrzej Pietrasiewicz return dev; 306500a2430fSAndrzej Pietrasiewicz } 306600a2430fSAndrzej Pietrasiewicz 306700a2430fSAndrzej Pietrasiewicz return NULL; 306800a2430fSAndrzej Pietrasiewicz } 306900a2430fSAndrzej Pietrasiewicz 307000a2430fSAndrzej Pietrasiewicz /* 307100a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 307200a2430fSAndrzej Pietrasiewicz */ 307300a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_get_single_dev(void) 307400a2430fSAndrzej Pietrasiewicz { 307500a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 307600a2430fSAndrzej Pietrasiewicz 307700a2430fSAndrzej Pietrasiewicz if (list_is_singular(&ffs_devices)) { 307800a2430fSAndrzej Pietrasiewicz dev = list_first_entry(&ffs_devices, struct ffs_dev, entry); 307900a2430fSAndrzej Pietrasiewicz if (dev->single) 308000a2430fSAndrzej Pietrasiewicz return dev; 308100a2430fSAndrzej Pietrasiewicz } 308200a2430fSAndrzej Pietrasiewicz 308300a2430fSAndrzej Pietrasiewicz return NULL; 308400a2430fSAndrzej Pietrasiewicz } 308500a2430fSAndrzej Pietrasiewicz 308600a2430fSAndrzej Pietrasiewicz /* 308700a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 308800a2430fSAndrzej Pietrasiewicz */ 308900a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_find_dev(const char *name) 309000a2430fSAndrzej Pietrasiewicz { 309100a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 309200a2430fSAndrzej Pietrasiewicz 309300a2430fSAndrzej Pietrasiewicz dev = _ffs_get_single_dev(); 309400a2430fSAndrzej Pietrasiewicz if (dev) 309500a2430fSAndrzej Pietrasiewicz return dev; 309600a2430fSAndrzej Pietrasiewicz 309700a2430fSAndrzej Pietrasiewicz return _ffs_do_find_dev(name); 309800a2430fSAndrzej Pietrasiewicz } 309900a2430fSAndrzej Pietrasiewicz 310000a2430fSAndrzej Pietrasiewicz /* Configfs support *********************************************************/ 310100a2430fSAndrzej Pietrasiewicz 310200a2430fSAndrzej Pietrasiewicz static inline struct f_fs_opts *to_ffs_opts(struct config_item *item) 310300a2430fSAndrzej Pietrasiewicz { 310400a2430fSAndrzej Pietrasiewicz return container_of(to_config_group(item), struct f_fs_opts, 310500a2430fSAndrzej Pietrasiewicz func_inst.group); 310600a2430fSAndrzej Pietrasiewicz } 310700a2430fSAndrzej Pietrasiewicz 310800a2430fSAndrzej Pietrasiewicz static void ffs_attr_release(struct config_item *item) 310900a2430fSAndrzej Pietrasiewicz { 311000a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts = to_ffs_opts(item); 311100a2430fSAndrzej Pietrasiewicz 311200a2430fSAndrzej Pietrasiewicz usb_put_function_instance(&opts->func_inst); 311300a2430fSAndrzej Pietrasiewicz } 311400a2430fSAndrzej Pietrasiewicz 311500a2430fSAndrzej Pietrasiewicz static struct configfs_item_operations ffs_item_ops = { 311600a2430fSAndrzej Pietrasiewicz .release = ffs_attr_release, 311700a2430fSAndrzej Pietrasiewicz }; 311800a2430fSAndrzej Pietrasiewicz 311900a2430fSAndrzej Pietrasiewicz static struct config_item_type ffs_func_type = { 312000a2430fSAndrzej Pietrasiewicz .ct_item_ops = &ffs_item_ops, 312100a2430fSAndrzej Pietrasiewicz .ct_owner = THIS_MODULE, 312200a2430fSAndrzej Pietrasiewicz }; 312300a2430fSAndrzej Pietrasiewicz 312400a2430fSAndrzej Pietrasiewicz 312500a2430fSAndrzej Pietrasiewicz /* Function registration interface ******************************************/ 312600a2430fSAndrzej Pietrasiewicz 312700a2430fSAndrzej Pietrasiewicz static void ffs_free_inst(struct usb_function_instance *f) 312800a2430fSAndrzej Pietrasiewicz { 312900a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts; 313000a2430fSAndrzej Pietrasiewicz 313100a2430fSAndrzej Pietrasiewicz opts = to_f_fs_opts(f); 313200a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 313300a2430fSAndrzej Pietrasiewicz _ffs_free_dev(opts->dev); 313400a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 313500a2430fSAndrzej Pietrasiewicz kfree(opts); 313600a2430fSAndrzej Pietrasiewicz } 313700a2430fSAndrzej Pietrasiewicz 313800a2430fSAndrzej Pietrasiewicz #define MAX_INST_NAME_LEN 40 313900a2430fSAndrzej Pietrasiewicz 314000a2430fSAndrzej Pietrasiewicz static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) 314100a2430fSAndrzej Pietrasiewicz { 314200a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts; 314300a2430fSAndrzej Pietrasiewicz char *ptr; 314400a2430fSAndrzej Pietrasiewicz const char *tmp; 314500a2430fSAndrzej Pietrasiewicz int name_len, ret; 314600a2430fSAndrzej Pietrasiewicz 314700a2430fSAndrzej Pietrasiewicz name_len = strlen(name) + 1; 314800a2430fSAndrzej Pietrasiewicz if (name_len > MAX_INST_NAME_LEN) 314900a2430fSAndrzej Pietrasiewicz return -ENAMETOOLONG; 315000a2430fSAndrzej Pietrasiewicz 315100a2430fSAndrzej Pietrasiewicz ptr = kstrndup(name, name_len, GFP_KERNEL); 315200a2430fSAndrzej Pietrasiewicz if (!ptr) 315300a2430fSAndrzej Pietrasiewicz return -ENOMEM; 315400a2430fSAndrzej Pietrasiewicz 315500a2430fSAndrzej Pietrasiewicz opts = to_f_fs_opts(fi); 315600a2430fSAndrzej Pietrasiewicz tmp = NULL; 315700a2430fSAndrzej Pietrasiewicz 315800a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 315900a2430fSAndrzej Pietrasiewicz 316000a2430fSAndrzej Pietrasiewicz tmp = opts->dev->name_allocated ? opts->dev->name : NULL; 316100a2430fSAndrzej Pietrasiewicz ret = _ffs_name_dev(opts->dev, ptr); 316200a2430fSAndrzej Pietrasiewicz if (ret) { 316300a2430fSAndrzej Pietrasiewicz kfree(ptr); 316400a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 316500a2430fSAndrzej Pietrasiewicz return ret; 316600a2430fSAndrzej Pietrasiewicz } 316700a2430fSAndrzej Pietrasiewicz opts->dev->name_allocated = true; 316800a2430fSAndrzej Pietrasiewicz 316900a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 317000a2430fSAndrzej Pietrasiewicz 317100a2430fSAndrzej Pietrasiewicz kfree(tmp); 317200a2430fSAndrzej Pietrasiewicz 317300a2430fSAndrzej Pietrasiewicz return 0; 317400a2430fSAndrzej Pietrasiewicz } 317500a2430fSAndrzej Pietrasiewicz 317600a2430fSAndrzej Pietrasiewicz static struct usb_function_instance *ffs_alloc_inst(void) 317700a2430fSAndrzej Pietrasiewicz { 317800a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts; 317900a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 318000a2430fSAndrzej Pietrasiewicz 318100a2430fSAndrzej Pietrasiewicz opts = kzalloc(sizeof(*opts), GFP_KERNEL); 318200a2430fSAndrzej Pietrasiewicz if (!opts) 318300a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 318400a2430fSAndrzej Pietrasiewicz 318500a2430fSAndrzej Pietrasiewicz opts->func_inst.set_inst_name = ffs_set_inst_name; 318600a2430fSAndrzej Pietrasiewicz opts->func_inst.free_func_inst = ffs_free_inst; 318700a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 318800a2430fSAndrzej Pietrasiewicz dev = _ffs_alloc_dev(); 318900a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 319000a2430fSAndrzej Pietrasiewicz if (IS_ERR(dev)) { 319100a2430fSAndrzej Pietrasiewicz kfree(opts); 319200a2430fSAndrzej Pietrasiewicz return ERR_CAST(dev); 319300a2430fSAndrzej Pietrasiewicz } 319400a2430fSAndrzej Pietrasiewicz opts->dev = dev; 319500a2430fSAndrzej Pietrasiewicz dev->opts = opts; 319600a2430fSAndrzej Pietrasiewicz 319700a2430fSAndrzej Pietrasiewicz config_group_init_type_name(&opts->func_inst.group, "", 319800a2430fSAndrzej Pietrasiewicz &ffs_func_type); 319900a2430fSAndrzej Pietrasiewicz return &opts->func_inst; 320000a2430fSAndrzej Pietrasiewicz } 320100a2430fSAndrzej Pietrasiewicz 320200a2430fSAndrzej Pietrasiewicz static void ffs_free(struct usb_function *f) 320300a2430fSAndrzej Pietrasiewicz { 320400a2430fSAndrzej Pietrasiewicz kfree(ffs_func_from_usb(f)); 320500a2430fSAndrzej Pietrasiewicz } 320600a2430fSAndrzej Pietrasiewicz 320700a2430fSAndrzej Pietrasiewicz static void ffs_func_unbind(struct usb_configuration *c, 320800a2430fSAndrzej Pietrasiewicz struct usb_function *f) 320900a2430fSAndrzej Pietrasiewicz { 321000a2430fSAndrzej Pietrasiewicz struct ffs_function *func = ffs_func_from_usb(f); 321100a2430fSAndrzej Pietrasiewicz struct ffs_data *ffs = func->ffs; 321200a2430fSAndrzej Pietrasiewicz struct f_fs_opts *opts = 321300a2430fSAndrzej Pietrasiewicz container_of(f->fi, struct f_fs_opts, func_inst); 321400a2430fSAndrzej Pietrasiewicz struct ffs_ep *ep = func->eps; 321500a2430fSAndrzej Pietrasiewicz unsigned count = ffs->eps_count; 321600a2430fSAndrzej Pietrasiewicz unsigned long flags; 321700a2430fSAndrzej Pietrasiewicz 321800a2430fSAndrzej Pietrasiewicz ENTER(); 321900a2430fSAndrzej Pietrasiewicz if (ffs->func == func) { 322000a2430fSAndrzej Pietrasiewicz ffs_func_eps_disable(func); 322100a2430fSAndrzej Pietrasiewicz ffs->func = NULL; 322200a2430fSAndrzej Pietrasiewicz } 322300a2430fSAndrzej Pietrasiewicz 322400a2430fSAndrzej Pietrasiewicz if (!--opts->refcnt) 322500a2430fSAndrzej Pietrasiewicz functionfs_unbind(ffs); 322600a2430fSAndrzej Pietrasiewicz 322700a2430fSAndrzej Pietrasiewicz /* cleanup after autoconfig */ 322800a2430fSAndrzej Pietrasiewicz spin_lock_irqsave(&func->ffs->eps_lock, flags); 322900a2430fSAndrzej Pietrasiewicz do { 323000a2430fSAndrzej Pietrasiewicz if (ep->ep && ep->req) 323100a2430fSAndrzej Pietrasiewicz usb_ep_free_request(ep->ep, ep->req); 323200a2430fSAndrzej Pietrasiewicz ep->req = NULL; 323300a2430fSAndrzej Pietrasiewicz ++ep; 323400a2430fSAndrzej Pietrasiewicz } while (--count); 323500a2430fSAndrzej Pietrasiewicz spin_unlock_irqrestore(&func->ffs->eps_lock, flags); 323600a2430fSAndrzej Pietrasiewicz kfree(func->eps); 323700a2430fSAndrzej Pietrasiewicz func->eps = NULL; 323800a2430fSAndrzej Pietrasiewicz /* 323900a2430fSAndrzej Pietrasiewicz * eps, descriptors and interfaces_nums are allocated in the 324000a2430fSAndrzej Pietrasiewicz * same chunk so only one free is required. 324100a2430fSAndrzej Pietrasiewicz */ 324200a2430fSAndrzej Pietrasiewicz func->function.fs_descriptors = NULL; 324300a2430fSAndrzej Pietrasiewicz func->function.hs_descriptors = NULL; 324400a2430fSAndrzej Pietrasiewicz func->function.ss_descriptors = NULL; 324500a2430fSAndrzej Pietrasiewicz func->interfaces_nums = NULL; 324600a2430fSAndrzej Pietrasiewicz 324700a2430fSAndrzej Pietrasiewicz ffs_event_add(ffs, FUNCTIONFS_UNBIND); 324800a2430fSAndrzej Pietrasiewicz } 324900a2430fSAndrzej Pietrasiewicz 325000a2430fSAndrzej Pietrasiewicz static struct usb_function *ffs_alloc(struct usb_function_instance *fi) 325100a2430fSAndrzej Pietrasiewicz { 325200a2430fSAndrzej Pietrasiewicz struct ffs_function *func; 325300a2430fSAndrzej Pietrasiewicz 325400a2430fSAndrzej Pietrasiewicz ENTER(); 325500a2430fSAndrzej Pietrasiewicz 325600a2430fSAndrzej Pietrasiewicz func = kzalloc(sizeof(*func), GFP_KERNEL); 325700a2430fSAndrzej Pietrasiewicz if (unlikely(!func)) 325800a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 325900a2430fSAndrzej Pietrasiewicz 326000a2430fSAndrzej Pietrasiewicz func->function.name = "Function FS Gadget"; 326100a2430fSAndrzej Pietrasiewicz 326200a2430fSAndrzej Pietrasiewicz func->function.bind = ffs_func_bind; 326300a2430fSAndrzej Pietrasiewicz func->function.unbind = ffs_func_unbind; 326400a2430fSAndrzej Pietrasiewicz func->function.set_alt = ffs_func_set_alt; 326500a2430fSAndrzej Pietrasiewicz func->function.disable = ffs_func_disable; 326600a2430fSAndrzej Pietrasiewicz func->function.setup = ffs_func_setup; 326700a2430fSAndrzej Pietrasiewicz func->function.suspend = ffs_func_suspend; 326800a2430fSAndrzej Pietrasiewicz func->function.resume = ffs_func_resume; 326900a2430fSAndrzej Pietrasiewicz func->function.free_func = ffs_free; 327000a2430fSAndrzej Pietrasiewicz 327100a2430fSAndrzej Pietrasiewicz return &func->function; 327200a2430fSAndrzej Pietrasiewicz } 327300a2430fSAndrzej Pietrasiewicz 327400a2430fSAndrzej Pietrasiewicz /* 327500a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 327600a2430fSAndrzej Pietrasiewicz */ 327700a2430fSAndrzej Pietrasiewicz static struct ffs_dev *_ffs_alloc_dev(void) 327800a2430fSAndrzej Pietrasiewicz { 327900a2430fSAndrzej Pietrasiewicz struct ffs_dev *dev; 328000a2430fSAndrzej Pietrasiewicz int ret; 328100a2430fSAndrzej Pietrasiewicz 328200a2430fSAndrzej Pietrasiewicz if (_ffs_get_single_dev()) 328300a2430fSAndrzej Pietrasiewicz return ERR_PTR(-EBUSY); 328400a2430fSAndrzej Pietrasiewicz 328500a2430fSAndrzej Pietrasiewicz dev = kzalloc(sizeof(*dev), GFP_KERNEL); 328600a2430fSAndrzej Pietrasiewicz if (!dev) 328700a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 328800a2430fSAndrzej Pietrasiewicz 328900a2430fSAndrzej Pietrasiewicz if (list_empty(&ffs_devices)) { 329000a2430fSAndrzej Pietrasiewicz ret = functionfs_init(); 329100a2430fSAndrzej Pietrasiewicz if (ret) { 329200a2430fSAndrzej Pietrasiewicz kfree(dev); 329300a2430fSAndrzej Pietrasiewicz return ERR_PTR(ret); 329400a2430fSAndrzej Pietrasiewicz } 329500a2430fSAndrzej Pietrasiewicz } 329600a2430fSAndrzej Pietrasiewicz 329700a2430fSAndrzej Pietrasiewicz list_add(&dev->entry, &ffs_devices); 329800a2430fSAndrzej Pietrasiewicz 329900a2430fSAndrzej Pietrasiewicz return dev; 330000a2430fSAndrzej Pietrasiewicz } 330100a2430fSAndrzej Pietrasiewicz 330200a2430fSAndrzej Pietrasiewicz /* 330300a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 330400a2430fSAndrzej Pietrasiewicz * The caller is responsible for "name" being available whenever f_fs needs it 330500a2430fSAndrzej Pietrasiewicz */ 330600a2430fSAndrzej Pietrasiewicz static int _ffs_name_dev(struct ffs_dev *dev, const char *name) 330700a2430fSAndrzej Pietrasiewicz { 330800a2430fSAndrzej Pietrasiewicz struct ffs_dev *existing; 330900a2430fSAndrzej Pietrasiewicz 331000a2430fSAndrzej Pietrasiewicz existing = _ffs_do_find_dev(name); 331100a2430fSAndrzej Pietrasiewicz if (existing) 331200a2430fSAndrzej Pietrasiewicz return -EBUSY; 331300a2430fSAndrzej Pietrasiewicz 331400a2430fSAndrzej Pietrasiewicz dev->name = name; 331500a2430fSAndrzej Pietrasiewicz 331600a2430fSAndrzej Pietrasiewicz return 0; 331700a2430fSAndrzej Pietrasiewicz } 331800a2430fSAndrzej Pietrasiewicz 331900a2430fSAndrzej Pietrasiewicz /* 332000a2430fSAndrzej Pietrasiewicz * The caller is responsible for "name" being available whenever f_fs needs it 332100a2430fSAndrzej Pietrasiewicz */ 332200a2430fSAndrzej Pietrasiewicz int ffs_name_dev(struct ffs_dev *dev, const char *name) 332300a2430fSAndrzej Pietrasiewicz { 332400a2430fSAndrzej Pietrasiewicz int ret; 332500a2430fSAndrzej Pietrasiewicz 332600a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 332700a2430fSAndrzej Pietrasiewicz ret = _ffs_name_dev(dev, name); 332800a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 332900a2430fSAndrzej Pietrasiewicz 333000a2430fSAndrzej Pietrasiewicz return ret; 333100a2430fSAndrzej Pietrasiewicz } 333200a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_name_dev); 333300a2430fSAndrzej Pietrasiewicz 333400a2430fSAndrzej Pietrasiewicz int ffs_single_dev(struct ffs_dev *dev) 333500a2430fSAndrzej Pietrasiewicz { 333600a2430fSAndrzej Pietrasiewicz int ret; 333700a2430fSAndrzej Pietrasiewicz 333800a2430fSAndrzej Pietrasiewicz ret = 0; 333900a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 334000a2430fSAndrzej Pietrasiewicz 334100a2430fSAndrzej Pietrasiewicz if (!list_is_singular(&ffs_devices)) 334200a2430fSAndrzej Pietrasiewicz ret = -EBUSY; 334300a2430fSAndrzej Pietrasiewicz else 334400a2430fSAndrzej Pietrasiewicz dev->single = true; 334500a2430fSAndrzej Pietrasiewicz 334600a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 334700a2430fSAndrzej Pietrasiewicz return ret; 334800a2430fSAndrzej Pietrasiewicz } 334900a2430fSAndrzej Pietrasiewicz EXPORT_SYMBOL_GPL(ffs_single_dev); 335000a2430fSAndrzej Pietrasiewicz 335100a2430fSAndrzej Pietrasiewicz /* 335200a2430fSAndrzej Pietrasiewicz * ffs_lock must be taken by the caller of this function 335300a2430fSAndrzej Pietrasiewicz */ 335400a2430fSAndrzej Pietrasiewicz static void _ffs_free_dev(struct ffs_dev *dev) 335500a2430fSAndrzej Pietrasiewicz { 335600a2430fSAndrzej Pietrasiewicz list_del(&dev->entry); 335700a2430fSAndrzej Pietrasiewicz if (dev->name_allocated) 335800a2430fSAndrzej Pietrasiewicz kfree(dev->name); 335900a2430fSAndrzej Pietrasiewicz kfree(dev); 336000a2430fSAndrzej Pietrasiewicz if (list_empty(&ffs_devices)) 336100a2430fSAndrzej Pietrasiewicz functionfs_cleanup(); 336200a2430fSAndrzej Pietrasiewicz } 336300a2430fSAndrzej Pietrasiewicz 336400a2430fSAndrzej Pietrasiewicz static void *ffs_acquire_dev(const char *dev_name) 336500a2430fSAndrzej Pietrasiewicz { 336600a2430fSAndrzej Pietrasiewicz struct ffs_dev *ffs_dev; 336700a2430fSAndrzej Pietrasiewicz 336800a2430fSAndrzej Pietrasiewicz ENTER(); 336900a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 337000a2430fSAndrzej Pietrasiewicz 337100a2430fSAndrzej Pietrasiewicz ffs_dev = _ffs_find_dev(dev_name); 337200a2430fSAndrzej Pietrasiewicz if (!ffs_dev) 337300a2430fSAndrzej Pietrasiewicz ffs_dev = ERR_PTR(-ENOENT); 337400a2430fSAndrzej Pietrasiewicz else if (ffs_dev->mounted) 337500a2430fSAndrzej Pietrasiewicz ffs_dev = ERR_PTR(-EBUSY); 337600a2430fSAndrzej Pietrasiewicz else if (ffs_dev->ffs_acquire_dev_callback && 337700a2430fSAndrzej Pietrasiewicz ffs_dev->ffs_acquire_dev_callback(ffs_dev)) 337800a2430fSAndrzej Pietrasiewicz ffs_dev = ERR_PTR(-ENOENT); 337900a2430fSAndrzej Pietrasiewicz else 338000a2430fSAndrzej Pietrasiewicz ffs_dev->mounted = true; 338100a2430fSAndrzej Pietrasiewicz 338200a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 338300a2430fSAndrzej Pietrasiewicz return ffs_dev; 338400a2430fSAndrzej Pietrasiewicz } 338500a2430fSAndrzej Pietrasiewicz 338600a2430fSAndrzej Pietrasiewicz static void ffs_release_dev(struct ffs_data *ffs_data) 338700a2430fSAndrzej Pietrasiewicz { 338800a2430fSAndrzej Pietrasiewicz struct ffs_dev *ffs_dev; 338900a2430fSAndrzej Pietrasiewicz 339000a2430fSAndrzej Pietrasiewicz ENTER(); 339100a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 339200a2430fSAndrzej Pietrasiewicz 339300a2430fSAndrzej Pietrasiewicz ffs_dev = ffs_data->private_data; 339400a2430fSAndrzej Pietrasiewicz if (ffs_dev) { 339500a2430fSAndrzej Pietrasiewicz ffs_dev->mounted = false; 339600a2430fSAndrzej Pietrasiewicz 339700a2430fSAndrzej Pietrasiewicz if (ffs_dev->ffs_release_dev_callback) 339800a2430fSAndrzej Pietrasiewicz ffs_dev->ffs_release_dev_callback(ffs_dev); 339900a2430fSAndrzej Pietrasiewicz } 340000a2430fSAndrzej Pietrasiewicz 340100a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 340200a2430fSAndrzej Pietrasiewicz } 340300a2430fSAndrzej Pietrasiewicz 340400a2430fSAndrzej Pietrasiewicz static int ffs_ready(struct ffs_data *ffs) 340500a2430fSAndrzej Pietrasiewicz { 340600a2430fSAndrzej Pietrasiewicz struct ffs_dev *ffs_obj; 340700a2430fSAndrzej Pietrasiewicz int ret = 0; 340800a2430fSAndrzej Pietrasiewicz 340900a2430fSAndrzej Pietrasiewicz ENTER(); 341000a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 341100a2430fSAndrzej Pietrasiewicz 341200a2430fSAndrzej Pietrasiewicz ffs_obj = ffs->private_data; 341300a2430fSAndrzej Pietrasiewicz if (!ffs_obj) { 341400a2430fSAndrzej Pietrasiewicz ret = -EINVAL; 341500a2430fSAndrzej Pietrasiewicz goto done; 341600a2430fSAndrzej Pietrasiewicz } 341700a2430fSAndrzej Pietrasiewicz if (WARN_ON(ffs_obj->desc_ready)) { 341800a2430fSAndrzej Pietrasiewicz ret = -EBUSY; 341900a2430fSAndrzej Pietrasiewicz goto done; 342000a2430fSAndrzej Pietrasiewicz } 342100a2430fSAndrzej Pietrasiewicz 342200a2430fSAndrzej Pietrasiewicz ffs_obj->desc_ready = true; 342300a2430fSAndrzej Pietrasiewicz ffs_obj->ffs_data = ffs; 342400a2430fSAndrzej Pietrasiewicz 342549a79d8bSKrzysztof Opasiak if (ffs_obj->ffs_ready_callback) { 342600a2430fSAndrzej Pietrasiewicz ret = ffs_obj->ffs_ready_callback(ffs); 342749a79d8bSKrzysztof Opasiak if (ret) 342849a79d8bSKrzysztof Opasiak goto done; 342949a79d8bSKrzysztof Opasiak } 343000a2430fSAndrzej Pietrasiewicz 343149a79d8bSKrzysztof Opasiak set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags); 343200a2430fSAndrzej Pietrasiewicz done: 343300a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 343400a2430fSAndrzej Pietrasiewicz return ret; 343500a2430fSAndrzej Pietrasiewicz } 343600a2430fSAndrzej Pietrasiewicz 343700a2430fSAndrzej Pietrasiewicz static void ffs_closed(struct ffs_data *ffs) 343800a2430fSAndrzej Pietrasiewicz { 343900a2430fSAndrzej Pietrasiewicz struct ffs_dev *ffs_obj; 3440f14e9ad1SRui Miguel Silva struct f_fs_opts *opts; 344100a2430fSAndrzej Pietrasiewicz 344200a2430fSAndrzej Pietrasiewicz ENTER(); 344300a2430fSAndrzej Pietrasiewicz ffs_dev_lock(); 344400a2430fSAndrzej Pietrasiewicz 344500a2430fSAndrzej Pietrasiewicz ffs_obj = ffs->private_data; 344600a2430fSAndrzej Pietrasiewicz if (!ffs_obj) 344700a2430fSAndrzej Pietrasiewicz goto done; 344800a2430fSAndrzej Pietrasiewicz 344900a2430fSAndrzej Pietrasiewicz ffs_obj->desc_ready = false; 345000a2430fSAndrzej Pietrasiewicz 345149a79d8bSKrzysztof Opasiak if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) && 345249a79d8bSKrzysztof Opasiak ffs_obj->ffs_closed_callback) 345300a2430fSAndrzej Pietrasiewicz ffs_obj->ffs_closed_callback(ffs); 345400a2430fSAndrzej Pietrasiewicz 3455f14e9ad1SRui Miguel Silva if (ffs_obj->opts) 3456f14e9ad1SRui Miguel Silva opts = ffs_obj->opts; 3457f14e9ad1SRui Miguel Silva else 3458f14e9ad1SRui Miguel Silva goto done; 3459f14e9ad1SRui Miguel Silva 3460f14e9ad1SRui Miguel Silva if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent 3461f14e9ad1SRui Miguel Silva || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount)) 346200a2430fSAndrzej Pietrasiewicz goto done; 346300a2430fSAndrzej Pietrasiewicz 346400a2430fSAndrzej Pietrasiewicz unregister_gadget_item(ffs_obj->opts-> 346500a2430fSAndrzej Pietrasiewicz func_inst.group.cg_item.ci_parent->ci_parent); 346600a2430fSAndrzej Pietrasiewicz done: 346700a2430fSAndrzej Pietrasiewicz ffs_dev_unlock(); 346800a2430fSAndrzej Pietrasiewicz } 346900a2430fSAndrzej Pietrasiewicz 347000a2430fSAndrzej Pietrasiewicz /* Misc helper functions ****************************************************/ 347100a2430fSAndrzej Pietrasiewicz 347200a2430fSAndrzej Pietrasiewicz static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) 347300a2430fSAndrzej Pietrasiewicz { 347400a2430fSAndrzej Pietrasiewicz return nonblock 347500a2430fSAndrzej Pietrasiewicz ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN 347600a2430fSAndrzej Pietrasiewicz : mutex_lock_interruptible(mutex); 347700a2430fSAndrzej Pietrasiewicz } 347800a2430fSAndrzej Pietrasiewicz 347900a2430fSAndrzej Pietrasiewicz static char *ffs_prepare_buffer(const char __user *buf, size_t len) 348000a2430fSAndrzej Pietrasiewicz { 348100a2430fSAndrzej Pietrasiewicz char *data; 348200a2430fSAndrzej Pietrasiewicz 348300a2430fSAndrzej Pietrasiewicz if (unlikely(!len)) 348400a2430fSAndrzej Pietrasiewicz return NULL; 348500a2430fSAndrzej Pietrasiewicz 348600a2430fSAndrzej Pietrasiewicz data = kmalloc(len, GFP_KERNEL); 348700a2430fSAndrzej Pietrasiewicz if (unlikely(!data)) 348800a2430fSAndrzej Pietrasiewicz return ERR_PTR(-ENOMEM); 348900a2430fSAndrzej Pietrasiewicz 34907fe9a937SDaniel Walter if (unlikely(copy_from_user(data, buf, len))) { 349100a2430fSAndrzej Pietrasiewicz kfree(data); 349200a2430fSAndrzej Pietrasiewicz return ERR_PTR(-EFAULT); 349300a2430fSAndrzej Pietrasiewicz } 349400a2430fSAndrzej Pietrasiewicz 349500a2430fSAndrzej Pietrasiewicz pr_vdebug("Buffer from user space:\n"); 349600a2430fSAndrzej Pietrasiewicz ffs_dump_mem("", data, len); 349700a2430fSAndrzej Pietrasiewicz 349800a2430fSAndrzej Pietrasiewicz return data; 349900a2430fSAndrzej Pietrasiewicz } 350000a2430fSAndrzej Pietrasiewicz 350100a2430fSAndrzej Pietrasiewicz DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); 350200a2430fSAndrzej Pietrasiewicz MODULE_LICENSE("GPL"); 350300a2430fSAndrzej Pietrasiewicz MODULE_AUTHOR("Michal Nazarewicz"); 3504