18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * inode.c -- user mode filesystem api for usb gadget controllers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2003-2004 David Brownell 68c2ecf20Sopenharmony_ci * Copyright (C) 2003 Agilent Technologies 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* #define VERBOSE_DEBUG */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/fs.h> 158c2ecf20Sopenharmony_ci#include <linux/fs_context.h> 168c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 178c2ecf20Sopenharmony_ci#include <linux/uts.h> 188c2ecf20Sopenharmony_ci#include <linux/wait.h> 198c2ecf20Sopenharmony_ci#include <linux/compiler.h> 208c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 218c2ecf20Sopenharmony_ci#include <linux/sched.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/poll.h> 248c2ecf20Sopenharmony_ci#include <linux/kthread.h> 258c2ecf20Sopenharmony_ci#include <linux/aio.h> 268c2ecf20Sopenharmony_ci#include <linux/uio.h> 278c2ecf20Sopenharmony_ci#include <linux/refcount.h> 288c2ecf20Sopenharmony_ci#include <linux/delay.h> 298c2ecf20Sopenharmony_ci#include <linux/device.h> 308c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <linux/usb/gadgetfs.h> 338c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * The gadgetfs API maps each endpoint to a file descriptor so that you 388c2ecf20Sopenharmony_ci * can use standard synchronous read/write calls for I/O. There's some 398c2ecf20Sopenharmony_ci * O_NONBLOCK and O_ASYNC/FASYNC style i/o support. Example usermode 408c2ecf20Sopenharmony_ci * drivers show how this works in practice. You can also use AIO to 418c2ecf20Sopenharmony_ci * eliminate I/O gaps between requests, to help when streaming data. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * Key parts that must be USB-specific are protocols defining how the 448c2ecf20Sopenharmony_ci * read/write operations relate to the hardware state machines. There 458c2ecf20Sopenharmony_ci * are two types of files. One type is for the device, implementing ep0. 468c2ecf20Sopenharmony_ci * The other type is for each IN or OUT endpoint. In both cases, the 478c2ecf20Sopenharmony_ci * user mode driver must configure the hardware before using it. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * - First, dev_config() is called when /dev/gadget/$CHIP is configured 508c2ecf20Sopenharmony_ci * (by writing configuration and device descriptors). Afterwards it 518c2ecf20Sopenharmony_ci * may serve as a source of device events, used to handle all control 528c2ecf20Sopenharmony_ci * requests other than basic enumeration. 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * - Then, after a SET_CONFIGURATION control request, ep_config() is 558c2ecf20Sopenharmony_ci * called when each /dev/gadget/ep* file is configured (by writing 568c2ecf20Sopenharmony_ci * endpoint descriptors). Afterwards these files are used to write() 578c2ecf20Sopenharmony_ci * IN data or to read() OUT data. To halt the endpoint, a "wrong 588c2ecf20Sopenharmony_ci * direction" request is issued (like reading an IN endpoint). 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe 618c2ecf20Sopenharmony_ci * not possible on all hardware. For example, precise fault handling with 628c2ecf20Sopenharmony_ci * respect to data left in endpoint fifos after aborted operations; or 638c2ecf20Sopenharmony_ci * selective clearing of endpoint halts, to implement SET_INTERFACE. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define DRIVER_DESC "USB Gadget filesystem" 678c2ecf20Sopenharmony_ci#define DRIVER_VERSION "24 Aug 2004" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic const char driver_desc [] = DRIVER_DESC; 708c2ecf20Sopenharmony_cistatic const char shortname [] = "gadgetfs"; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION (DRIVER_DESC); 738c2ecf20Sopenharmony_ciMODULE_AUTHOR ("David Brownell"); 748c2ecf20Sopenharmony_ciMODULE_LICENSE ("GPL"); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int ep_open(struct inode *, struct file *); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define GADGETFS_MAGIC 0xaee71ee7 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* /dev/gadget/$CHIP represents ep0 and the whole device */ 848c2ecf20Sopenharmony_cienum ep0_state { 858c2ecf20Sopenharmony_ci /* DISABLED is the initial state. */ 868c2ecf20Sopenharmony_ci STATE_DEV_DISABLED = 0, 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Only one open() of /dev/gadget/$CHIP; only one file tracks 898c2ecf20Sopenharmony_ci * ep0/device i/o modes and binding to the controller. Driver 908c2ecf20Sopenharmony_ci * must always write descriptors to initialize the device, then 918c2ecf20Sopenharmony_ci * the device becomes UNCONNECTED until enumeration. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci STATE_DEV_OPENED, 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* From then on, ep0 fd is in either of two basic modes: 968c2ecf20Sopenharmony_ci * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it 978c2ecf20Sopenharmony_ci * - SETUP: read/write will transfer control data and succeed; 988c2ecf20Sopenharmony_ci * or if "wrong direction", performs protocol stall 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci STATE_DEV_UNCONNECTED, 1018c2ecf20Sopenharmony_ci STATE_DEV_CONNECTED, 1028c2ecf20Sopenharmony_ci STATE_DEV_SETUP, 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* UNBOUND means the driver closed ep0, so the device won't be 1058c2ecf20Sopenharmony_ci * accessible again (DEV_DISABLED) until all fds are closed. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci STATE_DEV_UNBOUND, 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* enough for the whole queue: most events invalidate others */ 1118c2ecf20Sopenharmony_ci#define N_EVENT 5 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#define RBUF_SIZE 256 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistruct dev_data { 1168c2ecf20Sopenharmony_ci spinlock_t lock; 1178c2ecf20Sopenharmony_ci refcount_t count; 1188c2ecf20Sopenharmony_ci int udc_usage; 1198c2ecf20Sopenharmony_ci enum ep0_state state; /* P: lock */ 1208c2ecf20Sopenharmony_ci struct usb_gadgetfs_event event [N_EVENT]; 1218c2ecf20Sopenharmony_ci unsigned ev_next; 1228c2ecf20Sopenharmony_ci struct fasync_struct *fasync; 1238c2ecf20Sopenharmony_ci u8 current_config; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* drivers reading ep0 MUST handle control requests (SETUP) 1268c2ecf20Sopenharmony_ci * reported that way; else the host will time out. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci unsigned usermode_setup : 1, 1298c2ecf20Sopenharmony_ci setup_in : 1, 1308c2ecf20Sopenharmony_ci setup_can_stall : 1, 1318c2ecf20Sopenharmony_ci setup_out_ready : 1, 1328c2ecf20Sopenharmony_ci setup_out_error : 1, 1338c2ecf20Sopenharmony_ci setup_abort : 1, 1348c2ecf20Sopenharmony_ci gadget_registered : 1; 1358c2ecf20Sopenharmony_ci unsigned setup_wLength; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* the rest is basically write-once */ 1388c2ecf20Sopenharmony_ci struct usb_config_descriptor *config, *hs_config; 1398c2ecf20Sopenharmony_ci struct usb_device_descriptor *dev; 1408c2ecf20Sopenharmony_ci struct usb_request *req; 1418c2ecf20Sopenharmony_ci struct usb_gadget *gadget; 1428c2ecf20Sopenharmony_ci struct list_head epfiles; 1438c2ecf20Sopenharmony_ci void *buf; 1448c2ecf20Sopenharmony_ci wait_queue_head_t wait; 1458c2ecf20Sopenharmony_ci struct super_block *sb; 1468c2ecf20Sopenharmony_ci struct dentry *dentry; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* except this scratch i/o buffer for ep0 */ 1498c2ecf20Sopenharmony_ci u8 rbuf[RBUF_SIZE]; 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic inline void get_dev (struct dev_data *data) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci refcount_inc (&data->count); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void put_dev (struct dev_data *data) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci if (likely (!refcount_dec_and_test (&data->count))) 1608c2ecf20Sopenharmony_ci return; 1618c2ecf20Sopenharmony_ci /* needs no more cleanup */ 1628c2ecf20Sopenharmony_ci BUG_ON (waitqueue_active (&data->wait)); 1638c2ecf20Sopenharmony_ci kfree (data); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic struct dev_data *dev_new (void) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct dev_data *dev; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1718c2ecf20Sopenharmony_ci if (!dev) 1728c2ecf20Sopenharmony_ci return NULL; 1738c2ecf20Sopenharmony_ci dev->state = STATE_DEV_DISABLED; 1748c2ecf20Sopenharmony_ci refcount_set (&dev->count, 1); 1758c2ecf20Sopenharmony_ci spin_lock_init (&dev->lock); 1768c2ecf20Sopenharmony_ci INIT_LIST_HEAD (&dev->epfiles); 1778c2ecf20Sopenharmony_ci init_waitqueue_head (&dev->wait); 1788c2ecf20Sopenharmony_ci return dev; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* other /dev/gadget/$ENDPOINT files represent endpoints */ 1848c2ecf20Sopenharmony_cienum ep_state { 1858c2ecf20Sopenharmony_ci STATE_EP_DISABLED = 0, 1868c2ecf20Sopenharmony_ci STATE_EP_READY, 1878c2ecf20Sopenharmony_ci STATE_EP_ENABLED, 1888c2ecf20Sopenharmony_ci STATE_EP_UNBOUND, 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistruct ep_data { 1928c2ecf20Sopenharmony_ci struct mutex lock; 1938c2ecf20Sopenharmony_ci enum ep_state state; 1948c2ecf20Sopenharmony_ci refcount_t count; 1958c2ecf20Sopenharmony_ci struct dev_data *dev; 1968c2ecf20Sopenharmony_ci /* must hold dev->lock before accessing ep or req */ 1978c2ecf20Sopenharmony_ci struct usb_ep *ep; 1988c2ecf20Sopenharmony_ci struct usb_request *req; 1998c2ecf20Sopenharmony_ci ssize_t status; 2008c2ecf20Sopenharmony_ci char name [16]; 2018c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor desc, hs_desc; 2028c2ecf20Sopenharmony_ci struct list_head epfiles; 2038c2ecf20Sopenharmony_ci wait_queue_head_t wait; 2048c2ecf20Sopenharmony_ci struct dentry *dentry; 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic inline void get_ep (struct ep_data *data) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci refcount_inc (&data->count); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void put_ep (struct ep_data *data) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci if (likely (!refcount_dec_and_test (&data->count))) 2158c2ecf20Sopenharmony_ci return; 2168c2ecf20Sopenharmony_ci put_dev (data->dev); 2178c2ecf20Sopenharmony_ci /* needs no more cleanup */ 2188c2ecf20Sopenharmony_ci BUG_ON (!list_empty (&data->epfiles)); 2198c2ecf20Sopenharmony_ci BUG_ON (waitqueue_active (&data->wait)); 2208c2ecf20Sopenharmony_ci kfree (data); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* most "how to use the hardware" policy choices are in userspace: 2268c2ecf20Sopenharmony_ci * mapping endpoint roles (which the driver needs) to the capabilities 2278c2ecf20Sopenharmony_ci * which the usb controller has. most of those capabilities are exposed 2288c2ecf20Sopenharmony_ci * implicitly, starting with the driver name and then endpoint names. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic const char *CHIP; 2328c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(sb_mutex); /* Serialize superblock operations */ 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/* NOTE: don't use dev_printk calls before binding to the gadget 2378c2ecf20Sopenharmony_ci * at the end of ep0 configuration, or after unbind. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* too wordy: dev_printk(level , &(d)->gadget->dev , fmt , ## args) */ 2418c2ecf20Sopenharmony_ci#define xprintk(d,level,fmt,args...) \ 2428c2ecf20Sopenharmony_ci printk(level "%s: " fmt , shortname , ## args) 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#ifdef DEBUG 2458c2ecf20Sopenharmony_ci#define DBG(dev,fmt,args...) \ 2468c2ecf20Sopenharmony_ci xprintk(dev , KERN_DEBUG , fmt , ## args) 2478c2ecf20Sopenharmony_ci#else 2488c2ecf20Sopenharmony_ci#define DBG(dev,fmt,args...) \ 2498c2ecf20Sopenharmony_ci do { } while (0) 2508c2ecf20Sopenharmony_ci#endif /* DEBUG */ 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci#ifdef VERBOSE_DEBUG 2538c2ecf20Sopenharmony_ci#define VDEBUG DBG 2548c2ecf20Sopenharmony_ci#else 2558c2ecf20Sopenharmony_ci#define VDEBUG(dev,fmt,args...) \ 2568c2ecf20Sopenharmony_ci do { } while (0) 2578c2ecf20Sopenharmony_ci#endif /* DEBUG */ 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci#define ERROR(dev,fmt,args...) \ 2608c2ecf20Sopenharmony_ci xprintk(dev , KERN_ERR , fmt , ## args) 2618c2ecf20Sopenharmony_ci#define INFO(dev,fmt,args...) \ 2628c2ecf20Sopenharmony_ci xprintk(dev , KERN_INFO , fmt , ## args) 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* SYNCHRONOUS ENDPOINT OPERATIONS (bulk/intr/iso) 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * After opening, configure non-control endpoints. Then use normal 2708c2ecf20Sopenharmony_ci * stream read() and write() requests; and maybe ioctl() to get more 2718c2ecf20Sopenharmony_ci * precise FIFO status when recovering from cancellation. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic void epio_complete (struct usb_ep *ep, struct usb_request *req) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct ep_data *epdata = ep->driver_data; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!req->context) 2798c2ecf20Sopenharmony_ci return; 2808c2ecf20Sopenharmony_ci if (req->status) 2818c2ecf20Sopenharmony_ci epdata->status = req->status; 2828c2ecf20Sopenharmony_ci else 2838c2ecf20Sopenharmony_ci epdata->status = req->actual; 2848c2ecf20Sopenharmony_ci complete ((struct completion *)req->context); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* tasklock endpoint, returning when it's connected. 2888c2ecf20Sopenharmony_ci * still need dev->lock to use epdata->ep. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_cistatic int 2918c2ecf20Sopenharmony_ciget_ready_ep (unsigned f_flags, struct ep_data *epdata, bool is_write) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int val; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (f_flags & O_NONBLOCK) { 2968c2ecf20Sopenharmony_ci if (!mutex_trylock(&epdata->lock)) 2978c2ecf20Sopenharmony_ci goto nonblock; 2988c2ecf20Sopenharmony_ci if (epdata->state != STATE_EP_ENABLED && 2998c2ecf20Sopenharmony_ci (!is_write || epdata->state != STATE_EP_READY)) { 3008c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 3018c2ecf20Sopenharmony_cinonblock: 3028c2ecf20Sopenharmony_ci val = -EAGAIN; 3038c2ecf20Sopenharmony_ci } else 3048c2ecf20Sopenharmony_ci val = 0; 3058c2ecf20Sopenharmony_ci return val; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci val = mutex_lock_interruptible(&epdata->lock); 3098c2ecf20Sopenharmony_ci if (val < 0) 3108c2ecf20Sopenharmony_ci return val; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci switch (epdata->state) { 3138c2ecf20Sopenharmony_ci case STATE_EP_ENABLED: 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci case STATE_EP_READY: /* not configured yet */ 3168c2ecf20Sopenharmony_ci if (is_write) 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci fallthrough; 3198c2ecf20Sopenharmony_ci case STATE_EP_UNBOUND: /* clean disconnect */ 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci // case STATE_EP_DISABLED: /* "can't happen" */ 3228c2ecf20Sopenharmony_ci default: /* error! */ 3238c2ecf20Sopenharmony_ci pr_debug ("%s: ep %p not available, state %d\n", 3248c2ecf20Sopenharmony_ci shortname, epdata, epdata->state); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 3278c2ecf20Sopenharmony_ci return -ENODEV; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic ssize_t 3318c2ecf20Sopenharmony_ciep_io (struct ep_data *epdata, void *buf, unsigned len) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK (done); 3348c2ecf20Sopenharmony_ci int value; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci spin_lock_irq (&epdata->dev->lock); 3378c2ecf20Sopenharmony_ci if (likely (epdata->ep != NULL)) { 3388c2ecf20Sopenharmony_ci struct usb_request *req = epdata->req; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci req->context = &done; 3418c2ecf20Sopenharmony_ci req->complete = epio_complete; 3428c2ecf20Sopenharmony_ci req->buf = buf; 3438c2ecf20Sopenharmony_ci req->length = len; 3448c2ecf20Sopenharmony_ci value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC); 3458c2ecf20Sopenharmony_ci } else 3468c2ecf20Sopenharmony_ci value = -ENODEV; 3478c2ecf20Sopenharmony_ci spin_unlock_irq (&epdata->dev->lock); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (likely (value == 0)) { 3508c2ecf20Sopenharmony_ci value = wait_for_completion_interruptible(&done); 3518c2ecf20Sopenharmony_ci if (value != 0) { 3528c2ecf20Sopenharmony_ci spin_lock_irq (&epdata->dev->lock); 3538c2ecf20Sopenharmony_ci if (likely (epdata->ep != NULL)) { 3548c2ecf20Sopenharmony_ci DBG (epdata->dev, "%s i/o interrupted\n", 3558c2ecf20Sopenharmony_ci epdata->name); 3568c2ecf20Sopenharmony_ci usb_ep_dequeue (epdata->ep, epdata->req); 3578c2ecf20Sopenharmony_ci spin_unlock_irq (&epdata->dev->lock); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci wait_for_completion(&done); 3608c2ecf20Sopenharmony_ci if (epdata->status == -ECONNRESET) 3618c2ecf20Sopenharmony_ci epdata->status = -EINTR; 3628c2ecf20Sopenharmony_ci } else { 3638c2ecf20Sopenharmony_ci spin_unlock_irq (&epdata->dev->lock); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci DBG (epdata->dev, "endpoint gone\n"); 3668c2ecf20Sopenharmony_ci wait_for_completion(&done); 3678c2ecf20Sopenharmony_ci epdata->status = -ENODEV; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci return epdata->status; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci return value; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int 3768c2ecf20Sopenharmony_ciep_release (struct inode *inode, struct file *fd) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct ep_data *data = fd->private_data; 3798c2ecf20Sopenharmony_ci int value; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci value = mutex_lock_interruptible(&data->lock); 3828c2ecf20Sopenharmony_ci if (value < 0) 3838c2ecf20Sopenharmony_ci return value; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* clean up if this can be reopened */ 3868c2ecf20Sopenharmony_ci if (data->state != STATE_EP_UNBOUND) { 3878c2ecf20Sopenharmony_ci data->state = STATE_EP_DISABLED; 3888c2ecf20Sopenharmony_ci data->desc.bDescriptorType = 0; 3898c2ecf20Sopenharmony_ci data->hs_desc.bDescriptorType = 0; 3908c2ecf20Sopenharmony_ci usb_ep_disable(data->ep); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 3938c2ecf20Sopenharmony_ci put_ep (data); 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic long ep_ioctl(struct file *fd, unsigned code, unsigned long value) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct ep_data *data = fd->private_data; 4008c2ecf20Sopenharmony_ci int status; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if ((status = get_ready_ep (fd->f_flags, data, false)) < 0) 4038c2ecf20Sopenharmony_ci return status; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci spin_lock_irq (&data->dev->lock); 4068c2ecf20Sopenharmony_ci if (likely (data->ep != NULL)) { 4078c2ecf20Sopenharmony_ci switch (code) { 4088c2ecf20Sopenharmony_ci case GADGETFS_FIFO_STATUS: 4098c2ecf20Sopenharmony_ci status = usb_ep_fifo_status (data->ep); 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci case GADGETFS_FIFO_FLUSH: 4128c2ecf20Sopenharmony_ci usb_ep_fifo_flush (data->ep); 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci case GADGETFS_CLEAR_HALT: 4158c2ecf20Sopenharmony_ci status = usb_ep_clear_halt (data->ep); 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci default: 4188c2ecf20Sopenharmony_ci status = -ENOTTY; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci } else 4218c2ecf20Sopenharmony_ci status = -ENODEV; 4228c2ecf20Sopenharmony_ci spin_unlock_irq (&data->dev->lock); 4238c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 4248c2ecf20Sopenharmony_ci return status; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/* ASYNCHRONOUS ENDPOINT I/O OPERATIONS (bulk/intr/iso) */ 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistruct kiocb_priv { 4328c2ecf20Sopenharmony_ci struct usb_request *req; 4338c2ecf20Sopenharmony_ci struct ep_data *epdata; 4348c2ecf20Sopenharmony_ci struct kiocb *iocb; 4358c2ecf20Sopenharmony_ci struct mm_struct *mm; 4368c2ecf20Sopenharmony_ci struct work_struct work; 4378c2ecf20Sopenharmony_ci void *buf; 4388c2ecf20Sopenharmony_ci struct iov_iter to; 4398c2ecf20Sopenharmony_ci const void *to_free; 4408c2ecf20Sopenharmony_ci unsigned actual; 4418c2ecf20Sopenharmony_ci}; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int ep_aio_cancel(struct kiocb *iocb) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct kiocb_priv *priv = iocb->private; 4468c2ecf20Sopenharmony_ci struct ep_data *epdata; 4478c2ecf20Sopenharmony_ci int value; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci local_irq_disable(); 4508c2ecf20Sopenharmony_ci epdata = priv->epdata; 4518c2ecf20Sopenharmony_ci // spin_lock(&epdata->dev->lock); 4528c2ecf20Sopenharmony_ci if (likely(epdata && epdata->ep && priv->req)) 4538c2ecf20Sopenharmony_ci value = usb_ep_dequeue (epdata->ep, priv->req); 4548c2ecf20Sopenharmony_ci else 4558c2ecf20Sopenharmony_ci value = -EINVAL; 4568c2ecf20Sopenharmony_ci // spin_unlock(&epdata->dev->lock); 4578c2ecf20Sopenharmony_ci local_irq_enable(); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return value; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic void ep_user_copy_worker(struct work_struct *work) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work); 4658c2ecf20Sopenharmony_ci struct mm_struct *mm = priv->mm; 4668c2ecf20Sopenharmony_ci struct kiocb *iocb = priv->iocb; 4678c2ecf20Sopenharmony_ci size_t ret; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci kthread_use_mm(mm); 4708c2ecf20Sopenharmony_ci ret = copy_to_iter(priv->buf, priv->actual, &priv->to); 4718c2ecf20Sopenharmony_ci kthread_unuse_mm(mm); 4728c2ecf20Sopenharmony_ci if (!ret) 4738c2ecf20Sopenharmony_ci ret = -EFAULT; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* completing the iocb can drop the ctx and mm, don't touch mm after */ 4768c2ecf20Sopenharmony_ci iocb->ki_complete(iocb, ret, ret); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci kfree(priv->buf); 4798c2ecf20Sopenharmony_ci kfree(priv->to_free); 4808c2ecf20Sopenharmony_ci kfree(priv); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct kiocb *iocb = req->context; 4868c2ecf20Sopenharmony_ci struct kiocb_priv *priv = iocb->private; 4878c2ecf20Sopenharmony_ci struct ep_data *epdata = priv->epdata; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* lock against disconnect (and ideally, cancel) */ 4908c2ecf20Sopenharmony_ci spin_lock(&epdata->dev->lock); 4918c2ecf20Sopenharmony_ci priv->req = NULL; 4928c2ecf20Sopenharmony_ci priv->epdata = NULL; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* if this was a write or a read returning no data then we 4958c2ecf20Sopenharmony_ci * don't need to copy anything to userspace, so we can 4968c2ecf20Sopenharmony_ci * complete the aio request immediately. 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci if (priv->to_free == NULL || unlikely(req->actual == 0)) { 4998c2ecf20Sopenharmony_ci kfree(req->buf); 5008c2ecf20Sopenharmony_ci kfree(priv->to_free); 5018c2ecf20Sopenharmony_ci kfree(priv); 5028c2ecf20Sopenharmony_ci iocb->private = NULL; 5038c2ecf20Sopenharmony_ci /* aio_complete() reports bytes-transferred _and_ faults */ 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci iocb->ki_complete(iocb, req->actual ? req->actual : req->status, 5068c2ecf20Sopenharmony_ci req->status); 5078c2ecf20Sopenharmony_ci } else { 5088c2ecf20Sopenharmony_ci /* ep_copy_to_user() won't report both; we hide some faults */ 5098c2ecf20Sopenharmony_ci if (unlikely(0 != req->status)) 5108c2ecf20Sopenharmony_ci DBG(epdata->dev, "%s fault %d len %d\n", 5118c2ecf20Sopenharmony_ci ep->name, req->status, req->actual); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci priv->buf = req->buf; 5148c2ecf20Sopenharmony_ci priv->actual = req->actual; 5158c2ecf20Sopenharmony_ci INIT_WORK(&priv->work, ep_user_copy_worker); 5168c2ecf20Sopenharmony_ci schedule_work(&priv->work); 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci usb_ep_free_request(ep, req); 5208c2ecf20Sopenharmony_ci spin_unlock(&epdata->dev->lock); 5218c2ecf20Sopenharmony_ci put_ep(epdata); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic ssize_t ep_aio(struct kiocb *iocb, 5258c2ecf20Sopenharmony_ci struct kiocb_priv *priv, 5268c2ecf20Sopenharmony_ci struct ep_data *epdata, 5278c2ecf20Sopenharmony_ci char *buf, 5288c2ecf20Sopenharmony_ci size_t len) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct usb_request *req; 5318c2ecf20Sopenharmony_ci ssize_t value; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci iocb->private = priv; 5348c2ecf20Sopenharmony_ci priv->iocb = iocb; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci kiocb_set_cancel_fn(iocb, ep_aio_cancel); 5378c2ecf20Sopenharmony_ci get_ep(epdata); 5388c2ecf20Sopenharmony_ci priv->epdata = epdata; 5398c2ecf20Sopenharmony_ci priv->actual = 0; 5408c2ecf20Sopenharmony_ci priv->mm = current->mm; /* mm teardown waits for iocbs in exit_aio() */ 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* each kiocb is coupled to one usb_request, but we can't 5438c2ecf20Sopenharmony_ci * allocate or submit those if the host disconnected. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ci spin_lock_irq(&epdata->dev->lock); 5468c2ecf20Sopenharmony_ci value = -ENODEV; 5478c2ecf20Sopenharmony_ci if (unlikely(epdata->ep == NULL)) 5488c2ecf20Sopenharmony_ci goto fail; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC); 5518c2ecf20Sopenharmony_ci value = -ENOMEM; 5528c2ecf20Sopenharmony_ci if (unlikely(!req)) 5538c2ecf20Sopenharmony_ci goto fail; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci priv->req = req; 5568c2ecf20Sopenharmony_ci req->buf = buf; 5578c2ecf20Sopenharmony_ci req->length = len; 5588c2ecf20Sopenharmony_ci req->complete = ep_aio_complete; 5598c2ecf20Sopenharmony_ci req->context = iocb; 5608c2ecf20Sopenharmony_ci value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC); 5618c2ecf20Sopenharmony_ci if (unlikely(0 != value)) { 5628c2ecf20Sopenharmony_ci usb_ep_free_request(epdata->ep, req); 5638c2ecf20Sopenharmony_ci goto fail; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci spin_unlock_irq(&epdata->dev->lock); 5668c2ecf20Sopenharmony_ci return -EIOCBQUEUED; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cifail: 5698c2ecf20Sopenharmony_ci spin_unlock_irq(&epdata->dev->lock); 5708c2ecf20Sopenharmony_ci kfree(priv->to_free); 5718c2ecf20Sopenharmony_ci kfree(priv); 5728c2ecf20Sopenharmony_ci put_ep(epdata); 5738c2ecf20Sopenharmony_ci return value; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic ssize_t 5778c2ecf20Sopenharmony_ciep_read_iter(struct kiocb *iocb, struct iov_iter *to) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 5808c2ecf20Sopenharmony_ci struct ep_data *epdata = file->private_data; 5818c2ecf20Sopenharmony_ci size_t len = iov_iter_count(to); 5828c2ecf20Sopenharmony_ci ssize_t value; 5838c2ecf20Sopenharmony_ci char *buf; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if ((value = get_ready_ep(file->f_flags, epdata, false)) < 0) 5868c2ecf20Sopenharmony_ci return value; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* halt any endpoint by doing a "wrong direction" i/o call */ 5898c2ecf20Sopenharmony_ci if (usb_endpoint_dir_in(&epdata->desc)) { 5908c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_isoc(&epdata->desc) || 5918c2ecf20Sopenharmony_ci !is_sync_kiocb(iocb)) { 5928c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 5938c2ecf20Sopenharmony_ci return -EINVAL; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci DBG (epdata->dev, "%s halt\n", epdata->name); 5968c2ecf20Sopenharmony_ci spin_lock_irq(&epdata->dev->lock); 5978c2ecf20Sopenharmony_ci if (likely(epdata->ep != NULL)) 5988c2ecf20Sopenharmony_ci usb_ep_set_halt(epdata->ep); 5998c2ecf20Sopenharmony_ci spin_unlock_irq(&epdata->dev->lock); 6008c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 6018c2ecf20Sopenharmony_ci return -EBADMSG; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci buf = kmalloc(len, GFP_KERNEL); 6058c2ecf20Sopenharmony_ci if (unlikely(!buf)) { 6068c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 6078c2ecf20Sopenharmony_ci return -ENOMEM; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci if (is_sync_kiocb(iocb)) { 6108c2ecf20Sopenharmony_ci value = ep_io(epdata, buf, len); 6118c2ecf20Sopenharmony_ci if (value >= 0 && (copy_to_iter(buf, value, to) != value)) 6128c2ecf20Sopenharmony_ci value = -EFAULT; 6138c2ecf20Sopenharmony_ci } else { 6148c2ecf20Sopenharmony_ci struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL); 6158c2ecf20Sopenharmony_ci value = -ENOMEM; 6168c2ecf20Sopenharmony_ci if (!priv) 6178c2ecf20Sopenharmony_ci goto fail; 6188c2ecf20Sopenharmony_ci priv->to_free = dup_iter(&priv->to, to, GFP_KERNEL); 6198c2ecf20Sopenharmony_ci if (!priv->to_free) { 6208c2ecf20Sopenharmony_ci kfree(priv); 6218c2ecf20Sopenharmony_ci goto fail; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci value = ep_aio(iocb, priv, epdata, buf, len); 6248c2ecf20Sopenharmony_ci if (value == -EIOCBQUEUED) 6258c2ecf20Sopenharmony_ci buf = NULL; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_cifail: 6288c2ecf20Sopenharmony_ci kfree(buf); 6298c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 6308c2ecf20Sopenharmony_ci return value; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic ssize_t ep_config(struct ep_data *, const char *, size_t); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic ssize_t 6368c2ecf20Sopenharmony_ciep_write_iter(struct kiocb *iocb, struct iov_iter *from) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 6398c2ecf20Sopenharmony_ci struct ep_data *epdata = file->private_data; 6408c2ecf20Sopenharmony_ci size_t len = iov_iter_count(from); 6418c2ecf20Sopenharmony_ci bool configured; 6428c2ecf20Sopenharmony_ci ssize_t value; 6438c2ecf20Sopenharmony_ci char *buf; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if ((value = get_ready_ep(file->f_flags, epdata, true)) < 0) 6468c2ecf20Sopenharmony_ci return value; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci configured = epdata->state == STATE_EP_ENABLED; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* halt any endpoint by doing a "wrong direction" i/o call */ 6518c2ecf20Sopenharmony_ci if (configured && !usb_endpoint_dir_in(&epdata->desc)) { 6528c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_isoc(&epdata->desc) || 6538c2ecf20Sopenharmony_ci !is_sync_kiocb(iocb)) { 6548c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 6558c2ecf20Sopenharmony_ci return -EINVAL; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci DBG (epdata->dev, "%s halt\n", epdata->name); 6588c2ecf20Sopenharmony_ci spin_lock_irq(&epdata->dev->lock); 6598c2ecf20Sopenharmony_ci if (likely(epdata->ep != NULL)) 6608c2ecf20Sopenharmony_ci usb_ep_set_halt(epdata->ep); 6618c2ecf20Sopenharmony_ci spin_unlock_irq(&epdata->dev->lock); 6628c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 6638c2ecf20Sopenharmony_ci return -EBADMSG; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci buf = kmalloc(len, GFP_KERNEL); 6678c2ecf20Sopenharmony_ci if (unlikely(!buf)) { 6688c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 6698c2ecf20Sopenharmony_ci return -ENOMEM; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (unlikely(!copy_from_iter_full(buf, len, from))) { 6738c2ecf20Sopenharmony_ci value = -EFAULT; 6748c2ecf20Sopenharmony_ci goto out; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (unlikely(!configured)) { 6788c2ecf20Sopenharmony_ci value = ep_config(epdata, buf, len); 6798c2ecf20Sopenharmony_ci } else if (is_sync_kiocb(iocb)) { 6808c2ecf20Sopenharmony_ci value = ep_io(epdata, buf, len); 6818c2ecf20Sopenharmony_ci } else { 6828c2ecf20Sopenharmony_ci struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL); 6838c2ecf20Sopenharmony_ci value = -ENOMEM; 6848c2ecf20Sopenharmony_ci if (priv) { 6858c2ecf20Sopenharmony_ci value = ep_aio(iocb, priv, epdata, buf, len); 6868c2ecf20Sopenharmony_ci if (value == -EIOCBQUEUED) 6878c2ecf20Sopenharmony_ci buf = NULL; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ciout: 6918c2ecf20Sopenharmony_ci kfree(buf); 6928c2ecf20Sopenharmony_ci mutex_unlock(&epdata->lock); 6938c2ecf20Sopenharmony_ci return value; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/* used after endpoint configuration */ 6998c2ecf20Sopenharmony_cistatic const struct file_operations ep_io_operations = { 7008c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci .open = ep_open, 7038c2ecf20Sopenharmony_ci .release = ep_release, 7048c2ecf20Sopenharmony_ci .llseek = no_llseek, 7058c2ecf20Sopenharmony_ci .unlocked_ioctl = ep_ioctl, 7068c2ecf20Sopenharmony_ci .read_iter = ep_read_iter, 7078c2ecf20Sopenharmony_ci .write_iter = ep_write_iter, 7088c2ecf20Sopenharmony_ci}; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci/* ENDPOINT INITIALIZATION 7118c2ecf20Sopenharmony_ci * 7128c2ecf20Sopenharmony_ci * fd = open ("/dev/gadget/$ENDPOINT", O_RDWR) 7138c2ecf20Sopenharmony_ci * status = write (fd, descriptors, sizeof descriptors) 7148c2ecf20Sopenharmony_ci * 7158c2ecf20Sopenharmony_ci * That write establishes the endpoint configuration, configuring 7168c2ecf20Sopenharmony_ci * the controller to process bulk, interrupt, or isochronous transfers 7178c2ecf20Sopenharmony_ci * at the right maxpacket size, and so on. 7188c2ecf20Sopenharmony_ci * 7198c2ecf20Sopenharmony_ci * The descriptors are message type 1, identified by a host order u32 7208c2ecf20Sopenharmony_ci * at the beginning of what's written. Descriptor order is: full/low 7218c2ecf20Sopenharmony_ci * speed descriptor, then optional high speed descriptor. 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_cistatic ssize_t 7248c2ecf20Sopenharmony_ciep_config (struct ep_data *data, const char *buf, size_t len) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct usb_ep *ep; 7278c2ecf20Sopenharmony_ci u32 tag; 7288c2ecf20Sopenharmony_ci int value, length = len; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (data->state != STATE_EP_READY) { 7318c2ecf20Sopenharmony_ci value = -EL2HLT; 7328c2ecf20Sopenharmony_ci goto fail; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci value = len; 7368c2ecf20Sopenharmony_ci if (len < USB_DT_ENDPOINT_SIZE + 4) 7378c2ecf20Sopenharmony_ci goto fail0; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* we might need to change message format someday */ 7408c2ecf20Sopenharmony_ci memcpy(&tag, buf, 4); 7418c2ecf20Sopenharmony_ci if (tag != 1) { 7428c2ecf20Sopenharmony_ci DBG(data->dev, "config %s, bad tag %d\n", data->name, tag); 7438c2ecf20Sopenharmony_ci goto fail0; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci buf += 4; 7468c2ecf20Sopenharmony_ci len -= 4; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* NOTE: audio endpoint extensions not accepted here; 7498c2ecf20Sopenharmony_ci * just don't include the extra bytes. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* full/low speed descriptor, then high speed */ 7538c2ecf20Sopenharmony_ci memcpy(&data->desc, buf, USB_DT_ENDPOINT_SIZE); 7548c2ecf20Sopenharmony_ci if (data->desc.bLength != USB_DT_ENDPOINT_SIZE 7558c2ecf20Sopenharmony_ci || data->desc.bDescriptorType != USB_DT_ENDPOINT) 7568c2ecf20Sopenharmony_ci goto fail0; 7578c2ecf20Sopenharmony_ci if (len != USB_DT_ENDPOINT_SIZE) { 7588c2ecf20Sopenharmony_ci if (len != 2 * USB_DT_ENDPOINT_SIZE) 7598c2ecf20Sopenharmony_ci goto fail0; 7608c2ecf20Sopenharmony_ci memcpy(&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE, 7618c2ecf20Sopenharmony_ci USB_DT_ENDPOINT_SIZE); 7628c2ecf20Sopenharmony_ci if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE 7638c2ecf20Sopenharmony_ci || data->hs_desc.bDescriptorType 7648c2ecf20Sopenharmony_ci != USB_DT_ENDPOINT) { 7658c2ecf20Sopenharmony_ci DBG(data->dev, "config %s, bad hs length or type\n", 7668c2ecf20Sopenharmony_ci data->name); 7678c2ecf20Sopenharmony_ci goto fail0; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci spin_lock_irq (&data->dev->lock); 7728c2ecf20Sopenharmony_ci if (data->dev->state == STATE_DEV_UNBOUND) { 7738c2ecf20Sopenharmony_ci value = -ENOENT; 7748c2ecf20Sopenharmony_ci goto gone; 7758c2ecf20Sopenharmony_ci } else { 7768c2ecf20Sopenharmony_ci ep = data->ep; 7778c2ecf20Sopenharmony_ci if (ep == NULL) { 7788c2ecf20Sopenharmony_ci value = -ENODEV; 7798c2ecf20Sopenharmony_ci goto gone; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci switch (data->dev->gadget->speed) { 7838c2ecf20Sopenharmony_ci case USB_SPEED_LOW: 7848c2ecf20Sopenharmony_ci case USB_SPEED_FULL: 7858c2ecf20Sopenharmony_ci ep->desc = &data->desc; 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 7888c2ecf20Sopenharmony_ci /* fails if caller didn't provide that descriptor... */ 7898c2ecf20Sopenharmony_ci ep->desc = &data->hs_desc; 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci default: 7928c2ecf20Sopenharmony_ci DBG(data->dev, "unconnected, %s init abandoned\n", 7938c2ecf20Sopenharmony_ci data->name); 7948c2ecf20Sopenharmony_ci value = -EINVAL; 7958c2ecf20Sopenharmony_ci goto gone; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci value = usb_ep_enable(ep); 7988c2ecf20Sopenharmony_ci if (value == 0) { 7998c2ecf20Sopenharmony_ci data->state = STATE_EP_ENABLED; 8008c2ecf20Sopenharmony_ci value = length; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_cigone: 8038c2ecf20Sopenharmony_ci spin_unlock_irq (&data->dev->lock); 8048c2ecf20Sopenharmony_ci if (value < 0) { 8058c2ecf20Sopenharmony_cifail: 8068c2ecf20Sopenharmony_ci data->desc.bDescriptorType = 0; 8078c2ecf20Sopenharmony_ci data->hs_desc.bDescriptorType = 0; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci return value; 8108c2ecf20Sopenharmony_cifail0: 8118c2ecf20Sopenharmony_ci value = -EINVAL; 8128c2ecf20Sopenharmony_ci goto fail; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int 8168c2ecf20Sopenharmony_ciep_open (struct inode *inode, struct file *fd) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci struct ep_data *data = inode->i_private; 8198c2ecf20Sopenharmony_ci int value = -EBUSY; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&data->lock) != 0) 8228c2ecf20Sopenharmony_ci return -EINTR; 8238c2ecf20Sopenharmony_ci spin_lock_irq (&data->dev->lock); 8248c2ecf20Sopenharmony_ci if (data->dev->state == STATE_DEV_UNBOUND) 8258c2ecf20Sopenharmony_ci value = -ENOENT; 8268c2ecf20Sopenharmony_ci else if (data->state == STATE_EP_DISABLED) { 8278c2ecf20Sopenharmony_ci value = 0; 8288c2ecf20Sopenharmony_ci data->state = STATE_EP_READY; 8298c2ecf20Sopenharmony_ci get_ep (data); 8308c2ecf20Sopenharmony_ci fd->private_data = data; 8318c2ecf20Sopenharmony_ci VDEBUG (data->dev, "%s ready\n", data->name); 8328c2ecf20Sopenharmony_ci } else 8338c2ecf20Sopenharmony_ci DBG (data->dev, "%s state %d\n", 8348c2ecf20Sopenharmony_ci data->name, data->state); 8358c2ecf20Sopenharmony_ci spin_unlock_irq (&data->dev->lock); 8368c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 8378c2ecf20Sopenharmony_ci return value; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci/* EP0 IMPLEMENTATION can be partly in userspace. 8438c2ecf20Sopenharmony_ci * 8448c2ecf20Sopenharmony_ci * Drivers that use this facility receive various events, including 8458c2ecf20Sopenharmony_ci * control requests the kernel doesn't handle. Drivers that don't 8468c2ecf20Sopenharmony_ci * use this facility may be too simple-minded for real applications. 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic inline void ep0_readable (struct dev_data *dev) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci wake_up (&dev->wait); 8528c2ecf20Sopenharmony_ci kill_fasync (&dev->fasync, SIGIO, POLL_IN); 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic void clean_req (struct usb_ep *ep, struct usb_request *req) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci struct dev_data *dev = ep->driver_data; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (req->buf != dev->rbuf) { 8608c2ecf20Sopenharmony_ci kfree(req->buf); 8618c2ecf20Sopenharmony_ci req->buf = dev->rbuf; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci req->complete = epio_complete; 8648c2ecf20Sopenharmony_ci dev->setup_out_ready = 0; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic void ep0_complete (struct usb_ep *ep, struct usb_request *req) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct dev_data *dev = ep->driver_data; 8708c2ecf20Sopenharmony_ci unsigned long flags; 8718c2ecf20Sopenharmony_ci int free = 1; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* for control OUT, data must still get to userspace */ 8748c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 8758c2ecf20Sopenharmony_ci if (!dev->setup_in) { 8768c2ecf20Sopenharmony_ci dev->setup_out_error = (req->status != 0); 8778c2ecf20Sopenharmony_ci if (!dev->setup_out_error) 8788c2ecf20Sopenharmony_ci free = 0; 8798c2ecf20Sopenharmony_ci dev->setup_out_ready = 1; 8808c2ecf20Sopenharmony_ci ep0_readable (dev); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* clean up as appropriate */ 8848c2ecf20Sopenharmony_ci if (free && req->buf != &dev->rbuf) 8858c2ecf20Sopenharmony_ci clean_req (ep, req); 8868c2ecf20Sopenharmony_ci req->complete = epio_complete; 8878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct dev_data *dev = ep->driver_data; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (dev->setup_out_ready) { 8958c2ecf20Sopenharmony_ci DBG (dev, "ep0 request busy!\n"); 8968c2ecf20Sopenharmony_ci return -EBUSY; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci if (len > sizeof (dev->rbuf)) 8998c2ecf20Sopenharmony_ci req->buf = kmalloc(len, GFP_ATOMIC); 9008c2ecf20Sopenharmony_ci if (req->buf == NULL) { 9018c2ecf20Sopenharmony_ci req->buf = dev->rbuf; 9028c2ecf20Sopenharmony_ci return -ENOMEM; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci req->complete = ep0_complete; 9058c2ecf20Sopenharmony_ci req->length = len; 9068c2ecf20Sopenharmony_ci req->zero = 0; 9078c2ecf20Sopenharmony_ci return 0; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic ssize_t 9118c2ecf20Sopenharmony_ciep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct dev_data *dev = fd->private_data; 9148c2ecf20Sopenharmony_ci ssize_t retval; 9158c2ecf20Sopenharmony_ci enum ep0_state state; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 9188c2ecf20Sopenharmony_ci if (dev->state <= STATE_DEV_OPENED) { 9198c2ecf20Sopenharmony_ci retval = -EINVAL; 9208c2ecf20Sopenharmony_ci goto done; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* report fd mode change before acting on it */ 9248c2ecf20Sopenharmony_ci if (dev->setup_abort) { 9258c2ecf20Sopenharmony_ci dev->setup_abort = 0; 9268c2ecf20Sopenharmony_ci retval = -EIDRM; 9278c2ecf20Sopenharmony_ci goto done; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* control DATA stage */ 9318c2ecf20Sopenharmony_ci if ((state = dev->state) == STATE_DEV_SETUP) { 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (dev->setup_in) { /* stall IN */ 9348c2ecf20Sopenharmony_ci VDEBUG(dev, "ep0in stall\n"); 9358c2ecf20Sopenharmony_ci (void) usb_ep_set_halt (dev->gadget->ep0); 9368c2ecf20Sopenharmony_ci retval = -EL2HLT; 9378c2ecf20Sopenharmony_ci dev->state = STATE_DEV_CONNECTED; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci } else if (len == 0) { /* ack SET_CONFIGURATION etc */ 9408c2ecf20Sopenharmony_ci struct usb_ep *ep = dev->gadget->ep0; 9418c2ecf20Sopenharmony_ci struct usb_request *req = dev->req; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if ((retval = setup_req (ep, req, 0)) == 0) { 9448c2ecf20Sopenharmony_ci ++dev->udc_usage; 9458c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 9468c2ecf20Sopenharmony_ci retval = usb_ep_queue (ep, req, GFP_KERNEL); 9478c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 9488c2ecf20Sopenharmony_ci --dev->udc_usage; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci dev->state = STATE_DEV_CONNECTED; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* assume that was SET_CONFIGURATION */ 9538c2ecf20Sopenharmony_ci if (dev->current_config) { 9548c2ecf20Sopenharmony_ci unsigned power; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (gadget_is_dualspeed(dev->gadget) 9578c2ecf20Sopenharmony_ci && (dev->gadget->speed 9588c2ecf20Sopenharmony_ci == USB_SPEED_HIGH)) 9598c2ecf20Sopenharmony_ci power = dev->hs_config->bMaxPower; 9608c2ecf20Sopenharmony_ci else 9618c2ecf20Sopenharmony_ci power = dev->config->bMaxPower; 9628c2ecf20Sopenharmony_ci usb_gadget_vbus_draw(dev->gadget, 2 * power); 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci } else { /* collect OUT data */ 9668c2ecf20Sopenharmony_ci if ((fd->f_flags & O_NONBLOCK) != 0 9678c2ecf20Sopenharmony_ci && !dev->setup_out_ready) { 9688c2ecf20Sopenharmony_ci retval = -EAGAIN; 9698c2ecf20Sopenharmony_ci goto done; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 9728c2ecf20Sopenharmony_ci retval = wait_event_interruptible (dev->wait, 9738c2ecf20Sopenharmony_ci dev->setup_out_ready != 0); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* FIXME state could change from under us */ 9768c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 9778c2ecf20Sopenharmony_ci if (retval) 9788c2ecf20Sopenharmony_ci goto done; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (dev->state != STATE_DEV_SETUP) { 9818c2ecf20Sopenharmony_ci retval = -ECANCELED; 9828c2ecf20Sopenharmony_ci goto done; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci dev->state = STATE_DEV_CONNECTED; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (dev->setup_out_error) 9878c2ecf20Sopenharmony_ci retval = -EIO; 9888c2ecf20Sopenharmony_ci else { 9898c2ecf20Sopenharmony_ci len = min (len, (size_t)dev->req->actual); 9908c2ecf20Sopenharmony_ci ++dev->udc_usage; 9918c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 9928c2ecf20Sopenharmony_ci if (copy_to_user (buf, dev->req->buf, len)) 9938c2ecf20Sopenharmony_ci retval = -EFAULT; 9948c2ecf20Sopenharmony_ci else 9958c2ecf20Sopenharmony_ci retval = len; 9968c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 9978c2ecf20Sopenharmony_ci --dev->udc_usage; 9988c2ecf20Sopenharmony_ci clean_req (dev->gadget->ep0, dev->req); 9998c2ecf20Sopenharmony_ci /* NOTE userspace can't yet choose to stall */ 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci goto done; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* else normal: return event data */ 10068c2ecf20Sopenharmony_ci if (len < sizeof dev->event [0]) { 10078c2ecf20Sopenharmony_ci retval = -EINVAL; 10088c2ecf20Sopenharmony_ci goto done; 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci len -= len % sizeof (struct usb_gadgetfs_event); 10118c2ecf20Sopenharmony_ci dev->usermode_setup = 1; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ciscan: 10148c2ecf20Sopenharmony_ci /* return queued events right away */ 10158c2ecf20Sopenharmony_ci if (dev->ev_next != 0) { 10168c2ecf20Sopenharmony_ci unsigned i, n; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci n = len / sizeof (struct usb_gadgetfs_event); 10198c2ecf20Sopenharmony_ci if (dev->ev_next < n) 10208c2ecf20Sopenharmony_ci n = dev->ev_next; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* ep0 i/o has special semantics during STATE_DEV_SETUP */ 10238c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 10248c2ecf20Sopenharmony_ci if (dev->event [i].type == GADGETFS_SETUP) { 10258c2ecf20Sopenharmony_ci dev->state = STATE_DEV_SETUP; 10268c2ecf20Sopenharmony_ci n = i + 1; 10278c2ecf20Sopenharmony_ci break; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 10318c2ecf20Sopenharmony_ci len = n * sizeof (struct usb_gadgetfs_event); 10328c2ecf20Sopenharmony_ci if (copy_to_user (buf, &dev->event, len)) 10338c2ecf20Sopenharmony_ci retval = -EFAULT; 10348c2ecf20Sopenharmony_ci else 10358c2ecf20Sopenharmony_ci retval = len; 10368c2ecf20Sopenharmony_ci if (len > 0) { 10378c2ecf20Sopenharmony_ci /* NOTE this doesn't guard against broken drivers; 10388c2ecf20Sopenharmony_ci * concurrent ep0 readers may lose events. 10398c2ecf20Sopenharmony_ci */ 10408c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 10418c2ecf20Sopenharmony_ci if (dev->ev_next > n) { 10428c2ecf20Sopenharmony_ci memmove(&dev->event[0], &dev->event[n], 10438c2ecf20Sopenharmony_ci sizeof (struct usb_gadgetfs_event) 10448c2ecf20Sopenharmony_ci * (dev->ev_next - n)); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci dev->ev_next -= n; 10478c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci return retval; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci if (fd->f_flags & O_NONBLOCK) { 10528c2ecf20Sopenharmony_ci retval = -EAGAIN; 10538c2ecf20Sopenharmony_ci goto done; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci switch (state) { 10578c2ecf20Sopenharmony_ci default: 10588c2ecf20Sopenharmony_ci DBG (dev, "fail %s, state %d\n", __func__, state); 10598c2ecf20Sopenharmony_ci retval = -ESRCH; 10608c2ecf20Sopenharmony_ci break; 10618c2ecf20Sopenharmony_ci case STATE_DEV_UNCONNECTED: 10628c2ecf20Sopenharmony_ci case STATE_DEV_CONNECTED: 10638c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 10648c2ecf20Sopenharmony_ci DBG (dev, "%s wait\n", __func__); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* wait for events */ 10678c2ecf20Sopenharmony_ci retval = wait_event_interruptible (dev->wait, 10688c2ecf20Sopenharmony_ci dev->ev_next != 0); 10698c2ecf20Sopenharmony_ci if (retval < 0) 10708c2ecf20Sopenharmony_ci return retval; 10718c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 10728c2ecf20Sopenharmony_ci goto scan; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cidone: 10768c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 10778c2ecf20Sopenharmony_ci return retval; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic struct usb_gadgetfs_event * 10818c2ecf20Sopenharmony_cinext_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct usb_gadgetfs_event *event; 10848c2ecf20Sopenharmony_ci unsigned i; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci switch (type) { 10878c2ecf20Sopenharmony_ci /* these events purge the queue */ 10888c2ecf20Sopenharmony_ci case GADGETFS_DISCONNECT: 10898c2ecf20Sopenharmony_ci if (dev->state == STATE_DEV_SETUP) 10908c2ecf20Sopenharmony_ci dev->setup_abort = 1; 10918c2ecf20Sopenharmony_ci fallthrough; 10928c2ecf20Sopenharmony_ci case GADGETFS_CONNECT: 10938c2ecf20Sopenharmony_ci dev->ev_next = 0; 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci case GADGETFS_SETUP: /* previous request timed out */ 10968c2ecf20Sopenharmony_ci case GADGETFS_SUSPEND: /* same effect */ 10978c2ecf20Sopenharmony_ci /* these events can't be repeated */ 10988c2ecf20Sopenharmony_ci for (i = 0; i != dev->ev_next; i++) { 10998c2ecf20Sopenharmony_ci if (dev->event [i].type != type) 11008c2ecf20Sopenharmony_ci continue; 11018c2ecf20Sopenharmony_ci DBG(dev, "discard old event[%d] %d\n", i, type); 11028c2ecf20Sopenharmony_ci dev->ev_next--; 11038c2ecf20Sopenharmony_ci if (i == dev->ev_next) 11048c2ecf20Sopenharmony_ci break; 11058c2ecf20Sopenharmony_ci /* indices start at zero, for simplicity */ 11068c2ecf20Sopenharmony_ci memmove (&dev->event [i], &dev->event [i + 1], 11078c2ecf20Sopenharmony_ci sizeof (struct usb_gadgetfs_event) 11088c2ecf20Sopenharmony_ci * (dev->ev_next - i)); 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci default: 11128c2ecf20Sopenharmony_ci BUG (); 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type); 11158c2ecf20Sopenharmony_ci event = &dev->event [dev->ev_next++]; 11168c2ecf20Sopenharmony_ci BUG_ON (dev->ev_next > N_EVENT); 11178c2ecf20Sopenharmony_ci memset (event, 0, sizeof *event); 11188c2ecf20Sopenharmony_ci event->type = type; 11198c2ecf20Sopenharmony_ci return event; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cistatic ssize_t 11238c2ecf20Sopenharmony_ciep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci struct dev_data *dev = fd->private_data; 11268c2ecf20Sopenharmony_ci ssize_t retval = -ESRCH; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* report fd mode change before acting on it */ 11298c2ecf20Sopenharmony_ci if (dev->setup_abort) { 11308c2ecf20Sopenharmony_ci dev->setup_abort = 0; 11318c2ecf20Sopenharmony_ci retval = -EIDRM; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* data and/or status stage for control request */ 11348c2ecf20Sopenharmony_ci } else if (dev->state == STATE_DEV_SETUP) { 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci len = min_t(size_t, len, dev->setup_wLength); 11378c2ecf20Sopenharmony_ci if (dev->setup_in) { 11388c2ecf20Sopenharmony_ci retval = setup_req (dev->gadget->ep0, dev->req, len); 11398c2ecf20Sopenharmony_ci if (retval == 0) { 11408c2ecf20Sopenharmony_ci dev->state = STATE_DEV_CONNECTED; 11418c2ecf20Sopenharmony_ci ++dev->udc_usage; 11428c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 11438c2ecf20Sopenharmony_ci if (copy_from_user (dev->req->buf, buf, len)) 11448c2ecf20Sopenharmony_ci retval = -EFAULT; 11458c2ecf20Sopenharmony_ci else { 11468c2ecf20Sopenharmony_ci if (len < dev->setup_wLength) 11478c2ecf20Sopenharmony_ci dev->req->zero = 1; 11488c2ecf20Sopenharmony_ci retval = usb_ep_queue ( 11498c2ecf20Sopenharmony_ci dev->gadget->ep0, dev->req, 11508c2ecf20Sopenharmony_ci GFP_KERNEL); 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 11538c2ecf20Sopenharmony_ci --dev->udc_usage; 11548c2ecf20Sopenharmony_ci if (retval < 0) { 11558c2ecf20Sopenharmony_ci clean_req (dev->gadget->ep0, dev->req); 11568c2ecf20Sopenharmony_ci } else 11578c2ecf20Sopenharmony_ci retval = len; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci return retval; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* can stall some OUT transfers */ 11638c2ecf20Sopenharmony_ci } else if (dev->setup_can_stall) { 11648c2ecf20Sopenharmony_ci VDEBUG(dev, "ep0out stall\n"); 11658c2ecf20Sopenharmony_ci (void) usb_ep_set_halt (dev->gadget->ep0); 11668c2ecf20Sopenharmony_ci retval = -EL2HLT; 11678c2ecf20Sopenharmony_ci dev->state = STATE_DEV_CONNECTED; 11688c2ecf20Sopenharmony_ci } else { 11698c2ecf20Sopenharmony_ci DBG(dev, "bogus ep0out stall!\n"); 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci } else 11728c2ecf20Sopenharmony_ci DBG (dev, "fail %s, state %d\n", __func__, dev->state); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci return retval; 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic int 11788c2ecf20Sopenharmony_ciep0_fasync (int f, struct file *fd, int on) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct dev_data *dev = fd->private_data; 11818c2ecf20Sopenharmony_ci // caller must F_SETOWN before signal delivery happens 11828c2ecf20Sopenharmony_ci VDEBUG (dev, "%s %s\n", __func__, on ? "on" : "off"); 11838c2ecf20Sopenharmony_ci return fasync_helper (f, fd, on, &dev->fasync); 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic struct usb_gadget_driver gadgetfs_driver; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic int 11898c2ecf20Sopenharmony_cidev_release (struct inode *inode, struct file *fd) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci struct dev_data *dev = fd->private_data; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci /* closing ep0 === shutdown all */ 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (dev->gadget_registered) { 11968c2ecf20Sopenharmony_ci usb_gadget_unregister_driver (&gadgetfs_driver); 11978c2ecf20Sopenharmony_ci dev->gadget_registered = false; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* at this point "good" hardware has disconnected the 12018c2ecf20Sopenharmony_ci * device from USB; the host won't see it any more. 12028c2ecf20Sopenharmony_ci * alternatively, all host requests will time out. 12038c2ecf20Sopenharmony_ci */ 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci kfree (dev->buf); 12068c2ecf20Sopenharmony_ci dev->buf = NULL; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci /* other endpoints were all decoupled from this device */ 12098c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 12108c2ecf20Sopenharmony_ci dev->state = STATE_DEV_DISABLED; 12118c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci put_dev (dev); 12148c2ecf20Sopenharmony_ci return 0; 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cistatic __poll_t 12188c2ecf20Sopenharmony_ciep0_poll (struct file *fd, poll_table *wait) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci struct dev_data *dev = fd->private_data; 12218c2ecf20Sopenharmony_ci __poll_t mask = 0; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (dev->state <= STATE_DEV_OPENED) 12248c2ecf20Sopenharmony_ci return DEFAULT_POLLMASK; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci poll_wait(fd, &dev->wait, wait); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* report fd mode change before acting on it */ 12318c2ecf20Sopenharmony_ci if (dev->setup_abort) { 12328c2ecf20Sopenharmony_ci dev->setup_abort = 0; 12338c2ecf20Sopenharmony_ci mask = EPOLLHUP; 12348c2ecf20Sopenharmony_ci goto out; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (dev->state == STATE_DEV_SETUP) { 12388c2ecf20Sopenharmony_ci if (dev->setup_in || dev->setup_can_stall) 12398c2ecf20Sopenharmony_ci mask = EPOLLOUT; 12408c2ecf20Sopenharmony_ci } else { 12418c2ecf20Sopenharmony_ci if (dev->ev_next != 0) 12428c2ecf20Sopenharmony_ci mask = EPOLLIN; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ciout: 12458c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 12468c2ecf20Sopenharmony_ci return mask; 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistatic long dev_ioctl (struct file *fd, unsigned code, unsigned long value) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci struct dev_data *dev = fd->private_data; 12528c2ecf20Sopenharmony_ci struct usb_gadget *gadget = dev->gadget; 12538c2ecf20Sopenharmony_ci long ret = -ENOTTY; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 12568c2ecf20Sopenharmony_ci if (dev->state == STATE_DEV_OPENED || 12578c2ecf20Sopenharmony_ci dev->state == STATE_DEV_UNBOUND) { 12588c2ecf20Sopenharmony_ci /* Not bound to a UDC */ 12598c2ecf20Sopenharmony_ci } else if (gadget->ops->ioctl) { 12608c2ecf20Sopenharmony_ci ++dev->udc_usage; 12618c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci ret = gadget->ops->ioctl (gadget, code, value); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 12668c2ecf20Sopenharmony_ci --dev->udc_usage; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return ret; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci/* The in-kernel gadget driver handles most ep0 issues, in particular 12768c2ecf20Sopenharmony_ci * enumerating the single configuration (as provided from user space). 12778c2ecf20Sopenharmony_ci * 12788c2ecf20Sopenharmony_ci * Unrecognized ep0 requests may be handled in user space. 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cistatic void make_qualifier (struct dev_data *dev) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci struct usb_qualifier_descriptor qual; 12848c2ecf20Sopenharmony_ci struct usb_device_descriptor *desc; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci qual.bLength = sizeof qual; 12878c2ecf20Sopenharmony_ci qual.bDescriptorType = USB_DT_DEVICE_QUALIFIER; 12888c2ecf20Sopenharmony_ci qual.bcdUSB = cpu_to_le16 (0x0200); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci desc = dev->dev; 12918c2ecf20Sopenharmony_ci qual.bDeviceClass = desc->bDeviceClass; 12928c2ecf20Sopenharmony_ci qual.bDeviceSubClass = desc->bDeviceSubClass; 12938c2ecf20Sopenharmony_ci qual.bDeviceProtocol = desc->bDeviceProtocol; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* assumes ep0 uses the same value for both speeds ... */ 12968c2ecf20Sopenharmony_ci qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci qual.bNumConfigurations = 1; 12998c2ecf20Sopenharmony_ci qual.bRESERVED = 0; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci memcpy (dev->rbuf, &qual, sizeof qual); 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic int 13058c2ecf20Sopenharmony_ciconfig_buf (struct dev_data *dev, u8 type, unsigned index) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci int len; 13088c2ecf20Sopenharmony_ci int hs = 0; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci /* only one configuration */ 13118c2ecf20Sopenharmony_ci if (index > 0) 13128c2ecf20Sopenharmony_ci return -EINVAL; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (gadget_is_dualspeed(dev->gadget)) { 13158c2ecf20Sopenharmony_ci hs = (dev->gadget->speed == USB_SPEED_HIGH); 13168c2ecf20Sopenharmony_ci if (type == USB_DT_OTHER_SPEED_CONFIG) 13178c2ecf20Sopenharmony_ci hs = !hs; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci if (hs) { 13208c2ecf20Sopenharmony_ci dev->req->buf = dev->hs_config; 13218c2ecf20Sopenharmony_ci len = le16_to_cpu(dev->hs_config->wTotalLength); 13228c2ecf20Sopenharmony_ci } else { 13238c2ecf20Sopenharmony_ci dev->req->buf = dev->config; 13248c2ecf20Sopenharmony_ci len = le16_to_cpu(dev->config->wTotalLength); 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci ((u8 *)dev->req->buf) [1] = type; 13278c2ecf20Sopenharmony_ci return len; 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic int 13318c2ecf20Sopenharmony_cigadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct dev_data *dev = get_gadget_data (gadget); 13348c2ecf20Sopenharmony_ci struct usb_request *req = dev->req; 13358c2ecf20Sopenharmony_ci int value = -EOPNOTSUPP; 13368c2ecf20Sopenharmony_ci struct usb_gadgetfs_event *event; 13378c2ecf20Sopenharmony_ci u16 w_value = le16_to_cpu(ctrl->wValue); 13388c2ecf20Sopenharmony_ci u16 w_length = le16_to_cpu(ctrl->wLength); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (w_length > RBUF_SIZE) { 13418c2ecf20Sopenharmony_ci if (ctrl->bRequestType & USB_DIR_IN) { 13428c2ecf20Sopenharmony_ci /* Cast away the const, we are going to overwrite on purpose. */ 13438c2ecf20Sopenharmony_ci __le16 *temp = (__le16 *)&ctrl->wLength; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci *temp = cpu_to_le16(RBUF_SIZE); 13468c2ecf20Sopenharmony_ci w_length = RBUF_SIZE; 13478c2ecf20Sopenharmony_ci } else { 13488c2ecf20Sopenharmony_ci return value; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci spin_lock (&dev->lock); 13538c2ecf20Sopenharmony_ci dev->setup_abort = 0; 13548c2ecf20Sopenharmony_ci if (dev->state == STATE_DEV_UNCONNECTED) { 13558c2ecf20Sopenharmony_ci if (gadget_is_dualspeed(gadget) 13568c2ecf20Sopenharmony_ci && gadget->speed == USB_SPEED_HIGH 13578c2ecf20Sopenharmony_ci && dev->hs_config == NULL) { 13588c2ecf20Sopenharmony_ci spin_unlock(&dev->lock); 13598c2ecf20Sopenharmony_ci ERROR (dev, "no high speed config??\n"); 13608c2ecf20Sopenharmony_ci return -EINVAL; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci dev->state = STATE_DEV_CONNECTED; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci INFO (dev, "connected\n"); 13668c2ecf20Sopenharmony_ci event = next_event (dev, GADGETFS_CONNECT); 13678c2ecf20Sopenharmony_ci event->u.speed = gadget->speed; 13688c2ecf20Sopenharmony_ci ep0_readable (dev); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci /* host may have given up waiting for response. we can miss control 13718c2ecf20Sopenharmony_ci * requests handled lower down (device/endpoint status and features); 13728c2ecf20Sopenharmony_ci * then ep0_{read,write} will report the wrong status. controller 13738c2ecf20Sopenharmony_ci * driver will have aborted pending i/o. 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_ci } else if (dev->state == STATE_DEV_SETUP) 13768c2ecf20Sopenharmony_ci dev->setup_abort = 1; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci req->buf = dev->rbuf; 13798c2ecf20Sopenharmony_ci req->context = NULL; 13808c2ecf20Sopenharmony_ci switch (ctrl->bRequest) { 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci case USB_REQ_GET_DESCRIPTOR: 13838c2ecf20Sopenharmony_ci if (ctrl->bRequestType != USB_DIR_IN) 13848c2ecf20Sopenharmony_ci goto unrecognized; 13858c2ecf20Sopenharmony_ci switch (w_value >> 8) { 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci case USB_DT_DEVICE: 13888c2ecf20Sopenharmony_ci value = min (w_length, (u16) sizeof *dev->dev); 13898c2ecf20Sopenharmony_ci dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket; 13908c2ecf20Sopenharmony_ci req->buf = dev->dev; 13918c2ecf20Sopenharmony_ci break; 13928c2ecf20Sopenharmony_ci case USB_DT_DEVICE_QUALIFIER: 13938c2ecf20Sopenharmony_ci if (!dev->hs_config) 13948c2ecf20Sopenharmony_ci break; 13958c2ecf20Sopenharmony_ci value = min (w_length, (u16) 13968c2ecf20Sopenharmony_ci sizeof (struct usb_qualifier_descriptor)); 13978c2ecf20Sopenharmony_ci make_qualifier (dev); 13988c2ecf20Sopenharmony_ci break; 13998c2ecf20Sopenharmony_ci case USB_DT_OTHER_SPEED_CONFIG: 14008c2ecf20Sopenharmony_ci case USB_DT_CONFIG: 14018c2ecf20Sopenharmony_ci value = config_buf (dev, 14028c2ecf20Sopenharmony_ci w_value >> 8, 14038c2ecf20Sopenharmony_ci w_value & 0xff); 14048c2ecf20Sopenharmony_ci if (value >= 0) 14058c2ecf20Sopenharmony_ci value = min (w_length, (u16) value); 14068c2ecf20Sopenharmony_ci break; 14078c2ecf20Sopenharmony_ci case USB_DT_STRING: 14088c2ecf20Sopenharmony_ci goto unrecognized; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci default: // all others are errors 14118c2ecf20Sopenharmony_ci break; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci break; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* currently one config, two speeds */ 14168c2ecf20Sopenharmony_ci case USB_REQ_SET_CONFIGURATION: 14178c2ecf20Sopenharmony_ci if (ctrl->bRequestType != 0) 14188c2ecf20Sopenharmony_ci goto unrecognized; 14198c2ecf20Sopenharmony_ci if (0 == (u8) w_value) { 14208c2ecf20Sopenharmony_ci value = 0; 14218c2ecf20Sopenharmony_ci dev->current_config = 0; 14228c2ecf20Sopenharmony_ci usb_gadget_vbus_draw(gadget, 8 /* mA */ ); 14238c2ecf20Sopenharmony_ci // user mode expected to disable endpoints 14248c2ecf20Sopenharmony_ci } else { 14258c2ecf20Sopenharmony_ci u8 config, power; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (gadget_is_dualspeed(gadget) 14288c2ecf20Sopenharmony_ci && gadget->speed == USB_SPEED_HIGH) { 14298c2ecf20Sopenharmony_ci config = dev->hs_config->bConfigurationValue; 14308c2ecf20Sopenharmony_ci power = dev->hs_config->bMaxPower; 14318c2ecf20Sopenharmony_ci } else { 14328c2ecf20Sopenharmony_ci config = dev->config->bConfigurationValue; 14338c2ecf20Sopenharmony_ci power = dev->config->bMaxPower; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci if (config == (u8) w_value) { 14378c2ecf20Sopenharmony_ci value = 0; 14388c2ecf20Sopenharmony_ci dev->current_config = config; 14398c2ecf20Sopenharmony_ci usb_gadget_vbus_draw(gadget, 2 * power); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci /* report SET_CONFIGURATION like any other control request, 14448c2ecf20Sopenharmony_ci * except that usermode may not stall this. the next 14458c2ecf20Sopenharmony_ci * request mustn't be allowed start until this finishes: 14468c2ecf20Sopenharmony_ci * endpoints and threads set up, etc. 14478c2ecf20Sopenharmony_ci * 14488c2ecf20Sopenharmony_ci * NOTE: older PXA hardware (before PXA 255: without UDCCFR) 14498c2ecf20Sopenharmony_ci * has bad/racey automagic that prevents synchronizing here. 14508c2ecf20Sopenharmony_ci * even kernel mode drivers often miss them. 14518c2ecf20Sopenharmony_ci */ 14528c2ecf20Sopenharmony_ci if (value == 0) { 14538c2ecf20Sopenharmony_ci INFO (dev, "configuration #%d\n", dev->current_config); 14548c2ecf20Sopenharmony_ci usb_gadget_set_state(gadget, USB_STATE_CONFIGURED); 14558c2ecf20Sopenharmony_ci if (dev->usermode_setup) { 14568c2ecf20Sopenharmony_ci dev->setup_can_stall = 0; 14578c2ecf20Sopenharmony_ci goto delegate; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci break; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci#ifndef CONFIG_USB_PXA25X 14638c2ecf20Sopenharmony_ci /* PXA automagically handles this request too */ 14648c2ecf20Sopenharmony_ci case USB_REQ_GET_CONFIGURATION: 14658c2ecf20Sopenharmony_ci if (ctrl->bRequestType != 0x80) 14668c2ecf20Sopenharmony_ci goto unrecognized; 14678c2ecf20Sopenharmony_ci *(u8 *)req->buf = dev->current_config; 14688c2ecf20Sopenharmony_ci value = min (w_length, (u16) 1); 14698c2ecf20Sopenharmony_ci break; 14708c2ecf20Sopenharmony_ci#endif 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci default: 14738c2ecf20Sopenharmony_ciunrecognized: 14748c2ecf20Sopenharmony_ci VDEBUG (dev, "%s req%02x.%02x v%04x i%04x l%d\n", 14758c2ecf20Sopenharmony_ci dev->usermode_setup ? "delegate" : "fail", 14768c2ecf20Sopenharmony_ci ctrl->bRequestType, ctrl->bRequest, 14778c2ecf20Sopenharmony_ci w_value, le16_to_cpu(ctrl->wIndex), w_length); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci /* if there's an ep0 reader, don't stall */ 14808c2ecf20Sopenharmony_ci if (dev->usermode_setup) { 14818c2ecf20Sopenharmony_ci dev->setup_can_stall = 1; 14828c2ecf20Sopenharmony_cidelegate: 14838c2ecf20Sopenharmony_ci dev->setup_in = (ctrl->bRequestType & USB_DIR_IN) 14848c2ecf20Sopenharmony_ci ? 1 : 0; 14858c2ecf20Sopenharmony_ci dev->setup_wLength = w_length; 14868c2ecf20Sopenharmony_ci dev->setup_out_ready = 0; 14878c2ecf20Sopenharmony_ci dev->setup_out_error = 0; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci /* read DATA stage for OUT right away */ 14908c2ecf20Sopenharmony_ci if (unlikely (!dev->setup_in && w_length)) { 14918c2ecf20Sopenharmony_ci value = setup_req (gadget->ep0, dev->req, 14928c2ecf20Sopenharmony_ci w_length); 14938c2ecf20Sopenharmony_ci if (value < 0) 14948c2ecf20Sopenharmony_ci break; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci ++dev->udc_usage; 14978c2ecf20Sopenharmony_ci spin_unlock (&dev->lock); 14988c2ecf20Sopenharmony_ci value = usb_ep_queue (gadget->ep0, dev->req, 14998c2ecf20Sopenharmony_ci GFP_KERNEL); 15008c2ecf20Sopenharmony_ci spin_lock (&dev->lock); 15018c2ecf20Sopenharmony_ci --dev->udc_usage; 15028c2ecf20Sopenharmony_ci if (value < 0) { 15038c2ecf20Sopenharmony_ci clean_req (gadget->ep0, dev->req); 15048c2ecf20Sopenharmony_ci break; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* we can't currently stall these */ 15088c2ecf20Sopenharmony_ci dev->setup_can_stall = 0; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci /* state changes when reader collects event */ 15128c2ecf20Sopenharmony_ci event = next_event (dev, GADGETFS_SETUP); 15138c2ecf20Sopenharmony_ci event->u.setup = *ctrl; 15148c2ecf20Sopenharmony_ci ep0_readable (dev); 15158c2ecf20Sopenharmony_ci spin_unlock (&dev->lock); 15168c2ecf20Sopenharmony_ci return 0; 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci /* proceed with data transfer and status phases? */ 15218c2ecf20Sopenharmony_ci if (value >= 0 && dev->state != STATE_DEV_SETUP) { 15228c2ecf20Sopenharmony_ci req->length = value; 15238c2ecf20Sopenharmony_ci req->zero = value < w_length; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci ++dev->udc_usage; 15268c2ecf20Sopenharmony_ci spin_unlock (&dev->lock); 15278c2ecf20Sopenharmony_ci value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL); 15288c2ecf20Sopenharmony_ci spin_lock(&dev->lock); 15298c2ecf20Sopenharmony_ci --dev->udc_usage; 15308c2ecf20Sopenharmony_ci spin_unlock(&dev->lock); 15318c2ecf20Sopenharmony_ci if (value < 0) { 15328c2ecf20Sopenharmony_ci DBG (dev, "ep_queue --> %d\n", value); 15338c2ecf20Sopenharmony_ci req->status = 0; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci return value; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci /* device stalls when value < 0 */ 15398c2ecf20Sopenharmony_ci spin_unlock (&dev->lock); 15408c2ecf20Sopenharmony_ci return value; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic void destroy_ep_files (struct dev_data *dev) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci DBG (dev, "%s %d\n", __func__, dev->state); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci /* dev->state must prevent interference */ 15488c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 15498c2ecf20Sopenharmony_ci while (!list_empty(&dev->epfiles)) { 15508c2ecf20Sopenharmony_ci struct ep_data *ep; 15518c2ecf20Sopenharmony_ci struct inode *parent; 15528c2ecf20Sopenharmony_ci struct dentry *dentry; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci /* break link to FS */ 15558c2ecf20Sopenharmony_ci ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles); 15568c2ecf20Sopenharmony_ci list_del_init (&ep->epfiles); 15578c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci dentry = ep->dentry; 15608c2ecf20Sopenharmony_ci ep->dentry = NULL; 15618c2ecf20Sopenharmony_ci parent = d_inode(dentry->d_parent); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* break link to controller */ 15648c2ecf20Sopenharmony_ci mutex_lock(&ep->lock); 15658c2ecf20Sopenharmony_ci if (ep->state == STATE_EP_ENABLED) 15668c2ecf20Sopenharmony_ci (void) usb_ep_disable (ep->ep); 15678c2ecf20Sopenharmony_ci ep->state = STATE_EP_UNBOUND; 15688c2ecf20Sopenharmony_ci usb_ep_free_request (ep->ep, ep->req); 15698c2ecf20Sopenharmony_ci ep->ep = NULL; 15708c2ecf20Sopenharmony_ci mutex_unlock(&ep->lock); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci wake_up (&ep->wait); 15738c2ecf20Sopenharmony_ci put_ep (ep); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci /* break link to dcache */ 15768c2ecf20Sopenharmony_ci inode_lock(parent); 15778c2ecf20Sopenharmony_ci d_delete (dentry); 15788c2ecf20Sopenharmony_ci dput (dentry); 15798c2ecf20Sopenharmony_ci inode_unlock(parent); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic struct dentry * 15888c2ecf20Sopenharmony_cigadgetfs_create_file (struct super_block *sb, char const *name, 15898c2ecf20Sopenharmony_ci void *data, const struct file_operations *fops); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int activate_ep_files (struct dev_data *dev) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci struct usb_ep *ep; 15948c2ecf20Sopenharmony_ci struct ep_data *data; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci gadget_for_each_ep (ep, dev->gadget) { 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 15998c2ecf20Sopenharmony_ci if (!data) 16008c2ecf20Sopenharmony_ci goto enomem0; 16018c2ecf20Sopenharmony_ci data->state = STATE_EP_DISABLED; 16028c2ecf20Sopenharmony_ci mutex_init(&data->lock); 16038c2ecf20Sopenharmony_ci init_waitqueue_head (&data->wait); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci strncpy (data->name, ep->name, sizeof (data->name) - 1); 16068c2ecf20Sopenharmony_ci refcount_set (&data->count, 1); 16078c2ecf20Sopenharmony_ci data->dev = dev; 16088c2ecf20Sopenharmony_ci get_dev (dev); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci data->ep = ep; 16118c2ecf20Sopenharmony_ci ep->driver_data = data; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci data->req = usb_ep_alloc_request (ep, GFP_KERNEL); 16148c2ecf20Sopenharmony_ci if (!data->req) 16158c2ecf20Sopenharmony_ci goto enomem1; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci data->dentry = gadgetfs_create_file (dev->sb, data->name, 16188c2ecf20Sopenharmony_ci data, &ep_io_operations); 16198c2ecf20Sopenharmony_ci if (!data->dentry) 16208c2ecf20Sopenharmony_ci goto enomem2; 16218c2ecf20Sopenharmony_ci list_add_tail (&data->epfiles, &dev->epfiles); 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci return 0; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_cienomem2: 16268c2ecf20Sopenharmony_ci usb_ep_free_request (ep, data->req); 16278c2ecf20Sopenharmony_cienomem1: 16288c2ecf20Sopenharmony_ci put_dev (dev); 16298c2ecf20Sopenharmony_ci kfree (data); 16308c2ecf20Sopenharmony_cienomem0: 16318c2ecf20Sopenharmony_ci DBG (dev, "%s enomem\n", __func__); 16328c2ecf20Sopenharmony_ci destroy_ep_files (dev); 16338c2ecf20Sopenharmony_ci return -ENOMEM; 16348c2ecf20Sopenharmony_ci} 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_cistatic void 16378c2ecf20Sopenharmony_cigadgetfs_unbind (struct usb_gadget *gadget) 16388c2ecf20Sopenharmony_ci{ 16398c2ecf20Sopenharmony_ci struct dev_data *dev = get_gadget_data (gadget); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci DBG (dev, "%s\n", __func__); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 16448c2ecf20Sopenharmony_ci dev->state = STATE_DEV_UNBOUND; 16458c2ecf20Sopenharmony_ci while (dev->udc_usage > 0) { 16468c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 16478c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 16488c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci destroy_ep_files (dev); 16538c2ecf20Sopenharmony_ci gadget->ep0->driver_data = NULL; 16548c2ecf20Sopenharmony_ci set_gadget_data (gadget, NULL); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci /* we've already been disconnected ... no i/o is active */ 16578c2ecf20Sopenharmony_ci if (dev->req) 16588c2ecf20Sopenharmony_ci usb_ep_free_request (gadget->ep0, dev->req); 16598c2ecf20Sopenharmony_ci DBG (dev, "%s done\n", __func__); 16608c2ecf20Sopenharmony_ci put_dev (dev); 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic struct dev_data *the_device; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic int gadgetfs_bind(struct usb_gadget *gadget, 16668c2ecf20Sopenharmony_ci struct usb_gadget_driver *driver) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct dev_data *dev = the_device; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci if (!dev) 16718c2ecf20Sopenharmony_ci return -ESRCH; 16728c2ecf20Sopenharmony_ci if (0 != strcmp (CHIP, gadget->name)) { 16738c2ecf20Sopenharmony_ci pr_err("%s expected %s controller not %s\n", 16748c2ecf20Sopenharmony_ci shortname, CHIP, gadget->name); 16758c2ecf20Sopenharmony_ci return -ENODEV; 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci set_gadget_data (gadget, dev); 16798c2ecf20Sopenharmony_ci dev->gadget = gadget; 16808c2ecf20Sopenharmony_ci gadget->ep0->driver_data = dev; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci /* preallocate control response and buffer */ 16838c2ecf20Sopenharmony_ci dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); 16848c2ecf20Sopenharmony_ci if (!dev->req) 16858c2ecf20Sopenharmony_ci goto enomem; 16868c2ecf20Sopenharmony_ci dev->req->context = NULL; 16878c2ecf20Sopenharmony_ci dev->req->complete = epio_complete; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci if (activate_ep_files (dev) < 0) 16908c2ecf20Sopenharmony_ci goto enomem; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci INFO (dev, "bound to %s driver\n", gadget->name); 16938c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 16948c2ecf20Sopenharmony_ci dev->state = STATE_DEV_UNCONNECTED; 16958c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 16968c2ecf20Sopenharmony_ci get_dev (dev); 16978c2ecf20Sopenharmony_ci return 0; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_cienomem: 17008c2ecf20Sopenharmony_ci gadgetfs_unbind (gadget); 17018c2ecf20Sopenharmony_ci return -ENOMEM; 17028c2ecf20Sopenharmony_ci} 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_cistatic void 17058c2ecf20Sopenharmony_cigadgetfs_disconnect (struct usb_gadget *gadget) 17068c2ecf20Sopenharmony_ci{ 17078c2ecf20Sopenharmony_ci struct dev_data *dev = get_gadget_data (gadget); 17088c2ecf20Sopenharmony_ci unsigned long flags; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci spin_lock_irqsave (&dev->lock, flags); 17118c2ecf20Sopenharmony_ci if (dev->state == STATE_DEV_UNCONNECTED) 17128c2ecf20Sopenharmony_ci goto exit; 17138c2ecf20Sopenharmony_ci dev->state = STATE_DEV_UNCONNECTED; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci INFO (dev, "disconnected\n"); 17168c2ecf20Sopenharmony_ci next_event (dev, GADGETFS_DISCONNECT); 17178c2ecf20Sopenharmony_ci ep0_readable (dev); 17188c2ecf20Sopenharmony_ciexit: 17198c2ecf20Sopenharmony_ci spin_unlock_irqrestore (&dev->lock, flags); 17208c2ecf20Sopenharmony_ci} 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_cistatic void 17238c2ecf20Sopenharmony_cigadgetfs_suspend (struct usb_gadget *gadget) 17248c2ecf20Sopenharmony_ci{ 17258c2ecf20Sopenharmony_ci struct dev_data *dev = get_gadget_data (gadget); 17268c2ecf20Sopenharmony_ci unsigned long flags; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci INFO (dev, "suspended from state %d\n", dev->state); 17298c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 17308c2ecf20Sopenharmony_ci switch (dev->state) { 17318c2ecf20Sopenharmony_ci case STATE_DEV_SETUP: // VERY odd... host died?? 17328c2ecf20Sopenharmony_ci case STATE_DEV_CONNECTED: 17338c2ecf20Sopenharmony_ci case STATE_DEV_UNCONNECTED: 17348c2ecf20Sopenharmony_ci next_event (dev, GADGETFS_SUSPEND); 17358c2ecf20Sopenharmony_ci ep0_readable (dev); 17368c2ecf20Sopenharmony_ci fallthrough; 17378c2ecf20Sopenharmony_ci default: 17388c2ecf20Sopenharmony_ci break; 17398c2ecf20Sopenharmony_ci } 17408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 17418c2ecf20Sopenharmony_ci} 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cistatic struct usb_gadget_driver gadgetfs_driver = { 17448c2ecf20Sopenharmony_ci .function = (char *) driver_desc, 17458c2ecf20Sopenharmony_ci .bind = gadgetfs_bind, 17468c2ecf20Sopenharmony_ci .unbind = gadgetfs_unbind, 17478c2ecf20Sopenharmony_ci .setup = gadgetfs_setup, 17488c2ecf20Sopenharmony_ci .reset = gadgetfs_disconnect, 17498c2ecf20Sopenharmony_ci .disconnect = gadgetfs_disconnect, 17508c2ecf20Sopenharmony_ci .suspend = gadgetfs_suspend, 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci .driver = { 17538c2ecf20Sopenharmony_ci .name = shortname, 17548c2ecf20Sopenharmony_ci }, 17558c2ecf20Sopenharmony_ci}; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 17588c2ecf20Sopenharmony_ci/* DEVICE INITIALIZATION 17598c2ecf20Sopenharmony_ci * 17608c2ecf20Sopenharmony_ci * fd = open ("/dev/gadget/$CHIP", O_RDWR) 17618c2ecf20Sopenharmony_ci * status = write (fd, descriptors, sizeof descriptors) 17628c2ecf20Sopenharmony_ci * 17638c2ecf20Sopenharmony_ci * That write establishes the device configuration, so the kernel can 17648c2ecf20Sopenharmony_ci * bind to the controller ... guaranteeing it can handle enumeration 17658c2ecf20Sopenharmony_ci * at all necessary speeds. Descriptor order is: 17668c2ecf20Sopenharmony_ci * 17678c2ecf20Sopenharmony_ci * . message tag (u32, host order) ... for now, must be zero; it 17688c2ecf20Sopenharmony_ci * would change to support features like multi-config devices 17698c2ecf20Sopenharmony_ci * . full/low speed config ... all wTotalLength bytes (with interface, 17708c2ecf20Sopenharmony_ci * class, altsetting, endpoint, and other descriptors) 17718c2ecf20Sopenharmony_ci * . high speed config ... all descriptors, for high speed operation; 17728c2ecf20Sopenharmony_ci * this one's optional except for high-speed hardware 17738c2ecf20Sopenharmony_ci * . device descriptor 17748c2ecf20Sopenharmony_ci * 17758c2ecf20Sopenharmony_ci * Endpoints are not yet enabled. Drivers must wait until device 17768c2ecf20Sopenharmony_ci * configuration and interface altsetting changes create 17778c2ecf20Sopenharmony_ci * the need to configure (or unconfigure) them. 17788c2ecf20Sopenharmony_ci * 17798c2ecf20Sopenharmony_ci * After initialization, the device stays active for as long as that 17808c2ecf20Sopenharmony_ci * $CHIP file is open. Events must then be read from that descriptor, 17818c2ecf20Sopenharmony_ci * such as configuration notifications. 17828c2ecf20Sopenharmony_ci */ 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_cistatic int is_valid_config(struct usb_config_descriptor *config, 17858c2ecf20Sopenharmony_ci unsigned int total) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci return config->bDescriptorType == USB_DT_CONFIG 17888c2ecf20Sopenharmony_ci && config->bLength == USB_DT_CONFIG_SIZE 17898c2ecf20Sopenharmony_ci && total >= USB_DT_CONFIG_SIZE 17908c2ecf20Sopenharmony_ci && config->bConfigurationValue != 0 17918c2ecf20Sopenharmony_ci && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 17928c2ecf20Sopenharmony_ci && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; 17938c2ecf20Sopenharmony_ci /* FIXME if gadget->is_otg, _must_ include an otg descriptor */ 17948c2ecf20Sopenharmony_ci /* FIXME check lengths: walk to end */ 17958c2ecf20Sopenharmony_ci} 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_cistatic ssize_t 17988c2ecf20Sopenharmony_cidev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) 17998c2ecf20Sopenharmony_ci{ 18008c2ecf20Sopenharmony_ci struct dev_data *dev = fd->private_data; 18018c2ecf20Sopenharmony_ci ssize_t value, length = len; 18028c2ecf20Sopenharmony_ci unsigned total; 18038c2ecf20Sopenharmony_ci u32 tag; 18048c2ecf20Sopenharmony_ci char *kbuf; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 18078c2ecf20Sopenharmony_ci if (dev->state > STATE_DEV_OPENED) { 18088c2ecf20Sopenharmony_ci value = ep0_write(fd, buf, len, ptr); 18098c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 18108c2ecf20Sopenharmony_ci return value; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci if ((len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) || 18158c2ecf20Sopenharmony_ci (len > PAGE_SIZE * 4)) 18168c2ecf20Sopenharmony_ci return -EINVAL; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci /* we might need to change message format someday */ 18198c2ecf20Sopenharmony_ci if (copy_from_user (&tag, buf, 4)) 18208c2ecf20Sopenharmony_ci return -EFAULT; 18218c2ecf20Sopenharmony_ci if (tag != 0) 18228c2ecf20Sopenharmony_ci return -EINVAL; 18238c2ecf20Sopenharmony_ci buf += 4; 18248c2ecf20Sopenharmony_ci length -= 4; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci kbuf = memdup_user(buf, length); 18278c2ecf20Sopenharmony_ci if (IS_ERR(kbuf)) 18288c2ecf20Sopenharmony_ci return PTR_ERR(kbuf); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci spin_lock_irq (&dev->lock); 18318c2ecf20Sopenharmony_ci value = -EINVAL; 18328c2ecf20Sopenharmony_ci if (dev->buf) { 18338c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 18348c2ecf20Sopenharmony_ci kfree(kbuf); 18358c2ecf20Sopenharmony_ci return value; 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci dev->buf = kbuf; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci /* full or low speed config */ 18408c2ecf20Sopenharmony_ci dev->config = (void *) kbuf; 18418c2ecf20Sopenharmony_ci total = le16_to_cpu(dev->config->wTotalLength); 18428c2ecf20Sopenharmony_ci if (!is_valid_config(dev->config, total) || 18438c2ecf20Sopenharmony_ci total > length - USB_DT_DEVICE_SIZE) 18448c2ecf20Sopenharmony_ci goto fail; 18458c2ecf20Sopenharmony_ci kbuf += total; 18468c2ecf20Sopenharmony_ci length -= total; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci /* optional high speed config */ 18498c2ecf20Sopenharmony_ci if (kbuf [1] == USB_DT_CONFIG) { 18508c2ecf20Sopenharmony_ci dev->hs_config = (void *) kbuf; 18518c2ecf20Sopenharmony_ci total = le16_to_cpu(dev->hs_config->wTotalLength); 18528c2ecf20Sopenharmony_ci if (!is_valid_config(dev->hs_config, total) || 18538c2ecf20Sopenharmony_ci total > length - USB_DT_DEVICE_SIZE) 18548c2ecf20Sopenharmony_ci goto fail; 18558c2ecf20Sopenharmony_ci kbuf += total; 18568c2ecf20Sopenharmony_ci length -= total; 18578c2ecf20Sopenharmony_ci } else { 18588c2ecf20Sopenharmony_ci dev->hs_config = NULL; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci /* could support multiple configs, using another encoding! */ 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci /* device descriptor (tweaked for paranoia) */ 18648c2ecf20Sopenharmony_ci if (length != USB_DT_DEVICE_SIZE) 18658c2ecf20Sopenharmony_ci goto fail; 18668c2ecf20Sopenharmony_ci dev->dev = (void *)kbuf; 18678c2ecf20Sopenharmony_ci if (dev->dev->bLength != USB_DT_DEVICE_SIZE 18688c2ecf20Sopenharmony_ci || dev->dev->bDescriptorType != USB_DT_DEVICE 18698c2ecf20Sopenharmony_ci || dev->dev->bNumConfigurations != 1) 18708c2ecf20Sopenharmony_ci goto fail; 18718c2ecf20Sopenharmony_ci dev->dev->bcdUSB = cpu_to_le16 (0x0200); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci /* triggers gadgetfs_bind(); then we can enumerate. */ 18748c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 18758c2ecf20Sopenharmony_ci if (dev->hs_config) 18768c2ecf20Sopenharmony_ci gadgetfs_driver.max_speed = USB_SPEED_HIGH; 18778c2ecf20Sopenharmony_ci else 18788c2ecf20Sopenharmony_ci gadgetfs_driver.max_speed = USB_SPEED_FULL; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci value = usb_gadget_probe_driver(&gadgetfs_driver); 18818c2ecf20Sopenharmony_ci if (value != 0) { 18828c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 18838c2ecf20Sopenharmony_ci goto fail; 18848c2ecf20Sopenharmony_ci } else { 18858c2ecf20Sopenharmony_ci /* at this point "good" hardware has for the first time 18868c2ecf20Sopenharmony_ci * let the USB the host see us. alternatively, if users 18878c2ecf20Sopenharmony_ci * unplug/replug that will clear all the error state. 18888c2ecf20Sopenharmony_ci * 18898c2ecf20Sopenharmony_ci * note: everything running before here was guaranteed 18908c2ecf20Sopenharmony_ci * to choke driver model style diagnostics. from here 18918c2ecf20Sopenharmony_ci * on, they can work ... except in cleanup paths that 18928c2ecf20Sopenharmony_ci * kick in after the ep0 descriptor is closed. 18938c2ecf20Sopenharmony_ci */ 18948c2ecf20Sopenharmony_ci value = len; 18958c2ecf20Sopenharmony_ci dev->gadget_registered = true; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci return value; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_cifail: 19008c2ecf20Sopenharmony_ci dev->config = NULL; 19018c2ecf20Sopenharmony_ci dev->hs_config = NULL; 19028c2ecf20Sopenharmony_ci dev->dev = NULL; 19038c2ecf20Sopenharmony_ci spin_unlock_irq (&dev->lock); 19048c2ecf20Sopenharmony_ci pr_debug ("%s: %s fail %zd, %p\n", shortname, __func__, value, dev); 19058c2ecf20Sopenharmony_ci kfree (dev->buf); 19068c2ecf20Sopenharmony_ci dev->buf = NULL; 19078c2ecf20Sopenharmony_ci return value; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_cistatic int 19118c2ecf20Sopenharmony_cidev_open (struct inode *inode, struct file *fd) 19128c2ecf20Sopenharmony_ci{ 19138c2ecf20Sopenharmony_ci struct dev_data *dev = inode->i_private; 19148c2ecf20Sopenharmony_ci int value = -EBUSY; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci spin_lock_irq(&dev->lock); 19178c2ecf20Sopenharmony_ci if (dev->state == STATE_DEV_DISABLED) { 19188c2ecf20Sopenharmony_ci dev->ev_next = 0; 19198c2ecf20Sopenharmony_ci dev->state = STATE_DEV_OPENED; 19208c2ecf20Sopenharmony_ci fd->private_data = dev; 19218c2ecf20Sopenharmony_ci get_dev (dev); 19228c2ecf20Sopenharmony_ci value = 0; 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->lock); 19258c2ecf20Sopenharmony_ci return value; 19268c2ecf20Sopenharmony_ci} 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_cistatic const struct file_operations ep0_operations = { 19298c2ecf20Sopenharmony_ci .llseek = no_llseek, 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci .open = dev_open, 19328c2ecf20Sopenharmony_ci .read = ep0_read, 19338c2ecf20Sopenharmony_ci .write = dev_config, 19348c2ecf20Sopenharmony_ci .fasync = ep0_fasync, 19358c2ecf20Sopenharmony_ci .poll = ep0_poll, 19368c2ecf20Sopenharmony_ci .unlocked_ioctl = dev_ioctl, 19378c2ecf20Sopenharmony_ci .release = dev_release, 19388c2ecf20Sopenharmony_ci}; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci/* FILESYSTEM AND SUPERBLOCK OPERATIONS 19438c2ecf20Sopenharmony_ci * 19448c2ecf20Sopenharmony_ci * Mounting the filesystem creates a controller file, used first for 19458c2ecf20Sopenharmony_ci * device configuration then later for event monitoring. 19468c2ecf20Sopenharmony_ci */ 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci/* FIXME PAM etc could set this security policy without mount options 19508c2ecf20Sopenharmony_ci * if epfiles inherited ownership and permissons from ep0 ... 19518c2ecf20Sopenharmony_ci */ 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_cistatic unsigned default_uid; 19548c2ecf20Sopenharmony_cistatic unsigned default_gid; 19558c2ecf20Sopenharmony_cistatic unsigned default_perm = S_IRUSR | S_IWUSR; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_cimodule_param (default_uid, uint, 0644); 19588c2ecf20Sopenharmony_cimodule_param (default_gid, uint, 0644); 19598c2ecf20Sopenharmony_cimodule_param (default_perm, uint, 0644); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_cistatic struct inode * 19638c2ecf20Sopenharmony_cigadgetfs_make_inode (struct super_block *sb, 19648c2ecf20Sopenharmony_ci void *data, const struct file_operations *fops, 19658c2ecf20Sopenharmony_ci int mode) 19668c2ecf20Sopenharmony_ci{ 19678c2ecf20Sopenharmony_ci struct inode *inode = new_inode (sb); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci if (inode) { 19708c2ecf20Sopenharmony_ci inode->i_ino = get_next_ino(); 19718c2ecf20Sopenharmony_ci inode->i_mode = mode; 19728c2ecf20Sopenharmony_ci inode->i_uid = make_kuid(&init_user_ns, default_uid); 19738c2ecf20Sopenharmony_ci inode->i_gid = make_kgid(&init_user_ns, default_gid); 19748c2ecf20Sopenharmony_ci inode->i_atime = inode->i_mtime = inode->i_ctime 19758c2ecf20Sopenharmony_ci = current_time(inode); 19768c2ecf20Sopenharmony_ci inode->i_private = data; 19778c2ecf20Sopenharmony_ci inode->i_fop = fops; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci return inode; 19808c2ecf20Sopenharmony_ci} 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci/* creates in fs root directory, so non-renamable and non-linkable. 19838c2ecf20Sopenharmony_ci * so inode and dentry are paired, until device reconfig. 19848c2ecf20Sopenharmony_ci */ 19858c2ecf20Sopenharmony_cistatic struct dentry * 19868c2ecf20Sopenharmony_cigadgetfs_create_file (struct super_block *sb, char const *name, 19878c2ecf20Sopenharmony_ci void *data, const struct file_operations *fops) 19888c2ecf20Sopenharmony_ci{ 19898c2ecf20Sopenharmony_ci struct dentry *dentry; 19908c2ecf20Sopenharmony_ci struct inode *inode; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci dentry = d_alloc_name(sb->s_root, name); 19938c2ecf20Sopenharmony_ci if (!dentry) 19948c2ecf20Sopenharmony_ci return NULL; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci inode = gadgetfs_make_inode (sb, data, fops, 19978c2ecf20Sopenharmony_ci S_IFREG | (default_perm & S_IRWXUGO)); 19988c2ecf20Sopenharmony_ci if (!inode) { 19998c2ecf20Sopenharmony_ci dput(dentry); 20008c2ecf20Sopenharmony_ci return NULL; 20018c2ecf20Sopenharmony_ci } 20028c2ecf20Sopenharmony_ci d_add (dentry, inode); 20038c2ecf20Sopenharmony_ci return dentry; 20048c2ecf20Sopenharmony_ci} 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_cistatic const struct super_operations gadget_fs_operations = { 20078c2ecf20Sopenharmony_ci .statfs = simple_statfs, 20088c2ecf20Sopenharmony_ci .drop_inode = generic_delete_inode, 20098c2ecf20Sopenharmony_ci}; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_cistatic int 20128c2ecf20Sopenharmony_cigadgetfs_fill_super (struct super_block *sb, struct fs_context *fc) 20138c2ecf20Sopenharmony_ci{ 20148c2ecf20Sopenharmony_ci struct inode *inode; 20158c2ecf20Sopenharmony_ci struct dev_data *dev; 20168c2ecf20Sopenharmony_ci int rc; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci mutex_lock(&sb_mutex); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (the_device) { 20218c2ecf20Sopenharmony_ci rc = -ESRCH; 20228c2ecf20Sopenharmony_ci goto Done; 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci CHIP = usb_get_gadget_udc_name(); 20268c2ecf20Sopenharmony_ci if (!CHIP) { 20278c2ecf20Sopenharmony_ci rc = -ENODEV; 20288c2ecf20Sopenharmony_ci goto Done; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci /* superblock */ 20328c2ecf20Sopenharmony_ci sb->s_blocksize = PAGE_SIZE; 20338c2ecf20Sopenharmony_ci sb->s_blocksize_bits = PAGE_SHIFT; 20348c2ecf20Sopenharmony_ci sb->s_magic = GADGETFS_MAGIC; 20358c2ecf20Sopenharmony_ci sb->s_op = &gadget_fs_operations; 20368c2ecf20Sopenharmony_ci sb->s_time_gran = 1; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci /* root inode */ 20398c2ecf20Sopenharmony_ci inode = gadgetfs_make_inode (sb, 20408c2ecf20Sopenharmony_ci NULL, &simple_dir_operations, 20418c2ecf20Sopenharmony_ci S_IFDIR | S_IRUGO | S_IXUGO); 20428c2ecf20Sopenharmony_ci if (!inode) 20438c2ecf20Sopenharmony_ci goto Enomem; 20448c2ecf20Sopenharmony_ci inode->i_op = &simple_dir_inode_operations; 20458c2ecf20Sopenharmony_ci if (!(sb->s_root = d_make_root (inode))) 20468c2ecf20Sopenharmony_ci goto Enomem; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci /* the ep0 file is named after the controller we expect; 20498c2ecf20Sopenharmony_ci * user mode code can use it for sanity checks, like we do. 20508c2ecf20Sopenharmony_ci */ 20518c2ecf20Sopenharmony_ci dev = dev_new (); 20528c2ecf20Sopenharmony_ci if (!dev) 20538c2ecf20Sopenharmony_ci goto Enomem; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci dev->sb = sb; 20568c2ecf20Sopenharmony_ci dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations); 20578c2ecf20Sopenharmony_ci if (!dev->dentry) { 20588c2ecf20Sopenharmony_ci put_dev(dev); 20598c2ecf20Sopenharmony_ci goto Enomem; 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci /* other endpoint files are available after hardware setup, 20638c2ecf20Sopenharmony_ci * from binding to a controller. 20648c2ecf20Sopenharmony_ci */ 20658c2ecf20Sopenharmony_ci the_device = dev; 20668c2ecf20Sopenharmony_ci rc = 0; 20678c2ecf20Sopenharmony_ci goto Done; 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci Enomem: 20708c2ecf20Sopenharmony_ci kfree(CHIP); 20718c2ecf20Sopenharmony_ci CHIP = NULL; 20728c2ecf20Sopenharmony_ci rc = -ENOMEM; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci Done: 20758c2ecf20Sopenharmony_ci mutex_unlock(&sb_mutex); 20768c2ecf20Sopenharmony_ci return rc; 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci/* "mount -t gadgetfs path /dev/gadget" ends up here */ 20808c2ecf20Sopenharmony_cistatic int gadgetfs_get_tree(struct fs_context *fc) 20818c2ecf20Sopenharmony_ci{ 20828c2ecf20Sopenharmony_ci return get_tree_single(fc, gadgetfs_fill_super); 20838c2ecf20Sopenharmony_ci} 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_cistatic const struct fs_context_operations gadgetfs_context_ops = { 20868c2ecf20Sopenharmony_ci .get_tree = gadgetfs_get_tree, 20878c2ecf20Sopenharmony_ci}; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_cistatic int gadgetfs_init_fs_context(struct fs_context *fc) 20908c2ecf20Sopenharmony_ci{ 20918c2ecf20Sopenharmony_ci fc->ops = &gadgetfs_context_ops; 20928c2ecf20Sopenharmony_ci return 0; 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic void 20968c2ecf20Sopenharmony_cigadgetfs_kill_sb (struct super_block *sb) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci mutex_lock(&sb_mutex); 20998c2ecf20Sopenharmony_ci kill_litter_super (sb); 21008c2ecf20Sopenharmony_ci if (the_device) { 21018c2ecf20Sopenharmony_ci put_dev (the_device); 21028c2ecf20Sopenharmony_ci the_device = NULL; 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci kfree(CHIP); 21058c2ecf20Sopenharmony_ci CHIP = NULL; 21068c2ecf20Sopenharmony_ci mutex_unlock(&sb_mutex); 21078c2ecf20Sopenharmony_ci} 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic struct file_system_type gadgetfs_type = { 21128c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 21138c2ecf20Sopenharmony_ci .name = shortname, 21148c2ecf20Sopenharmony_ci .init_fs_context = gadgetfs_init_fs_context, 21158c2ecf20Sopenharmony_ci .kill_sb = gadgetfs_kill_sb, 21168c2ecf20Sopenharmony_ci}; 21178c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("gadgetfs"); 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/ 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_cistatic int __init init (void) 21228c2ecf20Sopenharmony_ci{ 21238c2ecf20Sopenharmony_ci int status; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci status = register_filesystem (&gadgetfs_type); 21268c2ecf20Sopenharmony_ci if (status == 0) 21278c2ecf20Sopenharmony_ci pr_info ("%s: %s, version " DRIVER_VERSION "\n", 21288c2ecf20Sopenharmony_ci shortname, driver_desc); 21298c2ecf20Sopenharmony_ci return status; 21308c2ecf20Sopenharmony_ci} 21318c2ecf20Sopenharmony_cimodule_init (init); 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_cistatic void __exit cleanup (void) 21348c2ecf20Sopenharmony_ci{ 21358c2ecf20Sopenharmony_ci pr_debug ("unregister %s\n", shortname); 21368c2ecf20Sopenharmony_ci unregister_filesystem (&gadgetfs_type); 21378c2ecf20Sopenharmony_ci} 21388c2ecf20Sopenharmony_cimodule_exit (cleanup); 21398c2ecf20Sopenharmony_ci 2140