dummy_hcd.c revision c688419141ad6134d7973fcf182e3719e98d7491
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
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This exposes a device side "USB gadget" API, driven by requests to a
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux-USB host controller driver.  USB traffic is simulated; there's
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no need for USB hardware.  Use this with two other drivers:
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Gadget driver, responding to requests (slave);
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Host-side device driver, as already familiar in Linux.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Having this all in one kernel can help some stages of development,
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bypassing some hardware (and driver) issues.  UML could help too.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
38d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
409454a57ab5922e5cd25321cae9d1a8cbeb3e2e85David Brownell#include <linux/usb/gadget.h>
4127729aadd31dafddaaf64c24f8ef6d0ff750f3aaEric Lescouet#include <linux/usb/hcd.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC	"USB Host+Gadget Emulator"
51391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION	"02 May 2005"
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern#define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
54caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_name [] = "dummy_hcd";
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_desc [] = "USB Host+Gadget Emulator";
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	gadget_name [] = "dummy_udc";
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell");
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL");
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstruct dummy_hcd_module_parameters {
651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	bool is_super_speed;
667eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	bool is_high_speed;
671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct dummy_hcd_module_parameters mod_data = {
707eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_super_speed = false,
717eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_high_speed = true,
721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanmodule_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana BrokhmanMODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
757eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhmanmodule_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
767eca4c5a8b73f22ad16ad6e76b901351732355daTatyana BrokhmanMODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep {
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			last_io;	/* jiffies timestamp */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		*gadget;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usb_endpoint_descriptor *desc;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep			ep;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			halted : 1;
87851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	unsigned			wedged : 1;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			already_seen : 1;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			setup_stage : 1;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request {
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;		/* ep's requests */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_request		req;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_ep, struct dummy_ep, ep);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(struct usb_request *_req)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_req, struct dummy_request, req);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints,
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types:
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Configurable:  direction (in/out), type (bulk, iso, etc), and endpoint
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     number can be changed.  Names like "ep-a" are used for this type.
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Fixed Function:  in other cases.  some characteristics may be mutable;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     that'd be hardware-specific.  Names like "ep12out-bulk" are used.
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on.
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0";
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep0name,				/* everyone has ep0 */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* act like a net2280: high speed, six configurable endpoints */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like pxa250: fifteen fixed function endpoints */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ep15in-int",
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like sa1100: two fixed function endpoints */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1out-bulk", "ep2in-bulk",
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
14152950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS	ARRAY_SIZE(ep_name)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
144d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE		64
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp {
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb		*urb;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head	urbp_list;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
153391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state {
154391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RESET,
155391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_SUSPENDED,
156391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RUNNING
157391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern};
158391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
159cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstruct dummy_hcd {
160cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy			*dum;
161cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	enum dummy_rh_state		rh_state;
162cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct timer_list		timer;
163cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				port_status;
164cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				old_status;
165cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned long			re_timeout;
166cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
167cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_device		*udev;
168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct list_head		urbp_list;
169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			active:1;
171cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			old_active:1;
172cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			resuming:1;
173cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman};
174cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy {
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t			lock;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE/GADGET side support
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep			ep [DUMMY_ENDPOINTS];
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				address;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		gadget;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget_driver	*driver;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request		fifo_req;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8				fifo_buf [FIFO_SIZE];
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16				devstatus;
188391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned			udc_suspended:1;
189f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			pullup:1;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER/HOST side support
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
194cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd		*hs_hcd;
1951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy_hcd		*ss_hcd;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
200cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return (struct dummy_hcd *) (hcd->hcd_priv);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of((void *) dum, struct usb_hcd, hcd_priv);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
208cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct device *dummy_dev(struct dummy_hcd *dum)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
210cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return dummy_hcd_to_hcd(dum)->self.controller;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
213d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum)
214d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
215d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return dum->gadget.dev.parent;
216d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
217d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (ep->gadget, struct dummy, gadget);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
225cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = container_of(gadget, struct dummy, gadget);
2261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER)
2271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->ss_hcd;
2281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	else
2291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->hs_hcd;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (dev, struct dummy, gadget.dev);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
237cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic struct dummy			the_controller;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */
242f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
243f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */
244f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep)
245f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
246f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	while (!list_empty (&ep->queue)) {
247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		struct dummy_request	*req;
248f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req = list_entry (ep->queue.next, struct dummy_request, queue);
250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		list_del_init (&req->queue);
251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.status = -ESHUTDOWN;
252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_unlock (&dum->lock);
254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.complete (&ep->ep, &req->req);
255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_lock (&dum->lock);
256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum)
262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy_ep	*ep;
264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* prevent any more requests */
266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->address = 0;
267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* The timer is left running so that outstanding URBs can fail */
269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* nuke any pending requests first, so driver i/o is quiesced */
271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		nuke (dum, ep);
273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
274f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* driver now does any non-usb quiescing necessary */
275f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
2771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/**
2781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * set_link_state_by_speed() - Sets the current state of the link according to
2791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *	the hcd speed
2801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
2811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *
2821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * This function updates the port_status according to the link state and the
2831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * speed of the hcd.
2841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */
2851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
2861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy *dum = dum_hcd->dum;
2881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) {
2901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) {
2911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
2921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
2931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
2941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
2951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE);
2961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
2971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
2981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
2991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* device is connected and not suspended */
3021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
3031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						 USB_PORT_STAT_SPEED_5GBPS) ;
3041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status &
3091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_ENABLE) == 1 &&
3101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(dum_hcd->port_status &
3111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 USB_SS_PORT_LS_U0) == 1 &&
3121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
3161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) {
3171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
3181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
3191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
3201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
3211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE |
3221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_LOW_SPEED |
3231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_HIGH_SPEED |
3241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_SUSPEND);
3251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
3311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
3361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
3371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else if ((dum_hcd->port_status &
3381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				  USB_PORT_STAT_SUSPEND) == 0 &&
3391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
3431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
3441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
345f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
346cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void set_link_state(struct dummy_hcd *dum_hcd)
347f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
348cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = dum_hcd->dum;
349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
350cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->active = 0;
3511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->pullup)
3521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
3531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed != USB_SPEED_SUPER) ||
3541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
3551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed == USB_SPEED_SUPER))
3561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			return;
3571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
3581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	set_link_state_by_speed(dum_hcd);
359f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
360cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
361cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	     dum_hcd->active)
362cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->resuming = 0;
363f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* if !connected or reset */
365cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
366cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
3671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
3681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * We're connected and not reset (reset occurred now),
3691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * and driver attached - disconnect!
3701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
371cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
3721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
3731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    dum->driver) {
3741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			stop_activity(dum);
3751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->disconnect(&dum->gadget);
3771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
378f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
379cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->active != dum_hcd->old_active) {
380cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->old_active && dum->driver->suspend) {
3811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->suspend(&dum->gadget);
3831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
3841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
3851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->resume(&dum->gadget);
3871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
388f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
389f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
390f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
391cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_status = dum_hcd->port_status;
392cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_active = dum_hcd->active;
393f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
394f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
395f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/
396f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state.  All the work is done when the host
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation.  Real device controller
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc.
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(dum->port_status & USB_PORT_STAT_ENABLE)
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
411cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		max;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !desc || ep->desc || _ep->name == ep0name
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| desc->bDescriptorType != USB_DT_ENDPOINT)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
421cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver)
422cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		return -ESHUTDOWN;
423719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior
424719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
425cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!is_enabled(dum_hcd))
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
427cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
428cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	/*
429cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
430cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * maximum packet size.
4311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	 * For SS devices the wMaxPacketSize is limited by 1024.
432cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 */
43329cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto	max = usb_endpoint_maxp(desc) & 0x7ff;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* drivers must not request bad settings, since lower levels
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (hardware or its drivers) may not check.  some endpoints
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't do iso, many have maxpacket limitations, etc.
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since this "hardware" driver is here to help debugging, we
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have some extra sanity checks.  (there could be more though,
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially for "ep9out" style fixed function ones.)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = -EINVAL;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (desc->bmAttributes & 0x03) {
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_BULK:
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int")) {
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (max == 1024)
4531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
4541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto done;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max == 512)
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4589063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4599063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		case USB_SPEED_FULL:
4609063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			if (max == 8 || max == 16 || max == 32 || max == 64)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we'll fake any legal size */
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4639063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			/* save a return statement */
4649063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		default:
4659063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_INT:
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 64)
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 8)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_ISOC:
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-bulk")
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int"))
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1023)
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* few chips support control except on ep0 */
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_ep->maxpacket = max;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = desc;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
515d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_ep->name,
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		desc->bEndpointAddress & 0x0f,
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *val;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (desc->bmAttributes & 0x03) {
5217c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_BULK:
5227c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "bulk";
5237c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5247c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_ISOC:
5257c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "iso";
5267c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5277c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_INT:
5287c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "intr";
5297c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5307c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
5317c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "ctrl";
5327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; val; }),
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		max);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* at this point real hardware should be NAKing transfers
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to that endpoint, until a buffer is queued to it.
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
539851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	ep->halted = ep->wedged = 0;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep)
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !ep->desc || _ep->name == ep0name)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = NULL;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nuke (dum, ep);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
563d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request *
56855016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5777039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn	req = kzalloc(sizeof(*req), mem_flags);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!req)
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&req->queue);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &req->req;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON (!list_empty (&req->queue));
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (req);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req)
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6055db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req,
60655016f10e31bb15b85d8c500f979dfdceb37d548Al Viro		gfp_t mem_flags)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
611cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_req || !list_empty (&req->queue) || !_req->complete)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
623719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
624cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver || !is_enabled(dum_hcd))
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
628d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&dum->fifo_req.queue) &&
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&ep->queue) &&
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy (dum->fifo_buf, _req->buf, _req->length);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
648c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
654c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell	}  else
655c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
680b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_save (flags);
681b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_lock (&dum->lock);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
690b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_unlock (&dum->lock);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
693d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		dev_dbg (udc_dev(dum),
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
698b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_restore (flags);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
703851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
715851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		ep->halted = ep->wedged = 0;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!list_empty (&ep->queue))
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
719851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	else {
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
721851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		if (wedged)
722851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern			ep->wedged = 1;
723851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	}
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
728851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int
729851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt(struct usb_ep *_ep, int value)
730851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
731851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, value, 0);
732851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
733851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
734851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int dummy_set_wedge(struct usb_ep *_ep)
735851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
736851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	if (!_ep || _ep->name == ep0name)
737851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		return -EINVAL;
738851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, 1, 1);
739851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
740851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
752851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	.set_wedge	= dummy_set_wedge,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget)
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday (&tv);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget)
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
768cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
770cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = gadget_to_dummy_hcd(_gadget);
771cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
7725742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
774cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
775391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
776cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
777cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
778391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
779391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
780391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
783cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->resuming = 1;
784cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
785cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
793cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (gadget_to_dummy_hcd(_gadget))->dum;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewiorstatic void dummy_udc_udpate_ep0(struct dummy *dum)
802b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior{
803c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	if (dum->gadget.speed == USB_SPEED_SUPER)
804b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 9;
805c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	else
806b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 64;
807b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior}
808b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
809f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value)
810f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
811d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd;
812f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
813f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
814f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
815b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	dum = gadget_dev_to_dummy(&_gadget->dev);
816b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
817b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	if (value && dum->driver) {
818b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		if (mod_data.is_super_speed)
8197177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz			dum->gadget.speed = dum->driver->max_speed;
820b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else if (mod_data.is_high_speed)
821b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
8227177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz					dum->driver->max_speed);
823b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else
824b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = USB_SPEED_FULL;
825b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dummy_udc_udpate_ep0(dum);
826b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
8277177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz		if (dum->gadget.speed < dum->driver->max_speed)
828b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dev_dbg(udc_dev(dum), "This device can perform faster"
8297177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				" if you connect it to a %s port...\n",
8307177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				usb_speed_string(dum->driver->max_speed));
831b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	}
832d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(_gadget);
833d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior
834f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
835f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
836d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
837f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
838b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
839d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
840f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
841f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
842f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
843aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
844aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
845aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
846aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
8470f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
852f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
853aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_start	= dummy_udc_start,
854aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_stop	= dummy_udc_stop,
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
86110523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf)
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = gadget_dev_to_dummy (dev);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
869cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
887aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
888aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
890aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
891aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8937177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz	if (driver->max_speed == USB_SPEED_UNKNOWN)
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9005742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
904d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
909aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
910aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
912aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
913aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
915d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
9192542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior
9202542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior	dummy_pullup(&dum->gadget, 0);
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
926d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
927d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
928d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
929d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev)
930d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
931cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return;
932d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
933d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9340fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewiorstatic void init_dummy_udc_hw(struct dummy *dum)
9350fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior{
9360fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	int i;
9370fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9380fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->gadget.ep_list);
9390fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
9400fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		struct dummy_ep	*ep = &dum->ep[i];
9410fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9420fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		if (!ep_name[i])
9430fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior			break;
9440fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.name = ep_name[i];
9450fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.ops = &dummy_ep_ops;
9460fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
9470fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->halted = ep->wedged = ep->already_seen =
9480fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior				ep->setup_stage = 0;
9490fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.maxpacket = ~0;
950c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior		ep->ep.max_streams = 16;
9510fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->last_io = jiffies;
9520fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->gadget = &dum->gadget;
9530fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->desc = NULL;
9540fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		INIT_LIST_HEAD(&ep->queue);
9550fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	}
9560fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9570fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	dum->gadget.ep0 = &dum->ep[0].ep;
9580fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	list_del_init(&dum->ep[0].ep.ep_list);
9590fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->fifo_req.queue);
960f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior
961f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#ifdef CONFIG_USB_OTG
962f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior	dum->gadget.is_otg = 1;
963f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#endif
9640fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior}
9650fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9668364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_probe (struct platform_device *pdev)
967d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
968cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy	*dum = &the_controller;
969d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
970d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
971d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
972d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
973d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz	dum->gadget.max_speed = USB_SPEED_SUPER;
974d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9750031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers	dev_set_name(&dum->gadget.dev, "gadget");
9768364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dum->gadget.dev.parent = &pdev->dev;
977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
978d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	rc = device_register (&dum->gadget.dev);
97975d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	if (rc < 0) {
98075d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar		put_device(&dum->gadget.dev);
981d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
98275d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	}
983d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9840fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	init_dummy_udc_hw(dum);
9850fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9860f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
9870f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	if (rc < 0)
9880f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_udc;
9890f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
990efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
991efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if (rc < 0)
9920f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_dev;
9930f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	platform_set_drvdata(pdev, dum);
9940f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	return rc;
9950f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
9960f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_dev:
9970f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
9980f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_udc:
9990f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	device_unregister(&dum->gadget.dev);
1000d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
1001d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1002d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10038364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_remove (struct platform_device *pdev)
1004d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
10058364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	struct dummy	*dum = platform_get_drvdata (pdev);
1006d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10070f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10088364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	platform_set_drvdata (pdev, NULL);
1009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_remove_file (&dum->gadget.dev, &dev_attr_function);
1010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_unregister (&dum->gadget.dev);
1011d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
1012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1013d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1014fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd,
1015fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior		int suspend)
1016391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1017fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_lock_irq(&dum->lock);
1018fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dum->udc_suspended = suspend;
1019d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
1020fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_unlock_irq(&dum->lock);
1021fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior}
1022fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior
1023fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state)
1024fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior{
1025fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1026fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1027391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1028fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1029fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 1);
1030d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1031391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1032391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1033391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1034fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_resume(struct platform_device *pdev)
1035391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1036fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1037fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1038391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1039fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1040fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 0);
1041d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1042391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1043391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1044391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
10453ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = {
1046d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
1047d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
1048391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
1049391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
10503ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
10513ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) gadget_name,
10523ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
10533ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
1054d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
1055d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue (
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
107355016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t				mem_flags
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1075cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
1078e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urb->transfer_buffer && urb->transfer_buffer_length)
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp = kmalloc (sizeof *urbp, mem_flags);
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1088cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1089cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1090e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_link_urb_to_ep(hcd, urb);
1091e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	if (rc) {
1092e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		kfree(urbp);
1093e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		goto done;
1094e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	}
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1096cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1097cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = urb->dev;
1098cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_get_dev(dum_hcd->udev);
1099cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (unlikely(dum_hcd->udev != urb->dev))
1100cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1102cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
1108cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!timer_pending(&dum_hcd->timer))
1109cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + 1);
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done:
1112cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1113e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1116e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1118cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
1119391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1120e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
1121391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1122391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1123391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1124cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1125cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1126e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1127e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1128cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
1129cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			!list_empty(&dum_hcd->urbp_list))
1130cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies);
1131e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1132cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1133e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11384d2f110c51eec853c50f68cf068888a77551c8d3Alan Sterntransfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
11394d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int *status)
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min (host_len, dev_len);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_host = usb_pipein (urb->pipe);
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely (len == 0))
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char		*ubuf, *rbuf;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = min (len, (unsigned) limit);
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* else transfer packet(s) */
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ubuf = urb->transfer_buffer + urb->actual_length;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rbuf = req->req.buf + req->req.actual;
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (to_host)
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (ubuf, rbuf, len);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (rbuf, ubuf, len);
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit -= len;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->actual_length += len;
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.actual += len;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
1202b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern		 * need to emulate such data-in-flight.
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12074d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
12114d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = -EOVERFLOW;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
12134d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = 0;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
12154d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
12294d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern						& URB_ZERO_PACKET))
12304d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock (&dum->lock);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.complete (&ep->ep, &req->req);
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock (&dum->lock);
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
12464d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (*status != -EINPROGRESS)
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
126429cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto		tmp = usb_endpoint_maxp(ep->desc);
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER) {
12701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		switch (ep->desc->bmAttributes & 0x03) {
12711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_ISOC:
12721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.8.2 USB3.0 Spec */
12731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 16 * 1024 * 8;
12741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
12751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_INT:
12761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.7.2 USB3.0 Spec */
12771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 1024 * 8;
12781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
12791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_BULK:
12801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		default:
12811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
12821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
12831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1287cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman#define is_active(dum_hcd)	((dum_hcd->port_status & \
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
12971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->ss_hcd : dum->hs_hcd)))
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return &dum->ep [0];
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
13228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman/**
13238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * handle_control_request() - handles all control transfers
13248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @dum: pointer to dummy (the_controller)
13258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @urb: the urb request to handle
13268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @setup: pointer to the setup data for a USB device control
13278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	 request
13288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @status: pointer to request handling status
13298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *
13308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * Return 0 - if the request was handled
13318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  1 - if the request wasn't handles
13328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  error code on error
13338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */
1334cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
13358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  struct usb_ctrlrequest *setup,
13368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  int *status)
13378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman{
13388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	struct dummy_ep		*ep2;
1339cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
13408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	int			ret_val = 1;
13418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_index;
13428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_value;
13438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
13448be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_index = le16_to_cpu(setup->wIndex);
13458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_value = le16_to_cpu(setup->wValue);
13468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	switch (setup->bRequest) {
13478be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_ADDRESS:
13488be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType != Dev_Request)
13498be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			break;
13508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dum->address = w_value;
13518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		*status = 0;
13528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dev_dbg(udc_dev(dum), "set_address = %d\n",
13538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value);
13548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		ret_val = 0;
13558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
13568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_FEATURE:
13578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
13588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
13598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
13608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
13618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_B_HNP_ENABLE:
13638be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.b_hnp_enable = 1;
13648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_HNP_SUPPORT:
13668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_hnp_support = 1;
13678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_ALT_HNP_SUPPORT:
13698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_alt_hnp_support = 1;
13708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
13721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
13731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
13741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
13751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
13761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
13771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
13781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
13791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
13801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
13811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
13821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
13831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
13841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
13851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
13861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
13871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
13881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
13891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
13901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
13911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
13928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
13938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
13948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
13958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
13968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus |= (1 << w_value);
13978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
13988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
13998be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
14008be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
14018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
14028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2 || ep2->ep.name == ep0name) {
14038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2->halted = 1;
14078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
14098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
14108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_CLEAR_FEATURE:
14128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
14138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
14158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
14168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value = USB_DEVICE_REMOTE_WAKEUP;
14178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
14191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
14221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
14261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
14291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
14331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
14361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
14408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
14448be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus &= ~(1 << w_value);
14458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
14468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14478be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
14488be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
14498be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
14508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2) {
14518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2->wedged)
14558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ep2->halted = 0;
14568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
14588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
14598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_GET_STATUS:
14618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_InRequest
14628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Intf_InRequest
14638be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Ep_InRequest) {
14648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			char *buf;
14658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/*
14668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * device: remote wakeup, selfpowered
14678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * interface: nothing
14688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * endpoint: halt
14698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 */
14708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			buf = (char *)urb->transfer_buffer;
14718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 0) {
14728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				if (setup->bRequestType == Ep_InRequest) {
14738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					ep2 = find_endpoint(dum, w_index);
14748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					if (!ep2) {
14758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						ret_val = -EOPNOTSUPP;
14768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						break;
14778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					}
14788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = ep2->halted;
14798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else if (setup->bRequestType ==
14808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					   Dev_InRequest) {
14818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = (u8)dum->devstatus;
14828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else
14838be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = 0;
14848be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14858be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 1)
14868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				buf[1] = 0;
14878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			urb->actual_length = min_t(u32, 2,
14888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				urb->transfer_buffer_length);
14898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
14918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
14928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	}
14948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	return ret_val;
14958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman}
14968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1500cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void dummy_timer(unsigned long _dum_hcd)
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1502cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
1503cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case USB_SPEED_SUPER:
15211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* Bus speed is 500000 bytes/ms, so use a little less */
15221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		total = 490000;
15231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1525cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1534cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1535cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd),
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&dum->lock, flags);
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->ep [i].already_seen = 0;
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
1548cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
15544d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int			status = -EINPROGRESS;
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
1557eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern		if (urb->unlinked)
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1559cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
1560391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = usb_pipetype (urb->pipe);
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (usb_pipein (urb->pipe))
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
1577cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
15804d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPROTO;
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && urb->error_count) {
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
1593cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
15954d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPIPE;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && ep->setup_stage) {
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_for_each_entry (req, &ep->queue, queue) {
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				list_del_init (&req->queue);
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
1610d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "stale req = %p\n",
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.complete (&ep->ep, &req->req);
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1628cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			value = handle_control_request(dum_hcd, urb, &setup,
16298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						       &status);
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = dum->driver->setup (&dum->gadget,
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
1650d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern					dev_dbg (udc_dev(dum),
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
16534d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				status = -EPIPE;
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (usb_pipetype (urb->pipe)) {
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
16704d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -ENOSYS;
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// case PIPE_BULK:  case PIPE_CONTROL:
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		treat_control_like_bulk:
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
16844d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			total = transfer(dum, urb, ep, limit, &status);
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
16894d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (status == -EINPROGRESS)
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del (&urbp->urbp_list);
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (urbp);
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1698cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
1700cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1706cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (list_empty(&dum_hcd->urbp_list)) {
1707cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_dev(dum_hcd->udev);
1708cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = NULL;
1709cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
1710391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1711cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1720c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1721c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1722c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1723c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1724c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf)
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1728cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1730391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1732cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1734cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1735541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1736391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1737f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1738cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
1739cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1740cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
1741cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1742f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1743f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1744cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
1746cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
1747cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status);
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1749cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
1750391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			usb_hcd_resume_root_hub (hcd);
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1752391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
1753cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
17581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanss_hub_descriptor(struct usb_hub_descriptor *desc)
17591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
17601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	memset(desc, 0, sizeof *desc);
17611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescriptorType = 0x2a;
17621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescLength = 12;
17631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->wHubCharacteristics = cpu_to_le16(0x0001);
17641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bNbrPorts = 1;
17651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
17661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.DeviceRemovable = 0xffff;
17671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
17681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
17691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic inline void
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc)
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (desc, 0, sizeof *desc);
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1775fd05e720099e8eeddb378305d1a41c1445344b91Al Viro	desc->wHubCharacteristics = cpu_to_le16(0x0001);
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
1777dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[0] = 0xff;
1778dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[1] = 0xff;
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control (
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1789cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1793541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1794391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1795391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1796cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1797cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1798cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
18051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
18061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
18071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
18081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
18091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
18101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1811cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
1813cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->resuming = 1;
1814cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->re_timeout = jiffies +
1815f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
18191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
18201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
18211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
18221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
18231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
18241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status &
18251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SS_PORT_STAT_POWER)
18261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
18271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
1828f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1830cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~(1 << wValue);
1831cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
18351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3 &&
18361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(wLength < USB_DT_SS_HUB_SIZE ||
18371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 wValue != (USB_DT_SS_HUB << 8))) {
18381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
18391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"Wrong hub descriptor type for "
18401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"USB 3.0 roothub.\n");
18411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
18421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
18431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3)
18441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
18451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		else
18461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			hub_descriptor((struct usb_hub_descriptor *) buf);
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
1849551509d267905705f6d723e51ec706916f06b859Harvey Harrison		*(__le32 *) buf = cpu_to_le32 (0);
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1858cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->resuming &&
1859cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
1860cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1861cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1863cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
1864cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
1865cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
1866cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
1867cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->dum->pullup) {
1868cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
18691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
18701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (hcd->speed < HCD_USB3) {
18711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					switch (dum_hcd->dum->gadget.speed) {
18721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_HIGH:
18731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
18741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						      USB_PORT_STAT_HIGH_SPEED;
18751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
18761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_LOW:
18771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.ep0->
18781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							maxpacket = 8;
18791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
18801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_PORT_STAT_LOW_SPEED;
18811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
18821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					default:
18831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.speed =
18841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SPEED_FULL;
18851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
18861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					}
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1890cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1891cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
1892cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
18991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_LINK_STATE:
19001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_LINK_STATE req not "
19031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
19071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * Since this is dummy we don't have an actual link so
19081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * there is nothing to do for the SET_LINK_STATE cmd
19091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
19101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
19111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U1_TIMEOUT:
19121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U2_TIMEOUT:
19131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* TODO: add suspend/resume support! */
19141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
19171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
19221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB2.0 hub */
19231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
19261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
19271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1929cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->active) {
1930cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
1931f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1932f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
1933f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
1934f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
1935cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				set_link_state(dum_hcd);
1936f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
1937cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman						& dum_hcd->dum->devstatus) != 0)
1938cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
19395742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1942f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
19431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3)
19441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
19451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else
19461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_POWER;
1947cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
1948f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
19491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_BH_PORT_RESET:
19501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB3.0 hub */
19511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_BH_PORT_RESET req not "
19541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* FALLS THROUGH */
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
1959f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
19601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status = 0;
19621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status =
19631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_SS_PORT_STAT_POWER |
19641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_CONNECTION |
19651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_RESET);
19661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
19671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
1968f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
1969f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
1970cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			/*
1971cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * We want to reset device status. All but the
1972cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * Self powered feature
1973cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 */
1974cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->dum->devstatus &=
1975cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				(1 << USB_DEVICE_SELF_POWERED);
19761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
19771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * FIXME USB3.0: what is the correct reset signaling
19781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * interval? Is it still 50msec as for HS?
19791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
1980cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
1981f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
19831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
19851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_SS_PORT_STAT_POWER) != 0) {
19861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
19871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
19881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
19891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
19901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
19911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_PORT_STAT_POWER) != 0) {
19921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
19931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
19941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
19951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
19961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
19971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case GetPortErrorCount:
19981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
19991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "GetPortErrorCount req not "
20011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "supported for USB 2.0 roothub\n");
20021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* We'll always return 0 since this is a dummy hub */
20051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		*(__le32 *) buf = cpu_to_le32(0);
20061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
20071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case SetHubDepth:
20081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
20091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "SetHubDepth req not supported for "
20111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "USB 2.0 roothub\n");
20121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2016cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd),
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
20191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanerror:
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2023cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2024685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
2025cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
2026685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern		usb_hcd_poll_rh_status (hcd);
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20300c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd)
2031391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2032cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2033391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2034441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
20353cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2036cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2037cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
2038cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	set_link_state(dum_hcd);
20393cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd->state = HC_STATE_SUSPENDED;
2040cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
2041391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2042391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2043391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
20440c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd)
2045391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2046cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
20473cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int rc = 0;
20483cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2049441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
2050391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2051cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2052541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd)) {
2053cfa59dab27d1b282886e7772a8f9548236883892Alan Stern		rc = -ESHUTDOWN;
20543cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else {
2055cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->rh_state = DUMMY_RH_RUNNING;
2056cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
2057cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (!list_empty(&dum_hcd->urbp_list))
2058cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			mod_timer(&dum_hcd->timer, jiffies);
20593cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		hcd->state = HC_STATE_RUNNING;
20603cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	}
2061cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
20623cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2063391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb)
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ep = usb_pipeendpoint (urb->pipe);
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf (buf, size,
20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (urb->dev->speed) {
20777c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_LOW:
20787c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "ls";
20797c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
20807c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_FULL:
20817c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "fs";
20827c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
20837c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_HIGH:
20847c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "hs";
20857c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
20861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 case USB_SPEED_SUPER:
20871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			s = "ss";
20881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
20897c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
20907c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "?";
20917c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (usb_pipetype (urb->pipe)) { \
20967c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_CONTROL: \
20977c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = ""; \
20987c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
20997c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_BULK: \
21007c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-bulk"; \
21017c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21027c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_INTERRUPT: \
21037c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-int"; \
21047c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21057c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default: \
21067c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-iso"; \
21077c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}; s;}),
21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
211310523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf)
21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd = dev_get_drvdata (dev);
2116cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2122cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2129cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic int dummy_start_ss(struct dummy_hcd *dum_hcd)
21361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
21371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	init_timer(&dum_hcd->timer);
21381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.function = dummy_timer;
21391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
21401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
21411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
21421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
21431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
21441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
21451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#ifdef CONFIG_USB_OTG
21461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
21471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#endif
21481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
21491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
21501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
21511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
21521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
21531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2154cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_start(struct usb_hcd *hcd)
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2156cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
21631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!usb_hcd_is_primary_hcd(hcd))
21641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dummy_start_ss(dum_hcd);
21651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2166cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_init(&dum_hcd->dum->lock);
2167cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	init_timer(&dum_hcd->timer);
2168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.function = dummy_timer;
2169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
2170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2172cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2174caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern	hcd->power_budget = POWER_BUDGET;
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
2176685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21785742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
21795742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
21805742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
21815742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
2183cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd)
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2190cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(hcd))->dum;
2191cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
2192cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_gadget_unregister_driver(dum->driver);
2193cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd)
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_g_get_frame (NULL);
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_setup(struct usb_hcd *hcd)
2204cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman{
2205cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (usb_hcd_is_primary_hcd(hcd)) {
2206cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
2207cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd->dum = &the_controller;
22081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
22091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * Mark the first roothub as being USB 2.0.
22101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * The USB 3.0 roothub will be registered later by
22111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * dummy_hcd_probe()
22121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
2213cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->speed = HCD_USB2;
2214cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_HIGH;
22151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
22161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
22171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd->dum = &the_controller;
22181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->speed = HCD_USB3;
22191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_SUPER;
2220cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	}
2221cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return 0;
2222cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman}
2223cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
22241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Change a group of bulk endpoints to support multiple stream IDs */
22251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
22261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
22271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	unsigned int num_streams, gfp_t mem_flags)
22281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (hcd->speed != HCD_USB3)
22301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
22311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			"%s() - ERROR! Not supported for USB2.0 roothub\n",
22321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			__func__);
22331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
22341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
22351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Reverts a group of bulk endpoints back to not using stream IDs. */
22371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
22381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
22391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	gfp_t mem_flags)
22401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (hcd->speed != HCD_USB3)
22421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
22431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			"%s() - ERROR! Not supported for USB2.0 roothub\n",
22441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			__func__);
22451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
22461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
22471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct hc_driver dummy_hcd = {
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
2251cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.hcd_priv_size =	sizeof(struct dummy_hcd),
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.flags =		HCD_USB3 | HCD_SHARED,
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2255cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.reset =		dummy_setup,
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_enqueue = 		dummy_urb_enqueue,
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_dequeue = 		dummy_urb_dequeue,
22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame_number = 	dummy_h_get_frame,
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_status_data = 	dummy_hub_status,
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_control = 		dummy_hub_control,
22660c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_suspend =		dummy_bus_suspend,
22670c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_resume =		dummy_bus_resume,
22681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.alloc_streams =	dummy_alloc_streams,
22701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.free_streams =		dummy_free_streams,
22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22738364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev)
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2275cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_hcd		*hs_hcd;
22761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_hcd		*ss_hcd;
22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22798364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!mod_data.is_super_speed)
22821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dummy_hcd.flags = HCD_USB2;
2283cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
2284cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!hs_hcd)
22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2286cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd->has_tt = 1;
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2288cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	retval = usb_add_hcd(hs_hcd, 0, 0);
22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
2290cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_hcd(hs_hcd);
22911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return retval;
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
22931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (mod_data.is_super_speed) {
22951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
22961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_name(&pdev->dev), hs_hcd);
22971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (!ss_hcd) {
22981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			retval = -ENOMEM;
22991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto dealloc_usb2_hcd;
23001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
23011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		retval = usb_add_hcd(ss_hcd, 0, 0);
23031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (retval)
23041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto put_usb3_hcd;
23051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
23061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
23071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanput_usb3_hcd:
23091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(ss_hcd);
23101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmandealloc_usb2_hcd:
23111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(hs_hcd);
23121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2316cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_hcd_remove(struct platform_device *pdev)
23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2318cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum;
2319cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
2320cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
23211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->ss_hcd) {
23231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
23241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
23251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
23261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2327cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2328cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
23291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2330cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	the_controller.hs_hcd = NULL;
23311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.ss_hcd = NULL;
23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2333d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23368364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
2337391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2338391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2339cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
23403cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int			rc = 0;
2341391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2342441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2343391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23443cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
2345cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
2346cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
23473cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
23483cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		rc = -EBUSY;
23493cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else
23503cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
23513cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2352391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2353391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23548364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_resume (struct platform_device *pdev)
2355391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2356391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2357391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2358441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2359391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23603cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
23613cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
2362391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (hcd);
2363391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2364391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2365391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23663ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = {
2367d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
2368d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
2369391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
2370391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
23713ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
23723ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) driver_name,
23733ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
23743ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2375d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2377d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2379a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_udc_pdev;
2380a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_hcd_pdev;
23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void)
23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2384a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	int	retval = -ENOMEM;
23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_disabled ())
23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2388d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
23897eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	if (!mod_data.is_high_speed && mod_data.is_super_speed)
23907eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		return -EINVAL;
23917eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman
2392a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_hcd_pdev = platform_device_alloc(driver_name, -1);
2393a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_hcd_pdev)
23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
2395a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_udc_pdev = platform_device_alloc(gadget_name, -1);
2396a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_udc_pdev)
2397a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_alloc_udc;
2398d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2399a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_hcd_driver);
2400a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (retval < 0)
2401a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_register_hcd_driver;
2402a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_udc_driver);
2403d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2404d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2405d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2406a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_hcd_pdev);
2407d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2408a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_hcd;
24091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!the_controller.hs_hcd ||
24101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	    (!the_controller.ss_hcd && mod_data.is_super_speed)) {
2411865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2412865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The hcd was added successfully but its probe function failed
2413865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2414865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2415865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2416865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_add_udc;
2417865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2418a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_udc_pdev);
2419d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2420a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_udc;
2421865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	if (!platform_get_drvdata(the_udc_pdev)) {
2422865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2423865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The udc was added successfully but its probe function failed
2424865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2425865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2426865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2427865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_probe_udc;
2428865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2429d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2430d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2431865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewiorerr_probe_udc:
2432865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	platform_device_del(the_udc_pdev);
2433a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_udc:
2434a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_del(the_hcd_pdev);
2435a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_hcd:
2436a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2437d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
2438a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
2439a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_register_hcd_driver:
2440a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_udc_pdev);
2441a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_alloc_udc:
2442a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_hcd_pdev);
24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init);
24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void)
24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2449a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_udc_pdev);
2450a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_hcd_pdev);
2451a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2452a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup);
2455