| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1 | /* | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2 | * f_fs.c -- user mode file system API for USB composite function controllers | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 3 | * | 
|  | 4 | * Copyright (C) 2010 Samsung Electronics | 
|  | 5 | * Author: Michal Nazarewicz <m.nazarewicz@samsung.com> | 
|  | 6 | * | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 7 | * Based on inode.c (GadgetFS) which was: | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 8 | * Copyright (C) 2003-2004 David Brownell | 
|  | 9 | * Copyright (C) 2003 Agilent Technologies | 
|  | 10 | * | 
|  | 11 | * This program is free software; you can redistribute it and/or modify | 
|  | 12 | * it under the terms of the GNU General Public License as published by | 
|  | 13 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 14 | * (at your option) any later version. | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 15 | */ | 
|  | 16 |  | 
|  | 17 |  | 
|  | 18 | /* #define DEBUG */ | 
|  | 19 | /* #define VERBOSE_DEBUG */ | 
|  | 20 |  | 
|  | 21 | #include <linux/blkdev.h> | 
| Randy Dunlap | b060869 | 2010-05-10 10:51:36 -0700 | [diff] [blame] | 22 | #include <linux/pagemap.h> | 
| Paul Gortmaker | f940fcd | 2011-05-27 09:56:31 -0400 | [diff] [blame] | 23 | #include <linux/export.h> | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 24 | #include <asm/unaligned.h> | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 25 |  | 
|  | 26 | #include <linux/usb/composite.h> | 
|  | 27 | #include <linux/usb/functionfs.h> | 
|  | 28 |  | 
|  | 29 |  | 
|  | 30 | #define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */ | 
|  | 31 |  | 
|  | 32 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 33 | /* Debugging ****************************************************************/ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 34 |  | 
|  | 35 | #ifdef VERBOSE_DEBUG | 
| Michal Nazarewicz | d8df0b6 | 2010-11-12 14:29:29 +0100 | [diff] [blame] | 36 | #  define pr_vdebug pr_debug | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 37 | #  define ffs_dump_mem(prefix, ptr, len) \ | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 38 | print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 39 | #else | 
| Michal Nazarewicz | d8df0b6 | 2010-11-12 14:29:29 +0100 | [diff] [blame] | 40 | #  define pr_vdebug(...)                 do { } while (0) | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 41 | #  define ffs_dump_mem(prefix, ptr, len) do { } while (0) | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 42 | #endif /* VERBOSE_DEBUG */ | 
|  | 43 |  | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 44 | #define ENTER()    pr_vdebug("%s()\n", __func__) | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 45 |  | 
|  | 46 |  | 
|  | 47 | /* The data structure and setup file ****************************************/ | 
|  | 48 |  | 
|  | 49 | enum ffs_state { | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 50 | /* | 
|  | 51 | * Waiting for descriptors and strings. | 
|  | 52 | * | 
|  | 53 | * In this state no open(2), read(2) or write(2) on epfiles | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 54 | * may succeed (which should not be the problem as there | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 55 | * should be no such files opened in the first place). | 
|  | 56 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 57 | FFS_READ_DESCRIPTORS, | 
|  | 58 | FFS_READ_STRINGS, | 
|  | 59 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 60 | /* | 
|  | 61 | * We've got descriptors and strings.  We are or have called | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 62 | * functionfs_ready_callback().  functionfs_bind() may have | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 63 | * been called but we don't know. | 
|  | 64 | * | 
|  | 65 | * This is the only state in which operations on epfiles may | 
|  | 66 | * succeed. | 
|  | 67 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 68 | FFS_ACTIVE, | 
|  | 69 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 70 | /* | 
|  | 71 | * All endpoints have been closed.  This state is also set if | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 72 | * we encounter an unrecoverable error.  The only | 
|  | 73 | * unrecoverable error is situation when after reading strings | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 74 | * from user space we fail to initialise epfiles or | 
|  | 75 | * functionfs_ready_callback() returns with error (<0). | 
|  | 76 | * | 
|  | 77 | * In this state no open(2), read(2) or write(2) (both on ep0 | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 78 | * as well as epfile) may succeed (at this point epfiles are | 
|  | 79 | * unlinked and all closed so this is not a problem; ep0 is | 
|  | 80 | * also closed but ep0 file exists and so open(2) on ep0 must | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 81 | * fail). | 
|  | 82 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 83 | FFS_CLOSING | 
|  | 84 | }; | 
|  | 85 |  | 
|  | 86 |  | 
|  | 87 | enum ffs_setup_state { | 
|  | 88 | /* There is no setup request pending. */ | 
|  | 89 | FFS_NO_SETUP, | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 90 | /* | 
|  | 91 | * User has read events and there was a setup request event | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 92 | * there.  The next read/write on ep0 will handle the | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 93 | * request. | 
|  | 94 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 95 | FFS_SETUP_PENDING, | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 96 | /* | 
|  | 97 | * There was event pending but before user space handled it | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 98 | * some other event was introduced which canceled existing | 
|  | 99 | * setup.  If this state is set read/write on ep0 return | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 100 | * -EIDRM.  This state is only set when adding event. | 
|  | 101 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 102 | FFS_SETUP_CANCELED | 
|  | 103 | }; | 
|  | 104 |  | 
|  | 105 |  | 
|  | 106 |  | 
|  | 107 | struct ffs_epfile; | 
|  | 108 | struct ffs_function; | 
|  | 109 |  | 
|  | 110 | struct ffs_data { | 
|  | 111 | struct usb_gadget		*gadget; | 
|  | 112 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 113 | /* | 
|  | 114 | * Protect access read/write operations, only one read/write | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 115 | * at a time.  As a consequence protects ep0req and company. | 
|  | 116 | * While setup request is being processed (queued) this is | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 117 | * held. | 
|  | 118 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 119 | struct mutex			mutex; | 
|  | 120 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 121 | /* | 
|  | 122 | * Protect access to endpoint related structures (basically | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 123 | * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 124 | * endpoint zero. | 
|  | 125 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 126 | spinlock_t			eps_lock; | 
|  | 127 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 128 | /* | 
|  | 129 | * XXX REVISIT do we need our own request? Since we are not | 
|  | 130 | * handling setup requests immediately user space may be so | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 131 | * slow that another setup will be sent to the gadget but this | 
|  | 132 | * time not to us but another function and then there could be | 
| Linus Torvalds | a4ce96a | 2010-07-21 09:25:42 -0700 | [diff] [blame] | 133 | * a race.  Is that the case? Or maybe we can use cdev->req | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 134 | * after all, maybe we just need some spinlock for that? | 
|  | 135 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 136 | struct usb_request		*ep0req;		/* P: mutex */ | 
|  | 137 | struct completion		ep0req_completion;	/* P: mutex */ | 
|  | 138 | int				ep0req_status;		/* P: mutex */ | 
|  | 139 |  | 
|  | 140 | /* reference counter */ | 
|  | 141 | atomic_t			ref; | 
|  | 142 | /* how many files are opened (EP0 and others) */ | 
|  | 143 | atomic_t			opened; | 
|  | 144 |  | 
|  | 145 | /* EP0 state */ | 
|  | 146 | enum ffs_state			state; | 
|  | 147 |  | 
|  | 148 | /* | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 149 | * Possible transitions: | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 150 | * + FFS_NO_SETUP       -> FFS_SETUP_PENDING  -- P: ev.waitq.lock | 
|  | 151 | *               happens only in ep0 read which is P: mutex | 
|  | 152 | * + FFS_SETUP_PENDING  -> FFS_NO_SETUP       -- P: ev.waitq.lock | 
|  | 153 | *               happens only in ep0 i/o  which is P: mutex | 
|  | 154 | * + FFS_SETUP_PENDING  -> FFS_SETUP_CANCELED -- P: ev.waitq.lock | 
|  | 155 | * + FFS_SETUP_CANCELED -> FFS_NO_SETUP       -- cmpxchg | 
|  | 156 | */ | 
|  | 157 | enum ffs_setup_state		setup_state; | 
|  | 158 |  | 
|  | 159 | #define FFS_SETUP_STATE(ffs)					\ | 
|  | 160 | ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state,	\ | 
|  | 161 | FFS_SETUP_CANCELED, FFS_NO_SETUP)) | 
|  | 162 |  | 
|  | 163 | /* Events & such. */ | 
|  | 164 | struct { | 
|  | 165 | u8				types[4]; | 
|  | 166 | unsigned short			count; | 
|  | 167 | /* XXX REVISIT need to update it in some places, or do we? */ | 
|  | 168 | unsigned short			can_stall; | 
|  | 169 | struct usb_ctrlrequest		setup; | 
|  | 170 |  | 
|  | 171 | wait_queue_head_t		waitq; | 
|  | 172 | } ev; /* the whole structure, P: ev.waitq.lock */ | 
|  | 173 |  | 
|  | 174 | /* Flags */ | 
|  | 175 | unsigned long			flags; | 
|  | 176 | #define FFS_FL_CALL_CLOSED_CALLBACK 0 | 
|  | 177 | #define FFS_FL_BOUND                1 | 
|  | 178 |  | 
|  | 179 | /* Active function */ | 
|  | 180 | struct ffs_function		*func; | 
|  | 181 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 182 | /* | 
|  | 183 | * Device name, write once when file system is mounted. | 
|  | 184 | * Intended for user to read if she wants. | 
|  | 185 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 186 | const char			*dev_name; | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 187 | /* Private data for our user (ie. gadget).  Managed by user. */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 188 | void				*private_data; | 
|  | 189 |  | 
|  | 190 | /* filled by __ffs_data_got_descs() */ | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 191 | /* | 
|  | 192 | * Real descriptors are 16 bytes after raw_descs (so you need | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 193 | * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the | 
|  | 194 | * first full speed descriptor).  raw_descs_length and | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 195 | * raw_fs_descs_length do not have those 16 bytes added. | 
|  | 196 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 197 | const void			*raw_descs; | 
|  | 198 | unsigned			raw_descs_length; | 
|  | 199 | unsigned			raw_fs_descs_length; | 
|  | 200 | unsigned			fs_descs_count; | 
|  | 201 | unsigned			hs_descs_count; | 
|  | 202 |  | 
|  | 203 | unsigned short			strings_count; | 
|  | 204 | unsigned short			interfaces_count; | 
|  | 205 | unsigned short			eps_count; | 
|  | 206 | unsigned short			_pad1; | 
|  | 207 |  | 
|  | 208 | /* filled by __ffs_data_got_strings() */ | 
|  | 209 | /* ids in stringtabs are set in functionfs_bind() */ | 
|  | 210 | const void			*raw_strings; | 
|  | 211 | struct usb_gadget_strings	**stringtabs; | 
|  | 212 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 213 | /* | 
|  | 214 | * File system's super block, write once when file system is | 
|  | 215 | * mounted. | 
|  | 216 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 217 | struct super_block		*sb; | 
|  | 218 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 219 | /* File permissions, written once when fs is mounted */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 220 | struct ffs_file_perms { | 
|  | 221 | umode_t				mode; | 
|  | 222 | uid_t				uid; | 
|  | 223 | gid_t				gid; | 
|  | 224 | }				file_perms; | 
|  | 225 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 226 | /* | 
|  | 227 | * The endpoint files, filled by ffs_epfiles_create(), | 
|  | 228 | * destroyed by ffs_epfiles_destroy(). | 
|  | 229 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 230 | struct ffs_epfile		*epfiles; | 
|  | 231 | }; | 
|  | 232 |  | 
|  | 233 | /* Reference counter handling */ | 
|  | 234 | static void ffs_data_get(struct ffs_data *ffs); | 
|  | 235 | static void ffs_data_put(struct ffs_data *ffs); | 
|  | 236 | /* Creates new ffs_data object. */ | 
|  | 237 | static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc)); | 
|  | 238 |  | 
|  | 239 | /* Opened counter handling. */ | 
|  | 240 | static void ffs_data_opened(struct ffs_data *ffs); | 
|  | 241 | static void ffs_data_closed(struct ffs_data *ffs); | 
|  | 242 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 243 | /* Called with ffs->mutex held; take over ownership of data. */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 244 | static int __must_check | 
|  | 245 | __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); | 
|  | 246 | static int __must_check | 
|  | 247 | __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); | 
|  | 248 |  | 
|  | 249 |  | 
|  | 250 | /* The function structure ***************************************************/ | 
|  | 251 |  | 
|  | 252 | struct ffs_ep; | 
|  | 253 |  | 
|  | 254 | struct ffs_function { | 
|  | 255 | struct usb_configuration	*conf; | 
|  | 256 | struct usb_gadget		*gadget; | 
|  | 257 | struct ffs_data			*ffs; | 
|  | 258 |  | 
|  | 259 | struct ffs_ep			*eps; | 
|  | 260 | u8				eps_revmap[16]; | 
|  | 261 | short				*interfaces_nums; | 
|  | 262 |  | 
|  | 263 | struct usb_function		function; | 
|  | 264 | }; | 
|  | 265 |  | 
|  | 266 |  | 
|  | 267 | static struct ffs_function *ffs_func_from_usb(struct usb_function *f) | 
|  | 268 | { | 
|  | 269 | return container_of(f, struct ffs_function, function); | 
|  | 270 | } | 
|  | 271 |  | 
|  | 272 | static void ffs_func_free(struct ffs_function *func); | 
|  | 273 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 274 | static void ffs_func_eps_disable(struct ffs_function *func); | 
|  | 275 | static int __must_check ffs_func_eps_enable(struct ffs_function *func); | 
|  | 276 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 277 | static int ffs_func_bind(struct usb_configuration *, | 
|  | 278 | struct usb_function *); | 
|  | 279 | static void ffs_func_unbind(struct usb_configuration *, | 
|  | 280 | struct usb_function *); | 
|  | 281 | static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); | 
|  | 282 | static void ffs_func_disable(struct usb_function *); | 
|  | 283 | static int ffs_func_setup(struct usb_function *, | 
|  | 284 | const struct usb_ctrlrequest *); | 
|  | 285 | static void ffs_func_suspend(struct usb_function *); | 
|  | 286 | static void ffs_func_resume(struct usb_function *); | 
|  | 287 |  | 
|  | 288 |  | 
|  | 289 | static int ffs_func_revmap_ep(struct ffs_function *func, u8 num); | 
|  | 290 | static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf); | 
|  | 291 |  | 
|  | 292 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 293 | /* The endpoints structures *************************************************/ | 
|  | 294 |  | 
|  | 295 | struct ffs_ep { | 
|  | 296 | struct usb_ep			*ep;	/* P: ffs->eps_lock */ | 
|  | 297 | struct usb_request		*req;	/* P: epfile->mutex */ | 
|  | 298 |  | 
|  | 299 | /* [0]: full speed, [1]: high speed */ | 
|  | 300 | struct usb_endpoint_descriptor	*descs[2]; | 
|  | 301 |  | 
|  | 302 | u8				num; | 
|  | 303 |  | 
|  | 304 | int				status;	/* P: epfile->mutex */ | 
|  | 305 | }; | 
|  | 306 |  | 
|  | 307 | struct ffs_epfile { | 
|  | 308 | /* Protects ep->ep and ep->req. */ | 
|  | 309 | struct mutex			mutex; | 
|  | 310 | wait_queue_head_t		wait; | 
|  | 311 |  | 
|  | 312 | struct ffs_data			*ffs; | 
|  | 313 | struct ffs_ep			*ep;	/* P: ffs->eps_lock */ | 
|  | 314 |  | 
|  | 315 | struct dentry			*dentry; | 
|  | 316 |  | 
|  | 317 | char				name[5]; | 
|  | 318 |  | 
|  | 319 | unsigned char			in;	/* P: ffs->eps_lock */ | 
|  | 320 | unsigned char			isoc;	/* P: ffs->eps_lock */ | 
|  | 321 |  | 
|  | 322 | unsigned char			_pad; | 
|  | 323 | }; | 
|  | 324 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 325 | static int  __must_check ffs_epfiles_create(struct ffs_data *ffs); | 
|  | 326 | static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); | 
|  | 327 |  | 
|  | 328 | static struct inode *__must_check | 
|  | 329 | ffs_sb_create_file(struct super_block *sb, const char *name, void *data, | 
|  | 330 | const struct file_operations *fops, | 
|  | 331 | struct dentry **dentry_p); | 
|  | 332 |  | 
|  | 333 |  | 
|  | 334 | /* Misc helper functions ****************************************************/ | 
|  | 335 |  | 
|  | 336 | static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) | 
|  | 337 | __attribute__((warn_unused_result, nonnull)); | 
|  | 338 | static char *ffs_prepare_buffer(const char * __user buf, size_t len) | 
|  | 339 | __attribute__((warn_unused_result, nonnull)); | 
|  | 340 |  | 
|  | 341 |  | 
|  | 342 | /* Control file aka ep0 *****************************************************/ | 
|  | 343 |  | 
|  | 344 | static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req) | 
|  | 345 | { | 
|  | 346 | struct ffs_data *ffs = req->context; | 
|  | 347 |  | 
|  | 348 | complete_all(&ffs->ep0req_completion); | 
|  | 349 | } | 
|  | 350 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 351 | static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) | 
|  | 352 | { | 
|  | 353 | struct usb_request *req = ffs->ep0req; | 
|  | 354 | int ret; | 
|  | 355 |  | 
|  | 356 | req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength); | 
|  | 357 |  | 
|  | 358 | spin_unlock_irq(&ffs->ev.waitq.lock); | 
|  | 359 |  | 
|  | 360 | req->buf      = data; | 
|  | 361 | req->length   = len; | 
|  | 362 |  | 
| Marek Szyprowski | ce1fd35 | 2011-01-28 13:55:36 +0100 | [diff] [blame] | 363 | /* | 
|  | 364 | * UDC layer requires to provide a buffer even for ZLP, but should | 
|  | 365 | * not use it at all. Let's provide some poisoned pointer to catch | 
|  | 366 | * possible bug in the driver. | 
|  | 367 | */ | 
|  | 368 | if (req->buf == NULL) | 
|  | 369 | req->buf = (void *)0xDEADBABE; | 
|  | 370 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 371 | INIT_COMPLETION(ffs->ep0req_completion); | 
|  | 372 |  | 
|  | 373 | ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); | 
|  | 374 | if (unlikely(ret < 0)) | 
|  | 375 | return ret; | 
|  | 376 |  | 
|  | 377 | ret = wait_for_completion_interruptible(&ffs->ep0req_completion); | 
|  | 378 | if (unlikely(ret)) { | 
|  | 379 | usb_ep_dequeue(ffs->gadget->ep0, req); | 
|  | 380 | return -EINTR; | 
|  | 381 | } | 
|  | 382 |  | 
|  | 383 | ffs->setup_state = FFS_NO_SETUP; | 
|  | 384 | return ffs->ep0req_status; | 
|  | 385 | } | 
|  | 386 |  | 
|  | 387 | static int __ffs_ep0_stall(struct ffs_data *ffs) | 
|  | 388 | { | 
|  | 389 | if (ffs->ev.can_stall) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 390 | pr_vdebug("ep0 stall\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 391 | usb_ep_set_halt(ffs->gadget->ep0); | 
|  | 392 | ffs->setup_state = FFS_NO_SETUP; | 
|  | 393 | return -EL2HLT; | 
|  | 394 | } else { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 395 | pr_debug("bogus ep0 stall!\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 396 | return -ESRCH; | 
|  | 397 | } | 
|  | 398 | } | 
|  | 399 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 400 | static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, | 
|  | 401 | size_t len, loff_t *ptr) | 
|  | 402 | { | 
|  | 403 | struct ffs_data *ffs = file->private_data; | 
|  | 404 | ssize_t ret; | 
|  | 405 | char *data; | 
|  | 406 |  | 
|  | 407 | ENTER(); | 
|  | 408 |  | 
|  | 409 | /* Fast check if setup was canceled */ | 
|  | 410 | if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) | 
|  | 411 | return -EIDRM; | 
|  | 412 |  | 
|  | 413 | /* Acquire mutex */ | 
|  | 414 | ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); | 
|  | 415 | if (unlikely(ret < 0)) | 
|  | 416 | return ret; | 
|  | 417 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 418 | /* Check state */ | 
|  | 419 | switch (ffs->state) { | 
|  | 420 | case FFS_READ_DESCRIPTORS: | 
|  | 421 | case FFS_READ_STRINGS: | 
|  | 422 | /* Copy data */ | 
|  | 423 | if (unlikely(len < 16)) { | 
|  | 424 | ret = -EINVAL; | 
|  | 425 | break; | 
|  | 426 | } | 
|  | 427 |  | 
|  | 428 | data = ffs_prepare_buffer(buf, len); | 
| Tobias Klauser | 537baab | 2010-12-09 15:52:39 +0100 | [diff] [blame] | 429 | if (IS_ERR(data)) { | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 430 | ret = PTR_ERR(data); | 
|  | 431 | break; | 
|  | 432 | } | 
|  | 433 |  | 
|  | 434 | /* Handle data */ | 
|  | 435 | if (ffs->state == FFS_READ_DESCRIPTORS) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 436 | pr_info("read descriptors\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 437 | ret = __ffs_data_got_descs(ffs, data, len); | 
|  | 438 | if (unlikely(ret < 0)) | 
|  | 439 | break; | 
|  | 440 |  | 
|  | 441 | ffs->state = FFS_READ_STRINGS; | 
|  | 442 | ret = len; | 
|  | 443 | } else { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 444 | pr_info("read strings\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 445 | ret = __ffs_data_got_strings(ffs, data, len); | 
|  | 446 | if (unlikely(ret < 0)) | 
|  | 447 | break; | 
|  | 448 |  | 
|  | 449 | ret = ffs_epfiles_create(ffs); | 
|  | 450 | if (unlikely(ret)) { | 
|  | 451 | ffs->state = FFS_CLOSING; | 
|  | 452 | break; | 
|  | 453 | } | 
|  | 454 |  | 
|  | 455 | ffs->state = FFS_ACTIVE; | 
|  | 456 | mutex_unlock(&ffs->mutex); | 
|  | 457 |  | 
|  | 458 | ret = functionfs_ready_callback(ffs); | 
|  | 459 | if (unlikely(ret < 0)) { | 
|  | 460 | ffs->state = FFS_CLOSING; | 
|  | 461 | return ret; | 
|  | 462 | } | 
|  | 463 |  | 
|  | 464 | set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags); | 
|  | 465 | return len; | 
|  | 466 | } | 
|  | 467 | break; | 
|  | 468 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 469 | case FFS_ACTIVE: | 
|  | 470 | data = NULL; | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 471 | /* | 
|  | 472 | * We're called from user space, we can use _irq | 
|  | 473 | * rather then _irqsave | 
|  | 474 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 475 | spin_lock_irq(&ffs->ev.waitq.lock); | 
|  | 476 | switch (FFS_SETUP_STATE(ffs)) { | 
|  | 477 | case FFS_SETUP_CANCELED: | 
|  | 478 | ret = -EIDRM; | 
|  | 479 | goto done_spin; | 
|  | 480 |  | 
|  | 481 | case FFS_NO_SETUP: | 
|  | 482 | ret = -ESRCH; | 
|  | 483 | goto done_spin; | 
|  | 484 |  | 
|  | 485 | case FFS_SETUP_PENDING: | 
|  | 486 | break; | 
|  | 487 | } | 
|  | 488 |  | 
|  | 489 | /* FFS_SETUP_PENDING */ | 
|  | 490 | if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) { | 
|  | 491 | spin_unlock_irq(&ffs->ev.waitq.lock); | 
|  | 492 | ret = __ffs_ep0_stall(ffs); | 
|  | 493 | break; | 
|  | 494 | } | 
|  | 495 |  | 
|  | 496 | /* FFS_SETUP_PENDING and not stall */ | 
|  | 497 | len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); | 
|  | 498 |  | 
|  | 499 | spin_unlock_irq(&ffs->ev.waitq.lock); | 
|  | 500 |  | 
|  | 501 | data = ffs_prepare_buffer(buf, len); | 
| Tobias Klauser | 537baab | 2010-12-09 15:52:39 +0100 | [diff] [blame] | 502 | if (IS_ERR(data)) { | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 503 | ret = PTR_ERR(data); | 
|  | 504 | break; | 
|  | 505 | } | 
|  | 506 |  | 
|  | 507 | spin_lock_irq(&ffs->ev.waitq.lock); | 
|  | 508 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 509 | /* | 
|  | 510 | * We are guaranteed to be still in FFS_ACTIVE state | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 511 | * but the state of setup could have changed from | 
|  | 512 | * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need | 
|  | 513 | * to check for that.  If that happened we copied data | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 514 | * from user space in vain but it's unlikely. | 
|  | 515 | * | 
|  | 516 | * For sure we are not in FFS_NO_SETUP since this is | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 517 | * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP | 
|  | 518 | * transition can be performed and it's protected by | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 519 | * mutex. | 
|  | 520 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 521 | if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { | 
|  | 522 | ret = -EIDRM; | 
|  | 523 | done_spin: | 
|  | 524 | spin_unlock_irq(&ffs->ev.waitq.lock); | 
|  | 525 | } else { | 
|  | 526 | /* unlocks spinlock */ | 
|  | 527 | ret = __ffs_ep0_queue_wait(ffs, data, len); | 
|  | 528 | } | 
|  | 529 | kfree(data); | 
|  | 530 | break; | 
|  | 531 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 532 | default: | 
|  | 533 | ret = -EBADFD; | 
|  | 534 | break; | 
|  | 535 | } | 
|  | 536 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 537 | mutex_unlock(&ffs->mutex); | 
|  | 538 | return ret; | 
|  | 539 | } | 
|  | 540 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 541 | static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, | 
|  | 542 | size_t n) | 
|  | 543 | { | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 544 | /* | 
|  | 545 | * We are holding ffs->ev.waitq.lock and ffs->mutex and we need | 
|  | 546 | * to release them. | 
|  | 547 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 548 | struct usb_functionfs_event events[n]; | 
|  | 549 | unsigned i = 0; | 
|  | 550 |  | 
|  | 551 | memset(events, 0, sizeof events); | 
|  | 552 |  | 
|  | 553 | do { | 
|  | 554 | events[i].type = ffs->ev.types[i]; | 
|  | 555 | if (events[i].type == FUNCTIONFS_SETUP) { | 
|  | 556 | events[i].u.setup = ffs->ev.setup; | 
|  | 557 | ffs->setup_state = FFS_SETUP_PENDING; | 
|  | 558 | } | 
|  | 559 | } while (++i < n); | 
|  | 560 |  | 
|  | 561 | if (n < ffs->ev.count) { | 
|  | 562 | ffs->ev.count -= n; | 
|  | 563 | memmove(ffs->ev.types, ffs->ev.types + n, | 
|  | 564 | ffs->ev.count * sizeof *ffs->ev.types); | 
|  | 565 | } else { | 
|  | 566 | ffs->ev.count = 0; | 
|  | 567 | } | 
|  | 568 |  | 
|  | 569 | spin_unlock_irq(&ffs->ev.waitq.lock); | 
|  | 570 | mutex_unlock(&ffs->mutex); | 
|  | 571 |  | 
|  | 572 | return unlikely(__copy_to_user(buf, events, sizeof events)) | 
|  | 573 | ? -EFAULT : sizeof events; | 
|  | 574 | } | 
|  | 575 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 576 | static ssize_t ffs_ep0_read(struct file *file, char __user *buf, | 
|  | 577 | size_t len, loff_t *ptr) | 
|  | 578 | { | 
|  | 579 | struct ffs_data *ffs = file->private_data; | 
|  | 580 | char *data = NULL; | 
|  | 581 | size_t n; | 
|  | 582 | int ret; | 
|  | 583 |  | 
|  | 584 | ENTER(); | 
|  | 585 |  | 
|  | 586 | /* Fast check if setup was canceled */ | 
|  | 587 | if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) | 
|  | 588 | return -EIDRM; | 
|  | 589 |  | 
|  | 590 | /* Acquire mutex */ | 
|  | 591 | ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); | 
|  | 592 | if (unlikely(ret < 0)) | 
|  | 593 | return ret; | 
|  | 594 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 595 | /* Check state */ | 
|  | 596 | if (ffs->state != FFS_ACTIVE) { | 
|  | 597 | ret = -EBADFD; | 
|  | 598 | goto done_mutex; | 
|  | 599 | } | 
|  | 600 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 601 | /* | 
|  | 602 | * We're called from user space, we can use _irq rather then | 
|  | 603 | * _irqsave | 
|  | 604 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 605 | spin_lock_irq(&ffs->ev.waitq.lock); | 
|  | 606 |  | 
|  | 607 | switch (FFS_SETUP_STATE(ffs)) { | 
|  | 608 | case FFS_SETUP_CANCELED: | 
|  | 609 | ret = -EIDRM; | 
|  | 610 | break; | 
|  | 611 |  | 
|  | 612 | case FFS_NO_SETUP: | 
|  | 613 | n = len / sizeof(struct usb_functionfs_event); | 
|  | 614 | if (unlikely(!n)) { | 
|  | 615 | ret = -EINVAL; | 
|  | 616 | break; | 
|  | 617 | } | 
|  | 618 |  | 
|  | 619 | if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) { | 
|  | 620 | ret = -EAGAIN; | 
|  | 621 | break; | 
|  | 622 | } | 
|  | 623 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 624 | if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq, | 
|  | 625 | ffs->ev.count)) { | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 626 | ret = -EINTR; | 
|  | 627 | break; | 
|  | 628 | } | 
|  | 629 |  | 
|  | 630 | return __ffs_ep0_read_events(ffs, buf, | 
|  | 631 | min(n, (size_t)ffs->ev.count)); | 
|  | 632 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 633 | case FFS_SETUP_PENDING: | 
|  | 634 | if (ffs->ev.setup.bRequestType & USB_DIR_IN) { | 
|  | 635 | spin_unlock_irq(&ffs->ev.waitq.lock); | 
|  | 636 | ret = __ffs_ep0_stall(ffs); | 
|  | 637 | goto done_mutex; | 
|  | 638 | } | 
|  | 639 |  | 
|  | 640 | len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); | 
|  | 641 |  | 
|  | 642 | spin_unlock_irq(&ffs->ev.waitq.lock); | 
|  | 643 |  | 
|  | 644 | if (likely(len)) { | 
|  | 645 | data = kmalloc(len, GFP_KERNEL); | 
|  | 646 | if (unlikely(!data)) { | 
|  | 647 | ret = -ENOMEM; | 
|  | 648 | goto done_mutex; | 
|  | 649 | } | 
|  | 650 | } | 
|  | 651 |  | 
|  | 652 | spin_lock_irq(&ffs->ev.waitq.lock); | 
|  | 653 |  | 
|  | 654 | /* See ffs_ep0_write() */ | 
|  | 655 | if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { | 
|  | 656 | ret = -EIDRM; | 
|  | 657 | break; | 
|  | 658 | } | 
|  | 659 |  | 
|  | 660 | /* unlocks spinlock */ | 
|  | 661 | ret = __ffs_ep0_queue_wait(ffs, data, len); | 
|  | 662 | if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len))) | 
|  | 663 | ret = -EFAULT; | 
|  | 664 | goto done_mutex; | 
|  | 665 |  | 
|  | 666 | default: | 
|  | 667 | ret = -EBADFD; | 
|  | 668 | break; | 
|  | 669 | } | 
|  | 670 |  | 
|  | 671 | spin_unlock_irq(&ffs->ev.waitq.lock); | 
|  | 672 | done_mutex: | 
|  | 673 | mutex_unlock(&ffs->mutex); | 
|  | 674 | kfree(data); | 
|  | 675 | return ret; | 
|  | 676 | } | 
|  | 677 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 678 | static int ffs_ep0_open(struct inode *inode, struct file *file) | 
|  | 679 | { | 
|  | 680 | struct ffs_data *ffs = inode->i_private; | 
|  | 681 |  | 
|  | 682 | ENTER(); | 
|  | 683 |  | 
|  | 684 | if (unlikely(ffs->state == FFS_CLOSING)) | 
|  | 685 | return -EBUSY; | 
|  | 686 |  | 
|  | 687 | file->private_data = ffs; | 
|  | 688 | ffs_data_opened(ffs); | 
|  | 689 |  | 
|  | 690 | return 0; | 
|  | 691 | } | 
|  | 692 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 693 | static int ffs_ep0_release(struct inode *inode, struct file *file) | 
|  | 694 | { | 
|  | 695 | struct ffs_data *ffs = file->private_data; | 
|  | 696 |  | 
|  | 697 | ENTER(); | 
|  | 698 |  | 
|  | 699 | ffs_data_closed(ffs); | 
|  | 700 |  | 
|  | 701 | return 0; | 
|  | 702 | } | 
|  | 703 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 704 | static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) | 
|  | 705 | { | 
|  | 706 | struct ffs_data *ffs = file->private_data; | 
|  | 707 | struct usb_gadget *gadget = ffs->gadget; | 
|  | 708 | long ret; | 
|  | 709 |  | 
|  | 710 | ENTER(); | 
|  | 711 |  | 
|  | 712 | if (code == FUNCTIONFS_INTERFACE_REVMAP) { | 
|  | 713 | struct ffs_function *func = ffs->func; | 
|  | 714 | ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; | 
|  | 715 | } else if (gadget->ops->ioctl) { | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 716 | ret = gadget->ops->ioctl(gadget, code, value); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 717 | } else { | 
|  | 718 | ret = -ENOTTY; | 
|  | 719 | } | 
|  | 720 |  | 
|  | 721 | return ret; | 
|  | 722 | } | 
|  | 723 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 724 | static const struct file_operations ffs_ep0_operations = { | 
|  | 725 | .owner =	THIS_MODULE, | 
|  | 726 | .llseek =	no_llseek, | 
|  | 727 |  | 
|  | 728 | .open =		ffs_ep0_open, | 
|  | 729 | .write =	ffs_ep0_write, | 
|  | 730 | .read =		ffs_ep0_read, | 
|  | 731 | .release =	ffs_ep0_release, | 
|  | 732 | .unlocked_ioctl =	ffs_ep0_ioctl, | 
|  | 733 | }; | 
|  | 734 |  | 
|  | 735 |  | 
|  | 736 | /* "Normal" endpoints operations ********************************************/ | 
|  | 737 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 738 | static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) | 
|  | 739 | { | 
|  | 740 | ENTER(); | 
|  | 741 | if (likely(req->context)) { | 
|  | 742 | struct ffs_ep *ep = _ep->driver_data; | 
|  | 743 | ep->status = req->status ? req->status : req->actual; | 
|  | 744 | complete(req->context); | 
|  | 745 | } | 
|  | 746 | } | 
|  | 747 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 748 | static ssize_t ffs_epfile_io(struct file *file, | 
|  | 749 | char __user *buf, size_t len, int read) | 
|  | 750 | { | 
|  | 751 | struct ffs_epfile *epfile = file->private_data; | 
|  | 752 | struct ffs_ep *ep; | 
|  | 753 | char *data = NULL; | 
|  | 754 | ssize_t ret; | 
|  | 755 | int halt; | 
|  | 756 |  | 
|  | 757 | goto first_try; | 
|  | 758 | do { | 
|  | 759 | spin_unlock_irq(&epfile->ffs->eps_lock); | 
|  | 760 | mutex_unlock(&epfile->mutex); | 
|  | 761 |  | 
|  | 762 | first_try: | 
|  | 763 | /* Are we still active? */ | 
|  | 764 | if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) { | 
|  | 765 | ret = -ENODEV; | 
|  | 766 | goto error; | 
|  | 767 | } | 
|  | 768 |  | 
|  | 769 | /* Wait for endpoint to be enabled */ | 
|  | 770 | ep = epfile->ep; | 
|  | 771 | if (!ep) { | 
|  | 772 | if (file->f_flags & O_NONBLOCK) { | 
|  | 773 | ret = -EAGAIN; | 
|  | 774 | goto error; | 
|  | 775 | } | 
|  | 776 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 777 | if (wait_event_interruptible(epfile->wait, | 
|  | 778 | (ep = epfile->ep))) { | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 779 | ret = -EINTR; | 
|  | 780 | goto error; | 
|  | 781 | } | 
|  | 782 | } | 
|  | 783 |  | 
|  | 784 | /* Do we halt? */ | 
|  | 785 | halt = !read == !epfile->in; | 
|  | 786 | if (halt && epfile->isoc) { | 
|  | 787 | ret = -EINVAL; | 
|  | 788 | goto error; | 
|  | 789 | } | 
|  | 790 |  | 
|  | 791 | /* Allocate & copy */ | 
|  | 792 | if (!halt && !data) { | 
|  | 793 | data = kzalloc(len, GFP_KERNEL); | 
|  | 794 | if (unlikely(!data)) | 
|  | 795 | return -ENOMEM; | 
|  | 796 |  | 
|  | 797 | if (!read && | 
|  | 798 | unlikely(__copy_from_user(data, buf, len))) { | 
|  | 799 | ret = -EFAULT; | 
|  | 800 | goto error; | 
|  | 801 | } | 
|  | 802 | } | 
|  | 803 |  | 
|  | 804 | /* We will be using request */ | 
|  | 805 | ret = ffs_mutex_lock(&epfile->mutex, | 
|  | 806 | file->f_flags & O_NONBLOCK); | 
|  | 807 | if (unlikely(ret)) | 
|  | 808 | goto error; | 
|  | 809 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 810 | /* | 
|  | 811 | * We're called from user space, we can use _irq rather then | 
|  | 812 | * _irqsave | 
|  | 813 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 814 | spin_lock_irq(&epfile->ffs->eps_lock); | 
|  | 815 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 816 | /* | 
|  | 817 | * While we were acquiring mutex endpoint got disabled | 
|  | 818 | * or changed? | 
|  | 819 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 820 | } while (unlikely(epfile->ep != ep)); | 
|  | 821 |  | 
|  | 822 | /* Halt */ | 
|  | 823 | if (unlikely(halt)) { | 
|  | 824 | if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) | 
|  | 825 | usb_ep_set_halt(ep->ep); | 
|  | 826 | spin_unlock_irq(&epfile->ffs->eps_lock); | 
|  | 827 | ret = -EBADMSG; | 
|  | 828 | } else { | 
|  | 829 | /* Fire the request */ | 
|  | 830 | DECLARE_COMPLETION_ONSTACK(done); | 
|  | 831 |  | 
|  | 832 | struct usb_request *req = ep->req; | 
|  | 833 | req->context  = &done; | 
|  | 834 | req->complete = ffs_epfile_io_complete; | 
|  | 835 | req->buf      = data; | 
|  | 836 | req->length   = len; | 
|  | 837 |  | 
|  | 838 | ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); | 
|  | 839 |  | 
|  | 840 | spin_unlock_irq(&epfile->ffs->eps_lock); | 
|  | 841 |  | 
|  | 842 | if (unlikely(ret < 0)) { | 
|  | 843 | /* nop */ | 
|  | 844 | } else if (unlikely(wait_for_completion_interruptible(&done))) { | 
|  | 845 | ret = -EINTR; | 
|  | 846 | usb_ep_dequeue(ep->ep, req); | 
|  | 847 | } else { | 
|  | 848 | ret = ep->status; | 
|  | 849 | if (read && ret > 0 && | 
|  | 850 | unlikely(copy_to_user(buf, data, ret))) | 
|  | 851 | ret = -EFAULT; | 
|  | 852 | } | 
|  | 853 | } | 
|  | 854 |  | 
|  | 855 | mutex_unlock(&epfile->mutex); | 
|  | 856 | error: | 
|  | 857 | kfree(data); | 
|  | 858 | return ret; | 
|  | 859 | } | 
|  | 860 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 861 | static ssize_t | 
|  | 862 | ffs_epfile_write(struct file *file, const char __user *buf, size_t len, | 
|  | 863 | loff_t *ptr) | 
|  | 864 | { | 
|  | 865 | ENTER(); | 
|  | 866 |  | 
|  | 867 | return ffs_epfile_io(file, (char __user *)buf, len, 0); | 
|  | 868 | } | 
|  | 869 |  | 
|  | 870 | static ssize_t | 
|  | 871 | ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) | 
|  | 872 | { | 
|  | 873 | ENTER(); | 
|  | 874 |  | 
|  | 875 | return ffs_epfile_io(file, buf, len, 1); | 
|  | 876 | } | 
|  | 877 |  | 
|  | 878 | static int | 
|  | 879 | ffs_epfile_open(struct inode *inode, struct file *file) | 
|  | 880 | { | 
|  | 881 | struct ffs_epfile *epfile = inode->i_private; | 
|  | 882 |  | 
|  | 883 | ENTER(); | 
|  | 884 |  | 
|  | 885 | if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) | 
|  | 886 | return -ENODEV; | 
|  | 887 |  | 
|  | 888 | file->private_data = epfile; | 
|  | 889 | ffs_data_opened(epfile->ffs); | 
|  | 890 |  | 
|  | 891 | return 0; | 
|  | 892 | } | 
|  | 893 |  | 
|  | 894 | static int | 
|  | 895 | ffs_epfile_release(struct inode *inode, struct file *file) | 
|  | 896 | { | 
|  | 897 | struct ffs_epfile *epfile = inode->i_private; | 
|  | 898 |  | 
|  | 899 | ENTER(); | 
|  | 900 |  | 
|  | 901 | ffs_data_closed(epfile->ffs); | 
|  | 902 |  | 
|  | 903 | return 0; | 
|  | 904 | } | 
|  | 905 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 906 | static long ffs_epfile_ioctl(struct file *file, unsigned code, | 
|  | 907 | unsigned long value) | 
|  | 908 | { | 
|  | 909 | struct ffs_epfile *epfile = file->private_data; | 
|  | 910 | int ret; | 
|  | 911 |  | 
|  | 912 | ENTER(); | 
|  | 913 |  | 
|  | 914 | if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) | 
|  | 915 | return -ENODEV; | 
|  | 916 |  | 
|  | 917 | spin_lock_irq(&epfile->ffs->eps_lock); | 
|  | 918 | if (likely(epfile->ep)) { | 
|  | 919 | switch (code) { | 
|  | 920 | case FUNCTIONFS_FIFO_STATUS: | 
|  | 921 | ret = usb_ep_fifo_status(epfile->ep->ep); | 
|  | 922 | break; | 
|  | 923 | case FUNCTIONFS_FIFO_FLUSH: | 
|  | 924 | usb_ep_fifo_flush(epfile->ep->ep); | 
|  | 925 | ret = 0; | 
|  | 926 | break; | 
|  | 927 | case FUNCTIONFS_CLEAR_HALT: | 
|  | 928 | ret = usb_ep_clear_halt(epfile->ep->ep); | 
|  | 929 | break; | 
|  | 930 | case FUNCTIONFS_ENDPOINT_REVMAP: | 
|  | 931 | ret = epfile->ep->num; | 
|  | 932 | break; | 
|  | 933 | default: | 
|  | 934 | ret = -ENOTTY; | 
|  | 935 | } | 
|  | 936 | } else { | 
|  | 937 | ret = -ENODEV; | 
|  | 938 | } | 
|  | 939 | spin_unlock_irq(&epfile->ffs->eps_lock); | 
|  | 940 |  | 
|  | 941 | return ret; | 
|  | 942 | } | 
|  | 943 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 944 | static const struct file_operations ffs_epfile_operations = { | 
|  | 945 | .owner =	THIS_MODULE, | 
|  | 946 | .llseek =	no_llseek, | 
|  | 947 |  | 
|  | 948 | .open =		ffs_epfile_open, | 
|  | 949 | .write =	ffs_epfile_write, | 
|  | 950 | .read =		ffs_epfile_read, | 
|  | 951 | .release =	ffs_epfile_release, | 
|  | 952 | .unlocked_ioctl =	ffs_epfile_ioctl, | 
|  | 953 | }; | 
|  | 954 |  | 
|  | 955 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 956 | /* File system and super block operations ***********************************/ | 
|  | 957 |  | 
|  | 958 | /* | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 959 | * Mounting the file system creates a controller file, used first for | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 960 | * function configuration then later for event monitoring. | 
|  | 961 | */ | 
|  | 962 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 963 | static struct inode *__must_check | 
|  | 964 | ffs_sb_make_inode(struct super_block *sb, void *data, | 
|  | 965 | const struct file_operations *fops, | 
|  | 966 | const struct inode_operations *iops, | 
|  | 967 | struct ffs_file_perms *perms) | 
|  | 968 | { | 
|  | 969 | struct inode *inode; | 
|  | 970 |  | 
|  | 971 | ENTER(); | 
|  | 972 |  | 
|  | 973 | inode = new_inode(sb); | 
|  | 974 |  | 
|  | 975 | if (likely(inode)) { | 
|  | 976 | struct timespec current_time = CURRENT_TIME; | 
|  | 977 |  | 
| Al Viro | 12ba8d1 | 2010-10-27 04:19:36 +0100 | [diff] [blame] | 978 | inode->i_ino	 = get_next_ino(); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 979 | inode->i_mode    = perms->mode; | 
|  | 980 | inode->i_uid     = perms->uid; | 
|  | 981 | inode->i_gid     = perms->gid; | 
|  | 982 | inode->i_atime   = current_time; | 
|  | 983 | inode->i_mtime   = current_time; | 
|  | 984 | inode->i_ctime   = current_time; | 
|  | 985 | inode->i_private = data; | 
|  | 986 | if (fops) | 
|  | 987 | inode->i_fop = fops; | 
|  | 988 | if (iops) | 
|  | 989 | inode->i_op  = iops; | 
|  | 990 | } | 
|  | 991 |  | 
|  | 992 | return inode; | 
|  | 993 | } | 
|  | 994 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 995 | /* Create "regular" file */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 996 | static struct inode *ffs_sb_create_file(struct super_block *sb, | 
|  | 997 | const char *name, void *data, | 
|  | 998 | const struct file_operations *fops, | 
|  | 999 | struct dentry **dentry_p) | 
|  | 1000 | { | 
|  | 1001 | struct ffs_data	*ffs = sb->s_fs_info; | 
|  | 1002 | struct dentry	*dentry; | 
|  | 1003 | struct inode	*inode; | 
|  | 1004 |  | 
|  | 1005 | ENTER(); | 
|  | 1006 |  | 
|  | 1007 | dentry = d_alloc_name(sb->s_root, name); | 
|  | 1008 | if (unlikely(!dentry)) | 
|  | 1009 | return NULL; | 
|  | 1010 |  | 
|  | 1011 | inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms); | 
|  | 1012 | if (unlikely(!inode)) { | 
|  | 1013 | dput(dentry); | 
|  | 1014 | return NULL; | 
|  | 1015 | } | 
|  | 1016 |  | 
|  | 1017 | d_add(dentry, inode); | 
|  | 1018 | if (dentry_p) | 
|  | 1019 | *dentry_p = dentry; | 
|  | 1020 |  | 
|  | 1021 | return inode; | 
|  | 1022 | } | 
|  | 1023 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1024 | /* Super block */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1025 | static const struct super_operations ffs_sb_operations = { | 
|  | 1026 | .statfs =	simple_statfs, | 
|  | 1027 | .drop_inode =	generic_delete_inode, | 
|  | 1028 | }; | 
|  | 1029 |  | 
|  | 1030 | struct ffs_sb_fill_data { | 
|  | 1031 | struct ffs_file_perms perms; | 
|  | 1032 | umode_t root_mode; | 
|  | 1033 | const char *dev_name; | 
|  | 1034 | }; | 
|  | 1035 |  | 
|  | 1036 | static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) | 
|  | 1037 | { | 
|  | 1038 | struct ffs_sb_fill_data *data = _data; | 
|  | 1039 | struct inode	*inode; | 
|  | 1040 | struct dentry	*d; | 
|  | 1041 | struct ffs_data	*ffs; | 
|  | 1042 |  | 
|  | 1043 | ENTER(); | 
|  | 1044 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1045 | /* Initialise data */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1046 | ffs = ffs_data_new(); | 
|  | 1047 | if (unlikely(!ffs)) | 
|  | 1048 | goto enomem0; | 
|  | 1049 |  | 
|  | 1050 | ffs->sb              = sb; | 
|  | 1051 | ffs->dev_name        = data->dev_name; | 
|  | 1052 | ffs->file_perms      = data->perms; | 
|  | 1053 |  | 
|  | 1054 | sb->s_fs_info        = ffs; | 
|  | 1055 | sb->s_blocksize      = PAGE_CACHE_SIZE; | 
|  | 1056 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 
|  | 1057 | sb->s_magic          = FUNCTIONFS_MAGIC; | 
|  | 1058 | sb->s_op             = &ffs_sb_operations; | 
|  | 1059 | sb->s_time_gran      = 1; | 
|  | 1060 |  | 
|  | 1061 | /* Root inode */ | 
|  | 1062 | data->perms.mode = data->root_mode; | 
|  | 1063 | inode = ffs_sb_make_inode(sb, NULL, | 
|  | 1064 | &simple_dir_operations, | 
|  | 1065 | &simple_dir_inode_operations, | 
|  | 1066 | &data->perms); | 
|  | 1067 | if (unlikely(!inode)) | 
|  | 1068 | goto enomem1; | 
|  | 1069 | d = d_alloc_root(inode); | 
|  | 1070 | if (unlikely(!d)) | 
|  | 1071 | goto enomem2; | 
|  | 1072 | sb->s_root = d; | 
|  | 1073 |  | 
|  | 1074 | /* EP0 file */ | 
|  | 1075 | if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, | 
|  | 1076 | &ffs_ep0_operations, NULL))) | 
|  | 1077 | goto enomem3; | 
|  | 1078 |  | 
|  | 1079 | return 0; | 
|  | 1080 |  | 
|  | 1081 | enomem3: | 
|  | 1082 | dput(d); | 
|  | 1083 | enomem2: | 
|  | 1084 | iput(inode); | 
|  | 1085 | enomem1: | 
|  | 1086 | ffs_data_put(ffs); | 
|  | 1087 | enomem0: | 
|  | 1088 | return -ENOMEM; | 
|  | 1089 | } | 
|  | 1090 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1091 | static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) | 
|  | 1092 | { | 
|  | 1093 | ENTER(); | 
|  | 1094 |  | 
|  | 1095 | if (!opts || !*opts) | 
|  | 1096 | return 0; | 
|  | 1097 |  | 
|  | 1098 | for (;;) { | 
|  | 1099 | char *end, *eq, *comma; | 
|  | 1100 | unsigned long value; | 
|  | 1101 |  | 
|  | 1102 | /* Option limit */ | 
|  | 1103 | comma = strchr(opts, ','); | 
|  | 1104 | if (comma) | 
|  | 1105 | *comma = 0; | 
|  | 1106 |  | 
|  | 1107 | /* Value limit */ | 
|  | 1108 | eq = strchr(opts, '='); | 
|  | 1109 | if (unlikely(!eq)) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1110 | pr_err("'=' missing in %s\n", opts); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1111 | return -EINVAL; | 
|  | 1112 | } | 
|  | 1113 | *eq = 0; | 
|  | 1114 |  | 
|  | 1115 | /* Parse value */ | 
|  | 1116 | value = simple_strtoul(eq + 1, &end, 0); | 
|  | 1117 | if (unlikely(*end != ',' && *end != 0)) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1118 | pr_err("%s: invalid value: %s\n", opts, eq + 1); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1119 | return -EINVAL; | 
|  | 1120 | } | 
|  | 1121 |  | 
|  | 1122 | /* Interpret option */ | 
|  | 1123 | switch (eq - opts) { | 
|  | 1124 | case 5: | 
|  | 1125 | if (!memcmp(opts, "rmode", 5)) | 
|  | 1126 | data->root_mode  = (value & 0555) | S_IFDIR; | 
|  | 1127 | else if (!memcmp(opts, "fmode", 5)) | 
|  | 1128 | data->perms.mode = (value & 0666) | S_IFREG; | 
|  | 1129 | else | 
|  | 1130 | goto invalid; | 
|  | 1131 | break; | 
|  | 1132 |  | 
|  | 1133 | case 4: | 
|  | 1134 | if (!memcmp(opts, "mode", 4)) { | 
|  | 1135 | data->root_mode  = (value & 0555) | S_IFDIR; | 
|  | 1136 | data->perms.mode = (value & 0666) | S_IFREG; | 
|  | 1137 | } else { | 
|  | 1138 | goto invalid; | 
|  | 1139 | } | 
|  | 1140 | break; | 
|  | 1141 |  | 
|  | 1142 | case 3: | 
|  | 1143 | if (!memcmp(opts, "uid", 3)) | 
|  | 1144 | data->perms.uid = value; | 
|  | 1145 | else if (!memcmp(opts, "gid", 3)) | 
|  | 1146 | data->perms.gid = value; | 
|  | 1147 | else | 
|  | 1148 | goto invalid; | 
|  | 1149 | break; | 
|  | 1150 |  | 
|  | 1151 | default: | 
|  | 1152 | invalid: | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1153 | pr_err("%s: invalid option\n", opts); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1154 | return -EINVAL; | 
|  | 1155 | } | 
|  | 1156 |  | 
|  | 1157 | /* Next iteration */ | 
|  | 1158 | if (!comma) | 
|  | 1159 | break; | 
|  | 1160 | opts = comma + 1; | 
|  | 1161 | } | 
|  | 1162 |  | 
|  | 1163 | return 0; | 
|  | 1164 | } | 
|  | 1165 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1166 | /* "mount -t functionfs dev_name /dev/function" ends up here */ | 
|  | 1167 |  | 
| Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 1168 | static struct dentry * | 
|  | 1169 | ffs_fs_mount(struct file_system_type *t, int flags, | 
|  | 1170 | const char *dev_name, void *opts) | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1171 | { | 
|  | 1172 | struct ffs_sb_fill_data data = { | 
|  | 1173 | .perms = { | 
|  | 1174 | .mode = S_IFREG | 0600, | 
|  | 1175 | .uid = 0, | 
|  | 1176 | .gid = 0 | 
|  | 1177 | }, | 
|  | 1178 | .root_mode = S_IFDIR | 0500, | 
|  | 1179 | }; | 
|  | 1180 | int ret; | 
|  | 1181 |  | 
|  | 1182 | ENTER(); | 
|  | 1183 |  | 
|  | 1184 | ret = functionfs_check_dev_callback(dev_name); | 
|  | 1185 | if (unlikely(ret < 0)) | 
| Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 1186 | return ERR_PTR(ret); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1187 |  | 
|  | 1188 | ret = ffs_fs_parse_opts(&data, opts); | 
|  | 1189 | if (unlikely(ret < 0)) | 
| Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 1190 | return ERR_PTR(ret); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1191 |  | 
|  | 1192 | data.dev_name = dev_name; | 
| Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 1193 | return mount_single(t, flags, &data, ffs_sb_fill); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1194 | } | 
|  | 1195 |  | 
|  | 1196 | static void | 
|  | 1197 | ffs_fs_kill_sb(struct super_block *sb) | 
|  | 1198 | { | 
|  | 1199 | void *ptr; | 
|  | 1200 |  | 
|  | 1201 | ENTER(); | 
|  | 1202 |  | 
|  | 1203 | kill_litter_super(sb); | 
|  | 1204 | ptr = xchg(&sb->s_fs_info, NULL); | 
|  | 1205 | if (ptr) | 
|  | 1206 | ffs_data_put(ptr); | 
|  | 1207 | } | 
|  | 1208 |  | 
|  | 1209 | static struct file_system_type ffs_fs_type = { | 
|  | 1210 | .owner		= THIS_MODULE, | 
|  | 1211 | .name		= "functionfs", | 
| Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 1212 | .mount		= ffs_fs_mount, | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1213 | .kill_sb	= ffs_fs_kill_sb, | 
|  | 1214 | }; | 
|  | 1215 |  | 
|  | 1216 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1217 | /* Driver's main init/cleanup functions *************************************/ | 
|  | 1218 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1219 | static int functionfs_init(void) | 
|  | 1220 | { | 
|  | 1221 | int ret; | 
|  | 1222 |  | 
|  | 1223 | ENTER(); | 
|  | 1224 |  | 
|  | 1225 | ret = register_filesystem(&ffs_fs_type); | 
|  | 1226 | if (likely(!ret)) | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1227 | pr_info("file system registered\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1228 | else | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1229 | pr_err("failed registering file system (%d)\n", ret); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1230 |  | 
|  | 1231 | return ret; | 
|  | 1232 | } | 
|  | 1233 |  | 
|  | 1234 | static void functionfs_cleanup(void) | 
|  | 1235 | { | 
|  | 1236 | ENTER(); | 
|  | 1237 |  | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1238 | pr_info("unloading\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1239 | unregister_filesystem(&ffs_fs_type); | 
|  | 1240 | } | 
|  | 1241 |  | 
|  | 1242 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1243 | /* ffs_data and ffs_function construction and destruction code **************/ | 
|  | 1244 |  | 
|  | 1245 | static void ffs_data_clear(struct ffs_data *ffs); | 
|  | 1246 | static void ffs_data_reset(struct ffs_data *ffs); | 
|  | 1247 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1248 | static void ffs_data_get(struct ffs_data *ffs) | 
|  | 1249 | { | 
|  | 1250 | ENTER(); | 
|  | 1251 |  | 
|  | 1252 | atomic_inc(&ffs->ref); | 
|  | 1253 | } | 
|  | 1254 |  | 
|  | 1255 | static void ffs_data_opened(struct ffs_data *ffs) | 
|  | 1256 | { | 
|  | 1257 | ENTER(); | 
|  | 1258 |  | 
|  | 1259 | atomic_inc(&ffs->ref); | 
|  | 1260 | atomic_inc(&ffs->opened); | 
|  | 1261 | } | 
|  | 1262 |  | 
|  | 1263 | static void ffs_data_put(struct ffs_data *ffs) | 
|  | 1264 | { | 
|  | 1265 | ENTER(); | 
|  | 1266 |  | 
|  | 1267 | if (unlikely(atomic_dec_and_test(&ffs->ref))) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1268 | pr_info("%s(): freeing\n", __func__); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1269 | ffs_data_clear(ffs); | 
|  | 1270 | BUG_ON(mutex_is_locked(&ffs->mutex) || | 
|  | 1271 | spin_is_locked(&ffs->ev.waitq.lock) || | 
|  | 1272 | waitqueue_active(&ffs->ev.waitq) || | 
|  | 1273 | waitqueue_active(&ffs->ep0req_completion.wait)); | 
|  | 1274 | kfree(ffs); | 
|  | 1275 | } | 
|  | 1276 | } | 
|  | 1277 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1278 | static void ffs_data_closed(struct ffs_data *ffs) | 
|  | 1279 | { | 
|  | 1280 | ENTER(); | 
|  | 1281 |  | 
|  | 1282 | if (atomic_dec_and_test(&ffs->opened)) { | 
|  | 1283 | ffs->state = FFS_CLOSING; | 
|  | 1284 | ffs_data_reset(ffs); | 
|  | 1285 | } | 
|  | 1286 |  | 
|  | 1287 | ffs_data_put(ffs); | 
|  | 1288 | } | 
|  | 1289 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1290 | static struct ffs_data *ffs_data_new(void) | 
|  | 1291 | { | 
|  | 1292 | struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL); | 
|  | 1293 | if (unlikely(!ffs)) | 
|  | 1294 | return 0; | 
|  | 1295 |  | 
|  | 1296 | ENTER(); | 
|  | 1297 |  | 
|  | 1298 | atomic_set(&ffs->ref, 1); | 
|  | 1299 | atomic_set(&ffs->opened, 0); | 
|  | 1300 | ffs->state = FFS_READ_DESCRIPTORS; | 
|  | 1301 | mutex_init(&ffs->mutex); | 
|  | 1302 | spin_lock_init(&ffs->eps_lock); | 
|  | 1303 | init_waitqueue_head(&ffs->ev.waitq); | 
|  | 1304 | init_completion(&ffs->ep0req_completion); | 
|  | 1305 |  | 
|  | 1306 | /* XXX REVISIT need to update it in some places, or do we? */ | 
|  | 1307 | ffs->ev.can_stall = 1; | 
|  | 1308 |  | 
|  | 1309 | return ffs; | 
|  | 1310 | } | 
|  | 1311 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1312 | static void ffs_data_clear(struct ffs_data *ffs) | 
|  | 1313 | { | 
|  | 1314 | ENTER(); | 
|  | 1315 |  | 
|  | 1316 | if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags)) | 
|  | 1317 | functionfs_closed_callback(ffs); | 
|  | 1318 |  | 
|  | 1319 | BUG_ON(ffs->gadget); | 
|  | 1320 |  | 
|  | 1321 | if (ffs->epfiles) | 
|  | 1322 | ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); | 
|  | 1323 |  | 
|  | 1324 | kfree(ffs->raw_descs); | 
|  | 1325 | kfree(ffs->raw_strings); | 
|  | 1326 | kfree(ffs->stringtabs); | 
|  | 1327 | } | 
|  | 1328 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1329 | static void ffs_data_reset(struct ffs_data *ffs) | 
|  | 1330 | { | 
|  | 1331 | ENTER(); | 
|  | 1332 |  | 
|  | 1333 | ffs_data_clear(ffs); | 
|  | 1334 |  | 
|  | 1335 | ffs->epfiles = NULL; | 
|  | 1336 | ffs->raw_descs = NULL; | 
|  | 1337 | ffs->raw_strings = NULL; | 
|  | 1338 | ffs->stringtabs = NULL; | 
|  | 1339 |  | 
|  | 1340 | ffs->raw_descs_length = 0; | 
|  | 1341 | ffs->raw_fs_descs_length = 0; | 
|  | 1342 | ffs->fs_descs_count = 0; | 
|  | 1343 | ffs->hs_descs_count = 0; | 
|  | 1344 |  | 
|  | 1345 | ffs->strings_count = 0; | 
|  | 1346 | ffs->interfaces_count = 0; | 
|  | 1347 | ffs->eps_count = 0; | 
|  | 1348 |  | 
|  | 1349 | ffs->ev.count = 0; | 
|  | 1350 |  | 
|  | 1351 | ffs->state = FFS_READ_DESCRIPTORS; | 
|  | 1352 | ffs->setup_state = FFS_NO_SETUP; | 
|  | 1353 | ffs->flags = 0; | 
|  | 1354 | } | 
|  | 1355 |  | 
|  | 1356 |  | 
|  | 1357 | static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) | 
|  | 1358 | { | 
| Michal Nazarewicz | fd7c9a0 | 2010-06-16 12:08:00 +0200 | [diff] [blame] | 1359 | struct usb_gadget_strings **lang; | 
|  | 1360 | int first_id; | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1361 |  | 
|  | 1362 | ENTER(); | 
|  | 1363 |  | 
|  | 1364 | if (WARN_ON(ffs->state != FFS_ACTIVE | 
|  | 1365 | || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) | 
|  | 1366 | return -EBADFD; | 
|  | 1367 |  | 
| Michal Nazarewicz | fd7c9a0 | 2010-06-16 12:08:00 +0200 | [diff] [blame] | 1368 | first_id = usb_string_ids_n(cdev, ffs->strings_count); | 
|  | 1369 | if (unlikely(first_id < 0)) | 
|  | 1370 | return first_id; | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1371 |  | 
|  | 1372 | ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); | 
|  | 1373 | if (unlikely(!ffs->ep0req)) | 
|  | 1374 | return -ENOMEM; | 
|  | 1375 | ffs->ep0req->complete = ffs_ep0_complete; | 
|  | 1376 | ffs->ep0req->context = ffs; | 
|  | 1377 |  | 
| Michal Nazarewicz | fd7c9a0 | 2010-06-16 12:08:00 +0200 | [diff] [blame] | 1378 | lang = ffs->stringtabs; | 
|  | 1379 | for (lang = ffs->stringtabs; *lang; ++lang) { | 
|  | 1380 | struct usb_string *str = (*lang)->strings; | 
|  | 1381 | int id = first_id; | 
|  | 1382 | for (; str->s; ++id, ++str) | 
|  | 1383 | str->id = id; | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1384 | } | 
|  | 1385 |  | 
|  | 1386 | ffs->gadget = cdev->gadget; | 
| Michal Nazarewicz | fd7c9a0 | 2010-06-16 12:08:00 +0200 | [diff] [blame] | 1387 | ffs_data_get(ffs); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1388 | return 0; | 
|  | 1389 | } | 
|  | 1390 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1391 | static void functionfs_unbind(struct ffs_data *ffs) | 
|  | 1392 | { | 
|  | 1393 | ENTER(); | 
|  | 1394 |  | 
|  | 1395 | if (!WARN_ON(!ffs->gadget)) { | 
|  | 1396 | usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req); | 
|  | 1397 | ffs->ep0req = NULL; | 
|  | 1398 | ffs->gadget = NULL; | 
|  | 1399 | ffs_data_put(ffs); | 
|  | 1400 | } | 
|  | 1401 | } | 
|  | 1402 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1403 | static int ffs_epfiles_create(struct ffs_data *ffs) | 
|  | 1404 | { | 
|  | 1405 | struct ffs_epfile *epfile, *epfiles; | 
|  | 1406 | unsigned i, count; | 
|  | 1407 |  | 
|  | 1408 | ENTER(); | 
|  | 1409 |  | 
|  | 1410 | count = ffs->eps_count; | 
|  | 1411 | epfiles = kzalloc(count * sizeof *epfiles, GFP_KERNEL); | 
|  | 1412 | if (!epfiles) | 
|  | 1413 | return -ENOMEM; | 
|  | 1414 |  | 
|  | 1415 | epfile = epfiles; | 
|  | 1416 | for (i = 1; i <= count; ++i, ++epfile) { | 
|  | 1417 | epfile->ffs = ffs; | 
|  | 1418 | mutex_init(&epfile->mutex); | 
|  | 1419 | init_waitqueue_head(&epfile->wait); | 
|  | 1420 | sprintf(epfiles->name, "ep%u",  i); | 
|  | 1421 | if (!unlikely(ffs_sb_create_file(ffs->sb, epfiles->name, epfile, | 
|  | 1422 | &ffs_epfile_operations, | 
|  | 1423 | &epfile->dentry))) { | 
|  | 1424 | ffs_epfiles_destroy(epfiles, i - 1); | 
|  | 1425 | return -ENOMEM; | 
|  | 1426 | } | 
|  | 1427 | } | 
|  | 1428 |  | 
|  | 1429 | ffs->epfiles = epfiles; | 
|  | 1430 | return 0; | 
|  | 1431 | } | 
|  | 1432 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1433 | static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) | 
|  | 1434 | { | 
|  | 1435 | struct ffs_epfile *epfile = epfiles; | 
|  | 1436 |  | 
|  | 1437 | ENTER(); | 
|  | 1438 |  | 
|  | 1439 | for (; count; --count, ++epfile) { | 
|  | 1440 | BUG_ON(mutex_is_locked(&epfile->mutex) || | 
|  | 1441 | waitqueue_active(&epfile->wait)); | 
|  | 1442 | if (epfile->dentry) { | 
|  | 1443 | d_delete(epfile->dentry); | 
|  | 1444 | dput(epfile->dentry); | 
|  | 1445 | epfile->dentry = NULL; | 
|  | 1446 | } | 
|  | 1447 | } | 
|  | 1448 |  | 
|  | 1449 | kfree(epfiles); | 
|  | 1450 | } | 
|  | 1451 |  | 
| Michal Nazarewicz | 7898aee | 2010-06-16 12:07:58 +0200 | [diff] [blame] | 1452 | static int functionfs_bind_config(struct usb_composite_dev *cdev, | 
|  | 1453 | struct usb_configuration *c, | 
|  | 1454 | struct ffs_data *ffs) | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1455 | { | 
|  | 1456 | struct ffs_function *func; | 
|  | 1457 | int ret; | 
|  | 1458 |  | 
|  | 1459 | ENTER(); | 
|  | 1460 |  | 
|  | 1461 | func = kzalloc(sizeof *func, GFP_KERNEL); | 
|  | 1462 | if (unlikely(!func)) | 
|  | 1463 | return -ENOMEM; | 
|  | 1464 |  | 
|  | 1465 | func->function.name    = "Function FS Gadget"; | 
|  | 1466 | func->function.strings = ffs->stringtabs; | 
|  | 1467 |  | 
|  | 1468 | func->function.bind    = ffs_func_bind; | 
|  | 1469 | func->function.unbind  = ffs_func_unbind; | 
|  | 1470 | func->function.set_alt = ffs_func_set_alt; | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1471 | func->function.disable = ffs_func_disable; | 
|  | 1472 | func->function.setup   = ffs_func_setup; | 
|  | 1473 | func->function.suspend = ffs_func_suspend; | 
|  | 1474 | func->function.resume  = ffs_func_resume; | 
|  | 1475 |  | 
|  | 1476 | func->conf   = c; | 
|  | 1477 | func->gadget = cdev->gadget; | 
|  | 1478 | func->ffs = ffs; | 
|  | 1479 | ffs_data_get(ffs); | 
|  | 1480 |  | 
|  | 1481 | ret = usb_add_function(c, &func->function); | 
|  | 1482 | if (unlikely(ret)) | 
|  | 1483 | ffs_func_free(func); | 
|  | 1484 |  | 
|  | 1485 | return ret; | 
|  | 1486 | } | 
|  | 1487 |  | 
|  | 1488 | static void ffs_func_free(struct ffs_function *func) | 
|  | 1489 | { | 
|  | 1490 | ENTER(); | 
|  | 1491 |  | 
|  | 1492 | ffs_data_put(func->ffs); | 
|  | 1493 |  | 
|  | 1494 | kfree(func->eps); | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1495 | /* | 
|  | 1496 | * eps and interfaces_nums are allocated in the same chunk so | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1497 | * only one free is required.  Descriptors are also allocated | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1498 | * in the same chunk. | 
|  | 1499 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1500 |  | 
|  | 1501 | kfree(func); | 
|  | 1502 | } | 
|  | 1503 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1504 | static void ffs_func_eps_disable(struct ffs_function *func) | 
|  | 1505 | { | 
|  | 1506 | struct ffs_ep *ep         = func->eps; | 
|  | 1507 | struct ffs_epfile *epfile = func->ffs->epfiles; | 
|  | 1508 | unsigned count            = func->ffs->eps_count; | 
|  | 1509 | unsigned long flags; | 
|  | 1510 |  | 
|  | 1511 | spin_lock_irqsave(&func->ffs->eps_lock, flags); | 
|  | 1512 | do { | 
|  | 1513 | /* pending requests get nuked */ | 
|  | 1514 | if (likely(ep->ep)) | 
|  | 1515 | usb_ep_disable(ep->ep); | 
|  | 1516 | epfile->ep = NULL; | 
|  | 1517 |  | 
|  | 1518 | ++ep; | 
|  | 1519 | ++epfile; | 
|  | 1520 | } while (--count); | 
|  | 1521 | spin_unlock_irqrestore(&func->ffs->eps_lock, flags); | 
|  | 1522 | } | 
|  | 1523 |  | 
|  | 1524 | static int ffs_func_eps_enable(struct ffs_function *func) | 
|  | 1525 | { | 
|  | 1526 | struct ffs_data *ffs      = func->ffs; | 
|  | 1527 | struct ffs_ep *ep         = func->eps; | 
|  | 1528 | struct ffs_epfile *epfile = ffs->epfiles; | 
|  | 1529 | unsigned count            = ffs->eps_count; | 
|  | 1530 | unsigned long flags; | 
|  | 1531 | int ret = 0; | 
|  | 1532 |  | 
|  | 1533 | spin_lock_irqsave(&func->ffs->eps_lock, flags); | 
|  | 1534 | do { | 
|  | 1535 | struct usb_endpoint_descriptor *ds; | 
|  | 1536 | ds = ep->descs[ep->descs[1] ? 1 : 0]; | 
|  | 1537 |  | 
|  | 1538 | ep->ep->driver_data = ep; | 
| Tatyana Brokhman | 72c973d | 2011-06-28 16:33:48 +0300 | [diff] [blame] | 1539 | ep->ep->desc = ds; | 
|  | 1540 | ret = usb_ep_enable(ep->ep); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1541 | if (likely(!ret)) { | 
|  | 1542 | epfile->ep = ep; | 
|  | 1543 | epfile->in = usb_endpoint_dir_in(ds); | 
|  | 1544 | epfile->isoc = usb_endpoint_xfer_isoc(ds); | 
|  | 1545 | } else { | 
|  | 1546 | break; | 
|  | 1547 | } | 
|  | 1548 |  | 
|  | 1549 | wake_up(&epfile->wait); | 
|  | 1550 |  | 
|  | 1551 | ++ep; | 
|  | 1552 | ++epfile; | 
|  | 1553 | } while (--count); | 
|  | 1554 | spin_unlock_irqrestore(&func->ffs->eps_lock, flags); | 
|  | 1555 |  | 
|  | 1556 | return ret; | 
|  | 1557 | } | 
|  | 1558 |  | 
|  | 1559 |  | 
|  | 1560 | /* Parsing and building descriptors and strings *****************************/ | 
|  | 1561 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1562 | /* | 
|  | 1563 | * This validates if data pointed by data is a valid USB descriptor as | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1564 | * well as record how many interfaces, endpoints and strings are | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1565 | * required by given configuration.  Returns address after the | 
|  | 1566 | * descriptor or NULL if data is invalid. | 
|  | 1567 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1568 |  | 
|  | 1569 | enum ffs_entity_type { | 
|  | 1570 | FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT | 
|  | 1571 | }; | 
|  | 1572 |  | 
|  | 1573 | typedef int (*ffs_entity_callback)(enum ffs_entity_type entity, | 
|  | 1574 | u8 *valuep, | 
|  | 1575 | struct usb_descriptor_header *desc, | 
|  | 1576 | void *priv); | 
|  | 1577 |  | 
|  | 1578 | static int __must_check ffs_do_desc(char *data, unsigned len, | 
|  | 1579 | ffs_entity_callback entity, void *priv) | 
|  | 1580 | { | 
|  | 1581 | struct usb_descriptor_header *_ds = (void *)data; | 
|  | 1582 | u8 length; | 
|  | 1583 | int ret; | 
|  | 1584 |  | 
|  | 1585 | ENTER(); | 
|  | 1586 |  | 
|  | 1587 | /* At least two bytes are required: length and type */ | 
|  | 1588 | if (len < 2) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1589 | pr_vdebug("descriptor too short\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1590 | return -EINVAL; | 
|  | 1591 | } | 
|  | 1592 |  | 
|  | 1593 | /* If we have at least as many bytes as the descriptor takes? */ | 
|  | 1594 | length = _ds->bLength; | 
|  | 1595 | if (len < length) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1596 | pr_vdebug("descriptor longer then available data\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1597 | return -EINVAL; | 
|  | 1598 | } | 
|  | 1599 |  | 
|  | 1600 | #define __entity_check_INTERFACE(val)  1 | 
|  | 1601 | #define __entity_check_STRING(val)     (val) | 
|  | 1602 | #define __entity_check_ENDPOINT(val)   ((val) & USB_ENDPOINT_NUMBER_MASK) | 
|  | 1603 | #define __entity(type, val) do {					\ | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1604 | pr_vdebug("entity " #type "(%02x)\n", (val));		\ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1605 | if (unlikely(!__entity_check_ ##type(val))) {		\ | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1606 | pr_vdebug("invalid entity's value\n");		\ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1607 | return -EINVAL;					\ | 
|  | 1608 | }							\ | 
|  | 1609 | ret = entity(FFS_ ##type, &val, _ds, priv);		\ | 
|  | 1610 | if (unlikely(ret < 0)) {				\ | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1611 | pr_debug("entity " #type "(%02x); ret = %d\n",	\ | 
| Michal Nazarewicz | d8df0b6 | 2010-11-12 14:29:29 +0100 | [diff] [blame] | 1612 | (val), ret);				\ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1613 | return ret;					\ | 
|  | 1614 | }							\ | 
|  | 1615 | } while (0) | 
|  | 1616 |  | 
|  | 1617 | /* Parse descriptor depending on type. */ | 
|  | 1618 | switch (_ds->bDescriptorType) { | 
|  | 1619 | case USB_DT_DEVICE: | 
|  | 1620 | case USB_DT_CONFIG: | 
|  | 1621 | case USB_DT_STRING: | 
|  | 1622 | case USB_DT_DEVICE_QUALIFIER: | 
|  | 1623 | /* function can't have any of those */ | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1624 | pr_vdebug("descriptor reserved for gadget: %d\n", | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1625 | _ds->bDescriptorType); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1626 | return -EINVAL; | 
|  | 1627 |  | 
|  | 1628 | case USB_DT_INTERFACE: { | 
|  | 1629 | struct usb_interface_descriptor *ds = (void *)_ds; | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1630 | pr_vdebug("interface descriptor\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1631 | if (length != sizeof *ds) | 
|  | 1632 | goto inv_length; | 
|  | 1633 |  | 
|  | 1634 | __entity(INTERFACE, ds->bInterfaceNumber); | 
|  | 1635 | if (ds->iInterface) | 
|  | 1636 | __entity(STRING, ds->iInterface); | 
|  | 1637 | } | 
|  | 1638 | break; | 
|  | 1639 |  | 
|  | 1640 | case USB_DT_ENDPOINT: { | 
|  | 1641 | struct usb_endpoint_descriptor *ds = (void *)_ds; | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1642 | pr_vdebug("endpoint descriptor\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1643 | if (length != USB_DT_ENDPOINT_SIZE && | 
|  | 1644 | length != USB_DT_ENDPOINT_AUDIO_SIZE) | 
|  | 1645 | goto inv_length; | 
|  | 1646 | __entity(ENDPOINT, ds->bEndpointAddress); | 
|  | 1647 | } | 
|  | 1648 | break; | 
|  | 1649 |  | 
|  | 1650 | case USB_DT_OTG: | 
|  | 1651 | if (length != sizeof(struct usb_otg_descriptor)) | 
|  | 1652 | goto inv_length; | 
|  | 1653 | break; | 
|  | 1654 |  | 
|  | 1655 | case USB_DT_INTERFACE_ASSOCIATION: { | 
|  | 1656 | struct usb_interface_assoc_descriptor *ds = (void *)_ds; | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1657 | pr_vdebug("interface association descriptor\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1658 | if (length != sizeof *ds) | 
|  | 1659 | goto inv_length; | 
|  | 1660 | if (ds->iFunction) | 
|  | 1661 | __entity(STRING, ds->iFunction); | 
|  | 1662 | } | 
|  | 1663 | break; | 
|  | 1664 |  | 
|  | 1665 | case USB_DT_OTHER_SPEED_CONFIG: | 
|  | 1666 | case USB_DT_INTERFACE_POWER: | 
|  | 1667 | case USB_DT_DEBUG: | 
|  | 1668 | case USB_DT_SECURITY: | 
|  | 1669 | case USB_DT_CS_RADIO_CONTROL: | 
|  | 1670 | /* TODO */ | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1671 | pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1672 | return -EINVAL; | 
|  | 1673 |  | 
|  | 1674 | default: | 
|  | 1675 | /* We should never be here */ | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1676 | pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1677 | return -EINVAL; | 
|  | 1678 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1679 | inv_length: | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1680 | pr_vdebug("invalid length: %d (descriptor %d)\n", | 
| Michal Nazarewicz | d8df0b6 | 2010-11-12 14:29:29 +0100 | [diff] [blame] | 1681 | _ds->bLength, _ds->bDescriptorType); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1682 | return -EINVAL; | 
|  | 1683 | } | 
|  | 1684 |  | 
|  | 1685 | #undef __entity | 
|  | 1686 | #undef __entity_check_DESCRIPTOR | 
|  | 1687 | #undef __entity_check_INTERFACE | 
|  | 1688 | #undef __entity_check_STRING | 
|  | 1689 | #undef __entity_check_ENDPOINT | 
|  | 1690 |  | 
|  | 1691 | return length; | 
|  | 1692 | } | 
|  | 1693 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1694 | static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, | 
|  | 1695 | ffs_entity_callback entity, void *priv) | 
|  | 1696 | { | 
|  | 1697 | const unsigned _len = len; | 
|  | 1698 | unsigned long num = 0; | 
|  | 1699 |  | 
|  | 1700 | ENTER(); | 
|  | 1701 |  | 
|  | 1702 | for (;;) { | 
|  | 1703 | int ret; | 
|  | 1704 |  | 
|  | 1705 | if (num == count) | 
|  | 1706 | data = NULL; | 
|  | 1707 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1708 | /* Record "descriptor" entity */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1709 | ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv); | 
|  | 1710 | if (unlikely(ret < 0)) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1711 | pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n", | 
| Michal Nazarewicz | d8df0b6 | 2010-11-12 14:29:29 +0100 | [diff] [blame] | 1712 | num, ret); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1713 | return ret; | 
|  | 1714 | } | 
|  | 1715 |  | 
|  | 1716 | if (!data) | 
|  | 1717 | return _len - len; | 
|  | 1718 |  | 
|  | 1719 | ret = ffs_do_desc(data, len, entity, priv); | 
|  | 1720 | if (unlikely(ret < 0)) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 1721 | pr_debug("%s returns %d\n", __func__, ret); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1722 | return ret; | 
|  | 1723 | } | 
|  | 1724 |  | 
|  | 1725 | len -= ret; | 
|  | 1726 | data += ret; | 
|  | 1727 | ++num; | 
|  | 1728 | } | 
|  | 1729 | } | 
|  | 1730 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1731 | static int __ffs_data_do_entity(enum ffs_entity_type type, | 
|  | 1732 | u8 *valuep, struct usb_descriptor_header *desc, | 
|  | 1733 | void *priv) | 
|  | 1734 | { | 
|  | 1735 | struct ffs_data *ffs = priv; | 
|  | 1736 |  | 
|  | 1737 | ENTER(); | 
|  | 1738 |  | 
|  | 1739 | switch (type) { | 
|  | 1740 | case FFS_DESCRIPTOR: | 
|  | 1741 | break; | 
|  | 1742 |  | 
|  | 1743 | case FFS_INTERFACE: | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1744 | /* | 
|  | 1745 | * Interfaces are indexed from zero so if we | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1746 | * encountered interface "n" then there are at least | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1747 | * "n+1" interfaces. | 
|  | 1748 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1749 | if (*valuep >= ffs->interfaces_count) | 
|  | 1750 | ffs->interfaces_count = *valuep + 1; | 
|  | 1751 | break; | 
|  | 1752 |  | 
|  | 1753 | case FFS_STRING: | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1754 | /* | 
|  | 1755 | * Strings are indexed from 1 (0 is magic ;) reserved | 
|  | 1756 | * for languages list or some such) | 
|  | 1757 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1758 | if (*valuep > ffs->strings_count) | 
|  | 1759 | ffs->strings_count = *valuep; | 
|  | 1760 | break; | 
|  | 1761 |  | 
|  | 1762 | case FFS_ENDPOINT: | 
|  | 1763 | /* Endpoints are indexed from 1 as well. */ | 
|  | 1764 | if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count) | 
|  | 1765 | ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK); | 
|  | 1766 | break; | 
|  | 1767 | } | 
|  | 1768 |  | 
|  | 1769 | return 0; | 
|  | 1770 | } | 
|  | 1771 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1772 | static int __ffs_data_got_descs(struct ffs_data *ffs, | 
|  | 1773 | char *const _data, size_t len) | 
|  | 1774 | { | 
|  | 1775 | unsigned fs_count, hs_count; | 
|  | 1776 | int fs_len, ret = -EINVAL; | 
|  | 1777 | char *data = _data; | 
|  | 1778 |  | 
|  | 1779 | ENTER(); | 
|  | 1780 |  | 
|  | 1781 | if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC || | 
|  | 1782 | get_unaligned_le32(data + 4) != len)) | 
|  | 1783 | goto error; | 
|  | 1784 | fs_count = get_unaligned_le32(data +  8); | 
|  | 1785 | hs_count = get_unaligned_le32(data + 12); | 
|  | 1786 |  | 
|  | 1787 | if (!fs_count && !hs_count) | 
|  | 1788 | goto einval; | 
|  | 1789 |  | 
|  | 1790 | data += 16; | 
|  | 1791 | len  -= 16; | 
|  | 1792 |  | 
|  | 1793 | if (likely(fs_count)) { | 
|  | 1794 | fs_len = ffs_do_descs(fs_count, data, len, | 
|  | 1795 | __ffs_data_do_entity, ffs); | 
|  | 1796 | if (unlikely(fs_len < 0)) { | 
|  | 1797 | ret = fs_len; | 
|  | 1798 | goto error; | 
|  | 1799 | } | 
|  | 1800 |  | 
|  | 1801 | data += fs_len; | 
|  | 1802 | len  -= fs_len; | 
|  | 1803 | } else { | 
|  | 1804 | fs_len = 0; | 
|  | 1805 | } | 
|  | 1806 |  | 
|  | 1807 | if (likely(hs_count)) { | 
|  | 1808 | ret = ffs_do_descs(hs_count, data, len, | 
|  | 1809 | __ffs_data_do_entity, ffs); | 
|  | 1810 | if (unlikely(ret < 0)) | 
|  | 1811 | goto error; | 
|  | 1812 | } else { | 
|  | 1813 | ret = 0; | 
|  | 1814 | } | 
|  | 1815 |  | 
|  | 1816 | if (unlikely(len != ret)) | 
|  | 1817 | goto einval; | 
|  | 1818 |  | 
|  | 1819 | ffs->raw_fs_descs_length = fs_len; | 
|  | 1820 | ffs->raw_descs_length    = fs_len + ret; | 
|  | 1821 | ffs->raw_descs           = _data; | 
|  | 1822 | ffs->fs_descs_count      = fs_count; | 
|  | 1823 | ffs->hs_descs_count      = hs_count; | 
|  | 1824 |  | 
|  | 1825 | return 0; | 
|  | 1826 |  | 
|  | 1827 | einval: | 
|  | 1828 | ret = -EINVAL; | 
|  | 1829 | error: | 
|  | 1830 | kfree(_data); | 
|  | 1831 | return ret; | 
|  | 1832 | } | 
|  | 1833 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1834 | static int __ffs_data_got_strings(struct ffs_data *ffs, | 
|  | 1835 | char *const _data, size_t len) | 
|  | 1836 | { | 
|  | 1837 | u32 str_count, needed_count, lang_count; | 
|  | 1838 | struct usb_gadget_strings **stringtabs, *t; | 
|  | 1839 | struct usb_string *strings, *s; | 
|  | 1840 | const char *data = _data; | 
|  | 1841 |  | 
|  | 1842 | ENTER(); | 
|  | 1843 |  | 
|  | 1844 | if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || | 
|  | 1845 | get_unaligned_le32(data + 4) != len)) | 
|  | 1846 | goto error; | 
|  | 1847 | str_count  = get_unaligned_le32(data + 8); | 
|  | 1848 | lang_count = get_unaligned_le32(data + 12); | 
|  | 1849 |  | 
|  | 1850 | /* if one is zero the other must be zero */ | 
|  | 1851 | if (unlikely(!str_count != !lang_count)) | 
|  | 1852 | goto error; | 
|  | 1853 |  | 
|  | 1854 | /* Do we have at least as many strings as descriptors need? */ | 
|  | 1855 | needed_count = ffs->strings_count; | 
|  | 1856 | if (unlikely(str_count < needed_count)) | 
|  | 1857 | goto error; | 
|  | 1858 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1859 | /* | 
|  | 1860 | * If we don't need any strings just return and free all | 
|  | 1861 | * memory. | 
|  | 1862 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1863 | if (!needed_count) { | 
|  | 1864 | kfree(_data); | 
|  | 1865 | return 0; | 
|  | 1866 | } | 
|  | 1867 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1868 | /* Allocate everything in one chunk so there's less maintenance. */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1869 | { | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1870 | struct { | 
|  | 1871 | struct usb_gadget_strings *stringtabs[lang_count + 1]; | 
|  | 1872 | struct usb_gadget_strings stringtab[lang_count]; | 
|  | 1873 | struct usb_string strings[lang_count*(needed_count+1)]; | 
|  | 1874 | } *d; | 
|  | 1875 | unsigned i = 0; | 
|  | 1876 |  | 
|  | 1877 | d = kmalloc(sizeof *d, GFP_KERNEL); | 
|  | 1878 | if (unlikely(!d)) { | 
|  | 1879 | kfree(_data); | 
|  | 1880 | return -ENOMEM; | 
|  | 1881 | } | 
|  | 1882 |  | 
|  | 1883 | stringtabs = d->stringtabs; | 
|  | 1884 | t = d->stringtab; | 
|  | 1885 | i = lang_count; | 
|  | 1886 | do { | 
|  | 1887 | *stringtabs++ = t++; | 
|  | 1888 | } while (--i); | 
|  | 1889 | *stringtabs = NULL; | 
|  | 1890 |  | 
|  | 1891 | stringtabs = d->stringtabs; | 
|  | 1892 | t = d->stringtab; | 
|  | 1893 | s = d->strings; | 
|  | 1894 | strings = s; | 
|  | 1895 | } | 
|  | 1896 |  | 
|  | 1897 | /* For each language */ | 
|  | 1898 | data += 16; | 
|  | 1899 | len -= 16; | 
|  | 1900 |  | 
|  | 1901 | do { /* lang_count > 0 so we can use do-while */ | 
|  | 1902 | unsigned needed = needed_count; | 
|  | 1903 |  | 
|  | 1904 | if (unlikely(len < 3)) | 
|  | 1905 | goto error_free; | 
|  | 1906 | t->language = get_unaligned_le16(data); | 
|  | 1907 | t->strings  = s; | 
|  | 1908 | ++t; | 
|  | 1909 |  | 
|  | 1910 | data += 2; | 
|  | 1911 | len -= 2; | 
|  | 1912 |  | 
|  | 1913 | /* For each string */ | 
|  | 1914 | do { /* str_count > 0 so we can use do-while */ | 
|  | 1915 | size_t length = strnlen(data, len); | 
|  | 1916 |  | 
|  | 1917 | if (unlikely(length == len)) | 
|  | 1918 | goto error_free; | 
|  | 1919 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1920 | /* | 
|  | 1921 | * User may provide more strings then we need, | 
|  | 1922 | * if that's the case we simply ignore the | 
|  | 1923 | * rest | 
|  | 1924 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1925 | if (likely(needed)) { | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1926 | /* | 
|  | 1927 | * s->id will be set while adding | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1928 | * function to configuration so for | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1929 | * now just leave garbage here. | 
|  | 1930 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1931 | s->s = data; | 
|  | 1932 | --needed; | 
|  | 1933 | ++s; | 
|  | 1934 | } | 
|  | 1935 |  | 
|  | 1936 | data += length + 1; | 
|  | 1937 | len -= length + 1; | 
|  | 1938 | } while (--str_count); | 
|  | 1939 |  | 
|  | 1940 | s->id = 0;   /* terminator */ | 
|  | 1941 | s->s = NULL; | 
|  | 1942 | ++s; | 
|  | 1943 |  | 
|  | 1944 | } while (--lang_count); | 
|  | 1945 |  | 
|  | 1946 | /* Some garbage left? */ | 
|  | 1947 | if (unlikely(len)) | 
|  | 1948 | goto error_free; | 
|  | 1949 |  | 
|  | 1950 | /* Done! */ | 
|  | 1951 | ffs->stringtabs = stringtabs; | 
|  | 1952 | ffs->raw_strings = _data; | 
|  | 1953 |  | 
|  | 1954 | return 0; | 
|  | 1955 |  | 
|  | 1956 | error_free: | 
|  | 1957 | kfree(stringtabs); | 
|  | 1958 | error: | 
|  | 1959 | kfree(_data); | 
|  | 1960 | return -EINVAL; | 
|  | 1961 | } | 
|  | 1962 |  | 
|  | 1963 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1964 | /* Events handling and management *******************************************/ | 
|  | 1965 |  | 
|  | 1966 | static void __ffs_event_add(struct ffs_data *ffs, | 
|  | 1967 | enum usb_functionfs_event_type type) | 
|  | 1968 | { | 
|  | 1969 | enum usb_functionfs_event_type rem_type1, rem_type2 = type; | 
|  | 1970 | int neg = 0; | 
|  | 1971 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1972 | /* | 
|  | 1973 | * Abort any unhandled setup | 
|  | 1974 | * | 
|  | 1975 | * We do not need to worry about some cmpxchg() changing value | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1976 | * of ffs->setup_state without holding the lock because when | 
|  | 1977 | * state is FFS_SETUP_PENDING cmpxchg() in several places in | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1978 | * the source does nothing. | 
|  | 1979 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1980 | if (ffs->setup_state == FFS_SETUP_PENDING) | 
|  | 1981 | ffs->setup_state = FFS_SETUP_CANCELED; | 
|  | 1982 |  | 
|  | 1983 | switch (type) { | 
|  | 1984 | case FUNCTIONFS_RESUME: | 
|  | 1985 | rem_type2 = FUNCTIONFS_SUSPEND; | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1986 | /* FALL THROUGH */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1987 | case FUNCTIONFS_SUSPEND: | 
|  | 1988 | case FUNCTIONFS_SETUP: | 
|  | 1989 | rem_type1 = type; | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1990 | /* Discard all similar events */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1991 | break; | 
|  | 1992 |  | 
|  | 1993 | case FUNCTIONFS_BIND: | 
|  | 1994 | case FUNCTIONFS_UNBIND: | 
|  | 1995 | case FUNCTIONFS_DISABLE: | 
|  | 1996 | case FUNCTIONFS_ENABLE: | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 1997 | /* Discard everything other then power management. */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 1998 | rem_type1 = FUNCTIONFS_SUSPEND; | 
|  | 1999 | rem_type2 = FUNCTIONFS_RESUME; | 
|  | 2000 | neg = 1; | 
|  | 2001 | break; | 
|  | 2002 |  | 
|  | 2003 | default: | 
|  | 2004 | BUG(); | 
|  | 2005 | } | 
|  | 2006 |  | 
|  | 2007 | { | 
|  | 2008 | u8 *ev  = ffs->ev.types, *out = ev; | 
|  | 2009 | unsigned n = ffs->ev.count; | 
|  | 2010 | for (; n; --n, ++ev) | 
|  | 2011 | if ((*ev == rem_type1 || *ev == rem_type2) == neg) | 
|  | 2012 | *out++ = *ev; | 
|  | 2013 | else | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 2014 | pr_vdebug("purging event %d\n", *ev); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2015 | ffs->ev.count = out - ffs->ev.types; | 
|  | 2016 | } | 
|  | 2017 |  | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 2018 | pr_vdebug("adding event %d\n", type); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2019 | ffs->ev.types[ffs->ev.count++] = type; | 
|  | 2020 | wake_up_locked(&ffs->ev.waitq); | 
|  | 2021 | } | 
|  | 2022 |  | 
|  | 2023 | static void ffs_event_add(struct ffs_data *ffs, | 
|  | 2024 | enum usb_functionfs_event_type type) | 
|  | 2025 | { | 
|  | 2026 | unsigned long flags; | 
|  | 2027 | spin_lock_irqsave(&ffs->ev.waitq.lock, flags); | 
|  | 2028 | __ffs_event_add(ffs, type); | 
|  | 2029 | spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); | 
|  | 2030 | } | 
|  | 2031 |  | 
|  | 2032 |  | 
|  | 2033 | /* Bind/unbind USB function hooks *******************************************/ | 
|  | 2034 |  | 
|  | 2035 | static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, | 
|  | 2036 | struct usb_descriptor_header *desc, | 
|  | 2037 | void *priv) | 
|  | 2038 | { | 
|  | 2039 | struct usb_endpoint_descriptor *ds = (void *)desc; | 
|  | 2040 | struct ffs_function *func = priv; | 
|  | 2041 | struct ffs_ep *ffs_ep; | 
|  | 2042 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2043 | /* | 
|  | 2044 | * If hs_descriptors is not NULL then we are reading hs | 
|  | 2045 | * descriptors now | 
|  | 2046 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2047 | const int isHS = func->function.hs_descriptors != NULL; | 
|  | 2048 | unsigned idx; | 
|  | 2049 |  | 
|  | 2050 | if (type != FFS_DESCRIPTOR) | 
|  | 2051 | return 0; | 
|  | 2052 |  | 
|  | 2053 | if (isHS) | 
|  | 2054 | func->function.hs_descriptors[(long)valuep] = desc; | 
|  | 2055 | else | 
|  | 2056 | func->function.descriptors[(long)valuep]    = desc; | 
|  | 2057 |  | 
|  | 2058 | if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) | 
|  | 2059 | return 0; | 
|  | 2060 |  | 
|  | 2061 | idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1; | 
|  | 2062 | ffs_ep = func->eps + idx; | 
|  | 2063 |  | 
|  | 2064 | if (unlikely(ffs_ep->descs[isHS])) { | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 2065 | pr_vdebug("two %sspeed descriptors for EP %d\n", | 
| Michal Nazarewicz | d8df0b6 | 2010-11-12 14:29:29 +0100 | [diff] [blame] | 2066 | isHS ? "high" : "full", | 
|  | 2067 | ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2068 | return -EINVAL; | 
|  | 2069 | } | 
|  | 2070 | ffs_ep->descs[isHS] = ds; | 
|  | 2071 |  | 
|  | 2072 | ffs_dump_mem(": Original  ep desc", ds, ds->bLength); | 
|  | 2073 | if (ffs_ep->ep) { | 
|  | 2074 | ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress; | 
|  | 2075 | if (!ds->wMaxPacketSize) | 
|  | 2076 | ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize; | 
|  | 2077 | } else { | 
|  | 2078 | struct usb_request *req; | 
|  | 2079 | struct usb_ep *ep; | 
|  | 2080 |  | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 2081 | pr_vdebug("autoconfig\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2082 | ep = usb_ep_autoconfig(func->gadget, ds); | 
|  | 2083 | if (unlikely(!ep)) | 
|  | 2084 | return -ENOTSUPP; | 
| Joe Perches | cc7e605 | 2010-11-14 19:04:49 -0800 | [diff] [blame] | 2085 | ep->driver_data = func->eps + idx; | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2086 |  | 
|  | 2087 | req = usb_ep_alloc_request(ep, GFP_KERNEL); | 
|  | 2088 | if (unlikely(!req)) | 
|  | 2089 | return -ENOMEM; | 
|  | 2090 |  | 
|  | 2091 | ffs_ep->ep  = ep; | 
|  | 2092 | ffs_ep->req = req; | 
|  | 2093 | func->eps_revmap[ds->bEndpointAddress & | 
|  | 2094 | USB_ENDPOINT_NUMBER_MASK] = idx + 1; | 
|  | 2095 | } | 
|  | 2096 | ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); | 
|  | 2097 |  | 
|  | 2098 | return 0; | 
|  | 2099 | } | 
|  | 2100 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2101 | static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, | 
|  | 2102 | struct usb_descriptor_header *desc, | 
|  | 2103 | void *priv) | 
|  | 2104 | { | 
|  | 2105 | struct ffs_function *func = priv; | 
|  | 2106 | unsigned idx; | 
|  | 2107 | u8 newValue; | 
|  | 2108 |  | 
|  | 2109 | switch (type) { | 
|  | 2110 | default: | 
|  | 2111 | case FFS_DESCRIPTOR: | 
|  | 2112 | /* Handled in previous pass by __ffs_func_bind_do_descs() */ | 
|  | 2113 | return 0; | 
|  | 2114 |  | 
|  | 2115 | case FFS_INTERFACE: | 
|  | 2116 | idx = *valuep; | 
|  | 2117 | if (func->interfaces_nums[idx] < 0) { | 
|  | 2118 | int id = usb_interface_id(func->conf, &func->function); | 
|  | 2119 | if (unlikely(id < 0)) | 
|  | 2120 | return id; | 
|  | 2121 | func->interfaces_nums[idx] = id; | 
|  | 2122 | } | 
|  | 2123 | newValue = func->interfaces_nums[idx]; | 
|  | 2124 | break; | 
|  | 2125 |  | 
|  | 2126 | case FFS_STRING: | 
|  | 2127 | /* String' IDs are allocated when fsf_data is bound to cdev */ | 
|  | 2128 | newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id; | 
|  | 2129 | break; | 
|  | 2130 |  | 
|  | 2131 | case FFS_ENDPOINT: | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2132 | /* | 
|  | 2133 | * USB_DT_ENDPOINT are handled in | 
|  | 2134 | * __ffs_func_bind_do_descs(). | 
|  | 2135 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2136 | if (desc->bDescriptorType == USB_DT_ENDPOINT) | 
|  | 2137 | return 0; | 
|  | 2138 |  | 
|  | 2139 | idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1; | 
|  | 2140 | if (unlikely(!func->eps[idx].ep)) | 
|  | 2141 | return -EINVAL; | 
|  | 2142 |  | 
|  | 2143 | { | 
|  | 2144 | struct usb_endpoint_descriptor **descs; | 
|  | 2145 | descs = func->eps[idx].descs; | 
|  | 2146 | newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress; | 
|  | 2147 | } | 
|  | 2148 | break; | 
|  | 2149 | } | 
|  | 2150 |  | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 2151 | pr_vdebug("%02x -> %02x\n", *valuep, newValue); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2152 | *valuep = newValue; | 
|  | 2153 | return 0; | 
|  | 2154 | } | 
|  | 2155 |  | 
|  | 2156 | static int ffs_func_bind(struct usb_configuration *c, | 
|  | 2157 | struct usb_function *f) | 
|  | 2158 | { | 
|  | 2159 | struct ffs_function *func = ffs_func_from_usb(f); | 
|  | 2160 | struct ffs_data *ffs = func->ffs; | 
|  | 2161 |  | 
|  | 2162 | const int full = !!func->ffs->fs_descs_count; | 
|  | 2163 | const int high = gadget_is_dualspeed(func->gadget) && | 
|  | 2164 | func->ffs->hs_descs_count; | 
|  | 2165 |  | 
|  | 2166 | int ret; | 
|  | 2167 |  | 
|  | 2168 | /* Make it a single chunk, less management later on */ | 
|  | 2169 | struct { | 
|  | 2170 | struct ffs_ep eps[ffs->eps_count]; | 
|  | 2171 | struct usb_descriptor_header | 
|  | 2172 | *fs_descs[full ? ffs->fs_descs_count + 1 : 0]; | 
|  | 2173 | struct usb_descriptor_header | 
|  | 2174 | *hs_descs[high ? ffs->hs_descs_count + 1 : 0]; | 
|  | 2175 | short inums[ffs->interfaces_count]; | 
|  | 2176 | char raw_descs[high ? ffs->raw_descs_length | 
|  | 2177 | : ffs->raw_fs_descs_length]; | 
|  | 2178 | } *data; | 
|  | 2179 |  | 
|  | 2180 | ENTER(); | 
|  | 2181 |  | 
|  | 2182 | /* Only high speed but not supported by gadget? */ | 
|  | 2183 | if (unlikely(!(full | high))) | 
|  | 2184 | return -ENOTSUPP; | 
|  | 2185 |  | 
|  | 2186 | /* Allocate */ | 
|  | 2187 | data = kmalloc(sizeof *data, GFP_KERNEL); | 
|  | 2188 | if (unlikely(!data)) | 
|  | 2189 | return -ENOMEM; | 
|  | 2190 |  | 
|  | 2191 | /* Zero */ | 
|  | 2192 | memset(data->eps, 0, sizeof data->eps); | 
|  | 2193 | memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs); | 
|  | 2194 | memset(data->inums, 0xff, sizeof data->inums); | 
|  | 2195 | for (ret = ffs->eps_count; ret; --ret) | 
|  | 2196 | data->eps[ret].num = -1; | 
|  | 2197 |  | 
|  | 2198 | /* Save pointers */ | 
|  | 2199 | func->eps             = data->eps; | 
|  | 2200 | func->interfaces_nums = data->inums; | 
|  | 2201 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2202 | /* | 
|  | 2203 | * Go through all the endpoint descriptors and allocate | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2204 | * endpoints first, so that later we can rewrite the endpoint | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2205 | * numbers without worrying that it may be described later on. | 
|  | 2206 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2207 | if (likely(full)) { | 
|  | 2208 | func->function.descriptors = data->fs_descs; | 
|  | 2209 | ret = ffs_do_descs(ffs->fs_descs_count, | 
|  | 2210 | data->raw_descs, | 
|  | 2211 | sizeof data->raw_descs, | 
|  | 2212 | __ffs_func_bind_do_descs, func); | 
|  | 2213 | if (unlikely(ret < 0)) | 
|  | 2214 | goto error; | 
|  | 2215 | } else { | 
|  | 2216 | ret = 0; | 
|  | 2217 | } | 
|  | 2218 |  | 
|  | 2219 | if (likely(high)) { | 
|  | 2220 | func->function.hs_descriptors = data->hs_descs; | 
|  | 2221 | ret = ffs_do_descs(ffs->hs_descs_count, | 
|  | 2222 | data->raw_descs + ret, | 
|  | 2223 | (sizeof data->raw_descs) - ret, | 
|  | 2224 | __ffs_func_bind_do_descs, func); | 
|  | 2225 | } | 
|  | 2226 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2227 | /* | 
|  | 2228 | * Now handle interface numbers allocation and interface and | 
|  | 2229 | * endpoint numbers rewriting.  We can do that in one go | 
|  | 2230 | * now. | 
|  | 2231 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2232 | ret = ffs_do_descs(ffs->fs_descs_count + | 
|  | 2233 | (high ? ffs->hs_descs_count : 0), | 
|  | 2234 | data->raw_descs, sizeof data->raw_descs, | 
|  | 2235 | __ffs_func_bind_do_nums, func); | 
|  | 2236 | if (unlikely(ret < 0)) | 
|  | 2237 | goto error; | 
|  | 2238 |  | 
|  | 2239 | /* And we're done */ | 
|  | 2240 | ffs_event_add(ffs, FUNCTIONFS_BIND); | 
|  | 2241 | return 0; | 
|  | 2242 |  | 
|  | 2243 | error: | 
|  | 2244 | /* XXX Do we need to release all claimed endpoints here? */ | 
|  | 2245 | return ret; | 
|  | 2246 | } | 
|  | 2247 |  | 
|  | 2248 |  | 
|  | 2249 | /* Other USB function hooks *************************************************/ | 
|  | 2250 |  | 
|  | 2251 | static void ffs_func_unbind(struct usb_configuration *c, | 
|  | 2252 | struct usb_function *f) | 
|  | 2253 | { | 
|  | 2254 | struct ffs_function *func = ffs_func_from_usb(f); | 
|  | 2255 | struct ffs_data *ffs = func->ffs; | 
|  | 2256 |  | 
|  | 2257 | ENTER(); | 
|  | 2258 |  | 
|  | 2259 | if (ffs->func == func) { | 
|  | 2260 | ffs_func_eps_disable(func); | 
|  | 2261 | ffs->func = NULL; | 
|  | 2262 | } | 
|  | 2263 |  | 
|  | 2264 | ffs_event_add(ffs, FUNCTIONFS_UNBIND); | 
|  | 2265 |  | 
|  | 2266 | ffs_func_free(func); | 
|  | 2267 | } | 
|  | 2268 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2269 | static int ffs_func_set_alt(struct usb_function *f, | 
|  | 2270 | unsigned interface, unsigned alt) | 
|  | 2271 | { | 
|  | 2272 | struct ffs_function *func = ffs_func_from_usb(f); | 
|  | 2273 | struct ffs_data *ffs = func->ffs; | 
|  | 2274 | int ret = 0, intf; | 
|  | 2275 |  | 
|  | 2276 | if (alt != (unsigned)-1) { | 
|  | 2277 | intf = ffs_func_revmap_intf(func, interface); | 
|  | 2278 | if (unlikely(intf < 0)) | 
|  | 2279 | return intf; | 
|  | 2280 | } | 
|  | 2281 |  | 
|  | 2282 | if (ffs->func) | 
|  | 2283 | ffs_func_eps_disable(ffs->func); | 
|  | 2284 |  | 
|  | 2285 | if (ffs->state != FFS_ACTIVE) | 
|  | 2286 | return -ENODEV; | 
|  | 2287 |  | 
|  | 2288 | if (alt == (unsigned)-1) { | 
|  | 2289 | ffs->func = NULL; | 
|  | 2290 | ffs_event_add(ffs, FUNCTIONFS_DISABLE); | 
|  | 2291 | return 0; | 
|  | 2292 | } | 
|  | 2293 |  | 
|  | 2294 | ffs->func = func; | 
|  | 2295 | ret = ffs_func_eps_enable(func); | 
|  | 2296 | if (likely(ret >= 0)) | 
|  | 2297 | ffs_event_add(ffs, FUNCTIONFS_ENABLE); | 
|  | 2298 | return ret; | 
|  | 2299 | } | 
|  | 2300 |  | 
|  | 2301 | static void ffs_func_disable(struct usb_function *f) | 
|  | 2302 | { | 
|  | 2303 | ffs_func_set_alt(f, 0, (unsigned)-1); | 
|  | 2304 | } | 
|  | 2305 |  | 
|  | 2306 | static int ffs_func_setup(struct usb_function *f, | 
|  | 2307 | const struct usb_ctrlrequest *creq) | 
|  | 2308 | { | 
|  | 2309 | struct ffs_function *func = ffs_func_from_usb(f); | 
|  | 2310 | struct ffs_data *ffs = func->ffs; | 
|  | 2311 | unsigned long flags; | 
|  | 2312 | int ret; | 
|  | 2313 |  | 
|  | 2314 | ENTER(); | 
|  | 2315 |  | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 2316 | pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); | 
|  | 2317 | pr_vdebug("creq->bRequest     = %02x\n", creq->bRequest); | 
|  | 2318 | pr_vdebug("creq->wValue       = %04x\n", le16_to_cpu(creq->wValue)); | 
|  | 2319 | pr_vdebug("creq->wIndex       = %04x\n", le16_to_cpu(creq->wIndex)); | 
|  | 2320 | pr_vdebug("creq->wLength      = %04x\n", le16_to_cpu(creq->wLength)); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2321 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2322 | /* | 
|  | 2323 | * Most requests directed to interface go through here | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2324 | * (notable exceptions are set/get interface) so we need to | 
|  | 2325 | * handle them.  All other either handled by composite or | 
|  | 2326 | * passed to usb_configuration->setup() (if one is set).  No | 
|  | 2327 | * matter, we will handle requests directed to endpoint here | 
|  | 2328 | * as well (as it's straightforward) but what to do with any | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2329 | * other request? | 
|  | 2330 | */ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2331 | if (ffs->state != FFS_ACTIVE) | 
|  | 2332 | return -ENODEV; | 
|  | 2333 |  | 
|  | 2334 | switch (creq->bRequestType & USB_RECIP_MASK) { | 
|  | 2335 | case USB_RECIP_INTERFACE: | 
|  | 2336 | ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex)); | 
|  | 2337 | if (unlikely(ret < 0)) | 
|  | 2338 | return ret; | 
|  | 2339 | break; | 
|  | 2340 |  | 
|  | 2341 | case USB_RECIP_ENDPOINT: | 
|  | 2342 | ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex)); | 
|  | 2343 | if (unlikely(ret < 0)) | 
|  | 2344 | return ret; | 
|  | 2345 | break; | 
|  | 2346 |  | 
|  | 2347 | default: | 
|  | 2348 | return -EOPNOTSUPP; | 
|  | 2349 | } | 
|  | 2350 |  | 
|  | 2351 | spin_lock_irqsave(&ffs->ev.waitq.lock, flags); | 
|  | 2352 | ffs->ev.setup = *creq; | 
|  | 2353 | ffs->ev.setup.wIndex = cpu_to_le16(ret); | 
|  | 2354 | __ffs_event_add(ffs, FUNCTIONFS_SETUP); | 
|  | 2355 | spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); | 
|  | 2356 |  | 
|  | 2357 | return 0; | 
|  | 2358 | } | 
|  | 2359 |  | 
|  | 2360 | static void ffs_func_suspend(struct usb_function *f) | 
|  | 2361 | { | 
|  | 2362 | ENTER(); | 
|  | 2363 | ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); | 
|  | 2364 | } | 
|  | 2365 |  | 
|  | 2366 | static void ffs_func_resume(struct usb_function *f) | 
|  | 2367 | { | 
|  | 2368 | ENTER(); | 
|  | 2369 | ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); | 
|  | 2370 | } | 
|  | 2371 |  | 
|  | 2372 |  | 
| Michal Nazarewicz | 5ab54cf | 2010-11-12 14:29:28 +0100 | [diff] [blame] | 2373 | /* Endpoint and interface numbers reverse mapping ***************************/ | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2374 |  | 
|  | 2375 | static int ffs_func_revmap_ep(struct ffs_function *func, u8 num) | 
|  | 2376 | { | 
|  | 2377 | num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK]; | 
|  | 2378 | return num ? num : -EDOM; | 
|  | 2379 | } | 
|  | 2380 |  | 
|  | 2381 | static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf) | 
|  | 2382 | { | 
|  | 2383 | short *nums = func->interfaces_nums; | 
|  | 2384 | unsigned count = func->ffs->interfaces_count; | 
|  | 2385 |  | 
|  | 2386 | for (; count; --count, ++nums) { | 
|  | 2387 | if (*nums >= 0 && *nums == intf) | 
|  | 2388 | return nums - func->interfaces_nums; | 
|  | 2389 | } | 
|  | 2390 |  | 
|  | 2391 | return -EDOM; | 
|  | 2392 | } | 
|  | 2393 |  | 
|  | 2394 |  | 
|  | 2395 | /* Misc helper functions ****************************************************/ | 
|  | 2396 |  | 
|  | 2397 | static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) | 
|  | 2398 | { | 
|  | 2399 | return nonblock | 
|  | 2400 | ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN | 
|  | 2401 | : mutex_lock_interruptible(mutex); | 
|  | 2402 | } | 
|  | 2403 |  | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2404 | static char *ffs_prepare_buffer(const char * __user buf, size_t len) | 
|  | 2405 | { | 
|  | 2406 | char *data; | 
|  | 2407 |  | 
|  | 2408 | if (unlikely(!len)) | 
|  | 2409 | return NULL; | 
|  | 2410 |  | 
|  | 2411 | data = kmalloc(len, GFP_KERNEL); | 
|  | 2412 | if (unlikely(!data)) | 
|  | 2413 | return ERR_PTR(-ENOMEM); | 
|  | 2414 |  | 
|  | 2415 | if (unlikely(__copy_from_user(data, buf, len))) { | 
|  | 2416 | kfree(data); | 
|  | 2417 | return ERR_PTR(-EFAULT); | 
|  | 2418 | } | 
|  | 2419 |  | 
| Michal Nazarewicz | aa02f17 | 2010-11-17 17:09:47 +0100 | [diff] [blame] | 2420 | pr_vdebug("Buffer from user space:\n"); | 
| Michal Nazarewicz | ddf8abd | 2010-05-05 12:53:14 +0200 | [diff] [blame] | 2421 | ffs_dump_mem("", data, len); | 
|  | 2422 |  | 
|  | 2423 | return data; | 
|  | 2424 | } |