zero.c 11.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * zero.c -- Gadget Zero, for USB development
 *
4 5
 * Copyright (C) 2003-2008 David Brownell
 * Copyright (C) 2008 by Nokia Corporation
L
Linus Torvalds 已提交
6
 *
D
David Brownell 已提交
7 8 9 10
 * 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.
L
Linus Torvalds 已提交
11 12 13 14 15
 */

/*
 * Gadget Zero only needs two bulk endpoints, and is an example of how you
 * can write a hardware-agnostic gadget driver running inside a USB device.
16
 * Some hardware details are visible, but don't affect most of the driver.
L
Linus Torvalds 已提交
17 18 19 20 21 22
 *
 * Use it with the Linux host/master side "usbtest" driver to get a basic
 * functional test of your device-side usb stack, or with "usb-skeleton".
 *
 * It supports two similar configurations.  One sinks whatever the usb host
 * writes, and in return sources zeroes.  The other loops whatever the host
23
 * writes back, so the host can read it.
L
Linus Torvalds 已提交
24 25 26 27
 *
 * Many drivers will only have one configuration, letting them be much
 * simpler if they also don't support high speed operation (like this
 * driver does).
D
David Brownell 已提交
28 29 30 31 32
 *
 * Why is *this* driver using two configurations, rather than setting up
 * two interfaces with different functions?  To help verify that multiple
 * configuration infrastucture is working correctly; also, so that it can
 * work with low capability USB controllers without four bulk endpoints.
L
Linus Torvalds 已提交
33 34
 */

35 36 37 38 39
/*
 * driver assumes self-powered hardware, and
 * has no way for users to trigger remote wakeup.
 */

D
David Brownell 已提交
40
/* #define VERBOSE_DEBUG */
L
Linus Torvalds 已提交
41 42

#include <linux/kernel.h>
43
#include <linux/slab.h>
L
Linus Torvalds 已提交
44
#include <linux/device.h>
45 46 47
#include <linux/module.h>
#include <linux/err.h>
#include <linux/usb/composite.h>
L
Linus Torvalds 已提交
48

49
#include "g_zero.h"
L
Linus Torvalds 已提交
50
/*-------------------------------------------------------------------------*/
51
USB_GADGET_COMPOSITE_OPTIONS();
L
Linus Torvalds 已提交
52

53
#define DRIVER_VERSION		"Cinco de Mayo 2008"
L
Linus Torvalds 已提交
54

55
static const char longname[] = "Gadget Zero";
L
Linus Torvalds 已提交
56 57 58 59

/*
 * Normally the "loopback" configuration is second (index 1) so
 * it's not the default.  Here's where to change that order, to
60 61
 * work better with hosts where config changes are problematic or
 * controllers (like original superh) that only support one config.
L
Linus Torvalds 已提交
62
 */
63
static bool loopdefault = 0;
64
module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
L
Linus Torvalds 已提交
65

66
static struct usb_zero_options gzero_options = {
67 68 69 70 71 72
	.isoc_interval = 4,
	.isoc_maxpacket = 1024,
	.bulk_buflen = 4096,
	.qlen = 32,
};

L
Linus Torvalds 已提交
73 74 75 76 77 78 79 80 81 82
/*-------------------------------------------------------------------------*/

/* Thanks to NetChip Technologies for donating this product ID.
 *
 * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
 * Instead:  allocate your own, using normal USB-IF procedures.
 */
#ifndef	CONFIG_USB_ZERO_HNPTEST
#define DRIVER_VENDOR_NUM	0x0525		/* NetChip */
#define DRIVER_PRODUCT_NUM	0xa4a0		/* Linux-USB "Gadget Zero" */
83
#define DEFAULT_AUTORESUME	0
L
Linus Torvalds 已提交
84 85 86
#else
#define DRIVER_VENDOR_NUM	0x1a0a		/* OTG test device IDs */
#define DRIVER_PRODUCT_NUM	0xbadd
87
#define DEFAULT_AUTORESUME	5
L
Linus Torvalds 已提交
88 89
#endif

90 91 92 93 94 95 96 97
/* If the optional "autoresume" mode is enabled, it provides good
 * functional coverage for the "USBCV" test harness from USB-IF.
 * It's always set if OTG mode is enabled.
 */
unsigned autoresume = DEFAULT_AUTORESUME;
module_param(autoresume, uint, S_IRUGO);
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");

L
Linus Torvalds 已提交
98 99
/*-------------------------------------------------------------------------*/

100
static struct usb_device_descriptor device_desc = {
L
Linus Torvalds 已提交
101 102 103
	.bLength =		sizeof device_desc,
	.bDescriptorType =	USB_DT_DEVICE,

104
	.bcdUSB =		cpu_to_le16(0x0200),
L
Linus Torvalds 已提交
105 106
	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,

107 108
	.idVendor =		cpu_to_le16(DRIVER_VENDOR_NUM),
	.idProduct =		cpu_to_le16(DRIVER_PRODUCT_NUM),
L
Linus Torvalds 已提交
109 110 111
	.bNumConfigurations =	2,
};

