dummy_hcd.c revision 59f08e6d2015a16fb4856f910ef0660d13a0c767
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>
4214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior#include <linux/scatterlist.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC	"USB Host+Gadget Emulator"
52391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION	"02 May 2005"
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern#define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
55caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_name [] = "dummy_hcd";
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_desc [] = "USB Host+Gadget Emulator";
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	gadget_name [] = "dummy_udc";
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell");
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL");
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstruct dummy_hcd_module_parameters {
661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	bool is_super_speed;
677eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	bool is_high_speed;
681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct dummy_hcd_module_parameters mod_data = {
717eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_super_speed = false,
727eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_high_speed = true,
731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanmodule_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana BrokhmanMODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
767eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhmanmodule_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
777eca4c5a8b73f22ad16ad6e76b901351732355daTatyana BrokhmanMODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep {
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			last_io;	/* jiffies timestamp */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		*gadget;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usb_endpoint_descriptor *desc;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep			ep;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			halted : 1;
88851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	unsigned			wedged : 1;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			already_seen : 1;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			setup_stage : 1;
91a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned			stream_en:1;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request {
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;		/* ep's requests */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_request		req;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_ep, struct dummy_ep, ep);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(struct usb_request *_req)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_req, struct dummy_request, req);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints,
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types:
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Configurable:  direction (in/out), type (bulk, iso, etc), and endpoint
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     number can be changed.  Names like "ep-a" are used for this type.
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Fixed Function:  in other cases.  some characteristics may be mutable;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     that'd be hardware-specific.  Names like "ep12out-bulk" are used.
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on.
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0";
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = {
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep0name,				/* everyone has ep0 */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* act like a net2280: high speed, six configurable endpoints */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like pxa250: fifteen fixed function endpoints */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ep15in-int",
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like sa1100: two fixed function endpoints */
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1out-bulk", "ep2in-bulk",
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
14352950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS	ARRAY_SIZE(ep_name)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
146d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE		64
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp {
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb		*urb;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head	urbp_list;
15214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct sg_mapping_iter	miter;
15314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32			miter_started;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
157391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state {
158391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RESET,
159391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_SUSPENDED,
160391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RUNNING
161391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern};
162391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
163cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstruct dummy_hcd {
164cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy			*dum;
165cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	enum dummy_rh_state		rh_state;
166cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct timer_list		timer;
167cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				port_status;
168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				old_status;
169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned long			re_timeout;
170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
171cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_device		*udev;
172cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct list_head		urbp_list;
173a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	u32				stream_en_ep;
174a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	u8				num_stream[30 / 2];
175cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
176cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			active:1;
177cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			old_active:1;
178cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			resuming:1;
179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman};
180cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy {
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t			lock;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE/GADGET side support
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep			ep [DUMMY_ENDPOINTS];
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				address;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		gadget;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget_driver	*driver;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request		fifo_req;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8				fifo_buf [FIFO_SIZE];
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16				devstatus;
194391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned			udc_suspended:1;
195f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			pullup:1;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER/HOST side support
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
200cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd		*hs_hcd;
2011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy_hcd		*ss_hcd;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
204cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
206cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return (struct dummy_hcd *) (hcd->hcd_priv);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
209cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of((void *) dum, struct usb_hcd, hcd_priv);
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
214cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct device *dummy_dev(struct dummy_hcd *dum)
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
216cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return dummy_hcd_to_hcd(dum)->self.controller;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
219d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum)
220d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
221d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return dum->gadget.dev.parent;
222d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
223d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (ep->gadget, struct dummy, gadget);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
229cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
231cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = container_of(gadget, struct dummy, gadget);
2321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER)
2331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->ss_hcd;
2341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	else
2351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->hs_hcd;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (dev, struct dummy, gadget.dev);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
243cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic struct dummy			the_controller;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */
248f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */
250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep)
251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	while (!list_empty (&ep->queue)) {
253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		struct dummy_request	*req;
254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req = list_entry (ep->queue.next, struct dummy_request, queue);
256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		list_del_init (&req->queue);
257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.status = -ESHUTDOWN;
258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_unlock (&dum->lock);
260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.complete (&ep->ep, &req->req);
261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_lock (&dum->lock);
262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum)
268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy_ep	*ep;
270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* prevent any more requests */
272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->address = 0;
273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
274f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* The timer is left running so that outstanding URBs can fail */
275f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* nuke any pending requests first, so driver i/o is quiesced */
277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		nuke (dum, ep);
279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
280f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* driver now does any non-usb quiescing necessary */
281f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
282f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
2831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/**
2841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * set_link_state_by_speed() - Sets the current state of the link according to
2851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *	the hcd speed
2861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
2871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *
2881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * This function updates the port_status according to the link state and the
2891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * speed of the hcd.
2901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */
2911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
2921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy *dum = dum_hcd->dum;
2941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) {
2961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) {
2971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
2981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
2991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
3001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
3011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE);
3021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* device is connected and not suspended */
3081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
3091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						 USB_PORT_STAT_SPEED_5GBPS) ;
3101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status &
3151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_ENABLE) == 1 &&
3161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(dum_hcd->port_status &
3171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 USB_SS_PORT_LS_U0) == 1 &&
3181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
3221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) {
3231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
3241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
3251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
3261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
3271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE |
3281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_LOW_SPEED |
3291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_HIGH_SPEED |
3301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_SUSPEND);
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		} else {
3361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
3371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
3421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
3431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else if ((dum_hcd->port_status &
3441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				  USB_PORT_STAT_SUSPEND) == 0 &&
3451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
3491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
3501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
351f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
352cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void set_link_state(struct dummy_hcd *dum_hcd)
353f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
354cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = dum_hcd->dum;
355cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
356cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->active = 0;
3571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->pullup)
3581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
3591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed != USB_SPEED_SUPER) ||
3601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
3611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed == USB_SPEED_SUPER))
3621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			return;
3631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
3641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	set_link_state_by_speed(dum_hcd);
365f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
366cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
367cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	     dum_hcd->active)
368cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->resuming = 0;
369f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* if !connected or reset */
371cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
372cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
3731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
3741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * We're connected and not reset (reset occurred now),
3751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * and driver attached - disconnect!
3761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
377cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
3781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
3791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    dum->driver) {
3801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			stop_activity(dum);
3811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->disconnect(&dum->gadget);
3831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
384f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
385cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->active != dum_hcd->old_active) {
386cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->old_active && dum->driver->suspend) {
3871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->suspend(&dum->gadget);
3891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
3901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
3911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->resume(&dum->gadget);
3931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
394f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
395f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
396f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
397cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_status = dum_hcd->port_status;
398cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_active = dum_hcd->active;
399f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
400f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
401f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/
402f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state.  All the work is done when the host
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation.  Real device controller
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc.
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(dum->port_status & USB_PORT_STAT_ENABLE)
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
417cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		max;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !desc || ep->desc || _ep->name == ep0name
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| desc->bDescriptorType != USB_DT_ENDPOINT)
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
427cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver)
428cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		return -ESHUTDOWN;
429719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior
430719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
431cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!is_enabled(dum_hcd))
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
433cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
434cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	/*
435cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
436cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * maximum packet size.
4371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	 * For SS devices the wMaxPacketSize is limited by 1024.
438cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 */
43929cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto	max = usb_endpoint_maxp(desc) & 0x7ff;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* drivers must not request bad settings, since lower levels
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (hardware or its drivers) may not check.  some endpoints
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't do iso, many have maxpacket limitations, etc.
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since this "hardware" driver is here to help debugging, we
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have some extra sanity checks.  (there could be more though,
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially for "ep9out" style fixed function ones.)
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = -EINVAL;
45059f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior	switch (usb_endpoint_type(desc)) {
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_BULK:
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int")) {
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (max == 1024)
4591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
4601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto done;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max == 512)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4649063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4659063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		case USB_SPEED_FULL:
4669063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			if (max == 8 || max == 16 || max == 32 || max == 64)
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we'll fake any legal size */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4699063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			/* save a return statement */
4709063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		default:
4719063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_INT:
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 64)
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 8)
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_ISOC:
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-bulk")
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int"))
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
5001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1023)
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* few chips support control except on ep0 */
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_ep->maxpacket = max;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = desc;
520a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (usb_ss_max_streams(_ep->comp_desc)) {
521a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (!usb_endpoint_xfer_bulk(desc)) {
522a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			dev_err(udc_dev(dum), "Can't enable stream support on "
523a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior					"non-bulk ep %s\n", _ep->name);
524a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			return -EINVAL;
525a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
526a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		ep->stream_en = 1;
527a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
529a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	dev_dbg(udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d stream %s\n",
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_ep->name,
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		desc->bEndpointAddress & 0x0f,
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *val;
53459f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior		 switch (usb_endpoint_type(desc)) {
5357c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_BULK:
5367c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "bulk";
5377c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5387c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_ISOC:
5397c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "iso";
5407c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5417c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_INT:
5427c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "intr";
5437c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5447c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
5457c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "ctrl";
5467c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; val; }),
548a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max, ep->stream_en ? "enabled" : "disabled");
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* at this point real hardware should be NAKing transfers
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to that endpoint, until a buffer is queued to it.
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
553851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	ep->halted = ep->wedged = 0;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep)
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !ep->desc || _ep->name == ep0name)
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = NULL;
573a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	ep->stream_en = 0;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nuke (dum, ep);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
578d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request *
58355016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5927039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn	req = kzalloc(sizeof(*req), mem_flags);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!req)
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&req->queue);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &req->req;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON (!list_empty (&req->queue));
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (req);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6205db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req,
62155016f10e31bb15b85d8c500f979dfdceb37d548Al Viro		gfp_t mem_flags)
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
626cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_req || !list_empty (&req->queue) || !_req->complete)
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
638719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
639cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver || !is_enabled(dum_hcd))
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
643d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&dum->fifo_req.queue) &&
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&ep->queue) &&
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy (dum->fifo_buf, _req->buf, _req->length);
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
663c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
669c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell	}  else
670c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
695b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_save (flags);
696b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_lock (&dum->lock);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
705b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_unlock (&dum->lock);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
708d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		dev_dbg (udc_dev(dum),
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
713b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_restore (flags);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
718851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
730851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		ep->halted = ep->wedged = 0;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!list_empty (&ep->queue))
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
734851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	else {
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
736851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		if (wedged)
737851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern			ep->wedged = 1;
738851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	}
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
743851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int
744851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt(struct usb_ep *_ep, int value)
745851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
746851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, value, 0);
747851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
748851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
749851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int dummy_set_wedge(struct usb_ep *_ep)
750851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
751851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	if (!_ep || _ep->name == ep0name)
752851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		return -EINVAL;
753851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, 1, 1);
754851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
755851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
767851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	.set_wedge	= dummy_set_wedge,
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget)
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday (&tv);
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget)
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
783cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
785cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = gadget_to_dummy_hcd(_gadget);
786cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
7875742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
789cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
790391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
791cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
792cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
793391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
794391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
795391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
798cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->resuming = 1;
799cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
800cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
808cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (gadget_to_dummy_hcd(_gadget))->dum;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
816d262127c330b852ce4b210a0b1b06e69d4d87704Sebastian Andrzej Siewiorstatic void dummy_udc_update_ep0(struct dummy *dum)
817b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior{
818c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	if (dum->gadget.speed == USB_SPEED_SUPER)
819b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 9;
820c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	else
821b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 64;
822b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior}
823b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
824f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value)
825f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
826d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd;
827f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
828f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
829f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
830b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	dum = gadget_dev_to_dummy(&_gadget->dev);
831b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
832b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	if (value && dum->driver) {
833b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		if (mod_data.is_super_speed)
8347177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz			dum->gadget.speed = dum->driver->max_speed;
835b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else if (mod_data.is_high_speed)
836b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
8377177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz					dum->driver->max_speed);
838b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else
839b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = USB_SPEED_FULL;
840d262127c330b852ce4b210a0b1b06e69d4d87704Sebastian Andrzej Siewior		dummy_udc_update_ep0(dum);
841b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
8427177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz		if (dum->gadget.speed < dum->driver->max_speed)
843b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dev_dbg(udc_dev(dum), "This device can perform faster"
8447177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				" if you connect it to a %s port...\n",
8457177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				usb_speed_string(dum->driver->max_speed));
846b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	}
847d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(_gadget);
848d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior
849f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
850f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
851d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
852f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
853b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
854d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
855f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
856f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
857f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
858aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
859aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
860aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
861aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
8620f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
867f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
868aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_start	= dummy_udc_start,
869aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_stop	= dummy_udc_stop,
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
87610523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf)
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = gadget_dev_to_dummy (dev);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
884cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
902aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
903aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
905aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
906aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9087177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz	if (driver->max_speed == USB_SPEED_UNKNOWN)
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9155742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
919d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
924aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
925aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
927aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
928aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
930d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
9342542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior
9352542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior	dummy_pullup(&dum->gadget, 0);
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
942d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
943d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
944d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev)
945d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
946cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return;
947d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
948d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9490fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewiorstatic void init_dummy_udc_hw(struct dummy *dum)
9500fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior{
9510fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	int i;
9520fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9530fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->gadget.ep_list);
9540fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
9550fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		struct dummy_ep	*ep = &dum->ep[i];
9560fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9570fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		if (!ep_name[i])
9580fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior			break;
9590fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.name = ep_name[i];
9600fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.ops = &dummy_ep_ops;
9610fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
9620fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->halted = ep->wedged = ep->already_seen =
9630fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior				ep->setup_stage = 0;
9640fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.maxpacket = ~0;
965c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior		ep->ep.max_streams = 16;
9660fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->last_io = jiffies;
9670fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->gadget = &dum->gadget;
9680fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->desc = NULL;
9690fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		INIT_LIST_HEAD(&ep->queue);
9700fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	}
9710fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9720fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	dum->gadget.ep0 = &dum->ep[0].ep;
9730fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	list_del_init(&dum->ep[0].ep.ep_list);
9740fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->fifo_req.queue);
975f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior
976f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#ifdef CONFIG_USB_OTG
977f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior	dum->gadget.is_otg = 1;
978f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#endif
9790fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior}
9800fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9818364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_probe (struct platform_device *pdev)
982d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
983cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy	*dum = &the_controller;
984d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
985d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
986d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
987d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
988d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz	dum->gadget.max_speed = USB_SPEED_SUPER;
989d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9900031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers	dev_set_name(&dum->gadget.dev, "gadget");
9918364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dum->gadget.dev.parent = &pdev->dev;
992d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
993d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	rc = device_register (&dum->gadget.dev);
99475d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	if (rc < 0) {
99575d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar		put_device(&dum->gadget.dev);
996d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
99775d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	}
998d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9990fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	init_dummy_udc_hw(dum);
10000fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
10010f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
10020f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	if (rc < 0)
10030f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_udc;
10040f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
1005efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
1006efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if (rc < 0)
10070f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_dev;
10080f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	platform_set_drvdata(pdev, dum);
10090f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	return rc;
10100f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
10110f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_dev:
10120f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10130f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_udc:
10140f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	device_unregister(&dum->gadget.dev);
1015d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
1016d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1017d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10188364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_remove (struct platform_device *pdev)
1019d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
10208364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	struct dummy	*dum = platform_get_drvdata (pdev);
1021d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10220f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10238364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	platform_set_drvdata (pdev, NULL);
1024d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_remove_file (&dum->gadget.dev, &dev_attr_function);
1025d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_unregister (&dum->gadget.dev);
1026d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
1027d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1028d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1029fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd,
1030fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior		int suspend)
1031391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1032fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_lock_irq(&dum->lock);
1033fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dum->udc_suspended = suspend;
1034d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
1035fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_unlock_irq(&dum->lock);
1036fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior}
1037fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior
1038fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state)
1039fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior{
1040fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1041fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1042391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1043fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1044fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 1);
1045d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1046391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1047391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1048391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1049fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_resume(struct platform_device *pdev)
1050391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1051fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1052fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1053391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1054fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1055fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 0);
1056d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1057391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1058391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1059391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
10603ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = {
1061d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
1062d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
1063391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
1064391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
10653ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
10663ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) gadget_name,
10673ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
10683ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
1069d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
1070d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1073a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc)
1074a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1075a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int index;
1076a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1077a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	index = usb_endpoint_num(desc) << 1;
1078a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (usb_endpoint_dir_in(desc))
1079a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index |= 1;
1080a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return index;
1081a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1082a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1095a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int dummy_ep_stream_en(struct dummy_hcd *dum_hcd, struct urb *urb)
1096a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1097a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	const struct usb_endpoint_descriptor *desc = &urb->ep->desc;
1098a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	u32 index;
1099a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1100a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (!usb_endpoint_xfer_bulk(desc))
1101a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return 0;
1102a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1103a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	index = dummy_get_ep_idx(desc);
1104a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return (1 << index) & dum_hcd->stream_en_ep;
1105a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1106a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1107a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior/*
1108a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * The max stream number is saved as a nibble so for the 30 possible endpoints
1109a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * we only 15 bytes of memory. Therefore we are limited to max 16 streams (0
1110a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * means we use only 1 stream). The maximum according to the spec is 16bit so
1111a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * if the 16 stream limit is about to go, the array size should be incremented
1112a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * to 30 elements of type u16.
1113a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior */
1114a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int get_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
1115a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		unsigned int pipe)
1116a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1117a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int max_streams;
1118a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1119a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)];
1120a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (usb_pipeout(pipe))
1121a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_streams >>= 4;
1122a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	else
1123a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_streams &= 0xf;
1124a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams++;
1125a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return max_streams;
1126a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1127a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1128a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic void set_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
1129a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		unsigned int pipe, unsigned int streams)
1130a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1131a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int max_streams;
1132a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1133a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	streams--;
1134a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)];
1135a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (usb_pipeout(pipe)) {
1136a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		streams <<= 4;
1137a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_streams &= 0xf;
1138a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	} else {
1139a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_streams &= 0xf0;
1140a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
1141a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams |= streams;
1142a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	dum_hcd->num_stream[usb_pipeendpoint(pipe)] = max_streams;
1143a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1144a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1145a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb)
1146a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1147a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int max_streams;
1148a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int enabled;
1149a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1150a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	enabled = dummy_ep_stream_en(dum_hcd, urb);
1151a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (!urb->stream_id) {
1152a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (enabled)
1153a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			return -EINVAL;
1154a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return 0;
1155a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
1156a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (!enabled)
1157a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return -EINVAL;
1158a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1159a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams = get_max_streams_for_pipe(dum_hcd,
1160a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			usb_pipeendpoint(urb->pipe));
1161a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (urb->stream_id > max_streams) {
1162a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		dev_err(dummy_dev(dum_hcd), "Stream id %d is out of range.\n",
1163a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior				urb->stream_id);
1164a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		BUG();
1165a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return -EINVAL;
1166a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
1167a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return 0;
1168a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1169a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue (
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
117355016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t				mem_flags
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1175cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
1178e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp = kmalloc (sizeof *urbp, mem_flags);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
118414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	urbp->miter_started = 0;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1186cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1187cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1188a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1189a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	rc = dummy_validate_stream(dum_hcd, urb);
1190a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (rc) {
1191a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		kfree(urbp);
1192a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		goto done;
1193a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
1194a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1195e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_link_urb_to_ep(hcd, urb);
1196e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	if (rc) {
1197e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		kfree(urbp);
1198e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		goto done;
1199e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	}
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1202cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = urb->dev;
1203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_get_dev(dum_hcd->udev);
1204cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (unlikely(dum_hcd->udev != urb->dev))
1205cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1207cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
1213cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!timer_pending(&dum_hcd->timer))
1214cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + 1);
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1216e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done:
1217cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1218e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1223cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
1224391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1225e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
1226391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1227391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1228391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1229cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1230cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1231e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1232e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1233cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
1234cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			!list_empty(&dum_hcd->urbp_list))
1235cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies);
1236e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1237cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1238e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewiorstatic int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
1242a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior		u32 len)
1243a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior{
1244a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	void *ubuf, *rbuf;
124514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct urbp *urbp = urb->hcpriv;
1246a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	int to_host;
124714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct sg_mapping_iter *miter = &urbp->miter;
124814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32 trans = 0;
124914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32 this_sg;
125014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	bool next_sg;
1251a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
1252a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	to_host = usb_pipein(urb->pipe);
1253a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	rbuf = req->req.buf + req->req.actual;
1254a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
125514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (!urb->num_sgs) {
125614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		ubuf = urb->transfer_buffer + urb->actual_length;
125714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
125814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(ubuf, rbuf, len);
125914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
126014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(rbuf, ubuf, len);
126114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		return len;
126214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
126314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
126414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (!urbp->miter_started) {
126514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		u32 flags = SG_MITER_ATOMIC;
126614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
126714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
126814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			flags |= SG_MITER_TO_SG;
126914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
127014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			flags |= SG_MITER_FROM_SG;
127114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
127214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		sg_miter_start(miter, urb->sg, urb->num_sgs, flags);
127314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		urbp->miter_started = 1;
127414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
127514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	next_sg = sg_miter_next(miter);
127614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (next_sg == false) {
127714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		WARN_ON_ONCE(1);
127814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		return -EINVAL;
127914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
128014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	do {
128114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		ubuf = miter->addr;
128214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		this_sg = min_t(u32, len, miter->length);
128314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		miter->consumed = this_sg;
128414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		trans += this_sg;
128514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
128614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
128714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(ubuf, rbuf, this_sg);
128814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
128914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(rbuf, ubuf, this_sg);
129014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		len -= this_sg;
129114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
129214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (!len)
129314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			break;
129414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		next_sg = sg_miter_next(miter);
129514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (next_sg == false) {
129614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			WARN_ON_ONCE(1);
129714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			return -EINVAL;
129814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		}
129914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
130014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		rbuf += this_sg;
130114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	} while (1);
130214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
130314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	sg_miter_stop(miter);
130414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	return trans;
1305a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior}
1306a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
1308a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
1309a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		struct dummy_ep *ep, int limit, int *status)
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1311a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (dummy_ep_stream_en(dum_hcd, urb)) {
1322a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			if ((urb->stream_id != req->req.stream_id))
1323a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior				continue;
1324a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
1325a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min (host_len, dev_len);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_host = usb_pipein (urb->pipe);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely (len == 0))
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = min (len, (unsigned) limit);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1357a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior			len = dummy_perform_transfer(urb, req, len);
1358a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
136014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			if (len < 0) {
136114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				req->req.status = len;
136214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			} else {
136314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				limit -= len;
136414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				urb->actual_length += len;
136514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				req->req.actual += len;
136614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			}
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
1374b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern		 * need to emulate such data-in-flight.
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
13794d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
13834d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = -EOVERFLOW;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
13854d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = 0;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
13874d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
14014d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern						& URB_ZERO_PACKET))
14024d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock (&dum->lock);
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.complete (&ep->ep, &req->req);
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock (&dum->lock);
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
14184d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (*status != -EINPROGRESS)
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
143629cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto		tmp = usb_endpoint_maxp(ep->desc);
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER) {
144259f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior		switch (usb_endpoint_type(ep->desc)) {
14431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_ISOC:
14441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.8.2 USB3.0 Spec */
14451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 16 * 1024 * 8;
14461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
14471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_INT:
14481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.7.2 USB3.0 Spec */
14491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 1024 * 8;
14501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
14511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_BULK:
14521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		default:
14531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
14541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
14551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1459cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman#define is_active(dum_hcd)	((dum_hcd->port_status & \
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
14691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->ss_hcd : dum->hs_hcd)))
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return &dum->ep [0];
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
14948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman/**
14958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * handle_control_request() - handles all control transfers
14968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @dum: pointer to dummy (the_controller)
14978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @urb: the urb request to handle
14988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @setup: pointer to the setup data for a USB device control
14998be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	 request
15008be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @status: pointer to request handling status
15018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *
15028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * Return 0 - if the request was handled
15038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  1 - if the request wasn't handles
15048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  error code on error
15058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */
1506cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
15078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  struct usb_ctrlrequest *setup,
15088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  int *status)
15098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman{
15108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	struct dummy_ep		*ep2;
1511cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
15128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	int			ret_val = 1;
15138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_index;
15148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_value;
15158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
15168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_index = le16_to_cpu(setup->wIndex);
15178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_value = le16_to_cpu(setup->wValue);
15188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	switch (setup->bRequest) {
15198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_ADDRESS:
15208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType != Dev_Request)
15218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			break;
15228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dum->address = w_value;
15238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		*status = 0;
15248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dev_dbg(udc_dev(dum), "set_address = %d\n",
15258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value);
15268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		ret_val = 0;
15278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
15288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_FEATURE:
15298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
15308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
15328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
15338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_B_HNP_ENABLE:
15358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.b_hnp_enable = 1;
15368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_HNP_SUPPORT:
15388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_hnp_support = 1;
15398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_ALT_HNP_SUPPORT:
15418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_alt_hnp_support = 1;
15428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
15441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
15471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
15511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
15541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
15581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
15611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
15658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
15668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
15688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus |= (1 << w_value);
15698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
15708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
15728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
15738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
15748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2 || ep2->ep.name == ep0name) {
15758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
15768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2->halted = 1;
15798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
15818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
15828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
15838be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_CLEAR_FEATURE:
15848be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
15858be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
15878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
15888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value = USB_DEVICE_REMOTE_WAKEUP;
15898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
15911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
15941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
15981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
16001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
16011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
16021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
16031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
16041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
16051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
16061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
16071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
16081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
16091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
16101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
16118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
16128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
16138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
16148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
16158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
16168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus &= ~(1 << w_value);
16178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
16188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
16198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
16208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
16218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
16228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2) {
16238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
16248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
16258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
16268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2->wedged)
16278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ep2->halted = 0;
16288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
16298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
16308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
16318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
16328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_GET_STATUS:
16338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_InRequest
16348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Intf_InRequest
16358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Ep_InRequest) {
16368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			char *buf;
16378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/*
16388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * device: remote wakeup, selfpowered
16398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * interface: nothing
16408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * endpoint: halt
16418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 */
16428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			buf = (char *)urb->transfer_buffer;
16438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 0) {
16448be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				if (setup->bRequestType == Ep_InRequest) {
16458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					ep2 = find_endpoint(dum, w_index);
16468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					if (!ep2) {
16478be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						ret_val = -EOPNOTSUPP;
16488be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						break;
16498be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					}
16508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = ep2->halted;
16518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else if (setup->bRequestType ==
16528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					   Dev_InRequest) {
16538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = (u8)dum->devstatus;
16548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else
16558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = 0;
16568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
16578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 1)
16588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				buf[1] = 0;
16598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			urb->actual_length = min_t(u32, 2,
16608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				urb->transfer_buffer_length);
16618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
16628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
16638be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
16648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
16658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	}
16668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	return ret_val;
16678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman}
16688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1672cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void dummy_timer(unsigned long _dum_hcd)
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1674cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
1675cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case USB_SPEED_SUPER:
16931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* Bus speed is 500000 bytes/ms, so use a little less */
16941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		total = 490000;
16951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1697cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1706cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1707cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd),
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&dum->lock, flags);
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->ep [i].already_seen = 0;
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
1720cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
17264d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int			status = -EINPROGRESS;
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
1729eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern		if (urb->unlinked)
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1731cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
1732391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = usb_pipetype (urb->pipe);
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (usb_pipein (urb->pipe))
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
1749cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
17524d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPROTO;
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && urb->error_count) {
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
1765cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
17674d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPIPE;
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && ep->setup_stage) {
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_for_each_entry (req, &ep->queue, queue) {
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				list_del_init (&req->queue);
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
1782d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "stale req = %p\n",
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.complete (&ep->ep, &req->req);
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1800cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			value = handle_control_request(dum_hcd, urb, &setup,
18018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						       &status);
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = dum->driver->setup (&dum->gadget,
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
1822d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern					dev_dbg (udc_dev(dum),
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
18254d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				status = -EPIPE;
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (usb_pipetype (urb->pipe)) {
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
18424d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -ENOSYS;
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// case PIPE_BULK:  case PIPE_CONTROL:
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		treat_control_like_bulk:
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
1856a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			total = transfer(dum_hcd, urb, ep, limit, &status);
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
18614d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (status == -EINPROGRESS)
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del (&urbp->urbp_list);
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (urbp);
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1870cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
1872cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1878cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (list_empty(&dum_hcd->urbp_list)) {
1879cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_dev(dum_hcd->udev);
1880cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = NULL;
1881cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
1882391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1883cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1892c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1893c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1894c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1895c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1896c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf)
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1900cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1902391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1904cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1906cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1907541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1908391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1909f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1910cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
1911cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1912cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
1913cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1914f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1915f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1916cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
1918cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
1919cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status);
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1921cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
1922391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			usb_hcd_resume_root_hub (hcd);
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1924391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
1925cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
19301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanss_hub_descriptor(struct usb_hub_descriptor *desc)
19311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
19321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	memset(desc, 0, sizeof *desc);
19331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescriptorType = 0x2a;
19341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescLength = 12;
19351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->wHubCharacteristics = cpu_to_le16(0x0001);
19361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bNbrPorts = 1;
19371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
19381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.DeviceRemovable = 0xffff;
19391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
19401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
19411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic inline void
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc)
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (desc, 0, sizeof *desc);
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1947fd05e720099e8eeddb378305d1a41c1445344b91Al Viro	desc->wHubCharacteristics = cpu_to_le16(0x0001);
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
1949dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[0] = 0xff;
1950dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[1] = 0xff;
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control (
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1961cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1965541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1966391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1967391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1968cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1969cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1970cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
19771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
19801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
19811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1983cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
1985cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->resuming = 1;
1986cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->re_timeout = jiffies +
1987f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
19911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
19931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
19941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
19951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
19961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status &
19971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SS_PORT_STAT_POWER)
19981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
19991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
2000f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
2002cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~(1 << wValue);
2003cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
20071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3 &&
20081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(wLength < USB_DT_SS_HUB_SIZE ||
20091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 wValue != (USB_DT_SS_HUB << 8))) {
20101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"Wrong hub descriptor type for "
20121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"USB 3.0 roothub.\n");
20131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3)
20161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
20171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		else
20181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			hub_descriptor((struct usb_hub_descriptor *) buf);
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
2021551509d267905705f6d723e51ec706916f06b859Harvey Harrison		*(__le32 *) buf = cpu_to_le32 (0);
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2030cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->resuming &&
2031cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
2032cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
2033cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2035cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
2036cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
2037cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
2038cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
2039cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->dum->pullup) {
2040cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
20411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
20421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (hcd->speed < HCD_USB3) {
20431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					switch (dum_hcd->dum->gadget.speed) {
20441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_HIGH:
20451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
20461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						      USB_PORT_STAT_HIGH_SPEED;
20471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
20481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_LOW:
20491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.ep0->
20501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							maxpacket = 8;
20511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
20521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_PORT_STAT_LOW_SPEED;
20531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
20541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					default:
20551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.speed =
20561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SPEED_FULL;
20571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
20581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					}
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2062cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
2063cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
2064cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
20711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_LINK_STATE:
20721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
20731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
20741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_LINK_STATE req not "
20751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
20761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
20771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
20781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
20791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * Since this is dummy we don't have an actual link so
20801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * there is nothing to do for the SET_LINK_STATE cmd
20811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
20821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
20831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U1_TIMEOUT:
20841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U2_TIMEOUT:
20851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* TODO: add suspend/resume support! */
20861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
20871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
20881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
20891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
20901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
20911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
20921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
20941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB2.0 hub */
20951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
20961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
20971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
20981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
20991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
21001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
2101cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->active) {
2102cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
2103f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
2104f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
2105f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
2106f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
2107cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				set_link_state(dum_hcd);
2108f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
2109cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman						& dum_hcd->dum->devstatus) != 0)
2110cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
21115742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2114f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
21151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3)
21161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
21171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else
21181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_POWER;
2119cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
2120f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
21211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_BH_PORT_RESET:
21221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB3.0 hub */
21231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
21241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
21251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_BH_PORT_RESET req not "
21261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
21271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
21281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
21291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* FALLS THROUGH */
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
2131f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
21321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
21331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status = 0;
21341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status =
21351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_SS_PORT_STAT_POWER |
21361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_CONNECTION |
21371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_RESET);
21381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
21391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
2140f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
2141f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
2142cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			/*
2143cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * We want to reset device status. All but the
2144cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * Self powered feature
2145cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 */
2146cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->dum->devstatus &=
2147cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				(1 << USB_DEVICE_SELF_POWERED);
21481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
21491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * FIXME USB3.0: what is the correct reset signaling
21501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * interval? Is it still 50msec as for HS?
21511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
2152cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
2153f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
21551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
21561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
21571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_SS_PORT_STAT_POWER) != 0) {
21581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
21591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
21601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
21611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
21621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
21631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_PORT_STAT_POWER) != 0) {
21641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
21651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
21661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
21671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
21681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
21691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case GetPortErrorCount:
21701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
21711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
21721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "GetPortErrorCount req not "
21731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "supported for USB 2.0 roothub\n");
21741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
21751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
21761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* We'll always return 0 since this is a dummy hub */
21771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		*(__le32 *) buf = cpu_to_le32(0);
21781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
21791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case SetHubDepth:
21801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
21811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
21821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "SetHubDepth req not supported for "
21831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "USB 2.0 roothub\n");
21841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2188cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd),
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
21911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanerror:
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2195cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2196685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
2197cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
2198685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern		usb_hcd_poll_rh_status (hcd);
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22020c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd)
2203391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2204cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2205391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2206441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
22073cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2208cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2209cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
2210cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	set_link_state(dum_hcd);
22113cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd->state = HC_STATE_SUSPENDED;
2212cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
2213391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2214391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2215391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
22160c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd)
2217391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2218cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
22193cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int rc = 0;
22203cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2221441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
2222391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2223cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2224541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd)) {
2225cfa59dab27d1b282886e7772a8f9548236883892Alan Stern		rc = -ESHUTDOWN;
22263cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else {
2227cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->rh_state = DUMMY_RH_RUNNING;
2228cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
2229cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (!list_empty(&dum_hcd->urbp_list))
2230cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			mod_timer(&dum_hcd->timer, jiffies);
22313cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		hcd->state = HC_STATE_RUNNING;
22323cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	}
2233cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
22343cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2235391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t
22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb)
22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ep = usb_pipeendpoint (urb->pipe);
22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf (buf, size,
22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (urb->dev->speed) {
22497c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_LOW:
22507c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "ls";
22517c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
22527c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_FULL:
22537c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "fs";
22547c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
22557c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_HIGH:
22567c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "hs";
22577c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
22581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 case USB_SPEED_SUPER:
22591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			s = "ss";
22601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
22617c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
22627c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "?";
22637c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (usb_pipetype (urb->pipe)) { \
22687c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_CONTROL: \
22697c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = ""; \
22707c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
22717c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_BULK: \
22727c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-bulk"; \
22737c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
22747c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_INTERRUPT: \
22757c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-int"; \
22767c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
22777c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default: \
22787c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-iso"; \
22797c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}; s;}),
22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
228510523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf)
22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd = dev_get_drvdata (dev);
2288cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2293cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2294cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2301cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic int dummy_start_ss(struct dummy_hcd *dum_hcd)
23081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
23091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	init_timer(&dum_hcd->timer);
23101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.function = dummy_timer;
23111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
23121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
2313a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	dum_hcd->stream_en_ep = 0;
23141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
23151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
23161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
23171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
23181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#ifdef CONFIG_USB_OTG
23191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
23201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#endif
23211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
23221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
23241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
23251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
23261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2327cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_start(struct usb_hcd *hcd)
23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2329cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
23361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!usb_hcd_is_primary_hcd(hcd))
23371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dummy_start_ss(dum_hcd);
23381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2339cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_init(&dum_hcd->dum->lock);
2340cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	init_timer(&dum_hcd->timer);
2341cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.function = dummy_timer;
2342cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
2343cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2345cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2347caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern	hcd->power_budget = POWER_BUDGET;
23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
2349685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23515742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
23525742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
23535742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
23545742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
2356cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd)
23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2363cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(hcd))->dum;
2364cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
2365cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_gadget_unregister_driver(dum->driver);
2366cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd)
23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_g_get_frame (NULL);
23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2376cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_setup(struct usb_hcd *hcd)
2377cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman{
237814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	hcd->self.sg_tablesize = ~0;
2379cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (usb_hcd_is_primary_hcd(hcd)) {
2380cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
2381cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd->dum = &the_controller;
23821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
23831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * Mark the first roothub as being USB 2.0.
23841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * The USB 3.0 roothub will be registered later by
23851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * dummy_hcd_probe()
23861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
2387cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->speed = HCD_USB2;
2388cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_HIGH;
23891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
23901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
23911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd->dum = &the_controller;
23921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->speed = HCD_USB3;
23931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_SUPER;
2394cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	}
2395cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return 0;
2396cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman}
2397cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
23981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Change a group of bulk endpoints to support multiple stream IDs */
2399d81f3e4f5792acab5929ef99aad6ca5e21a31a0eSebastian Andrzej Siewiorstatic int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
24001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
24011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	unsigned int num_streams, gfp_t mem_flags)
24021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2403a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2404a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned long flags;
2405a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int max_stream;
2406a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int ret_streams = num_streams;
2407a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int index;
2408a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int i;
2409a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2410a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (!num_eps)
2411a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return -EINVAL;
2412a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2413a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2414a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	for (i = 0; i < num_eps; i++) {
2415a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index = dummy_get_ep_idx(&eps[i]->desc);
2416a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if ((1 << index) & dum_hcd->stream_en_ep) {
2417a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			ret_streams = -EINVAL;
2418a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			goto out;
2419a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
2420a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_stream = usb_ss_max_streams(&eps[i]->ss_ep_comp);
2421a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (!max_stream) {
2422a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			ret_streams = -EINVAL;
2423a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			goto out;
2424a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
2425a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (max_stream < ret_streams) {
2426a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			dev_dbg(dummy_dev(dum_hcd), "Ep 0x%x only supports %u "
2427a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior					"stream IDs.\n",
2428a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior					eps[i]->desc.bEndpointAddress,
2429a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior					max_stream);
2430a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			ret_streams = max_stream;
2431a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
2432a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
2433a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2434a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	for (i = 0; i < num_eps; i++) {
2435a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index = dummy_get_ep_idx(&eps[i]->desc);
2436a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		dum_hcd->stream_en_ep |= 1 << index;
2437a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		set_max_streams_for_pipe(dum_hcd,
2438a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior				usb_endpoint_num(&eps[i]->desc), ret_streams);
2439a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
2440a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorout:
2441a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2442a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return ret_streams;
24431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
24441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
24451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Reverts a group of bulk endpoints back to not using stream IDs. */
2446d81f3e4f5792acab5929ef99aad6ca5e21a31a0eSebastian Andrzej Siewiorstatic int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
24471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
24481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	gfp_t mem_flags)
24491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2450a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2451a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned long flags;
2452a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int ret;
2453a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int index;
2454a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int i;
2455a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2456a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2457a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	for (i = 0; i < num_eps; i++) {
2458a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index = dummy_get_ep_idx(&eps[i]->desc);
2459a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (!((1 << index) & dum_hcd->stream_en_ep)) {
2460a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			ret = -EINVAL;
2461a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			goto out;
2462a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
2463a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
2464a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2465a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	for (i = 0; i < num_eps; i++) {
2466a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index = dummy_get_ep_idx(&eps[i]->desc);
2467a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		dum_hcd->stream_en_ep &= ~(1 << index);
2468a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		set_max_streams_for_pipe(dum_hcd,
2469a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior				usb_endpoint_num(&eps[i]->desc), 0);
2470a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
2471a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	ret = 0;
2472a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorout:
2473a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2474a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return ret;
24751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
24761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
24771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct hc_driver dummy_hcd = {
24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
2480cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.hcd_priv_size =	sizeof(struct dummy_hcd),
24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.flags =		HCD_USB3 | HCD_SHARED,
24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2484cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.reset =		dummy_setup,
24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_enqueue = 		dummy_urb_enqueue,
24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_dequeue = 		dummy_urb_dequeue,
24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame_number = 	dummy_h_get_frame,
24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_status_data = 	dummy_hub_status,
24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_control = 		dummy_hub_control,
24950c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_suspend =		dummy_bus_suspend,
24960c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_resume =		dummy_bus_resume,
24971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
24981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.alloc_streams =	dummy_alloc_streams,
24991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.free_streams =		dummy_free_streams,
25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25028364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev)
25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2504cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_hcd		*hs_hcd;
25051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_hcd		*ss_hcd;
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25088364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!mod_data.is_super_speed)
25111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dummy_hcd.flags = HCD_USB2;
2512cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
2513cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!hs_hcd)
25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2515cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd->has_tt = 1;
25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2517cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	retval = usb_add_hcd(hs_hcd, 0, 0);
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
2519cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_hcd(hs_hcd);
25201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return retval;
25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
25231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (mod_data.is_super_speed) {
25241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
25251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_name(&pdev->dev), hs_hcd);
25261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (!ss_hcd) {
25271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			retval = -ENOMEM;
25281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto dealloc_usb2_hcd;
25291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
25301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
25311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		retval = usb_add_hcd(ss_hcd, 0, 0);
25321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (retval)
25331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto put_usb3_hcd;
25341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
25351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
25361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
25371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanput_usb3_hcd:
25381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(ss_hcd);
25391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmandealloc_usb2_hcd:
25401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(hs_hcd);
25411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2545cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_hcd_remove(struct platform_device *pdev)
25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2547cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum;
2548cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
2549cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
25501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
25511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->ss_hcd) {
25521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
25531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
25541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
25551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2556cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2557cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
25581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2559cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	the_controller.hs_hcd = NULL;
25601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.ss_hcd = NULL;
25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2562d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25658364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
2566391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2567391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2568cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
25693cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int			rc = 0;
2570391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2571441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2572391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
25733cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
2574cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
2575cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
25763cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
25773cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		rc = -EBUSY;
25783cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else
25793cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
25803cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2581391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2582391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
25838364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_resume (struct platform_device *pdev)
2584391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2585391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2586391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2587441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2588391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
25893cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
25903cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
2591391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (hcd);
2592391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2593391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2594391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
25953ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = {
2596d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
2597d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
2598391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
2599391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
26003ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
26013ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) driver_name,
26023ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
26033ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2604d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2606d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2608a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_udc_pdev;
2609a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_hcd_pdev;
26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void)
26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2613a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	int	retval = -ENOMEM;
26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_disabled ())
26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2617d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
26187eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	if (!mod_data.is_high_speed && mod_data.is_super_speed)
26197eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		return -EINVAL;
26207eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman
2621a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_hcd_pdev = platform_device_alloc(driver_name, -1);
2622a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_hcd_pdev)
26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
2624a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_udc_pdev = platform_device_alloc(gadget_name, -1);
2625a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_udc_pdev)
2626a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_alloc_udc;
2627d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2628a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_hcd_driver);
2629a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (retval < 0)
2630a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_register_hcd_driver;
2631a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_udc_driver);
2632d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2633d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2634d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2635a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_hcd_pdev);
2636d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2637a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_hcd;
26381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!the_controller.hs_hcd ||
26391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	    (!the_controller.ss_hcd && mod_data.is_super_speed)) {
2640865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2641865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The hcd was added successfully but its probe function failed
2642865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2643865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2644865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2645865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_add_udc;
2646865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2647a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_udc_pdev);
2648d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2649a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_udc;
2650865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	if (!platform_get_drvdata(the_udc_pdev)) {
2651865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2652865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The udc was added successfully but its probe function failed
2653865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2654865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2655865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2656865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_probe_udc;
2657865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2658d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2659d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2660865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewiorerr_probe_udc:
2661865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	platform_device_del(the_udc_pdev);
2662a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_udc:
2663a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_del(the_hcd_pdev);
2664a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_hcd:
2665a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2666d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
2667a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
2668a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_register_hcd_driver:
2669a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_udc_pdev);
2670a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_alloc_udc:
2671a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_hcd_pdev);
26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init);
26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void)
26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2678a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_udc_pdev);
2679a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_hcd_pdev);
2680a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2681a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup);
2684