dummy_hcd.c revision a04ce20d9f5e9484ed3879e1290bd05933cbbe2a
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maintainer: Alan Stern <stern@rowland.harvard.edu>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 David Brownell
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003-2005 Alan Stern
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This exposes a device side "USB gadget" API, driven by requests to a
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux-USB host controller driver.  USB traffic is simulated; there's
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no need for USB hardware.  Use this with two other drivers:
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Gadget driver, responding to requests (slave);
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Host-side device driver, as already familiar in Linux.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Having this all in one kernel can help some stages of development,
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bypassing some hardware (and driver) issues.  UML could help too.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
38d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
409454a57ab5922e5cd25321cae9d1a8cbeb3e2e85David Brownell#include <linux/usb/gadget.h>
4127729aadd31dafddaaf64c24f8ef6d0ff750f3aaEric Lescouet#include <linux/usb/hcd.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC	"USB Host+Gadget Emulator"
51391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION	"02 May 2005"
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern#define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
54caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_name [] = "dummy_hcd";
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_desc [] = "USB Host+Gadget Emulator";
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	gadget_name [] = "dummy_udc";
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell");
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL");
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstruct dummy_hcd_module_parameters {
651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	bool is_super_speed;
667eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	bool is_high_speed;
671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct dummy_hcd_module_parameters mod_data = {
707eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_super_speed = false,
717eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_high_speed = true,
721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanmodule_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana BrokhmanMODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
757eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhmanmodule_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
767eca4c5a8b73f22ad16ad6e76b901351732355daTatyana BrokhmanMODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep {
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			last_io;	/* jiffies timestamp */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		*gadget;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usb_endpoint_descriptor *desc;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep			ep;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			halted : 1;
87851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	unsigned			wedged : 1;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			already_seen : 1;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			setup_stage : 1;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request {
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;		/* ep's requests */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_request		req;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_ep, struct dummy_ep, ep);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(struct usb_request *_req)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_req, struct dummy_request, req);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints,
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types:
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Configurable:  direction (in/out), type (bulk, iso, etc), and endpoint
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     number can be changed.  Names like "ep-a" are used for this type.
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Fixed Function:  in other cases.  some characteristics may be mutable;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     that'd be hardware-specific.  Names like "ep12out-bulk" are used.
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on.
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0";
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep0name,				/* everyone has ep0 */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* act like a net2280: high speed, six configurable endpoints */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like pxa250: fifteen fixed function endpoints */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ep15in-int",
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like sa1100: two fixed function endpoints */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1out-bulk", "ep2in-bulk",
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
14152950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS	ARRAY_SIZE(ep_name)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
144d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE		64
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp {
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb		*urb;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head	urbp_list;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
153391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state {
154391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RESET,
155391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_SUSPENDED,
156391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RUNNING
157391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern};
158391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
159cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstruct dummy_hcd {
160cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy			*dum;
161cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	enum dummy_rh_state		rh_state;
162cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct timer_list		timer;
163cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				port_status;
164cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				old_status;
165cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned long			re_timeout;
166cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
167cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_device		*udev;
168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct list_head		urbp_list;
169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			active:1;
171cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			old_active:1;
172cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			resuming:1;
173cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman};
174cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy {
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t			lock;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE/GADGET side support
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep			ep [DUMMY_ENDPOINTS];
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				address;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		gadget;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget_driver	*driver;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request		fifo_req;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8				fifo_buf [FIFO_SIZE];
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16				devstatus;
188391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned			udc_suspended:1;
189f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			pullup:1;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER/HOST side support
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
194cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd		*hs_hcd;
1951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy_hcd		*ss_hcd;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
200cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return (struct dummy_hcd *) (hcd->hcd_priv);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of((void *) dum, struct usb_hcd, hcd_priv);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
208cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct device *dummy_dev(struct dummy_hcd *dum)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
210cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return dummy_hcd_to_hcd(dum)->self.controller;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
213d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum)
214d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
215d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return dum->gadget.dev.parent;
216d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
217d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (ep->gadget, struct dummy, gadget);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
225cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = container_of(gadget, struct dummy, gadget);
2261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER)
2271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->ss_hcd;
2281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	else
2291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->hs_hcd;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (dev, struct dummy, gadget.dev);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
237cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic struct dummy			the_controller;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */
242f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
243f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */
244f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep)
245f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
246f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	while (!list_empty (&ep->queue)) {
247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		struct dummy_request	*req;
248f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req = list_entry (ep->queue.next, struct dummy_request, queue);
250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		list_del_init (&req->queue);
251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.status = -ESHUTDOWN;
252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_unlock (&dum->lock);
254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.complete (&ep->ep, &req->req);
255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_lock (&dum->lock);
256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum)
262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy_ep	*ep;
264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* prevent any more requests */
266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->address = 0;
267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* The timer is left running so that outstanding URBs can fail */
269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* nuke any pending requests first, so driver i/o is quiesced */
271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		nuke (dum, ep);
273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
274f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* driver now does any non-usb quiescing necessary */
275f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
2771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/**
2781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * set_link_state_by_speed() - Sets the current state of the link according to
2791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *	the hcd speed
2801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
2811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *
2821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * This function updates the port_status according to the link state and the
2831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * speed of the hcd.
2841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */
2851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
2861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy *dum = dum_hcd->dum;
2881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) {
2901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) {
2911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
2921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
2931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
2941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
2951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE);
2961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
2971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
2981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
2991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* device is connected and not suspended */
3021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
3031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						 USB_PORT_STAT_SPEED_5GBPS) ;
3041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status &
3091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_ENABLE) == 1 &&
3101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(dum_hcd->port_status &
3111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 USB_SS_PORT_LS_U0) == 1 &&
3121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
3161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) {
3171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
3181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
3191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
3201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
3211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE |
3221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_LOW_SPEED |
3231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_HIGH_SPEED |
3241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_SUSPEND);
3251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
3311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
3361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
3371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else if ((dum_hcd->port_status &
3381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				  USB_PORT_STAT_SUSPEND) == 0 &&
3391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
3431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
3441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
345f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
346cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void set_link_state(struct dummy_hcd *dum_hcd)
347f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
348cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = dum_hcd->dum;
349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
350cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->active = 0;
3511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->pullup)
3521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
3531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed != USB_SPEED_SUPER) ||
3541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
3551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed == USB_SPEED_SUPER))
3561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			return;
3571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
3581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	set_link_state_by_speed(dum_hcd);
359f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
360cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
361cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	     dum_hcd->active)
362cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->resuming = 0;
363f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* if !connected or reset */
365cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
366cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
3671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
3681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * We're connected and not reset (reset occurred now),
3691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * and driver attached - disconnect!
3701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
371cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
3721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
3731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    dum->driver) {
3741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			stop_activity(dum);
3751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->disconnect(&dum->gadget);
3771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
378f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
379cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->active != dum_hcd->old_active) {
380cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->old_active && dum->driver->suspend) {
3811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->suspend(&dum->gadget);
3831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
3841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
3851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->resume(&dum->gadget);
3871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
388f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
389f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
390f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
391cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_status = dum_hcd->port_status;
392cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_active = dum_hcd->active;
393f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
394f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
395f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/
396f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state.  All the work is done when the host
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation.  Real device controller
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc.
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(dum->port_status & USB_PORT_STAT_ENABLE)
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
411cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		max;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !desc || ep->desc || _ep->name == ep0name
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| desc->bDescriptorType != USB_DT_ENDPOINT)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
421cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver)
422cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		return -ESHUTDOWN;
423719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior
424719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
425cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!is_enabled(dum_hcd))
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
427cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
428cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	/*
429cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
430cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * maximum packet size.
4311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	 * For SS devices the wMaxPacketSize is limited by 1024.
432cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 */
43329cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto	max = usb_endpoint_maxp(desc) & 0x7ff;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* drivers must not request bad settings, since lower levels
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (hardware or its drivers) may not check.  some endpoints
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't do iso, many have maxpacket limitations, etc.
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since this "hardware" driver is here to help debugging, we
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have some extra sanity checks.  (there could be more though,
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially for "ep9out" style fixed function ones.)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = -EINVAL;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (desc->bmAttributes & 0x03) {
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_BULK:
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int")) {
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (max == 1024)
4531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
4541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto done;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max == 512)
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4589063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4599063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		case USB_SPEED_FULL:
4609063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			if (max == 8 || max == 16 || max == 32 || max == 64)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we'll fake any legal size */
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4639063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			/* save a return statement */
4649063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		default:
4659063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_INT:
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 64)
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 8)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_ISOC:
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-bulk")
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int"))
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1023)
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* few chips support control except on ep0 */
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_ep->maxpacket = max;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = desc;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
515d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_ep->name,
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		desc->bEndpointAddress & 0x0f,
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *val;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (desc->bmAttributes & 0x03) {
5217c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_BULK:
5227c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "bulk";
5237c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5247c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_ISOC:
5257c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "iso";
5267c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5277c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_INT:
5287c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "intr";
5297c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5307c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
5317c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "ctrl";
5327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; val; }),
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		max);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* at this point real hardware should be NAKing transfers
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to that endpoint, until a buffer is queued to it.
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
539851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	ep->halted = ep->wedged = 0;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep)
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !ep->desc || _ep->name == ep0name)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = NULL;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nuke (dum, ep);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
563d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request *
56855016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5777039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn	req = kzalloc(sizeof(*req), mem_flags);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!req)
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&req->queue);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &req->req;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON (!list_empty (&req->queue));
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (req);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req)
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6055db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req,
60655016f10e31bb15b85d8c500f979dfdceb37d548Al Viro		gfp_t mem_flags)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
611cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_req || !list_empty (&req->queue) || !_req->complete)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
623719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
624cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver || !is_enabled(dum_hcd))
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
628d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&dum->fifo_req.queue) &&
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&ep->queue) &&
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy (dum->fifo_buf, _req->buf, _req->length);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
648c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
654c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell	}  else
655c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
680b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_save (flags);
681b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_lock (&dum->lock);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
690b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_unlock (&dum->lock);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
693d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		dev_dbg (udc_dev(dum),
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
698b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_restore (flags);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
703851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
715851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		ep->halted = ep->wedged = 0;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!list_empty (&ep->queue))
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
719851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	else {
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
721851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		if (wedged)
722851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern			ep->wedged = 1;
723851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	}
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
728851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int
729851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt(struct usb_ep *_ep, int value)
730851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
731851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, value, 0);
732851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
733851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
734851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int dummy_set_wedge(struct usb_ep *_ep)
735851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
736851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	if (!_ep || _ep->name == ep0name)
737851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		return -EINVAL;
738851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, 1, 1);
739851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
740851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
752851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	.set_wedge	= dummy_set_wedge,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget)
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday (&tv);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget)
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
768cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
770cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = gadget_to_dummy_hcd(_gadget);
771cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
7725742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
774cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
775391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
776cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
777cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
778391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
779391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
780391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
783cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->resuming = 1;
784cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
785cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
793cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (gadget_to_dummy_hcd(_gadget))->dum;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewiorstatic void dummy_udc_udpate_ep0(struct dummy *dum)
802b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior{
803c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	if (dum->gadget.speed == USB_SPEED_SUPER)
804b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 9;
805c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	else
806b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 64;
807b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior}
808b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
809f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value)
810f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
811d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd;
812f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
813f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
814f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
815b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	dum = gadget_dev_to_dummy(&_gadget->dev);
816b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
817b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	if (value && dum->driver) {
818b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		if (mod_data.is_super_speed)
8197177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz			dum->gadget.speed = dum->driver->max_speed;
820b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else if (mod_data.is_high_speed)
821b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
8227177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz					dum->driver->max_speed);
823b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else
824b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = USB_SPEED_FULL;
825b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dummy_udc_udpate_ep0(dum);
826b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
8277177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz		if (dum->gadget.speed < dum->driver->max_speed)
828b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dev_dbg(udc_dev(dum), "This device can perform faster"
8297177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				" if you connect it to a %s port...\n",
8307177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				usb_speed_string(dum->driver->max_speed));
831b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	}
832d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(_gadget);
833d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior
834f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
835f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
836d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
837f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
838b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
839d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
840f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
841f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
842f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
843aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
844aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
845aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
846aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
8470f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
852f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
853aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_start	= dummy_udc_start,
854aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_stop	= dummy_udc_stop,
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
86110523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf)
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = gadget_dev_to_dummy (dev);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
869cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
887aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
888aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
890aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
891aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8937177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz	if (driver->max_speed == USB_SPEED_UNKNOWN)
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9005742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
904d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
909aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
910aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
912aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
913aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
915d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
9192542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior
9202542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior	dummy_pullup(&dum->gadget, 0);
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
926d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
927d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
928d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
929d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev)
930d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
931cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return;
932d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
933d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9340fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewiorstatic void init_dummy_udc_hw(struct dummy *dum)
9350fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior{
9360fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	int i;
9370fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9380fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->gadget.ep_list);
9390fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
9400fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		struct dummy_ep	*ep = &dum->ep[i];
9410fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9420fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		if (!ep_name[i])
9430fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior			break;
9440fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.name = ep_name[i];
9450fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.ops = &dummy_ep_ops;
9460fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
9470fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->halted = ep->wedged = ep->already_seen =
9480fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior				ep->setup_stage = 0;
9490fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.maxpacket = ~0;
950c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior		ep->ep.max_streams = 16;
9510fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->last_io = jiffies;
9520fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->gadget = &dum->gadget;
9530fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->desc = NULL;
9540fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		INIT_LIST_HEAD(&ep->queue);
9550fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	}
9560fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9570fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	dum->gadget.ep0 = &dum->ep[0].ep;
9580fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	list_del_init(&dum->ep[0].ep.ep_list);
9590fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->fifo_req.queue);
960f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior
961f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#ifdef CONFIG_USB_OTG
962f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior	dum->gadget.is_otg = 1;
963f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#endif
9640fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior}
9650fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9668364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_probe (struct platform_device *pdev)
967d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
968cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy	*dum = &the_controller;
969d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
970d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
971d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
972d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
973d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz	dum->gadget.max_speed = USB_SPEED_SUPER;
974d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9750031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers	dev_set_name(&dum->gadget.dev, "gadget");
9768364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dum->gadget.dev.parent = &pdev->dev;
977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
978d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	rc = device_register (&dum->gadget.dev);
97975d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	if (rc < 0) {
98075d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar		put_device(&dum->gadget.dev);
981d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
98275d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	}
983d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9840fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	init_dummy_udc_hw(dum);
9850fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9860f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
9870f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	if (rc < 0)
9880f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_udc;
9890f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
990efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
991efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if (rc < 0)
9920f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_dev;
9930f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	platform_set_drvdata(pdev, dum);
9940f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	return rc;
9950f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
9960f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_dev:
9970f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
9980f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_udc:
9990f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	device_unregister(&dum->gadget.dev);
1000d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
1001d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1002d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10038364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_remove (struct platform_device *pdev)
1004d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
10058364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	struct dummy	*dum = platform_get_drvdata (pdev);
1006d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10070f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10088364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	platform_set_drvdata (pdev, NULL);
1009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_remove_file (&dum->gadget.dev, &dev_attr_function);
1010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_unregister (&dum->gadget.dev);
1011d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
1012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1013d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1014fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd,
1015fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior		int suspend)
1016391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1017fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_lock_irq(&dum->lock);
1018fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dum->udc_suspended = suspend;
1019d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
1020fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_unlock_irq(&dum->lock);
1021fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior}
1022fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior
1023fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state)
1024fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior{
1025fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1026fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1027391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1028fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1029fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 1);
1030d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1031391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1032391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1033391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1034fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_resume(struct platform_device *pdev)
1035391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1036fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1037fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1038391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1039fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1040fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 0);
1041d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1042391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1043391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1044391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
10453ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = {
1046d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
1047d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
1048391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
1049391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
10503ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
10513ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) gadget_name,
10523ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
10533ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
1054d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
1055d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue (
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
107355016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t				mem_flags
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1075cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
1078e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urb->transfer_buffer && urb->transfer_buffer_length)
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp = kmalloc (sizeof *urbp, mem_flags);
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1088cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1089cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1090e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_link_urb_to_ep(hcd, urb);
1091e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	if (rc) {
1092e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		kfree(urbp);
1093e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		goto done;
1094e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	}
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1096cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1097cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = urb->dev;
1098cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_get_dev(dum_hcd->udev);
1099cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (unlikely(dum_hcd->udev != urb->dev))
1100cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1102cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
1108cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!timer_pending(&dum_hcd->timer))
1109cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + 1);
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done:
1112cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1113e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1116e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1118cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
1119391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1120e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
1121391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1122391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1123391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1124cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1125cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1126e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1127e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1128cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
1129cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			!list_empty(&dum_hcd->urbp_list))
1130cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies);
1131e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1132cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1133e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1136a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewiorstatic int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
1137a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior		u32 len)
1138a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior{
1139a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	void *ubuf, *rbuf;
1140a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	int to_host;
1141a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
1142a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	to_host = usb_pipein(urb->pipe);
1143a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	rbuf = req->req.buf + req->req.actual;
1144a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	ubuf = urb->transfer_buffer + urb->actual_length;
1145a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
1146a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	if (to_host)
1147a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior		memcpy(ubuf, rbuf, len);
1148a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	else
1149a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior		memcpy(rbuf, ubuf, len);
1150a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	return len;
1151a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior}
1152a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11554d2f110c51eec853c50f68cf068888a77551c8d3Alan Sterntransfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
11564d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int *status)
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min (host_len, dev_len);
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_host = usb_pipein (urb->pipe);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely (len == 0))
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = min (len, (unsigned) limit);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1198a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior			len = dummy_perform_transfer(urb, req, len);
1199a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit -= len;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->actual_length += len;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.actual += len;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
1212b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern		 * need to emulate such data-in-flight.
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12174d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
12214d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = -EOVERFLOW;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
12234d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = 0;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
12254d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
12394d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern						& URB_ZERO_PACKET))
12404d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock (&dum->lock);
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.complete (&ep->ep, &req->req);
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock (&dum->lock);
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
12564d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (*status != -EINPROGRESS)
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
127429cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto		tmp = usb_endpoint_maxp(ep->desc);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER) {
12801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		switch (ep->desc->bmAttributes & 0x03) {
12811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_ISOC:
12821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.8.2 USB3.0 Spec */
12831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 16 * 1024 * 8;
12841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
12851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_INT:
12861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.7.2 USB3.0 Spec */
12871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 1024 * 8;
12881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
12891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_BULK:
12901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		default:
12911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
12921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
12931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1297cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman#define is_active(dum_hcd)	((dum_hcd->port_status & \
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
13071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->ss_hcd : dum->hs_hcd)))
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return &dum->ep [0];
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
13328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman/**
13338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * handle_control_request() - handles all control transfers
13348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @dum: pointer to dummy (the_controller)
13358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @urb: the urb request to handle
13368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @setup: pointer to the setup data for a USB device control
13378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	 request
13388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @status: pointer to request handling status
13398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *
13408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * Return 0 - if the request was handled
13418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  1 - if the request wasn't handles
13428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  error code on error
13438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */
1344cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
13458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  struct usb_ctrlrequest *setup,
13468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  int *status)
13478be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman{
13488be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	struct dummy_ep		*ep2;
1349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
13508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	int			ret_val = 1;
13518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_index;
13528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_value;
13538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
13548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_index = le16_to_cpu(setup->wIndex);
13558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_value = le16_to_cpu(setup->wValue);
13568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	switch (setup->bRequest) {
13578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_ADDRESS:
13588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType != Dev_Request)
13598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			break;
13608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dum->address = w_value;
13618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		*status = 0;
13628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dev_dbg(udc_dev(dum), "set_address = %d\n",
13638be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value);
13648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		ret_val = 0;
13658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
13668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_FEATURE:
13678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
13688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
13698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
13708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
13718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_B_HNP_ENABLE:
13738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.b_hnp_enable = 1;
13748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_HNP_SUPPORT:
13768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_hnp_support = 1;
13778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_ALT_HNP_SUPPORT:
13798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_alt_hnp_support = 1;
13808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
13811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
13821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
13831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
13841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
13851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
13861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
13871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
13881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
13891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
13901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
13911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
13921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
13931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
13941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
13951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
13961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
13971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
13981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
13991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
14038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
14068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus |= (1 << w_value);
14078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
14088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
14108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
14118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
14128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2 || ep2->ep.name == ep0name) {
14138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2->halted = 1;
14178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
14198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
14208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_CLEAR_FEATURE:
14228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
14238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
14258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
14268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value = USB_DEVICE_REMOTE_WAKEUP;
14278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
14291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
14321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
14361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
14391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
14431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
14461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14498be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
14508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
14548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus &= ~(1 << w_value);
14558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
14568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
14588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
14598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
14608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2) {
14618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14638be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2->wedged)
14658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ep2->halted = 0;
14668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
14688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
14698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_GET_STATUS:
14718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_InRequest
14728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Intf_InRequest
14738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Ep_InRequest) {
14748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			char *buf;
14758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/*
14768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * device: remote wakeup, selfpowered
14778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * interface: nothing
14788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * endpoint: halt
14798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 */
14808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			buf = (char *)urb->transfer_buffer;
14818be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 0) {
14828be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				if (setup->bRequestType == Ep_InRequest) {
14838be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					ep2 = find_endpoint(dum, w_index);
14848be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					if (!ep2) {
14858be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						ret_val = -EOPNOTSUPP;
14868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						break;
14878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					}
14888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = ep2->halted;
14898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else if (setup->bRequestType ==
14908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					   Dev_InRequest) {
14918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = (u8)dum->devstatus;
14928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else
14938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = 0;
14948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 1)
14968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				buf[1] = 0;
14978be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			urb->actual_length = min_t(u32, 2,
14988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				urb->transfer_buffer_length);
14998be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15008be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
15018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
15028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
15038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	}
15048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	return ret_val;
15058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman}
15068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1510cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void dummy_timer(unsigned long _dum_hcd)
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1512cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
1513cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case USB_SPEED_SUPER:
15311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* Bus speed is 500000 bytes/ms, so use a little less */
15321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		total = 490000;
15331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1535cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1544cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1545cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd),
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&dum->lock, flags);
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->ep [i].already_seen = 0;
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
1558cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
15644d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int			status = -EINPROGRESS;
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
1567eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern		if (urb->unlinked)
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1569cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
1570391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = usb_pipetype (urb->pipe);
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (usb_pipein (urb->pipe))
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
1587cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
15904d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPROTO;
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && urb->error_count) {
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
1603cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
16054d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPIPE;
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && ep->setup_stage) {
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_for_each_entry (req, &ep->queue, queue) {
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				list_del_init (&req->queue);
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
1620d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "stale req = %p\n",
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.complete (&ep->ep, &req->req);
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1638cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			value = handle_control_request(dum_hcd, urb, &setup,
16398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						       &status);
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = dum->driver->setup (&dum->gadget,
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
1660d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern					dev_dbg (udc_dev(dum),
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
16634d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				status = -EPIPE;
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (usb_pipetype (urb->pipe)) {
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
16804d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -ENOSYS;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// case PIPE_BULK:  case PIPE_CONTROL:
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		treat_control_like_bulk:
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
16944d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			total = transfer(dum, urb, ep, limit, &status);
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
16994d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (status == -EINPROGRESS)
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del (&urbp->urbp_list);
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (urbp);
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1708cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
1710cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1716cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (list_empty(&dum_hcd->urbp_list)) {
1717cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_dev(dum_hcd->udev);
1718cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = NULL;
1719cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
1720391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1721cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1730c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1731c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1732c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1733c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1734c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf)
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1738cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1740391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1742cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1744cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1745541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1746391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1747f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1748cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
1749cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1750cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
1751cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1752f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1753f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1754cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
1756cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
1757cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status);
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1759cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
1760391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			usb_hcd_resume_root_hub (hcd);
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1762391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
1763cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
17681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanss_hub_descriptor(struct usb_hub_descriptor *desc)
17691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
17701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	memset(desc, 0, sizeof *desc);
17711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescriptorType = 0x2a;
17721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescLength = 12;
17731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->wHubCharacteristics = cpu_to_le16(0x0001);
17741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bNbrPorts = 1;
17751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
17761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.DeviceRemovable = 0xffff;
17771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
17781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
17791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic inline void
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc)
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (desc, 0, sizeof *desc);
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1785fd05e720099e8eeddb378305d1a41c1445344b91Al Viro	desc->wHubCharacteristics = cpu_to_le16(0x0001);
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
1787dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[0] = 0xff;
1788dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[1] = 0xff;
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control (
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1799cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1803541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1804391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1805391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1806cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1807cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1808cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
18151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
18161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
18171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
18181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
18191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
18201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1821cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
1823cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->resuming = 1;
1824cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->re_timeout = jiffies +
1825f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
18291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
18301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
18311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
18321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
18331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
18341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status &
18351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SS_PORT_STAT_POWER)
18361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
18371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
1838f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1840cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~(1 << wValue);
1841cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
18451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3 &&
18461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(wLength < USB_DT_SS_HUB_SIZE ||
18471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 wValue != (USB_DT_SS_HUB << 8))) {
18481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
18491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"Wrong hub descriptor type for "
18501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"USB 3.0 roothub.\n");
18511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
18521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
18531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3)
18541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
18551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		else
18561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			hub_descriptor((struct usb_hub_descriptor *) buf);
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
1859551509d267905705f6d723e51ec706916f06b859Harvey Harrison		*(__le32 *) buf = cpu_to_le32 (0);
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1868cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->resuming &&
1869cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
1870cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1871cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1873cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
1874cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
1875cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
1876cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
1877cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->dum->pullup) {
1878cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
18791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
18801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (hcd->speed < HCD_USB3) {
18811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					switch (dum_hcd->dum->gadget.speed) {
18821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_HIGH:
18831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
18841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						      USB_PORT_STAT_HIGH_SPEED;
18851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
18861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_LOW:
18871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.ep0->
18881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							maxpacket = 8;
18891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
18901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_PORT_STAT_LOW_SPEED;
18911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
18921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					default:
18931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.speed =
18941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SPEED_FULL;
18951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
18961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					}
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1900cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1901cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
1902cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
19091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_LINK_STATE:
19101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_LINK_STATE req not "
19131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
19171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * Since this is dummy we don't have an actual link so
19181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * there is nothing to do for the SET_LINK_STATE cmd
19191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
19201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
19211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U1_TIMEOUT:
19221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U2_TIMEOUT:
19231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* TODO: add suspend/resume support! */
19241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
19271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
19321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB2.0 hub */
19331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
19361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
19371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1939cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->active) {
1940cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
1941f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1942f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
1943f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
1944f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
1945cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				set_link_state(dum_hcd);
1946f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
1947cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman						& dum_hcd->dum->devstatus) != 0)
1948cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
19495742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1952f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
19531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3)
19541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
19551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else
19561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_POWER;
1957cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
1958f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
19591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_BH_PORT_RESET:
19601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB3.0 hub */
19611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_BH_PORT_RESET req not "
19641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* FALLS THROUGH */
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
1969f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
19701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status = 0;
19721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status =
19731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_SS_PORT_STAT_POWER |
19741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_CONNECTION |
19751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_RESET);
19761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
19771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
1978f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
1979f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
1980cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			/*
1981cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * We want to reset device status. All but the
1982cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * Self powered feature
1983cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 */
1984cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->dum->devstatus &=
1985cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				(1 << USB_DEVICE_SELF_POWERED);
19861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
19871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * FIXME USB3.0: what is the correct reset signaling
19881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * interval? Is it still 50msec as for HS?
19891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
1990cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
1991f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
19931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
19951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_SS_PORT_STAT_POWER) != 0) {
19961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
19971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
19981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
19991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
20001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
20011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_PORT_STAT_POWER) != 0) {
20021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
20031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
20041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
20051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
20071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case GetPortErrorCount:
20081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
20091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "GetPortErrorCount req not "
20111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "supported for USB 2.0 roothub\n");
20121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* We'll always return 0 since this is a dummy hub */
20151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		*(__le32 *) buf = cpu_to_le32(0);
20161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
20171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case SetHubDepth:
20181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
20191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "SetHubDepth req not supported for "
20211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "USB 2.0 roothub\n");
20221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2026cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd),
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
20291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanerror:
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2033cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2034685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
2035cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
2036685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern		usb_hcd_poll_rh_status (hcd);
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20400c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd)
2041391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2042cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2043391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2044441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
20453cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2046cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2047cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
2048cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	set_link_state(dum_hcd);
20493cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd->state = HC_STATE_SUSPENDED;
2050cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
2051391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2052391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2053391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
20540c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd)
2055391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2056cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
20573cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int rc = 0;
20583cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2059441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
2060391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2061cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2062541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd)) {
2063cfa59dab27d1b282886e7772a8f9548236883892Alan Stern		rc = -ESHUTDOWN;
20643cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else {
2065cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->rh_state = DUMMY_RH_RUNNING;
2066cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
2067cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (!list_empty(&dum_hcd->urbp_list))
2068cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			mod_timer(&dum_hcd->timer, jiffies);
20693cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		hcd->state = HC_STATE_RUNNING;
20703cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	}
2071cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
20723cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2073391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb)
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ep = usb_pipeendpoint (urb->pipe);
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf (buf, size,
20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (urb->dev->speed) {
20877c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_LOW:
20887c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "ls";
20897c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
20907c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_FULL:
20917c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "fs";
20927c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
20937c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_HIGH:
20947c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "hs";
20957c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
20961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 case USB_SPEED_SUPER:
20971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			s = "ss";
20981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
20997c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
21007c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "?";
21017c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (usb_pipetype (urb->pipe)) { \
21067c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_CONTROL: \
21077c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = ""; \
21087c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21097c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_BULK: \
21107c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-bulk"; \
21117c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21127c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_INTERRUPT: \
21137c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-int"; \
21147c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21157c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default: \
21167c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-iso"; \
21177c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}; s;}),
21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
212310523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf)
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd = dev_get_drvdata (dev);
2126cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2132cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2139cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic int dummy_start_ss(struct dummy_hcd *dum_hcd)
21461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
21471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	init_timer(&dum_hcd->timer);
21481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.function = dummy_timer;
21491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
21501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
21511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
21521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
21531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
21541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
21551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#ifdef CONFIG_USB_OTG
21561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
21571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#endif
21581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
21591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
21601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
21611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
21621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
21631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2164cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_start(struct usb_hcd *hcd)
21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2166cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
21731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!usb_hcd_is_primary_hcd(hcd))
21741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dummy_start_ss(dum_hcd);
21751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2176cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_init(&dum_hcd->dum->lock);
2177cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	init_timer(&dum_hcd->timer);
2178cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.function = dummy_timer;
2179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
2180cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2182cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2184caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern	hcd->power_budget = POWER_BUDGET;
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
2186685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21885742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
21895742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
21905742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
21915742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
2193cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd)
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2200cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(hcd))->dum;
2201cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
2202cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_gadget_unregister_driver(dum->driver);
2203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd)
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_g_get_frame (NULL);
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2213cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_setup(struct usb_hcd *hcd)
2214cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman{
2215cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (usb_hcd_is_primary_hcd(hcd)) {
2216cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
2217cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd->dum = &the_controller;
22181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
22191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * Mark the first roothub as being USB 2.0.
22201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * The USB 3.0 roothub will be registered later by
22211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * dummy_hcd_probe()
22221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
2223cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->speed = HCD_USB2;
2224cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_HIGH;
22251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
22261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
22271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd->dum = &the_controller;
22281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->speed = HCD_USB3;
22291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_SUPER;
2230cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	}
2231cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return 0;
2232cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman}
2233cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
22341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Change a group of bulk endpoints to support multiple stream IDs */
22351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
22361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
22371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	unsigned int num_streams, gfp_t mem_flags)
22381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (hcd->speed != HCD_USB3)
22401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
22411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			"%s() - ERROR! Not supported for USB2.0 roothub\n",
22421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			__func__);
22431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
22441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
22451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Reverts a group of bulk endpoints back to not using stream IDs. */
22471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
22481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
22491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	gfp_t mem_flags)
22501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (hcd->speed != HCD_USB3)
22521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
22531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			"%s() - ERROR! Not supported for USB2.0 roothub\n",
22541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			__func__);
22551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
22561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
22571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct hc_driver dummy_hcd = {
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
2261cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.hcd_priv_size =	sizeof(struct dummy_hcd),
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.flags =		HCD_USB3 | HCD_SHARED,
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2265cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.reset =		dummy_setup,
22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_enqueue = 		dummy_urb_enqueue,
22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_dequeue = 		dummy_urb_dequeue,
22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame_number = 	dummy_h_get_frame,
22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_status_data = 	dummy_hub_status,
22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_control = 		dummy_hub_control,
22760c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_suspend =		dummy_bus_suspend,
22770c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_resume =		dummy_bus_resume,
22781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.alloc_streams =	dummy_alloc_streams,
22801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.free_streams =		dummy_free_streams,
22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22838364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev)
22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2285cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_hcd		*hs_hcd;
22861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_hcd		*ss_hcd;
22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22898364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!mod_data.is_super_speed)
22921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dummy_hcd.flags = HCD_USB2;
2293cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
2294cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!hs_hcd)
22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2296cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd->has_tt = 1;
22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2298cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	retval = usb_add_hcd(hs_hcd, 0, 0);
22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
2300cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_hcd(hs_hcd);
23011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return retval;
23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (mod_data.is_super_speed) {
23051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
23061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_name(&pdev->dev), hs_hcd);
23071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (!ss_hcd) {
23081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			retval = -ENOMEM;
23091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto dealloc_usb2_hcd;
23101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
23111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		retval = usb_add_hcd(ss_hcd, 0, 0);
23131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (retval)
23141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto put_usb3_hcd;
23151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
23161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
23171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanput_usb3_hcd:
23191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(ss_hcd);
23201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmandealloc_usb2_hcd:
23211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(hs_hcd);
23221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2326cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_hcd_remove(struct platform_device *pdev)
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2328cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum;
2329cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
2330cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
23311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->ss_hcd) {
23331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
23341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
23351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
23361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2337cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2338cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
23391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2340cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	the_controller.hs_hcd = NULL;
23411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.ss_hcd = NULL;
23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2343d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23468364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
2347391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2348391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
23503cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int			rc = 0;
2351391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2352441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2353391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23543cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
2355cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
2356cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
23573cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
23583cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		rc = -EBUSY;
23593cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else
23603cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
23613cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2362391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2363391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23648364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_resume (struct platform_device *pdev)
2365391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2366391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2367391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2368441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2369391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23703cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
23713cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
2372391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (hcd);
2373391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2374391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2375391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
23763ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = {
2377d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
2378d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
2379391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
2380391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
23813ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
23823ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) driver_name,
23833ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
23843ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2385d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2387d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2389a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_udc_pdev;
2390a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_hcd_pdev;
23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void)
23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2394a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	int	retval = -ENOMEM;
23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_disabled ())
23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2398d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
23997eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	if (!mod_data.is_high_speed && mod_data.is_super_speed)
24007eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		return -EINVAL;
24017eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman
2402a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_hcd_pdev = platform_device_alloc(driver_name, -1);
2403a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_hcd_pdev)
24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
2405a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_udc_pdev = platform_device_alloc(gadget_name, -1);
2406a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_udc_pdev)
2407a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_alloc_udc;
2408d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2409a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_hcd_driver);
2410a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (retval < 0)
2411a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_register_hcd_driver;
2412a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_udc_driver);
2413d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2414d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2415d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2416a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_hcd_pdev);
2417d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2418a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_hcd;
24191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!the_controller.hs_hcd ||
24201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	    (!the_controller.ss_hcd && mod_data.is_super_speed)) {
2421865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2422865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The hcd was added successfully but its probe function failed
2423865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2424865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2425865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2426865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_add_udc;
2427865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2428a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_udc_pdev);
2429d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2430a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_udc;
2431865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	if (!platform_get_drvdata(the_udc_pdev)) {
2432865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2433865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The udc was added successfully but its probe function failed
2434865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2435865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2436865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2437865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_probe_udc;
2438865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2439d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2440d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2441865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewiorerr_probe_udc:
2442865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	platform_device_del(the_udc_pdev);
2443a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_udc:
2444a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_del(the_hcd_pdev);
2445a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_hcd:
2446a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2447d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
2448a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
2449a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_register_hcd_driver:
2450a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_udc_pdev);
2451a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_alloc_udc:
2452a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_hcd_pdev);
24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init);
24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void)
24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2459a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_udc_pdev);
2460a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_hcd_pdev);
2461a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2462a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup);
2465