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.0-rc5 335 lines 8.3 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 * 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 .unbind = gfs_unbind, 166 .iProduct = DRIVER_DESC, 167}; 168 169static struct ffs_data *gfs_ffs_data; 170static unsigned long gfs_registered; 171 172static int gfs_init(void) 173{ 174 ENTER(); 175 176 return functionfs_init(); 177} 178module_init(gfs_init); 179 180static void gfs_exit(void) 181{ 182 ENTER(); 183 184 if (test_and_clear_bit(0, &gfs_registered)) 185 usb_composite_unregister(&gfs_driver); 186 187 functionfs_cleanup(); 188} 189module_exit(gfs_exit); 190 191static int functionfs_ready_callback(struct ffs_data *ffs) 192{ 193 int ret; 194 195 ENTER(); 196 197 if (WARN_ON(test_and_set_bit(0, &gfs_registered))) 198 return -EBUSY; 199 200 gfs_ffs_data = ffs; 201 ret = usb_composite_probe(&gfs_driver, gfs_bind); 202 if (unlikely(ret < 0)) 203 clear_bit(0, &gfs_registered); 204 return ret; 205} 206 207static void functionfs_closed_callback(struct ffs_data *ffs) 208{ 209 ENTER(); 210 211 if (test_and_clear_bit(0, &gfs_registered)) 212 usb_composite_unregister(&gfs_driver); 213} 214 215static int functionfs_check_dev_callback(const char *dev_name) 216{ 217 return 0; 218} 219 220static int gfs_bind(struct usb_composite_dev *cdev) 221{ 222 int ret, i; 223 224 ENTER(); 225 226 if (WARN_ON(!gfs_ffs_data)) 227 return -ENODEV; 228 229 ret = gether_setup(cdev->gadget, gfs_hostaddr); 230 if (unlikely(ret < 0)) 231 goto error_quick; 232 233 ret = usb_string_ids_tab(cdev, gfs_strings); 234 if (unlikely(ret < 0)) 235 goto error; 236 237 ret = functionfs_bind(gfs_ffs_data, cdev); 238 if (unlikely(ret < 0)) 239 goto error; 240 241 for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { 242 struct gfs_configuration *c = gfs_configurations + i; 243 244 c->c.label = gfs_strings[i].s; 245 c->c.iConfiguration = gfs_strings[i].id; 246 c->c.bConfigurationValue = 1 + i; 247 c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER; 248 249 ret = usb_add_config(cdev, &c->c, gfs_do_config); 250 if (unlikely(ret < 0)) 251 goto error_unbind; 252 } 253 254 return 0; 255 256error_unbind: 257 functionfs_unbind(gfs_ffs_data); 258error: 259 gether_cleanup(); 260error_quick: 261 gfs_ffs_data = NULL; 262 return ret; 263} 264 265static int gfs_unbind(struct usb_composite_dev *cdev) 266{ 267 ENTER(); 268 269 /* 270 * We may have been called in an error recovery from 271 * composite_bind() after gfs_unbind() failure so we need to 272 * check if gfs_ffs_data is not NULL since gfs_bind() handles 273 * all error recovery itself. I'd rather we werent called 274 * from composite on orror recovery, but what you're gonna 275 * do...? 276 */ 277 if (gfs_ffs_data) { 278 gether_cleanup(); 279 functionfs_unbind(gfs_ffs_data); 280 gfs_ffs_data = NULL; 281 } 282 283 return 0; 284} 285 286static int gfs_do_config(struct usb_configuration *c) 287{ 288 struct gfs_configuration *gc = 289 container_of(c, struct gfs_configuration, c); 290 int ret; 291 292 if (WARN_ON(!gfs_ffs_data)) 293 return -ENODEV; 294 295 if (gadget_is_otg(c->cdev->gadget)) { 296 c->descriptors = gfs_otg_desc; 297 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; 298 } 299 300 if (gc->eth) { 301 ret = gc->eth(c, gfs_hostaddr); 302 if (unlikely(ret < 0)) 303 return ret; 304 } 305 306 ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data); 307 if (unlikely(ret < 0)) 308 return ret; 309 310 /* 311 * After previous do_configs there may be some invalid 312 * pointers in c->interface array. This happens every time 313 * a user space function with fewer interfaces than a user 314 * space function that was run before the new one is run. The 315 * compasit's set_config() assumes that if there is no more 316 * then MAX_CONFIG_INTERFACES interfaces in a configuration 317 * then there is a NULL pointer after the last interface in 318 * c->interface array. We need to make sure this is true. 319 */ 320 if (c->next_interface_id < ARRAY_SIZE(c->interface)) 321 c->interface[c->next_interface_id] = NULL; 322 323 return 0; 324} 325 326#ifdef CONFIG_USB_FUNCTIONFS_ETH 327 328static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) 329{ 330 return can_support_ecm(c->cdev->gadget) 331 ? ecm_bind_config(c, ethaddr) 332 : geth_bind_config(c, ethaddr); 333} 334 335#endif