Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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