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>
4518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior#include <linux/io.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC	"USB Host+Gadget Emulator"
50391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION	"02 May 2005"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern#define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
53caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern
5418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char	driver_name[] = "dummy_hcd";
5518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char	driver_desc[] = "USB Host+Gadget Emulator";
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char	gadget_name[] = "dummy_udc";
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej SiewiorMODULE_DESCRIPTION(DRIVER_DESC);
6018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej SiewiorMODULE_AUTHOR("David Brownell");
6118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej SiewiorMODULE_LICENSE("GPL");
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstruct dummy_hcd_module_parameters {
641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	bool is_super_speed;
657eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	bool is_high_speed;
661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct dummy_hcd_module_parameters mod_data = {
697eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_super_speed = false,
707eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_high_speed = true,
711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanmodule_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana BrokhmanMODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
747eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhmanmodule_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
757eca4c5a8b73f22ad16ad6e76b901351732355daTatyana BrokhmanMODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep {
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			last_io;	/* jiffies timestamp */
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		*gadget;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usb_endpoint_descriptor *desc;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep			ep;
8518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	unsigned			halted:1;
8618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	unsigned			wedged:1;
8718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	unsigned			already_seen:1;
8818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	unsigned			setup_stage:1;
89a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned			stream_en:1;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request {
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;		/* ep's requests */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_request		req;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline struct dummy_ep *usb_ep_to_dummy_ep(struct usb_ep *_ep)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	return container_of(_ep, struct dummy_ep, ep);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(struct usb_request *_req)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	return container_of(_req, struct dummy_request, req);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints,
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types:
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Configurable:  direction (in/out), type (bulk, iso, etc), and endpoint
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     number can be changed.  Names like "ep-a" are used for this type.
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Fixed Function:  in other cases.  some characteristics may be mutable;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     that'd be hardware-specific.  Names like "ep12out-bulk" are used.
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on.
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char ep0name[] = "ep0";
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic const char *const ep_name[] = {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep0name,				/* everyone has ep0 */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* act like a net2280: high speed, six configurable endpoints */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like pxa250: fifteen fixed function endpoints */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ep15in-int",
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like sa1100: two fixed function endpoints */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1out-bulk", "ep2in-bulk",
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
14152950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS	ARRAY_SIZE(ep_name)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
144d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE		64
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp {
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb		*urb;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head	urbp_list;
15014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct sg_mapping_iter	miter;
15114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32			miter_started;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
154391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
155391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state {
156391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RESET,
157391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_SUSPENDED,
158391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RUNNING
159391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern};
160391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
161cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstruct dummy_hcd {
162cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy			*dum;
163cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	enum dummy_rh_state		rh_state;
164cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct timer_list		timer;
165cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				port_status;
166cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				old_status;
167cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned long			re_timeout;
168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_device		*udev;
170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct list_head		urbp_list;
171a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	u32				stream_en_ep;
172a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	u8				num_stream[30 / 2];
173cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
174cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			active:1;
175cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			old_active:1;
176cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			resuming:1;
177cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman};
178cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy {
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t			lock;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE/GADGET side support
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	struct dummy_ep			ep[DUMMY_ENDPOINTS];
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				address;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		gadget;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget_driver	*driver;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request		fifo_req;
19018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	u8				fifo_buf[FIFO_SIZE];
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16				devstatus;
192391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned			udc_suspended:1;
193f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			pullup:1;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER/HOST side support
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
198cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd		*hs_hcd;
1991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy_hcd		*ss_hcd;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
202cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
204cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return (struct dummy_hcd *) (hcd->hcd_priv);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of((void *) dum, struct usb_hcd, hcd_priv);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
212cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct device *dummy_dev(struct dummy_hcd *dum)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
214cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return dummy_hcd_to_hcd(dum)->self.controller;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline struct device *udc_dev(struct dummy *dum)
218d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
219d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return dum->gadget.dev.parent;
220d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
221d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
22218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline struct dummy *ep_to_dummy(struct dummy_ep *ep)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	return container_of(ep->gadget, struct dummy, gadget);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
227cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
229cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = container_of(gadget, struct dummy, gadget);
2301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER)
2311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->ss_hcd;
2321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	else
2331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->hs_hcd;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline struct dummy *gadget_dev_to_dummy(struct device *dev)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	return container_of(dev, struct dummy, gadget.dev);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic struct dummy			the_controller;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
245f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */
246f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */
24818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void nuke(struct dummy *dum, struct dummy_ep *ep)
249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
25018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	while (!list_empty(&ep->queue)) {
251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		struct dummy_request	*req;
252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
25318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		req = list_entry(ep->queue.next, struct dummy_request, queue);
25418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		list_del_init(&req->queue);
255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.status = -ESHUTDOWN;
256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
25718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		spin_unlock(&dum->lock);
25818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		req->req.complete(&ep->ep, &req->req);
25918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		spin_lock(&dum->lock);
260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
26418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void stop_activity(struct dummy *dum)
265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy_ep	*ep;
267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* prevent any more requests */
269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->address = 0;
270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* The timer is left running so that outstanding URBs can fail */
272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* nuke any pending requests first, so driver i/o is quiesced */
27418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list)
27518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		nuke(dum, ep);
276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* driver now does any non-usb quiescing necessary */
278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
2801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/**
2811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * set_link_state_by_speed() - Sets the current state of the link according to
2821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *	the hcd speed
2831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
2841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *
2851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * This function updates the port_status according to the link state and the
2861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * speed of the hcd.
2871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */
2881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
2891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy *dum = dum_hcd->dum;
2911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) {
2931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) {
2941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
2951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
2961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
2971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
2981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE);
2991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* device is connected and not suspended */
3051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
3061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						 USB_PORT_STAT_SPEED_5GBPS) ;
3071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status &
3121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_ENABLE) == 1 &&
3131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(dum_hcd->port_status &
3141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 USB_SS_PORT_LS_U0) == 1 &&
3151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
3191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) {
3201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
3211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
3221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
3231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
3241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE |
3251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_LOW_SPEED |
3261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_HIGH_SPEED |
3271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_SUSPEND);
3281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
3341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
3391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
3401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else if ((dum_hcd->port_status &
3411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				  USB_PORT_STAT_SUSPEND) == 0 &&
3421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
3461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
3471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
348f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void set_link_state(struct dummy_hcd *dum_hcd)
350f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
351cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = dum_hcd->dum;
352cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
353cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->active = 0;
3541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->pullup)
3551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
3561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed != USB_SPEED_SUPER) ||
3571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
3581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed == USB_SPEED_SUPER))
3591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			return;
3601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
3611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	set_link_state_by_speed(dum_hcd);
362f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
363cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
364cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	     dum_hcd->active)
365cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->resuming = 0;
366f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* if !connected or reset */
368cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
369cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
3701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
3711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * We're connected and not reset (reset occurred now),
3721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * and driver attached - disconnect!
3731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
374cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
3751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
3761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    dum->driver) {
3771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			stop_activity(dum);
3781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->disconnect(&dum->gadget);
3801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
381f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
382cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->active != dum_hcd->old_active) {
383cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->old_active && dum->driver->suspend) {
3841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->suspend(&dum->gadget);
3861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
3871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
3881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->resume(&dum->gadget);
3901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
391f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
392f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
393f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
394cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_status = dum_hcd->port_status;
395cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_active = dum_hcd->active;
396f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
397f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
398f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/
399f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state.  All the work is done when the host
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation.  Real device controller
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc.
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(dum->port_status & USB_PORT_STAT_ENABLE)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_enable(struct usb_ep *_ep,
41118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		const struct usb_endpoint_descriptor *desc)
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
414cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		max;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	ep = usb_ep_to_dummy_ep(_ep);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !desc || ep->desc || _ep->name == ep0name
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| desc->bDescriptorType != USB_DT_ENDPOINT)
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
42318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dum = ep_to_dummy(ep);
424cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver)
425cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		return -ESHUTDOWN;
426719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior
427719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
428cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!is_enabled(dum_hcd))
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
430cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
431cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	/*
432cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
433cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * maximum packet size.
4341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	 * For SS devices the wMaxPacketSize is limited by 1024.
435cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 */
43629cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto	max = usb_endpoint_maxp(desc) & 0x7ff;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* drivers must not request bad settings, since lower levels
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (hardware or its drivers) may not check.  some endpoints
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't do iso, many have maxpacket limitations, etc.
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since this "hardware" driver is here to help debugging, we
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have some extra sanity checks.  (there could be more though,
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially for "ep9out" style fixed function ones.)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = -EINVAL;
44759f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior	switch (usb_endpoint_type(desc)) {
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_BULK:
44918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		if (strstr(ep->ep.name, "-iso")
45018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				|| strstr(ep->ep.name, "-int")) {
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (max == 1024)
4561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
4571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto done;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max == 512)
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4619063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4629063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		case USB_SPEED_FULL:
4639063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			if (max == 8 || max == 16 || max == 32 || max == 64)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we'll fake any legal size */
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4669063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			/* save a return statement */
4679063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		default:
4689063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_INT:
47218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 64)
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 8)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_ISOC:
49218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		if (strstr(ep->ep.name, "-bulk")
49318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				|| strstr(ep->ep.name, "-int"))
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1023)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* few chips support control except on ep0 */
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_ep->maxpacket = max;
516a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (usb_ss_max_streams(_ep->comp_desc)) {
517a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (!usb_endpoint_xfer_bulk(desc)) {
518a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			dev_err(udc_dev(dum), "Can't enable stream support on "
519a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior					"non-bulk ep %s\n", _ep->name);
520a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			return -EINVAL;
521a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
522a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		ep->stream_en = 1;
523a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
5243cf0ad02e42a91e85ffe9bd67422dd266531d3ecSebastian Andrzej Siewior	ep->desc = desc;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
526a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	dev_dbg(udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d stream %s\n",
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_ep->name,
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		desc->bEndpointAddress & 0x0f,
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *val;
53159f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior		 switch (usb_endpoint_type(desc)) {
5327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_BULK:
5337c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "bulk";
5347c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5357c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_ISOC:
5367c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "iso";
5377c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5387c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_INT:
5397c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "intr";
5407c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5417c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
5427c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "ctrl";
5437c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; val; }),
545a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max, ep->stream_en ? "enabled" : "disabled");
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* at this point real hardware should be NAKing transfers
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to that endpoint, until a buffer is queued to it.
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
550851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	ep->halted = ep->wedged = 0;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_disable(struct usb_ep *_ep)
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	ep = usb_ep_to_dummy_ep(_ep);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !ep->desc || _ep->name == ep0name)
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
56618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dum = ep_to_dummy(ep);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
56818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_lock_irqsave(&dum->lock, flags);
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = NULL;
570a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	ep->stream_en = 0;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
57218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	nuke(dum, ep);
57318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_unlock_irqrestore(&dum->lock, flags);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
57518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dev_dbg(udc_dev(dum), "disabled %s\n", _ep->name);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
57918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic struct usb_request *dummy_alloc_request(struct usb_ep *_ep,
58018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		gfp_t mem_flags)
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
58718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	ep = usb_ep_to_dummy_ep(_ep);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5897039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn	req = kzalloc(sizeof(*req), mem_flags);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!req)
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
59218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	INIT_LIST_HEAD(&req->queue);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &req->req;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
59618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req)
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60120edfbb6a17f3007c1905e9849d8d306e318883bSebastian Andrzej Siewior	if (!_ep || !_req)
60220edfbb6a17f3007c1905e9849d8d306e318883bSebastian Andrzej Siewior		return;
60318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	ep = usb_ep_to_dummy_ep(_ep);
60420edfbb6a17f3007c1905e9849d8d306e318883bSebastian Andrzej Siewior	if (!ep->desc && _ep->name != ep0name)
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
60718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	req = usb_request_to_dummy_request(_req);
60818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	WARN_ON(!list_empty(&req->queue));
60918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	kfree(req);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void fifo_complete(struct usb_ep *ep, struct usb_request *req)
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_queue(struct usb_ep *_ep, struct usb_request *_req,
61755016f10e31bb15b85d8c500f979dfdceb37d548Al Viro		gfp_t mem_flags)
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
622cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	req = usb_request_to_dummy_request(_req);
62618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	if (!_req || !list_empty(&req->queue) || !_req->complete)
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	ep = usb_ep_to_dummy_ep(_ep);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dum = ep_to_dummy(ep);
634719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
635cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver || !is_enabled(dum_hcd))
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
63918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dev_dbg(udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
64418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_lock_irqsave(&dum->lock, flags);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
64818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			list_empty(&dum->fifo_req.queue) &&
64918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			list_empty(&ep->queue) &&
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
65418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		memcpy(dum->fifo_buf, _req->buf, _req->length);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
658c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
65918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		spin_unlock(&dum->lock);
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
66218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		_req->complete(_ep, _req);
66318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		spin_lock(&dum->lock);
664c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell	}  else
665c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
66618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_unlock_irqrestore(&dum->lock, flags);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
68418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	ep = usb_ep_to_dummy_ep(_ep);
68518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dum = ep_to_dummy(ep);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	local_irq_save(flags);
69118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_lock(&dum->lock);
69218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	list_for_each_entry(req, &ep->queue, queue) {
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
69418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			list_del_init(&req->queue);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
70018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_unlock(&dum->lock);
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
70318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		dev_dbg(udc_dev(dum),
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
70618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		_req->complete(_ep, _req);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
70818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	local_irq_restore(flags);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
713851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
72018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	ep = usb_ep_to_dummy_ep(_ep);
72118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dum = ep_to_dummy(ep);
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
725851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		ep->halted = ep->wedged = 0;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
72718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			!list_empty(&ep->queue))
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
729851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	else {
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
731851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		if (wedged)
732851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern			ep->wedged = 1;
733851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	}
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
738851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int
739851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt(struct usb_ep *_ep, int value)
740851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
741851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, value, 0);
742851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
743851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
744851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int dummy_set_wedge(struct usb_ep *_ep)
745851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
746851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	if (!_ep || _ep->name == ep0name)
747851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		return -EINVAL;
748851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, 1, 1);
749851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
750851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
762851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	.set_wedge	= dummy_set_wedge,
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
76818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_g_get_frame(struct usb_gadget *_gadget)
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
77218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	do_gettimeofday(&tv);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
77618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_wakeup(struct usb_gadget *_gadget)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
778cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
780cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = gadget_to_dummy_hcd(_gadget);
781cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
7825742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
784cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
785391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
786cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
787cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
788391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
789391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
790391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
793cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->resuming = 1;
794cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
795cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
79918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dum = gadget_to_dummy_hcd(_gadget)->dum;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811d262127c330b852ce4b210a0b1b06e69d4d87704Sebastian Andrzej Siewiorstatic void dummy_udc_update_ep0(struct dummy *dum)
812b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior{
813c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	if (dum->gadget.speed == USB_SPEED_SUPER)
814b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 9;
815c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	else
816b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 64;
817b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior}
818b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
81918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_pullup(struct usb_gadget *_gadget, int value)
820f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
821d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd;
822f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
823f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
824f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
825b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	dum = gadget_dev_to_dummy(&_gadget->dev);
826b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
827b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	if (value && dum->driver) {
828b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		if (mod_data.is_super_speed)
8297177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz			dum->gadget.speed = dum->driver->max_speed;
830b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else if (mod_data.is_high_speed)
831b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
8327177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz					dum->driver->max_speed);
833b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else
834b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = USB_SPEED_FULL;
835d262127c330b852ce4b210a0b1b06e69d4d87704Sebastian Andrzej Siewior		dummy_udc_update_ep0(dum);
836b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
8377177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz		if (dum->gadget.speed < dum->driver->max_speed)
838b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dev_dbg(udc_dev(dum), "This device can perform faster"
8397177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				" if you connect it to a %s port...\n",
8407177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				usb_speed_string(dum->driver->max_speed));
841b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	}
842d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(_gadget);
843d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior
84418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_lock_irqsave(&dum->lock, flags);
845f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
846d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
84718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_unlock_irqrestore(&dum->lock, flags);
848b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
849d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
850f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
851f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
852f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
853aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
854aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
855aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
856aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
8570f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
862f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
863aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_start	= dummy_udc_start,
864aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_stop	= dummy_udc_stop,
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
87018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic ssize_t show_function(struct device *dev, struct device_attribute *attr,
87118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		char *buf)
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
87318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	struct dummy	*dum = gadget_dev_to_dummy(dev);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
87718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	return scnprintf(buf, PAGE_SIZE, "%s\n", dum->driver->function);
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
87918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
897aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
898aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
900aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
901aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9037177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz	if (driver->max_speed == USB_SPEED_UNKNOWN)
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9105742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
91418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
919aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
920aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
922aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
923aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
92518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
9292542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
935d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
936d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
93718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void dummy_gadget_release(struct device *dev)
938d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
939cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return;
940d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
941d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9420fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewiorstatic void init_dummy_udc_hw(struct dummy *dum)
9430fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior{
9440fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	int i;
9450fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9460fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->gadget.ep_list);
9470fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
9480fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		struct dummy_ep	*ep = &dum->ep[i];
9490fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9500fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		if (!ep_name[i])
9510fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior			break;
9520fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.name = ep_name[i];
9530fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.ops = &dummy_ep_ops;
9540fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
9550fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->halted = ep->wedged = ep->already_seen =
9560fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior				ep->setup_stage = 0;
9570fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.maxpacket = ~0;
958c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior		ep->ep.max_streams = 16;
9590fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->last_io = jiffies;
9600fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->gadget = &dum->gadget;
9610fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->desc = NULL;
9620fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		INIT_LIST_HEAD(&ep->queue);
9630fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	}
9640fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9650fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	dum->gadget.ep0 = &dum->ep[0].ep;
9660fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	list_del_init(&dum->ep[0].ep.ep_list);
9670fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->fifo_req.queue);
968f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior
969f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#ifdef CONFIG_USB_OTG
970f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior	dum->gadget.is_otg = 1;
971f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#endif
9720fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior}
9730fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
97418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_udc_probe(struct platform_device *pdev)
975d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
976cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy	*dum = &the_controller;
977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
978d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
979d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
980d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
981d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz	dum->gadget.max_speed = USB_SPEED_SUPER;
982d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9830031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers	dev_set_name(&dum->gadget.dev, "gadget");
9848364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dum->gadget.dev.parent = &pdev->dev;
985d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
98618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	rc = device_register(&dum->gadget.dev);
98775d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	if (rc < 0) {
98875d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar		put_device(&dum->gadget.dev);
989d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
99075d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	}
991d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9920fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	init_dummy_udc_hw(dum);
9930fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9940f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
9950f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	if (rc < 0)
9960f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_udc;
9970f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
99818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	rc = device_create_file(&dum->gadget.dev, &dev_attr_function);
999efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if (rc < 0)
10000f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_dev;
10010f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	platform_set_drvdata(pdev, dum);
10020f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	return rc;
10030f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
10040f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_dev:
10050f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10060f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_udc:
10070f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	device_unregister(&dum->gadget.dev);
1008d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
1009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
101118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_udc_remove(struct platform_device *pdev)
1012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
101318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	struct dummy	*dum = platform_get_drvdata(pdev);
1014d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10150f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
101618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	platform_set_drvdata(pdev, NULL);
101718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	device_remove_file(&dum->gadget.dev, &dev_attr_function);
101818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	device_unregister(&dum->gadget.dev);
1019d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
1020d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1021d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1022fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd,
1023fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior		int suspend)
1024391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1025fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_lock_irq(&dum->lock);
1026fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dum->udc_suspended = suspend;
1027d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
1028fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_unlock_irq(&dum->lock);
1029fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior}
1030fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior
1031fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state)
1032fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior{
1033fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1034fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1035391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1036fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1037fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 1);
1038d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1039391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1040391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1041391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1042fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_resume(struct platform_device *pdev)
1043391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1044fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1045fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1046391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1047fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1048fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 0);
1049d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1050391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1051391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1052391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
10533ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = {
1054d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
1055d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
1056391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
1057391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
10583ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
10593ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) gadget_name,
10603ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
10613ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
1062d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
1063d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1066a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc)
1067a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1068a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int index;
1069a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1070a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	index = usb_endpoint_num(desc) << 1;
1071a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (usb_endpoint_dir_in(desc))
1072a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index |= 1;
1073a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return index;
1074a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1075a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1088a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int dummy_ep_stream_en(struct dummy_hcd *dum_hcd, struct urb *urb)
1089a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1090a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	const struct usb_endpoint_descriptor *desc = &urb->ep->desc;
1091a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	u32 index;
1092a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1093a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (!usb_endpoint_xfer_bulk(desc))
1094a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return 0;
1095a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1096a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	index = dummy_get_ep_idx(desc);
1097a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return (1 << index) & dum_hcd->stream_en_ep;
1098a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1099a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1100a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior/*
1101a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * The max stream number is saved as a nibble so for the 30 possible endpoints
1102a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * we only 15 bytes of memory. Therefore we are limited to max 16 streams (0
1103a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * means we use only 1 stream). The maximum according to the spec is 16bit so
1104a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * if the 16 stream limit is about to go, the array size should be incremented
1105a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior * to 30 elements of type u16.
1106a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior */
1107a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int get_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
1108a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		unsigned int pipe)
1109a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1110a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int max_streams;
1111a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1112a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)];
1113a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (usb_pipeout(pipe))
1114a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_streams >>= 4;
1115a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	else
1116a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_streams &= 0xf;
1117a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams++;
1118a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return max_streams;
1119a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1120a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1121a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic void set_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
1122a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		unsigned int pipe, unsigned int streams)
1123a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1124a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int max_streams;
1125a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1126a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	streams--;
1127a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)];
1128a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (usb_pipeout(pipe)) {
1129a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		streams <<= 4;
1130a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_streams &= 0xf;
1131a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	} else {
1132a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_streams &= 0xf0;
1133a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
1134a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams |= streams;
1135a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	dum_hcd->num_stream[usb_pipeendpoint(pipe)] = max_streams;
1136a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1137a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1138a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb)
1139a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior{
1140a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int max_streams;
1141a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int enabled;
1142a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1143a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	enabled = dummy_ep_stream_en(dum_hcd, urb);
1144a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (!urb->stream_id) {
1145a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (enabled)
1146a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			return -EINVAL;
1147a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return 0;
1148a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
1149a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (!enabled)
1150a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return -EINVAL;
1151a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1152a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	max_streams = get_max_streams_for_pipe(dum_hcd,
1153a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			usb_pipeendpoint(urb->pipe));
1154a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (urb->stream_id > max_streams) {
1155a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		dev_err(dummy_dev(dum_hcd), "Stream id %d is out of range.\n",
1156a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior				urb->stream_id);
1157a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		BUG();
1158a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return -EINVAL;
1159a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
1160a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return 0;
1161a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior}
1162a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
116318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_urb_enqueue(
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
116655016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t				mem_flags
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
1171e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
117318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	urbp = kmalloc(sizeof *urbp, mem_flags);
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
117714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	urbp->miter_started = 0;
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1180cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1181a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1182a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	rc = dummy_validate_stream(dum_hcd, urb);
1183a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (rc) {
1184a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		kfree(urbp);
1185a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		goto done;
1186a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
1187a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
1188e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_link_urb_to_ep(hcd, urb);
1189e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	if (rc) {
1190e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		kfree(urbp);
1191e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		goto done;
1192e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	}
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1194cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1195cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = urb->dev;
1196cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_get_dev(dum_hcd->udev);
1197cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (unlikely(dum_hcd->udev != urb->dev))
1198cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1200cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
120218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
1206cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!timer_pending(&dum_hcd->timer))
1207cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + 1);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1209e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done:
1210cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1211e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1214e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1216cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
1217391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1218e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
1219391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1220391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1221391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1222cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1223cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1224e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1225e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1226cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
1227cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			!list_empty(&dum_hcd->urbp_list))
1228cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies);
1229e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1230cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1231e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1234a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewiorstatic int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
1235a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior		u32 len)
1236a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior{
1237a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	void *ubuf, *rbuf;
123814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct urbp *urbp = urb->hcpriv;
1239a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	int to_host;
124014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct sg_mapping_iter *miter = &urbp->miter;
124114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32 trans = 0;
124214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32 this_sg;
124314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	bool next_sg;
1244a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
1245a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	to_host = usb_pipein(urb->pipe);
1246a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	rbuf = req->req.buf + req->req.actual;
1247a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
124814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (!urb->num_sgs) {
124914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		ubuf = urb->transfer_buffer + urb->actual_length;
125014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
125114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(ubuf, rbuf, len);
125214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
125314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(rbuf, ubuf, len);
125414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		return len;
125514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
125614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
125714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (!urbp->miter_started) {
125814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		u32 flags = SG_MITER_ATOMIC;
125914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
126014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
126114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			flags |= SG_MITER_TO_SG;
126214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
126314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			flags |= SG_MITER_FROM_SG;
126414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
126514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		sg_miter_start(miter, urb->sg, urb->num_sgs, flags);
126614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		urbp->miter_started = 1;
126714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
126814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	next_sg = sg_miter_next(miter);
126914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (next_sg == false) {
127014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		WARN_ON_ONCE(1);
127114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		return -EINVAL;
127214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
127314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	do {
127414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		ubuf = miter->addr;
127514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		this_sg = min_t(u32, len, miter->length);
127614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		miter->consumed = this_sg;
127714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		trans += this_sg;
127814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
127914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
128014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(ubuf, rbuf, this_sg);
128114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
128214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(rbuf, ubuf, this_sg);
128314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		len -= this_sg;
128414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
128514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (!len)
128614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			break;
128714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		next_sg = sg_miter_next(miter);
128814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (next_sg == false) {
128914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			WARN_ON_ONCE(1);
129014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			return -EINVAL;
129114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		}
129214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
129314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		rbuf += this_sg;
129414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	} while (1);
129514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
129614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	sg_miter_stop(miter);
129714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	return trans;
1298a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior}
1299a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
1301a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorstatic int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
1302a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		struct dummy_ep *ep, int limit, int *status)
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1304a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
130918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	list_for_each_entry(req, &ep->queue, queue) {
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1314a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (dummy_ep_stream_en(dum_hcd, urb)) {
1315a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			if ((urb->stream_id != req->req.stream_id))
1316a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior				continue;
1317a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
1318a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
132818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		len = min(host_len, dev_len);
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
133218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		to_host = usb_pipein(urb->pipe);
133318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		if (unlikely(len == 0))
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
133918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			len = min_t(unsigned, len, limit);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1350a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior			len = dummy_perform_transfer(urb, req, len);
1351a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
1353b1443ac0e486842c133b8805ee035ab3ff918763Dan Carpenter			if ((int)len < 0) {
135414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				req->req.status = len;
135514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			} else {
135614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				limit -= len;
135714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				urb->actual_length += len;
135814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				req->req.actual += len;
135914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			}
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
1367b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern		 * need to emulate such data-in-flight.
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
13724d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
13764d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = -EOVERFLOW;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
13784d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = 0;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
13804d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
13944d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern						& URB_ZERO_PACKET))
13954d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
140018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			list_del_init(&req->queue);
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
140218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			spin_unlock(&dum->lock);
140318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			req->req.complete(&ep->ep, &req->req);
140418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			spin_lock(&dum->lock);
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
14114d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (*status != -EINPROGRESS)
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
142118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int periodic_bytes(struct dummy *dum, struct dummy_ep *ep)
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
142929cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto		tmp = usb_endpoint_maxp(ep->desc);
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER) {
143559f08e6d2015a16fb4856f910ef0660d13a0c767Sebastian Andrzej Siewior		switch (usb_endpoint_type(ep->desc)) {
14361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_ISOC:
14371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.8.2 USB3.0 Spec */
14381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 16 * 1024 * 8;
14391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
14401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_INT:
14411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.7.2 USB3.0 Spec */
14421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 1024 * 8;
14431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
14441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_BULK:
14451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		default:
14461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
14471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
14481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1452cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman#define is_active(dum_hcd)	((dum_hcd->port_status & \
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic struct dummy_ep *find_endpoint(struct dummy *dum, u8 address)
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
14621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->ss_hcd : dum->hs_hcd)))
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
146518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		return &dum->ep[0];
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
146718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		struct dummy_ep	*ep = &dum->ep[i];
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
14878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman/**
14888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * handle_control_request() - handles all control transfers
14898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @dum: pointer to dummy (the_controller)
14908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @urb: the urb request to handle
14918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @setup: pointer to the setup data for a USB device control
14928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	 request
14938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @status: pointer to request handling status
14948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *
14958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * Return 0 - if the request was handled
14968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  1 - if the request wasn't handles
14978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  error code on error
14988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */
1499cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
15008be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  struct usb_ctrlrequest *setup,
15018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  int *status)
15028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman{
15038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	struct dummy_ep		*ep2;
1504cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
15058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	int			ret_val = 1;
15068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_index;
15078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_value;
15088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
15098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_index = le16_to_cpu(setup->wIndex);
15108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_value = le16_to_cpu(setup->wValue);
15118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	switch (setup->bRequest) {
15128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_ADDRESS:
15138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType != Dev_Request)
15148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			break;
15158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dum->address = w_value;
15168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		*status = 0;
15178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dev_dbg(udc_dev(dum), "set_address = %d\n",
15188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value);
15198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		ret_val = 0;
15208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
15218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_FEATURE:
15228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
15238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
15258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
15268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_B_HNP_ENABLE:
15288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.b_hnp_enable = 1;
15298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_HNP_SUPPORT:
15318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_hnp_support = 1;
15328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_ALT_HNP_SUPPORT:
15348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_alt_hnp_support = 1;
15358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
15371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
15401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
15441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
15471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
15511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
15541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
15588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
15598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
15618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus |= (1 << w_value);
15628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
15638be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
15658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
15668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
15678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2 || ep2->ep.name == ep0name) {
15688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
15698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2->halted = 1;
15728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
15748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
15758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
15768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_CLEAR_FEATURE:
15778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
15788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
15808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
15818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value = USB_DEVICE_REMOTE_WAKEUP;
15828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
15841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
15871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
15911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
15931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
15941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
15981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
15991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
16001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
16011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
16021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
16031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
16048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
16058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
16068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
16078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
16088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
16098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus &= ~(1 << w_value);
16108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
16118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
16128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
16138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
16148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
16158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2) {
16168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
16178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
16188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
16198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2->wedged)
16208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ep2->halted = 0;
16218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
16228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
16238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
16248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
16258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_GET_STATUS:
16268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_InRequest
16278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Intf_InRequest
16288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Ep_InRequest) {
16298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			char *buf;
16308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/*
16318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * device: remote wakeup, selfpowered
16328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * interface: nothing
16338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * endpoint: halt
16348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 */
16358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			buf = (char *)urb->transfer_buffer;
16368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 0) {
16378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				if (setup->bRequestType == Ep_InRequest) {
16388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					ep2 = find_endpoint(dum, w_index);
16398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					if (!ep2) {
16408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						ret_val = -EOPNOTSUPP;
16418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						break;
16428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					}
16438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = ep2->halted;
16448be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else if (setup->bRequestType ==
16458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					   Dev_InRequest) {
16468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = (u8)dum->devstatus;
16478be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else
16488be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = 0;
16498be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
16508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 1)
16518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				buf[1] = 0;
16528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			urb->actual_length = min_t(u32, 2,
16538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				urb->transfer_buffer_length);
16548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
16558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
16568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
16578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
16588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	}
16598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	return ret_val;
16608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman}
16618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1665cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void dummy_timer(unsigned long _dum_hcd)
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1667cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
1668cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case USB_SPEED_SUPER:
16861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* Bus speed is 500000 bytes/ms, so use a little less */
16871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		total = 490000;
16881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1690cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
169718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_lock_irqsave(&dum->lock, flags);
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1699cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1700cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd),
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
170218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		spin_unlock_irqrestore(&dum->lock, flags);
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
170718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		if (!ep_name[i])
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
170918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		dum->ep[i].already_seen = 0;
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
1713cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
17194d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int			status = -EINPROGRESS;
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
1722eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern		if (urb->unlinked)
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1724cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
1725391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
172618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		type = usb_pipetype(urb->pipe);
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
173718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		if (usb_pipein(urb->pipe))
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
1742cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
17454d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPROTO;
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
175218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		if (ep == &dum->ep[0] && urb->error_count) {
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
1758cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
17604d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPIPE;
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
176618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		if (ep == &dum->ep[0] && ep->setup_stage) {
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
177018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			setup = *(struct usb_ctrlrequest *) urb->setup_packet;
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
177218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			list_for_each_entry(req, &ep->queue, queue) {
177318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				list_del_init(&req->queue);
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
177518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				dev_dbg(udc_dev(dum), "stale req = %p\n",
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
177818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				spin_unlock(&dum->lock);
177918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				req->req.complete(&ep->ep, &req->req);
178018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				spin_lock(&dum->lock);
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1793cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			value = handle_control_request(dum_hcd, urb, &setup,
17948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						       &status);
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
180018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				spin_unlock(&dum->lock);
180118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				value = dum->driver->setup(&dum->gadget,
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
180318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior				spin_lock(&dum->lock);
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
181518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior					dev_dbg(udc_dev(dum),
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
18184d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				status = -EPIPE;
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
182718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		switch (usb_pipetype(urb->pipe)) {
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
183418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			limit = max(limit, periodic_bytes(dum, ep));
18354d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -ENOSYS;
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
184218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			limit = max(limit, periodic_bytes(dum, ep));
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
184618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiortreat_control_like_bulk:
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
1848a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			total = transfer(dum_hcd, urb, ep, limit, &status);
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
18534d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (status == -EINPROGRESS)
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
185718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		list_del(&urbp->urbp_list);
185818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		kfree(urbp);
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1862cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
186318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		spin_unlock(&dum->lock);
1864cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
186518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		spin_lock(&dum->lock);
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1870cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (list_empty(&dum_hcd->urbp_list)) {
1871cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_dev(dum_hcd->udev);
1872cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = NULL;
1873cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
1874391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1875cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
187818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	spin_unlock_irqrestore(&dum->lock, flags);
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1884c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1885c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1886c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1887c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1888c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
189018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_hub_status(struct usb_hcd *hcd, char *buf)
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1892cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1894391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1896cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1898cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1899541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1900391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1901f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1902cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
1903cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1904cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
1905cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1906f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1907f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1908cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
1910cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
1911cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status);
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1913cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
191418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior			usb_hcd_resume_root_hub(hcd);
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1916391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
1917cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
19221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanss_hub_descriptor(struct usb_hub_descriptor *desc)
19231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
19241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	memset(desc, 0, sizeof *desc);
19251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescriptorType = 0x2a;
19261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescLength = 12;
19271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->wHubCharacteristics = cpu_to_le16(0x0001);
19281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bNbrPorts = 1;
19291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
19301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.DeviceRemovable = 0xffff;
19311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
19321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
193318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline void hub_descriptor(struct usb_hub_descriptor *desc)
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
193518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	memset(desc, 0, sizeof *desc);
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1938fd05e720099e8eeddb378305d1a41c1445344b91Al Viro	desc->wHubCharacteristics = cpu_to_le16(0x0001);
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
1940dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[0] = 0xff;
1941dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[1] = 0xff;
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
194418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_hub_control(
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1952cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1956541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1957391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1958391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1959cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1960cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1961cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
19681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
19711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
19721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1974cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
1976cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->resuming = 1;
1977cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->re_timeout = jiffies +
1978f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
19821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
19841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
19851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
19861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
19871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status &
19881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SS_PORT_STAT_POWER)
19891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
19901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
1991f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1993cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~(1 << wValue);
1994cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
19981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3 &&
19991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(wLength < USB_DT_SS_HUB_SIZE ||
20001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 wValue != (USB_DT_SS_HUB << 8))) {
20011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"Wrong hub descriptor type for "
20031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"USB 3.0 roothub.\n");
20041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3)
20071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
20081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		else
20091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			hub_descriptor((struct usb_hub_descriptor *) buf);
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
201218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		*(__le32 *) buf = cpu_to_le32(0);
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2021cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->resuming &&
2022cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
2023cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
2024cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2026cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
2027cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
2028cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
2029cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
2030cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->dum->pullup) {
2031cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
20321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
20331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (hcd->speed < HCD_USB3) {
20341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					switch (dum_hcd->dum->gadget.speed) {
20351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_HIGH:
20361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
20371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						      USB_PORT_STAT_HIGH_SPEED;
20381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
20391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_LOW:
20401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.ep0->
20411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							maxpacket = 8;
20421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
20431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_PORT_STAT_LOW_SPEED;
20441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
20451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					default:
20461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.speed =
20471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SPEED_FULL;
20481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
20491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					}
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2053cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
205418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		((__le16 *) buf)[0] = cpu_to_le16(dum_hcd->port_status);
205518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		((__le16 *) buf)[1] = cpu_to_le16(dum_hcd->port_status >> 16);
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
20621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_LINK_STATE:
20631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
20641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
20651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_LINK_STATE req not "
20661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
20671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
20681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
20691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
20701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * Since this is dummy we don't have an actual link so
20711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * there is nothing to do for the SET_LINK_STATE cmd
20721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
20731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
20741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U1_TIMEOUT:
20751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U2_TIMEOUT:
20761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* TODO: add suspend/resume support! */
20771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
20781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
20791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
20801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
20811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
20821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
20831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
20851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB2.0 hub */
20861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
20871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
20881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
20891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
20901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
20911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
2092cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->active) {
2093cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
2094f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
2095f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
2096f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
2097f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
2098cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				set_link_state(dum_hcd);
2099f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
2100cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman						& dum_hcd->dum->devstatus) != 0)
2101cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
21025742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2105f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
21061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3)
21071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
21081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else
21091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_POWER;
2110cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
2111f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
21121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_BH_PORT_RESET:
21131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB3.0 hub */
21141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
21151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
21161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_BH_PORT_RESET req not "
21171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
21181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
21191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
21201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* FALLS THROUGH */
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
2122f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
21231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
21241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status = 0;
21251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status =
21261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_SS_PORT_STAT_POWER |
21271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_CONNECTION |
21281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_RESET);
21291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
21301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
2131f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
2132f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
2133cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			/*
2134cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * We want to reset device status. All but the
2135cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * Self powered feature
2136cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 */
2137cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->dum->devstatus &=
2138cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				(1 << USB_DEVICE_SELF_POWERED);
21391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
21401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * FIXME USB3.0: what is the correct reset signaling
21411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * interval? Is it still 50msec as for HS?
21421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
2143cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
2144f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
21461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
21471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
21481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_SS_PORT_STAT_POWER) != 0) {
21491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
21501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
21511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
21521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
21531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
21541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_PORT_STAT_POWER) != 0) {
21551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
21561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
21571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
21581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
21591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
21601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case GetPortErrorCount:
21611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
21621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
21631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "GetPortErrorCount req not "
21641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "supported for USB 2.0 roothub\n");
21651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
21661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
21671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* We'll always return 0 since this is a dummy hub */
21681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		*(__le32 *) buf = cpu_to_le32(0);
21691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
21701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case SetHubDepth:
21711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
21721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
21731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "SetHubDepth req not supported for "
21741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "USB 2.0 roothub\n");
21751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd),
21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
21821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanerror:
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2186cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2187685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
2188cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
218918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		usb_hcd_poll_rh_status(hcd);
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
219318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_bus_suspend(struct usb_hcd *hcd)
2194391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2195cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2196391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
219718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
21983cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2199cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2200cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
2201cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	set_link_state(dum_hcd);
22023cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd->state = HC_STATE_SUSPENDED;
2203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
2204391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2205391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2206391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
220718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_bus_resume(struct usb_hcd *hcd)
2208391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2209cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
22103cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int rc = 0;
22113cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
221218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
2213391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2214cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2215541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd)) {
2216cfa59dab27d1b282886e7772a8f9548236883892Alan Stern		rc = -ESHUTDOWN;
22173cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else {
2218cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->rh_state = DUMMY_RH_RUNNING;
2219cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
2220cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (!list_empty(&dum_hcd->urbp_list))
2221cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			mod_timer(&dum_hcd->timer, jiffies);
22223cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		hcd->state = HC_STATE_RUNNING;
22233cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	}
2224cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
22253cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2226391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)
22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
223218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	int ep = usb_pipeendpoint(urb->pipe);
22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	return snprintf(buf, size,
22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
223818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		switch (urb->dev->speed) {
223918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		case USB_SPEED_LOW:
22407c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "ls";
22417c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
224218f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		case USB_SPEED_FULL:
22437c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "fs";
22447c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
224518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		case USB_SPEED_HIGH:
22467c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "hs";
22477c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
224818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		case USB_SPEED_SUPER:
22491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			s = "ss";
22501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
225118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		default:
22527c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "?";
22537c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
225518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "",
22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
225718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		switch (usb_pipetype(urb->pipe)) { \
225818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		case PIPE_CONTROL: \
22597c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = ""; \
22607c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
226118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		case PIPE_BULK: \
22627c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-bulk"; \
22637c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
226418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		case PIPE_INTERRUPT: \
22657c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-int"; \
22667c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
226718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		default: \
22687c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-iso"; \
22697c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
227018f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		}; s; }),
22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
227418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic ssize_t show_urbs(struct device *dev, struct device_attribute *attr,
227518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		char *buf)
22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
227718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	struct usb_hcd		*hcd = dev_get_drvdata(dev);
2278cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2283cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2284cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
228718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior		temp = show_urb(buf, PAGE_SIZE - size, urbp->urb);
22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2291cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
229518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic DEVICE_ATTR(urbs, S_IRUGO, show_urbs, NULL);
22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic int dummy_start_ss(struct dummy_hcd *dum_hcd)
22981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	init_timer(&dum_hcd->timer);
23001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.function = dummy_timer;
23011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
23021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
2303a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	dum_hcd->stream_en_ep = 0;
23041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
23051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
23061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
23071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
23081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#ifdef CONFIG_USB_OTG
23091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
23101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#endif
23111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
23121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
23141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
23151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
23161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2317cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_start(struct usb_hcd *hcd)
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2319cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
23261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!usb_hcd_is_primary_hcd(hcd))
23271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dummy_start_ss(dum_hcd);
23281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2329cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_init(&dum_hcd->dum->lock);
2330cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	init_timer(&dum_hcd->timer);
2331cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.function = dummy_timer;
2332cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
2333cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2335cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2337caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern	hcd->power_budget = POWER_BUDGET;
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
2339685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23415742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
23425742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
23435742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
23445742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
2346cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
234918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void dummy_stop(struct usb_hcd *hcd)
23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
235318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dum = hcd_to_dummy_hcd(hcd)->dum;
2354cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
2355cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_gadget_unregister_driver(dum->driver);
2356cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
236118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_h_get_frame(struct usb_hcd *hcd)
23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
236318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	return dummy_g_get_frame(NULL);
23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2366cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_setup(struct usb_hcd *hcd)
2367cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman{
236814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	hcd->self.sg_tablesize = ~0;
2369cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (usb_hcd_is_primary_hcd(hcd)) {
2370cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
2371cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd->dum = &the_controller;
23721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
23731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * Mark the first roothub as being USB 2.0.
23741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * The USB 3.0 roothub will be registered later by
23751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * dummy_hcd_probe()
23761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
2377cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->speed = HCD_USB2;
2378cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_HIGH;
23791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
23801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
23811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd->dum = &the_controller;
23821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->speed = HCD_USB3;
23831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_SUPER;
2384cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	}
2385cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return 0;
2386cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman}
2387cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
23881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Change a group of bulk endpoints to support multiple stream IDs */
2389d81f3e4f5792acab5929ef99aad6ca5e21a31a0eSebastian Andrzej Siewiorstatic int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
23901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
23911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	unsigned int num_streams, gfp_t mem_flags)
23921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2393a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2394a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned long flags;
2395a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int max_stream;
2396a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int ret_streams = num_streams;
2397a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int index;
2398a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int i;
2399a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2400a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	if (!num_eps)
2401a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		return -EINVAL;
2402a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2403a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2404a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	for (i = 0; i < num_eps; i++) {
2405a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index = dummy_get_ep_idx(&eps[i]->desc);
2406a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if ((1 << index) & dum_hcd->stream_en_ep) {
2407a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			ret_streams = -EINVAL;
2408a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			goto out;
2409a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
2410a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		max_stream = usb_ss_max_streams(&eps[i]->ss_ep_comp);
2411a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (!max_stream) {
2412a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			ret_streams = -EINVAL;
2413a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			goto out;
2414a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
2415a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (max_stream < ret_streams) {
2416a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			dev_dbg(dummy_dev(dum_hcd), "Ep 0x%x only supports %u "
2417a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior					"stream IDs.\n",
2418a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior					eps[i]->desc.bEndpointAddress,
2419a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior					max_stream);
2420a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			ret_streams = max_stream;
2421a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
2422a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
2423a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2424a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	for (i = 0; i < num_eps; i++) {
2425a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index = dummy_get_ep_idx(&eps[i]->desc);
2426a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		dum_hcd->stream_en_ep |= 1 << index;
2427a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		set_max_streams_for_pipe(dum_hcd,
2428a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior				usb_endpoint_num(&eps[i]->desc), ret_streams);
2429a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
2430a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorout:
2431a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2432a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return ret_streams;
24331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
24341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
24351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Reverts a group of bulk endpoints back to not using stream IDs. */
2436d81f3e4f5792acab5929ef99aad6ca5e21a31a0eSebastian Andrzej Siewiorstatic int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
24371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
24381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	gfp_t mem_flags)
24391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2440a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2441a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned long flags;
2442a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	int ret;
2443a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int index;
2444a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	unsigned int i;
2445a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2446a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2447a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	for (i = 0; i < num_eps; i++) {
2448a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index = dummy_get_ep_idx(&eps[i]->desc);
2449a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		if (!((1 << index) & dum_hcd->stream_en_ep)) {
2450a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			ret = -EINVAL;
2451a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior			goto out;
2452a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		}
2453a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
2454a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior
2455a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	for (i = 0; i < num_eps; i++) {
2456a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		index = dummy_get_ep_idx(&eps[i]->desc);
2457a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		dum_hcd->stream_en_ep &= ~(1 << index);
2458a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior		set_max_streams_for_pipe(dum_hcd,
2459a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior				usb_endpoint_num(&eps[i]->desc), 0);
2460a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	}
2461a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	ret = 0;
2462a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewiorout:
2463a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2464a54c979fed31b4230b2e63132f7167206e4e5d69Sebastian Andrzej Siewior	return ret;
24651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
24661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
24671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct hc_driver dummy_hcd = {
24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
2470cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.hcd_priv_size =	sizeof(struct dummy_hcd),
24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.flags =		HCD_USB3 | HCD_SHARED,
24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2474cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.reset =		dummy_setup,
24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
247818f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	.urb_enqueue =		dummy_urb_enqueue,
247918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	.urb_dequeue =		dummy_urb_dequeue,
24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
248118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	.get_frame_number =	dummy_h_get_frame,
24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
248318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	.hub_status_data =	dummy_hub_status,
248418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	.hub_control =		dummy_hub_control,
24850c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_suspend =		dummy_bus_suspend,
24860c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_resume =		dummy_bus_resume,
24871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
24881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.alloc_streams =	dummy_alloc_streams,
24891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.free_streams =		dummy_free_streams,
24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24928364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev)
24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2494cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_hcd		*hs_hcd;
24951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_hcd		*ss_hcd;
24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24988364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!mod_data.is_super_speed)
25011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dummy_hcd.flags = HCD_USB2;
2502cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
2503cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!hs_hcd)
25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2505cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd->has_tt = 1;
25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2507cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	retval = usb_add_hcd(hs_hcd, 0, 0);
25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
2509cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_hcd(hs_hcd);
25101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return retval;
25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
25131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (mod_data.is_super_speed) {
25141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
25151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_name(&pdev->dev), hs_hcd);
25161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (!ss_hcd) {
25171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			retval = -ENOMEM;
25181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto dealloc_usb2_hcd;
25191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
25201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
25211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		retval = usb_add_hcd(ss_hcd, 0, 0);
25221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (retval)
25231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto put_usb3_hcd;
25241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
25251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
25261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
25271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanput_usb3_hcd:
25281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(ss_hcd);
25291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmandealloc_usb2_hcd:
25301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(hs_hcd);
25311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2535cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_hcd_remove(struct platform_device *pdev)
25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2537cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum;
2538cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
253918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dum = hcd_to_dummy_hcd(platform_get_drvdata(pdev))->dum;
25401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
25411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->ss_hcd) {
25421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
25431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
25441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
25451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2546cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2547cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
25481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2549cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	the_controller.hs_hcd = NULL;
25501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.ss_hcd = NULL;
25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2552d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
255518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_hcd_suspend(struct platform_device *pdev, pm_message_t state)
2556391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2557391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2558cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
25593cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int			rc = 0;
2560391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
256118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
2562391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
256318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	hcd = platform_get_drvdata(pdev);
2564cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
2565cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
25663cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
25673cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		rc = -EBUSY;
25683cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else
25693cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
25703cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2571391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2572391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
257318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int dummy_hcd_resume(struct platform_device *pdev)
2574391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2575391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2576391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
257718f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
2578391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
257918f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	hcd = platform_get_drvdata(pdev);
25803cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
258118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	usb_hcd_poll_rh_status(hcd);
2582391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2583391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2584391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
25853ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = {
2586d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
2587d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
2588391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
2589391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
25903ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
25913ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) driver_name,
25923ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
25933ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2594d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2596d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2598a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_udc_pdev;
2599a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_hcd_pdev;
26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
260118f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic int __init init(void)
26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2603a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	int	retval = -ENOMEM;
26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
260518f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewior	if (usb_disabled())
26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2607d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
26087eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	if (!mod_data.is_high_speed && mod_data.is_super_speed)
26097eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		return -EINVAL;
26107eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman
2611a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_hcd_pdev = platform_device_alloc(driver_name, -1);
2612a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_hcd_pdev)
26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
2614a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_udc_pdev = platform_device_alloc(gadget_name, -1);
2615a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_udc_pdev)
2616a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_alloc_udc;
2617d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2618a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_hcd_driver);
2619a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (retval < 0)
2620a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_register_hcd_driver;
2621a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_udc_driver);
2622d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2623d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2624d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2625a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_hcd_pdev);
2626d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2627a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_hcd;
26281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!the_controller.hs_hcd ||
26291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	    (!the_controller.ss_hcd && mod_data.is_super_speed)) {
2630865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2631865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The hcd was added successfully but its probe function failed
2632865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2633865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2634865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2635865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_add_udc;
2636865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2637a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_udc_pdev);
2638d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2639a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_udc;
2640865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	if (!platform_get_drvdata(the_udc_pdev)) {
2641865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2642865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The udc was added successfully but its probe function failed
2643865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2644865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2645865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2646865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_probe_udc;
2647865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2648d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2649d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2650865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewiorerr_probe_udc:
2651865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	platform_device_del(the_udc_pdev);
2652a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_udc:
2653a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_del(the_hcd_pdev);
2654a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_hcd:
2655a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2656d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
2657a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
2658a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_register_hcd_driver:
2659a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_udc_pdev);
2660a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_alloc_udc:
2661a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_hcd_pdev);
26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
266418f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiormodule_init(init);
26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
266618f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiorstatic void __exit cleanup(void)
26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2668a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_udc_pdev);
2669a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_hcd_pdev);
2670a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2671a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
267318f2cbaa2b9617eed20789ce40878920a8ea6bebSebastian Andrzej Siewiormodule_exit(cleanup);
2674