112
#ifdef CONFIG_USB_OTG
113
static struct usb_otg_descriptor otg_descriptor = {
L
Linus Torvalds 已提交
114 115 116
	.bLength =		sizeof otg_descriptor,
	.bDescriptorType =	USB_DT_OTG,

117 118 119 120
	/* REVISIT SRP-only hardware is possible, although
	 * it would not be called "OTG" ...
	 */
	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
L
Linus Torvalds 已提交
121 122
};

123
static const struct usb_descriptor_header *otg_desc[] = {
L
Linus Torvalds 已提交
124 125 126
	(struct usb_descriptor_header *) &otg_descriptor,
	NULL,
};
127 128
#else
#define otg_desc	NULL
129
#endif
L
Linus Torvalds 已提交
130

131
/* string IDs are assigned dynamically */
D
David Brownell 已提交
132 133
/* default serial number takes at least two packets */
static char serial[] = "0123456789.0123456789.0123456789";
L
Linus Torvalds 已提交
134

135
#define USB_GZERO_SS_DESC	(USB_GADGET_FIRST_AVAIL_IDX + 0)
136
#define USB_GZERO_LB_DESC	(USB_GADGET_FIRST_AVAIL_IDX + 1)
137

138
static struct usb_string strings_dev[] = {
139
	[USB_GADGET_MANUFACTURER_IDX].s = "",
140 141
	[USB_GADGET_PRODUCT_IDX].s = longname,
	[USB_GADGET_SERIAL_IDX].s = serial,
142
	[USB_GZERO_SS_DESC].s	= "source and sink data",
143
	[USB_GZERO_LB_DESC].s	= "loop input to output",
L
Linus Torvalds 已提交
144 145 146
	{  }			/* end of list */
};

147
static struct usb_gadget_strings stringtab_dev = {
L
Linus Torvalds 已提交
148
	.language	= 0x0409,	/* en-us */
149
	.strings	= strings_dev,
L
Linus Torvalds 已提交
150 151
};

152 153 154 155
static struct usb_gadget_strings *dev_strings[] = {
	&stringtab_dev,
	NULL,
};
L
Linus Torvalds 已提交
156 157 158

/*-------------------------------------------------------------------------*/

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 193 194 195 196 197 198 199
static struct timer_list	autoresume_timer;

static void zero_autoresume(unsigned long _c)
{
	struct usb_composite_dev	*cdev = (void *)_c;
	struct usb_gadget		*g = cdev->gadget;

	/* unconfigured devices can't issue wakeups */
	if (!cdev->config)
		return;

	/* Normally the host would be woken up for something
	 * more significant than just a timer firing; likely
	 * because of some direct user request.
	 */
	if (g->speed != USB_SPEED_UNKNOWN) {
		int status = usb_gadget_wakeup(g);
		INFO(cdev, "%s --> %d\n", __func__, status);
	}
}

static void zero_suspend(struct usb_composite_dev *cdev)
{
	if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
		return;

	if (autoresume) {
		mod_timer(&autoresume_timer, jiffies + (HZ * autoresume));
		DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
	} else
		DBG(cdev, "%s\n", __func__);
}

static void zero_resume(struct usb_composite_dev *cdev)
{
	DBG(cdev, "%s\n", __func__);
	del_timer(&autoresume_timer);
}

/*-------------------------------------------------------------------------*/

200 201 202 203 204 205 206
static struct usb_configuration loopback_driver = {
	.label          = "loopback",
	.bConfigurationValue = 2,
	.bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
	/* .iConfiguration = DYNAMIC */
};

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
static struct usb_function *func_ss;
static struct usb_function_instance *func_inst_ss;

static int ss_config_setup(struct usb_configuration *c,
		const struct usb_ctrlrequest *ctrl)
{
	switch (ctrl->bRequest) {
	case 0x5b:
	case 0x5c:
		return func_ss->setup(func_ss, ctrl);
	default:
		return -EOPNOTSUPP;
	}
}

