dummy_hcd.c revision 0fb5759952e934dd5ff25fd79f45cb5d69c8d2d1
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maintainer: Alan Stern <stern@rowland.harvard.edu>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 David Brownell
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003-2005 Alan Stern
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This exposes a device side "USB gadget" API, driven by requests to a
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux-USB host controller driver.  USB traffic is simulated; there's
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no need for USB hardware.  Use this with two other drivers:
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Gadget driver, responding to requests (slave);
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Host-side device driver, as already familiar in Linux.
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Having this all in one kernel can help some stages of development,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bypassing some hardware (and driver) issues.  UML could help too.
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
47d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
499454a57ab5922e5cd25321cae9d1a8cbeb3e2e85David Brownell#include <linux/usb/gadget.h>
5027729aadd31dafddaaf64c24f8ef6d0ff750f3aaEric Lescouet#include <linux/usb/hcd.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC	"USB Host+Gadget Emulator"
60391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION	"02 May 2005"
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern#define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
63caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_name [] = "dummy_hcd";
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_desc [] = "USB Host+Gadget Emulator";
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	gadget_name [] = "dummy_udc";
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC);
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell");
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL");
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstruct dummy_hcd_module_parameters {
741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	bool is_super_speed;
757eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	bool is_high_speed;
761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct dummy_hcd_module_parameters mod_data = {
797eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_super_speed = false,
807eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_high_speed = true,
811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanmodule_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana BrokhmanMODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
847eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhmanmodule_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
857eca4c5a8b73f22ad16ad6e76b901351732355daTatyana BrokhmanMODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep {
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			last_io;	/* jiffies timestamp */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		*gadget;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usb_endpoint_descriptor *desc;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep			ep;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			halted : 1;
96851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	unsigned			wedged : 1;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			already_seen : 1;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			setup_stage : 1;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;		/* ep's requests */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_request		req;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_ep, struct dummy_ep, ep);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(struct usb_request *_req)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_req, struct dummy_request, req);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints,
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types:
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Configurable:  direction (in/out), type (bulk, iso, etc), and endpoint
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     number can be changed.  Names like "ep-a" are used for this type.
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Fixed Function:  in other cases.  some characteristics may be mutable;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     that'd be hardware-specific.  Names like "ep12out-bulk" are used.
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on.
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0";
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep0name,				/* everyone has ep0 */
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* act like a net2280: high speed, six configurable endpoints */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like pxa250: fifteen fixed function endpoints */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ep15in-int",
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like sa1100: two fixed function endpoints */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1out-bulk", "ep2in-bulk",
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15052950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS	ARRAY_SIZE(ep_name)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
153d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE		64
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp {
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb		*urb;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head	urbp_list;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
162391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state {
163391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RESET,
164391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_SUSPENDED,
165391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RUNNING
166391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern};
167391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstruct dummy_hcd {
169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy			*dum;
170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	enum dummy_rh_state		rh_state;
171cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct timer_list		timer;
172cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				port_status;
173cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				old_status;
174cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned long			re_timeout;
175cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
176cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_device		*udev;
177cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct list_head		urbp_list;
178cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			active:1;
180cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			old_active:1;
181cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			resuming:1;
182cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman};
183cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy {
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t			lock;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE/GADGET side support
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep			ep [DUMMY_ENDPOINTS];
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				address;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		gadget;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget_driver	*driver;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request		fifo_req;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8				fifo_buf [FIFO_SIZE];
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16				devstatus;
197391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned			udc_suspended:1;
198f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			pullup:1;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER/HOST side support
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd		*hs_hcd;
2041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy_hcd		*ss_hcd;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
209cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return (struct dummy_hcd *) (hcd->hcd_priv);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
212cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of((void *) dum, struct usb_hcd, hcd_priv);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
217cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct device *dummy_dev(struct dummy_hcd *dum)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
219cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return dummy_hcd_to_hcd(dum)->self.controller;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
222d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum)
223d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
224d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return dum->gadget.dev.parent;
225d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
226d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (ep->gadget, struct dummy, gadget);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
232cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
234cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = container_of(gadget, struct dummy, gadget);
2351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER)
2361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->ss_hcd;
2371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	else
2381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->hs_hcd;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (dev, struct dummy, gadget.dev);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
246cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic struct dummy			the_controller;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */
251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */
253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep)
254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	while (!list_empty (&ep->queue)) {
256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		struct dummy_request	*req;
257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req = list_entry (ep->queue.next, struct dummy_request, queue);
259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		list_del_init (&req->queue);
260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.status = -ESHUTDOWN;
261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_unlock (&dum->lock);
263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.complete (&ep->ep, &req->req);
264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_lock (&dum->lock);
265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum)
271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy_ep	*ep;
273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
274f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* prevent any more requests */
275f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->address = 0;
276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* The timer is left running so that outstanding URBs can fail */
278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* nuke any pending requests first, so driver i/o is quiesced */
280f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
281f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		nuke (dum, ep);
282f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
283f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* driver now does any non-usb quiescing necessary */
284f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
285f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
2861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/**
2871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * set_link_state_by_speed() - Sets the current state of the link according to
2881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *	the hcd speed
2891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
2901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *
2911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * This function updates the port_status according to the link state and the
2921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * speed of the hcd.
2931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */
2941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
2951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy *dum = dum_hcd->dum;
2971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) {
2991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) {
3001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
3011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
3021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
3031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
3041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE);
3051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* device is connected and not suspended */
3111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
3121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						 USB_PORT_STAT_SPEED_5GBPS) ;
3131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status &
3181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_ENABLE) == 1 &&
3191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(dum_hcd->port_status &
3201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 USB_SS_PORT_LS_U0) == 1 &&
3211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
3251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) {
3261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
3271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
3281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
3291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
3301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE |
3311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_LOW_SPEED |
3321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_HIGH_SPEED |
3331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_SUSPEND);
3341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
3401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
3451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
3461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else if ((dum_hcd->port_status &
3471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				  USB_PORT_STAT_SUSPEND) == 0 &&
3481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
3521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
3531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
354f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
355cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void set_link_state(struct dummy_hcd *dum_hcd)
356f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
357cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = dum_hcd->dum;
358cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
359cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->active = 0;
3601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->pullup)
3611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
3621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed != USB_SPEED_SUPER) ||
3631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
3641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed == USB_SPEED_SUPER))
3651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			return;
3661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
3671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	set_link_state_by_speed(dum_hcd);
368f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
369cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
370cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	     dum_hcd->active)
371cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->resuming = 0;
372f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* if !connected or reset */
374cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
375cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
3761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
3771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * We're connected and not reset (reset occurred now),
3781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * and driver attached - disconnect!
3791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
380cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
3811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
3821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    dum->driver) {
3831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			stop_activity(dum);
3841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->disconnect(&dum->gadget);
3861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
387f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
388cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->active != dum_hcd->old_active) {
389cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->old_active && dum->driver->suspend) {
3901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->suspend(&dum->gadget);
3921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
3931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
3941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->resume(&dum->gadget);
3961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
397f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
398f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
399f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
400cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_status = dum_hcd->port_status;
401cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_active = dum_hcd->active;
402f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
403f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
404f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/
405f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state.  All the work is done when the host
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation.  Real device controller
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc.
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(dum->port_status & USB_PORT_STAT_ENABLE)
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
420cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		max;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !desc || ep->desc || _ep->name == ep0name
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| desc->bDescriptorType != USB_DT_ENDPOINT)
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
430cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver)
431cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		return -ESHUTDOWN;
432719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior
433719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
434cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!is_enabled(dum_hcd))
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
436cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
437cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	/*
438cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
439cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * maximum packet size.
4401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	 * For SS devices the wMaxPacketSize is limited by 1024.
441cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 */
442cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* drivers must not request bad settings, since lower levels
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (hardware or its drivers) may not check.  some endpoints
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't do iso, many have maxpacket limitations, etc.
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since this "hardware" driver is here to help debugging, we
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have some extra sanity checks.  (there could be more though,
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially for "ep9out" style fixed function ones.)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = -EINVAL;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (desc->bmAttributes & 0x03) {
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_BULK:
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int")) {
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (max == 1024)
4621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
4631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto done;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max == 512)
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4679063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4689063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		case USB_SPEED_FULL:
4699063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			if (max == 8 || max == 16 || max == 32 || max == 64)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we'll fake any legal size */
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4729063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			/* save a return statement */
4739063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		default:
4749063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_INT:
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 64)
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 8)
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_ISOC:
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-bulk")
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int"))
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
5031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1023)
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* few chips support control except on ep0 */
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_ep->maxpacket = max;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = desc;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
524d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_ep->name,
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		desc->bEndpointAddress & 0x0f,
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *val;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (desc->bmAttributes & 0x03) {
5307c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_BULK:
5317c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "bulk";
5327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5337c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_ISOC:
5347c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "iso";
5357c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5367c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_INT:
5377c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "intr";
5387c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5397c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
5407c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "ctrl";
5417c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; val; }),
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		max);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* at this point real hardware should be NAKing transfers
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to that endpoint, until a buffer is queued to it.
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
548851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	ep->halted = ep->wedged = 0;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep)
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !ep->desc || _ep->name == ep0name)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = NULL;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nuke (dum, ep);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
572d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request *
57755016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5867039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn	req = kzalloc(sizeof(*req), mem_flags);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!req)
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&req->queue);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &req->req;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON (!list_empty (&req->queue));
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (req);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req)
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6145db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req,
61555016f10e31bb15b85d8c500f979dfdceb37d548Al Viro		gfp_t mem_flags)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
620cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_req || !list_empty (&req->queue) || !_req->complete)
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
632719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
633cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver || !is_enabled(dum_hcd))
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
637d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&dum->fifo_req.queue) &&
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&ep->queue) &&
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy (dum->fifo_buf, _req->buf, _req->length);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
657c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
663c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell	}  else
664c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
689b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_save (flags);
690b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_lock (&dum->lock);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
699b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_unlock (&dum->lock);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
702d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		dev_dbg (udc_dev(dum),
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
707b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_restore (flags);
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
712851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
724851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		ep->halted = ep->wedged = 0;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!list_empty (&ep->queue))
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
728851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	else {
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
730851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		if (wedged)
731851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern			ep->wedged = 1;
732851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	}
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
737851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int
738851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt(struct usb_ep *_ep, int value)
739851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
740851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, value, 0);
741851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
742851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
743851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int dummy_set_wedge(struct usb_ep *_ep)
744851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
745851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	if (!_ep || _ep->name == ep0name)
746851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		return -EINVAL;
747851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, 1, 1);
748851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
749851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
761851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	.set_wedge	= dummy_set_wedge,
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget)
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday (&tv);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget)
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
777cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
779cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = gadget_to_dummy_hcd(_gadget);
780cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
7815742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
783cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
784391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
785cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
786cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
787391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
788391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
789391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
792cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->resuming = 1;
793cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
794cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
802cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (gadget_to_dummy_hcd(_gadget))->dum;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
810f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value)
811f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
812d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd;
813f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
814f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
815f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
816d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(_gadget);
817d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	dum = dum_hcd->dum;
818d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior
819f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
820f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
821d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
822f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
823d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
824f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
825f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
826f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
8270f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget_driver *driver,
8280f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		int (*bind)(struct usb_gadget *));
8290f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget_driver *driver);
8300f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
835f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
8360f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	.start		= dummy_udc_start,
8370f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	.stop		= dummy_udc_stop,
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
84410523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf)
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = gadget_dev_to_dummy (dev);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
852cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8700f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget_driver *driver,
871b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König		int (*bind)(struct usb_gadget *))
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
873cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy	*dum = &the_controller;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval, i;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum)
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->driver)
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
880b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König	if (!bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN)
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8875742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (mod_data.is_super_speed)
8911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dum->gadget.speed = driver->speed;
8927eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	else if (mod_data.is_high_speed)
8937eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, driver->speed);
8941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	else
8957eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		dum->gadget.speed = USB_SPEED_FULL;
8961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed < driver->speed)
8977eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		dev_dbg(udc_dev(dum), "This device can perform faster"
8987eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman				" if you connect it to a %s port...\n",
8997eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman			(driver->speed == USB_SPEED_SUPER ?
9007eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman			 "SuperSpeed" : "HighSpeed"));
9011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
9021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER) {
9031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		for (i = 0; i < DUMMY_ENDPOINTS; i++)
9041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->ep[i].ep.max_streams = 0x10;
9051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dum->ep[0].ep.maxpacket = 9;
9060fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	} else {
9070fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		for (i = 0; i < DUMMY_ENDPOINTS; i++)
9080fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior			dum->ep[i].ep.max_streams = 0;
9091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dum->ep[0].ep.maxpacket = 64;
9100fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	}
91199fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior
91299fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior	if (dum->gadget.speed == USB_SPEED_SUPER)
91399fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior		dum->gadget.is_otg =
91499fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior			(dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0);
91599fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior	else
91699fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior		dum->gadget.is_otg =
91799fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior			(dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
91899fd14080e7f0a65b87830bf5062b09f6e80dd13Sebastian Andrzej Siewior
9195933101718ea3d283983a923c5524c88138e5564Alan Stern	driver->driver.bus = NULL;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->gadget.dev.driver = &driver->driver;
922d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
924b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König	retval = bind(&dum->gadget);
9255933101718ea3d283983a923c5524c88138e5564Alan Stern	if (retval) {
9265933101718ea3d283983a923c5524c88138e5564Alan Stern		dum->driver = NULL;
9275933101718ea3d283983a923c5524c88138e5564Alan Stern		dum->gadget.dev.driver = NULL;
9285933101718ea3d283983a923c5524c88138e5564Alan Stern		return retval;
9295933101718ea3d283983a923c5524c88138e5564Alan Stern	}
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9312542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior	/* khubd will enumerate this in a while */
9322542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior	dummy_pullup(&dum->gadget, 1);
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9360f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget_driver *driver)
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
938cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy	*dum = &the_controller;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum)
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
9426bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell	if (!driver || driver != dum->driver || !driver->unbind)
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
945d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9482542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior	dummy_pullup(&dum->gadget, 0);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->unbind (&dum->gadget);
9515933101718ea3d283983a923c5524c88138e5564Alan Stern	dum->gadget.dev.driver = NULL;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
9532542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior
9542542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior	dummy_pullup(&dum->gadget, 0);
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
960d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
961d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
962d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
963d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev)
964d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
965cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return;
966d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
967d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9680fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewiorstatic void init_dummy_udc_hw(struct dummy *dum)
9690fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior{
9700fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	int i;
9710fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9720fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->gadget.ep_list);
9730fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
9740fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		struct dummy_ep	*ep = &dum->ep[i];
9750fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9760fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		if (!ep_name[i])
9770fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior			break;
9780fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.name = ep_name[i];
9790fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.ops = &dummy_ep_ops;
9800fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
9810fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->halted = ep->wedged = ep->already_seen =
9820fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior				ep->setup_stage = 0;
9830fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.maxpacket = ~0;
9840fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->last_io = jiffies;
9850fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->gadget = &dum->gadget;
9860fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->desc = NULL;
9870fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		INIT_LIST_HEAD(&ep->queue);
9880fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	}
9890fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9900fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	dum->gadget.ep0 = &dum->ep[0].ep;
9910fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	list_del_init(&dum->ep[0].ep.ep_list);
9920fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->fifo_req.queue);
9930fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior}
9940fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9958364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_probe (struct platform_device *pdev)
996d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
997cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy	*dum = &the_controller;
998d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
999d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1000d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
1001d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
1002d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.is_dualspeed = 1;
1003d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10040031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers	dev_set_name(&dum->gadget.dev, "gadget");
10058364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dum->gadget.dev.parent = &pdev->dev;
1006d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
1007d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	rc = device_register (&dum->gadget.dev);
100875d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	if (rc < 0) {
100975d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar		put_device(&dum->gadget.dev);
1010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
101175d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	}
1012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10130fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	init_dummy_udc_hw(dum);
10140fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
10150f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
10160f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	if (rc < 0)
10170f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_udc;
10180f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
1019efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
1020efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if (rc < 0)
10210f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_dev;
10220f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	platform_set_drvdata(pdev, dum);
10230f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	return rc;
10240f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
10250f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_dev:
10260f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10270f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_udc:
10280f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	device_unregister(&dum->gadget.dev);
1029d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
1030d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1031d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10328364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_remove (struct platform_device *pdev)
1033d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
10348364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	struct dummy	*dum = platform_get_drvdata (pdev);
1035d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10360f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10378364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	platform_set_drvdata (pdev, NULL);
1038d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_remove_file (&dum->gadget.dev, &dev_attr_function);
1039d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_unregister (&dum->gadget.dev);
1040d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
1041d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1042d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1043fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd,
1044fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior		int suspend)
1045391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1046fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_lock_irq(&dum->lock);
1047fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dum->udc_suspended = suspend;
1048d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
1049fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_unlock_irq(&dum->lock);
1050fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior}
1051fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior
1052fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state)
1053fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior{
1054fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1055fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1056391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1057fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1058fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 1);
1059d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1060391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1061391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1062391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1063fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_resume(struct platform_device *pdev)
1064391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1065fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1066fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1067391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1068fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1069fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 0);
1070d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1071391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1072391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1073391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
10743ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = {
1075d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
1076d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
1077391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
1078391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
10793ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
10803ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) gadget_name,
10813ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
10823ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
1083d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
1084d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue (
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
110255016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t				mem_flags
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1104cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
1107e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urb->transfer_buffer && urb->transfer_buffer_length)
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp = kmalloc (sizeof *urbp, mem_flags);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1117cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1118cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1119e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_link_urb_to_ep(hcd, urb);
1120e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	if (rc) {
1121e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		kfree(urbp);
1122e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		goto done;
1123e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	}
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1125cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1126cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = urb->dev;
1127cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_get_dev(dum_hcd->udev);
1128cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (unlikely(dum_hcd->udev != urb->dev))
1129cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
1137cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!timer_pending(&dum_hcd->timer))
1138cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + 1);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1140e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done:
1141cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1142e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1145e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1147cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
1148391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1149e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
1150391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1151391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1152391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1153cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1154cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1155e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1156e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1157cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
1158cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			!list_empty(&dum_hcd->urbp_list))
1159cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies);
1160e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1161cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1162e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11674d2f110c51eec853c50f68cf068888a77551c8d3Alan Sterntransfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
11684d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int *status)
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min (host_len, dev_len);
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_host = usb_pipein (urb->pipe);
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely (len == 0))
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char		*ubuf, *rbuf;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = min (len, (unsigned) limit);
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* else transfer packet(s) */
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ubuf = urb->transfer_buffer + urb->actual_length;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rbuf = req->req.buf + req->req.actual;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (to_host)
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (ubuf, rbuf, len);
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (rbuf, ubuf, len);
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit -= len;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->actual_length += len;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.actual += len;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
1231b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern		 * need to emulate such data-in-flight.
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12364d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
12404d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = -EOVERFLOW;
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
12424d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = 0;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
12444d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
12584d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern						& URB_ZERO_PACKET))
12594d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock (&dum->lock);
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.complete (&ep->ep, &req->req);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock (&dum->lock);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
12754d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (*status != -EINPROGRESS)
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER) {
12991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		switch (ep->desc->bmAttributes & 0x03) {
13001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_ISOC:
13011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.8.2 USB3.0 Spec */
13021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 16 * 1024 * 8;
13031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
13041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_INT:
13051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.7.2 USB3.0 Spec */
13061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 1024 * 8;
13071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
13081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_BULK:
13091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		default:
13101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
13111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
13121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1316cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman#define is_active(dum_hcd)	((dum_hcd->port_status & \
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
13261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->ss_hcd : dum->hs_hcd)))
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return &dum->ep [0];
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
13518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman/**
13528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * handle_control_request() - handles all control transfers
13538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @dum: pointer to dummy (the_controller)
13548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @urb: the urb request to handle
13558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @setup: pointer to the setup data for a USB device control
13568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	 request
13578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @status: pointer to request handling status
13588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *
13598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * Return 0 - if the request was handled
13608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  1 - if the request wasn't handles
13618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  error code on error
13628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */
1363cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
13648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  struct usb_ctrlrequest *setup,
13658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  int *status)
13668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman{
13678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	struct dummy_ep		*ep2;
1368cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
13698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	int			ret_val = 1;
13708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_index;
13718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_value;
13728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
13738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_index = le16_to_cpu(setup->wIndex);
13748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_value = le16_to_cpu(setup->wValue);
13758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	switch (setup->bRequest) {
13768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_ADDRESS:
13778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType != Dev_Request)
13788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			break;
13798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dum->address = w_value;
13808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		*status = 0;
13818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dev_dbg(udc_dev(dum), "set_address = %d\n",
13828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value);
13838be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		ret_val = 0;
13848be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
13858be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_FEATURE:
13868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
13878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
13888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
13898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
13908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_B_HNP_ENABLE:
13928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.b_hnp_enable = 1;
13938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_HNP_SUPPORT:
13958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_hnp_support = 1;
13968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_ALT_HNP_SUPPORT:
13988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_alt_hnp_support = 1;
13998be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
14011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
14041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
14081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
14111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
14151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
14181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
14228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
14258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus |= (1 << w_value);
14268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
14278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
14298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
14308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
14318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2 || ep2->ep.name == ep0name) {
14328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2->halted = 1;
14368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
14388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
14398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_CLEAR_FEATURE:
14418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
14428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
14448be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
14458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value = USB_DEVICE_REMOTE_WAKEUP;
14468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
14481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
14511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
14551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
14581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
14621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
14651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
14698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
14738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus &= ~(1 << w_value);
14748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
14758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
14778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
14788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
14798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2) {
14808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14838be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2->wedged)
14848be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ep2->halted = 0;
14858be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
14878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
14888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_GET_STATUS:
14908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_InRequest
14918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Intf_InRequest
14928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Ep_InRequest) {
14938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			char *buf;
14948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/*
14958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * device: remote wakeup, selfpowered
14968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * interface: nothing
14978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * endpoint: halt
14988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 */
14998be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			buf = (char *)urb->transfer_buffer;
15008be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 0) {
15018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				if (setup->bRequestType == Ep_InRequest) {
15028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					ep2 = find_endpoint(dum, w_index);
15038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					if (!ep2) {
15048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						ret_val = -EOPNOTSUPP;
15058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						break;
15068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					}
15078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = ep2->halted;
15088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else if (setup->bRequestType ==
15098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					   Dev_InRequest) {
15108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = (u8)dum->devstatus;
15118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else
15128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = 0;
15138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 1)
15158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				buf[1] = 0;
15168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			urb->actual_length = min_t(u32, 2,
15178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				urb->transfer_buffer_length);
15188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
15208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
15218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
15228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	}
15238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	return ret_val;
15248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman}
15258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1529cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void dummy_timer(unsigned long _dum_hcd)
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1531cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
1532cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case USB_SPEED_SUPER:
15501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* Bus speed is 500000 bytes/ms, so use a little less */
15511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		total = 490000;
15521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1554cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1563cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1564cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd),
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&dum->lock, flags);
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->ep [i].already_seen = 0;
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
1577cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
15834d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int			status = -EINPROGRESS;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
1586eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern		if (urb->unlinked)
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1588cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
1589391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = usb_pipetype (urb->pipe);
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (usb_pipein (urb->pipe))
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
1606cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
16094d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPROTO;
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && urb->error_count) {
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
1622cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
16244d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPIPE;
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && ep->setup_stage) {
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_for_each_entry (req, &ep->queue, queue) {
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				list_del_init (&req->queue);
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
1639d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "stale req = %p\n",
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.complete (&ep->ep, &req->req);
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1657cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			value = handle_control_request(dum_hcd, urb, &setup,
16588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						       &status);
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = dum->driver->setup (&dum->gadget,
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
1679d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern					dev_dbg (udc_dev(dum),
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
16824d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				status = -EPIPE;
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (usb_pipetype (urb->pipe)) {
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
16994d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -ENOSYS;
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// case PIPE_BULK:  case PIPE_CONTROL:
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		treat_control_like_bulk:
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
17134d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			total = transfer(dum, urb, ep, limit, &status);
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
17184d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (status == -EINPROGRESS)
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del (&urbp->urbp_list);
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (urbp);
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1727cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
1729cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1735cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (list_empty(&dum_hcd->urbp_list)) {
1736cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_dev(dum_hcd->udev);
1737cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = NULL;
1738cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
1739391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1740cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1749c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1750c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1751c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1752c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1753c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf)
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1757cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1759391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1763cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1764541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1765391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1766f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1767cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
1768cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1769cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
1770cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1771f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1772f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1773cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
1775cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
1776cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status);
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1778cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
1779391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			usb_hcd_resume_root_hub (hcd);
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1781391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
1782cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
17871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanss_hub_descriptor(struct usb_hub_descriptor *desc)
17881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
17891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	memset(desc, 0, sizeof *desc);
17901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescriptorType = 0x2a;
17911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescLength = 12;
17921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->wHubCharacteristics = cpu_to_le16(0x0001);
17931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bNbrPorts = 1;
17941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
17951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.DeviceRemovable = 0xffff;
17961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
17971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
17981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic inline void
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc)
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (desc, 0, sizeof *desc);
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1804fd05e720099e8eeddb378305d1a41c1445344b91Al Viro	desc->wHubCharacteristics = cpu_to_le16(0x0001);
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
1806dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[0] = 0xff;
1807dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[1] = 0xff;
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control (
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1818cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1822541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1823391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1824391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1825cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1826cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1827cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
18341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
18351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
18361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
18371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
18381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
18391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1840cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
1842cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->resuming = 1;
1843cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->re_timeout = jiffies +
1844f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
18481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
18491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
18501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
18511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
18521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
18531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status &
18541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SS_PORT_STAT_POWER)
18551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
18561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
1857f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1859cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~(1 << wValue);
1860cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
18641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3 &&
18651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(wLength < USB_DT_SS_HUB_SIZE ||
18661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 wValue != (USB_DT_SS_HUB << 8))) {
18671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
18681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"Wrong hub descriptor type for "
18691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"USB 3.0 roothub.\n");
18701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
18711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
18721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3)
18731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
18741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		else
18751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			hub_descriptor((struct usb_hub_descriptor *) buf);
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
1878551509d267905705f6d723e51ec706916f06b859Harvey Harrison		*(__le32 *) buf = cpu_to_le32 (0);
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1887cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->resuming &&
1888cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
1889cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1890cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1892cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
1893cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
1894cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
1895cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
1896cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->dum->pullup) {
1897cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
18981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
18991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (hcd->speed < HCD_USB3) {
19001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					switch (dum_hcd->dum->gadget.speed) {
19011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_HIGH:
19021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
19031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						      USB_PORT_STAT_HIGH_SPEED;
19041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
19051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_LOW:
19061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.ep0->
19071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							maxpacket = 8;
19081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
19091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_PORT_STAT_LOW_SPEED;
19101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
19111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					default:
19121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.speed =
19131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SPEED_FULL;
19141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
19151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					}
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1919cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1920cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
1921cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
19281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_LINK_STATE:
19291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_LINK_STATE req not "
19321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
19361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * Since this is dummy we don't have an actual link so
19371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * there is nothing to do for the SET_LINK_STATE cmd
19381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
19391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
19401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U1_TIMEOUT:
19411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U2_TIMEOUT:
19421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* TODO: add suspend/resume support! */
19431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
19461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
19511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB2.0 hub */
19521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
19551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
19561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1958cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->active) {
1959cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
1960f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1961f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
1962f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
1963f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
1964cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				set_link_state(dum_hcd);
1965f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
1966cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman						& dum_hcd->dum->devstatus) != 0)
1967cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
19685742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1971f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
19721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3)
19731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
19741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else
19751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_POWER;
1976cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
1977f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
19781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_BH_PORT_RESET:
19791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB3.0 hub */
19801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_BH_PORT_RESET req not "
19831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* FALLS THROUGH */
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
1988f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
19891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status = 0;
19911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status =
19921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_SS_PORT_STAT_POWER |
19931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_CONNECTION |
19941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_RESET);
19951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
19961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
1997f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
1998f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
1999cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			/*
2000cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * We want to reset device status. All but the
2001cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * Self powered feature
2002cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 */
2003cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->dum->devstatus &=
2004cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				(1 << USB_DEVICE_SELF_POWERED);
20051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
20061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * FIXME USB3.0: what is the correct reset signaling
20071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * interval? Is it still 50msec as for HS?
20081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
2009cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
2010f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
20121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
20131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
20141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_SS_PORT_STAT_POWER) != 0) {
20151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
20161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
20171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
20181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
20191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
20201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_PORT_STAT_POWER) != 0) {
20211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
20221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
20231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
20241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
20261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case GetPortErrorCount:
20271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
20281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "GetPortErrorCount req not "
20301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "supported for USB 2.0 roothub\n");
20311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* We'll always return 0 since this is a dummy hub */
20341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		*(__le32 *) buf = cpu_to_le32(0);
20351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
20361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case SetHubDepth:
20371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
20381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "SetHubDepth req not supported for "
20401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "USB 2.0 roothub\n");
20411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2045cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd),
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
20481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanerror:
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2052cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2053685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
2054cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
2055685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern		usb_hcd_poll_rh_status (hcd);
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20590c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd)
2060391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2061cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2062391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2063441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
20643cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2065cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2066cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
2067cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	set_link_state(dum_hcd);
20683cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd->state = HC_STATE_SUSPENDED;
2069cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
2070391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2071391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2072391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
20730c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd)
2074391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2075cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
20763cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int rc = 0;
20773cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2078441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
2079391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2080cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2081541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd)) {
2082cfa59dab27d1b282886e7772a8f9548236883892Alan Stern		rc = -ESHUTDOWN;
20833cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else {
2084cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->rh_state = DUMMY_RH_RUNNING;
2085cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
2086cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (!list_empty(&dum_hcd->urbp_list))
2087cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			mod_timer(&dum_hcd->timer, jiffies);
20883cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		hcd->state = HC_STATE_RUNNING;
20893cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	}
2090cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
20913cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2092391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb)
20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ep = usb_pipeendpoint (urb->pipe);
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf (buf, size,
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (urb->dev->speed) {
21067c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_LOW:
21077c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "ls";
21087c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21097c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_FULL:
21107c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "fs";
21117c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21127c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_HIGH:
21137c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "hs";
21147c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 case USB_SPEED_SUPER:
21161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			s = "ss";
21171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
21187c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
21197c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "?";
21207c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (usb_pipetype (urb->pipe)) { \
21257c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_CONTROL: \
21267c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = ""; \
21277c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21287c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_BULK: \
21297c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-bulk"; \
21307c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21317c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_INTERRUPT: \
21327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-int"; \
21337c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21347c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default: \
21357c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-iso"; \
21367c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}; s;}),
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
214210523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf)
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd = dev_get_drvdata (dev);
2145cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2150cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2151cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2158cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic int dummy_start_ss(struct dummy_hcd *dum_hcd)
21651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
21661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	init_timer(&dum_hcd->timer);
21671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.function = dummy_timer;
21681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
21691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
21701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
21711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
21721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
21731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
21741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#ifdef CONFIG_USB_OTG
21751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
21761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#endif
21771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
21781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
21791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
21801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
21811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
21821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2183cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_start(struct usb_hcd *hcd)
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2185cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
21921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!usb_hcd_is_primary_hcd(hcd))
21931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dummy_start_ss(dum_hcd);
21941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2195cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_init(&dum_hcd->dum->lock);
2196cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	init_timer(&dum_hcd->timer);
2197cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.function = dummy_timer;
2198cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
2199cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2203caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern	hcd->power_budget = POWER_BUDGET;
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
2205685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22075742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
22085742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
22095742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
22105742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
2212cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd)
22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2219cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(hcd))->dum;
2220cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
2221cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_gadget_unregister_driver(dum->driver);
2222cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd)
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_g_get_frame (NULL);
22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2232cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_setup(struct usb_hcd *hcd)
2233cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman{
2234cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (usb_hcd_is_primary_hcd(hcd)) {
2235cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
2236cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd->dum = &the_controller;
22371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
22381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * Mark the first roothub as being USB 2.0.
22391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * The USB 3.0 roothub will be registered later by
22401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * dummy_hcd_probe()
22411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
2242cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->speed = HCD_USB2;
2243cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_HIGH;
22441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
22451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
22461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd->dum = &the_controller;
22471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->speed = HCD_USB3;
22481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_SUPER;
2249cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	}
2250cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return 0;
2251cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman}
2252cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
22531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Change a group of bulk endpoints to support multiple stream IDs */
22541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
22551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
22561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	unsigned int num_streams, gfp_t mem_flags)
22571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (hcd->speed != HCD_USB3)
22591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
22601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			"%s() - ERROR! Not supported for USB2.0 roothub\n",
22611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			__func__);
22621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
22631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
22641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Reverts a group of bulk endpoints back to not using stream IDs. */
22661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
22671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
22681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	gfp_t mem_flags)
22691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (hcd->speed != HCD_USB3)
22711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
22721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			"%s() - ERROR! Not supported for USB2.0 roothub\n",
22731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			__func__);
22741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
22751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
22761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct hc_driver dummy_hcd = {
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
2280cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.hcd_priv_size =	sizeof(struct dummy_hcd),
22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.flags =		HCD_USB3 | HCD_SHARED,
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2284cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.reset =		dummy_setup,
22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_enqueue = 		dummy_urb_enqueue,
22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_dequeue = 		dummy_urb_dequeue,
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame_number = 	dummy_h_get_frame,
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_status_data = 	dummy_hub_status,
22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_control = 		dummy_hub_control,
22950c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_suspend =		dummy_bus_suspend,
22960c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_resume =		dummy_bus_resume,
22971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.alloc_streams =	dummy_alloc_streams,
22991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.free_streams =		dummy_free_streams,
23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23028364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev)
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2304cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_hcd		*hs_hcd;
23051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_hcd		*ss_hcd;
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23088364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!mod_data.is_super_speed)
23111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dummy_hcd.flags = HCD_USB2;
2312cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
2313cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!hs_hcd)
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2315cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd->has_tt = 1;
23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2317cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	retval = usb_add_hcd(hs_hcd, 0, 0);
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
2319cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_hcd(hs_hcd);
23201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return retval;
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (mod_data.is_super_speed) {
23241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
23251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_name(&pdev->dev), hs_hcd);
23261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (!ss_hcd) {
23271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			retval = -ENOMEM;
23281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto dealloc_usb2_hcd;
23291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
23301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		retval = usb_add_hcd(ss_hcd, 0, 0);
23321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (retval)
23331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto put_usb3_hcd;
23341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
23351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
23361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanput_usb3_hcd:
23381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(ss_hcd);
23391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmandealloc_usb2_hcd:
23401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(hs_hcd);
23411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2345cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_hcd_remove(struct platform_device *pdev)
23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2347cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum;
2348cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
2349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
23501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->ss_hcd) {
23521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
23531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
23541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
23551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2356cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2357cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
23581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2359cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	the_controller.hs_hcd = NULL;
23601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.ss_hcd = NULL;
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2362d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23658364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
2366391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2367391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2368cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
23693cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int			rc = 0;
2370391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2371441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2372391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23733cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
2374cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
2375cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
23763cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
23773cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		rc = -EBUSY;
23783cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else
23793cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
23803cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2381391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2382391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23838364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_resume (struct platform_device *pdev)
2384391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2385391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2386391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2387441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2388391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23893cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
23903cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
2391391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (hcd);
2392391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2393391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2394391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23953ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = {
2396d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
2397d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
2398391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
2399391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
24003ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
24013ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) driver_name,
24023ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
24033ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2404d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2406d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2408a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_udc_pdev;
2409a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_hcd_pdev;
24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void)
24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2413a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	int	retval = -ENOMEM;
24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_disabled ())
24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2417d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
24187eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	if (!mod_data.is_high_speed && mod_data.is_super_speed)
24197eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		return -EINVAL;
24207eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman
2421a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_hcd_pdev = platform_device_alloc(driver_name, -1);
2422a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_hcd_pdev)
24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
2424a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_udc_pdev = platform_device_alloc(gadget_name, -1);
2425a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_udc_pdev)
2426a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_alloc_udc;
2427d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2428a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_hcd_driver);
2429a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (retval < 0)
2430a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_register_hcd_driver;
2431a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_udc_driver);
2432d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2433d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2434d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2435a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_hcd_pdev);
2436d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2437a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_hcd;
24381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!the_controller.hs_hcd ||
24391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	    (!the_controller.ss_hcd && mod_data.is_super_speed)) {
2440865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2441865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The hcd was added successfully but its probe function failed
2442865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2443865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2444865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2445865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_add_udc;
2446865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2447a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_udc_pdev);
2448d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2449a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_udc;
2450865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	if (!platform_get_drvdata(the_udc_pdev)) {
2451865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2452865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The udc was added successfully but its probe function failed
2453865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2454865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2455865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2456865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_probe_udc;
2457865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2458d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2459d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2460865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewiorerr_probe_udc:
2461865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	platform_device_del(the_udc_pdev);
2462a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_udc:
2463a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_del(the_hcd_pdev);
2464a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_hcd:
2465a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2466d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
2467a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
2468a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_register_hcd_driver:
2469a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_udc_pdev);
2470a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_alloc_udc:
2471a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_hcd_pdev);
24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init);
24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void)
24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2478a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_udc_pdev);
2479a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_hcd_pdev);
2480a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2481a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup);
2484