g_ffs.c 7.71 KB
Newer Older
1 2 3 4
/*
 * g_ffs.c -- user mode file system API for USB composite function controllers
 *
 * Copyright (C) 2010 Samsung Electronics
5
 * Author: Michal Nazarewicz <mina86@mina86.com>
6 7 8 9 10 11 12
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

13 14
#define pr_fmt(fmt) "g_ffs: " fmt

15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
#include <linux/module.h>
#include <linux/utsname.h>

/*
 * kbuild is not very cooperative with respect to linking separately
 * compiled library objects into one module.  So for now we won't use
 * separate compilation ... ensuring init/exit sections work to shrink
 * the runtime footprint, and giving us at least some parts of what
 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
 */

#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"

#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
#  if defined USB_ETH_RNDIS
#    undef USB_ETH_RNDIS
#  endif
#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS
#    define USB_ETH_RNDIS y
#  endif

#  include "f_ecm.c"
#  include "f_subset.c"
#  ifdef USB_ETH_RNDIS
#    include "f_rndis.c"
#    include "rndis.c"
#  endif
#  include "u_ether.c"

static u8 gfs_hostaddr[ETH_ALEN];
48 49
#  ifdef CONFIG_USB_FUNCTIONFS_ETH
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
50
#  endif
51
#else
52 53
#  define gether_cleanup() do { } while (0)
#  define gether_setup(gadget, hostaddr)   ((int)0)
54
#  define gfs_hostaddr NULL
55 56 57 58 59 60 61 62 63 64 65 66
#endif

#include "f_fs.c"

#define DRIVER_NAME	"g_ffs"
#define DRIVER_DESC	"USB Function Filesystem"
#define DRIVER_VERSION	"24 Aug 2004"

MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Michal Nazarewicz");
MODULE_LICENSE("GPL");

67 68
#define GFS_VENDOR_ID	0x1d6b	/* Linux Foundation */
#define GFS_PRODUCT_ID	0x0105	/* FunctionFS Gadget */
69 70 71 72 73 74 75 76

static struct usb_device_descriptor gfs_dev_desc = {
	.bLength		= sizeof gfs_dev_desc,
	.bDescriptorType	= USB_DT_DEVICE,

	.bcdUSB			= cpu_to_le16(0x0200),
	.bDeviceClass		= USB_CLASS_PER_INTERFACE,

77 78
	.idVendor		= cpu_to_le16(GFS_VENDOR_ID),
	.idProduct		= cpu_to_le16(GFS_PRODUCT_ID),
79 80
};

81 82 83 84 85 86
module_param_named(bDeviceClass,    gfs_dev_desc.bDeviceClass,    byte,   0644);
MODULE_PARM_DESC(bDeviceClass, "USB Device class");
module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte,   0644);
MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte,   0644);
MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
87 88 89 90 91 92 93

static const struct usb_descriptor_header *gfs_otg_desc[] = {
	(const struct usb_descriptor_header *)
	&(const struct usb_otg_descriptor) {
		.bLength		= sizeof(struct usb_otg_descriptor),
		.bDescriptorType	= USB_DT_OTG,

94 95 96 97
		/*
		 * REVISIT SRP-only hardware is possible, although
		 * it would not be called "OTG" ...
		 */
98 99 100 101 102 103
		.bmAttributes		= USB_OTG_SRP | USB_OTG_HNP,
	},

	NULL
};

104
/* String IDs are assigned dynamically */
105 106
static struct usb_string gfs_strings[] = {
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
107
	{ .s = "FunctionFS + RNDIS" },
108 109
#endif
#ifdef CONFIG_USB_FUNCTIONFS_ETH
110
	{ .s = "FunctionFS + ECM" },
111 112
#endif
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
113
	{ .s = "FunctionFS" },
114 115 116 117 118 119 120 121 122 123 124 125
#endif
	{  } /* end of list */
};

static struct usb_gadget_strings *gfs_dev_strings[] = {
	&(struct usb_gadget_strings) {
		.language	= 0x0409,	/* en-us */
		.strings	= gfs_strings,
	},
	NULL,
};

126 127 128 129
struct gfs_configuration {
	struct usb_configuration c;
	int (*eth)(struct usb_configuration *c, u8 *ethaddr);
} gfs_configurations[] = {
130
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
131 132 133
	{
		.eth		= rndis_bind_config,
	},
134 135 136
#endif

#ifdef CONFIG_USB_FUNCTIONFS_ETH
137 138 139
	{
		.eth		= eth_bind_config,
	},
140 141 142
#endif

#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
143 144
	{
	},
145
#endif
146
};
147 148 149

static int gfs_bind(struct usb_composite_dev *cdev);
static int gfs_unbind(struct usb_composite_dev *cdev);
150
static int gfs_do_config(struct usb_configuration *c);
151 152

static struct usb_composite_driver gfs_driver = {
153
	.name		= DRIVER_NAME,
154 155
	.dev		= &gfs_dev_desc,
	.strings	= gfs_dev_strings,
156
	.max_speed	= USB_SPEED_HIGH,
157
	.unbind		= gfs_unbind,
158
	.iProduct	= DRIVER_DESC,
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
};