222 223 224 225 226 227 228 229
static struct usb_configuration sourcesink_driver = {
	.label                  = "source/sink",
	.setup                  = ss_config_setup,
	.bConfigurationValue    = 3,
	.bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
	/* .iConfiguration      = DYNAMIC */
};

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
module_param_named(buflen, gzero_options.bulk_buflen, uint, 0);
module_param_named(pattern, gzero_options.pattern, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none");

module_param_named(isoc_interval, gzero_options.isoc_interval, uint,
		S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(isoc_interval, "1 - 16");

module_param_named(isoc_maxpacket, gzero_options.isoc_maxpacket, uint,
		S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");

module_param_named(isoc_mult, gzero_options.isoc_mult, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");

module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
		S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");

static struct usb_function *func_lb;
static struct usb_function_instance *func_inst_lb;

module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(qlen, "depth of loopback queue");

255
static int __init zero_bind(struct usb_composite_dev *cdev)
L
Linus Torvalds 已提交
256
{
257 258
	struct f_ss_opts	*ss_opts;
	struct f_lb_opts	*lb_opts;
259
	int			status;
260

261 262
	/* Allocate string descriptor numbers ... note that string
	 * contents can be overridden by the composite_dev glue.
263
	 */
264 265 266 267
	status = usb_string_ids_tab(cdev, strings_dev);
	if (status < 0)
		return status;

268 269 270
	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
	device_desc.iSerialNumber = strings_dev[USB_GADGET_SERIAL_IDX].id;
271

272 273
	setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	func_inst_ss = usb_get_function_instance("SourceSink");
	if (IS_ERR(func_inst_ss))
		return PTR_ERR(func_inst_ss);

	ss_opts =  container_of(func_inst_ss, struct f_ss_opts, func_inst);
	ss_opts->pattern = gzero_options.pattern;
	ss_opts->isoc_interval = gzero_options.isoc_interval;
	ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
	ss_opts->isoc_mult = gzero_options.isoc_mult;
	ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket;
	ss_opts->bulk_buflen = gzero_options.bulk_buflen;

	func_ss = usb_get_function(func_inst_ss);
	if (IS_ERR(func_ss))
		goto err_put_func_inst_ss;

	func_inst_lb = usb_get_function_instance("Loopback");
	if (IS_ERR(func_inst_lb))
		goto err_put_func_ss;

	lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst);
	lb_opts->bulk_buflen = gzero_options.bulk_buflen;
	lb_opts->qlen = gzero_options.qlen;

	func_lb = usb_get_function(func_inst_lb);
	if (IS_ERR(func_lb)) {
		status = PTR_ERR(func_lb);
		goto err_put_func_inst_lb;
	}

304
	sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id;
305 306
	loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id;

307 308
	/* support autoresume for remote wakeup testing */
	sourcesink_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
309
	loopback_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
310
	sourcesink_driver.descriptors = NULL;
311 312
	loopback_driver.descriptors = NULL;
	if (autoresume) {
313
		sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
314 315
		loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
	}
316 317 318 319 320

	/* support OTG systems */
	if (gadget_is_otg(cdev->gadget)) {
		sourcesink_driver.descriptors = otg_desc;
		sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
321 322
		loopback_driver.descriptors = otg_desc;
		loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
323 324
	}

325 326
	/* Register primary, then secondary configuration.  Note that
	 * SH3 only allows one config...
L
Linus Torvalds 已提交
327
	 */
328
	if (loopdefault) {
329 330
		usb_add_config_only(cdev, &loopback_driver);
		usb_add_config_only(cdev, &sourcesink_driver);
331
	} else {
332 333
		usb_add_config_only(cdev, &sourcesink_driver);
		usb_add_config_only(cdev, &loopback_driver);
L
Linus Torvalds 已提交
334
	}
335 336 337
	status = usb_add_function(&sourcesink_driver, func_ss);
	if (status)
		goto err_conf_flb;
L
Linus Torvalds 已提交
338

339 340 341 342 343 344
	usb_ep_autoconfig_reset(cdev->gadget);
	status = usb_add_function(&loopback_driver, func_lb);
	if (status)
		goto err_conf_flb;

	usb_ep_autoconfig_reset(cdev->gadget);
345
	usb_composite_overwrite_options(cdev, &coverwrite);
L
Linus Torvalds 已提交
346

347
	INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
L
Linus Torvalds 已提交
348 349

	return 0;
350 351 352 353 354 355 356 357 358 359 360 361 362 363

err_conf_flb:
	usb_put_function(func_lb);
	func_lb = NULL;
err_put_func_inst_lb:
	usb_put_function_instance(func_inst_lb);
	func_inst_lb = NULL;
err_put_func_ss:
	usb_put_function(func_ss);
	func_ss = NULL;
err_put_func_inst_ss:
	usb_put_function_instance(func_inst_ss);
	func_inst_ss = NULL;
	return status;
L
Linus Torvalds 已提交
364 365
}

366 367 368
static int zero_unbind(struct usb_composite_dev *cdev)
{
	del_timer_sync(&autoresume_timer);
369 370 371 372
	if (!IS_ERR_OR_NULL(func_ss))
		usb_put_function(func_ss);
	if (!IS_ERR_OR_NULL(func_lb))
		usb_put_function(func_lb);
373 374 375
	return 0;
}

376
static __refdata struct usb_composite_driver zero_driver = {
377 378 379
	.name		= "zero",
	.dev		= &device_desc,
	.strings	= dev_strings,
380
	.max_speed	= USB_SPEED_SUPER,
381
	.bind		= zero_bind,
382 383 384
	.unbind		= zero_unbind,
	.suspend	= zero_suspend,
	.resume		= zero_resume,
L
Linus Torvalds 已提交
385 386
};

D
David Brownell 已提交
387 388
MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
L
Linus Torvalds 已提交
389

390
static int __init init(void)
L
Linus Torvalds 已提交
391
{
392
	return usb_composite_probe(&zero_driver);
L
Linus Torvalds 已提交
393
}
394
module_init(init);
L
Linus Torvalds 已提交
395

396
static void __exit cleanup(void)
L
Linus Torvalds 已提交
397
{
398
	usb_composite_unregister(&zero_driver);
L
Linus Torvalds 已提交
399
}
400
module_exit(cleanup);