/drivers/usb/gadget/g_ffs.c
C | 336 lines | 224 code | 62 blank | 50 comment | 20 complexity | 464c2beec92547687bd08bb0d4f6899b MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
1/* 2 * g_ffs.c -- user mode file system API for USB composite function controllers 3 * 4 * Copyright (C) 2010 Samsung Electronics 5 * Author: Michal Nazarewicz <m.nazarewicz@samsung.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22#define pr_fmt(fmt) "g_ffs: " fmt 23 24#include <linux/module.h> 25#include <linux/utsname.h> 26 27/* 28 * kbuild is not very cooperative with respect to linking separately 29 * compiled library objects into one module. So for now we won't use 30 * separate compilation ... ensuring init/exit sections work to shrink 31 * the runtime footprint, and giving us at least some parts of what 32 * a "gcc --combine ... part1.c part2.c part3.c ... " build would. 33 */ 34 35#include "composite.c" 36#include "usbstring.c" 37#include "config.c" 38#include "epautoconf.c" 39 40#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS 41# if defined USB_ETH_RNDIS 42# undef USB_ETH_RNDIS 43# endif 44# ifdef CONFIG_USB_FUNCTIONFS_RNDIS 45# define USB_ETH_RNDIS y 46# endif 47 48# include "f_ecm.c" 49# include "f_subset.c" 50# ifdef USB_ETH_RNDIS 51# include "f_rndis.c" 52# include "rndis.c" 53# endif 54# include "u_ether.c" 55 56static u8 gfs_hostaddr[ETH_ALEN]; 57# ifdef CONFIG_USB_FUNCTIONFS_ETH 58static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); 59# endif 60#else 61# define gether_cleanup() do { } while (0) 62# define gether_setup(gadget, hostaddr) ((int)0) 63# define gfs_hostaddr NULL 64#endif 65 66#include "f_fs.c" 67 68#define DRIVER_NAME "g_ffs" 69#define DRIVER_DESC "USB Function Filesystem" 70#define DRIVER_VERSION "24 Aug 2004" 71 72MODULE_DESCRIPTION(DRIVER_DESC); 73MODULE_AUTHOR("Michal Nazarewicz"); 74MODULE_LICENSE("GPL"); 75 76#define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */ 77#define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */ 78 79static struct usb_device_descriptor gfs_dev_desc = { 80 .bLength = sizeof gfs_dev_desc, 81 .bDescriptorType = USB_DT_DEVICE, 82 83 .bcdUSB = cpu_to_le16(0x0200), 84 .bDeviceClass = USB_CLASS_PER_INTERFACE, 85 86 .idVendor = cpu_to_le16(GFS_VENDOR_ID), 87 .idProduct = cpu_to_le16(GFS_PRODUCT_ID), 88}; 89 90module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644); 91MODULE_PARM_DESC(bDeviceClass, "USB Device class"); 92module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644); 93MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass"); 94module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644); 95MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol"); 96 97static const struct usb_descriptor_header *gfs_otg_desc[] = { 98 (const struct usb_descriptor_header *) 99 &(const struct usb_otg_descriptor) { 100 .bLength = sizeof(struct usb_otg_descriptor), 101 .bDescriptorType = USB_DT_OTG, 102 103 /* 104 * REVISIT SRP-only hardware is possible, although 105 * it would not be called "OTG" ... 106 */ 107 .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, 108 }, 109 110 NULL 111}; 112 113/* String IDs are assigned dynamically */ 114static struct usb_string gfs_strings[] = { 115#ifdef CONFIG_USB_FUNCTIONFS_RNDIS 116 { .s = "FunctionFS + RNDIS" }, 117#endif 118#ifdef CONFIG_USB_FUNCTIONFS_ETH 119 { .s = "FunctionFS + ECM" }, 120#endif 121#ifdef CONFIG_USB_FUNCTIONFS_GENERIC 122 { .s = "FunctionFS" }, 123#endif 124 { } /* end of list */ 125}; 126 127static struct usb_gadget_strings *gfs_dev_strings[] = { 128 &(struct usb_gadget_strings) { 129 .language = 0x0409, /* en-us */ 130 .strings = gfs_strings, 131 }, 132 NULL, 133}; 134 135struct gfs_configuration { 136 struct usb_configuration c; 137 int (*eth)(struct usb_configuration *c, u8 *ethaddr); 138} gfs_configurations[] = { 139#ifdef CONFIG_USB_FUNCTIONFS_RNDIS 140 { 141 .eth = rndis_bind_config, 142 }, 143#endif 144 145#ifdef CONFIG_USB_FUNCTIONFS_ETH 146 { 147 .eth = eth_bind_config, 148 }, 149#endif 150 151#ifdef CONFIG_USB_FUNCTIONFS_GENERIC 152 { 153 }, 154#endif 155}; 156 157static int gfs_bind(struct usb_composite_dev *cdev); 158static int gfs_unbind(struct usb_composite_dev *cdev); 159static int gfs_do_config(struct usb_configuration *c); 160 161static struct usb_composite_driver gfs_driver = { 162 .name = DRIVER_NAME, 163 .dev = &gfs_dev_desc, 164 .strings = gfs_dev_strings, 165 .max_speed = USB_SPEED_HIGH, 166 .unbind = gfs_unbind, 167 .iProduct = DRIVER_DESC, 168}; 169 170static struct ffs_data *gfs_ffs_data; 171static unsigned long gfs_registered; 172 173static int gfs_init(void) 174{ 175 ENTER(); 176 177 return functionfs_init(); 178} 179module_init(gfs_init); 180 181static void gfs_exit(void) 182{ 183 ENTER(); 184 185 if (test_and_clear_bit(0, &gfs_registered)) 186 usb_composite_unregister(&gfs_driver); 187 188 functionfs_cleanup(); 189} 190module_exit(gfs_exit); 191 192static int functionfs_ready_callback(struct ffs_data *ffs) 193{ 194 int ret; 195 196 ENTER(); 197 198 if (WARN_ON(test_and_set_bit(0, &gfs_registered))) 199 return -EBUSY; 200 201 gfs_ffs_data = ffs; 202 ret = usb_composite_probe(&gfs_driver, gfs_bind); 203 if (unlikely(ret < 0)) 204 clear_bit(0, &gfs_registered); 205 return ret; 206} 207 208static void functionfs_closed_callback(struct ffs_data *ffs) 209{ 210 ENTER(); 211 212 if (test_and_clear_bit(0, &gfs_registered)) 213 usb_composite_unregister(&gfs_driver); 214} 215 216static int functionfs_check_dev_callback(const char *dev_name) 217{ 218 return 0; 219} 220 221static int gfs_bind(struct usb_composite_dev *cdev) 222{ 223 int ret, i; 224 225 ENTER(); 226 227 if (WARN_ON(!gfs_ffs_data)) 228 return -ENODEV; 229 230 ret = gether_setup(cdev->gadget, gfs_hostaddr); 231 if (unlikely(ret < 0)) 232 goto error_quick; 233 234 ret = usb_string_ids_tab(cdev, gfs_strings); 235 if (unlikely(ret < 0)) 236 goto error; 237 238 ret = functionfs_bind(gfs_ffs_data, cdev); 239 if (unlikely(ret < 0)) 240 goto error; 241 242 for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { 243 struct gfs_configuration *c = gfs_configurations + i; 244 245 c->c.label = gfs_strings[i].s; 246 c->c.iConfiguration = gfs_strings[i].id; 247 c->c.bConfigurationValue = 1 + i; 248 c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER; 249 250 ret = usb_add_config(cdev, &c->c, gfs_do_config); 251 if (unlikely(ret < 0)) 252 goto error_unbind; 253 } 254 255 return 0; 256 257error_unbind: 258 functionfs_unbind(gfs_ffs_data); 259error: 260 gether_cleanup(); 261error_quick: 262 gfs_ffs_data = NULL; 263 return ret; 264} 265 266static int gfs_unbind(struct usb_composite_dev *cdev) 267{ 268 ENTER(); 269 270 /* 271 * We may have been called in an error recovery from 272 * composite_bind() after gfs_unbind() failure so we need to 273 * check if gfs_ffs_data is not NULL since gfs_bind() handles 274 * all error recovery itself. I'd rather we werent called 275 * from composite on orror recovery, but what you're gonna 276 * do...? 277 */ 278 if (gfs_ffs_data) { 279 gether_cleanup(); 280 functionfs_unbind(gfs_ffs_data); 281 gfs_ffs_data = NULL; 282 } 283 284 return 0; 285} 286 287static int gfs_do_config(struct usb_configuration *c) 288{ 289 struct gfs_configuration *gc = 290 container_of(c, struct gfs_configuration, c); 291 int ret; 292 293 if (WARN_ON(!gfs_ffs_data)) 294 return -ENODEV; 295 296 if (gadget_is_otg(c->cdev->gadget)) { 297 c->descriptors = gfs_otg_desc; 298 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; 299 } 300 301 if (gc->eth) { 302 ret = gc->eth(c, gfs_hostaddr); 303 if (unlikely(ret < 0)) 304 return ret; 305 } 306 307 ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data); 308 if (unlikely(ret < 0)) 309 return ret; 310 311 /* 312 * After previous do_configs there may be some invalid 313 * pointers in c->interface array. This happens every time 314 * a user space function with fewer interfaces than a user 315 * space function that was run before the new one is run. The 316 * compasit's set_config() assumes that if there is no more 317 * then MAX_CONFIG_INTERFACES interfaces in a configuration 318 * then there is a NULL pointer after the last interface in 319 * c->interface array. We need to make sure this is true. 320 */ 321 if (c->next_interface_id < ARRAY_SIZE(c->interface)) 322 c->interface[c->next_interface_id] = NULL; 323 324 return 0; 325} 326 327#ifdef CONFIG_USB_FUNCTIONFS_ETH 328 329static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) 330{ 331 return can_support_ecm(c->cdev->gadget) 332 ? ecm_bind_config(c, ethaddr) 333 : geth_bind_config(c, ethaddr); 334} 335 336#endif