static struct ffs_data *gfs_ffs_data;
static unsigned long gfs_registered;

static int  gfs_init(void)
{
	ENTER();

	return functionfs_init();
}
module_init(gfs_init);

static void  gfs_exit(void)
{
	ENTER();

	if (test_and_clear_bit(0, &gfs_registered))
		usb_composite_unregister(&gfs_driver);

	functionfs_cleanup();
}
module_exit(gfs_exit);

static int functionfs_ready_callback(struct ffs_data *ffs)
{
	int ret;

	ENTER();

	if (WARN_ON(test_and_set_bit(0, &gfs_registered)))
		return -EBUSY;

	gfs_ffs_data = ffs;
193
	ret = usb_composite_probe(&gfs_driver, gfs_bind);
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
	if (unlikely(ret < 0))
		clear_bit(0, &gfs_registered);
	return ret;
}

static void functionfs_closed_callback(struct ffs_data *ffs)
{
	ENTER();

	if (test_and_clear_bit(0, &gfs_registered))
		usb_composite_unregister(&gfs_driver);
}

static int functionfs_check_dev_callback(const char *dev_name)
{
	return 0;
}

static int gfs_bind(struct usb_composite_dev *cdev)
{
214
	int ret, i;
215 216 217 218 219 220 221 222 223 224

	ENTER();

	if (WARN_ON(!gfs_ffs_data))
		return -ENODEV;

	ret = gether_setup(cdev->gadget, gfs_hostaddr);
	if (unlikely(ret < 0))
		goto error_quick;

225
	ret = usb_string_ids_tab(cdev, gfs_strings);
226 227 228 229 230 231 232
	if (unlikely(ret < 0))
		goto error;

	ret = functionfs_bind(gfs_ffs_data, cdev);
	if (unlikely(ret < 0))
		goto error;

233 234
	for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
		struct gfs_configuration *c = gfs_configurations + i;
235

236 237
		c->c.label			= gfs_strings[i].s;
		c->c.iConfiguration		= gfs_strings[i].id;
238 239
		c->c.bConfigurationValue	= 1 + i;
		c->c.bmAttributes		= USB_CONFIG_ATT_SELFPOWER;
240

241
		ret = usb_add_config(cdev, &c->c, gfs_do_config);
242 243 244
		if (unlikely(ret < 0))
			goto error_unbind;
	}
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260

	return 0;

error_unbind:
	functionfs_unbind(gfs_ffs_data);
error:
	gether_cleanup();
error_quick:
	gfs_ffs_data = NULL;
	return ret;
}

static int gfs_unbind(struct usb_composite_dev *cdev)
{
	ENTER();

261 262
	/*
	 * We may have been called in an error recovery from
263 264 265 266
	 * composite_bind() after gfs_unbind() failure so we need to
	 * check if gfs_ffs_data is not NULL since gfs_bind() handles
	 * all error recovery itself.  I'd rather we werent called
	 * from composite on orror recovery, but what you're gonna
267 268
	 * do...?
	 */
269 270 271 272 273 274 275 276 277
	if (gfs_ffs_data) {
		gether_cleanup();
		functionfs_unbind(gfs_ffs_data);
		gfs_ffs_data = NULL;
	}

	return 0;
}

278
static int gfs_do_config(struct usb_configuration *c)
279
{
280 281
	struct gfs_configuration *gc =
		container_of(c, struct gfs_configuration, c);
282 283 284 285 286 287 288 289 290 291
	int ret;

	if (WARN_ON(!gfs_ffs_data))
		return -ENODEV;

	if (gadget_is_otg(c->cdev->gadget)) {
		c->descriptors = gfs_otg_desc;
		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
	}

292 293
	if (gc->eth) {
		ret = gc->eth(c, gfs_hostaddr);
294 295 296 297
		if (unlikely(ret < 0))
			return ret;
	}

298
	ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data);
299 300 301
	if (unlikely(ret < 0))
		return ret;

302 303
	/*
	 * After previous do_configs there may be some invalid
304 305 306 307 308 309
	 * pointers in c->interface array.  This happens every time
	 * a user space function with fewer interfaces than a user
	 * space function that was run before the new one is run.  The
	 * compasit's set_config() assumes that if there is no more
	 * then MAX_CONFIG_INTERFACES interfaces in a configuration
	 * then there is a NULL pointer after the last interface in
310 311
	 * c->interface array.  We need to make sure this is true.
	 */
312 313 314
	if (c->next_interface_id < ARRAY_SIZE(c->interface))
		c->interface[c->next_interface_id] = NULL;

315 316 317 318
	return 0;
}

#ifdef CONFIG_USB_FUNCTIONFS_ETH
319

320
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
321
{
322 323 324
	return can_support_ecm(c->cdev->gadget)
		? ecm_bind_config(c, ethaddr)
		: geth_bind_config(c, ethaddr);
325
}
326

327
#endif